📄 records-lib.pl
字号:
if ($1 eq 'in-addr') { $name = &compress_ip(&arpa_to_ip($name)); } else { $name = &ip6arpa_to_net($name); unless (&is_ip6_subnet($orig_name)) { $name = &compress_ip6($name); } } } elsif ($_[0] <= 0) { if ($name eq $origin) { $name = '@' unless ($_[3]); } elsif ($name =~ /^([\d.:]+)$origin$/) { # # Removing the origin in this case would leave # a name which looks like an IP address. As # such we let the FQDN be displayed to avoid # any confusion. # } elsif ($origin eq '.') { $name =~ s/\.$//o; } else { $name =~ s/\.$origin$//; } } } return $name;}## This subroutine checks an IPv6 address to see if it is actually a subnet.# We do this by counting the number of colons (:) in the address. If a :: is# seen then we cannot determine if this is a subnet, because we do not know how# many zeros should replace the ::. We also cater for IPv6 reverse addresses.## is_ip6_subnet(IPv6_address)#sub is_ip6_subnet { my $addr = lc($_[0]); return 0 unless ($addr); if ($addr =~ /^(.*\.)ip6\.arpa\.?$/o) { $addr = $1; return ($addr !~ /^([\da-f*]\.){32}$/o); } return 0 if ($addr =~ /::/o || $addr !~ /^[\da-f:*]+$/o); return (($addr =~ s/:/:/go) != 7);}## This subroutine is used to check the SOA serial number. It will return# one of two values: a negative number to indicate an error, or a positive# number to indicate the next serial number to use. A value of one is used# to indicate that whatever next serial number the name server uses is# okay. For example, dynamic zones may have their serial number sequentially# incremented automatically.## Returns = 1 if okay to proceed - no serial number needed,# > 1 serial number is set to what number to use,# = -1 serial number unobtainable# = -2 invalid serial number format# = -3 abort updates## check_soa_serial(dynamic_data_ref, zone, @records, soa_ref)#sub check_soa_serial { my $dynamic_zone = my $serial = my $nn = 0; my $sec = my $min = my $hour = my $day = my $mon = my $year = 0; my $rec = my $today = my $serial_date = my $future = my $soa_ref = ''; my $abort_updates = -3; $dynamic_zone = $_[0]->[1]; if ($dynamic_zone) { $serial = $_[0]->[3]; return -1 if ($serial < 0); # Serial number unobtainable. } else { $serial = &get_soa_rec($_[1], $_[2], $soa_ref); if ($serial) { ($serial) = ($serial =~ /\sSOA\s+\S+\s+\S+\s+(\d+)/io); } if ($serial) { $_[3] = $soa_ref if (defined($_[3])); } else { return -1; # Serial number unobtainable. } } # # No checks needed if we are using a simple sequential number for the # serial number, or we have requested no serial number updates for # static zones. # unless ($config{'soa_date_style'}) { return ($dynamic_zone) ? 1 : ++$serial; } return 1 if (! $config{'updserial_on'} && ! $dynamic_zone); if ($serial =~ /^(\d{8})(\d\d)$/o) { $serial_date = $1; $nn = $2; } else { return -2; } $today = &today(); # Get todays date. # # If the serial number date is earlier than today, regardless of the # current number, then we have no problem :-) Just start afresh with # todays date. # if ($serial_date < $today) { return $today . '00'; } # # If the serial number date is today and the number is less than 99, # then again we have no problem. Just use the next number. # if ($serial_date == $today && $nn < 99) { return ($dynamic_zone) ? 1 : ++$serial; } # # At this point we have two scenarios left: # # 1) The serial number date is in the future # 2) The date is todays date but the number equals 99 # # We handle both cases the same by rechecking the config options, # they may have changed since last time, and acting accordingly. # if ($config{'serial_exceed99'} == 0) { return $abort_updates; } elsif ($config{'serial_exceed99'} == 1) { # Just use the next number. return ($dynamic_zone) ? 1 : ++$serial; } # # We want to use a future date. Calculate one if necessary and # return the new serial number. We must, however, check that the # current value is a valid date, because we may have changed from # using sequential numbers to the date format. # unless (&valid_date($serial)) { $nn = 500; # Force a new date to be calculated. } if ($nn < 99) { # This can only be for the future date scenario. return ($dynamic_zone) ? 1 : ++$serial; } # # For dynamic zones we must be careful with future dates. It is # possible for the date to become invalid when the serial number is # automatically incremented. For example, 2003043099 would become # 2003043100. To resolve this we record the new future date when # we check if we can increment the serial number (see save_record). # We then pass that to bump_soa_record to reset the serial number # after the name server has auto-incremented it. # $future = &calc_secs($serial_date); $future += 86400 unless ($nn == 500); # Add one day. ($sec, $min, $hour, $day, $mon, $year) = localtime($future); $future = sprintf('%4.4d%2.2d%2.2d00', $year + 1900, $mon + 1, $day); return $future;}## Calculate the number of seconds since the epoch.## calc_secs(YYYYMMDD)#sub calc_secs { use integer; my $secs = my $day = my $mon = my $year = my $leap_days = my $y = 0; my @days_in_mon = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); ($year, $mon, $day) = ($_[0] =~ /^(\d{4})(\d\d)(\d\d)$/o); $mon -= 2; # Subtract 2 because the array starts at 0 and we only # need the previous months - excluding this one. if ($mon >= 0) { # Add up all the days in the previous months. foreach (0 .. $mon) { $day += $days_in_mon[$_]; } } $y = $year - 1972; $leap_days = int($y / 4); # # If we are in a leap year and in January or February, then we must # remove one of the leap days. We will have calculated to include the # leap day for this year, but we haven't reached that leap day yet! # $leap_days-- if ((($y % 4) == 0) && $mon < 1); $year -= 1970; # Calculate the number of years. $day += ($year * 365) + $leap_days; # Add up all the days. $secs = $day * 86400; # Convert to seconds. return $secs;}## Get a zone's SOA record. If the 'records' argument is present then we have# already read the zone file for the records so we may as well use that rather# than reading the zone again. If 'ref_rec' is present then it means we want the# reference to the SOA record returned to the caller.## get_soa_rec(zone, @records, rec_ref)#sub get_soa_rec { my $n = my $v = 0; my $zone = my $zone_conf = my $output = ''; my $file = my $rec = my $rec_ref = ''; my @recs = (); $zone_conf = $_[0]; $zone = lc($zone_conf->{'value'}); $zone .= '.' unless ($zone =~ /\.$/o); $rec_ref = undef; if (defined($_[1])) { @recs = @{ $_[1] }; } else { $file = &find_value('file', $zone_conf->{'members'}); # # We might as well treat this as a stub zone since we only # want the SOA record. # @recs = &get_zone($zone_conf, $file, $zone, undef, 'stub'); } for ($n = 0; $n < @recs; $n++) { $rec = $recs[$n]; if ($rec->{'type'} eq 'SOA') { $output = $rec->{'fqdn'} . ' '; $output .= ($rec->{'ttl'}) ? $rec->{'ttl'} : 0; $output .= ' IN SOA'; for ($v = 0; $rec->{'values'}->[$v]; $v++) { $output .= ' ' . $rec->{'values'}->[$v]; } $rec_ref = $rec; last; } } $_[2] = $rec_ref if (defined($_[2])); return ($output =~/\sSOA\s+\S+\s+\S+\s+\d/io) ? $output : '';}## check_serial_number(dynamic_zone_ref, zone, @records, soa_ref)#sub check_serial_number { my $serial_okay = 0; my $err = ''; $serial_okay = &check_soa_serial($_[0], $_[1], $_[2], $_[3]); if ($serial_okay < 0) { $err = ($serial_okay == -1) ? 'soa_serial_unob' : ($serial_okay == -2) ? 'soa_serial_invalid' : 'soa_serial_max'; &terror($err); } return $serial_okay;}## valid_date(date_string - YYYYMMDDnn)#sub valid_date { my $year = my $month = my $day = 0; my $date_str = ''; my @days_in_mon = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); $date_str = $_[0]; return 0 unless ($date_str); if ($date_str =~ /^(\d{4})(\d\d)(\d\d)\d\d$/o) { $year = $1; $month = $2; $day = $3; } else { return 0; } return 0 if ($year < 1970); # # If we specify that the next number is to be used then just return. # The year must still be valid but the days and months may not be. # return 1 if ($config{'serial_exceed99'} == 1); return 0 if ($month < 1 || $month > 12); # # Calculate if it is a leap year to see if we need to adjust the # number of days in February. # if (($year % 4) == 0 && (($year % 100) != 0 || ($year % 400) == 0)) { $days_in_mon[1]++; } return 0 if ($day < 1 || $day > $days_in_mon[$month - 1]); return 1;}## check_update_err(error_string)#sub check_update_err { my $error = my $status = ''; $error = $_[0]; return unless ($error); if ($error =~ /\sopcode: UPDATE, status: ([^,]+),/io) { $status = $1; if ($status eq 'NXRRSET') { &terror('update_no_rec'); } elsif ($status eq 'SERVFAIL') { &terror('update_servfail'); } elsif ($status eq 'NOTAUTH') { &terror('updates_no_allow'); } } &error("<pre>$error</pre>");}## See if the given record type, with the specified token number, needs the# value converting to/from FQDN. For example, MX records have as their values:## the preference/priority, as token 0, is not to be converted;# the mail server, as token 1, which may be converted.## The returned value will be >=0 in the case of record values which may be# converted. The number indicates its token count. A value of -1 is returned# in all other instances.## convert_value(record_type, token_count)#sub convert_value { my $token_count = 0; my $type = ''; $type = $_[0]; $token_count = $_[1]; if ($type eq 'CNAME' || $type eq 'DNAME' || $type eq 'NS') { return 0; } elsif ($type eq 'MX' || $type eq 'RP') { return (! defined($token_count) || $token_count == 1) ? 1 : -1; } elsif ($type eq 'SRV') { return (! defined($token_count) || $token_count == 3) ? 3 : -1; } else { return -1; }}## This subroutine will check an IPv4 or IPv6 address to see if it is valid.# Wildcards are catered for, as are subnets. All addresses are assumed to be# in the 'forward' format - e.g. 10.1.2.3. The fact that an address could be# a name, as in a PTR record, or a value, as in an A record, is also taken# into account.## The final argument, must_be_ipv4, can take the value -1, 0 or 1. -1 indicates# that the address can be either IPv4 or IPv6. 1 indicates that it must be an# IPv4 address, and 0 indicates that it must be IPv6.## valipaddr(addr, origin, name_or_value, wild_allowed, subnet_allowed,# must_be_ipv4)#sub valipaddr { my $name = my $wild = my $subnet = my $ipv4 = my $wild_seen = 0; my $addr = my $origin = ''; ($addr, $origin, $name, $wild, $subnet, $ipv4) = @_; if ($addr =~ /\*/o) { $wild_seen++; return 0 unless ($config{'allow_wild'} && $wild); return 0 unless ($name); } # # We handle the address by looking to see the type of zone we are in, # and then the type of address it is. The other arguments should then # simply decide if the address is valid or not. # if ($origin =~ /\.(in-addr|ip6)\.arpa\.$/o) { # # This is a reverse zone. As a name the address may belong to # one of several record types, including PTR, RP, TXT, etc. # As a value it will probably belong to a CNAME record. # # Despite this being a reverse zone, we will have presented, # and received, the addresses in the 'forward' format. As such # we do not need to convert them from their reverse arpa domain # name to the forward format. We will, however, need to modify # the address if it is a subnet. # return 1 if ($addr eq '*'); if ($1 eq 'in-addr') { # IPv4 reverse zone. if ($wild_seen) { if ($addr =~ /^(.+)\.\*$/o) { $addr = $1 . '.0'; } else { return 0; } } if ($subnet) { if ($addr =~ /^\d{1,3}(\.\d{1,3})?(\.\d{1,3})?(\.\d{1,3})?$/o) { $addr .= '.0' unless (defined($3)); $addr .= '.0' unless (defined($2)); $addr .= '.0' unless (defined($1)); } else { # Invalid subnet given. return 0; } } } else { # IPv6 reverse zone. if ($wild_seen) { if ($addr =~ /^(.+)\*$/o) { $addr = $1 . '0'; } else { return 0; } } if ($subnet && $addr =~ /^([\da-f]{1,4}:){0,6}[\da-f]{1,4}$/io) { # # At this point we have an IPv6 # address as a value. Any subnet will # be dealt with by expand_ip6. # $addr = &expand_ip6($addr, 1); } } } else { # # This is a forward zone. The address will be a value belonging # to either an A or AAAA/A6 record. Neither subnets nor # wildcards are allowed. # return 0 if ($name || $wild_seen); } # # Now see if the final address is valid or not. # if ($addr =~ /:/o && # It's an IPv6 address. $addr =~ /^[:\da-f]+$/io) { if ($ipv4 == 1) { # But it must be IPv4! return 0; } else { $addr = expand_ip6($addr, 0); return ($addr =~ /^([\da-f]{1,4}:){7}[\da-f]{1,4}$/io); } } elsif ($addr =~ /^[\d.]+$/o) { # It's an IPv4 address. if ($ipv4 == 0) { # But it must be IPv6! return 0; } else { return &check_ipaddress($addr); } } return 0;}## seen_no_recs(file, named_status, zone_type)#sub seen_no_recs { my $file = $_[0]; printf '<p><center><b><u>%s:</u></b> %s', $text{'Warning'}, $text{'no_zone_recs'}; if (defined($file)) { $file = $config{'chroot'} . &absolute_path($file); if (! -e $file) { print ' - ', $text{'zone_file_noexist'}, '</center><p>'; return; } elsif (! -s $file) { print ' - ', $text{'zone_file_empty'}, '</center><p>'; return; } } if ($_[1] <= 0) { print ' - ', $text{'named_pos_no_run'}; } elsif ($_[2] eq 'master') { print '.'; } else { print ' - ', $text{'xfr_failed2'}; } print '</center><p>'; return;}1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -