--- a/.hgignore Tue Jan 11 23:37:09 2011 +0100
+++ b/.hgignore Thu Jan 13 00:20:26 2011 +0100
@@ -1,8 +1,2 @@
-.hgignore
-dnssec-keytool
-update-serial
-zone-ls
-zone-mk
-zone-rm
bind
-dnstools.geany
+blib
--- a/Build.PL Tue Jan 11 23:37:09 2011 +0100
+++ b/Build.PL Thu Jan 13 00:20:26 2011 +0100
@@ -2,6 +2,7 @@
my $build = Module::Build->new(
module_name => "dnstools",
dist_version => "0.1",
+ license => "perl",
);
$build->create_build_script;
--- a/Makefile Tue Jan 11 23:37:09 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-DESTDIR =
-
-prefix = /usr/local
-bindir = ${prefix}/bin
-sbindir = ${prefix}/sbin
-libdir = ${prefix}/lib/dnstools
-sysconfdir = /etc/dnstools
-
-
-ALL = zone-ls zone-mk zone-rm \
- update-serial \
- dnssec-keytool
-
-CLEANFILES = $(ALL)
-
-.PHONY: all clean distclean install
-
-all: $(ALL)
-
-clean:
-
-distclean: clean
- -rm -f $(CLEANFILES)
-
-
-%: %.pl
- @perl -c $<
- @cp -f $< $@
- @chmod a+x-w $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/dnssec-keytool Thu Jan 13 00:20:26 2011 +0100
@@ -0,0 +1,350 @@
+#! /usr/bin/perl
+
+use v5.10;
+use warnings;
+use strict;
+use FindBin;
+use File::Temp;
+use Getopt::Long;
+use Pod::Usage;
+use File::Basename;
+use if $ENV{DEBUG} => "Smart::Comments";
+use DNStools::Config qw(get_config);
+
+my $ME = basename $0;
+
+sub read_conf(@);
+sub read_argv($);
+sub rm_keys($@);
+sub ck_zone($@);
+sub create_ksk($@);
+sub create_zsk($@);
+sub post_create($@);
+
+MAIN: {
+ ### reading config
+ my %conf = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
+
+ my ($cmd, @zones) = read_argv($conf{master_dir});
+
+ given ($cmd) {
+ when ("rm") { rm_keys($conf{master_dir}, @zones); exit }
+ when ("ck") { ck_zone($conf{master_dir}, @zones) }
+ when ("ksk") { create_ksk($conf{master_dir}, @zones) }
+ };
+
+ create_zsk($conf{master_dir}, @zones);
+ post_create($conf{master_dir}, @zones);
+}
+
+sub read_argv ($) {
+ my ($master_dir) = @_;
+ my ($cmd, @zones); # return
+
+ GetOptions(
+ "zsk" => sub { $cmd = "zsk" },
+ "ksk" => sub { $cmd = "ksk" },
+ "rm" => sub { $cmd = "rm" },
+ "ck|check" => sub { $cmd = "ck" },
+ "h|help" => sub { pod2usage(-exitvalue => 0, -verbose => 1) },
+ "m|man" => sub {
+ pod2usage(
+ -exitvalue => 0,
+ -noperldoc => system("perldoc -V &>/dev/null"),
+ -verbose => 2
+ );
+ },
+ )
+ and @ARGV
+ or pod2usage;
+
+ # checks the zones in argv if there are managed zones
+ foreach (@ARGV) {
+ chomp(my $zone = `idn --quiet "$_"`);
+
+ die "zone $zone is not managed\n"
+ if not -f "$master_dir/$zone/$zone";
+
+ push @zones, $zone;
+ }
+ return ($cmd, @zones);
+}
+
+
+sub rm_keys ($@) {
+
+ # deletes all the keys were handed over -rm in argv
+ my ($master_dir, @zone) = @_;
+
+ for (@zone) {
+ my $zone = $_;
+
+ my $zpf = "$master_dir/$zone";
+ my $ep = 0;
+
+ if (-e "$zpf/$zone.signed") {
+ unlink "$zpf/$zone.signed" and $ep = 1;
+ }
+ if (-e "$zpf/.keycounter") {
+ unlink "$zpf/.keycounter" and $ep = 1;
+ }
+ if (-e "$zpf/.index.ksk") {
+ unlink "$zpf/.index.ksk" and $ep = 1;
+ }
+ if (-e "$zpf/.index.zsk") {
+ unlink "$zpf/.index.zsk" and $ep = 1;
+ }
+ if (-e "$zpf/dsset-$zone.") {
+ unlink "$zpf/dsset-$zone." and $ep = 1;
+ }
+ if (-e "$zpf/keyset-$zone.") {
+ unlink "$zpf/keyset-$zone." and $ep = 1;
+ }
+
+ for (glob("$zpf/K$zone*")) {
+ chomp($_);
+ unlink("$_");
+ }
+
+ if ($ep == 1) {
+ print " * $zone: removed key-set\n";
+ }
+
+ open(my $old, "$zpf/$zone") or die "$zpf/$zone: $!\n";
+ my $fh = File::Temp->new(DIR => $zpf) or die "Can't create tmpfile: $!\n";
+ print $fh grep { not /^\s*\$INCLUDE.*"K$zone.*\.key"/i } <$old>;
+ rename($fh->filename => "$zpf/$zone")
+ or die "Can't rename " . $fh->filename . " to $zpf/$zone: $!\n";
+ }
+}
+
+sub create_ksk ($@) {
+ my ($master_dir, @zone) = @_;
+ my @index;
+ my $keyname;
+
+ for (@zone) {
+ my $zone = $_;
+ my $zpf = "$master_dir/$zone";
+
+ $keyname =
+ `cd $zpf && dnssec-keygen -a RSASHA1 -b 2048 -f KSK -n ZONE $zone`;
+
+ unless (-f "$zpf/.index.ksk") { @index = (); }
+ else {
+ open(INDEX, "$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
+ @index = <INDEX>;
+ close(INDEX);
+ }
+
+ push @index, $keyname;
+ if (@index > 2) { shift(@index); }
+
+ {
+ my $fh = File::Temp->new(DIR => "$zpf")
+ or die "Can't create tmpdir: $!\n";
+ print $fh join "" => @index, "";
+ rename($fh->filename => "$zpf/.index.ksk")
+ or die "Can't rename "
+ . $fh->filename
+ . " to $zpf/.index.ksk: $!\n";
+ }
+
+ chomp($keyname);
+ print " * $zone: new KSK $keyname\n";
+ print "!! THE KSK must be published !! \n";
+
+ }
+}
+
+sub create_zsk ($@) {
+ my ($master_dir, @zone) = @_;
+ my @index;
+ my $keyname;
+
+ for (@zone) {
+ my $zone = $_;
+ my $zpf = "$master_dir/$zone";
+
+ $keyname = `cd $zpf && dnssec-keygen -a RSASHA1 -b 512 -n ZONE $zone`;
+
+ unless (-f "$zpf/.index.zsk") {
+ @index = ();
+ }
+ else {
+ open(INDEX, "$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
+ @index = <INDEX>;
+ close(INDEX);
+ }
+
+ push @index, $keyname;
+ if (@index > 2) { shift(@index); }
+
+ {
+ my $fh = File::Temp->new(DIR => "$zpf")
+ or die "Can't create tmpdir: $!\n";
+ print $fh join "" => @index, "";
+ rename($fh->filename => "$zpf/.index.zsk")
+ or die "Can't rename "
+ . $fh->filename
+ . " to $zpf/.index.zsk: $!\n";
+ }
+ chomp($keyname);
+ print " * $zone: new ZSK $keyname\n";
+
+ open(KC, ">$zpf/.keycounter") or die "$zpf/keycounter: $!\n";
+ print KC "0";
+ close(KC);
+ }
+}
+
+sub ck_zone ($@) {
+ my ($master_dir, @zone) = @_;
+
+ for (@zone) {
+ my $zone = $_;
+ my $zpf = "$master_dir/$zone";
+ my $keyfile;
+ my @content;
+ my @keylist;
+
+ for (<$zpf/*>) {
+ if (m#(K$zone.*\.key)#) {
+ $keyfile = $1;
+ open(KEYFILE, "<", "$zpf/$keyfile")
+ or die "$zpf/$keyfile: $!\n";
+ @content = <KEYFILE>;
+ close(KEYFILE);
+ for (@content) {
+ if (m#DNSKEY.257#) {
+ push @keylist, $keyfile;
+ }
+ }
+ }
+ }
+
+ open(INDEX, ">$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
+ for (@keylist) {
+ s#\.key##;
+ print INDEX "$_\n";
+ }
+ close(INDEX);
+
+ print " * $zone: new .index.ksk created\n";
+ if (-f "$zpf/.index.zsk") {
+ unlink("$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
+ }
+ }
+}
+
+sub post_create ($@) {
+ my ($master_dir, @zone) = @_;
+ for (@zone) {
+ my $zone = $_;
+ `touch $master_dir/$zone/$zone`;
+ &kill_useless_keys($zone, $master_dir);
+ &key_to_zonefile($zone, $master_dir);
+ }
+}
+
+sub kill_useless_keys ($@) {
+
+ # the function deletes all keys that are not available in the zone
+
+ my $zone = $_[0];
+ my $master_dir = $_[1];
+ my @keylist = ();
+ my $zpf = "$master_dir/$zone";
+
+ open(INDEX, "<$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
+ @keylist = <INDEX>;
+ close(INDEX);
+ open(INDEX, "<$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
+ push @keylist, <INDEX>;
+
+ # shortened the key name from the index file on the id in order to
+ # be able to compare
+ for (@keylist) {
+ chomp;
+ s#K.*\+.*\+(.*)#$1#;
+ }
+
+ # reviewed every key file (KSK, ZSK), whether they are described in
+ # the respective index file. if not they will be deleted.
+ for (glob("$master_dir/$zone/K*")) {
+ chomp;
+ my $file = $_;
+ my $rm_count = 1;
+ my $keyname;
+ for (@keylist) {
+ if ($file =~ /$_/) { $rm_count = 0; }
+ }
+ if ($rm_count == 1) {
+ unlink "$file";
+ if ($file =~ /$zpf\/(.*\.key)/) {
+ print " * $zone: Key $1 removed \n";
+ }
+ }
+ }
+}
+
+sub key_to_zonefile ($@) {
+
+ # the function added all keys to the indexfile
+ my $zone = $_[0];
+ my $master_dir = $_[1];
+ my $zpf = "$master_dir/$zone";
+ my @old_content;
+ my @new_content = ();
+
+ open(ZONEFILE, "<$zpf/$zone");
+ @old_content = <ZONEFILE>;
+ close(ZONEFILE);
+
+ for (@old_content) {
+ unless (m#INCLUDE.*key#) { push @new_content, $_; }
+ }
+
+ for (<$zpf/*>) {
+ if (m#(.*\/)(K.*\.key)#) {
+ push @new_content, "\$INCLUDE \"$2\"\n";
+ }
+ }
+ open(ZONEFILE, ">$zpf/$zone") or die "$zpf/$zone: $!\n";
+ print ZONEFILE @new_content;
+ close(ZONEFILE);
+}
+
+__END__
+
+=pod
+
+=head1 NAME
+
+dnssec-keytool
+
+=head1 SYNOPSIS
+
+dnssec-keytool {-z|-k|-r|-c} zone
+
+=head1 DESCRIPTION
+
+Blabla.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-z> created a new ZSK
+
+=item B<-k> created a new ZSK and KSK
+
+=item B<-r> delete the key-set of a zone
+
+=item B<-c> created configuration files for the dnstools and a new ZSK for an existing KSK
+
+=back
+
+=cut
+
+# vim:sts=4 sw=4 aw ai sm:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/update-serial Thu Jan 13 00:20:26 2011 +0100
@@ -0,0 +1,548 @@
+#!/usr/bin/perl
+
+use v5.10;
+use strict;
+use warnings;
+
+use FindBin;
+use File::Basename;
+use Pod::Usage;
+use Getopt::Long;
+use File::Temp;
+use IO::File;
+use POSIX qw(strftime);
+use if $ENV{DEBUG} => "Smart::Comments";
+use DNStools::Config qw(get_config);
+
+sub uniq(@);
+sub zones(@);
+sub changed_zones();
+sub update_index($);
+sub signature_expired($);
+sub need_rollover();
+sub done_rollover();
+sub begin_rollover(@);
+sub end_rollover(@);
+sub unlink_unused_keys($);
+sub include_keys($);
+sub sign($);
+sub update_serial($);
+
+sub mk_zone_conf;
+sub file_entry;
+sub server_reload;
+
+my %config;
+my %opt;
+
+MAIN: {
+
+ GetOptions(
+ "sign-alert-time=i" => \$opt{sign_alert_time},
+ "key-counter-end=i" => \$opt{key_counter_end},
+ "h|help" => sub { pod2usage(-exit 0, -verbose => 1) },
+ "m|man" => sub {
+ pod2usage(
+ -exit 0,
+ -verbose => 2,
+ -noperldoc => system("perldoc -v &>/dev/null")
+ );
+ },
+ ) or pod2usage;
+
+ # merge the config and the defined options from commandline
+ %config = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf", \%opt);
+
+ our $bind_dir = $config{bind_dir};
+ our $conf_dir = $config{zone_conf_dir};
+
+ my @candidates = @ARGV ? zones(@ARGV) : changed_zones;
+ push @candidates, update_index($config{indexzone});
+ push @candidates, signature_expired($config{sign_alert_time});
+
+ my @need_rollover = need_rollover;
+ my @done_rollover = done_rollover;
+
+ push @candidates, begin_rollover(@need_rollover);
+ push @candidates, end_rollover(@done_rollover);
+
+ foreach my $zone (uniq(@candidates)) {
+ update_serial($zone);
+ sign($zone);
+ }
+ say "Need to ... file_entry, mk_zone_conf, server_reload";
+ exit;
+
+ file_entry; # bearbeitet die file-eintraege der konfigurations-datei
+ mk_zone_conf; # konfiguration zusammenfuegen
+ server_reload; # server neu laden
+
+}
+
+sub uniq(@) {
+
+ # remove duplicate entries
+ my %all;
+ @all{@_} = ();
+ keys %all;
+}
+
+sub zones(@) {
+
+ # check whether the zones in argv are managed zones and
+ # insert them into the list new_serial
+
+ my @r;
+
+ foreach (@_) {
+ chomp(my $zone = `idn --quiet "$_"`);
+ die "$zone is not managed\n"
+ if not -e "$config{master_dir}/$zone/$zone";
+ push @r, $zone;
+ }
+
+ return @r;
+}
+
+sub changed_zones() {
+
+ # find candidates in our master dir
+ my @r;
+
+ while (glob "$config{master_dir}/*") {
+ my $zone = basename($_);
+
+ if (not -e "$_/.stamp") {
+ say " * $zone: no .stamp file found"; # NOCH IN NEW_SERIAL PUSHEN
+ push @r, $zone;
+ next;
+ }
+
+ my $stamp_age = -M _;
+ my $file_age = -M "$_/$zone";
+
+ next if $stamp_age <= $file_age; # should be only <
+
+ push @r, $zone;
+ say " * $zone: zone file modified";
+ }
+ return @r;
+}
+
+sub signature_expired($) {
+ my $sign_alert_time = shift; # the time between the end and the new signing
+ # (see external configuration)
+ my @r;
+
+# erzeugt $time (die zeit ab der neu signiert werden soll)
+# ... warum eigentlich nur bis zu den Stunden und nicht auch Minuten und Sekunden?
+ my $time = strftime("%Y%m%d%H" => localtime time + 3600 * $sign_alert_time);
+
+ ## vergleicht fuer alle zonen im ordner $config{master_dir} mit einer
+ ## <zone>.signed-datei den zeitpunkt in $time mit dem ablaufdatum der
+ ## signatur, welcher aus der datei <zone>.signed ausgelesen wird.
+ ZONE: while (my $dir = glob "$config{master_dir}/*") {
+ my $zone = basename $dir;
+
+ next if not -e "$dir/$zone.signed";
+
+ open(my $fh, "$dir/$zone.signed")
+ or die "Can't open $dir/$zone.signed: $!\n";
+ push @r, $zone
+ if /RRSIG\s+SOA[\d ]+(\d{10})\d{4}\s+\(/ ~~ [<$fh>]
+ and $1 < $time;
+ }
+
+ return @r;
+}
+
+sub sign($) {
+
+ my $zone = shift;
+ my $dir = "$config{master_dir}/$zone";
+
+ my $pid = fork // die "Can't fork: $!";
+
+ if ($pid == 0) {
+ chdir $dir or die "Can't chdir to $dir: $!\n";
+ exec "dnssec-signzone" => $zone;
+ die "Can't exec: $!\n";
+ }
+
+ wait == $pid or die "Child is lost: $!";
+ die "Can't sign zone!" if $?;
+
+ say " * $zone neu signiert";
+
+ open(my $fh, "+>>$dir/.keycounter")
+ or die "Can't open $dir/.keycounter for update: $!\n";
+ seek($fh, 0, 0);
+ my $kc = <$fh>;
+ truncate($fh, 0);
+ say $fh ++$kc;
+}
+
+sub update_serial($) {
+
+ my $zone = shift;
+
+ my $file = "$config{master_dir}/$zone/$zone";
+ my $in = IO::File->new($file) or die "Can't open $file: $!\n";
+ my $out = File::Temp->new(DIR => dirname $file)
+ or die "Can't open tmpfile: $!\n";
+ my $_ = join "" => <$in>;
+
+ my $serial;
+ s/^(\s+)(\d{10})(?=\s*;\s*serial)/$1 . ($serial = new_serial($2))/emi
+ or die "Serial number not found for replacement!";
+
+ print $out $_;
+
+ close($in);
+ close($out);
+
+ rename($out->filename => $file)
+ or die "Can't rename tmp to $file: $!\n";
+
+ $serial =~ s/\s*//g;
+ say " * $zone: serial incremented to $serial";
+
+ open(my $stamp, ">", dirname($file) . "/.stamp");
+ print $stamp time() . " " . localtime() . "\n";
+
+ say " * $zone: stamp aktualisiert";
+}
+
+sub new_serial($) {
+
+ my ($date, $cnt) = $_[0] =~ /(\d{8})(\d\d)/;
+
+ state $now = strftime("%4Y%02m%02d", localtime);
+
+ return $date eq $now
+ ? sprintf "%s%02d", $date, $cnt + 1
+ : "${now}00";
+
+}
+
+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($) {
+ my $indexzone = shift;
+
+ my @iz;
+
+ {
+ open(my $fh, "$config{master_dir}/$indexzone/$indexzone")
+ or die "$config{master_dir}/$indexzone/$indexzone: $!\n";
+ chomp(@iz = grep !/ZONE::/ => <$fh>);
+ }
+
+ for my $dir (glob "$config{master_dir}/*") {
+ my $zone = basename($dir);
+ my $info = -e ("$dir/.keycounter") ? "sec-on" : "sec-off";
+ push @iz, join "::", "\t\tIN TXT\t\t\"ZONE", $zone, $info;
+ }
+
+ {
+ my $fh = File::Temp->new(DIR => "$config{master_dir}/$indexzone")
+ or die "Can't create tmpdir: $!\n";
+ print $fh join "\n" => @iz, "";
+ rename($fh->filename => "$config{master_dir}/$indexzone/$indexzone")
+ or die "Can't rename "
+ . $fh->filename
+ . " to $config{master_dir}/$indexzone/$indexzone: $!\n";
+ }
+
+ say "** index-zone aktualisiert";
+ return $indexzone;
+}
+
+sub file_entry {
+
+ # prueft jede domain, die ein verzeichnis in $config{master_dir} hat, ob sie
+ # dnssec nutzt.
+ # passt die eintraege in $config_file falls noetig an.
+ our $conf_dir;
+
+ while (glob "$config{master_dir}/*") {
+ s#($config{master_dir}/)(.*)#$2#;
+ my $zone = $_;
+ my $zone_file = "$config{master_dir}/$zone/$zone";
+ my $conf_file = "$conf_dir/$zone";
+ my @c_content;
+
+ unless (-f "$conf_file") {
+ die "$conf_file: $! \n";
+ }
+
+ if (-e "$config{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" }
+}
+
+sub need_rollover() {
+
+ # gibt alle zonen mit abgelaufenen keycounter
+ my @r;
+
+ while (my $kc = glob "$config{master_dir}/*/.keycounter") {
+ my $zone = basename dirname $kc;
+ my $key;
+
+ {
+ open(my $fh, $kc) or die "$kc: $!\n";
+ chomp($key = <$fh>);
+ }
+
+ push @r, $zone if $config{key_counter_end} <= $key;
+ }
+
+ return @r;
+}
+
+sub done_rollover() {
+
+ # funktion ueberprueft ob ein keyrollover fertig ist
+ # die bedingung dafuer ist das:
+ # - eine datei .index.zsk vorhanden ist
+ # - die datei .index.zsk älter ist, als die rollover-Zeit
+ # - die datei .index.zsk ueber mehr als eine zeile gross ist
+ # (also mehr als einen Schlüssel enthält)
+ my @r;
+ my $now = time;
+
+ while (my $dir = glob "$config{master_dir}/*") {
+ my $zone = basename $dir;
+
+ my @index = ();
+ my $index_wc;
+
+ # prueft nach der ".index.zsk"-datei und erstellt den zeitpunkt
+ # an dem das key-rollover endet.
+ # rollover is done when mtime of the .index.zsk + abl_zeit is
+ # in the past
+ next if not -e "$dir/.index.zsk";
+ next if (stat _)[9] + 3600 * $config{abl_zeit} >= $now;
+
+ # prueft die anzahl der schluessel in der .index.zsk
+ open(my $fh, "$dir/.index.zsk") or die "$dir/.index.zsk: $!\n";
+ (<$fh>);
+ push @r, $zone if $. > 1;
+ }
+
+ return @r;
+}
+
+sub begin_rollover(@) {
+ my @zones = @_;
+ my @r;
+
+ # anfang des key-rollovers
+
+ foreach my $zone (@zones) {
+
+ # erzeugt zsks
+ my $dir = "$config{master_dir}/$zone";
+ my ($keyname, @keys);
+
+ # create a new key
+ { # need to change the direcoty, thus some more effort
+ # alternativly: $keyname = `cd $dir && dnssec-keygen ...`;
+ # would do, but is more fragile on shell meta characters
+
+ open(my $keygen, "-|") or do {
+ chdir $dir or die "Can't chdir to $dir: $!\n";
+ exec "dnssec-keygen",
+ -a => "RSASHA1",
+ -b => 512,
+ -n => "ZONE",
+ $zone;
+ die "Can't exec: $!";
+ };
+ chomp($keyname = <$keygen>);
+ close($keygen) or die "dnssec-keygen failed: $@";
+ }
+
+ open(my $fh, "+>>$dir/.index.zsk") or die "$dir/.index.zsk: $!\n";
+ seek($fh, 0, 0);
+ chomp(@keys = <$fh>);
+
+ ### @keys
+
+ push @keys, $keyname;
+ shift @keys if @keys > 2;
+
+ truncate($fh, 0) or die "truncate";
+ print $fh join "\n" => @keys;
+
+ print " * $zone: neuer ZSK $keyname erstellt\n";
+
+ open($fh, ">$dir/.keycounter") or die "$dir/.keycounter: $!\n";
+ say $fh 0;
+ close($fh);
+
+ unlink_unused_keys($zone);
+ include_keys($zone);
+ push @r, $zone;
+ }
+
+ return @r;
+}
+
+sub include_keys($) {
+
+ # die funktion fugt alle schluessel in eine zonedatei
+ my $zone = shift;
+ my $dir = "$config{master_dir}/$zone";
+
+ my $in = IO::File->new("$dir/$zone") or die "Can't open $dir/$zone: $!\n";
+ my $out = File::Temp->new(DIR => $dir) or die "Can't open tmpfile: $!\n";
+
+ print $out grep { !/\$include\s+.*key/i } $in;
+ print $out map { "\$INCLUDE @{[basename $_]}\n" } glob "$dir/K*key";
+
+ close $in;
+ close $out;
+ rename($out->filename => "$dir/$zone")
+ or die "Can't rename tmp to $dir/$zone: $!\n";
+
+}
+
+sub unlink_unused_keys($) {
+
+ # die funktion loescht alle schluessel die nicht in der index.zsk
+ # der uebergebenen zone stehen
+ my $zone = shift;
+
+ my @keys;
+ my $dir = "$config{master_dir}/$zone";
+
+ {
+
+ # collect the keys and cut everything except the key id
+ # we cut the basenames (w/o the .private|.key suffix)
+ open(my $zsk, "<$dir/.index.zsk") or die "$dir/.index.zsk: $!\n";
+ open(my $ksk, "<$dir/.index.ksk") or die "$dir/.index.ksk: $!\n";
+ @keys = (<$zsk>, <$ksk>);
+ }
+
+ # prueft alle schluesseldateien (ksk, zsk) ob sie in der jeweiligen
+ # indexdatei beschrieben sind. wenn nicht werden sie geloescht.
+ for my $file (glob "$dir/K*.key $dir/K*.private") {
+ unlink $file if basename($file, ".key", ".private") ~~ @keys;
+ }
+}
+
+sub end_rollover(@) {
+
+ my @zones = @_;
+ my @r;
+
+ foreach my $zone (@zones) {
+
+ my $dir = "$config{master_dir}/$zone";
+
+ open(my $fh, "+>>$dir/.index.zsk")
+ or die "Can't open $dir/.index.zsk: $!\n";
+ seek($fh, 0, 0);
+ chomp(my @keys = <$fh>);
+
+ if (@keys > 1) {
+ truncate($fh, 0);
+ say $fh $keys[-1];
+ }
+ close($fh);
+
+ unlink_unused_keys($zone);
+ include_keys($zone);
+ push @r => $zone;
+ }
+
+ return @r;
+}
+
+__END__
+
+=head1 NAME
+
+ update-serial - updates the serial numbers and re-signs the zone files
+
+=head1 SYNOPSIS
+
+ update-serial [options] [zone...]
+
+=head1 DESCRIPTION
+
+B<update-serial> scans the configured directories for modified zone files. On any
+file found it increments the serial number and signs the zone, if approbiate.
+
+=head1 OPTIONS
+
+=over
+
+=item B<--sign-alert-time> I<days>
+
+=item B<--key-counter-end> I<integer>
+
+Maximum number if key usages.
+
+
+=back
+
+The common options B<-h>|B<--help>|B<-m>|B<--man> are supported.
+
+=head1 AUTHOR
+
+L<andre.suess@pipkin.cc>
+
+=cut
+
+# vim:sts=4 sw=4 aw ai sm:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/zone-ls Thu Jan 13 00:20:26 2011 +0100
@@ -0,0 +1,145 @@
+#! /usr/bin/perl
+
+use v5.10;
+use strict;
+use warnings;
+use Pod::Usage;
+use File::Basename;
+use FindBin;
+use Time::Local;
+use Getopt::Long;
+use if $ENV{DEBUG} => "Smart::Comments";
+use DNStools::Config qw(get_config);
+
+my %config;
+my $opt_expiry = undef;
+
+MAIN: {
+ my %info; # will hold the information we collected
+
+ GetOptions(
+ "e|expiry" => \$opt_expiry,
+ "h|help" => sub { pod2usage(-exit => 0, -verbose => 1) },
+ "m|man" => sub {
+ pod2usage(
+ -exit => 0,
+ -verbose => 2,
+ -noperldoc => system("perldoc -V &>/dev/null")
+ );
+ },
+ ) or pod2usage;
+
+ %config = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
+ die "$config{master_dir}: $!\n" if not -d $config{master_dir};
+
+ foreach my $dir (grep { -d } glob "$config{master_dir}/*") {
+
+ my $zone = basename($dir);
+ $info{$zone} = { status => "OK" };
+
+ if (not -f "$dir/.index.zsk") {
+ $info{$zone}{zsk} = 0;
+ $info{$zone}{ksk} = 0;
+ $info{$zone}{kc} = 0;
+ $info{$zone}{end} = "-";
+ $info{$zone}{expiry} = undef;
+ next;
+ }
+
+ # prueft wie viele zsks genutzt werden
+ {
+ open(my ($fh), $_ = "<$dir/.index.zsk")
+ or die "Can't open $_: $!\n";
+ () = <$fh>;
+ $info{$zone}{zsk} = $.
+ }
+
+ # prueft wie viele ksks genutzt werden
+ {
+ open(my ($fh), $_ = "<$dir/.index.ksk")
+ or die "Can't open $_: $!\n";
+ () = <$fh>;
+ $info{$zone}{ksk} = $.
+ }
+
+ # prueft wie oft die schluessel zum signieren genutzt wurden
+ {
+ open(my ($fh), $_ = "<$dir/.keycounter")
+ or die "Can't open $_: $!\n";
+ chomp($info{$zone}{kc} = <$fh>);
+ }
+
+ # prueft das ablaufdatum
+ if (!-f "$dir/$zone.signed") {
+ $info{$zone}{end} = "-";
+ next;
+ }
+
+ open(my ($fh), $_ = "<$dir/$zone.signed") or die "Can't open $_: $!\n";
+ while (<$fh>) {
+ next if not /RSIG\s+SOA\s.*\s
+ (?<year>\d\d\d\d)
+ (?<mon>\d\d)
+ (?<day>\d\d)
+ (?<hour>\d\d)
+ (?<min>\d\d)\d+\s\(/ix;
+ $info{$zone}{end} = "$+{day}.$+{mon}.$+{year} $+{hour}:$+{min}";
+ $info{$zone}{expiry} =
+ timelocal(0, $+{min}, $+{hour}, $+{day}, $+{mon} - 1, $+{year});
+ }
+ }
+
+ { # output
+
+ my $sort_by =
+ $opt_expiry
+ ? sub { ($info{$a}{expiry} // 2**64) <=> ($info{$b}{expiry} // 2**64) }
+ : sub { $a cmp $b };
+
+ my $format_h = "%-35s %-8s %1s/%1s %3s %7s\n";
+ my $format_l = "%-35s %-8s %1d/%1d %5d %19s\n";
+
+ printf $format_h => qw(Domain Status ZSK KSK Used Sig-end);
+
+ foreach my $zone (sort $sort_by keys %info) {
+ printf $format_l => $zone,
+ @{ $info{$zone} }{qw(status zsk ksk kc end)};
+ }
+ }
+}
+
+__END__
+
+=head1 NAME
+
+ zone-ls -- lists all zones
+
+=head1 SYNOPSIS
+
+ zone-ls [-e|--expiry]
+
+=head1 DESCRIPTION
+
+This B<zone-ls> lists all zones under control of our dnstools suite. The output is ordered by domain name.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-e>|B<--expiry>
+
+Order the output by expiry date. The sooner the key expires, the more top the
+domain is listed.
+
+=back
+
+Additionally the common B<-h>|B<--help>|B<-m>|B<--man> options, which should be
+self explanatory.
+
+=head1 AUTHORS
+
+L<andre.suess@pipkin.cc>
+
+=cut
+
+# vim:ts=4 sw=4 ai si aw:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/zone-mk Thu Jan 13 00:20:26 2011 +0100
@@ -0,0 +1,120 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use FindBin;
+use DNStools::Config qw(get_config);
+
+my %config;
+
+if (@ARGV < 2) {
+ print "usage: zone-mk kundennummer domain ... \n";
+ exit 1;
+}
+
+# oeffnet Konfigurations- und Templatefiles - relativ oder absolut
+my @configs = ("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
+my @templc = (
+ "$FindBin::Bin/templates/named.config",
+ "/etc/dnstools/templates/named.config"
+);
+my @templz =
+ ("$FindBin::Bin/templates/named.zone", "/etc/dnstools/templates/named.zone");
+
+for (grep { -f } @templc) {
+ open(TEMPCONF, $_) or die "Can't open $_: $!\n";
+}
+unless (seek(TEMPCONF, 0, 0)) {
+ die "Can't open template (searched: @templc)\n";
+}
+
+for (grep { -f } @templz) {
+ open(TEMPZONE, $_) or die "Can't open $_: $!\n";
+}
+unless (seek(TEMPZONE, 0, 0)) {
+ die "Can't open template (searched: @templz)\n";
+}
+
+
+%config = get_config(@configs);
+
+my $primary = $config{primary};
+my $secondary = $config{secondary};
+my $zone_conf_dir = $config{zone_conf_dir};
+my $master_dir = $config{master_dir};
+my $customer = shift @ARGV;
+chomp(my $primary_ip = `dig +short $primary`);
+chomp(my $secondary_ip = `dig +short $secondary`);
+chomp(my $this_host = `hostname -f`);
+chomp(my $this_ip = `hostname -i`);
+chomp(my $this_domain = `hostname -d`);
+chomp(my $time = `date +%Y%m%d00`);
+chomp(my $start = `date -I`);
+my $hostmaster = "hostmaster.$this_domain";
+
+unless (-d $master_dir and -r $master_dir) {
+ die "$master_dir: $!\n";
+}
+
+unless (-d $zone_conf_dir and -r $zone_conf_dir) {
+ die "$master_dir: $!\n";
+}
+
+# legt fuer jede domain in @ARGV ein verzeichnis in $master_dir an.
+# schreibt aus den angegebenen templates die dateien $zonefile und $config
+# in die entsprechenden verzeichnisse.
+for (@ARGV) {
+
+ chomp(my $domain = `idn --quiet "$_"`);
+ my $zonefile = "$master_dir/$domain/$domain";
+ my $config = "$zone_conf_dir/$domain";
+ my $utf8domain = "$_";
+
+ unless (-d "$master_dir/$domain") {
+ `mkdir $master_dir/$domain`;
+ }
+
+ if (-f $zonefile) {
+ $zonefile =~ s#/.*/##;
+ print "$zonefile exists. Skipping $domain\n";
+ next;
+ }
+ if (-f $config) {
+ $config =~ s#/.*/##;
+ print "$config exists. Skipping $domain\n";
+ next;
+ }
+
+ print "$domain ($_) for $customer \n";
+
+ my @tempzone = <TEMPZONE>;
+ for (@tempzone) {
+ s#<start>#$start#;
+ s#<domain>#$domain#;
+ s#<time>#$time#;
+ s#<primary>#$primary#;
+ s#<secondary>#$secondary#;
+ s#<hostmaster>#$hostmaster#;
+ s#<customer>#$customer#;
+ s#<utf8domain>#$utf8domain#;
+ }
+
+ open(ZONEOUT, ">$zonefile");
+ print ZONEOUT @tempzone;
+ close(ZONEOUT);
+
+ my @tempconf = <TEMPCONF>;
+ for (@tempconf) {
+ s#<domain>#$domain#;
+ s#<start>#$start#;
+ s#<customer>#$customer#;
+ s#<utf8domain>#$utf8domain#;
+ s#<file>#$master_dir/$domain/$domain#;
+ s#<primary_ip>#$primary_ip#;
+ s#<secondary_ip>#$secondary_ip#;
+ }
+
+ open(CONFOUT, ">$config");
+ print CONFOUT @tempconf;
+ close(CONFOUT);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/zone-rm Thu Jan 13 00:20:26 2011 +0100
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use File::Path;
+use FindBin;
+use DNStools::Config qw(get_config);
+
+# liest die Konfiguration ein
+my %config = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
+
+my $master_dir = $config{"master_dir"};
+my $conf_dir = $config{"zone_conf_dir"};
+
+for (@ARGV) {
+ chomp(my $zone = `idn --quiet "$_"`);
+
+ if (-d "$master_dir/$zone") {
+ rmtree "$master_dir/$zone/"
+ and print "zone-dir for $zone removed\n";
+ }
+ else {
+ print "$master_dir/$zone: $!\n";
+ }
+
+ if (-e "$conf_dir/$zone") {
+ unlink "$conf_dir/$zone"
+ and print "configuration-file for $zone removed\n";
+ }
+ else {
+ print "$conf_dir/$zone: $!\n";
+ }
+}
--- a/dnssec-keytool.pl Tue Jan 11 23:37:09 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,350 +0,0 @@
-#! /usr/bin/perl
-
-use v5.10;
-use warnings;
-use strict;
-use FindBin;
-use File::Temp;
-use Getopt::Long;
-use Pod::Usage;
-use File::Basename;
-use if $ENV{DEBUG} => "Smart::Comments";
-use DNStools::Config qw(get_config);
-
-my $ME = basename $0;
-
-sub read_conf(@);
-sub read_argv($);
-sub rm_keys($@);
-sub ck_zone($@);
-sub create_ksk($@);
-sub create_zsk($@);
-sub post_create($@);
-
-MAIN: {
- ### reading config
- my %conf = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
-
- my ($cmd, @zones) = read_argv($conf{master_dir});
-
- given ($cmd) {
- when ("rm") { rm_keys($conf{master_dir}, @zones); exit }
- when ("ck") { ck_zone($conf{master_dir}, @zones) }
- when ("ksk") { create_ksk($conf{master_dir}, @zones) }
- };
-
- create_zsk($conf{master_dir}, @zones);
- post_create($conf{master_dir}, @zones);
-}
-
-sub read_argv ($) {
- my ($master_dir) = @_;
- my ($cmd, @zones); # return
-
- GetOptions(
- "zsk" => sub { $cmd = "zsk" },
- "ksk" => sub { $cmd = "ksk" },
- "rm" => sub { $cmd = "rm" },
- "ck|check" => sub { $cmd = "ck" },
- "h|help" => sub { pod2usage(-exitvalue => 0, -verbose => 1) },
- "m|man" => sub {
- pod2usage(
- -exitvalue => 0,
- -noperldoc => system("perldoc -V &>/dev/null"),
- -verbose => 2
- );
- },
- )
- and @ARGV
- or pod2usage;
-
- # checks the zones in argv if there are managed zones
- foreach (@ARGV) {
- chomp(my $zone = `idn --quiet "$_"`);
-
- die "zone $zone is not managed\n"
- if not -f "$master_dir/$zone/$zone";
-
- push @zones, $zone;
- }
- return ($cmd, @zones);
-}
-
-
-sub rm_keys ($@) {
-
- # deletes all the keys were handed over -rm in argv
- my ($master_dir, @zone) = @_;
-
- for (@zone) {
- my $zone = $_;
-
- my $zpf = "$master_dir/$zone";
- my $ep = 0;
-
- if (-e "$zpf/$zone.signed") {
- unlink "$zpf/$zone.signed" and $ep = 1;
- }
- if (-e "$zpf/.keycounter") {
- unlink "$zpf/.keycounter" and $ep = 1;
- }
- if (-e "$zpf/.index.ksk") {
- unlink "$zpf/.index.ksk" and $ep = 1;
- }
- if (-e "$zpf/.index.zsk") {
- unlink "$zpf/.index.zsk" and $ep = 1;
- }
- if (-e "$zpf/dsset-$zone.") {
- unlink "$zpf/dsset-$zone." and $ep = 1;
- }
- if (-e "$zpf/keyset-$zone.") {
- unlink "$zpf/keyset-$zone." and $ep = 1;
- }
-
- for (glob("$zpf/K$zone*")) {
- chomp($_);
- unlink("$_");
- }
-
- if ($ep == 1) {
- print " * $zone: removed key-set\n";
- }
-
- open(my $old, "$zpf/$zone") or die "$zpf/$zone: $!\n";
- my $fh = File::Temp->new(DIR => $zpf) or die "Can't create tmpfile: $!\n";
- print $fh grep { not /^\s*\$INCLUDE.*"K$zone.*\.key"/i } <$old>;
- rename($fh->filename => "$zpf/$zone")
- or die "Can't rename " . $fh->filename . " to $zpf/$zone: $!\n";
- }
-}
-
-sub create_ksk ($@) {
- my ($master_dir, @zone) = @_;
- my @index;
- my $keyname;
-
- for (@zone) {
- my $zone = $_;
- my $zpf = "$master_dir/$zone";
-
- $keyname =
- `cd $zpf && dnssec-keygen -a RSASHA1 -b 2048 -f KSK -n ZONE $zone`;
-
- unless (-f "$zpf/.index.ksk") { @index = (); }
- else {
- open(INDEX, "$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
- @index = <INDEX>;
- close(INDEX);
- }
-
- push @index, $keyname;
- if (@index > 2) { shift(@index); }
-
- {
- my $fh = File::Temp->new(DIR => "$zpf")
- or die "Can't create tmpdir: $!\n";
- print $fh join "" => @index, "";
- rename($fh->filename => "$zpf/.index.ksk")
- or die "Can't rename "
- . $fh->filename
- . " to $zpf/.index.ksk: $!\n";
- }
-
- chomp($keyname);
- print " * $zone: new KSK $keyname\n";
- print "!! THE KSK must be published !! \n";
-
- }
-}
-
-sub create_zsk ($@) {
- my ($master_dir, @zone) = @_;
- my @index;
- my $keyname;
-
- for (@zone) {
- my $zone = $_;
- my $zpf = "$master_dir/$zone";
-
- $keyname = `cd $zpf && dnssec-keygen -a RSASHA1 -b 512 -n ZONE $zone`;
-
- unless (-f "$zpf/.index.zsk") {
- @index = ();
- }
- else {
- open(INDEX, "$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
- @index = <INDEX>;
- close(INDEX);
- }
-
- push @index, $keyname;
- if (@index > 2) { shift(@index); }
-
- {
- my $fh = File::Temp->new(DIR => "$zpf")
- or die "Can't create tmpdir: $!\n";
- print $fh join "" => @index, "";
- rename($fh->filename => "$zpf/.index.zsk")
- or die "Can't rename "
- . $fh->filename
- . " to $zpf/.index.zsk: $!\n";
- }
- chomp($keyname);
- print " * $zone: new ZSK $keyname\n";
-
- open(KC, ">$zpf/.keycounter") or die "$zpf/keycounter: $!\n";
- print KC "0";
- close(KC);
- }
-}
-
-sub ck_zone ($@) {
- my ($master_dir, @zone) = @_;
-
- for (@zone) {
- my $zone = $_;
- my $zpf = "$master_dir/$zone";
- my $keyfile;
- my @content;
- my @keylist;
-
- for (<$zpf/*>) {
- if (m#(K$zone.*\.key)#) {
- $keyfile = $1;
- open(KEYFILE, "<", "$zpf/$keyfile")
- or die "$zpf/$keyfile: $!\n";
- @content = <KEYFILE>;
- close(KEYFILE);
- for (@content) {
- if (m#DNSKEY.257#) {
- push @keylist, $keyfile;
- }
- }
- }
- }
-
- open(INDEX, ">$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
- for (@keylist) {
- s#\.key##;
- print INDEX "$_\n";
- }
- close(INDEX);
-
- print " * $zone: new .index.ksk created\n";
- if (-f "$zpf/.index.zsk") {
- unlink("$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
- }
- }
-}
-
-sub post_create ($@) {
- my ($master_dir, @zone) = @_;
- for (@zone) {
- my $zone = $_;
- `touch $master_dir/$zone/$zone`;
- &kill_useless_keys($zone, $master_dir);
- &key_to_zonefile($zone, $master_dir);
- }
-}
-
-sub kill_useless_keys ($@) {
-
- # the function deletes all keys that are not available in the zone
-
- my $zone = $_[0];
- my $master_dir = $_[1];
- my @keylist = ();
- my $zpf = "$master_dir/$zone";
-
- open(INDEX, "<$zpf/.index.zsk") or die "$zpf/.index.zsk: $!\n";
- @keylist = <INDEX>;
- close(INDEX);
- open(INDEX, "<$zpf/.index.ksk") or die "$zpf/.index.ksk: $!\n";
- push @keylist, <INDEX>;
-
- # shortened the key name from the index file on the id in order to
- # be able to compare
- for (@keylist) {
- chomp;
- s#K.*\+.*\+(.*)#$1#;
- }
-
- # reviewed every key file (KSK, ZSK), whether they are described in
- # the respective index file. if not they will be deleted.
- for (glob("$master_dir/$zone/K*")) {
- chomp;
- my $file = $_;
- my $rm_count = 1;
- my $keyname;
- for (@keylist) {
- if ($file =~ /$_/) { $rm_count = 0; }
- }
- if ($rm_count == 1) {
- unlink "$file";
- if ($file =~ /$zpf\/(.*\.key)/) {
- print " * $zone: Key $1 removed \n";
- }
- }
- }
-}
-
-sub key_to_zonefile ($@) {
-
- # the function added all keys to the indexfile
- my $zone = $_[0];
- my $master_dir = $_[1];
- my $zpf = "$master_dir/$zone";
- my @old_content;
- my @new_content = ();
-
- open(ZONEFILE, "<$zpf/$zone");
- @old_content = <ZONEFILE>;
- close(ZONEFILE);
-
- for (@old_content) {
- unless (m#INCLUDE.*key#) { push @new_content, $_; }
- }
-
- for (<$zpf/*>) {
- if (m#(.*\/)(K.*\.key)#) {
- push @new_content, "\$INCLUDE \"$2\"\n";
- }
- }
- open(ZONEFILE, ">$zpf/$zone") or die "$zpf/$zone: $!\n";
- print ZONEFILE @new_content;
- close(ZONEFILE);
-}
-
-__END__
-
-=pod
-
-=head1 NAME
-
-dnssec-keytool
-
-=head1 SYNOPSIS
-
-dnssec-keytool {-z|-k|-r|-c} zone
-
-=head1 DESCRIPTION
-
-Blabla.
-
-=head1 OPTIONS
-
-=over
-
-=item B<-z> created a new ZSK
-
-=item B<-k> created a new ZSK and KSK
-
-=item B<-r> delete the key-set of a zone
-
-=item B<-c> created configuration files for the dnstools and a new ZSK for an existing KSK
-
-=back
-
-=cut
-
-# vim:sts=4 sw=4 aw ai sm:
--- a/update-serial.pl Tue Jan 11 23:37:09 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,548 +0,0 @@
-#!/usr/bin/perl
-
-use v5.10;
-use strict;
-use warnings;
-
-use FindBin;
-use File::Basename;
-use Pod::Usage;
-use Getopt::Long;
-use File::Temp;
-use IO::File;
-use POSIX qw(strftime);
-use if $ENV{DEBUG} => "Smart::Comments";
-use DNStools::Config qw(get_config);
-
-sub uniq(@);
-sub zones(@);
-sub changed_zones();
-sub update_index($);
-sub signature_expired($);
-sub need_rollover();
-sub done_rollover();
-sub begin_rollover(@);
-sub end_rollover(@);
-sub unlink_unused_keys($);
-sub include_keys($);
-sub sign($);
-sub update_serial($);
-
-sub mk_zone_conf;
-sub file_entry;
-sub server_reload;
-
-my %config;
-my %opt;
-
-MAIN: {
-
- GetOptions(
- "sign-alert-time=i" => \$opt{sign_alert_time},
- "key-counter-end=i" => \$opt{key_counter_end},
- "h|help" => sub { pod2usage(-exit 0, -verbose => 1) },
- "m|man" => sub {
- pod2usage(
- -exit 0,
- -verbose => 2,
- -noperldoc => system("perldoc -v &>/dev/null")
- );
- },
- ) or pod2usage;
-
- # merge the config and the defined options from commandline
- %config = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf", \%opt);
-
- our $bind_dir = $config{bind_dir};
- our $conf_dir = $config{zone_conf_dir};
-
- my @candidates = @ARGV ? zones(@ARGV) : changed_zones;
- push @candidates, update_index($config{indexzone});
- push @candidates, signature_expired($config{sign_alert_time});
-
- my @need_rollover = need_rollover;
- my @done_rollover = done_rollover;
-
- push @candidates, begin_rollover(@need_rollover);
- push @candidates, end_rollover(@done_rollover);
-
- foreach my $zone (uniq(@candidates)) {
- update_serial($zone);
- sign($zone);
- }
- say "Need to ... file_entry, mk_zone_conf, server_reload";
- exit;
-
- file_entry; # bearbeitet die file-eintraege der konfigurations-datei
- mk_zone_conf; # konfiguration zusammenfuegen
- server_reload; # server neu laden
-
-}
-
-sub uniq(@) {
-
- # remove duplicate entries
- my %all;
- @all{@_} = ();
- keys %all;
-}
-
-sub zones(@) {
-
- # check whether the zones in argv are managed zones and
- # insert them into the list new_serial
-
- my @r;
-
- foreach (@_) {
- chomp(my $zone = `idn --quiet "$_"`);
- die "$zone is not managed\n"
- if not -e "$config{master_dir}/$zone/$zone";
- push @r, $zone;
- }
-
- return @r;
-}
-
-sub changed_zones() {
-
- # find candidates in our master dir
- my @r;
-
- while (glob "$config{master_dir}/*") {
- my $zone = basename($_);
-
- if (not -e "$_/.stamp") {
- say " * $zone: no .stamp file found"; # NOCH IN NEW_SERIAL PUSHEN
- push @r, $zone;
- next;
- }
-
- my $stamp_age = -M _;
- my $file_age = -M "$_/$zone";
-
- next if $stamp_age <= $file_age; # should be only <
-
- push @r, $zone;
- say " * $zone: zone file modified";
- }
- return @r;
-}
-
-sub signature_expired($) {
- my $sign_alert_time = shift; # the time between the end and the new signing
- # (see external configuration)
- my @r;
-
-# erzeugt $time (die zeit ab der neu signiert werden soll)
-# ... warum eigentlich nur bis zu den Stunden und nicht auch Minuten und Sekunden?
- my $time = strftime("%Y%m%d%H" => localtime time + 3600 * $sign_alert_time);
-
- ## vergleicht fuer alle zonen im ordner $config{master_dir} mit einer
- ## <zone>.signed-datei den zeitpunkt in $time mit dem ablaufdatum der
- ## signatur, welcher aus der datei <zone>.signed ausgelesen wird.
- ZONE: while (my $dir = glob "$config{master_dir}/*") {
- my $zone = basename $dir;
-
- next if not -e "$dir/$zone.signed";
-
- open(my $fh, "$dir/$zone.signed")
- or die "Can't open $dir/$zone.signed: $!\n";
- push @r, $zone
- if /RRSIG\s+SOA[\d ]+(\d{10})\d{4}\s+\(/ ~~ [<$fh>]
- and $1 < $time;
- }
-
- return @r;
-}
-
-sub sign($) {
-
- my $zone = shift;
- my $dir = "$config{master_dir}/$zone";
-
- my $pid = fork // die "Can't fork: $!";
-
- if ($pid == 0) {
- chdir $dir or die "Can't chdir to $dir: $!\n";
- exec "dnssec-signzone" => $zone;
- die "Can't exec: $!\n";
- }
-
- wait == $pid or die "Child is lost: $!";
- die "Can't sign zone!" if $?;
-
- say " * $zone neu signiert";
-
- open(my $fh, "+>>$dir/.keycounter")
- or die "Can't open $dir/.keycounter for update: $!\n";
- seek($fh, 0, 0);
- my $kc = <$fh>;
- truncate($fh, 0);
- say $fh ++$kc;
-}
-
-sub update_serial($) {
-
- my $zone = shift;
-
- my $file = "$config{master_dir}/$zone/$zone";
- my $in = IO::File->new($file) or die "Can't open $file: $!\n";
- my $out = File::Temp->new(DIR => dirname $file)
- or die "Can't open tmpfile: $!\n";
- my $_ = join "" => <$in>;
-
- my $serial;
- s/^(\s+)(\d{10})(?=\s*;\s*serial)/$1 . ($serial = new_serial($2))/emi
- or die "Serial number not found for replacement!";
-
- print $out $_;
-
- close($in);
- close($out);
-
- rename($out->filename => $file)
- or die "Can't rename tmp to $file: $!\n";
-
- $serial =~ s/\s*//g;
- say " * $zone: serial incremented to $serial";
-
- open(my $stamp, ">", dirname($file) . "/.stamp");
- print $stamp time() . " " . localtime() . "\n";
-
- say " * $zone: stamp aktualisiert";
-}
-
-sub new_serial($) {
-
- my ($date, $cnt) = $_[0] =~ /(\d{8})(\d\d)/;
-
- state $now = strftime("%4Y%02m%02d", localtime);
-
- return $date eq $now
- ? sprintf "%s%02d", $date, $cnt + 1
- : "${now}00";
-
-}
-
-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($) {
- my $indexzone = shift;
-
- my @iz;
-
- {
- open(my $fh, "$config{master_dir}/$indexzone/$indexzone")
- or die "$config{master_dir}/$indexzone/$indexzone: $!\n";
- chomp(@iz = grep !/ZONE::/ => <$fh>);
- }
-
- for my $dir (glob "$config{master_dir}/*") {
- my $zone = basename($dir);
- my $info = -e ("$dir/.keycounter") ? "sec-on" : "sec-off";
- push @iz, join "::", "\t\tIN TXT\t\t\"ZONE", $zone, $info;
- }
-
- {
- my $fh = File::Temp->new(DIR => "$config{master_dir}/$indexzone")
- or die "Can't create tmpdir: $!\n";
- print $fh join "\n" => @iz, "";
- rename($fh->filename => "$config{master_dir}/$indexzone/$indexzone")
- or die "Can't rename "
- . $fh->filename
- . " to $config{master_dir}/$indexzone/$indexzone: $!\n";
- }
-
- say "** index-zone aktualisiert";
- return $indexzone;
-}
-
-sub file_entry {
-
- # prueft jede domain, die ein verzeichnis in $config{master_dir} hat, ob sie
- # dnssec nutzt.
- # passt die eintraege in $config_file falls noetig an.
- our $conf_dir;
-
- while (glob "$config{master_dir}/*") {
- s#($config{master_dir}/)(.*)#$2#;
- my $zone = $_;
- my $zone_file = "$config{master_dir}/$zone/$zone";
- my $conf_file = "$conf_dir/$zone";
- my @c_content;
-
- unless (-f "$conf_file") {
- die "$conf_file: $! \n";
- }
-
- if (-e "$config{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" }
-}
-
-sub need_rollover() {
-
- # gibt alle zonen mit abgelaufenen keycounter
- my @r;
-
- while (my $kc = glob "$config{master_dir}/*/.keycounter") {
- my $zone = basename dirname $kc;
- my $key;
-
- {
- open(my $fh, $kc) or die "$kc: $!\n";
- chomp($key = <$fh>);
- }
-
- push @r, $zone if $config{key_counter_end} <= $key;
- }
-
- return @r;
-}
-
-sub done_rollover() {
-
- # funktion ueberprueft ob ein keyrollover fertig ist
- # die bedingung dafuer ist das:
- # - eine datei .index.zsk vorhanden ist
- # - die datei .index.zsk älter ist, als die rollover-Zeit
- # - die datei .index.zsk ueber mehr als eine zeile gross ist
- # (also mehr als einen Schlüssel enthält)
- my @r;
- my $now = time;
-
- while (my $dir = glob "$config{master_dir}/*") {
- my $zone = basename $dir;
-
- my @index = ();
- my $index_wc;
-
- # prueft nach der ".index.zsk"-datei und erstellt den zeitpunkt
- # an dem das key-rollover endet.
- # rollover is done when mtime of the .index.zsk + abl_zeit is
- # in the past
- next if not -e "$dir/.index.zsk";
- next if (stat _)[9] + 3600 * $config{abl_zeit} >= $now;
-
- # prueft die anzahl der schluessel in der .index.zsk
- open(my $fh, "$dir/.index.zsk") or die "$dir/.index.zsk: $!\n";
- (<$fh>);
- push @r, $zone if $. > 1;
- }
-
- return @r;
-}
-
-sub begin_rollover(@) {
- my @zones = @_;
- my @r;
-
- # anfang des key-rollovers
-
- foreach my $zone (@zones) {
-
- # erzeugt zsks
- my $dir = "$config{master_dir}/$zone";
- my ($keyname, @keys);
-
- # create a new key
- { # need to change the direcoty, thus some more effort
- # alternativly: $keyname = `cd $dir && dnssec-keygen ...`;
- # would do, but is more fragile on shell meta characters
-
- open(my $keygen, "-|") or do {
- chdir $dir or die "Can't chdir to $dir: $!\n";
- exec "dnssec-keygen",
- -a => "RSASHA1",
- -b => 512,
- -n => "ZONE",
- $zone;
- die "Can't exec: $!";
- };
- chomp($keyname = <$keygen>);
- close($keygen) or die "dnssec-keygen failed: $@";
- }
-
- open(my $fh, "+>>$dir/.index.zsk") or die "$dir/.index.zsk: $!\n";
- seek($fh, 0, 0);
- chomp(@keys = <$fh>);
-
- ### @keys
-
- push @keys, $keyname;
- shift @keys if @keys > 2;
-
- truncate($fh, 0) or die "truncate";
- print $fh join "\n" => @keys;
-
- print " * $zone: neuer ZSK $keyname erstellt\n";
-
- open($fh, ">$dir/.keycounter") or die "$dir/.keycounter: $!\n";
- say $fh 0;
- close($fh);
-
- unlink_unused_keys($zone);
- include_keys($zone);
- push @r, $zone;
- }
-
- return @r;
-}
-
-sub include_keys($) {
-
- # die funktion fugt alle schluessel in eine zonedatei
- my $zone = shift;
- my $dir = "$config{master_dir}/$zone";
-
- my $in = IO::File->new("$dir/$zone") or die "Can't open $dir/$zone: $!\n";
- my $out = File::Temp->new(DIR => $dir) or die "Can't open tmpfile: $!\n";
-
- print $out grep { !/\$include\s+.*key/i } $in;
- print $out map { "\$INCLUDE @{[basename $_]}\n" } glob "$dir/K*key";
-
- close $in;
- close $out;
- rename($out->filename => "$dir/$zone")
- or die "Can't rename tmp to $dir/$zone: $!\n";
-
-}
-
-sub unlink_unused_keys($) {
-
- # die funktion loescht alle schluessel die nicht in der index.zsk
- # der uebergebenen zone stehen
- my $zone = shift;
-
- my @keys;
- my $dir = "$config{master_dir}/$zone";
-
- {
-
- # collect the keys and cut everything except the key id
- # we cut the basenames (w/o the .private|.key suffix)
- open(my $zsk, "<$dir/.index.zsk") or die "$dir/.index.zsk: $!\n";
- open(my $ksk, "<$dir/.index.ksk") or die "$dir/.index.ksk: $!\n";
- @keys = (<$zsk>, <$ksk>);
- }
-
- # prueft alle schluesseldateien (ksk, zsk) ob sie in der jeweiligen
- # indexdatei beschrieben sind. wenn nicht werden sie geloescht.
- for my $file (glob "$dir/K*.key $dir/K*.private") {
- unlink $file if basename($file, ".key", ".private") ~~ @keys;
- }
-}
-
-sub end_rollover(@) {
-
- my @zones = @_;
- my @r;
-
- foreach my $zone (@zones) {
-
- my $dir = "$config{master_dir}/$zone";
-
- open(my $fh, "+>>$dir/.index.zsk")
- or die "Can't open $dir/.index.zsk: $!\n";
- seek($fh, 0, 0);
- chomp(my @keys = <$fh>);
-
- if (@keys > 1) {
- truncate($fh, 0);
- say $fh $keys[-1];
- }
- close($fh);
-
- unlink_unused_keys($zone);
- include_keys($zone);
- push @r => $zone;
- }
-
- return @r;
-}
-
-__END__
-
-=head1 NAME
-
- update-serial - updates the serial numbers and re-signs the zone files
-
-=head1 SYNOPSIS
-
- update-serial [options] [zone...]
-
-=head1 DESCRIPTION
-
-B<update-serial> scans the configured directories for modified zone files. On any
-file found it increments the serial number and signs the zone, if approbiate.
-
-=head1 OPTIONS
-
-=over
-
-=item B<--sign-alert-time> I<days>
-
-=item B<--key-counter-end> I<integer>
-
-Maximum number if key usages.
-
-
-=back
-
-The common options B<-h>|B<--help>|B<-m>|B<--man> are supported.
-
-=head1 AUTHOR
-
-L<andre.suess@pipkin.cc>
-
-=cut
-
-# vim:sts=4 sw=4 aw ai sm:
--- a/zone-ls.pl Tue Jan 11 23:37:09 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-#! /usr/bin/perl
-
-use v5.10;
-use strict;
-use warnings;
-use Pod::Usage;
-use File::Basename;
-use FindBin;
-use Time::Local;
-use Getopt::Long;
-use if $ENV{DEBUG} => "Smart::Comments";
-use DNStools::Config qw(get_config);
-
-my %config;
-my $opt_expiry = undef;
-
-MAIN: {
- my %info; # will hold the information we collected
-
- GetOptions(
- "e|expiry" => \$opt_expiry,
- "h|help" => sub { pod2usage(-exit => 0, -verbose => 1) },
- "m|man" => sub {
- pod2usage(
- -exit => 0,
- -verbose => 2,
- -noperldoc => system("perldoc -V &>/dev/null")
- );
- },
- ) or pod2usage;
-
- %config = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
- die "$config{master_dir}: $!\n" if not -d $config{master_dir};
-
- foreach my $dir (grep { -d } glob "$config{master_dir}/*") {
-
- my $zone = basename($dir);
- $info{$zone} = { status => "OK" };
-
- if (not -f "$dir/.index.zsk") {
- $info{$zone}{zsk} = 0;
- $info{$zone}{ksk} = 0;
- $info{$zone}{kc} = 0;
- $info{$zone}{end} = "-";
- $info{$zone}{expiry} = undef;
- next;
- }
-
- # prueft wie viele zsks genutzt werden
- {
- open(my ($fh), $_ = "<$dir/.index.zsk")
- or die "Can't open $_: $!\n";
- () = <$fh>;
- $info{$zone}{zsk} = $.
- }
-
- # prueft wie viele ksks genutzt werden
- {
- open(my ($fh), $_ = "<$dir/.index.ksk")
- or die "Can't open $_: $!\n";
- () = <$fh>;
- $info{$zone}{ksk} = $.
- }
-
- # prueft wie oft die schluessel zum signieren genutzt wurden
- {
- open(my ($fh), $_ = "<$dir/.keycounter")
- or die "Can't open $_: $!\n";
- chomp($info{$zone}{kc} = <$fh>);
- }
-
- # prueft das ablaufdatum
- if (!-f "$dir/$zone.signed") {
- $info{$zone}{end} = "-";
- next;
- }
-
- open(my ($fh), $_ = "<$dir/$zone.signed") or die "Can't open $_: $!\n";
- while (<$fh>) {
- next if not /RSIG\s+SOA\s.*\s
- (?<year>\d\d\d\d)
- (?<mon>\d\d)
- (?<day>\d\d)
- (?<hour>\d\d)
- (?<min>\d\d)\d+\s\(/ix;
- $info{$zone}{end} = "$+{day}.$+{mon}.$+{year} $+{hour}:$+{min}";
- $info{$zone}{expiry} =
- timelocal(0, $+{min}, $+{hour}, $+{day}, $+{mon} - 1, $+{year});
- }
- }
-
- { # output
-
- my $sort_by =
- $opt_expiry
- ? sub { ($info{$a}{expiry} // 2**64) <=> ($info{$b}{expiry} // 2**64) }
- : sub { $a cmp $b };
-
- my $format_h = "%-35s %-8s %1s/%1s %3s %7s\n";
- my $format_l = "%-35s %-8s %1d/%1d %5d %19s\n";
-
- printf $format_h => qw(Domain Status ZSK KSK Used Sig-end);
-
- foreach my $zone (sort $sort_by keys %info) {
- printf $format_l => $zone,
- @{ $info{$zone} }{qw(status zsk ksk kc end)};
- }
- }
-}
-
-__END__
-
-=head1 NAME
-
- zone-ls -- lists all zones
-
-=head1 SYNOPSIS
-
- zone-ls [-e|--expiry]
-
-=head1 DESCRIPTION
-
-This B<zone-ls> lists all zones under control of our dnstools suite. The output is ordered by domain name.
-
-=head1 OPTIONS
-
-=over
-
-=item B<-e>|B<--expiry>
-
-Order the output by expiry date. The sooner the key expires, the more top the
-domain is listed.
-
-=back
-
-Additionally the common B<-h>|B<--help>|B<-m>|B<--man> options, which should be
-self explanatory.
-
-=head1 AUTHORS
-
-L<andre.suess@pipkin.cc>
-
-=cut
-
-# vim:ts=4 sw=4 ai si aw:
--- a/zone-mk.pl Tue Jan 11 23:37:09 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use FindBin;
-use DNStools::Config qw(get_config);
-
-my %config;
-
-if (@ARGV < 2) {
- print "usage: zone-mk kundennummer domain ... \n";
- exit 1;
-}
-
-# oeffnet Konfigurations- und Templatefiles - relativ oder absolut
-my @configs = ("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
-my @templc = (
- "$FindBin::Bin/templates/named.config",
- "/etc/dnstools/templates/named.config"
-);
-my @templz =
- ("$FindBin::Bin/templates/named.zone", "/etc/dnstools/templates/named.zone");
-
-for (grep { -f } @templc) {
- open(TEMPCONF, $_) or die "Can't open $_: $!\n";
-}
-unless (seek(TEMPCONF, 0, 0)) {
- die "Can't open template (searched: @templc)\n";
-}
-
-for (grep { -f } @templz) {
- open(TEMPZONE, $_) or die "Can't open $_: $!\n";
-}
-unless (seek(TEMPZONE, 0, 0)) {
- die "Can't open template (searched: @templz)\n";
-}
-
-
-%config = get_config(@configs);
-
-my $primary = $config{primary};
-my $secondary = $config{secondary};
-my $zone_conf_dir = $config{zone_conf_dir};
-my $master_dir = $config{master_dir};
-my $customer = shift @ARGV;
-chomp(my $primary_ip = `dig +short $primary`);
-chomp(my $secondary_ip = `dig +short $secondary`);
-chomp(my $this_host = `hostname -f`);
-chomp(my $this_ip = `hostname -i`);
-chomp(my $this_domain = `hostname -d`);
-chomp(my $time = `date +%Y%m%d00`);
-chomp(my $start = `date -I`);
-my $hostmaster = "hostmaster.$this_domain";
-
-unless (-d $master_dir and -r $master_dir) {
- die "$master_dir: $!\n";
-}
-
-unless (-d $zone_conf_dir and -r $zone_conf_dir) {
- die "$master_dir: $!\n";
-}
-
-# legt fuer jede domain in @ARGV ein verzeichnis in $master_dir an.
-# schreibt aus den angegebenen templates die dateien $zonefile und $config
-# in die entsprechenden verzeichnisse.
-for (@ARGV) {
-
- chomp(my $domain = `idn --quiet "$_"`);
- my $zonefile = "$master_dir/$domain/$domain";
- my $config = "$zone_conf_dir/$domain";
- my $utf8domain = "$_";
-
- unless (-d "$master_dir/$domain") {
- `mkdir $master_dir/$domain`;
- }
-
- if (-f $zonefile) {
- $zonefile =~ s#/.*/##;
- print "$zonefile exists. Skipping $domain\n";
- next;
- }
- if (-f $config) {
- $config =~ s#/.*/##;
- print "$config exists. Skipping $domain\n";
- next;
- }
-
- print "$domain ($_) for $customer \n";
-
- my @tempzone = <TEMPZONE>;
- for (@tempzone) {
- s#<start>#$start#;
- s#<domain>#$domain#;
- s#<time>#$time#;
- s#<primary>#$primary#;
- s#<secondary>#$secondary#;
- s#<hostmaster>#$hostmaster#;
- s#<customer>#$customer#;
- s#<utf8domain>#$utf8domain#;
- }
-
- open(ZONEOUT, ">$zonefile");
- print ZONEOUT @tempzone;
- close(ZONEOUT);
-
- my @tempconf = <TEMPCONF>;
- for (@tempconf) {
- s#<domain>#$domain#;
- s#<start>#$start#;
- s#<customer>#$customer#;
- s#<utf8domain>#$utf8domain#;
- s#<file>#$master_dir/$domain/$domain#;
- s#<primary_ip>#$primary_ip#;
- s#<secondary_ip>#$secondary_ip#;
- }
-
- open(CONFOUT, ">$config");
- print CONFOUT @tempconf;
- close(CONFOUT);
-}
--- a/zone-rm.pl Tue Jan 11 23:37:09 2011 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#!/usr/bin/perl
-
-use warnings;
-use strict;
-use File::Path;
-use FindBin;
-use DNStools::Config qw(get_config);
-
-# liest die Konfiguration ein
-my %config = get_config("$FindBin::Bin/dnstools.conf", "/etc/dnstools.conf");
-
-my $master_dir = $config{"master_dir"};
-my $conf_dir = $config{"zone_conf_dir"};
-
-for (@ARGV) {
- chomp(my $zone = `idn --quiet "$_"`);
-
- if (-d "$master_dir/$zone") {
- rmtree "$master_dir/$zone/"
- and print "zone-dir for $zone removed\n";
- }
- else {
- print "$master_dir/$zone: $!\n";
- }
-
- if (-e "$conf_dir/$zone") {
- unlink "$conf_dir/$zone"
- and print "configuration-file for $zone removed\n";
- }
- else {
- print "$conf_dir/$zone: $!\n";
- }
-}