#!/usr/bin/perl


#
# Scan a subnet for live hosts
#
# If given IP address or hostname, scan everything on that subnet.
# If given partial IP address (e.g. 140.174.97), do the same.
#
# Method used:
#
#  Use fping to scan the net; any hits send to gethostbyaddr to
# get the hostname.  This will print out a list of hostname and/or
# IP addresses that are alive, one per line.
#

require 'config/paths.pl';
require 'config/saint.cf';
require 'perl/socket.pl';	# work around socket.ph problems
$name = $ARGV[0];
if (! $name) { die "Usage: $0 network-address\n"; }
if ($ARGV[1] =~ "FW") {
  $firewall_flag=1;
}
#
# hostname?
if ($name !~ /[0-9]+\.[0-9]+\.[0-9]+/) {
	($name, $aliases, $type, $len, @ip) = gethostbyname($name);
	($a,$b,$c,$d) = unpack('C4',$ip[0]);
	$name = "$a.$b.$c";
	}

#
# IP addr?  If four octets, chop off the last one
if ($name =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {
	($name) = ($name =~ /^([0-9]+\.[0-9]+\.[0-9]+)\.[0-9]+/);
	}

# 3 octets of an ip address:
if ($name =~ /^[0-9]+\.[0-9]+\.[0-9]+$/) {
	for $i (1..255) { $args .= "$name.$i "; }
	}
# range of IP addresses:
elsif ($name =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
	# don't allow ranges beyond one class B network
	die "IP address range too large\n" if (($1 != $5) || ($2 != $6));
	# don't allow reversed ranges
	die "Null IP address range\n"
		if (($3 > $7) || (($3 == $7) && ($4 > $8)));
	for $i ($3..$7) {
		for $j ($4..$8) { $args .= "$1.$2.$i.$j "; }
		}
	}
# range of subnets:
elsif ($name =~ /^(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)$/) {
	# don't allow ranges beyond one class B network
	die "IP address range too large\n" if (($1 != $4) || ($2 != $5));
	# don't allow reversed ranges
	die "Null IP address range\n" if ($3 > $6);
	for $i ($3..$6) {
		for $j (1..255) { $args .= "$1.$2.$i.$j "; }
		}
	}
else { die "Can't figure out what to scan ($name)\n"; }


# spawn off fping, look at results
if ($firewall_flag || $dont_use_ping) {
	($ports = $std_ports) =~ s/,/ /g;
	if ($ports =~ /(\d+)\s*-\s*(\d+)/) {
		my(@str) = $1..$2;
		my($str) = join ' ',@str;
		$ports =~ s/$&/$str/;
	}
	die "Can't execute $FWPING" unless open(FPING, "$FWPING -p \"$ports\" $args |");
}
 else {
	die "Can't execute $FPING" unless open(FPING, "$FPING $args |");
}

while (<FPING>) {
	chop;
	($target, $result) = /(\S+)\s+(.*)$/;
	if ($_ =~ /is unreachable/) { next; }
	if ($_ =~ /is alive/) {
		print "$target\n";
		# v3.4.5 (s.k.) The rest is now done in
		# perl/targets.pl:target_acquisition()
		# for checking that fqdn resolves back to
		# original IP address
		#($a,$b,$c,$d) = split(/\./, $target);
		#@ip = ($a,$b,$c,$d);
		## Hack alert!! Some libcs dump when ahost has many addresses.
		#if (fork() == 0) {
		#	($name) = gethostbyaddr(pack("C4", @ip), &_AF_INET);
		#	if ($name) { print "$name\n"; }
		#	else { print "$target\n"; }
		#	exit;
		#	}
		#else { wait; }
		}
	}

close(FPING);
exit;
