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"; |
|