X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-utils.git;a=blobdiff_plain;f=scripts%2Fnamed-conf;h=0a91daf7e18db286bec1a510cbccbbf26dda5c11;hp=39bee7f9ae35c2e949077549ae752c91845b5221;hb=f8ddd2789c8752cd919a9f9d5f1e05d615ceff1a;hpb=e9ff70ef02494d7716aed0a63898e77ffcf73dbb diff --git a/scripts/named-conf b/scripts/named-conf index 39bee7f..0a91daf 100755 --- a/scripts/named-conf +++ b/scripts/named-conf @@ -1,4 +1,19 @@ #!/usr/bin/perl -w +# This is chiark-named-conf, which is Copyright 2002 Ian Jackson. +# +# chiark-named-conf and its manpage are free software; you can +# redistribute it and/or modify them under the terms of the GNU +# General Public License as published by the Free Software Foundation; +# either version 2, or (at your option) any later version. +# +# chiark-named-conf and its manpage are distributed in the hope that +# it will be useful, but WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. use strict; use IO::File; @@ -6,7 +21,51 @@ use Data::Dumper; use POSIX; use Fcntl qw(:DEFAULT :flock); -use vars qw($quis +# bastard Perl wants me to do this now ! +sub loarg(); +sub soarg(); +sub usageerr ($); +sub cfg_fail ($); +sub read_config ($); +sub qualify ($); +sub bad_modifiers ($); +sub zone_conf ($$$$$@); +sub set_output($); +sub progress ($$); +sub verbose ($); +sub process_zones (@); +sub zone_warning ($$); +sub zone_warnmore ($); +sub zone_check_full (); +sub zone_reset(); +sub zone_investigate(); +sub zone_check_nsrrset ($$$$); +sub zone_ns_name ($$); +sub zone_server_queue ($$$$$); +sub zone_server_addr ($$$$$); +sub zone_check_soa ($$$$); +sub zone_consistency(); +sub zone_servers_ok (); +sub zone_consistency_set ($%); +sub zone_check_local (); +sub zone_servers_simplefind (); +sub zone_server_simple ($$$); +sub zone_style ($$); +sub mail_zone_before (); +sub mail_zone_after (); +sub pmail ($); +sub ptime ($); +sub mail_zone_mail (); +sub zone_output (); +sub output_files (); +sub debug_dump ($); +sub debug_trace ($); +sub has_suffix_of ($$); +sub lookup ($$$$); +sub dig (&$$$); +sub domain_canon ($$); + +use vars qw($quis $stdout_fh $stderr_fh $mode $doall $domail $etcfile $where $debug $needglue $localonly $repeat $verbosity @@ -27,10 +86,14 @@ $verbosity= 2; $admin=''; $mail_state_dir=''; $mail_max_warnfreq= 50; $repeat= 0; $domail= ''; -$progress_fh= 'STDOUT'; -$warn_fh= 'STDERR'; $modifiers= ''; +$group2modcmd{'foreign'}= '*$!@?'; +$group2used{'foreign'}= 1; +($progress_fh= $stdout_fh= new_from_fd IO::Handle(1,'w') and + $warn_fh= $stderr_fh = new_from_fd IO::Handle(2,'w')) + or die "$quis: setup standard filehandles: $!\n"; + use vars qw($dig_owner $dig_type $dig_rdata); while (@ARGV && $ARGV[0] =~ m/^\-/) { @@ -39,7 +102,7 @@ while (@ARGV && $ARGV[0] =~ m/^\-/) { last if m/^$/; if (m/^(yes|no|force)$/) { m/^./; $mode= $&; $domail=''; } elsif (m/^nothing$/) { $mode= 'x'; $domail=''; } - elsif (m/^mail\-(first|middle|final|final-test)/) { + elsif (m/^mail\-(first|middle|final|final\-test)$/) { $mode='n'; $domail=$1; } @@ -81,7 +144,7 @@ usageerr("-q may be specified at most twice") if $verbosity<0; usageerr("-v may be specified at most once") if $verbosity>3; usageerr("-D may be specified at most twice") if $debug>2; usageerr("must specify either -f|-y|-n or zones (and not both)") - if !!$mode == !!@ARGV; + if !!$mode == !!@ARGV && !$domail; sub usageerr ($) { die <close or die "$quis: write messages to stdout: $!\n"; +$stderr_fh->close or die "$quis: write messages to stderr: $!\n"; exit 0; #-------------------- configuration reading @@ -270,7 +335,7 @@ sub bad_modifiers ($) { local ($_) = @_; if (!eval { die "bad modifier $&" if m/[^!*\$\@~?]/; - die "repeated modifier $1" if m/(.).*$1/; + die "repeated modifier $1" if m/(.).*\1/; 1; }) { $@ =~ s/\n//; @@ -314,7 +379,7 @@ sub zone_conf ($$$$$@) { $zone_cfg{$zone}{$sfx}= $aref; } foreach $sfx (qw(self_soa self_ns)) { - $zone_cfg{$zone}{$sfx} =~ s/\*$/$zone/; + map { s/\*$/$zone/ } @{ $zone_cfg{$zone}{$sfx} }; } $zone_cfg{$zone}{'output'}= $output; push @zone_cfg_list, $zone; @@ -346,11 +411,12 @@ sub process_zones (@) { foreach $zone (@zones) { $cfg= $zone_cfg{$zone} || { 'style_p' => 'foreign', - 's' => 'f', + 's' => "f $group2modcmd{'foreign'}", 'servers' => [ ], }; - mail_zone_before() if $domail; + mail_zone_before() or next + if $domail; zone_reset(); progress(1, sprintf "%-20s %s", $zone, $$cfg{'style_p'}); if ($check && ($doall || !zone_style('?',0))) { @@ -700,14 +766,14 @@ sub mail_zone_before () { for (;;) { $m_lock= new IO::File "${m_base}_lock", O_RDWR|O_CREAT, 0600 - or die "$quis: create lockfile ${m_base}_lock"; + or die "$quis: create lockfile ${m_base}_lock: $!\n"; if (!flock($m_lock, LOCK_EX|LOCK_NB)) { <$m_lock> =~ m/^\d+ /; die "$quis: $zone: concurrrency? - flock $&$!\n"; $m_lock->close; - next; + return 0; } - (@s1= $m_lock->fstat) or die "$quis: fstat ${m_base}_lock: $!\n"; + (@s1= $m_lock->stat) or die "$quis: fstat ${m_base}_lock: $!\n"; (@s2= stat "${m_base}_lock") or die "$quis: stat ${m_base}_lock: $!\n"; last if ($s1[0] eq $s2[0] && $s1[1] eq $s2[1]); @@ -726,17 +792,17 @@ sub mail_zone_before () { if ($2 eq ':' && $3 eq ':') { warn "$quis: $zone: mid/last run, but last". "run already done, ignoring zone\n"; - next; + return 0; } @m_ok= split /\:/, $2; @m_fail= split /\:/, $3; } } elsif ($! != &ENOENT) { die "$quis: open ${m_base}_info: $!\n"; - } elsif ($domail eq 'first') { + } elsif ($domail ne 'first') { warn "$quis: $zone: first run, but not --mail-first,". " ignoring zone\n"; - next; + return 0; } if ($domail eq 'first') { remove "${m_base}_history" or $!==&ENOENT @@ -749,6 +815,7 @@ sub mail_zone_before () { $m_time= time; progress(-1, "\n".('-'x70)."\n".ptime($m_time)."\n"); + return 1; } sub mail_zone_after () { @@ -761,18 +828,25 @@ sub mail_zone_after () { progress(-1,"everything is fine"); } close $progress_fh or die "$quis: close ${m_base}_history: $!\n"; - $progress_fh= $warn_fh= 'STDERR'; + $progress_fh= $warn_fh= $stderr_fh; if ($domail =~ m/^final/) { if (100*@m_fail <= $$cfg{'mailmwarn'}*(@m_fail + @m_ok)) { - printf " %-40s ok\n" or die "$quis: mail ok report: $!\n"; + printf " %-40s ok\n", $zone or die "$quis: mail ok report: $!\n"; } elsif (zone_style('@',0)) { - printf " %-40s mail suppressed\n" + printf " %-40s mail suppressed\n", $zone or die "$quis: mail suppress report: $!\n"; } else { mail_zone_mail(); } - } + } else { + printf " %-40s %d warns. OK %s Fail %s\n", + $zone, + defined $zone_warnings{$zone} ? $zone_warnings{$zone} : 0, + join(',', map { $_ - $m_time } @m_ok), + join(',', map { $_ - $m_time } @m_fail) + or die "$quis: checking progress report: $!\n"; + } @m_fail= @m_ok= ('','') if $domail =~ m/^final/; @@ -797,15 +871,15 @@ sub ptime ($) { } sub mail_zone_mail () { - my ($log, $zone_to, $zterr, $c, $r, $t); + my ($log, $zone_to, $zterr, $c, $r, $t, @soas); $m_m= new IO::File "${m_base}_mail", 'w', 0666 or die "$quis: create ${m_base}_mail: $!\n"; $zone_to=''; $zterr=''; - if (!zone_style("\$",$$cfg{'s'} =~ m/u/)) { + if (!zone_style("\$", $$cfg{'s'} !~ m/[ps]/)) { eval { - $_= lookup($zone,'soa','0','problem-addr'); - m/\n\n/ and die "multiple soas\n"; - m/^\S+ (\S.*\@\S+) [0-9 ]+$/ or + ($r,@soas)= lookup($zone,'soa','0','problem-addr'); + @soas==1 or die "multiple soas\n"; + $soas[0] =~ m/^\S+ (\S.*\@\S+) [0-9 ]+$/ or die "bad soa \`$_'\n"; $zone_to= $1; }; @@ -813,7 +887,7 @@ sub mail_zone_mail () { $zterr =~ s/\n$//; } pmail < +From: zone checker <$$cfg{'admin'}> Subject: $zone - configuration problems report END ; @@ -842,7 +916,7 @@ if length $zterr; The zone has had configuration errors or persistent operational problems during recent checks. See the logs below for details. -Check history for $zone: +Recent check history for $zone: END ; if ($m_lastok ne '-') { @@ -851,7 +925,7 @@ END pmail(" No record of this zone ever being fine.\n"); } for $t (@m_fail) { - pmail(" Errors/warnings at: ".ptime($t)."\n"); + pmail(" Zone had problems at: ".ptime($t)."\n"); } for $t (@m_ok) { pmail(" Everything in order at: ".ptime($t)."\n"); @@ -860,18 +934,20 @@ END $log= new IO::File "${m_base}_history",'r' or die "$quis: reopen ${m_base}_history: $!"; undef $/; - pmail($log); + pmail($log->getline); $/= "\n"; - $log->error && $log->close - or die "$quis: reread or close ${m_base}_log: $!"; + (!$log->error and $log->close) + or die "$quis: reread or close ${m_base}_log: $!\n"; + $log->eof or die; $m_m->close or die "$quis: close ${m_base}_mail: $!\n"; $m_m= new IO::File "${m_base}_mail" or die "$quis: reopen ${m_base}_mail: $!"; defined($c= fork) or die "$quis: fork for mail: $!\n"; if (!$c) { - open STDIN, "<& ${m_m}" or die "$quis - sendmail: dup for stdin: $!\n"; - exec (qw(/usr/sbin/sendmail -odq -oee -oi), + defined dup2($m_m->fileno, 0) + or die "$quis - sendmail: dup for stdin: $!\n"; + exec (qw(/usr/sbin/sendmail -odb -oee -oi), ($domail eq 'final' ? '-t' : $$cfg{'admin'})); die "$quis - sendmail: exec: $!\n"; } @@ -880,8 +956,9 @@ END $r == $c or die "$quis: waitpid sendmail ($c): $r $!"; $? and warn "$quis: sendmail failed: $?\n"; - printf " %-40s %s\n", $zone, $zone_to or - die "$quis: write mailing report: $!\n"; + printf " %-40s %s\n", $zone, + length $zone_to ? $zone_to : 'reporting to admin' + or die "$quis: write mailing report: $!\n"; } #-------------------- outputting