#!/usr/local/bin/perl5.00502
#	program:	hosts
#	release:	1.5.0
#	purpose:	Generate a listing of hosts within a domain.
#			The default just lists all domain record names, one per line.
#			The "-a" option restricts the output to only "A" resource-
#			records, and makes the first output field be the IP address,
#			with the second field being the domain name.
#			The "-r" option does a recursive domain traversal.
#	input:		Domain name on command line,
#			optional nameserver to direct queries to.
#	output:		List of hosts within the domain,
#			or the word "ERROR" (distinguishable from a real
#			record because it has no period on the end).
#	exit value:	0 if succeeds, 1 if fails (and "ERROR" output).
#	author:		Paul Balyoz
#
#
# Copyright (C) 1993-2000 Paul A. Balyoz <pab@domtools.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

#
# Temporary storage for a zone dump
#
@a = split(/\//,$0);
$TMP="/tmp/$a[$#a].$$";

#
# Usage and Mydie functions
#
sub usage {
	print STDERR "usage: $0 [-r] [\@nameserver] dom.ain.\n";
	print "ERROR\n";
	unlink $TMP;
	exit 1;
}

sub mydie {
	local($str) = @_;

	print STDERR "$str\n";
	print "ERROR\n";
	unlink $TMP;
	exit 1;
}

#
# Parse command-line arguments
#

require 'getopts.pl';
&Getopts('ra') || &usage(1);

# Set flags
$recursive = $addronly = 0;
$opt_r && $recursive++;
$opt_a && $addronly++;

# Only 2 possible things left: @nameserver (optional), and domain name (required).
if ($#ARGV < 0 || $#ARGV > 1) {
	&usage;
}
foreach (@ARGV) {
	if (/^@/) {
		$atnameserver = $_;
	}
	else {
		$dom = $_;
	}
}
&usage  if $dom eq "";

#
# Determine what zone the given domain lives in.
#

$zone=`/usr/local/domtools/bin/zone $atnameserver $dom`;
$? != 0 && &mydie ("hosts: could not tell what zone $dom is in.");
chop ($zone);

#
# Get a dump of that zone
#

system "/usr/local/domtools/bin/axfr $atnameserver $zone > $TMP";
$? != 0 && &mydie ("hosts: could not transfer zone $dom");

#
# Send a recursive, selected group of domains thru uniq and domsort.
# Even though "uniq" seems redundant considering the "-u" option to domsort,
# it serves a purpose: to remove many redundant entries before sorting,
# to speed things up.
#

open (DOMSORT, "| uniq | /usr/local/domtools/bin/domsort -u") || &mydie ("could not launch domsort with a pipe");

#
# If recursion is specified, handle things one way.
#

if ($recursive) {
	open (ZONEDATA, $TMP) || &mydie ("hosts: could not open temp file $TMP");
	while (<ZONEDATA>) {
		chop;
#print "input=<$_>\n";
		@fields = split;
		if ($fields[0] =~ /\.$dom$/i || $fields[0] =~ /^$dom$/i) {
			if ($fields[1] ne "NS" && $fields[1] ne "SOA") {
				if (! $addronly || $fields[1] eq "A") {
					print DOMSORT $fields[0]."\n";
#print "\tanswer=<$fields[0]>\n";
				}
			} else {	# NS or SOA record:
				if ($fields[0] =~ /\.$dom$/i) {
					($index = $fields[0]) =~ tr/A-Z/a-z/;
					$subzones{$index} = $fields[0];
#print "\tstash recursive <$fields[0]>\n";
				}
			}
		}
	}
	if (%subzones) {
		 foreach $i (sort keys(%subzones)) {
			system "/usr/local/bin/perl5.00502 $0 -r $subzones{$i}";
		}
	}
	close (ZONEDATA);

#
# Not recursive, so handle things a different way.
#

} else {
	open (ZONEDATA, $TMP) || &mydie ("hosts: could not open temp file $TMP");
	while (<ZONEDATA>) {
		chop;
#print "input=<$_>\n";
		@fields = split;
		if ($fields[0] =~ /^[^\.]+\.$dom$/i || $fields[0] =~ /^$dom$/i) {
			if ($fields[1] ne "NS" && $fields[1] ne "SOA") {
				if (! $addronly || $fields[1] eq "A") {
					print DOMSORT $fields[0]."\n";
				}
			}
		}
	}
	close (ZONEDATA);
}

#
# Clean up and exit.
#
close (DOMSORT);

unlink($TMP);
exit 0;
