geoip

This Release
geoip 0.1.0
Date
Status
Stable
Latest Testing
geoip 0.0.2 —
Other Releases
Abstract
Geolocation using GeoIP.
Description
Provides geolocation (determining country, city etc. from an IP address) using GeoIP data.
Released By
tomasv
License
The (three-clause) BSD License
Resources
Special Files
Tags

Extensions

geoip 0.1.0

README

geoip

This extension provides IP-based geolocation, i.e. you provide an IPv4 address and the extension looks for info about country, city, GPS etc.

To operate, the extension needs data mapping IP addresses to the other info, but these data are not part of the extension. A good free dataset is GeoLite from MaxMind (available at www.maxmind.com).

Installation

To install the extension, basically all you need to do is this

make install

and then (if you're on PostgreSQL 9.1 or above)

CREATE EXTENSION geoip;

For versions of PostgreSQL less than 9.1.0, you'll need to run the installation script manually:

psql -d mydb -f /path/to/pgsql/share/contrib/geoip.sql

Now you're ready to use the extension. More details about the installation options and issues are available in the INSTALL file.

Using the extension

The extension allows you to search for country, city and ASN. All of that is encapsulated into these functions:

  • geoip_country_code(inet) - returns country code (2 chars)
  • geoip_country(inet) - returns all country info (code, name, ...)
  • geoip_city_location(inet) - returns just location ID (INT)
  • geoip_city(inet) - returns all the city info (GPS, ZIP code, ...)
  • geoip_asn(inet) - retusn ASN name and IP range

Using the functions is quite straightforward, especially for functions that return a single value

db=# SELECT geoip_country_code('78.45.133.255'::inet);

 geoip_country_code 
--------------------
 CZ
(1 row)

db=# SELECT geoip_city_location('78.45.133.255'::inet);

 geoip_city_location 
---------------------
               21235
(1 row)

The functions that return a tuple are a bit more complicated. Probably the best way to call them is like a SRF:

db=# SELECT * FROM geoip_city('78.45.133.255'::inet);

 loc_id | country | region |  city  | latitude | longitude | ...
--------+---------+--------+--------+----------+-----------+-----
  21235 | CZ      | 52     | Prague |  50.0833 |   14.4667 | ...

db=# SELECT * FROM geoip_country('78.45.133.255'::inet);

 begin_ip  |    end_ip     | country |      name      
-----------+---------------+---------+----------------
 78.44.0.0 | 78.45.255.255 | CZ      | Czech Republic
(1 row)

db=# SELECT * FROM geoip_asn('78.45.133.255'::inet);

 begin_ip  |    end_ip     |               name                
-----------+---------------+-----------------------------------
 78.44.0.0 | 78.45.255.255 | AS6830 UPC Broadband Holding B.V.
(1 row)

Sure, you can access the data directly through the tables.

Loading the data

This extension requires manual downloading and loading the data. Once you have the extension installed (so that the tables exist), go to http://www.maxmind.com and download the CSV files

  • http://www.maxmind.com/app/geolitecountry - GeoIPCountryCSV.zip
  • http://www.maxmind.com/app/geolitecity - GeoLiteCity_20120207.zip
  • http://www.maxmind.com/app/asnum - GeoIPASNum2.zip

Now we need to preprocess the CSV files so that it's possible to load them into the tables with a COPY. First, unzip the GeoIPCountryCSV.zip and remove the two columns with IP addresses encoded as INT values.

$ unzip GeoIPCountryCSV.zip
$ sed 's/^\("[^"]*","[^"]*",\)"[^"]*","[^"]*",\("[^"]*","[^"]*"\)/\1\2/' \
      GeoIPCountryWhois.csv > countries.csv

Now unzip the GeoLite city data and remove the first two rows (header)

$ tail -$((`wc -l GeoLiteCity-Blocks.csv | awk '{print $1}'`-2)) \
  GeoLiteCity-Blocks.csv > blocks.csv

$ tail -$((`wc -l GeoLiteCity-Location.csv | awk '{print $1}'`-2)) \
  GeoLiteCity-Location.csv > locations.csv

It's time to load the data into the database. There's still a bit of transforming that needs to be done (and doing it in shell would be awkward), so we'll create a few temporary tables. So log in to the database and do this (the PATH needs to be replaced with an actual absolute path to the files).

COPY geoip_country FROM 'PATH/countries.csv'
WITH csv DELIMITER ',' NULL '' QUOTE '"' ENCODING 'ISO-8859-2';

CREATE TEMPORARY TABLE geoip_city_block_tmp (
    begin_ip    BIGINT      NOT NULL,
    end_ip      BIGINT      NOT NULL,
    loc_id      INTEGER     NOT NULL
);

CREATE TEMPORARY TABLE geoip_asn_tmp (
    begin_ip    BIGINT      NOT NULL,
    end_ip      BIGINT      NOT NULL,
    name        TEXT        NOT NULL
);

COPY geoip_city_block_tmp FROM 'PATH/blocks.csv'
WITH csv DELIMITER ',' NULL '' QUOTE '"' ENCODING 'ISO-8859-2';

COPY geoip_city_location FROM 'PATH/locations.csv'
WITH csv DELIMITER ',' NULL '' QUOTE '"' ENCODING 'ISO-8859-2';

COPY geoip_asn_tmp FROM 'PATH/GeoIPASNum2.csv'
WITH csv DELIMITER ',' NULL '' QUOTE '"' ENCODING 'ISO-8859-2';

INSERT INTO geoip_city_block
     SELECT geoip_bigint_to_inet(begin_ip),
            geoip_bigint_to_inet(end_ip), loc_id
       FROM geoip_city_block_tmp;

INSERT INTO geoip_asn
     SELECT geoip_bigint_to_inet(begin_ip),
            geoip_bigint_to_inet(end_ip), name
       FROM geoip_asn_tmp;

ANALYZE;

Now the data is loaded.

Copyright and License

Copyright (c) 2012 Tomas Vondra The extension is distributed under BSD license (see the LICENSE file)