use IO::File;
use Data::Dumper;
-use vars qw($etcfile $where);
-$etcfile= "/etc/bind/chiark-conf-gen.zones";
-$where= '<built-in>';
+use vars qw($quis $mode
+ $etcfile $where
+ $debug $needglue $localonly $verbosity);
+
+$quis= $0; $quis =~ s,.*/,,;
-use vars qw($mode $verbosity $debug $needglue $localonly);
$mode= '';
-$verbosity= 1;
+$etcfile= "/etc/bind/chiark-conf-gen.zones";
+$where= '<built-in>';
$debug= 0;
-$needglue= 0;
+$needglue= 1;
$localonly= 0;
+$verbosity= 1;
use vars qw($dig_owner $dig_type $dig_rdata);
$_= shift @ARGV;
if (s/^\-\-//) {
last if m/^$/;
- if (m/^quiet$/) { $verbosity=0; }
- elsif (m/^verbose$/) { $verbosity=2; }
- elsif (m/^(yes|no|force)$/) { m/^./; $mode= $&; }
+ if (m/^(yes|no|force)$/) { m/^./; $mode= $&; }
elsif (m/^config$/) { $etcfile= loarg(); $where= '--config option'; }
+ elsif (m/^glueless$/) { $needglue=0; }
+ elsif (m/^localonly$/) { $localonly=1; }
+ elsif (m/^quiet$/) { $verbosity=0; }
+ elsif (m/^verbose$/) { $verbosity=2; }
else { usageerr("unknown option --$_"); }
} else {
s/^\-//;
last if m/^$/;
while (m/^./) {
if (s/^[ynf]//) { $mode=$&; }
- elsif (s/^v//) { $verbosity=2; }
- elsif (s/^q//) { $verbosity=0; }
+ elsif (s/^C//) { $etcfile= soarg(); $where= '-C option'; }
elsif (s/^D//) { $debug++; }
elsif (s/^g//) { $needglue=0; }
- elsif (s/^C//) { $etcfile= soarg(); $where= '-C option'; }
+ elsif (s/^l//) { $localonly=1; }
+ elsif (s/^q//) { $verbosity=0; }
+ elsif (s/^v//) { $verbosity=2; }
else { usageerr("unknown option -$&"); }
}
}
process_zones($mode ? @zone_cfg_list : @ARGV);
debug_dump('%output_contents');
+exit 0;
#-------------------- configuration reading
-sub cfg_fail ($) { die "$0: $where:\n $_[0]\n"; }
+sub cfg_fail ($) { die "$quis: $where:\n $_[0]\n"; }
sub read_config ($) {
my ($if) = @_;
};
progress(sprintf "%-40s %s", $zone, $$cfg{'style'});
if ($check) {
- eval { zone_check() };
+ eval {
+ if ($localonly && $cfg->{'style'} eq 'foreign') {
+ zone_warning("foreign zone specified with -l");
+ } elsif ($localonly && $cfg->{'style'} ne 'primary') {
+ zone_check_local();
+ } else {
+ zone_check_full();
+ }
+ };
zone_warning("checks failed: $@") if length $@;
}
zone_output() if $install;
}
+ print STDERR "$quis: $warnings warnings\n" or die $!
+ if $warnings;
}
sub zone_warning ($) {
use vars qw(@to_check); # ($addr,$whyask,$is_auth,$glueless_ok, ...)
use vars qw(@to_check_soa); # ($addr,$whyask, ...)
-sub zone_check () {
- my ($super_zone, @super_nsnames,
- $super_ns, @super_ns_addrs, $s, $wa, $is_auth,
- %nsrrset_checked, %soa_checked, $addr, $glueless_ok, $rcode);
+sub zone_check_full () {
+ zone_reset();
+ zone_investigate();
+ zone_consistency();
+ zone_servers_ok();
+}
+sub zone_reset() {
%delgs= %auths= %glue= %soas= %addr_is_ok= ();
@to_check= @to_check_soa= ();
+}
+
+sub zone_investigate() {
+ my ($super_zone, @super_nsnames,
+ $super_ns, @super_ns_addrs, $s, $wa, $is_auth,
+ %nsrrset_checked, %soa_checked, $addr, $glueless_ok, $rcode);
$super_zone= $zone;
for (;;) {
last;
}
}
- zone_consistency();
}
sub zone_check_nsrrset ($$$$) {
foreach $s (@s) {
@glue= @{ $s2g{$s} };
if (!@glue) {
- zone_warning("glueless NS $s, from $ww") unless $glueless_ok;
+ zone_warning("glueless NS $s, from $ww")
+ unless $glueless_ok || !$needglue;
next;
}
$glue= join ' ', sort @glue;
}
sub zone_consistency() {
- my ($d, $org_ser, $origin, $a, $showok, $h);
+ my ($d, $org_ser, $origin, $a, $h);
zone_consistency_set('delegations',\%delgs);
foreach $d (keys %delgs) { delete $auths{$d}; }
zone_consistency_set('zone nameserver rrset',\%auths);
" eg from ".((values %{ $soas{$org_ser} })[1]));
}
}
+}
+
+sub zone_servers_ok () {
+ my ($showok);
if (%addr_is_ok) {
$showok= 0;
foreach $a (@{ $cfg->{'servers'} }) {
}
}
+sub zone_check_local () {
+ zone_reset();
+ zone_servers_simplefind();
+ zone_servers_ok();
+}
+
+sub zone_servers_simplefind () {
+ my ($rcode,@nsnames,$ns,@soas,$origin);
+ if ($cfg->{'style'} eq 'stealth') {
+ ($rcode,@nsnames)= lookup($zone,'ns-','0');
+ foreach $ns (@nsnames) { zone_server_simple($ns,'NS'); }
+ }
+ ($rcode,@soas)= lookup($zone,'soa','0');
+ 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');
+}
+
+sub zone_server_simple ($$) {
+ my ($name,$why) = @_;
+ my ($rcode,@addrs,$addr);
+ ($rcode,@addrs)= lookup($name,'a','0');
+ foreach $addr (@addrs) { $addr_is_ok{$addr}= "$name ($why)"; }
+}
#-------------------- outputting
debug_trace("lookup ==> (->$okrcodes) $domain $type");
$h= new IO::Handle;
- defined($c= open $h, "-|") or die "$0: fork adnshost:\n $!\n";
+ defined($c= open $h, "-|") or die "$quis: fork adnshost:\n $!\n";
if (!$c) {
exec 'adnshost','-Fi','+Do','+Dt','+Dc','-Cf',"-t$type",
'-',"$domain.";
- die "$0: exec adnshost:\n $!\n";
+ die "$quis: exec adnshost:\n $!\n";
}
@result= $h->getlines();
- $h->error and die "$0: read from adnshost:\n $!\n";
+ $h->error and die "$quis: read from adnshost:\n $!\n";
chomp @result;
$!=0; $h->close;
- die "$0: lookup -t$type $domain $okrcodes failed $? $!\n"
+ die "$quis: lookup -t$type $domain $okrcodes failed $? $!\n"
if $! or $?>6 or index($okrcodes,$?)<0;
debug_trace("lookup <== $? @result");
return ($?,@result);
debug_trace("dig ==> \@$qaddr $qowner $qtype");
$h= new IO::Handle;
- defined($c= open $h, "-|") or die "$0: fork dig:\n $!\n";
+ defined($c= open $h, "-|") or die "$quis: fork dig:\n $!\n";
if (!$c) {
open STDERR, ">&STDOUT" or die $!;
exec ('dig',
'+nodef','+nosea','+nodebug','+norecurse',
"\@$qaddr",'-t',$qtype,$qowner);
- die "$0: exec dig:\n $!\n";
+ die "$quis: exec dig:\n $!\n";
}
$inmid='';
for (;;) {
if (!defined($_= $h->getline())) {
- $h->error() and die "$0: read from dig:\n $!\n";
+ $h->error() and die "$quis: read from dig:\n $!\n";
last;
}
chomp;
sub domain_canon ($) {
local ($_) = @_;
s/(.)\.$/$1/;
+ die "domain $_ ?" unless m/^[0-9a-z]/i;
return lc $_;
}
sub lookup1 ($$) {
my ($type,$domain) = @_;
my (@result)= lookup($type,$domain);
- @result==1 or die "$0: lookup -t$type $domain gave more than one RR\n";
+ @result==1 or die "$quis: lookup -t$type $domain gave more than one RR\n";
return $result[0];
}
for $super_ns (@super_ns) {
@deleg_ns= ();
open DIG, "dig @$super_ns. -t ns +norecurse $zone."
- or die "$0: fork for dig:\n $!\n";
+ or die "$quis: fork for dig:\n $!\n";
while (<DIG>) {
endfile
-chdir "$base/primary" or die "$0: chdir $base/primary:\n $!";
+chdir "$base/primary" or die "$quis: chdir $base/primary:\n $!";
beginfile('primary.zones');
for $f (<*_db>) {
sub beginfile ($) {
$currentfile= $_[0];
$currentfile_opened= $install ? "$conf/$currentfile.new" : "/dev/null";
- open CFF, "> $toopen" or die "$0: begin $currentfile_opened:\n $!\n";
+ open CFF, "> $toopen" or die "$quis: begin $currentfile_opened:\n $!\n";
}
endfile () {
- close CFF or die "$0: close $currentfile_opened:\n $!\n";
+ close CFF or die "$quis: close $currentfile_opened:\n $!\n";
push @files, $currentfile;
}
sub installfiles () {
return unless $install;
- chdir $conf or die "$0: chdir $conf:\n $!\n";
+ chdir $conf or die "$quis: chdir $conf:\n $!\n";
for $f (@files) {
- rename "$f.new", $f or die "$0: install new $f:\n $!\n";
+ rename "$f.new", $f or die "$quis: install new $f:\n $!\n";
}
}