#!/usr/bin/perl -X use strict; use IO::Socket; use Getopt::Long; our ($auto, $ASnum, $abuse, $query, $whoisd, $rport, $recurs, $subnet, $email, $teche, $netname, $cidr, $help, $quiet, $instuff) = undef; $whoisd = 'whois.arin.net'; $rport = 43; GetOptions( "asnumber" => \$ASnum, "recursive" => \$recurs, "teche" => \$teche, "abuse" => \$abuse, "netname" => \$netname, "cidr" => \$cidr, "subnet" => \$subnet, "whoisd:s" => \$whoisd, "help" => \$help, "quiet" => \$quiet, "port:i" => \$rport); $auto = 1 if (defined ($query = $ARGV[0])); clhelp() if (defined $help); if (defined $quiet) { quiet() if (defined $auto); } unless (defined $auto) { print STDERR "Enter your query, !help, or !quit to exit.\n$whoisd\> "; INSTUFF: while (chomp ($instuff = )){ if ( $instuff !~ /^!|^$/ ){ #is this a param command or a useless CR? $query = $instuff; dowho($query); } elsif ( $instuff =~ /^!(help)$/i){ inthelp(); } elsif ( $instuff =~ /^!(q|quit|exit)$/i){ print STDERR "Adios.\n"; exit; } elsif ( $instuff =~ /^!set [[:alpha:]]{1,10}\s?=\s?.*/ ){ $instuff = $1; my @newparm = split /[\s =]/, $instuff; my $foo = "\$$newparm[1] = qw/$newparm[2]/"; eval "$foo"; print STDERR "$whoisd\> "; } elsif ( $instuff =~ /^!unset [[:alpha:]]{1,10}$/ ){ $instuff = $1; my @newparm = split /[\s =]/, $instuff; my $foo = "undef \$$newparm[1]"; eval "$foo"; print STDERR "$whoisd\> "; } else { print STDERR "I don't know what to do with $instuff\n"; print STDERR "$whoisd\> "; } } } else { dowho($query); } sub dowho{ chomp(my $request = $_[0]); my $sock = IO::Socket::INET -> new(PeerAddr => "$whoisd", PeerPort => "$rport", Proto => "tcp") or die "Funny, I can't reach $whoisd.\n"; my ($send, $recv); die "\n" unless (defined ($send = fork())); if ($send) { print $sock $request . "\x0a" ; print STDERR "looking up $request at $whoisd\n"; my (@outlist,@reply); while ($recv = <$sock>) { push @reply, $recv; } close $sock; kill ('TERM', $send); if ($recurs){ my (@demons, $repline); foreach $repline (@reply) { if ($repline =~ s/^[^%#].*(whois\.[a-z]{2,20}\.[a-z]{2,}[a-z.]*).*$/$1/i) { chomp $repline; push @demons, $repline unless ($repline =~ m/$whoisd/i); } } if (@demons){ if ($demons[0] =~ /^([.\w-\d]+)$/){ print STDERR "$whoisd refers to $demons[0] and you have" , " requested recursion.\n"; local $whoisd = "$1"; dowho($query); return; } else { print STDERR "$whoisd refers to illegal host $demons[0]." , " Requested recursion failed.\n"; return; } } } if ($subnet){ my (@nets, $repline); foreach $repline (@reply) { if ($repline =~ s/^[^\(]*\((NET[[:alnum:]-]+)\).*$/$1/) { push @nets, $repline; } } if ($nets[1]) { my $subnet = pop @nets; splice (@nets, 0); print STDERR "Query string \"$request\" returns multiple", , " subnets and you have the \"--subnet\" option turned" , " on.\n -- To view all results, type \"!unset subnet" , "\" and reenter your query.\n"; dowho($subnet); return; } else { @outlist = outformat(@reply); print "@outlist\n"; print STDERR "$whoisd\> " unless (defined $auto); close $sock; kill ('TERM', $send); return; } } else { @outlist = outformat(@reply); print "@outlist\n"; print STDERR "$whoisd\> " unless (defined $auto); close $sock; kill ('TERM', $send); return; } } close $sock; } sub outformat { # Break out only those elements specified by cmdline switches. If none spec'd, # return entire whois reply. my (%data, $key, $val, $line) = (); foreach $line (@_) { ($key, $val) = split /:\s+/, $line; chomp ($key, $val); $data{$key} = $val; } my @outdata; push @outdata, $data{TechEmail} if ($teche && $data{TechEmail}); push @outdata, $data{ASNumber} if ($ASnum && $data{ASNumber}); push @outdata, $data{OrgAbuseEmail} if ($abuse && $data{OrgAbuseEmail}); push @outdata, $data{NetName} if (defined $netname && $data{NetName}); push @outdata, $data{netname} if (defined $netname && $data{netname}); push @outdata, $data{CIDR} if ($cidr && $data{CIDR}); @outdata = @_ unless $outdata[0]; return @outdata; } sub quiet { open(NEWOUT, ">/dev/null") || die; *STDERR = *NEWOUT; } sub clhelp { print "Usage: $0 [OPTION]... [query]\n" ."\nA flexible whois client designed with address records in mind," ." that will return complete records or specific fields from whois" ." servers. An interactive mode is available if no query is entered" ." on the commandline. At the prompt, enter !quit to exit, !help for" ." interactive mode help.\n"; print "\n -h,\t--help \tthis ramble\n" ." -w,\t--whoisd\twhois server - default: whois.arin.net)\n" ." -p,\t--port \tserver tcp port - default: 43\n" ." -s,\t--subnet\tIf multiple networks are returned, fetch detail on last reported (most specific?)\n" ." -r,\t--recursive\tIf another whois server is referenced in the output, try the query there\n" ." -t,\t--techemail\tEmail contact, technical (if available)\n" ." --ab,\t--abuse \tEmail contact, abuse (if available)\n" ." -n,\t--netname \tNetwork name (if available)\n" ." -c,\t--cidr \tCIDR block (if available)\n" ." --asn,\t--asnumber\tAutonomous system number (if available)\n" ." -q,\t--quiet \tMinimize client chatter (batch mode only). By default, activity details go to stdout.\n"; exit; } sub inthelp { print "Enter your query at the > prompt and press \"enter\".\n" ."\nCommands must be prefixed with a !, such as !quit\n" ."To set any switch, use \"!set =1\":\n" ."To unset any switch, use \"!unset \":\n" ."available switches are: \n\tASnum, recurs, teche, abuse, netname, cidr, subnet\n" ."To change server or port, use \"!set whoisd=\" or \"!set rport=\"\n" ." \nMost whois servers provide a help facility:\n" ."\tserver\t\thelp query\n" ."\t------\t\t----------\n" ."\twhois.nic.mil\thelp\n" ."\twhois.arin.net\t?\n" ."\twhois.ripe.net\thelp\n" ."\twhois.apnic.net\thelp\n"; }