added update-serial
authorasuess@dns.net.schlittermann.de
Thu, 02 Dec 2010 09:38:16 +0100
changeset 36 6847290f1155
parent 35 b809ae6c2f57
child 37 d3158de72598
added update-serial
dnstools.conf
update-serial
--- a/dnstools.conf	Fri Oct 15 11:04:37 2010 +0200
+++ b/dnstools.conf	Thu Dec 02 09:38:16 2010 +0100
@@ -3,7 +3,7 @@
 zone_conf_dir = /etc/bind/zones.d	# Verzeichnis für die Zonen-Konfigurationdateien
 
 key_counter_end = 40			# Anzahl der Signierungen bis zum Key-Rollover
-sign_alert_time = 144			# Warn-Zeitraum vor dem Ablauf einer Zone-Signatur in h
+sign_alert_time = 168			# Warn-Zeitraum vor dem Ablauf einer Zone-Signatur in h
 abl_zeit = 24				# Dauer des Key-Rollover (2 Schluessel) in h
 
 secondary = hh.schlittermann.de
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/update-serial	Thu Dec 02 09:38:16 2010 +0100
@@ -0,0 +1,331 @@
+#!/usr/bin/perl 
+
+use strict;
+use warnings;
+use FindBin;
+use File::Basename;
+
+sub del_double {
+    # entfernt doppelte eintraege in einer liste
+    my %all;
+    grep { $all{$_} = 0 } @_;
+    return ( keys %all );
+}
+
+sub read_conf {
+    # liest die Konfiguration ein
+    my @configs = ( "$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf" );
+    our %config;
+
+    for ( grep {-f} @configs ) {
+        open( CONFIG, $_ ) or die "Can't open $_: $!\n";
+    }
+    unless ( seek( CONFIG, 0, 0 ) ) {
+        die "Can't open config (searched: @configs)\n";
+    }
+    while (<CONFIG>) {
+        chomp;
+        s/#.*//;
+        s/\t//g;
+        s/\s//g;
+
+        next unless length;
+        my ( $cname, $ccont ) = split( /\s*=\s*/, $_, 2 );
+        $config{$cname} = $ccont;
+    }
+    close(CONFIG);
+}
+
+sub add_argv {
+    # prueft ob zonen aus ARGV verwaltete zonen sind
+    # und fuegt sie, falls ja in die liste @new_serial ein
+    our @new_serial;
+    our $master_dir;
+    my $zone;
+    
+    for (@ARGV) {
+        chomp( $zone = `idn --quiet "$_"` );
+        if ( -e "$master_dir/$zone/$zone" ) {
+            push @new_serial, $zone;
+        }
+    }
+}
+
+sub changed_zone {
+    our $master_dir;
+    our @new_serial;
+
+    for (<$master_dir/*>) {
+        my $zone = basename($_);
+
+        if (-e "$master_dir/$zone/.stamp") {
+            my $stamptime = (-M "$master_dir/$zone/.stamp");
+            my $filetime = (-M "$master_dir/$zone/$zone");
+            if ($stamptime > $filetime) {
+                push @new_serial, $zone;
+                print " * $zone: zonedatei wurde geaendert\n";
+            }
+        }
+        else {
+            print " * $zone: keine .stamp-datei gefunden\n"; # NOCH IN NEW_SERIAL PUSHEN
+            push @new_serial, $zone;
+        }
+    }
+
+}
+
+sub sign_end {
+    our $sign_alert_time;  # die zeit zwischen dem ende und der neuen
+                           # signierung (siehe externe konfiguration)
+    our $master_dir;
+    our @new_serial;
+    
+    # erzeugt $time (die zeit ab der neu signiert werden soll)
+    chomp( my $unixtime = `date +%s` );
+    $unixtime = $unixtime + ( 3600 * $sign_alert_time );
+    my $time = `date -d \@$unixtime +%Y%m%d%H`;
+    
+    ## vergleicht fuer alle zonen im ordner $master_dir mit einer
+    ## <zone>.signed-datei den zeitpunkt in $time mit dem ablaufdatum der
+    ## signatur, welcher aus der datei <zone>.signed ausgelesen wird.
+    for (<$master_dir/*>) {
+        s#($master_dir/)(.*)#$2#;
+        my $zone = $_;
+    
+        if ( -e "$master_dir/$zone/$zone.signed" ) {
+            open( ZONE, "$master_dir/$zone/$zone.signed" );
+            my @zone_sig_content = <ZONE>;
+            close(ZONE);
+            
+            for (@zone_sig_content) {
+                if (m#SOA.*[0-9]{14}#) {
+                    s#.*([0-9]{10})([0-9]{4}).*#$1#;
+                    if ( $_ < $time ) {
+                        push @new_serial, $zone;
+                    }
+                }
+            }
+        }
+    }
+}
+
+sub sign_zone {
+    # signiert die zonen und erhoeht den wert in der keycounter-datei
+    our @new_serial;
+    our $master_dir;
+    my $zone;
+    my $kc;
+
+    for ( &del_double( @new_serial ) ) {
+        $zone = $_;
+
+        unless (-e "$master_dir/$zone/.index.zsk") {
+            next;
+        }
+
+        chdir "$master_dir/$zone";
+        if (`dnssec-signzone $zone 2>/dev/null`) {
+            print " * $zone neu signiert \n";
+
+            # erhoeht den keycounter
+            if ("$master_dir/$zone/.keycounter") {
+                open( KC, "$master_dir/$zone/.keycounter" );
+                $kc = <KC>;
+                close(KC);
+                $kc += 1;
+            }
+            else {
+                $kc = 1;
+            }
+            open( KC, ">$master_dir/$zone/.keycounter" );
+            print KC $kc;
+            close(KC);
+        }
+        else { print "$zone konnte nicht signiert werden \n"; }
+    }
+}
+
+sub update_serial {
+    our $master_dir;
+    our @new_serial;
+    chomp (my  $date = `date +%Y%m%d`);
+    my @new_content;
+    my  $sdate;
+    my  $scount;
+    my  $serial;
+
+    for ( &del_double( @new_serial ) ) {
+        # erhoeht den serial
+        my $zone = $_;
+        my $file = "$master_dir/$zone/$zone";
+        my @new_content = ();
+ 
+        open (SER, "<$file") or die "$file: $!\n";
+        for (<SER>) {
+            if (/^\s+(\d+)(\d{2})\s*;\s*serial/i) {
+                $sdate  = $1;
+                $scount = $2;
+                $serial = "$sdate$scount";
+                if ( $date eq $sdate ) {
+                    $scount++;
+                }
+                else {
+                    $sdate = $date;
+                    $scount = "00";
+                }
+            }
+            if ($serial) {
+                s/$serial/$sdate$scount/;
+            }
+            push @new_content, $_;
+        }
+        close (SER);
+
+        open (RES, ">$file") or die "$file: $!\n";
+        print RES @new_content;
+        close (RES);
+        print " * $zone: serial erhoeht \n";
+
+        open(STAMP, ">$master_dir/$zone/.stamp") or die "$master_dir/$zone/.stamp: $!\n";
+        close(STAMP);
+        print " * $zone: stamp aktualisiert \n";
+    }
+}
+
+sub mk_zone_conf {
+    # erzeugt eine named.conf-datei aus den entsprechenden vorlagen.
+    our $bind_dir;
+    our $conf_dir;
+
+    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);
+    print "** zonekonfiguration erzeugt\n";
+}
+
+sub update_index {
+    # aktualisiert die indexzone;
+    our @new_serial;
+    our $indexzone;
+    our $master_dir;
+    my @iz_content_old;
+    my @iz_content_new;
+
+    open (INDEXZONE, "$master_dir/$indexzone/$indexzone")
+        or die "$master_dir/$indexzone/$indexzone: $!\n";
+    @iz_content_old = <INDEXZONE>;
+    close (INDEXZONE);
+
+    for (@iz_content_old) {
+        unless (m#ZONE::#) {
+            push @iz_content_new, $_;
+        }
+    }
+
+    for my $dir ( glob "$master_dir/*" ) {
+        my $zone = basename($dir);
+        my $info_end = "::sec-off";
+
+        if (-e "$dir/.keycounter") {
+            $info_end = "::sec-on";
+        }
+
+        my $iz_line = "\t\tIN TXT\t\t\"ZONE::$zone$info_end\"\n";
+
+        push @iz_content_new, $iz_line;
+    }
+
+    open (INDEXZONE, ">$master_dir/$indexzone/$indexzone")
+        or die "$master_dir/$indexzone/$indexzone: $!\n";
+    print INDEXZONE @iz_content_new;
+    close (INDEXZONE);
+
+    # fuegt die index-zone in die liste damit der serial erhoet wird
+    push @new_serial, $indexzone;
+
+    print "** index-zone aktualisiert \n";
+}
+
+sub file_entry {
+    # prueft jede domain, die ein verzeichnis in $master_dir hat, ob sie
+    # dnssec nutzt.
+    # passt die eintraege in $config_file falls noetig an.
+    our $master_dir;
+    our $conf_dir;
+
+    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;
+
+        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);
+            for (@c_content) {
+                if (m{(.*)($zone_file)(";)}) {
+                    print " * zonekonfiguration aktualisiert ($2 ==> $2.signed)\n";
+                    $_ = "$1$2.signed$3\n";
+                }
+            }
+            open( FILE, ">$conf_file" ) or die "$conf_file: $!\n";
+            print FILE @c_content;
+            close(FILE);
+        }
+        else {
+            open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
+            @c_content = <FILE>;
+            close(FILE);
+            for (@c_content) {
+                if (m{(.*)($zone_file)\.signed(.*)}) {
+                    print " * zonekonfiguration aktualisiert ($2.signed ==> $2)\n";
+                    $_ = "$1$2$3\n";
+                }
+            }
+            open( FILE, ">$conf_file" ) or die "$conf_file: $!\n";
+            print FILE @c_content;
+            close(FILE);
+        }
+    }
+}
+
+sub server_reload {
+    if (`rndc reload`) {print "** reload dns-server \n"};
+}
+
+
+&read_conf;
+
+our %config;
+our @new_serial;     # liste fuer neuen serial
+our $master_dir      = $config{master_dir};
+our $bind_dir        = $config{bind_dir};
+our $conf_dir        = $config{zone_conf_dir};
+our $sign_alert_time = $config{sign_alert_time};
+our $indexzone       = $config{indexzone};
+
+&add_argv;
+&changed_zone;
+&sign_end;
+
+if (@new_serial) {
+    &update_index; # index zone aktuallisieren
+    &update_serial; # serial aktuallisieren
+    &sign_zone; # zone signieren
+}
+
+&file_entry;  # bearbeitet die file-eintraege der konfigurations-datei
+&mk_zone_conf; # konfiguration zusammenfuegen
+&server_reload; # server neu laden
+