⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.93
Server IP:
65.108.141.171
Server:
Linux server.heloix.com 5.4.0-214-generic #234-Ubuntu SMP Fri Mar 14 23:50:27 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
7.4.33
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
webmin
/
virtualmin-slavedns
/
View File Name :
virtual_feature.pl
# Defines functions for this feature use strict; use warnings; our (%text, %in); our $module_name; require 'virtualmin-slavedns-lib.pl'; my $input_name = $module_name; $input_name =~ s/[^A-Za-z0-9]/_/g; # feature_name() # Returns a short name for this feature sub feature_name { return $text{'feat_name'}; } # feature_losing(&domain) # Returns a description of what will be deleted when this feature is removed sub feature_losing { return $text{'feat_losing'}; } # feature_label(in-edit-form) # Returns the name of this feature, as displayed on the domain creation and # editing form sub feature_label { my ($edit) = @_; return $edit ? $text{'feat_label2'} : $text{'feat_label'}; } # feature_hlink(in-edit-form) # Returns a help page linked to by the label returned by feature_label sub feature_hlink { return 'feat'; } # feature_check() # Returns undef if all the needed programs for this feature are installed, # or an error message if not sub feature_check { return &foreign_installed("bind8", 1) == 2 ? undef : &text('feat_echeck', '../bind8/'); } # feature_depends(&domain) # Returns undef if all pre-requisite features for this domain are enabled, # or an error message if not. # Checks for a default master IP address in template. sub feature_depends { my ($d, $oldd) = @_; if (!$oldd || !$oldd->{$module_name}) { my $tmpl = &virtual_server::get_template($d->{'template'}); my $mip = $d->{$module_name."master"} || $tmpl->{$module_name."master"}; return $text{'feat_emaster'} if ($mip eq '' || $mip eq 'none'); } return undef; } # feature_clash(&domain, [field]) # Returns undef if there is no clash for this domain for this feature, or # an error message if so. # Checks for a DNS zone with the same name. sub feature_clash { my ($d, $field) = @_; if (!$field || $field eq "dom") { my $z = &virtual_server::get_bind_zone($d->{'dom'}); return $z ? $text{'feat_clash'} : $d->{'dns'} ? $text{'feat_clash2'} : undef; } return undef; } # feature_suitable([&parentdom], [&aliasdom], [&subdom]) # Returns 1 if some feature can be used with the specified alias, # parent and sub domains. # Doesn't make sense for alias domains. sub feature_suitable { my ($parentdom, $aliasdom, $subdom) = @_; return !$aliasdom; } # feature_setup(&domain) # Called when this feature is added, with the domain object as a parameter sub feature_setup { my ($d) = @_; my $tmpl = &virtual_server::get_template($d->{'template'}); my @mips = split(/\s+/, $d->{$module_name."master"} || $tmpl->{$module_name."master"}); &$virtual_server::first_print($text{'setup_bind'}); if (!@mips) { &$virtual_server::second_print($text{'setup_emaster'}); return 0; } if (defined(&virtual_server::obtain_lock_dns)) { &virtual_server::obtain_lock_dns($d, 1); } # Create the slave zone directive &virtual_server::require_bind(); my $conf = &bind8::get_config(); my $dir = { 'name' => 'zone', 'values' => [ $d->{'dom'} ], 'type' => 1, 'members' => [ { 'name' => 'type', 'values' => [ 'slave' ] }, { 'name' => 'masters', 'type' => 1, 'members' => [ map { { 'name' => $_ } } @mips ] } ], }; # Allow masters to update my $also = { 'name' => 'allow-notify', 'type' => 1, 'members' => [ ] }; foreach my $ip (@mips) { push(@{$also->{'members'}}, { 'name' => $ip }); } push(@{$dir->{'members'}}, $also); # Create and add slave file my $base = $bind8::config{'slave_dir'} || &bind8::base_directory(); my $file = &bind8::automatic_filename($d->{'dom'}, 0, $base); push(@{$dir->{'members'}}, { 'name' => 'file', 'values' => [ $file ] } ); no strict "subs"; &open_tempfile(ZONE, ">".&bind8::make_chroot($file), 0, 1); &close_tempfile(ZONE); use strict "subs"; &bind8::set_ownership(&bind8::make_chroot($file)); # Work out where to add my $pconf; my $indent = 0; if ($tmpl->{$module_name.'view'}) { # Adding inside a view. This may use named.conf, or an include # file references inside the view, if any $pconf = &bind8::get_config_parent(); my $view = &virtual_server::get_bind_view($conf, $tmpl->{$module_name.'view'}); if ($view) { my $addfile = &bind8::add_to_file(); my $addfileok; if ($bind8::config{'zones_file'} && $view->{'file'} ne $bind8::config{'zones_file'}) { # BIND module config asks for a file .. make # sure it is included in the view foreach my $vm (@{$view->{'members'}}) { if ($vm->{'file'} eq $addfile) { # Add file is OK $addfileok = 1; } } } if (!$addfileok) { # Add to named.conf $pconf = $view; $indent = 1; $dir->{'file'} = $view->{'file'}; } else { # Add to the file $dir->{'file'} = $addfile; $pconf = &bind8::get_config_parent($addfile); } } else { &error(&virtual_server::text('setup_ednsview', $tmpl->{$module_name.'view'})); } } else { # Adding at top level .. but perhaps in a different file $dir->{'file'} = &bind8::add_to_file(); $pconf = &bind8::get_config_parent($dir->{'file'}); } # Add to .conf file &bind8::save_directive($pconf, undef, [ $dir ], $indent); &flush_file_lines(&bind8::make_chroot($dir->{'file'})); unlink($bind8::zone_names_cache); undef(@bind8::list_zone_names_cache); if (defined(&virtual_server::release_lock_dns)) { &virtual_server::release_lock_dns($d, 1); } # All done &virtual_server::register_post_action(\&virtual_server::restart_bind); &$virtual_server::second_print(&text('setup_done', join(' ', @mips))); return 1; } # feature_modify(&domain, &olddomain) # Called when a domain with this feature is modified. # Renames the zone and file if the domain name is changed. sub feature_modify { my ($d, $oldd) = @_; if ($d->{'dom'} ne $oldd->{'dom'}) { &$virtual_server::first_print($text{'modify_bind'}); if (defined(&virtual_server::obtain_lock_dns)) { &virtual_server::obtain_lock_dns($d, 1); } # Get the zone object my $z = &virtual_server::get_bind_zone($oldd->{'dom'}); if ($z) { # Rename records file, for real and in .conf my $file = &bind8::find("file", $z->{'members'}); my $fn = $file->{'values'}->[0]; my $nfn = $fn; $nfn =~ s/$oldd->{'dom'}/$d->{'dom'}/; if ($fn ne $nfn) { &rename_logged(&bind8::make_chroot($fn), &bind8::make_chroot($nfn)) } $file->{'values'}->[0] = $nfn; $file->{'value'} = $nfn; # Change zone in .conf file $z->{'values'}->[0] = $d->{'dom'}; $z->{'value'} = $d->{'dom'}; &bind8::save_directive(&bind8::get_config_parent(), [ $z ], [ $z ], 0); &flush_file_lines(); # Clear zone names caches unlink($bind8::zone_names_cache); undef(@bind8::list_zone_names_cache); } else { &$virtual_server::second_print( $virtual_server::text{'save_nobind'}); } if (defined(&virtual_server::release_lock_dns)) { &virtual_server::release_lock_dns($d, 1); } # All done &$virtual_server::second_print($virtual_server::text{'setup_done'}); return 1; } return 1; } # feature_delete(&domain) # Called when this feature is disabled, or when the domain is being deleted sub feature_delete { my ($d) = @_; &$virtual_server::first_print($text{'delete_bind'}); if (defined(&virtual_server::obtain_lock_dns)) { &virtual_server::obtain_lock_dns($d, 1); } # Get the zone object my $z = &virtual_server::get_bind_zone($d->{'dom'}); if ($z) { # Delete records file my $file = &bind8::find("file", $z->{'members'}); if ($file) { my $zonefile = &bind8::make_chroot($file->{'values'}->[0]); &unlink_file($zonefile); } # Delete from .conf file my $rootfile = &bind8::make_chroot($z->{'file'}); my $lref = &read_file_lines($rootfile); splice(@$lref, $z->{'line'}, $z->{'eline'} - $z->{'line'} + 1); &flush_file_lines($rootfile); # Clear zone names caches unlink($bind8::zone_names_cache); undef(@bind8::list_zone_names_cache); &virtual_server::register_post_action(\&virtual_server::restart_bind); } else { &$virtual_server::second_print($virtual_server::text{'save_nobind'}); } if (defined(&virtual_server::release_lock_dns)) { &virtual_server::release_lock_dns($d, 1); } # All done &$virtual_server::second_print($virtual_server::text{'setup_done'}); return 1; } # feature_import(domain-name, user-name, db-name) # Returns 1 if this feature is already enabled for some domain being imported, # or 0 if not sub feature_import { my ($dname, $user, $db) = @_; my $z = &virtual_server::get_bind_zone($dname); if ($z) { my $type = &bind8::find("type", $z->{'members'}); if ($type && ($type->{'values'}->[0] eq 'slave' || $type->{'values'}->[0] eq 'stub')) { return 1; } } return 0; } # feature_links(&domain) # Returns an array of link objects for webmin modules for this feature sub feature_links { my ($d) = @_; return ( { 'mod' => $module_name, 'desc' => $text{'links_link'}, 'page' => 'edit.cgi?dom='.$d->{'dom'}, 'cat' => 'server', } ); } # feature_webmin(&main-domain, &all-domains) # Returns a list of webmin module names and ACL hash references to be set for # the Webmin user when this feature is enabled sub feature_webmin { my @doms = map { $_->{'dom'} } grep { $_->{$module_name} } @{$_[1]}; if (@doms) { return ( [ $module_name, { 'dom' => join(" ", @doms), 'noconfig' => 1 } ] ); } else { return ( ); } } sub feature_modules { return ( [ $module_name, $text{'feat_module'} ] ); } # feature_backup(&domain, file, &opts, &all-opts) # Called to backup this feature for the domain to the given file. Must return 1 # on success or 0 on failure. # Saves the named.conf block for this domain. sub feature_backup { my ($d, $file) = @_; &$virtual_server::first_print($text{'backup_conf'}); my $z = &virtual_server::get_bind_zone($d->{'dom'}); if ($z) { my $lref = &read_file_lines($z->{'file'}, 1); my $dstlref = &virtual_server::read_file_lines_as_domain_user($d, $file); @$dstlref = @$lref[$z->{'line'} .. $z->{'eline'}]; &virtual_server::flush_file_lines_as_domain_user($d, $file); &$virtual_server::second_print($virtual_server::text{'setup_done'}); return 1; } else { &$virtual_server::second_print($virtual_server::text{'backup_dnsnozone'}); return 0; } } # feature_restore(&domain, file, &opts, &all-opts) # Called to restore this feature for the domain from the given file. Must # return 1 on success or 0 on failure sub feature_restore { my ($d, $file) = @_; &$virtual_server::first_print($text{'restore_conf'}); if (defined(&virtual_server::obtain_lock_dns)) { &virtual_server::obtain_lock_dns($d, 1); } my $z = &virtual_server::get_bind_zone($d->{'dom'}); my $rv; if ($z) { my $rootfile = &bind8::make_chroot($z->{'file'}); my $lref = &read_file_lines($rootfile); my $srclref = &read_file_lines($file, 1); splice(@$lref, $z->{'line'}, $z->{'eline'}-$z->{'line'}+1, @$srclref); &flush_file_lines($rootfile); &virtual_server::register_post_action(\&virtual_server::restart_bind); &$virtual_server::second_print($virtual_server::text{'setup_done'}); $rv = 1; } else { &$virtual_server::second_print( $virtual_server::text{'backup_dnsnozone'}); $rv = 0; } if (defined(&virtual_server::release_lock_dns)) { &virtual_server::release_lock_dns($d, 1); } return $rv; } # feature_backup_name() # Returns a description for what is backed up for this feature sub feature_backup_name { return $text{'backup_name'}; } # feature_validate(&domain) # Checks if this feature is properly setup for the virtual server, and returns # an error message if any problem is found. # Checks if the zone exists and is a slave. sub feature_validate { my ($d) = @_; my $z = &virtual_server::get_bind_zone($d->{'dom'}); if ($z) { my $type = &bind8::find("type", $z->{'members'}); if ($type && ($type->{'values'}->[0] eq 'slave' || $type->{'values'}->[0] eq 'stub')) { return undef; } return $text{'validate_etype'}; } return $text{'validate_ezone'}; } # Always show master DNS server input sub feature_inputs_show { return 1; } # feature_inputs([&domain]) # Returns a field for master DNS server(s) sub feature_inputs { my ($d) = @_; my $tmpl = &virtual_server::get_template($d ? $d->{'template'} : 0); return &ui_table_row($text{'feat_master'}, &ui_opt_textbox($input_name."_master", $tmpl->{$module_name."master"}, 30, $text{'feat_mastertmpl'})); } # feature_inputs_parse(&domain, &in) # Update the domain object with a custom master DNS server sub feature_inputs_parse { my ($d, $in) = @_; if (defined($in->{$input_name."_master"}) && !$in->{$input_name."_master_def"}) { my @ips = split(/\s+/, $in->{$input_name."_master"}); foreach my $ip (@ips) { &check_ipaddress($ip) || return &text('tmpl_eip', $ip); } @ips || return $text{'tmpl_eips'}; $d->{$module_name."master"} = $in->{$input_name."_master"}; } return undef; } # feature_args(&domain) # Return command-line arguments for domain registration sub feature_args { return ( { 'name' => $module_name."-master", 'value' => 'nameservers', 'opt' => 1, 'desc' => 'Master DNS servers for slave domain' }, ); } # feature_args_parse(&domain, &args) # Parse command-line arguments from feature_args sub feature_args_parse { my ($d, $args) = @_; if (defined($args->{$module_name."-master"})) { my @ips = split(/\s+/, $args->{$module_name."-master"}); foreach my $ip (@ips) { &check_ipaddress($ip) || return "Invalid master DNS server IP address $ip"; } @ips || return "No master DNS server IP addresses given"; $d->{$module_name."master"} = join(" ", @ips); } return undef; } # template_input(&template) # Returns HTML for editing per-template options for this plugin sub template_input { my ($tmpl) = @_; # Master IPs input my $v = $tmpl->{$module_name."master"}; $v = "none" if (!defined($v) && $tmpl->{'default'}); my $rv; $rv .= &ui_table_row($text{'tmpl_master'}, &ui_radio($input_name."_mode", $v eq "" ? 0 : $v eq "none" ? 1 : 2, [ $tmpl->{'default'} ? ( ) : ( [ 0, $text{'default'} ] ), [ 1, $text{'tmpl_notset'} ], [ 2, $text{'tmpl_ips'} ] ])."\n". &ui_textbox($input_name, $v eq "none" ? undef : $v, 30)); # Add to view input, if any &virtual_server::require_bind(); my $conf = &bind8::get_config(); my @views = &bind8::find("view", $conf); if (@views) { $rv .= &ui_table_row($text{'tmpl_view'}, &ui_select($input_name."_view", $tmpl->{$module_name."view"}, [ [ "", $virtual_server::text{'newdns_noview'} ], map { [ $_->{'values'}->[0] ] } @views ])); } return $rv; } # template_parse(&template, &in) # Updates the given template object by parsing the inputs generated by # template_input. All template fields must start with the module name. sub template_parse { my ($tmpl, $in) = @_; # Parse master IPs field if ($in->{$input_name.'_mode'} == 0) { $tmpl->{$module_name."master"} = ""; } elsif ($in->{$input_name.'_mode'} == 1) { $tmpl->{$module_name."master"} = "none"; } else { my @ips = split(/\s+/, $in->{$input_name}); foreach my $ip (@ips) { &check_ipaddress($ip) || &error(&text('tmpl_eip', $ip)); } @ips || &error($text{'tmpl_eips'}); $tmpl->{$module_name."master"} = join(" ", @ips); } # Parse view field if (defined($in->{$input_name.'_view'})) { $tmpl->{$module_name."view"} = $in->{$input_name.'_view'}; } } 1;