package Fdns;

use strict;
use warnings;

use base 'Exporter';
our @EXPORT = qw(dns dns_soa dns_ns dns_axfr dns_zones path2dns dns_read);
our @EXPORT_OK = ();

# (C) Miek Gieben, 2008
# placed under the GPL 3

# perform a DNS lookup
sub dns($$$) {
    my ($res, $name, $type) = @_;
    my @data;
    my $q = $res->send($name, $type);
    if (! $q) {
	# no answer, timeout... or other problems
	return @data;
    }
    foreach ($q->answer) {
	print "dns: ", $_->string;
	if ($type eq "ANY") {
	    push @data, $_;
	    next;
	}
	if ($_->type eq $type) {
	    push @data, $_;
	}
    }
    @data;
}

sub dns_soa($$) {
    # res, name
    dns(shift, shift, "SOA");
}

sub dns_ns($$) {
    # res, name
    dns(shift, shift, "NS");
}

sub dns_axfr($$) {
    my ($res, $zone) = @_;
    my ($res_axfr, @zone);

    my @ns = dns_ns($res, $zone);
    # try all the nameserver inturn until we have a hit
    foreach (@ns) {
	$res_axfr = Net::DNS::Resolver->new(
		recurse => 0,
		nameservers => [$_->rdatastr],
		debug => 0);
	@zone = $res_axfr->axfr($zone);
	if (@zone) {
	    return @zone;
	}
    }
    @zone; # should be empty
}

sub dns_zones($$) {
    # get a zone name, retrieve all delegated names
    my ($res, $z) = @_;
    my %seen;
    my @dir = qw(. .. @);

    foreach (dns_axfr($res, $z)) {
	# kill everything after the first dot, this isn't completely how it should be
	# but works okay in most cases
	my $n = lc $_->name;
	my $zr = $z; $zr =~ s/\.$//;	# kill the dot
	next if ($n eq $zr);

	$n =~ s/\.?$zr$//;		# remove the domain from the name
					# we already have the domain in the path
	if (! exists $seen{$n}) {
	    push @dir, $n;
	}
	$seen{$n}++;
    }
    @dir;
}

sub dns_read($$$) {
    # $res, name and type
    my @data = dns(shift, shift, shift);
    my @res;
    foreach (@data) {
	push @res, $_->string;
    }
    @res;
}

sub path2dns($) {
    # make a DNS name out of pathname
    my $p = shift;
    if ($p eq "/") {
	(".");
    } else {
        reverse split /\//, $p;
    }
}
1;
