#!/usr/bin/perl

use strict;
use warnings;
use Martnet::DDNS;
use File::Temp qw/tempfile/;
use Getopt::Std;

# Use '-f' flag to force replacing all of the zone files (used when
# changing IPs)
my %opts;
getopts('f', \%opts);

my $ddns = Martnet::DDNS->new();
my $force_replace = $opts{f} ? 1 : 0;

my @vh = $ddns->get('_vhosts');

# For each virtual host, generate a vhost zone file if there isn't one
my $changecount = 0;
foreach my $i (@vh) {
    my $zf = "/var/lib/bind/vhost/db.$i->{zone}";
    if ( $force_replace || (! -f $zf) ) {
	print "Generating new zone file for $i->{zone}\n";
	open(my $fh, ">", $zf)
	    || die "Can't create output file $zf: $!";
	create_zonefile($fh, $i);
	$changecount++;
    }
}

# For each vhost in /var/lib/bind/vhost, make sure it has an entry in the zone file.
foreach my $i (</var/lib/bind/vhost/*>) {
    my ($zone) = ($i =~ /\/db.(.+)$/);
    next unless ($zone);
    unless (contains_zone($zone, @vh)) {
	print "Unlinking old zone file for $zone\n";
	unlink($i);
	$changecount++;
    }
}

if ($changecount) {
    # If we made any changes, then generate the full vhost list
    my ($fh, $path) = tempfile();
    foreach my $i (sort {$a->{zone} cmp $b->{zone}} @vh) {
	if ($ddns->is_dnssec($i->{zone})) {
	    print $fh "zone \"$i->{zone}\" { type master; file \"/var/lib/bind/vhost/db.$i->{zone}.signed\"; };\n";
	} else {
	    print $fh "zone \"$i->{zone}\" { type master; file \"/var/lib/bind/vhost/db.$i->{zone}\"; };\n";
	}
    }
    close $fh;
    print "Installing new vhost list\n";
    system("install -o bind -g bind $path /var/lib/bind/unified.zones.9");
    print "Reloading DNS files\n";
    system("/usr/sbin/rndc reload");
}

exit 0;

sub contains_zone {
    my ($zone, @zl) = @_;

    foreach my $i (@zl) {
	return 1
	    if ($i->{zone} eq $zone);
    }
    return 0;
}

sub create_zonefile {
    my ($fh, $i) = @_;

    my $zone = $i->{zone} . ".";
    my @now = localtime();
    my $serial = sprintf("%.4d%.2d%.2d01", $now[5]+1900, $now[4]+1, $now[3]);

    print $fh <<EOF
;
; This is an automatically-generated file. Do not edit by hand; it will be overwritten.
; Use instead:
;     # add-vhost <hostname>.
;     # del-vhost <hostname>.
;     # list-vhosts
;  
\$TTL	43200
$zone	IN	SOA	mister-dns.martnet.com. root.martnet.com. (
        $serial  ; Serial
	43200       ; Refresh every 12 hours
	3600        ; Retry every hour
	604800      ; Expire after a week
	43200 )     ; Negative Cache TTL 12 hours

; define name servers
$zone	IN	NS	ns1.martnet.com.
$zone	IN	NS	ns2.martnet.com.

; define localhost
localhost	IN	A	127.0.0.1

; define machine names
$zone	IN	A	190.92.153.173
$zone	IN      MX	5	$zone
$zone	IN      MX	10	mx2.martnet.com.
$zone	IN      MX	15	mx3.martnet.com.

*.$zone	IN	A	190.92.153.173
*.$zone	IN      MX	5	$zone
*.$zone	IN      MX	10	mx2.martnet.com.
*.$zone	IN      MX	15	mx3.martnet.com.
EOF
;
}
