#!/usr/bin/perl # # abuseEmail v1.0 # Finds out abuse emails address for a specified IP address # http://logidac.com/abuseEmail/ # # Created by Guillaume Filion # Copyright (C) 2001 Logidac enr. # 16 Charles-Couillard # Beaumont, Québec # Canada, G0R 1C0 # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ##### # Options: # # Verbose level: # 0: silent, only output the result # 1: same as 0 but also output fatal errors (default) # 2: same as 1 but also output non-fatal errors # 5: noisy: explain every action $main::verbose=1; ################### use strict; use IO::Socket; my $ip = $ARGV[@ARGV-1] || die "Error: Please specify a host IP address.\n"; die "Error: This doesn't looks like a numeric IP address.\n" unless isIP($ip); $main::abuseEmail=""; $main::trustEmail=0; # Check for -v flag $main::verbose=5 if (($ARGV[0] eq "-v") or ($ARGV[0] eq "-V")); # Checking if it's a Private ip address print "Checking if $ip is a Private ip address..." if ($main::verbose>=5); if ( # RFC1918 between("192.168.0.0",$ip,"192.168.255.255") # RESERVED-2 || between("172.16.0.0",$ip,"172.31.255.255") # IANA-BBLK-RESERVED || between("10.0.0.0",$ip,"10.255.255.255") # RESERVED-6 ) { print "\nError: $ip is a private IP address (RFC1918). It's a local machine or a spoofed ip, either way, I can't give you any infos on this.\n" if ($main::verbose>=1); exit(1); } print "no\n" if ($main::verbose>=5); # Checking if it's a reserved ip address print "Checking if $ip is a reserved ip address..." if ($main::verbose>=5); if ( # IANA reserved between("0.0.0.0",$ip,"0.255.255.255") # RESERVED-1 || between("128.0.0.0",$ip,"128.0.255.255") # RESERVED-3 || between("191.255.0.0",$ip,"191.255.255.255") # RESERVED-4 || between("223.255.255.0",$ip,"223.255.255.255") # RESERVED-5 || between("67.0.0.0",$ip,"95.255.255.255") # RESERVED-7 || between("96.0.0.0",$ip,"126.255.255.255") # RESERVED-8 || between("1.0.0.0",$ip,"1.255.255.255") # RESERVED-9 || between("197.0.0.0",$ip,"197.255.255.255") # RESERVED-13 || between("201.0.0.0",$ip,"201.255.255.255") # RESERVED-14 || between("23.0.0.0",$ip,"23.255.255.255") # RESERVED-23 || between("31.0.0.0",$ip,"31.255.255.255") # RESERVED-31 || between("41.0.0.0",$ip,"41.255.255.255") # RESERVED-41A || between("127.0.0.0",$ip,"127.255.255.255") # LOOPBACK ) { print "\nError: $ip is a reserved IP address. It's very likely to be a spoofed ip, or your network admin/BOFH is on crack, either way, I can't give you any infos on this.\n" if ($main::verbose>=1); exit(1); } print "no\n" if ($main::verbose>=5); # Check IP's hostname print "Checking the hostname associated with $ip... " if ($main::verbose>=5); my $hostname = ip2host($ip); do {print (($hostname)?"$hostname":"none")} if ($main::verbose>=5); if ($hostname && (host2ip($hostname) ne $ip)) { # Hum, Paranoid reverse DNS didn't passed, I don't trust this hostname print " Hum, Paranoid reverse DNS didn't passed, I don't trust this hostname" if ($main::verbose>=5); $hostname=""; } print "\n" if ($main::verbose>=5); # Checking directly at abuse.net for this hostname if ($hostname) { print "\nChecking for this hostname at abuse.net..." if ($main::verbose>=5); whoisAbuseAddList($hostname,1); } print "\n" if ($main::verbose>=5); # Checking DNS zone's SOA print "Checking DNS zone's Start of Authority " if ($main::verbose>=5); my $soa; # SOA on the hostname if ($hostname && not($main::trustEmail)) { # We don't have enough confidence in the addresses we allready got, trying to find more... print "on the hostname...\n" if ($main::verbose>=5); my $nsname=$hostname; while ($nsname=popByte($nsname)) { $soa=DNSsoa($nsname); last if $soa; } if ($soa) { print "found: $soa\n" if ($main::verbose>=5); print "\nChecking for this SOA at abuse.net..." if ($main::verbose>=5); whoisAbuseAddList(popByte($soa),0); } else { print "not found.\n" if ($main::verbose>=5); } } # SOA on ip address # This will usually give use emails of upstream providers print "on the ip address..." if ($main::verbose>=5); $soa=""; my $nsname=inaddr($ip); while ($nsname=popByte($nsname)) { $soa=DNSsoa($nsname); last if $soa; } if ($soa) { print "found: $soa\n" if ($main::verbose>=5); print "\nChecking for this SOA at abuse.net..." if ($main::verbose>=5); whoisAbuseAddList(popByte($soa),0); } else { print "not found.\n" if ($main::verbose>=5); } #print "\n" if ($main::verbose>=5); # Checking with ARIN/APNIC/RIPE/AUSNIC (last resort) #if (not($main::trustEmail)) { # print "As a last resort, trying to lookup on ARIN\n" if ($main::verbose>=5); # print "Starting with whois.arin.net..." if ($main::verbose>=5); # my $whois =whoisip($ip); # my @arin = split(/\n/, $whois ); # # Desparatly trying to find an email address... # foreach my $line (@arin) { # #print "\n$line\n"; # if ($line =~ /.*([^\s]+\@[^\s]+).*/) { # print "found $1\n" if ($main::verbose>=5); # whoisAbuseAddList(emailDomain($1),0); # } # } #} # Done! # remove the trailing comma chop $main::abuseEmail; print "\n\nFound these abuse addresses: " if ($main::verbose>=5); print "$main::abuseEmail\n"; print "Confidence: $main::trustEmail (the more, the better).\n" if ($main::verbose>=5); exit(0); ################################### SUB ROUTINES ################################################### ## DNS functions sub ip2host { my $foo; my $ip = shift; if (isIP($ip)) { my @aa = split('\.', $ip); my $aaa = pack('C4', @aa); $foo = gethostbyaddr($aaa,2); } return $foo; } sub host2ip { my $host = shift; my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($host); my ($a,$b,$c,$d) = unpack('C4',$addrs[0]); return "$a\.$b\.$c\.$d"; } sub DNSsoa { my $domain = shift; my $soa; use Net::DNS; my $res = new Net::DNS::Resolver; my $query = $res->query($domain, "SOA"); $soa = ($query->answer)[0]->rname if ($query); return $soa; } # Takes 192.168.0.4 and returns 4.0.168.192.in-addr.arpa sub inaddr { my $ip = shift; my $inaddr; if ($ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/) { $inaddr = "$4\.$3\.$2\.$1\.in-addr.arpa"; } return $inaddr; } ## Misc functions # Return true if a string is empty or contains things of little interest. sub empty { $a = shift; return 1 unless $a; return (($a ne "\n") && not($a =~ /\s/)) ; } # Finds out the domain of an email address sub emailDomain { $a = shift; ($a =~ /.+\@(.+)/); return $1; } ## IP addresses manipulations functions # Checks if this is really an ip address sub isIP { my $ip = shift; return ( ($ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/) and $1<256 and $2<256 and $3<256 and $4<256 ); } # Transforms an ip address to a decimal number sub ip2dec { my ($ip) = shift; my $dec=0; if ( ($ip =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/) and $1<256 and $2<256 and $3<256 and $4<256 ) { $dec = $1*(16777216) + $2*(65536) + $3*(256) + $4*(1); } return $dec; } # Transforms a decimal number to an ip address sub dec2ip { my ($dec) = shift; return 0 if ($dec>=0 or $dec<=4294967295); my @ip; $ip[0]=$dec/16777216; $ip[1]=($ip[0]-int($ip[0]))*16777216/65536; $ip[2]=($ip[1]-int($ip[1]))*65536/256; $ip[3]=($ip[2]-int($ip[2]))*256/1; return (int($ip[0]),"\.",int($ip[1]),"\.",int($ip[2]),"\.",int($ip[3])); } # $a > $b sub greater { my ($a,$b) = @_; return (ip2dec($a) > ip2dec($b)); } # $a < $b sub smaller { my ($a,$b) = @_; return (ip2dec($a) < ip2dec($b)); } # $a <= $ip <= $b sub between { my ($a,$ip,$b) = @_; return ((ip2dec($a) <= ip2dec($ip)) && (ip2dec($ip) <= ip2dec($b))); } # Remove the first byte of an ip address (in fact, removes everything before the first period). sub popByte { my $a = shift; ($a =~ /.+?\.(.+)/); return $1; } ## Whois functions # Very high level function that queries whois.abuse.net with a domain name and adds the result to the list. sub whoisAbuseAddList { my ($query,$strict) = shift; my @abuse = split(/\n/, whois("whois.abuse.net", $query) ); foreach my $address (@abuse) { if ($address =~ /([^\s]+\@[^\s]+)/) { my $possibleEmail=$1; if (not($strict) or ($hostname =~ emailDomain($possibleEmail)) ) { print "found $possibleEmail\n" if ($main::verbose>=5); addToList($possibleEmail); $main::trustEmail+=1 if not($address =~ "(default, no info)"); } } } } # High level function to add an email address to the list. # Check if the address is allready prensent. sub addToList { my $a = shift; my $found=0; $a =~ tr/A-Z/a-z/; my @list = split(",", $main::abuseEmail); foreach my $address (@list) { if ($a eq $address) { $found=1; last; } } $main::trustEmail+=1 if ($found); $main::abuseEmail = sprintf("%s%s,",$main::abuseEmail,$a) if not($found); } # Whois client function # Based on GeekTools Whois Proxy v2.2.5 # Code mangled by Robb Ballard # Copyright 1999 CenterGate Research Group, LLC # http://www.geektools.com/software.php # ex: whois("whois.corenic.net","logidac.com"); sub whois { my $nicserv = $_[0]; my $myquery = $_[1]; my $output=""; my $port = getservbyname 'whois', 'tcp'; my $remote = IO::Socket::INET->new( Proto=>'tcp', PeerAddr=>$nicserv, PeerPort=>$port, Timeout=>'15' ); if (!$remote) { print "Unable to connect to $nicserv.\n" if ($main::verbose>=2); return ""; } if ($nicserv eq "whois.networksolutions.com") { print $remote "L $myquery\r\n"; } elsif ($nicserv eq "whois.arin.net") { print $remote "NE $myquery\t\n"; } else { print $remote "$myquery\r\n"; } my @result = <$remote>; close $remote; foreach my $resline (@result) { $output = $output." ".$resline; } return $output; } # Queries whois.arin.net for an ip address and follows its trace. # Based on GeekTools Whois Proxy v2.2.5 # Code mangled by Robb Ballard # Copyright 1999 CenterGate Research Group, LLC # http://www.geektools.com/software.php sub whoisip { my @lookfor = ( [".*NETBLK-RIPE.*", "whois.ripe.net"], [".*NETBLK-.+-RIPE.*", "whois.ripe.net"], [".*NET-RIPE.*", "whois.ripe.net"], [".*APNIC.*", "whois.apnic.net"], [".AUNIC-AU.*", "whois.aunic.net"] ); my $myquery = shift; my $nicserv = "whois.arin.net"; my @result; my $output=""; REPEAT: while ($myquery) { @result = split(/\n/, whois($nicserv,$myquery) ); foreach my $resline (@lookfor) { if ($result[0] =~ m/@{$resline}[0]/) { $nicserv = @{$resline}[1]; print "Switching to $nicserv\n" if ($main::verbose>=5); next REPEAT; } } last; } foreach my $resline (@result) { $output = $output.$resline; } return $output; } __END__ =pod =head1 NAME abuseEmail - Finds out abuse email addresses for a specified IP address =head1 SYNOPSIS B [B<-v>] I =head1 DESCRIPTION B receives an IP address and tries to find out, using its internal whois and DNS clients, what is the responsible party's email address. =head1 OPTIONS =item B<-v> Set verbosity level to 5. The script will explain every action it makes; it will also display a confidence level for the email addresses found. =head1 DIAGNOSTICS =item Error: Please specify a host IP address. (F) You did not specified an IP address to lookup. =item Error: This doesn't looks like a numeric IP address. (F) Specifing an hostname will not work, a numeric IP address is required. =item Error: %s is a private IP address (RFC1918). It's a local machine or a spoofed ip, either way, I can't give you any infos on this. (F) Because of an IP address shortage, the IANA (Internet Assigned Numbers Authority), decided to specify addresses that could only be used in private networks, not on the public Internet. You asked this program to lookup this kind of address, as it is a private address, it is not listed in any directory. You may want to ping this address to see if this come from a computer using a private address on your local network. It is also possible that the person who tried to connect to your computer sent a spoofed ip packet, that is, sending an ip packet with an incorrect "from:" tag. There is not much that you can do about this. Sorry. =item Error: %s is a reserved IP address. It's very likely to be a spoofed ip, or your network admin/BOFH is on crack, either way, I can't give you any infos on this. (F) The IP address you specified is a reserved address for experimental purposes; it is almost impossible that such an IP address is used on the Net. What is very likely is that the person who tried to connect to your computer sent a spoofed ip packet, that is, sending an ip packet with an incorrect "from:" tag. There is not much that you can do about this. Sorry. =head1 REQUIRES Perl 5.004, IO::Socket, Net::DNS::Resolver =head1 SEE ALSO dig(1), whois(1), perl(1) =head1 BUGS Yes, there might be some. Please report any one you find to gfk@logidac.com =head1 TODO =item Make ARIN whois lookup catch email addresses. =item Better handling of the email addresses, and find out which one are best. =head1 WEBSITE Visit B for more infos and the lastest version. =head1 AUTHOR Guillaume Filion =cut