update-zone
changeset 32 d1addc2ec712
parent 31 1cea07056124
child 33 d3269961e944
--- 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 <heiko@datom.de>
+#
+# … 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 = <FILE>;
+            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 = <FILE>;
-        close(FILE);
+            }
+        }
+        else {
+
+            open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
+            @c_content = <FILE>;
+            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 <FROM>;
+        close(FROM);
+    }
+    close(TO);
 
-        open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
-        @c_content = <FILE>;
-        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 (<I>) {
+            /^\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 (<I>) { 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]: "; $_ = <STDIN>; }
+            /^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 <FROM>;
-    close(FROM);
-}
-close(TO);
-
-
-system "named-checkconf";
-system "named-checkconf -z";
-system "rndc reload";