#!/usr/bin/perl -w

# tristan+dns@ethereal.net 7mar2003
# 
# goes through a list of domains to slave, verifies their legitimacy, outputs
# bind8/9 config
#
# whipped this up in about an hour, don't blame me for bugs :)

use strict;
use Net::DNS;

my $root = 'a.root-servers.net.';

my %domains = ();

#my %iam = (
#	'ns1.electricrain.com' => 1,
#	'ns2.electricrain.com' => 1,
#);

my %iam = (
	'ns1.ethereal.net' => 1,
	'ns.yikes.net' => 1,
	'spicy.datasoup.com' => 1,
);

sub main {

	my $searcher = Net::DNS::Resolver->new();

	my $resolver = Net::DNS::Resolver->new();
	   $resolver->recurse(0);
	   $resolver->udp_timeout(1);
	   $resolver->tcp_timeout(1);

	while (my $domain = <>) {
		chomp $domain;

		last if !$domain or $domain =~ /^\s*$/;

		if ($domain && $domain !~ /^#/) {
			warn "Working on domain: [$domain]\n";
			runquery($resolver, $root, $domain);
		}
	}

	foreach my $domain (sort keys %domains) {

		next if $domains{$domain}{'bad'};

		my $lame = 1;

		for my $ns (@{$domains{$domain}{'ns'}}) {

			next unless $lame;

			$resolver->nameservers($ns);

			my $query = $resolver->query($domain, 'SOA');

			if (!$query or !$query->answer()) {

				$domains{$domain}{'bad'} = "couldn't get SOA - lame delegation to $ns";
				next;
			}

			foreach my $rr ($query->answer()) {

				next unless $rr->type() eq 'SOA';
				my $mname = $rr->mname();

				if ($iam{$mname}) {
					$domains{$domain}{'bad'} = "SOA MNAME is me";
					last;
				}

				$resolver->nameserver($mname);
				my @zone = $resolver->axfr($domain);

				if (scalar @zone < 1) {
					$domains{$domain}{'bad'} = "$mname refused AXFR";
					next;
				}

				my $query = $searcher->search($mname);

				if (!$query or !$query->answer()) {
					# this shouldn't happen...
					$domains{$domain}{'bad'} = "can't look up $mname";
					next;
				}

				foreach my $rr ($query->answer()) {

					next unless $rr->type() eq 'A';
					my $addr = $rr->address();

					print qq!zone "$domain" {\n\ttype slave;\n\tmasters { $addr; };\n };\n!;

				}
			}

			$lame = 0;
		}
	}

	foreach my $domain (sort keys %domains) {

		next unless $domains{$domain}{'bad'};
		print "// $domain: $domains{$domain}{'bad'}\n";
	}
}

sub runquery {
	my ($resolver,$ns,$domain) = @_;

	$resolver->nameservers($ns);

	print "Sending NS query to $ns\n";

	my $packet = Net::DNS::Packet->new($domain, 'NS', 'IN');
	my $query = $resolver->send($packet);

	unless ($query) {
		print "query against $ns failed: ", $resolver->errorstring(), "\n";
		return 0;
	}

	if ($query->answer()) {

		print "Got answer..\n";

		my $good = 0;
		my @nameservers = ();

		foreach my $rr ($query->answer()) {

			next unless $rr->type() eq 'NS';

			my $name = lc $rr->nsdname();

			print "\tname: [$name]\n";

			if ($iam{$name}) {
				$good = 1;
			} else {
				push(@nameservers, $name);
			}
		}

		if ($good) {
			@{$domains{$domain}{'ns'}} = @nameservers;
		} else {
			$domains{$domain}{'bad'} = "exists, but I'm not a nameserver for it";
		}

		return 1;

	} elsif ($query->authority()) {

		print "Got authority..\n";

		my $results = 0;

		foreach my $rr ($query->authority()) {

			next unless $rr->type() eq 'NS';

			$results++;

			last if runquery($resolver, $rr->nsdname(), $domain);
		}

		$domains{$domain}{'bad'} = "domain doesn't exist" unless $results;
	}
}

main()

__END__
