update-zone
changeset 32 d1addc2ec712
parent 31 1cea07056124
child 33 d3269961e944
equal deleted inserted replaced
31:1cea07056124 32:d1addc2ec712
     1 #!/usr/bin/perl
     1 #! /usr/bin/perl
       
     2 # (c) 1998 Heiko Schlittermann <heiko@datom.de>
       
     3 #
       
     4 # … work in progress do integrate dnssec (branch suess)
       
     5 #
       
     6 # Update the serial numbers in zone files
       
     7 # The serial number needs to match a specified pattern (see
       
     8 # the line marked w/ PATTERN.
       
     9 #
       
    10 # ToDo:
       
    11 # . test against an md5 sum, not just the date of the stamp file
       
    12 # . FIXME: handle `/' in file names (currently only working in
       
    13 #   the current directory)
       
    14 # . optionally reload the named
     2 
    15 
     3 use strict;
    16 use strict;
       
    17 use warnings;
       
    18 
       
    19 use File::Basename;
       
    20 use File::Copy;
     4 use FindBin;
    21 use FindBin;
     5 
    22 
     6 # liest die Konfiguration ein
       
     7 my @configs = ( "$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf" );
    23 my @configs = ( "$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf" );
     8 my @dnssec_signs
    24 my @dnssec_signs
     9     = ( "$FindBin::Bin/dnssec-sign", "/usr/bin/dnstools/dnssec-sign" );
    25     = ( "$FindBin::Bin/dnssec-sign", "/usr/bin/dnstools/dnssec-sign" );
    10 my %config;
    26 my %config;
    11 my $dnssec_sign;
    27 my $dnssec_sign;
    12 
    28 my @change_names = ();
    13 for ( grep {-f} @configs ) {
    29 
       
    30 foreach ( grep {-f} @configs ) {
    14     open( CONFIG, $_ ) or die "Can't open $_: $!\n";
    31     open( CONFIG, $_ ) or die "Can't open $_: $!\n";
    15 }
    32 }
       
    33 
    16 unless ( seek( CONFIG, 0, 0 ) ) {
    34 unless ( seek( CONFIG, 0, 0 ) ) {
    17     die "Can't open config (searched: @configs)\n";
    35     die "Can't open config (searched: @configs)\n";
    18 }
    36 }
    19 
    37 foreach ( grep {-f} @dnssec_signs ) {
    20 for ( grep {-f} @dnssec_signs ) {
       
    21     if ( -x $_ ) {
    38     if ( -x $_ ) {
    22         $dnssec_sign = $_;
    39         $dnssec_sign = $_;
    23     }
    40     }
    24     else {
    41     else {
    25         die "Can't run $_\n";
    42         die "Can't run $_\n";
    39 
    56 
    40 my $bind_dir   = $config{bind_dir};
    57 my $bind_dir   = $config{bind_dir};
    41 my $conf_dir   = $config{zone_conf_dir};
    58 my $conf_dir   = $config{zone_conf_dir};
    42 my $master_dir = $config{master_dir};
    59 my $master_dir = $config{master_dir};
    43 
    60 
    44 unless ( -d $master_dir and -r $master_dir ) {
    61 my $ME = basename $0;
    45     die "$master_dir: $!\n";
    62 my @tmpfiles;
    46 }
    63 my $verbose = 0;
    47 
    64 my $opt_yes = 0;
    48 unless ( -d $bind_dir and -r $bind_dir ) {
    65 my @Zones;
    49     die "$bind_dir: $!\n";
    66 my $file;
    50 }
    67 
    51 
    68 sub cleanup() { unlink @tmpfiles; }
    52 # dnssec - new sign
    69 END { cleanup(); }
    53 system "$dnssec_sign";
    70 
    54 die "$dnssec_sign not found ($!)" if $? == -1;
    71 for (@ARGV) {
    55 exit 1 if $?;
    72     if ( $_ eq "-y" ) {
    56 
    73         $opt_yes = 1;
    57 
    74         shift @ARGV;
    58 # prueft jede domain, die ein verzeichnis in $master_dir hat, ob es eine
    75     }
    59 # datei $zone_file.signed gibt und ob diese datei in $config_file eingetragen
    76 }
    60 # ist.
    77 
    61 # passt die eintraege in $config_file falls noetig an.
    78 @Zones = @ARGV ? @ARGV : glob("$master_dir/*");
    62 while (<$master_dir/*>) {
    79 
    63     s#($master_dir/)(.*)#$2#;
    80 MAIN: {
    64     my $zone = $_;
    81     my $changed;
    65 
    82     my ( $dd, $mm, $yy ) = ( localtime() )[ 3 .. 5 ];
    66     my $zone_file = "$master_dir/$zone/$zone";
    83     my $date;
    67     my $conf_file = "$conf_dir/$zone";
    84     $mm++;
    68     my @c_content;
    85 
    69 
    86 
    70     unless ( -f "$conf_file" ) {
    87     # fuehrt automatische aktuallisierungen der zonen durch
    71         die "$conf_file: $! \n";
    88     system "$dnssec_sign";
    72     }
    89 
    73 
    90     # prueft jede domain, die ein verzeichnis in $master_dir hat, ob sie
    74     if ( -f "$zone_file.signed" ) {
    91     # dnssec nutzt.
    75 
    92     # passt die eintraege in $config_file falls noetig an.
    76         open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
    93     while (<$master_dir/*>) {
    77         @c_content = <FILE>;
    94         s#($master_dir/)(.*)#$2#;
    78         close(FILE);
    95         my $zone = $_;
    79 
    96 
    80         for (@c_content) {
    97         my $zone_file = "$master_dir/$zone/$zone";
    81             if (m{(.*)($zone_file)(";)}) {
    98         my $conf_file = "$conf_dir/$zone";
    82                 print "$2 ==> $2.signed\n";
    99         my @c_content;
    83                 $_ = "$1$2.signed$3\n";
   100 
       
   101         unless ( -f "$conf_file" ) {
       
   102             die "$conf_file: $! \n";
       
   103         }
       
   104 
       
   105         if ( -e "$master_dir/$zone/.keycounter" ) {
       
   106 
       
   107             open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
       
   108             @c_content = <FILE>;
       
   109             close(FILE);
       
   110 
       
   111             for (@c_content) {
       
   112                 if (m{(.*)($zone_file)(";)}) {
       
   113                     print "$2 ==> $2.signed\n";
       
   114                     $_ = "$1$2.signed$3\n";
       
   115                 }
       
   116 
       
   117                 open( FILE, ">$conf_file" ) or die "$conf_file: $!\n";
       
   118                 print FILE @c_content;
       
   119                 close(FILE);
       
   120 
    84             }
   121             }
    85 
   122         }
       
   123         else {
       
   124 
       
   125             open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
       
   126             @c_content = <FILE>;
       
   127             close(FILE);
       
   128 
       
   129             for (@c_content) {
       
   130                 if (m{(.*)($zone_file)\.signed(.*)}) {
       
   131                     print "$2.signed ==> $2\n";
       
   132                     $_ = "$1$2$3\n";
       
   133                 }
       
   134             }
       
   135     
    86             open( FILE, ">$conf_file" ) or die "$conf_file: $!\n";
   136             open( FILE, ">$conf_file" ) or die "$conf_file: $!\n";
    87             print FILE @c_content;
   137             print FILE @c_content;
    88             close(FILE);
   138             close(FILE);
    89 
   139         }
    90         }
   140     }
    91     }
   141 
    92     else {
   142     # erzeugt eine named.conf-datei aus den entsprechenden vorlagen.
    93 
   143     open( TO, ">$bind_dir/named.conf.zones" )
    94         open( FILE, "<$conf_file" ) or die "$conf_file: $!\n";
   144         or die "$bind_dir/named.conf.zones: $!\n";
    95         @c_content = <FILE>;
   145     while (<$conf_dir/*>) {
    96         close(FILE);
   146         open( FROM, "$_" ) or die "$_: $! \n";
    97 
   147         print TO <FROM>;
    98         for (@c_content) {
   148         close(FROM);
    99             if (m{(.*)($zone_file)\.signed(.*)}) {
   149     }
   100                 print "$2.signed ==> $2\n";
   150     close(TO);
   101                 $_ = "$1$2$3\n";
   151 
       
   152     # update-serial
       
   153     foreach ( $dd, $mm ) { s/^\d$/0$&/; }
       
   154     $yy += 1900;
       
   155     $date = "$yy$mm$dd";
       
   156 
       
   157     while ( my $file = shift @Zones ) {
       
   158 
       
   159         my $file_basename = basename($file);
       
   160 
       
   161         $file =~ s#($master_dir)(/.*)#$1$2$2#;
       
   162         local ( *I, *O );
       
   163         my $done = 0;
       
   164 
       
   165         my $new   = "$file.$$.tmp";
       
   166         my $bak   = "$file.bak";
       
   167         my $stamp = $master_dir . "/.stamp/" . basename($file);
       
   168 
       
   169         $file =~ /(\.bak|~)$/ and next;
       
   170         $file !~ /\./ and next;
       
   171 
       
   172         $verbose && print "$file:";
       
   173 
       
   174         if ( -f $stamp && ( ( stat($stamp) )[9] >= ( stat($file) )[9] ) ) {
       
   175             $verbose && print " fresh, skipping.\n";
       
   176             next;
       
   177         }
       
   178 
       
   179         $done = 0;
       
   180         push @tmpfiles, $new;
       
   181         open( *I, "<$file" ) or die("Can't open < $file: $!\n");
       
   182         open( *O, ">$new" )  or die("Can't open > $new: $!\n");
       
   183 
       
   184         while (<I>) {
       
   185             /^\s+((\d+)(\d{2}))\s*;\s*serial/i and do {    # PATTERN
       
   186                 my ( $sdate, $scount, $serial ) = ( $2, $3, $1 );
       
   187                 $done = 1;
       
   188                 print " [$file] serial $sdate$scount";
       
   189 
       
   190                 if   ( $date eq $sdate ) { $scount++; }
       
   191                 else                     { $sdate = $date; $scount = "00"; }
       
   192 
       
   193                 print " bumping to $sdate$scount";
       
   194                 s/$serial/$sdate$scount/;
       
   195 
       
   196             };
       
   197             print O;
       
   198         }
       
   199 
       
   200         close(O);
       
   201         close(I);
       
   202 
       
   203         if ($done) {
       
   204 
       
   205             open( I, "<$new" )  or die("Can't open <$new: $!\n");
       
   206             open( O, ">$file" ) or die("Can't open >$file: $!\n");
       
   207             while (<I>) { print O or die("Can't write to $file: $!\n"); }
       
   208             close(I) or die("Can't close $new: $!\n");
       
   209             close(O) or die("Can't close $file: $!\n");
       
   210 
       
   211             unlink $new;
       
   212 
       
   213             open( O, ">$stamp" ) or die("Can't open >$stamp: $!\n");
       
   214             close(O);
       
   215             $changed++;
       
   216 
       
   217             push @change_names, $file_basename;
       
   218 
       
   219         }
       
   220         else {
       
   221             print " $file: no serial number found: no zone file?";
       
   222         }
       
   223         print "\n";
       
   224     }
       
   225 
       
   226     if ($changed) {
       
   227         my $pidfile;
       
   228 
       
   229 
       
   230         print
       
   231             "** Changed $changed files, the nameserver needs to be reloaded!\n";
       
   232         foreach (
       
   233             qw(/var/run/bind/run/named.pid /var/run/named.pid /etc/named.pid))
       
   234         {
       
   235             -f $_ and $pidfile = $_ and last;
       
   236         }
       
   237 
       
   238         # dnssec-sign aufruf fuer geanderten domains
       
   239         system "$dnssec_sign @change_names";
       
   240         die "$dnssec_sign not found ($!)" if $? == -1;
       
   241         exit 1 if $?;
       
   242 
       
   243         if ($pidfile) {
       
   244             if ($opt_yes) {
       
   245                 $_ = "y";
       
   246                 print "** Nameserver will be reloaded\n";
   102             }
   247             }
   103         }
   248             else { print "** Reload now? [Y/n]: "; $_ = <STDIN>; }
   104 
   249             /^y|^$/i and system "rndc reload";
   105         open( FILE, ">$conf_file" ) or die "$conf_file: $!\n";
   250         }
   106         print FILE @c_content;
   251         else {
   107         close(FILE);
   252             print
   108     }
   253                 "** No PID of a running named found.  Please reload manually.\n";
   109 }
   254         }
   110 
   255 
   111 # erzeugt eine named.conf-datei aus den entsprechenden vorlagen.
   256     }
   112 open( TO, ">$bind_dir/named.conf.zones" )
   257 
   113     or die "$bind_dir/named.conf.zones: $!\n";
   258 }
   114 while (<$conf_dir/*>) {
   259 
   115     open( FROM, "$_" ) or die "$_: $! \n";
       
   116     print TO <FROM>;
       
   117     close(FROM);
       
   118 }
       
   119 close(TO);
       
   120 
       
   121 
       
   122 system "named-checkconf";
       
   123 system "named-checkconf -z";
       
   124 system "rndc reload";