#!FOOPERL

#
# Copyright (c) Xerox Corporation 1997, 1998. All rights reserved.
#
# License is granted to copy, to use, and to make and to use derivative
# works, provided that Xerox is acknowledged in all documentation
# pertaining to any such copy or derivative work. Xerox grants no other
# licenses expressed or implied. The Xerox trade name should not be used
# in any advertising without its written permission.
#
# XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE
# MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
# FOR ANY PARTICULAR PURPOSE.  The software is provided "as is" without
# express or implied warranty of any kind.
#
# These notices must be retained in any copies of any part of this software.
#



#----- default directory names and executable paths ----------
# users can override these values using the command line options listed
# the output directory for this program, command line opt -h
$hmakerdir =  "FOOHMKRDIR";
# no modifications should occur below this point


#-----------------------------------------------
# command line options
# option: -h directory
#   action: write pid file and error log to directory
#   default: write pid file and error log to $hmakerdir defined above
# option: -i inputfile
#   action: read address requests from inputfile
#   default: read a request address from the command line
# option: -o outputfile
#   action: write output address/as combinations to outputfile
#   default: write output address/as combinations to standard output
# option: -d 
#   action: delay a random period, between 0 and 10 min, at start
#   default: do not delay for any time at start


#------ perl standard modules and libraries -----------
use Getopt::Std;
use Socket;


#----- main program --------------------
&initialize;
&lookup;
&output;
&log_error(end);
exit;

#------------ initialization operations -----------------------
sub initialize {
    # check the command line args are correct
    if (!getopts('h:i:o:d')  || (@ARGV > 1)) {
        print 
   "usage: as_lookup [-i infile] [-o outfile] [-h outputdir] [-d] [ipaddress]\n";
       exit(-1);
    }    if (defined($opt_h)) {
        $hmakerdir = $opt_h;
    }
    $errorfile = "$hmakerdir/as_lookup.err";
    $pidfile = "$hmakerdir/as_lookup.pid";
    &log_error(start);
    # write my pid file
    open(PIDFILE, ">$pidfile") || &log_quit(pid);
    print PIDFILE "$$\n";
    close(PIDFILE);
    # to avoid having every htmlmaker query radb at once
    # we may delay up to 10 minutes before sending the request
    if ($opt_d) {
  	srand(time() ^ ($$ + ($$ << 15) ) ); 
	$delay = int(rand 600);
        &log_error(delay);
	sleep($delay);
    }
    # get the addresses to lookup
    $count = 0;
    if ($opt_i) {
	# read source list from input file
	open(INFILE,"$opt_i") || &log_quit(infile);
	while($line = <INFILE>) {
	    chop($line);
	    $address[$count] = $line;
	    $count++;
	}
	if ($count > 500) {
	    $count = 500;
	}
	close(INFILE);
    } else {
	# get the address from the command line
	if (@ARGV == 1) {
	    $count = 1;
	    $address[0] = $ARGV[0];
	}

    }
    if ($count == 0) {
	&log_quit(noaddress);
    }
    return(1);
}

#------------ lookup as numbers ------------------------------
sub lookup {
    # open a tcp socket
    $proto = getprotobyname('tcp');
    socket(WHOIS, PF_INET, SOCK_STREAM, $proto) || &log_quit(sockerr);
    # bind to the whois port at radb.ra.net
    $iaddr = inet_aton("radb.ra.net");
    $port = 43;
    $paddr = sockaddr_in($port,$iaddr);
    connect(WHOIS,$paddr) ||  &log_quit(conerr);
    # set to single line buffering
    select(WHOIS); $|=1; select(STDOUT);
    # tell the server we are sending multiple requests
    print WHOIS "!!\n";
    for($i=0; $i < $count; $i++) {
	print WHOIS "!r$address[$i],l\n";
	$asnum[$i] = -1;
	$mydate = 0;
	while ($line = <WHOIS> ) {
	    if ($line =~ /^\*[o][r]:/) {
		# this is the AS origin line
		($junk,$newas) = split("AS", $line);
		chop($newas);
	    }
	    if ($line =~ /^\*[c][h]:/) {
		# this is the date of the last AS origin
		($junk,$mail,$newdate) = split(" ",$line);
		if ($newdate > $mydate) {
		    $asnum[$i] = $newas;
		    $mydate = $newdate;
		}
	    }
	    if (($line eq "C\n") || ($line eq "D\n")) {
		# this is the end of the record for this source
		last;
	    }
	}
    }
    close(WHOIS);
    return(1);
}

