Geoip2kml
If you would like to see geographical distribution of all ips in the world download the latest maxmind GeoLiteCity database ( http://www.maxmind.com/app/geolitecity) and run this script to generate Google Earth KML file. Enjoy ;-)
Below are a few screenshots with the kind of visual data you can get with this tool:
Mapping entire Asia?
Or may be just Bay Area?
Each green dot contains a set of ip addresses assigned to that area
And here is the code to make your own maps. Just copy and paste it into geoip2kml file and run it as perl geoip2kml:
#!/usr/bin/perl
# This script will convert GeoIP data obtained from maxmind
# to Google Earth's KML format for easy viewing. It also
# supports filters to narrow down interesting areas.
#
# You can get latest GeoIP database here:
# http://www.maxmind.com/app/geolitecity
# Note: Click on "Download the latest GeoLite City CSV Format" link
# and extract all files in the same directory as this executable
# The first time you execute, you will have to generate a new
# database optimized for operations of this script.
#
# Usage:
# geoip2kml -o output_file -f countrycode_or_city_filter
#
# Developed by iphelix@midnightresearch.com
use Socket;
use Getopt::Std;
my %options;
getopt('of',\%options);
my $output_file = $options{o};
my $filter = $options{f};
unless (defined $output_file) {
print '
_____ __________.____
/ \______ \ |
/ \ / \| _/ |
/ Y \ | \ |___
\____|__ /____|_ /_______ \
\/ \/ \/
'."\t\tpresents...\n\n";
print "geoip2kml - Converts GeoIP information to Google Earth's KML format\n";
print "For questions and bug reports contact: iphelix at midnightresearch.com\n\n";
print "Typical Usage: ./geoip2kml -o filename.kml -f US\n";
print " -o filename - specify output KML file name to use with Google Earth\n";
print " -f filter - specify filter (regex) to use when generating KML file\n";
print " e.g -f US will only show US locations or\n";
print " -f \"San Francisco\" will display all ips assigned\n";
print " to San Francisco and South San Francisco area\n";
exit 1;
}
###############################################################################
# A) First check if GeoLiteCity-Ids exists which is important for future steps
unless(-e "GeoLiteCity-Ids.csv") {
print "[!!!] I did not detect GeoLiteCity-Ids.csv file!\n";
print "[ * ] Generating GeoLiteCity-Ids.csv (it might take awhile)...\n";
my $temp;
open(BLOC,"GeoLiteCity-Blocks.csv") || die "[!!!] Couldn't open GeoLiteCity-Blocks.csv\n";
# skip first two lines
#read BLOC, $temp, 1; read BLOC, $temp, 1;
my @ids;
my ($startIpNum,$endIpNum,$locId);
my $counter=-1;
while(<BLOC>) {
$counter++;
if($counter < 2) { next; } # skip first two lines
s/\"//g;
($startIpNum,$endIpNum,$locId) = split(/,/);
$ids[$locId] = $ids[$locId].$startIpNum.'-'.$endIpNum."|";
}
close BLOC;
my $counter=0;
print "[ * ] Done loading, now sorting ".@ids." elements\n";
open(IDS,">GeoLiteCity-Ids.csv") || die "[!!!] Couldn't open GeoLiteCity-Ids.csv\n";
foreach (@ids) {
print IDS $counter.','.$_."\n";
unless($counter % 100000) { print "$counter - $_\n"; }
$counter++;
}
close IDS;
}
###############################################################################
# B) Load GeoLiteCity-Ids file and split values into array
my $counter = 0;
my @blocks;
open(BLOC, "GeoLiteCity-Ids.csv") || die "[!!!] Couldn't open GeoLiteCity-Ids.csv\n";
print "[ * ] Loading GeoLiteCity database...\n";
while(<BLOC>) {
my ($blocId,$ips) = split(/,/);
$blocks[$blocId] = $ips;
$counter++;
}
close BLOC;
print "[ * ] Finished loading ".@blocks." elements\n";
###############################################################################
# C) Start generating KML file
print "[ * ] Generating KML file...\n";
$counter = 0;
open(OUT, ">$output_file");
print OUT "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
print OUT "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n";
print OUT "<Document>\n";
print OUT "<Style id='small'>\n";
print OUT " <IconStyle>\n";
print OUT " <scale>0.5</scale>\n";
print OUT " <Icon><href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href></Icon>\n";
print OUT " </IconStyle>\n";
print OUT "</Style>\n";
print OUT "<Style id='medium'>\n";
print OUT " <IconStyle>\n";
print OUT " <scale>1.0</scale>\n";
print OUT " <Icon><href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href></Icon>\n";
print OUT " </IconStyle>\n";
print OUT "</Style>\n";
print OUT "<Style id='large'>\n";
print OUT " <IconStyle>\n";
print OUT " <scale>1.5</scale>\n";
print OUT " <Icon><href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href></Icon>\n";
print OUT " </IconStyle>\n";
print OUT "</Style>\n";
print OUT "<Style id='gigantic'>\n";
print OUT " <IconStyle>\n";
print OUT " <scale>2.0</scale>\n";
print OUT " <Icon><href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href></Icon>\n";
print OUT " </IconStyle>\n";
print OUT "</Style>\n";
print OUT "<Folder>\n";
print OUT " <name>GeoIP $filter</name>\n";
# Go through GeoLiteCity-Location file printing out data
open(LOC, "GeoLiteCity-Location.csv") || die "[!!!] Couldn't open GeoLiteCity-Location.csv\n";
while(<LOC>) {
s/\"//g;
my ($locId,$country,$region,$city,$postalCode,$latitude,$longitude,$dmaCode,$areaCode) = split(/,/);
# skip headers and filtered locations
if($city eq 'city' || $city eq '') { next; }
if(defined $filter && ($country ne $filter) && ($city !~ $filter)) { next; }
my (@ranges) = split(/\|/,$blocks[$locId]);
pop @ranges; #remove last empty | to avoid 0.0.0.0-0.0.0.0
my $description = "<![CDATA[\n";
foreach (@ranges) {
my ($startIpNum, $endIpNum) = split(/-/);
chomp($startIpNum);
$description .= inet_ntoa(pack('N',$startIpNum))."
- ".inet_ntoa(pack('N',$endIpNum))."<br>\n";
}
$description .= "]]>\n";
# skip cities with 0 assigned ips
unless(@ranges) { next; }
# Add proper styling to the icon depending on the number of IPs in the area
my $size_style = "small";
if($#ranges < 10) { $size_style = "small"; }
elsif($#ranges < 100) { $size_style = "medium"; }
elsif($#ranges < 1000) { $size_style = "large"; }
else { $size_style = "gigantic"; }
print OUT " <Placemark>\n";
print OUT " <name>$city, $country</name>\n";
print OUT " <description>".$description."</description>\n";
print OUT " <styleUrl>#$size_style</styleUrl>\n";
print OUT " <Point>\n";
print OUT " <coordinates>$longitude,$latitude</coordinates>\n";
print OUT " </Point>\n";
print OUT " </Placemark>\n";
$counter++;
}
close LOC;
print OUT " </Folder>\n";
print OUT "</Document>\n";
print OUT "</kml>";
close OUT;
print "[ * ] Generated $counter listings\n";


