📄 makezones
字号:
{ last if ($net == $rzone_number[$rzone]); } if ($rzone >= $rzone_count) { $net = ($d >= 192)? "$d.$c.$b" : "$d.$c"; do error("$net is not a known network."); } else { $thisaddress = "$d.$c.$b.$a"; if ($addresses{"$thisaddress"} != "") { do error("duplicate IP address $thisaddress specified for a PTR record.\n". "** The first occurrence was in line $addresses{$thisaddress}."); } else { local($handle) = "REVERSE$rzone"; print $handle "$a"; print $handle ".$b" if $d < 192; print $handle " $ttl $class PTR $rest"; $addresses{"$thisaddress"} = $nline; } } return; }# Type HINFO - host information; no further checkingif ($type eq "HINFO") { print FORWARD "$printname $ttl $class HINFO $rest"; return; }# Type MX - mail exchanger; there must be a preference and# a fully-qualified gateway name.if ($type eq "MX") { ($pref,$gateway) = split(/\s+/, $rest, 2); do check_fqn($gateway, "MX"); if ($pref !~ /^\d+$/) { do error("invalid MX preference field (not all digits)."); } print FORWARD "$printname $ttl $class MX $pref $gateway"; return; }# Type TXT - arbitrary descriptive text, enclosed in double quotesif ($type eq "TXT") { if ($rest !~ /^\".*\"\s*$/) { do error("malformed TXT record - must use double quotes."); } print FORWARD "$printname $ttl $class TXT $rest"; return; }# Type WKS - well-known services. This commonly is continued onto# other lines, so we must handle continuations. Check the protocol# field is either TCP or UDP, then check all the services appear# in the $services file, if it is set (typically /etc/services).# Check the address is in a known network, unless external.if ($type eq "WKS") { ($address,$proto,$rest) = split(/\s+/, $rest, 3); # Check the address if (!$external_net) { local($a,$b,$c,$d) = $address =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; if ($a eq "") { do error("IP address on WKS record is incomplete"); return; } if ($a > 255 || $b > 255 || $c > 255 || $d > 255) { do error("IP address contains component with value greater than 255."); return; } $net = ($a << 24) + ($b << 16); $net += ($c << 8) if $a >= 192; for ($rzone = 0; $rzone < $rzone_count; $rzone++) { last if ($net == $rzone_number[$rzone]); } if ($rzone >= $rzone_count) { $net = ($a >= 192)? "$a.$b.$c" : "$a.$b"; do error("$net is not a known network."); } } # Check the protocol if ($proto ne "UDP" && $proto ne "TCP") { do error("protocol in WKS record must be \"UCP\" or \"TCP\"."); } # Start of line prefix - the rest of the line is in $rest $pref = "$printname $ttl $class WKS $address $proto"; # Allow continuation bracket at start of list only if (substr($rest, 0, 1) eq "(") { $continued = 1; ($list) = $rest =~ /^\(\s*(.+)$/; } else { $continued = 0; $list = $rest; } # Loop for handling continuation records for (;;) { while (substr($list, -1) eq "\n") { chop($list); } while (substr($list, -1) eq " ") { chop($list); } # Loop for scanning the list of services while ($list ne "") { if (index($list, " ") >= 0) { ($servicename,$list) = split(/\s+/, $list, 2); } else { $servicename = $list; $list = ""; # Check for closing bracket at end of line. It may or may not # be preceded by a space. if ($continued && substr($servicename, -1) eq ")") { chop($servicename); $continued = 0; } } # Check the service if required. $servicename can be empty if # a closing bracket is preceded by a space. if ("$services" ne "" && $servicename ne "") { if (system("$grep \'^$servicename[ \t]\' $services >/dev/null")/256) { do error("\"$servicename\" does not appear in $services"); } } } print FORWARD "$pref $rest"; return if !$continued; # Read in the next line, which contains more services, for the # next time round this loop. $_ = <SOURCE>; $nline++; ($list) = $_ =~ /^\s*(.+)$/; $rest = "$list\n"; $pref = " "; } } # Else we have a bad recorddo error("unknown record type.");}################################################### Generate the zone data ###################################################sub generate_zones{local($i);$lastname = "";$nline = 0;print "Generating the zone data...\n" if $chatty;# Open the input fileopen(SOURCE, "$source_file") || do give_up("unable to open $source_file");# Open the output filesopen(FORWARD, ">$forward_file.new") || do give_up("unable to open $forward_file.new"); for ($i = 0; $i < $rzone_count; $i++) { open("REVERSE$i", ">$rzone_file[$i].new") || do give_up("unable to open $rzone_file[$i].new"); } # Copy the SOA record into all the output filesfor ($nline = 1; $nline <= $soa_count; $nline++) { $_ = <SOURCE>; print FORWARD $_; do print_reverse($_); } # Copy all the NS records for these zones to all the outputs. Stop# on reaching a non-NS record or a record with a name field. Skip# blank lines, and handle comments as normal.$nline--;for (;;) { $_ = <SOURCE>; $nline++; if (/^;/) { do handle_comment(); next; } next if /^\s*$/; last if /^\S/; local($ttl,$class,$ns) = /^\s+(\d+\s+|)(IN\s+|)NS\s+(\S+)\s*$/; last if $ns eq ""; do check_fqn($ns, "NS"); print FORWARD $_; do print_reverse($_); } # OK, now we have the first general record in $_. We can now scan# the rest of the file, processing as required. We do a check on# the first character of the line, because it is easy in moments# of absent-mindedness to do silly things like put in comments with# a sharp sign character instead of a semicolon. Let through only# those characters that can legally begin a line. for (;;) { if (!/^\s*$/) { if (!/^[\s\da-zA-Z\;>\"@\*]/) { do error("invalid line - semicolon omitted?"); } elsif (substr($_, 0, 1) eq ";") { do handle_comment(); } else { do handle_record(); } } last if ! ($_ = <SOURCE>); $nline++; }# Close all the filesclose FORWARD;close SOURCE; for ($i = 0; $i < $rzone_count; $i++) { close("REVERSE$i"); }}################################################### Rescan source for CNAME check ###################################################sub cname_check{$nline = 0;$lastname = "";print "Re-reading the source file for CNAME check...\n" if $chatty;# Open the input fileopen(SOURCE, "$source_file") || do give_up("unable to open $source_file");# Skip the SOA recordfor ($nline = 1; $nline <= $soa_count; $nline++) { $_ = <SOURCE>; } $nline--;# Scan for CNAMEs. We only need to do a very little parsing,# as all checking has previously been done. We must still# do the lastname stuff, to catch cases of a CNAME record# followed by nameless records.for (;;) { last if ! ($_ = <SOURCE>); $nline++; if (!/^\s*$/ && substr($_, 0, 1) ne ";") { if (/^>(E|F|R) /) { $rest = substr($_, 3); } else { $rest = $_; } ($name,$rest) = split(/\s+/, $rest, 2); $name = $lastname if $name eq ""; $lastname = $name; if ($rest =~ /^\d/) { ($ttl,$rest) = split(/\s+/, $rest, 2); } ($class,$rest) = split(/\s+/, $rest, 2); if ($class eq "IN") { ($type,$rest) = split(/\s+/, $rest, 2); } else { $type = $class; } if ($type ne "CNAME" && $cnames{$name} ne "") { do error("$name appears on a CNAME record (line $cnames{$name}) and ". "so may not\n appear on any other records."); } } }close SOURCE; }################################################### Compare new/old zone lengths ###################################################sub check_length{local($length_old, $length_new, $length_diff);local($name) = $_[0];if (! -e $name) { do give_up("$name is unavailable for length checking."); return; } @stat_data = stat($name);$length_old = $stat_data[7];@stat_data = stat("$name.new");$length_new = $stat_data[7];$length_diff = $length_old - $length_new;if ($length_diff > ($length_old/20)) { do error("$name.new is more than 5% shorter than $name.\n". "** Use -short to override this check."); $lastwaserror = 1; } elsif ($chatty) { print "\n" if $lastwaserror; print "Length of $name is OK\n"; $lastwaserror = 0; } }sub compare_lengths{local($i);print "Comparing lengths of old and new zone files...\n" if $chatty;$lastwaserror = 0;do check_length("$forward_file");for ($i = 0; $i < $rzone_count; $i++) { do check_length("$rzone_file[$i]"); } }################################################### Rename new zones to final names ###################################################sub rename_zones {local($i);print "Renaming the new zone files to their final names...\n" if $chatty;rename("$forward_file.new", "$forward_file");for ($i = 0; $i < $rzone_count; $i++) { rename("$rzone_file[$i].new", "$rzone_file[$i]"); }}################################################### Remove temporary files #################################################### This is used to remove the temporary files if processing# fails. It is not an error for the temps not to exist.sub remove_temps{local ($i);unlink "$forward_file.new";for ($i = 0; $i < $rzone_count; $i++) { unlink "$rzone_file[$i].new"; }}################################################### Main Program #################################################### After any serious error, the script dies and does not# return to the main code. Syntax errors etc. carry on,# leaving $errors containing the count. Only generate_zones()# cname_check() and compare_lengths() handle errors in this #way - all the other routines generate hard errors.$rzone_count = $errors = 0;$soa_count = 6;do unpick_args();do verify();do update_serial();do generate_zones();print "\n" if $errors > 0;do cname_check();$nline = -1;if ($errors == 0) { do compare_lengths() if !$opt_short; if ($errors == 0) { do rename_zones(); print "\nMakezones completed successfully.\n"; exit 0; } }do remove_temps(); print "\n** Makezones failed.\n";exit 99;# End of makezones
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -