moving to Build.PL hs12
authorHeiko Schlittermann <hs@schlittermann.de>
Thu, 13 Jan 2011 00:20:26 +0100
branchhs12
changeset 77 35905799cfd1
parent 76 7c48ae30987c
child 78 bb780a686eb6
moving to Build.PL
.hgignore
Build.PL
Makefile
bin/dnssec-keytool
bin/update-serial
bin/zone-ls
bin/zone-mk
bin/zone-rm
dnssec-keytool.pl
update-serial.pl
zone-ls.pl
zone-mk.pl
zone-rm.pl
--- 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";
-    }
-}