X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;ds=sidebyside;f=scripts%2Fnamed-conf;h=dfabc82dc36f9e8c3b08bfb538fc2756c32d64ba;hb=b3f3d259857a51c3df303c44276457cad8d99d07;hp=a54db8277c5c26adfbe4dff32435ab21535f9f8c;hpb=5ed8bc665fbc0fc51dbfebdeed49153686e26699;p=chiark-utils.git diff --git a/scripts/named-conf b/scripts/named-conf index a54db82..dfabc82 100755 --- a/scripts/named-conf +++ b/scripts/named-conf @@ -135,7 +135,7 @@ sub read_config ($) { last; } chomp; s/\s+$//; - if (m/\\$/) { $before.= $_; next; } + if (s/\\$//) { $before.= $_; next; } $_= $before.$_; $before= ''; s/^\s+//; @@ -200,7 +200,8 @@ sub read_config ($) { read_config($1); } else { cfg_fail("unknown configuration directive". - " or incorrect syntax or arguments"); + " or incorrect syntax or arguments:\n". + " \`$_'"); } } $fh->close or cfg_fail("close config file $if:\n $!"); @@ -230,10 +231,11 @@ sub zone_conf ($$$$$@) { $zone_cfg{$zone}{'style_p'}= $style.$mod; $zone_cfg{$zone}{'s'}= $sabbr.$mod; # p)rimary s)econdary u)npub f)oreign $zone_cfg{$zone}{'servers'}= [ @servers ]; - foreach $sfx (qw(soa ns addr)) { - { no strict 'refs'; $aref= [ @{ "self_$sfx" } ]; } - @$aref or cfg_fail("failed to specify self-$sfx before zone"); - $zone_cfg{$zone}{"self_$sfx"}= $aref; + foreach $sfx (qw(self_soa self_ns self_addr forbid_addr conv_glueless)) { + { no strict 'refs'; $aref= [ @$sfx ]; } + @$aref or cfg_fail("failed to specify $sfx before zone") + if $sfx =~ m/^self/; + $zone_cfg{$zone}{$sfx}= $aref; } $zone_cfg{$zone}{'output'}= $output; push @zone_cfg_list, $zone; @@ -248,7 +250,7 @@ sub set_output($) { #-------------------- checking -use vars qw($zone $cfg $warnings); +use vars qw($zone $cfg $warnings %zone_warnings); $warnings= 0; sub progress ($) { @@ -289,14 +291,22 @@ sub process_zones (@) { $output_contents{$$cfg{'output'}} .= zone_output() if $install; } - print STDERR "$quis: $warnings warnings\n" or die $! - if $warnings; + if ($warnings) { + printf STDERR ("%s: %d warning(s) in %d zone(s);". + " %d zone(s) checked ok.\n", + $quis, + $warnings, + scalar(keys %zone_warnings), + scalar(@zones - keys %zone_warnings)); + } else { + progress(sprintf "%d zone(s) checked ok", scalar @zones); + } } use vars qw(%delgs); # $delgs{$nameserver_list} = [ $whosaidandwhy ] use vars qw(%auths); # $auths{$nameserver_list} = [ $whosaidandwhy ] use vars qw(%glue); # $glue{$name}{$addr_list} = [ $whosaidandwhy ] -use vars qw(%soas); # $soa{"$origin $serial"} = [ $whosaidandwhy ] +use vars qw(%soas); # $soa{"$serial $origin"} = [ $whosaidandwhy ] use vars qw(%addr_is_ok %warned); use vars qw($delg_to_us); use vars qw(@to_check); # ($addr,$whyask,$is_auth,$glueless_ok, ...) @@ -306,15 +316,15 @@ sub zone_warning ($$) { my ($w,$o) = @_; my ($wk); - $wk= $w; - $wk =~ s/,.*// if !$repeat; - return 0 if $warned{$w}{$wk}++; + return 0 if !$repeat && $warned{$w}++; $w =~ s/\n$//; $w =~ s,\n, // ,g; + $w .= " ($o)" if length $o; print STDERR "$zone: warning: $w\n" or die $!; $warnings++; + $zone_warnings{$zone}++; return 1; } @@ -343,12 +353,14 @@ sub zone_investigate() { for (;;) { debug_trace("zone $zone superzone $super_zone"); $super_zone =~ s/^[^.]+\.// or die "no superzone ? ($super_zone)\n"; - ($rcode,@super_nsnames)= lookup($super_zone,'ns-','06'); + ($rcode,@super_nsnames)= + lookup($super_zone,'ns-','06',"superzone search"); last if !$rcode; } for $super_ns (@super_nsnames) { $super_ns= lc $super_ns; - ($rcode,@super_ns_addrs)= lookup($super_ns,'a','0'); + ($rcode,@super_ns_addrs)= + lookup($super_ns,'a','0',"published nameserver"); foreach $addr (@super_ns_addrs) { push @to_check, $addr, @@ -378,8 +390,8 @@ sub zone_investigate() { sub zone_check_nsrrset ($$$$) { my ($uaddr,$wa, $is_auth, $glueless_ok) = @_; my (@s, $s, %s2g, @glue, $glue, $delgs_or_auths, $wwn, $ww); - verbose("checking delegation by $ww"); $ww= "[$uaddr] $wa"; + verbose("checking delegation by $ww"); dig(sub { if ($dig_type eq 'ns' && $dig_owner eq $zone) { $s2g{lc $dig_rdata} = [ ]; @@ -395,16 +407,18 @@ sub zone_check_nsrrset ($$$$) { zone_warning("unable to find NS RRset at [$uaddr]", $wa); return; } elsif (keys %s2g == 1) { - zone_warning("only one nameserver",$ww); + zone_warning("only one nameserver ". (join '', keys %s2g), + $ww); } @s= sort keys %s2g; foreach $s (@s) { + zone_ns_name($s,$ww); @glue= @{ $s2g{$s} }; if (!@glue) { - zone_warning("glueless NS $s,".($needglue<=1 ? " (eg)" : ""), - $ww) + zone_warning("glueless NS $s", $ww) unless $glueless_ok || !$needglue || - grep { has_suffix_of($s,".$_"); } @conv_glueless; + grep { has_suffix_of($s,".$_"); } + @{ $cfg->{'conv_glueless'} }; next; } $glue= join ' ', sort @glue; @@ -415,22 +429,30 @@ sub zone_check_nsrrset ($$$$) { push @{ $delgs_or_auths->{$s} }, $ww; } -sub zone_server_addr ($$$$$) { - my ($addr,$name,$ww,$wwq,$is_soa) = @_; +sub zone_ns_name ($$) { + my ($name,$ww) = @_; my ($cg); - $addr_is_ok{$addr}= "$name ($wwq)" - if $is_soa || $cfg->{'s'} =~ m/u/; - foreach $cg (@conv_glueless) { - next unless has_suffix_of(".$name",".$cg"); - zone_warning("nameserver [$addr] $name in serverless-glueless". + $delg_to_us=1 if grep { $name eq $_ } @{ $cfg->{'self_ns'} }; + foreach $cg (@{ $cfg->{'conv_glueless'} }) { + zone_warning("nameserver $name in serverless-glueless". " namespace area $cg", - $ww); + $ww) + if has_suffix_of(".$name",".$cg"); } - zone_warning("configured as stealth but we [$addr] $name are published", + zone_warning("published server, as $name, but configured as stealth", $ww) - if $cfg->{'s'} =~ m/u/ && grep { $_ eq $addr } @self_addr; + if $cfg->{'s'} =~ m/u/ && + grep { $_ eq $name } + @{ $cfg->{'self_ns'} }, @{ $cfg->{'self_soa'} }; +} + +sub zone_server_addr ($$$$$) { + my ($addr,$name,$ww,$wwq,$is_soa) = @_; + debug_trace("zone_server_addr ".join '|',@_); + $addr_is_ok{$addr}= "$name ($wwq)" + if $is_soa || $cfg->{'s'} =~ m/u/; zone_warning("forbidden nameserver address [$addr] $name",$ww) - if grep { $_ eq $addr } @forbid_addr; + if grep { $_ eq $addr } @{ $cfg->{'forbid_addr'} }; my ($name_is_self, $addr_is_self); $name_is_self= grep { $_ eq $name } @@ -438,13 +460,20 @@ sub zone_server_addr ($$$$$) { $addr_is_self= grep { $_ eq $addr } @{ $cfg->{'self_addr'} }; if ($name_is_self && !$addr_is_self) { - zone_warning("our name $name with wrong address [$addr]",$ww); - } elsif (!$name_is_self && $addr_is_self) { - zone_warning(($is_soa ? "SOA ORIGIN maps to" : "referral to"). - " us [$addr] with wrong name $name", + zone_warning("our $name supplied with wrong address [$addr]", $ww); + } + if (!$name_is_self && $addr_is_self) { + zone_warning("we [$addr] are named in ". + ($is_soa ? "SOA" : "NS"). + " by wrong name $name", $ww); } - $delg_to_us=1 if $name_is_self; + if (!$name_is_self && !$addr_is_self && + $is_soa && $cfg->{'s'} =~ m/p/) { + zone_warning("SOA ORIGIN $name is not us (". + (join ' ', @{ $cfg->{'self_soa'} }).")", $ww); + } + $delg_to_us=1 if $addr_is_self && !$is_soa; } sub zone_check_soa ($$$) { @@ -459,7 +488,7 @@ sub zone_check_soa ($$$) { } elsif ($dig_type eq 'soa' && $dig_owner eq $zone && !$lame) { die "several SOAs ? $ww" if defined $origin; $got= $dig_rdata; - $got =~ m/^(\S+) \d+/ or die "$got ?"; + $got =~ m/^\d+ (\S+)$/ or die "$got ?"; $origin= $1; } }, @@ -467,7 +496,7 @@ sub zone_check_soa ($$$) { $lame= 'broken' if !$lame && !defined $origin; if ($lame) { zone_warning("$lame server [$uaddr]",$wa); return; } push @{ $soas{$got} }, $ww; - ($rcode,@soa_addrs)= lookup($origin,'a','0'); + ($rcode,@soa_addrs)= lookup($origin,'a','0',"SOA ORIGIN"); $wwn= "SOA ORIGIN from $ww"; foreach $soa_addr (@soa_addrs) { zone_server_addr($soa_addr,$origin,$wwn,"SOA [$uaddr]",1); @@ -483,23 +512,12 @@ sub zone_consistency() { foreach $h (keys %glue) { zone_consistency_set("glue for $h", $glue{$h}); } - zone_consistency_set("SOA ORIGIN and SERIAL",\%soas); + zone_consistency_set("serial number and/or SOA ORIGIN",\%soas); $self_soa= $cfg->{'self_soa'}; - if ($cfg->{'s'} =~ m/p/) { - foreach $org_ser (keys %soas) { - $org_ser =~ m/^(\S+) \d+$/ or die "$org_ser ?"; - $origin= $1; - next if grep { $_ eq $origin } @$self_soa; - foreach $wa (@{ $soas{$org_ser} }) { - zone_warning("SOA ORIGIN $origin is not our name (@$self_soa)", - $wa); - } - } - } } sub zone_servers_ok () { - my ($showok); + my ($showok,%fs); if (%addr_is_ok) { $showok= 0; foreach $a (@{ $cfg->{'servers'} }) { @@ -516,6 +534,8 @@ sub zone_servers_ok () { if ($cfg->{'s'} =~ m/s/ && !$delg_to_us) { zone_warning("we are supposedly published secondary,". " but not listed as a nameserver",''); + map { $fs{$_}=1 } keys(%delgs), keys(%auths); + zone_warnmore("servers are: ". join ' ', sort keys %fs); } } @@ -538,19 +558,23 @@ sub zone_check_local () { sub zone_servers_simplefind () { my ($rcode,@nsnames,$ns,@soas,$origin); - ($rcode,@nsnames)= lookup($zone,'ns-','0'); - foreach $ns (@nsnames) { zone_server_simple($ns,'NS',0); } + ($rcode,@nsnames)= lookup($zone,'ns-','0',"zone's servers"); + foreach $ns (@nsnames) { + zone_ns_name($ns,"NS"); + zone_server_simple($ns,'NS',0); + } - ($rcode,@soas)= lookup($zone,'soa','0'); + ($rcode,@soas)= lookup($zone,'soa','0',"SOA ORIGIN"); die "multiple SOA RRs in set! @soas ?" if @soas!=1; $soas[0] =~ m/^(\S+)\s/ or die "SOA ? $_"; - zone_server_simple(domain_canon($1),'SOA',1); + zone_server_simple(domain_canon($1,"lookup $zone SOA"),'SOA',1); } sub zone_server_simple ($$$) { my ($name,$ww,$is_soa) = @_; my ($rcode,@addrs,$addr); - ($rcode,@addrs)= lookup($name,'a','0'); + ($rcode,@addrs)= lookup($name,'a','0', "server - ". + ($is_soa ? "SOA ORIGIN" : "NS")); foreach $addr (@addrs) { zone_server_addr($addr,$name,$ww,$ww,$is_soa); } } @@ -633,14 +657,16 @@ sub debug_trace ($) { } sub has_suffix_of ($$) { - my ($whole,$suffix); + my ($whole,$suffix) = @_; + debug_trace("has_suffix_of $whole $suffix"); return 0 if length $whole < length $suffix; return 0 if substr($whole, length($whole) - length($suffix)) ne $suffix; + debug_trace("has_suffix_of $whole $suffix YES"); return 1; } -sub lookup ($$$) { - my ($domain,$type,$okrcodes) = @_; +sub lookup ($$$$) { + my ($domain,$type,$okrcodes,$w) = @_; my ($c,$h,@result); debug_trace("lookup ==> (->$okrcodes) $domain $type"); $h= new IO::Handle; @@ -655,17 +681,16 @@ sub lookup ($$$) { $h->error and die "$quis: read from adnshost:\n $!\n"; chomp @result; $!=0; $h->close; - die "$quis: lookup -t$type $domain $okrcodes failed $? $! @result\n" + die "$quis: lookup -t$type $domain $okrcodes ($w) failed $? $! @result\n" if $! or $?&255 or $?>1536 or index($okrcodes,$?>>8)<0; debug_trace("lookup <== $? @result"); return ($?,@result); } - sub dig (&$$$) { my ($eachrr, $qowner,$qtype,$qaddr) = @_; # also pseudo-rr with type `flags:' - my ($h,$inmid,$irdata,$c); + my ($h,$inmid,$irdata,$c,$digwhy); local ($_); debug_trace("dig ==> \@$qaddr $qowner $qtype"); @@ -694,6 +719,7 @@ sub dig (&$$$) { s/$/ \(/ unless s/\s*\)\s*$//; } if (s/\s*\(\s*$//) { $inmid= $_; next; } + $digwhy= "dig $qowner $qtype $qaddr \`$_'"; if (m/^\;\; flags\:( [-0-9a-z ]+)\;/) { $dig_owner=''; $dig_type='flags:'; $dig_rdata= "$1 "; debug_trace("dig f: $dig_rdata"); @@ -701,17 +727,17 @@ sub dig (&$$$) { } elsif (m/^\;/) { } elsif (!m/\S/) { } elsif (m/^([-.0-9a-z]+)\s+\d\w+\s+in\s+([a-z]+)\s+(\S.*)/i) { - $dig_owner=domain_canon($1); $dig_type=lc $2; $irdata=$3; + $dig_owner=domain_canon($1,$digwhy); $dig_type=lc $2; $irdata=$3; if ($dig_type eq 'a') { $irdata =~ m/^[.0-9]+$/ or die "$irdata ?"; $dig_rdata= $&; } elsif ($dig_type eq 'ns') { $irdata =~ m/^[-.0-9a-z]+$/i or die "bad nameserver $irdata ?"; - $dig_rdata= domain_canon($irdata); + $dig_rdata= domain_canon($irdata,$digwhy); } elsif ($dig_type eq 'soa') { $irdata =~ m/^([-.0-9a-z]+)\s+.*\s+(\d+)(?:\s+\d\w+){4}$/i or die "bad SOA $irdata ?"; - $dig_rdata= domain_canon($1).' '.$2; + $dig_rdata= $2.' '.domain_canon($1,$digwhy); } else { debug_trace("ignoring uknown RR type $dig_type"); next; @@ -726,9 +752,10 @@ sub dig (&$$$) { debug_trace("dig <== gave $?"); } -sub domain_canon ($) { - local ($_) = @_; - s/(.)\.$/$1/; - die "domain $_ ?" unless m/^[0-9a-z]/i; - return lc $_; +sub domain_canon ($$) { + my ($i,$w) = @_; + $i =~ s/(.)\.$/$1/; + return '.' if $i eq '.'; + die "domain $i ($w) ?" unless $i =~ m/^[0-9a-z]/i; + return lc $i; }