#------------ produce output ----------------------------------
sub output {
    if (defined($opt_o)) {
	# open the output file
	open(OUTFILE,">$opt_o") || &log_quit(outfile);
    }
    for($i=0; $i < $count; $i++) {
	if (defined($opt_o)) {
	    # print each address and asnumber to the output file
	    print OUTFILE "$address[$i] $asnum[$i]\n";
	} else {
	    print "$address[$i] $asnum[$i]\n";
	}
	if ($asnum[$i] == -1) {
	    &log_error(notfound);
	}
    }
    if (defined($opt_o)) {
	# if we were writing to a file, close it
	close(OUTFILE);
    }
    return(1);
}

#-------------- error handling --------------------------------
sub log_error {
    # write any error messages into the errorfile
    local($errname) = $_[0];
    local($sc,$mn,$hr,$dy,$mo,$yr,$wd,$yd,$isd) = gmtime();
    $mo = $mo + 1;
    # okay, let's get ready for year 2000...
    if ($yr < 100) {
        $yr = "19$yr";
    } else {
    # this assumes gmtime really returns 108 for 2008 like it
    # should, but if different times implement different gmtime
    # the we have trouble
        $yr = $yr -100;
        $yr = "20$yr";
    }
    if ($hr < 10) { $hr = "0$hr"; }
    if ($mn < 10) { $mn = "0$mn"; }
    if ($sc < 10) { $sc = "0$sc"; }
    local($errdate) = "$mo/$dy/$yr $hr:$mn:$sc GMT";
    open(ERRORFILE, ">>$errorfile") ||
        die "AS Lookup unable to open error log $errorfile\n";
    if ($errname eq "start") {
	print ERRORFILE "$errdate START: as lookup started\n";
    } elsif ($errname eq "end") {
	print ERRORFILE "$errdate END: as lookup completed\n";
    } elsif ($errname eq "delay") {
	print ERRORFILE "$errdate DELAY: random delay of $delay seconds\n";
    } elsif ($errname eq "notfound") {
	print ERRORFILE "$errdate ERROR: unable to find AS for $address[$i]\n";
    } else {
        print ERRORFILE "$errdate ERROR: unidentified error code $errname:\n";
        print ERRORFILE "ERROR CODE IGNORED, RESUMING...\n";
    }
    close(ERRORFILE);
}

sub log_quit {
    # write any error messages into the errorfile and exit
    local($errname) = $_[0];
    local($sc,$mn,$hr,$dy,$mo,$yr,$wd,$yd,$isd) = gmtime();
    $mo = $mo + 1;
    # okay, let's get ready for year 2000...
    if ($yr < 100) {
        $yr = "19$yr";
    } else {
    # this assumes gmtime really returns 108 for 2008 like it
    # should, but if different times implement different gmtime
    # the we have trouble
        $yr = $yr -100;
        $yr = "20$yr";
    }
    if ($hr < 10) { $hr = "0$hr"; }
    if ($mn < 10) { $mn = "0$mn"; }
    if ($sc < 10) { $sc = "0$sc"; }
    local($errdate) = "$mo/$dy/$yr $hr:$mn:$sc GMT";
    open(ERRORFILE, ">>$errorfile") ||
        die "AS Lookup unable to open error log $errorfile\n";
    if ($errname eq "pid") {
        print ERRORFILE "$errdate ERROR: unable to write pid file $pidfile\n";
    } elsif ($errname eq "infile") {
        print ERRORFILE "$errdate ERROR: unable to open input file $opt_i\n";
    } elsif ($errname eq "outfile") {
        print ERRORFILE "$errdate ERROR: unable to open output file $opt_o\n";
    } elsif ($errname eq "noaddress") {
        print ERRORFILE "$errdate ERROR: no addresses given as input\n";
    } elsif ($errname eq "sockerr") {
        print ERRORFILE "$errdate ERROR: unable to open socket for whois\n";
    } elsif ($errname eq "conerr") {
        print ERRORFILE "$errdate ERROR: unable to connect whois socket\n";
    } else {
        print ERRORFILE "$errdate ERROR: unidentified error code $errname:\n";
    }
    print ERRORFILE "FATAL ERROR, EXITING.\n";
    close(ERRORFILE);
    exit(-1);
}



