73 ); |
76 ); |
74 } |
77 } |
75 ) or pod2usage; |
78 ) or pod2usage; |
76 |
79 |
77 # merge the config and the defined options from commandline |
80 # merge the config and the defined options from commandline |
78 %config = get_config("$ENV{DNSTOOLS_CONF}", "dnstools.conf", |
81 my @configs = ( "dnstools.conf", "$ENV{HOME}/.dnstools.conf", |
79 "$ENV{HOME}/.dnstools.conf", "/etc/dnstools.conf", \%opt); |
82 "/etc/dnstools.conf"); |
80 |
83 unshift @configs, $ENV{DNSTOOLS_CONF} if defined $ENV{DNSTOOLS_CONF}; |
81 our $bind_dir = $config{bind_dir}; |
84 %config = get_config(@configs, \%opt); |
82 our $conf_dir = $config{zone_conf_dir}; |
|
83 |
85 |
84 my @candidates = @ARGV ? zones(@ARGV) : changed_zones; |
86 my @candidates = @ARGV ? zones(@ARGV) : changed_zones; |
85 push @candidates, update_index($config{indexzone}); |
87 push @candidates, update_index($config{indexzone}); |
86 push @candidates, signature_expired($config{sign_alert_time}); |
88 push @candidates, signature_expired($config{sign_alert_time}); |
87 |
89 |
90 |
92 |
91 push @candidates, begin_rollover(@need_rollover); |
93 push @candidates, begin_rollover(@need_rollover); |
92 push @candidates, end_rollover(@done_rollover); |
94 push @candidates, end_rollover(@done_rollover); |
93 |
95 |
94 foreach my $zone (uniq(@candidates)) { |
96 foreach my $zone (uniq(@candidates)) { |
|
97 # say "XXX: candidate $zone"; |
95 update_serial($zone); |
98 update_serial($zone); |
96 sign($zone); |
99 sign($zone) if dnssec_enabled($zone, "$config{master_dir}/$config{indexzone}/$config{indexzone}"); |
97 } |
100 # say "XXX: $zone should be signed" if dnssec_enabled($zone, "$config{master_dir}/$config{indexzone}/$config{indexzone}"); |
98 say "Need to ... file_entry, mk_zone_conf, server_reload"; |
101 } |
99 exit; |
102 |
100 |
103 file_entry; |
101 file_entry; # bearbeitet die file-eintraege der konfigurations-datei |
104 mk_zone_conf($config{bind_dir}, $config{zone_conf_dir}); |
102 mk_zone_conf; # konfiguration zusammenfuegen |
105 server_reload; |
103 server_reload; # server neu laden |
|
104 |
106 |
105 } |
107 } |
106 |
108 |
107 sub uniq(@) { |
109 sub uniq(@) { |
108 |
110 |
141 say " * $zone: no .stamp file found"; # NOCH IN NEW_SERIAL PUSHEN |
143 say " * $zone: no .stamp file found"; # NOCH IN NEW_SERIAL PUSHEN |
142 push @r, $zone; |
144 push @r, $zone; |
143 next; |
145 next; |
144 } |
146 } |
145 |
147 |
146 my $stamp_age = -M _; |
148 my $stamp_mtime = (stat _)[8]; |
147 my $file_age = -M "$_/$zone"; |
149 my $stamp_mtime2 = (stat "$_/.stamp")[8]; |
148 |
150 my $zone_file_mtime = (stat "$_/$zone")[8] or die "Can't stat '$_/$zone': $!"; |
149 next if $stamp_age <= $file_age; # should be only < |
151 # TODO: do this here? |
|
152 my $kc_file_mtime = 0; |
|
153 $kc_file_mtime = (stat "$_/.keycounter")[8] or die "Can't stat '$_/.keycounter': $!" if -f "$_/.keycounter"; |
|
154 # say "XXX: zone: $zone | stamp_mtime: $stamp_mtime| stamp_mtime2: $stamp_mtime2 | zone_file_mtime: $zone_file_mtime | kc_file_mtime: $kc_file_mtime"; |
|
155 |
|
156 next unless $stamp_mtime < $zone_file_mtime or $stamp_mtime < $kc_file_mtime; |
150 |
157 |
151 push @r, $zone; |
158 push @r, $zone; |
152 say " * $zone: zone file modified"; |
159 say " * $zone: zone file modified"; |
153 } |
160 } |
154 return @r; |
161 return @r; |
230 or die "Can't rename tmp to $file: $!\n"; |
238 or die "Can't rename tmp to $file: $!\n"; |
231 |
239 |
232 $serial =~ s/\s*//g; |
240 $serial =~ s/\s*//g; |
233 say " * $zone: serial incremented to $serial"; |
241 say " * $zone: serial incremented to $serial"; |
234 |
242 |
235 open(my $stamp, ">", dirname($file) . "/.stamp"); |
243 my ($atime, $utime) = (time) x 2; |
236 print $stamp time() . " " . localtime() . "\n"; |
244 my $s = (dirname $file) . '/.stamp'; |
|
245 utime $atime, $utime, $s or die "Can't 'utime $atime, $utime, $s': $!"; |
237 |
246 |
238 say " * $zone: stamp aktualisiert"; |
247 say " * $zone: stamp aktualisiert"; |
|
248 # say " XXX $zone: stamp '$s' aktualisiert"; |
239 } |
249 } |
240 |
250 |
241 sub new_serial($) { |
251 sub new_serial($) { |
242 |
252 |
243 my ($date, $cnt) = $_[0] =~ /(\d{8})(\d\d)/; |
253 my ($date, $cnt) = $_[0] =~ /(\d{8})(\d\d)/; |
248 ? sprintf "%s%02d", $date, $cnt + 1 |
258 ? sprintf "%s%02d", $date, $cnt + 1 |
249 : "${now}00"; |
259 : "${now}00"; |
250 |
260 |
251 } |
261 } |
252 |
262 |
253 sub mk_zone_conf { |
263 sub mk_zone_conf($$) { |
254 |
264 |
255 # erzeugt eine named.conf-datei aus den entsprechenden vorlagen. |
265 # erzeugt eine named.conf-datei aus den entsprechenden vorlagen. |
256 our $bind_dir; |
266 my ($bind_dir, $conf_dir) = @_; |
257 our $conf_dir; |
|
258 |
267 |
259 open(TO, ">$bind_dir/named.conf.zones") |
268 open(TO, ">$bind_dir/named.conf.zones") |
260 or die "$bind_dir/named.conf.zones: $!\n"; |
269 or die "$bind_dir/named.conf.zones: $!\n"; |
261 while (<$conf_dir/*>) { |
270 while (<$conf_dir/*>) { |
262 open(FROM, "$_") or die "$_: $! \n"; |
271 open(FROM, "$_") or die "$_: $! \n"; |
279 } |
289 } |
280 |
290 |
281 for my $dir (glob "$config{master_dir}/*") { |
291 for my $dir (glob "$config{master_dir}/*") { |
282 my $zone = basename($dir); |
292 my $zone = basename($dir); |
283 my $info = -e ("$dir/.keycounter") ? "sec-on" : "sec-off"; |
293 my $info = -e ("$dir/.keycounter") ? "sec-on" : "sec-off"; |
284 push @iz, join "::", "\t\tIN TXT\t\t\"ZONE", $zone, $info; |
294 push @iz, join "::", "\t\tIN TXT\t\t\"ZONE", $zone, $info . '"'; |
285 } |
295 } |
286 |
296 |
287 { |
297 { |
288 my $fh = File::Temp->new(DIR => "$config{master_dir}/$indexzone") |
298 my $fh = File::Temp->new(DIR => "$config{master_dir}/$indexzone") |
289 or die "Can't create tmpdir: $!\n"; |
299 or die "Can't create tmpdir: $!\n"; |
290 print $fh join "\n" => @iz, ""; |
300 print $fh join "\n" => @iz, ""; |
291 rename($fh->filename => "$config{master_dir}/$indexzone/$indexzone") |
301 rename($fh->filename => "$config{master_dir}/$indexzone/$indexzone") |
292 or die "Can't rename " |
302 or die "Can't rename " |
293 . $fh->filename |
303 . $fh->filename |
294 . " to $config{master_dir}/$indexzone/$indexzone: $!\n"; |
304 . " to $config{master_dir}/$indexzone/$indexzone: $!\n"; |
|
305 $fh->unlink_on_destroy(0); |
295 } |
306 } |
296 |
307 |
297 say "** index-zone aktualisiert"; |
308 say "** index-zone aktualisiert"; |
298 return $indexzone; |
309 return $indexzone; |
299 } |
310 } |
301 sub file_entry { |
312 sub file_entry { |
302 |
313 |
303 # prueft jede domain, die ein verzeichnis in $config{master_dir} hat, ob sie |
314 # prueft jede domain, die ein verzeichnis in $config{master_dir} hat, ob sie |
304 # dnssec nutzt. |
315 # dnssec nutzt. |
305 # passt die eintraege in $config_file falls noetig an. |
316 # passt die eintraege in $config_file falls noetig an. |
306 our $conf_dir; |
317 my $cd = $config{zone_conf_dir}; |
307 |
318 my $md = $config{master_dir}; |
308 while (glob "$config{master_dir}/*") { |
319 |
309 s#($config{master_dir}/)(.*)#$2#; |
320 while (glob "$md/*") { |
310 my $zone = $_; |
321 m#($md/)(.*)#; |
311 my $zone_file = "$config{master_dir}/$zone/$zone"; |
322 my $z = $2; |
312 my $conf_file = "$conf_dir/$zone"; |
323 my $cf = "$cd/$z"; |
313 my @c_content; |
324 my $de = dnssec_enabled $z, "$md/$config{indexzone}/$config{indexzone}"; |
314 |
325 my $suf = $de ? '.signed' : ''; |
315 unless (-f "$conf_file") { |
326 # TODO: assuming that paths in $md and in zone config snippets match somehow |
316 die "$conf_file: $! \n"; |
327 my $zp = "$z/$z$suf"; |
|
328 my $zf = "$md/$z/$z$suf"; |
|
329 |
|
330 my ($files, $changed) = (0, 0); |
|
331 my $czf; |
|
332 open C, "+<$cf" or die "Cant't open '$cf': $!"; |
|
333 my @lines = <C>; # TODO: deal with race condition? |
|
334 my ($mode, $uid, $gid, $atime, $mtime) = (stat C)[2, 4, 5, 8, 9] or die "Can't stat: $!"; |
|
335 $mode &= 07777; |
|
336 for (@lines) { |
|
337 next unless /^\s*file\s+"([^"]*)"\s*;\s*$/; |
|
338 $czf = $1; |
|
339 $files++; |
|
340 $_ = qq(\tfile "$zf";) and $changed++ unless $czf =~ m#\Q$z/$z$suf\E$#; |
317 } |
341 } |
318 |
342 |
319 if (-e "$config{master_dir}/$zone/.keycounter") { |
343 die "Multiple file statements found in '$cf' (maybe inside multiline comments)" if $files > 1; |
320 open(FILE, "<$conf_file") or die "$conf_file: $!\n"; |
344 return unless $changed; |
321 @c_content = <FILE>; |
345 |
322 close(FILE); |
346 # file statement in config snippet doesnt match, so we make a backup first and write a new config |
323 for (@c_content) { |
347 my $cb = "$cf.bak"; |
324 if (m{(.*)($zone_file)(";)}) { |
348 open B, ">$cb" or die "Can't open '$cb': $!"; |
325 print |
349 print B @lines; |
326 " * zonekonfiguration aktualisiert ($2 ==> $2.signed)\n"; |
350 close B; |
327 $_ = "$1$2.signed$3\n"; |
351 chown $uid, $gid, $cb or die "Can't 'chown $uid, $gid, $cb': $!"; |
328 } |
352 chmod $mode, $cb or die "Can't 'chmod $mode, $cb': $!"; |
329 } |
353 utime $atime, $mtime, $cb or die "Can't 'utime $atime, $mtime, $cb': $!"; |
330 open(FILE, ">$conf_file") or die "$conf_file: $!\n"; |
354 |
331 print FILE @c_content; |
355 seek C, 0, 0 or die "Can't seek C, 0, 0: $!"; |
332 close(FILE); |
356 # write back @lines we modified earlier |
333 } |
357 print C @lines; |
334 else { |
358 close C; |
335 open(FILE, "<$conf_file") or die "$conf_file: $!\n"; |
359 |
336 @c_content = <FILE>; |
360 print " * zonekonfiguration aktualisiert ($czf ==> $zf)\n"; |
337 close(FILE); |
361 |
338 for (@c_content) { |
362 } |
339 if (m{(.*)($zone_file)\.signed(.*)}) { |
363 |
340 print |
|
341 " * zonekonfiguration aktualisiert ($2.signed ==> $2)\n"; |
|
342 $_ = "$1$2$3\n"; |
|
343 } |
|
344 } |
|
345 open(FILE, ">$conf_file") or die "$conf_file: $!\n"; |
|
346 print FILE @c_content; |
|
347 close(FILE); |
|
348 } |
|
349 } |
|
350 } |
364 } |
351 |
365 |
352 sub server_reload { |
366 sub server_reload { |
353 if (`rndc reload`) { print "** reload dns-server \n" } |
367 if (`rndc reload`) { print "** reload dns-server \n" } |
354 } |
368 } |