diff -r 1cea07056124 -r d1addc2ec712 update-zone --- a/update-zone Thu Aug 12 10:18:58 2010 +0200 +++ b/update-zone Fri Aug 13 10:09:37 2010 +0200 @@ -1,23 +1,40 @@ -#!/usr/bin/perl +#! /usr/bin/perl +# (c) 1998 Heiko Schlittermann +# +# … work in progress do integrate dnssec (branch suess) +# +# Update the serial numbers in zone files +# The serial number needs to match a specified pattern (see +# the line marked w/ PATTERN. +# +# ToDo: +# . test against an md5 sum, not just the date of the stamp file +# . FIXME: handle `/' in file names (currently only working in +# the current directory) +# . optionally reload the named use strict; +use warnings; + +use File::Basename; +use File::Copy; use FindBin; -# liest die Konfiguration ein my @configs = ( "$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf" ); my @dnssec_signs = ( "$FindBin::Bin/dnssec-sign", "/usr/bin/dnstools/dnssec-sign" ); my %config; my $dnssec_sign; +my @change_names = (); -for ( grep {-f} @configs ) { +foreach ( grep {-f} @configs ) { open( CONFIG, $_ ) or die "Can't open $_: $!\n"; } + unless ( seek( CONFIG, 0, 0 ) ) { die "Can't open config (searched: @configs)\n"; } - -for ( grep {-f} @dnssec_signs ) { +foreach ( grep {-f} @dnssec_signs ) { if ( -x $_ ) { $dnssec_sign = $_; } @@ -41,84 +58,202 @@ my $conf_dir = $config{zone_conf_dir}; my $master_dir = $config{master_dir}; -unless ( -d $master_dir and -r $master_dir ) { - die "$master_dir: $!\n"; +my $ME = basename $0; +my @tmpfiles; +my $verbose = 0; +my $opt_yes = 0; +my @Zones; +my $file; + +sub cleanup() { unlink @tmpfiles; } +END { cleanup(); } + +for (@ARGV) { + if ( $_ eq "-y" ) { + $opt_yes = 1; + shift @ARGV; + } } -unless ( -d $bind_dir and -r $bind_dir ) { - die "$bind_dir: $!\n"; -} +@Zones = @ARGV ? @ARGV : glob("$master_dir/*"); -# dnssec - new sign -system "$dnssec_sign"; -die "$dnssec_sign not found ($!)" if $? == -1; -exit 1 if $?; +MAIN: { + my $changed; + my ( $dd, $mm, $yy ) = ( localtime() )[ 3 .. 5 ]; + my $date; + $mm++; -# prueft jede domain, die ein verzeichnis in $master_dir hat, ob es eine -# datei $zone_file.signed gibt und ob diese datei in $config_file eingetragen -# ist. -# passt die eintraege in $config_file falls noetig an. -while (<$master_dir/*>) { - s#($master_dir/)(.*)#$2#; - my $zone = $_; + # fuehrt automatische aktuallisierungen der zonen durch + system "$dnssec_sign"; + + # prueft jede domain, die ein verzeichnis in $master_dir hat, ob sie + # dnssec nutzt. + # passt die eintraege in $config_file falls noetig an. + while (<$master_dir/*>) { + s#($master_dir/)(.*)#$2#; + my $zone = $_; - my $zone_file = "$master_dir/$zone/$zone"; - my $conf_file = "$conf_dir/$zone"; - my @c_content; + my $zone_file = "$master_dir/$zone/$zone"; + my $conf_file = "$conf_dir/$zone"; + my @c_content; + + unless ( -f "$conf_file" ) { + die "$conf_file: $! \n"; + } + + if ( -e "$master_dir/$zone/.keycounter" ) { + + open( FILE, "<$conf_file" ) or die "$conf_file: $!\n"; + @c_content = ; + close(FILE); - unless ( -f "$conf_file" ) { - die "$conf_file: $! \n"; - } + for (@c_content) { + if (m{(.*)($zone_file)(";)}) { + print "$2 ==> $2.signed\n"; + $_ = "$1$2.signed$3\n"; + } - if ( -f "$zone_file.signed" ) { + open( FILE, ">$conf_file" ) or die "$conf_file: $!\n"; + print FILE @c_content; + close(FILE); - open( FILE, "<$conf_file" ) or die "$conf_file: $!\n"; - @c_content = ; - close(FILE); + } + } + else { + + open( FILE, "<$conf_file" ) or die "$conf_file: $!\n"; + @c_content = ; + close(FILE); - for (@c_content) { - if (m{(.*)($zone_file)(";)}) { - print "$2 ==> $2.signed\n"; - $_ = "$1$2.signed$3\n"; + for (@c_content) { + if (m{(.*)($zone_file)\.signed(.*)}) { + print "$2.signed ==> $2\n"; + $_ = "$1$2$3\n"; + } } - + open( FILE, ">$conf_file" ) or die "$conf_file: $!\n"; print FILE @c_content; close(FILE); - } } - else { + + # erzeugt eine named.conf-datei aus den entsprechenden vorlagen. + open( TO, ">$bind_dir/named.conf.zones" ) + or die "$bind_dir/named.conf.zones: $!\n"; + while (<$conf_dir/*>) { + open( FROM, "$_" ) or die "$_: $! \n"; + print TO ; + close(FROM); + } + close(TO); - open( FILE, "<$conf_file" ) or die "$conf_file: $!\n"; - @c_content = ; - close(FILE); + # update-serial + foreach ( $dd, $mm ) { s/^\d$/0$&/; } + $yy += 1900; + $date = "$yy$mm$dd"; + + while ( my $file = shift @Zones ) { + + my $file_basename = basename($file); + + $file =~ s#($master_dir)(/.*)#$1$2$2#; + local ( *I, *O ); + my $done = 0; + + my $new = "$file.$$.tmp"; + my $bak = "$file.bak"; + my $stamp = $master_dir . "/.stamp/" . basename($file); - for (@c_content) { - if (m{(.*)($zone_file)\.signed(.*)}) { - print "$2.signed ==> $2\n"; - $_ = "$1$2$3\n"; - } + $file =~ /(\.bak|~)$/ and next; + $file !~ /\./ and next; + + $verbose && print "$file:"; + + if ( -f $stamp && ( ( stat($stamp) )[9] >= ( stat($file) )[9] ) ) { + $verbose && print " fresh, skipping.\n"; + next; + } + + $done = 0; + push @tmpfiles, $new; + open( *I, "<$file" ) or die("Can't open < $file: $!\n"); + open( *O, ">$new" ) or die("Can't open > $new: $!\n"); + + while () { + /^\s+((\d+)(\d{2}))\s*;\s*serial/i and do { # PATTERN + my ( $sdate, $scount, $serial ) = ( $2, $3, $1 ); + $done = 1; + print " [$file] serial $sdate$scount"; + + if ( $date eq $sdate ) { $scount++; } + else { $sdate = $date; $scount = "00"; } + + print " bumping to $sdate$scount"; + s/$serial/$sdate$scount/; + + }; + print O; } - open( FILE, ">$conf_file" ) or die "$conf_file: $!\n"; - print FILE @c_content; - close(FILE); + close(O); + close(I); + + if ($done) { + + open( I, "<$new" ) or die("Can't open <$new: $!\n"); + open( O, ">$file" ) or die("Can't open >$file: $!\n"); + while () { print O or die("Can't write to $file: $!\n"); } + close(I) or die("Can't close $new: $!\n"); + close(O) or die("Can't close $file: $!\n"); + + unlink $new; + + open( O, ">$stamp" ) or die("Can't open >$stamp: $!\n"); + close(O); + $changed++; + + push @change_names, $file_basename; + + } + else { + print " $file: no serial number found: no zone file?"; + } + print "\n"; } + + if ($changed) { + my $pidfile; + + + print + "** Changed $changed files, the nameserver needs to be reloaded!\n"; + foreach ( + qw(/var/run/bind/run/named.pid /var/run/named.pid /etc/named.pid)) + { + -f $_ and $pidfile = $_ and last; + } + + # dnssec-sign aufruf fuer geanderten domains + system "$dnssec_sign @change_names"; + die "$dnssec_sign not found ($!)" if $? == -1; + exit 1 if $?; + + if ($pidfile) { + if ($opt_yes) { + $_ = "y"; + print "** Nameserver will be reloaded\n"; + } + else { print "** Reload now? [Y/n]: "; $_ = ; } + /^y|^$/i and system "rndc reload"; + } + else { + print + "** No PID of a running named found. Please reload manually.\n"; + } + + } + } -# erzeugt eine named.conf-datei aus den entsprechenden vorlagen. -open( TO, ">$bind_dir/named.conf.zones" ) - or die "$bind_dir/named.conf.zones: $!\n"; -while (<$conf_dir/*>) { - open( FROM, "$_" ) or die "$_: $! \n"; - print TO ; - close(FROM); -} -close(TO); - - -system "named-checkconf"; -system "named-checkconf -z"; -system "rndc reload";