I am a fan of free data and sharing cool information
So I give props to maxmind.com for their free lite geo IP data base.The database can be found at : http://dev.maxmind.com/geoip/geoip2/geolite2/ They are CSV Files so you need to import them.
here is how I import them into MySQL:
Create the first table:
CREATE TABLE `geocityblocks` ( `network_start_ip` varchar(45) DEFAULT NULL, `network_prefix_length` bigint(20) DEFAULT NULL, `geoname_id` bigint(20) DEFAULT NULL, `registered_country_geoname_id` bigint(20) DEFAULT NULL, `represented_country_geoname_id` bigint(20) DEFAULT NULL, `postal_code` varchar(45) DEFAULT NULL, `latitude` float(10,6) DEFAULT NULL, `longitude` float(10,6) DEFAULT NULL, `is_anonymous_proxy` int(11) DEFAULT NULL, `is_satellite_provider` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;now import the very large 198meg CSV file. I run this command in MySQL Workbench:
load data local infile 'C:/Users/mell/Downloads/GeoLite2-City-CSV/GeoLite2-City-CSV_20141202/GeoLite2-City-Blocks.csv' into table `test`.`geoCityBlocks` fields terminated by ',' OPTIONALLY enclosed by '"' lines terminated by '\n' ignore 1 lines (network_start_ip,network_prefix_length,geoname_id,registered_country_geoname_id,represented_country_geoname_id, postal_code,latitude,longitude,is_anonymous_proxy,is_satellite_provider)
It should be around 3,080,877 rows
Now lets work on the other table:
CREATE TABLE `geocitylocations` ( `geoname_id` varchar(100) DEFAULT NULL, `continent_code` varchar(100) DEFAULT NULL, `continent_name` varchar(100) DEFAULT NULL, `country_iso_code` varchar(100) DEFAULT NULL, `country_name` varchar(100) DEFAULT NULL, `subdivision_iso_code` varchar(100) DEFAULT NULL, `subdivision_name` varchar(100) DEFAULT NULL, `city_name` varchar(100) DEFAULT NULL, `metro_code` varchar(100) DEFAULT NULL, `time_zone` varchar(100) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8
Now import the data to that table. I run this command in MySQL Workbench:
load data local infile 'C:/Users/mell/Downloads/GeoLite2-City-CSV/GeoLite2-City-CSV_20141202/GeoLite2-City-Locations.csv' into table `test`.`geoCityLocations` fields terminated by ',' OPTIONALLY enclosed by '"' lines terminated by '\n' ignore 1 lines (geoname_id,continent_code,continent_name,country_iso_code,country_name,subdivision_iso_code,subdivision_name, city_name,metro_code,time_zone)should be around 86,470 rows
for the US this is how an entry looks
geoname_id=4700168
continent_code=NA
continent_name=North America
country_iso_code=US
country_name=United States
subdivision_iso_code=TX
subdivision_name=Texas
city_name=Irving
metro_code=623
time_zone=America/Chicago
and finally some code to use the data:
PHP Code: https://github.com/maxmind/geoip-api-php/blob/master/src/geoip.inc
About the CSV files: http://dev.maxmind.com/geoip/geoip2/geoip2-csv-databases/
So lets make this stuff more useful. Since everything is stored in ipv6 as strings we need to add 2 more fields:
ipv6_binary as varbinary(16)
ipv6_binary_top as as varbinary(16)
So run this is MySQL workbench: its going to take a few minutes
ALTER TABLE `test`.`geocityblocks` ADD COLUMN `ipv6_binary` VARBINARY(16) NULL AFTER `is_satellite_provider` ; ALTER TABLE `test`.`geocityblocks` ADD COLUMN `ipv6_binary_top` VARBINARY(16) NULL AFTER `ipv6_binary` ;This is going to store the ipv6 address as binary in ipv6_binary. e.g. 4.28.169.0 = ffff 041c a900
Then we will compute the top range and add that as well in ipv6_binary_top:255 allowed address FFFF 041C A9FF
-- The below line to set the binary for all the address. it takes awhile to run and you will need a version of MySQL that supports INET6_ATON, (run time about 3-5 minutes) :)
update test.geoCityBlocks set ipv6_binary=INET6_ATON(network_start_ip);now increment the ipv6_binary_top: INET6_ATON(network_start_ip) + getIpRange(network_prefix_length)
You will need to use the function I made list at the bottom of the page.
matching the IP:
You will need to pad the hex up to 16:
select * from test.geoCityBlocks where ipv6_binary>=x'00000000000000000000ffff041ca900' && ipv6_binary_top<=x'00000000000000000000ffff041ca900'
Functions:
DELIMITER $$ CREATE FUNCTION `test`.`getIpRange` (network_prefix INT) RETURNS INTEGER BEGIN DECLARE x INT; DECLARE j INT; DECLARE y INT; SET x = 1; SET y = 1; SET j = 129-network_prefix; sloop: LOOP SET x = x + 1; IF x > j THEN LEAVE sloop; END IF; SET y = y + y; ITERATE sloop; END LOOP sloop; RETURN y; END