#!/usr/bin/perl
use Socket;
use DBI;
use CGI qw(:standard);
use tracker;
use tracker_cgi;

$| = 1;
print $tracker::tracker_header;

$_ = param("query_string");

if ( /^\s*([-:_.\w]*)/ )
	{
	$_ = $1;
	}
else
	{ tracker::cgi_die("Invalid query") }
	
my ($dbconn, $query);
$dbconn = tracker::conndb() or tracker::cgi_die("Database error");

if (/^([\dABCDEFabcdef]{2}[-:]){5}[\dABCDEFabcdef]{2}$/)		# XX-XX-XX-XX-XX-XX or XX:XX:XX:XX:XX:XX mac addr
	{
	s/:/-/g;
	$query = "mac_addr = " . $dbconn->quote($_)
	}
	
elsif (/^([\dABCDEFabcdef]{4}\.){2}[\dabcdefABCDEF]{4}$/)	#XXXX.XXXX.XXXX
	{
	$_ = tracker::reformat_rtr_mac($_);
	$query = "mac_addr = " . $dbconn->quote($_)
	}
	
elsif (	/^	#beginning of the line
	([12]?	#(zero or one digits that are either 1 or 2
	\d{1,2}	#followed by one or two digits
	\.)	#then a dot )
	{3}	#three of those
	[12]?\d{1,2} # and one more with no dot after it
	$	#and no more
	/x )
	{
	$query = "ip_addr = " . $dbconn->quote($_)
	}
elsif (	/^
	\.?	#might start with a dot
	([12]?\d{1,2}\.)	#octet in decimal representation, like above
	{1,2}	#one, or two.. if there were three it would be an exact ip address
	[12]?\d{1,2}\.?	#one octet at the end and maybe a dot.
	$	# and no more
	/x )
	{
	$query = "ip_addr like " . $dbconn->quote('%' . $_ . '%')
	}
	
elsif (	/^
	([\dabcdefABCDEF]	#character class for hex digits
	{2}[-:])	#two hex digits and then a dash or colon
	{1,4}	#1-4 of those, if we had 5 we had an exact mac address
	[\dabcdefABCDEF]{2}	#and a trailing pair of hex digits
	$	#and no more
	/x )
	{
	s/:/-/g;
	$query = "mac_addr like " . $dbconn->quote('%' . $_ . '%')
	}
		
elsif (/^[\w-_\.]*$/ && /\./)
	#if the query string is all alphanumeric, and it has a dot in it, assumme it is an
	#FQDN.  Append a dot on the end, then look it up in DNS	
	{
	my $addr,@ascii_addrs;
	my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($_ . ".");
	foreach $addr (@addrs) 
		{
		$addr = inet_ntoa($addr);
		$hostcache{$addr} = $name;
		push(@ascii_addrs, $dbconn->quote($addr))
		}
	if (@ascii_addrs == 0) 
		{
		print tracker::html_errors(["host not found"]), end_html();
		$dbconn->disconnect;
		exit
		}
	$query = "ip_addr = " . join( " or ip_addr = ", @ascii_addrs )
	}
	
elsif (/^[a-z][\w-_]*/i )
	{
	my $addr,@ascii_addrs;
	foreach $domain (@tracker::domains)
		{
		my $fqdn = $_ . "." . $domain . ".";
		my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($fqdn);
		foreach $addr (@addrs) 
			{
			$addr = inet_ntoa($addr);
			$hostcache{$addr} = $name;
			push(@ascii_addrs, $dbconn->quote($addr))
			}
		}
	if (@ascii_addrs == 0)
		{
		print tracker::html_errors(["host not found"]), end_html();
		$dbconn->disconnect;
		exit
		}
	$query = "ip_addr = " . join( " or ip_addr = ", @ascii_addrs )
	}

else
	{
	print tracker::html_errors(["Unable to parse query.<p>Looking for a hostname, ip or mac address."]), end_html();
	$dbconn->disconnect;
	exit
	}
	
my $sth = $dbconn->prepare("SELECT COUNT(*) FROM nodes WHERE " . $query . ";");
$sth->execute or cgi_die("Database error:" . $dbconn->errstr);
( $rows ) = $sth->fetchrow_array();

$sth = $dbconn->prepare('SELECT mac_addr, switch, vlan, module, port, ' .
	'ip_addr, ' . tracker::timestamp("last_updated") .
	'FROM nodes WHERE ' . $query . ';');
$sth->execute or cgi_die("Database error:" . $dbconn->errstr);

tracker::start_node_table();

while (@row = $sth->fetchrow_array) 
	{
	my $hostname;
	#if we've got less than 20 rows, we may as well reverse resolve them.
	if ( $rows <= 20 )
		{ $hostname = gethostbyaddr(inet_aton(@row[5]), AF_INET) }
	tracker::node_row($hostname,@row)
	}

$sth->finish;
$dbconn->disconnect;
tracker::end_table();
print $tracker::tracker_footer;

