#!/usr/bin/perl # Copyright (C) 2006-2007 Unregistered DNS # # 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. sub inet_aton { my $SourceStr=$_[0]; my @SourceStrArray = split(/\./, $SourceStr); if ($#SourceStrArray < 3) { die("Error: Address should have the format \"aa.bb.cc.dd\" " . $#SourceStrArray . "."); } my $DestValue = @SourceStrArray[0]; $DestValue <<= 8; $DestValue |= @SourceStrArray[1]; $DestValue <<= 8; $DestValue |= @SourceStrArray[2]; $DestValue <<= 8; $DestValue |= @SourceStrArray[3]; return $DestValue; } sub addrule { my $Address=$_[0]; my $AddressCount=$_[1]; my $Country=$_[2]; my $SubnetMaskBin = sprintf "%b", scalar($AddressCount); my $SubnetMaskBinCnt = $SubnetMaskBin; $SubnetMaskBinCnt =~ s/1//g; my $SubnetBit = (32 - length($SubnetMaskBinCnt)); # calc subnet mask my $SubnetMaskBit=(1 << 31); my $SubnetMaskVal=0; for($j=0;$j<$SubnetBit;$j++) { $SubnetMaskVal|=$SubnetMaskBit; $SubnetMaskBit>>=1; } my $SubnetMaskVal1=($SubnetMaskVal >> 24)&255; my $SubnetMaskVal2=($SubnetMaskVal >> 16)&255; my $SubnetMaskVal3=($SubnetMaskVal >> 8)&255; my $SubnetMaskVal4=$SubnetMaskVal&255; # add it my @NicDatum = (inet_aton($Address), inet_aton($SubnetMaskVal1 . "." . $SubnetMaskVal2 . "." . $SubnetMaskVal3 . "." . $SubnetMaskVal4), $Country); push @NicDataArray, [ @NicDatum ]; } if ($#ARGV < 0) { print STDERR "Usage: countrycheck.pl (*NIC data file) ... < (IP address list file)\n"; print STDERR "\n"; print STDERR "(*NIC data file): Data files which provided by regional internet registry such as.\n"; print STDERR " ARIN, APNIC, RIPE, LACNIC and AfriNIC (or more in future).\n"; print STDERR "\n"; print STDERR "(IP address list file): text file which contains IP addresses (CR/LF separated).\n"; exit; } @NicDataArray = (); for(local $i=0;$i<=$#ARGV;$i++) { print STDERR "Reading #" . ($i+1) . "/" . ($#ARGV+1) . " " . @ARGV[$i] . "..."; open(DATAFILE, "<" . $ARGV[$i]); while () { @TextArray = split(/\|/, $_); # parse only ipv4, ipv6 if ((lc(@TextArray[2]) eq "ipv4") && (@TextArray[3] ne "*")) { # check country $found=0; # check whether number of addresses is CIDR-ready or not. $SubnetMaskBin = sprintf "%b", scalar(@TextArray[4]); $SubnetMaskBinCnt = $SubnetMaskBin; $SubnetMaskBinCnt =~ s/0//g; if (length($SubnetMaskBinCnt) > 1) { # print "$CommentChar Notice: @TextArray[3]/\#@TextArray[4] ($SubnetMaskBin) is not CIDR-ready number; splitted.\n"; } @AddressArray = split(/\./, @TextArray[3]); if ($#AddressArray < 3) { print "$CommentChar Error: \"@TextArray[3]\" should have 4 fields.\n"; last; } $AddressValue = scalar(@AddressArray[0]) << 24; $AddressValue |= scalar(@AddressArray[1]) << 16; $AddressValue |= scalar(@AddressArray[2]) << 8; $AddressValue |= scalar(@AddressArray[3]); for (local $i=0;$i 0) { $AddressStr = sprintf "%d.", ($AddressValue >> 24) & 255; $AddressStr .= sprintf "%d.", ($AddressValue >> 16) & 255; $AddressStr .= sprintf "%d.", ($AddressValue >> 8) & 255; $AddressStr .= sprintf "%d", $AddressValue & 255; # print "$CommentChar Notice: $AddressStr/\#$AddressCount goes across the subnet boundary. splitted.\n"; while ($AddressCount > 0) { $AddressCountSub = $AddressCount; while (($AddressValue & ($AddressCountSub - 1)) > 0) { $AddressCountSub /= 2; } $AddressStr = sprintf "%d.", ($AddressValue >> 24) & 255; $AddressStr .= sprintf "%d.", ($AddressValue >> 16) & 255; $AddressStr .= sprintf "%d.", ($AddressValue >> 8) & 255; $AddressStr .= sprintf "%d", $AddressValue & 255; addrule($AddressStr, $AddressCountSub, @TextArray[1]); $AddressValue += $AddressCountSub; $AddressCount -= $AddressCountSub; } } else { $AddressStr = sprintf "%d.", ($AddressValue >> 24) & 255; $AddressStr .= sprintf "%d.", ($AddressValue >> 16) & 255; $AddressStr .= sprintf "%d.", ($AddressValue >> 8) & 255; $AddressStr .= sprintf "%d", $AddressValue & 255; $AddressCount = 2 ** (length($SubnetMaskBin) - $i - 1); addrule($AddressStr, $AddressCount, @TextArray[1]); $AddressValue += $AddressCount; } } } } elsif (lc(@TextArray[3]) eq "ipv6") { } elsif (lc(@TextArray[0]) eq "2") { # database version print STDERR " Database version " . @TextArray[2] . " "; } } close(DATAFILE); print STDERR "done.\n"; } print STDERR "... Data count " . $#NicDataArray . "\n"; print STDERR "Processing "; $prevpos = 0; while () { print STDERR "."; $TargetAddrStr = $_; $TargetAddrStr =~ s/\r$//; $TargetAddrStr =~ s/\n$//; $TargetAddr = inet_aton($TargetAddrStr); for (local $i=$prevpos;$i<=$#NicDataArray;$i++) { if (($TargetAddr & $NicDataArray[$i][1]) == ($NicDataArray[$i][0] & $NicDataArray[$i][1])) { # found country print "$TargetAddrStr $NicDataArray[$i][2]\n"; $prevpos=$i; last; } } for (local $i=0;$i<$prevpos;$i++) { if (($TargetAddr & $NicDataArray[$i][1]) == ($NicDataArray[$i][0] & $NicDataArray[$i][1])) { # found country print "$TargetAddrStr $NicDataArray[$i][2]\n"; $prevpos=$i; last; } } }