#!/usr/bin/perl -W

# (P) & (C) 2006 by Peter Bieringer <pb at bieringer dot de>

# Perl demonstration program how getaddrinfo should resolve addresses for a name in a proper way

# 20060827/PB: initial
# 20060828/PB: implement SOA check for domain (in case of no search domain is used), replace "search" with "query"

# TODO:
# - configurable options


use Net::DNS;


my @search_domains;

# Get search domains
sub get_search_domains() {
	open (RESOLVCONF, "< /etc/resolv.conf") || die "Can't open /etc/resolv.conf";
	while (<RESOLVCONF>) {
		chomp ($_);
		my ($token, @values) = split / /, $_;
		if (defined $token && $token eq "search") {
			push @search_domains, @values;
		};
	};
	close (RESOLVCONF);
	print "Found following search domains:\n";
	for my $search_domain (@search_domains) {
		print " " . $search_domain . "\n";
	};
};


get_search_domains();

my $host = $ARGV[0];

if (! defined $host || $host eq "") {
	die "Missing host to resolv (arg1)";
};

my @resolv_result;
my $flag_have_result = 0;
my $flag_have_noerror = 0;
my $flag_have_ipv4 = 0;
my $flag_have_ipv6 = 0;
my $flag_have_soa = 0;

print "\nStart lookup(s)\n";

for my $search_domain ("", @search_domains) {
	my $lookup_host = $host . "." . $search_domain;

	print " Lookup: " . $lookup_host . "\n";

	my $res = Net::DNS::Resolver->new(dnsrch => 0, defnames => 0);

	# AAAA query
	my $query = $res->query($lookup_host, "AAAA");
	print " Query: " . $lookup_host . " AAAA\n";

	if ($query) {
		$flag_have_result = 1;
		foreach my $rr ($query->answer) {
			next unless($rr->type eq "AAAA");
			print "  Result: " . $rr->type . " " . $rr->address . "\n";
			push @resolv_result, $rr->type  . " " . $rr->address;
			$flag_have_ipv6 = 1;
		}
	} else {
		warn "  Query failed: ", $res->errorstring, "\n";
		if ($res->errorstring eq "NOERROR") {
			$flag_have_noerror = 1;
		};
	};

	# A query
	$query = $res->query($lookup_host, "A");
	print " Query: " . $lookup_host . " A\n";

	if ($query) {
		$flag_have_result = 1;
		foreach my $rr ($query->answer) {
			next unless($rr->type eq "A");
			print "  Result: " . $rr->type . " " . $rr->address . "\n";
			push @resolv_result, $rr->type  . " " . $rr->address;
			$flag_have_ipv4 = 1;
		}
	} else {
		warn "  Query failed: ", $res->errorstring, "\n";
		if ($res->errorstring eq "NOERROR") {
			$flag_have_noerror = 1;
		};
	};

	if ($flag_have_result || $flag_have_noerror) {
		goto ("LABEL_end");
	};

	if ($search_domain ne "") {
		# a search domain is used, try next one
		next;
	};

	# no search domain is currently used
	if (scalar(@search_domains) == 0) {
		# also none are given, so SOA check can be skipped at all
		goto ("LABEL_end");
	};

	# NXDOMAIN doesn't differ between "host not exists" and "domain not exists" 
	# check for SOA of used domain now
	my $domain = $lookup_host;
	while (1 == 1) {
		# strip 1st part
		$domain =~ /^[^.]+\.(.*)$/;
		$domain = $1;

		if (!defined $domain || $domain eq "") {
			last;
		};

		$query = $res->query($domain, "SOA");
		print " Query: " . $domain . " SOA\n";

		if ($query) {
			foreach my $rr ($query->answer) {
				next unless($rr->type eq "SOA");
				print "  Result: " . $rr->type . " " . $rr->string . "\n";
				push @resolv_result, $rr->type  . " " . $rr->string;
				$flag_have_soa = 1;
			}
		} else {
			warn "  Query failed: ", $res->errorstring, "\n";
			if ($res->errorstring eq "NOERROR") {
				$flag_have_noerror = 1;
			};
		};

		if ($flag_have_soa || $flag_have_noerror) {
			goto ("LABEL_end");
		};
	};
};

LABEL_end:

print "\nResult:\n";
print " Flags:\n";
print "  flag_have_result=" . $flag_have_result . "\n";
print "  flag_have_noerror=" . $flag_have_noerror . "\n";
print "  flag_have_ipv4=" . $flag_have_ipv4 . "\n";
print "  flag_have_ipv6=" . $flag_have_ipv6 . "\n";
print "  flag_have_soa=" . $flag_have_soa . "\n";
print " DNS resolver result:\n";
if ($flag_have_noerror) {
	print "  NOERROR\n";
} elsif ($flag_have_result) {
	print "  SUCCESS\n";
} elsif ($flag_have_soa) {
	print "  NXDOMAIN\n";
} elsif ($flag_have_soa == 0 && $flag_have_result == 0) {
	print "  NXDOMAIN\n";
};
print " DNS resolver result details:\n";
foreach my $result (@resolv_result) {
	print "  " . $result . "\n";
};


