+ $glue= join ' ', sort @glue;
+ push @{ $glue{$s}{$glue} }, $ww;
+ }
+ $s= join ' ', @s;
+ $delgs_or_auths= defined($name_if_auth) ? \%auths : \%delgs;
+ push @{ $delgs_or_auths->{$s} }, $ww;
+}
+
+sub zone_ns_name ($$) {
+ my ($name,$ww) = @_;
+ $delg_to_us=1 if grep { $name eq $_ } @{ $cfg->{'self_ns'} };
+ zone_warning("published server, as $name, but configured as stealth",
+ $ww)
+ if $cfg->{'s'} =~ m/u/ &&
+ grep { $_ eq $name }
+ @{ $cfg->{'self_ns'} }, @{ $cfg->{'self_soa'} };
+}
+
+sub zone_server_queue ($$$$$) {
+ my ($addr,$name,$wwn,$wwq,$is_soa) = @_;
+ zone_server_addr($addr,$name,$wwn,$wwq,$is_soa);
+ push @to_check, $addr, "$name, $wwn", $name, $is_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 } @{ $cfg->{'forbid_addr'} };
+ zone_warning("forbidden server address for our slave [$addr] $name",$ww)
+ if $cfg->{'s'} =~ m/p/ and
+ grep { $_ eq $addr } @{ $cfg->{'forbid_slave'} };
+
+ my ($name_is_self, $addr_is_self);
+ $name_is_self= grep { $_ eq $name }
+ @{ $cfg->{$is_soa ? 'self_soa' : 'self_ns'} };
+ $addr_is_self= grep { $_ eq $addr }
+ @{ $cfg->{'self_addr'} };
+ if ($name_is_self && !$addr_is_self) {
+ 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);
+ }
+ if (!$name_is_self && !$addr_is_self &&
+ $is_soa && $cfg->{'s'} =~ m/p/) {
+ zone_warning("SOA MNAME $name is not us (".
+ (join ' ', @{ $cfg->{'self_soa'} }).")", $ww);
+ }
+ $delg_to_us=1 if $addr_is_self && !$is_soa;
+}
+
+sub zone_check_soa ($$$$) {
+ my ($uaddr,$wa,$name,$is_ns) = @_;
+ my ($lame,$serial,$mname,$got,$rcode,@soa_addrs,$soa_addr,$ww,$wwn);
+ verbose("checking service at [$uaddr] $name");
+ $lame= 'dead or lame';
+ $ww= "[$uaddr] $wa";
+ dig(sub {
+ if ($dig_type eq 'flags:') {
+ $lame= $dig_rdata =~ m/ aa / ? '' : 'lame';
+ } elsif ($dig_type eq 'soa' && $dig_owner eq $zone && !$lame) {
+ die "several SOAs ? $ww" if defined $mname;
+ $got= $dig_rdata;
+ $got =~ m/^(\d+) (\S+)$/ or die "$got ?";
+ ($serial,$mname) = ($1,$2);
+ }
+ },
+ $zone,'soa',$uaddr);
+ $lame= 'broken' if !$lame && !defined $mname;
+ if ($lame) { zone_warning("$lame server [$uaddr]",$wa); return; }
+ progress(2, sprintf "%-16s %46s has %s%s",
+ $zone, "$name [$uaddr]", $serial, $is_ns ? '' : '*');
+ push @{ $soas{$got} }, $ww;
+ ($rcode,@soa_addrs)= lookup($mname,'a','0',"SOA MNAME");
+ $wwn= "SOA MNAME from $ww";
+ foreach $soa_addr (@soa_addrs) {
+ zone_server_queue($soa_addr,$mname,$wwn,"SOA [$uaddr]",1);
+ }
+}
+
+sub zone_consistency() {
+ my ($d, $org_ser, $mname, $a, $h, $self_soa, $wa);
+ zone_consistency_set('delegations',\%delgs);
+ foreach $d (keys %delgs) { delete $auths{$d}; }
+ zone_consistency_set('zone nameserver rrset',\%auths);
+ foreach $h (keys %glue) {
+ zone_consistency_set("glue for $h", $glue{$h});
+ }
+ zone_consistency_set("serial number and/or SOA MNAME",\%soas);
+ $self_soa= $cfg->{'self_soa'};
+}
+
+sub zone_servers_ok () {
+ my ($showok,%fs);
+ if (%addr_is_ok) {
+ $showok= 0;
+ foreach $a (@{ $cfg->{'servers'} }) {
+ next if exists $addr_is_ok{$a};
+ zone_warning("we slave from [$a]",'')
+ and $showok=1;
+ }
+ if ($showok) {
+ foreach $a (keys %addr_is_ok) {
+ zone_warnmore("permitted master [$a] $addr_is_ok{$a}");
+ }
+ }
+ }
+ 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);
+ }
+}
+
+sub zone_consistency_set ($%) {
+ my ($msg,$set) = @_;
+ my ($d,$o);
+ if (keys(%$set) > 1) {
+ zone_warning("inconsistent $msg:",'');
+ foreach $d (keys %$set) {
+ foreach $o (@{ $set->{$d} }) { zone_warnmore(" $d from $o"); }
+ }
+ }
+}
+
+sub zone_check_local () {
+ zone_servers_simplefind();
+ zone_servers_ok();
+}
+
+sub zone_servers_simplefind () {
+ my ($rcode,@nsnames,$ns,@soas,$mname);
+
+ ($rcode,@nsnames)= lookup($zone,'ns-','0',"zone's servers");
+ foreach $ns (@nsnames) {
+ zone_ns_name($ns,"NS");
+ zone_server_simple($ns,'NS',0);
+ }
+ $delgs{join ' ', sort @nsnames} = [ "zone's servers" ];
+
+ ($rcode,@soas)= lookup($zone,'soa','0',"SOA MNAME");
+ die "multiple SOA RRs in set! @soas ?" if @soas!=1;
+ $soas[0] =~ m/^(\S+)\s/ or die "SOA ? $_";
+ 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', "server - ".
+ ($is_soa ? "SOA MNAME" : "NS"));
+ foreach $addr (@addrs) { zone_server_addr($addr,$name,$ww,$ww,$is_soa); }
+}
+
+sub zone_style ($$) {
+ my ($stylechar, $default) = @_;
+ local ($_) = $$cfg{'s'};
+ $stylechar =~ s/\W/\\$&/ or die;
+ return m/(\S*)$stylechar/ ? $1 !~ m/\!/ : $default;
+}
+
+#-------------------- mailing
+
+use vars qw($m_base $m_lastok @m_ok @m_fail
+ $m_info $m_time $m_lock $m_m);