#!/usr/local/bin/perl

use strict;
use warnings;
use Sys::Hostname;
use DBI;

my $DEBUG = 0;

my $dbun = 'user'; # username to connect to sql database with
my $dbpw = 'pass';  # password to connect to sql database with
my $dsn = 'DBI:mysql:host=mysql.example.net;database=dns'; # dsn to access database

my $dbh = DBI->connect($dsn, $dbun, $dbpw, {RaiseError => 1});

my $dir = '/home/config/tinydns/secondary';

my %ips;
open(IFCONFIG, "/sbin/ifconfig -a |") || die "Cannot pipe ifconfig -a: $!\n";
while(<IFCONFIG>){
	if(/^\s*inet\s+(?:addr:)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+/){
		next if($1 =~ /^127\.0\.0\.1$/);
		$ips{$1} = 1;
	}
}
close IFCONFIG;

my $sql = 'SELECT domain,axfr_host,source_addr FROM secondaries';
my $x = 0;
foreach my $ip (keys %ips){
	if($x){
		$sql .= ' OR';
	}else{
		$sql .= ' WHERE';
		$x=1;
	}
	$sql .= ' source_addr = ' . $dbh->quote($ip);
}
die "no ip addrs found\n" unless($x);
$sql .= ' ORDER BY domain';
my $sth = $dbh->prepare($sql);
$sth->execute;
my $update;
my %domains;
while(my $row=$sth->fetchrow_arrayref){
	$domains{$row->[0]} = 1;
	my $cmd = '/usr/local/bin/tcpclient -H -R -l 0 ';
	if($row->[2]){
		$cmd .= "-i $row->[2] ";
	}
	$cmd .= "$row->[1] 53 /usr/local/bin/axfr-get $row->[0] $dir/$row->[0].new $dir/$row->[0].tmp";

	warn "cmd: $cmd\n" if($DEBUG);
	system($cmd);

	if(-f "${dir}/$row->[0].new"){
		if(-f "${dir}/$row->[0]"){
			my $code = system("/usr/bin/cmp ${dir}/$row->[0].new ${dir}/$row->[0] >/dev/null 2>&1");
			$code /= 256;

			if($code){
				$update = 1;
				warn "$dir/$row->[0].new <-> $dir/$row->[0] differ.\n" if($DEBUG);
				rename("$dir/$row->[0].new","$dir/$row->[0]") || die "could not rename $row->[0].new to $row->[0]: $!\n";
			}else{
				unlink("$dir/$row->[0].new") || die "couldnt unlink $dir/$row->[0].new: $!\n";
			}
		}else{
			$update = 1;
			warn "no original $dir/$row->[0] - renaming to create.\n" if($DEBUG);
			rename("$dir/$row->[0].new","$dir/$row->[0]") || die "could not rename $row->[0].new to $row->[0]: $!\n";
		}

		foreach my $table (qw/a mx txt cname domains srv ptr domains ns loc delegation/){
			my $sql = "DELETE FROM $table WHERE domain = " . $dbh->quote($row->[0]);
			my $sth = $dbh->prepare($sql);
			$sth->execute;
		}

		my $sql = 'DELETE FROM delegation WHERE domain LIKE ' . $dbh->quote("%.$row->[0]");
		my $sth = $dbh->prepare($sql);
		$sth->execute;
	}else{
		warn "could not open $dir/$row->[0].new: $!\n";
	}

}

# clean off [most] stale files.  
# if a secondary is listed for a source addr
# that is no longer using this code, the zone
# will sit there.
$sql = 'SELECT domain FROM secondaries';
$sth = $dbh->prepare($sql);
$sth->execute;
my %current;
while(my $row=$sth->fetchrow_arrayref){
	$current{$row->[0]} = 1;
}
opendir(DIR, $dir) || die "cannot opendir $dir: $!\n";
foreach my $file (grep {!/^\./} readdir DIR){
	unless($current{$file}){
		if(unlink("$dir/$file")){
			$update=1;
		}else{
			warn "could not unlink $dir/$file ($file not in sql): $!\n";
		}
	}
}
closedir DIR;

$dbh->disconnect;

if($update){
	warn "See update\n" if($DEBUG);
	my $hostname = hostname();

	open(SECONDARY, ">/home/config/tinydns/input/secondaries.out.$hostname.$$.tmp") || die "couldnt write to secondaries.out..$hostname.$$.tmp: $!\n";
	open(SORT, "/usr/bin/sort -u $dir/* |") || die "Cannot pipe sort: $!\n";
	while(<SORT>){
		print SECONDARY;
	}
	close SORT;
	close SECONDARY;

	rename("/home/config/tinydns/input/secondaries.out.$hostname.$$.tmp",'/home/config/tinydns/input/secondaries.out') ||
	  die "could not rename secondaries.out.$hostname.$$.tmp: $!\n";
}
