update-serial.pl
branchhs12
changeset 56 6af96ec29ada
parent 55 ee22798cf2c3
child 57 d33fd3eee469
equal deleted inserted replaced
55:ee22798cf2c3 56:6af96ec29ada
     5 use warnings;
     5 use warnings;
     6 use FindBin;
     6 use FindBin;
     7 use File::Basename;
     7 use File::Basename;
     8 use Pod::Usage;
     8 use Pod::Usage;
     9 use Getopt::Long;
     9 use Getopt::Long;
       
    10 use Smart::Comments;
       
    11 use File::Temp;
       
    12 use POSIX qw(strftime);
    10 
    13 
    11 sub uniq(@);
    14 sub uniq(@);
    12 sub read_conf(@);
    15 sub read_conf(@);
    13 sub add_argv;
    16 sub zones(@);
    14 sub changed_zone;
    17 sub changed_zones();
    15 sub sign_end;
    18 sub update_index($);
       
    19 sub sign_expired($);
       
    20 
    16 sub sign_zone;
    21 sub sign_zone;
    17 sub update_serial;
    22 sub update_serial;
    18 sub mk_zone_conf;
    23 sub mk_zone_conf;
    19 sub update_index;
       
    20 sub file_entry;
    24 sub file_entry;
    21 sub server_reload;
    25 sub server_reload;
    22 sub to_begin_ro;
    26 sub to_begin_ro;
    23 sub to_end_ro;
    27 sub to_end_ro;
    24 sub begin_ro;
    28 sub begin_ro;
    25 sub key_to_zonefile;
    29 sub key_to_zonefile;
    26 sub kill_useless_keys;
    30 sub kill_useless_keys;
    27 sub end_ro;
    31 sub end_ro;
    28 
    32 
    29 my %config;
    33 my %config;
       
    34 my %opt;
    30 
    35 
    31 MAIN: {
    36 MAIN: {
    32 
    37 
    33     GetOptions(
    38     GetOptions(
    34         "h|help" => sub { pod2usage(-exit 0, -verbose => 1) },
    39         "sign-alert-time=i" => \$opt{sign_alert_time},
    35         "m|man"  => sub {
    40         "h|help"            => sub { pod2usage(-exit 0, -verbose => 1) },
       
    41         "m|man"             => sub {
    36             pod2usage(
    42             pod2usage(
    37                 -exit 0,
    43                 -exit 0,
    38                 -verbose   => 2,
    44                 -verbose   => 2,
    39                 -noperldoc => system("perldoc -v &>/dev/null")
    45                 -noperldoc => system("perldoc -v &>/dev/null")
    40             );
    46             );
    41         },
    47         },
    42     ) or pod2usage;
    48     ) or pod2usage;
    43 
    49 
    44     %config = read_conf("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
    50     # merge the config and the defined options from commandline
    45 
    51     %config = (
    46     our @new_serial;       # liste fuer neuen serial
    52         read_conf("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf"),
       
    53         map { $_ => $opt{$_} } grep { defined $opt{$_} } keys %opt
       
    54     );
       
    55 
       
    56     our @new_serial;       # DO NOT USE
    47     our @begin_ro_list;    # liste mit zonen deren key-rollover beginnt
    57     our @begin_ro_list;    # liste mit zonen deren key-rollover beginnt
    48     our @end_ro_list;      # liste mit zonen deren key-rollover fertig ist
    58     our @end_ro_list;      # liste mit zonen deren key-rollover fertig ist
    49     our $bind_dir        = $config{bind_dir};
    59     our $bind_dir        = $config{bind_dir};
    50     our $conf_dir        = $config{zone_conf_dir};
    60     our $conf_dir        = $config{zone_conf_dir};
    51     our $sign_alert_time = $config{sign_alert_time};
       
    52     our $indexzone       = $config{indexzone};
       
    53     our $key_counter_end = $config{key_counter_end};
    61     our $key_counter_end = $config{key_counter_end};
    54     our $ablauf_zeit     = $config{abl_zeit};
    62     our $ablauf_zeit     = $config{abl_zeit};
    55 
    63 
    56     add_argv;
    64     my @candidates = @ARGV ? zones(@ARGV) : changed_zones;
    57 
    65     push @candidates, update_index($config{indexzone});
    58     changed_zone;
    66     push @candidates, sign_expired($config{sign_alert_time});
    59     sign_end;
    67     ### @candidates
    60 
    68     exit;
    61     to_begin_ro;    # prueft nach beginnenden rollover-verfahren
    69 
    62     to_end_ro;      # prueft nach endenden rollover-verfahren
    70     to_begin_ro;           # prueft nach beginnenden rollover-verfahren
       
    71     to_end_ro;             # prueft nach endenden rollover-verfahren
    63 
    72 
    64     if (@begin_ro_list) {
    73     if (@begin_ro_list) {
    65         begin_ro;    # eine rollover-beginn-sequenz
    74         begin_ro;          # eine rollover-beginn-sequenz
    66     }
    75     }
    67 
    76 
    68     if (@end_ro_list) {
    77     if (@end_ro_list) {
    69         end_ro;      # eine rollover-end-squenz
    78         end_ro;            # eine rollover-end-squenz
    70     }
    79     }
    71 
    80 
    72     if (@new_serial) {
    81     if (@new_serial) {
    73         update_index;     # index zone aktuallisieren
    82 
    74         update_serial;    # serial aktuallisieren
    83         #--update_index;     # index zone aktuallisieren
    75         sign_zone;        # zone signieren
    84         update_serial;     # serial aktuallisieren
       
    85         sign_zone;         # zone signieren
    76     }
    86     }
    77 
    87 
    78     file_entry;       # bearbeitet die file-eintraege der konfigurations-datei
    88     file_entry;       # bearbeitet die file-eintraege der konfigurations-datei
    79     mk_zone_conf;     # konfiguration zusammenfuegen
    89     mk_zone_conf;     # konfiguration zusammenfuegen
    80     server_reload;    # server neu laden
    90     server_reload;    # server neu laden
    81 
    91 
    82 }
    92 }
    83 
    93 
    84 sub uniq(@) {
    94 sub uniq(@) {
       
    95 
    85     # remove duplicate entries
    96     # remove duplicate entries
    86     my %all;
    97     my %all;
    87     @all{@_} = ();
    98     @all{@_} = ();
    88     keys %all;
    99     keys %all;
    89 }
   100 }
   106     }
   117     }
   107 
   118 
   108     return %config;
   119     return %config;
   109 }
   120 }
   110 
   121 
   111 sub add_argv {
   122 sub zones(@) {
   112     # checked whether the zones in argv are managed zones and
   123 
   113     #inserted them into the list new_serial
   124     # check whether the zones in argv are managed zones and
   114     our @new_serial;
   125     # insert them into the list new_serial
   115     my $zone;
   126 
   116 
   127     my @r;
   117     for (@ARGV) {
   128 
   118         chomp($zone = `idn --quiet "$_"`);
   129     foreach (@_) {
   119         if (-e "$config{master_dir}/$zone/$zone") {
   130         chomp(my $zone = `idn --quiet "$_"`);
   120             push @new_serial, $zone;
   131         die "$zone is not managed\n"
   121         }
   132           if not -e "$config{master_dir}/$zone/$zone";
   122     }
   133         push @r, $zone;
   123 }
   134     }
   124 
   135 
   125 sub changed_zone {
   136     return @r;
   126     our @new_serial;
   137 }
       
   138 
       
   139 sub changed_zones() {
       
   140 
       
   141     # find candidates in our master dir
       
   142     my @r;
   127 
   143 
   128     while (glob "$config{master_dir}/*") {
   144     while (glob "$config{master_dir}/*") {
   129         my $zone = basename($_);
   145         my $zone = basename($_);
   130 
   146 
   131         if (-e "$config{master_dir}/$zone/.stamp") {
   147         if (not -e "$_/.stamp") {
   132             my $stamptime = (-M "$config{master_dir}/$zone/.stamp");
   148             say " * $zone: no .stamp file found";    # NOCH IN NEW_SERIAL PUSHEN
   133             my $filetime  = (-M "$config{master_dir}/$zone/$zone");
   149             push @r, $zone;
   134             if ($stamptime > $filetime) {
   150             next;
   135                 push @new_serial, $zone;
   151         }
   136                 print " * $zone: zonedatei wurde geaendert\n";
   152 
   137             }
   153         my $stamp_age = -M _;
   138         }
   154         my $file_age  = -M "$_/$zone";
   139         else {
   155 
   140             print " * $zone: keine .stamp-datei gefunden\n"
   156         next if $stamp_age <= $file_age;             # should be only <
   141               ;    # NOCH IN NEW_SERIAL PUSHEN
   157 
   142             push @new_serial, $zone;
   158         push @r, $zone;
   143         }
   159         say " * $zone: zone file modified";
   144     }
   160     }
   145 
   161     return @r;
   146 }
   162 }
   147 
   163 
   148 sub sign_end {
   164 sub sign_expired($) {
   149     our $sign_alert_time;    # the time between the end and the new signing
   165     my $sign_alert_time = shift;  # the time between the end and the new signing
   150                              # (see external configuration)
   166                                   # (see external configuration)
   151     our @new_serial;
   167     my @r;
   152 
   168 
   153     # erzeugt $time (die zeit ab der neu signiert werden soll)
   169     # erzeugt $time (die zeit ab der neu signiert werden soll)
   154     my $unixtime = time + (3600 * $sign_alert_time);
   170     # ... warum eigentlich nur bis zu den Stunden und nicht auch Minuten und Sekunden?
   155     my $time = `date -d \@$unixtime +%Y%m%d%H`;
   171     my $time = strftime("%Y%m%d%H" => localtime time + 3600 * $sign_alert_time);
   156 
   172 
   157     ## vergleicht fuer alle zonen im ordner $config{master_dir} mit einer
   173     ## vergleicht fuer alle zonen im ordner $config{master_dir} mit einer
   158     ## <zone>.signed-datei den zeitpunkt in $time mit dem ablaufdatum der
   174     ## <zone>.signed-datei den zeitpunkt in $time mit dem ablaufdatum der
   159     ## signatur, welcher aus der datei <zone>.signed ausgelesen wird.
   175     ## signatur, welcher aus der datei <zone>.signed ausgelesen wird.
   160     while (glob "$config{master_dir}/*") {
   176     ZONE: while (my $dir = glob "$config{master_dir}/*") {
   161         s#($config{master_dir}/)(.*)#$2#;
   177         my $zone = basename $dir;
   162         my $zone = $_;
   178 
   163 
   179 	next if not -e "$dir/$zone.signed";
   164         if (-e "$config{master_dir}/$zone/$zone.signed") {
   180 
   165             open(ZONE, "$config{master_dir}/$zone/$zone.signed");
   181 	open(my $fh, "$dir/$zone.signed") or die "Can't open $dir/$zone.signed: $!\n";
   166             my @zone_sig_content = <ZONE>;
   182 	push @r, $zone if
   167             close(ZONE);
   183 	    /RRSIG\s+SOA[\d ]+(\d{10})\d{4}\s+\(/ ~~ [<$fh>]
   168 
   184 	    and $1 < $time;
   169             for (@zone_sig_content) {
   185     }
   170                 if (m#SOA.*[0-9]{14}#) {
   186 
   171                     s#.*([0-9]{10})([0-9]{4}).*#$1#;
   187     return @r;
   172                     if ($_ < $time) {
       
   173                         push @new_serial, $zone;
       
   174                     }
       
   175                 }
       
   176             }
       
   177         }
       
   178     }
       
   179 }
   188 }
   180 
   189 
   181 sub sign_zone {
   190 sub sign_zone {
   182 
   191 
   183     # signiert die zonen und erhoeht den wert in der keycounter-datei
   192     # signiert die zonen und erhoeht den wert in der keycounter-datei
   277     }
   286     }
   278     close(TO);
   287     close(TO);
   279     print "** zonekonfiguration erzeugt\n";
   288     print "** zonekonfiguration erzeugt\n";
   280 }
   289 }
   281 
   290 
   282 sub update_index {
   291 sub update_index($) {
   283 
   292     my $indexzone = shift;
   284     # aktualisiert die indexzone;
   293 
   285     our @new_serial;
   294     my @iz;
   286     our $indexzone;
   295 
   287     my @iz_content_old;
   296     {
   288     my @iz_content_new;
   297         open(my $fh, "$config{master_dir}/$indexzone/$indexzone")
   289 
   298           or die "$config{master_dir}/$indexzone/$indexzone: $!\n";
   290     open(INDEXZONE, "$config{master_dir}/$indexzone/$indexzone")
   299         chomp(@iz = grep !/ZONE::/ => <$fh>);
   291       or die "$config{master_dir}/$indexzone/$indexzone: $!\n";
       
   292     @iz_content_old = <INDEXZONE>;
       
   293     close(INDEXZONE);
       
   294 
       
   295     for (@iz_content_old) {
       
   296         unless (m#ZONE::#) {
       
   297             push @iz_content_new, $_;
       
   298         }
       
   299     }
   300     }
   300 
   301 
   301     for my $dir (glob "$config{master_dir}/*") {
   302     for my $dir (glob "$config{master_dir}/*") {
   302         my $zone     = basename($dir);
   303         my $zone = basename($dir);
   303         my $info_end = "::sec-off";
   304         my $info = -e ("$dir/.keycounter") ? "sec-on" : "sec-off";
   304 
   305         push @iz, join "::", "\t\tIN TXT\t\t\"ZONE", $zone, $info;
   305         if (-e "$dir/.keycounter") {
   306     }
   306             $info_end = "::sec-on";
   307 
   307         }
   308     {
   308 
   309         my $fh = File::Temp->new(DIR => "$config{master_dir}/$indexzone")
   309         my $iz_line = "\t\tIN TXT\t\t\"ZONE::$zone$info_end\"\n";
   310           or die "Can't create tmpdir: $!\n";
   310 
   311         print $fh join "\n" => @iz, "";
   311         push @iz_content_new, $iz_line;
   312         rename($fh->filename => "$config{master_dir}/$indexzone/$indexzone")
   312     }
   313           or die "Can't rename "
   313 
   314           . $fh->filename
   314     open(INDEXZONE, ">$config{master_dir}/$indexzone/$indexzone")
   315           . " to $config{master_dir}/$indexzone/$indexzone: $!\n";
   315       or die "$config{master_dir}/$indexzone/$indexzone: $!\n";
   316     }
   316     print INDEXZONE @iz_content_new;
   317 
   317     close(INDEXZONE);
   318     say "** index-zone aktualisiert";
   318 
   319     return $indexzone;
   319     # fuegt die index-zone in die liste damit der serial erhoet wird
       
   320     push @new_serial, $indexzone;
       
   321 
       
   322     print "** index-zone aktualisiert \n";
       
   323 }
   320 }
   324 
   321 
   325 sub file_entry {
   322 sub file_entry {
   326 
   323 
   327     # prueft jede domain, die ein verzeichnis in $config{master_dir} hat, ob sie
   324     # prueft jede domain, die ein verzeichnis in $config{master_dir} hat, ob sie
   587  
   584  
   588  update-serial - updates the serial numbers and re-signs the zone files
   585  update-serial - updates the serial numbers and re-signs the zone files
   589 
   586 
   590 =head1 SYNOPSIS
   587 =head1 SYNOPSIS
   591 
   588 
   592  update-serial [zone...]
   589  update-serial [options] [zone...]
   593 
   590 
   594 =head1 DESCRIPTION
   591 =head1 DESCRIPTION
   595 
   592 
   596 B<update-serial> scans the configured directories for modified zone files. On any
   593 B<update-serial> scans the configured directories for modified zone files. On any
   597 file found it increments the serial number and signs the zone, if approbiate.
   594 file found it increments the serial number and signs the zone, if approbiate.
   598 
   595 
   599 =head1 OPTIONS
   596 =head1 OPTIONS
   600 
   597 
       
   598 =over
       
   599 
       
   600 =item B<--sign-alert-time> I<days>
       
   601 
       
   602 
       
   603 =back
       
   604 
   601 The common options B<-h>|B<--help>|B<-m>|B<--man> are supported.
   605 The common options B<-h>|B<--help>|B<-m>|B<--man> are supported.
   602 
   606 
   603 =head1 AUTHOR
   607 =head1 AUTHOR
   604 
   608 
   605 L<andre.suess@pipkin.cc>
   609 L<andre.suess@pipkin.cc>