Skip to content

Assigning IP addresses to a geographical location

Knowing roughly where a visitor is connecting from is genuinely useful: you can send them to the shop of their own country, show events happening near them, or keep whole regions away from your SSH daemon.

It is not, however, something to build a security control on. Visitors behind a proxy in another country, behind a corporate VPN, or coming out of a Tor exit node will be placed wherever their exit point is, and mobile carriers routinely hand out addresses that geolocate hundreds of kilometres from the actual device. Treat the result as a hint, never as a fact.

Geolocating an address is commonly called GeoIP, after MaxMind’s product of that name, which is the service most people have heard of.

This post was written in 2008 and most of the services it surveyed no longer exist: NetOp’s DNS based country service and the HostIP.info project are both gone. The MaxMind section below has been updated to the current tooling — the legacy .dat databases and the geoiplookup binary were discontinued in 2018 and replaced by the MMDB format, and since December 2019 even the free GeoLite2 databases require a (free) MaxMind account and license key. The techniques are still valid; the specific endpoints are history.

MaxMind GeoIP

MaxMind sells commercial databases and publishes free ones, GeoLite2, under a more restrictive licence. Both come as MMDB files that you download and query locally, which means no network round trip per lookup and no third party learning your visitors’ addresses.

On Debian and Ubuntu, the tooling lives in two packages: geoipupdate fetches and refreshes the databases, and mmdb-bin provides the mmdblookup command line client.

apt install geoipupdate mmdb-bin

Sign up for a free account, create a license key, and put it into /etc/GeoIP.conf:

AccountID       <your account id>
LicenseKey      <your license key>
EditionIDs      GeoLite2-City GeoLite2-Country
DatabaseDirectory /var/lib/GeoIP

Then fetch the databases. The free editions are rebuilt twice a week, so this belongs in a cron job or a systemd timer:

geoipupdate -v

And query them:

mmdblookup --file /var/lib/GeoIP/GeoLite2-City.mmdb --ip 84.226.106.171 country iso_code
"CH" <utf8_string>

Leave off the path at the end of the command to dump everything the database knows about the address — continent, country, subdivisions, city, postal code, approximate coordinates and, importantly, an accuracy radius. Most of the modern languages have an official or community MMDB reader, so the same file can be queried straight from your application.

Geolocation over DNS

The idea behind NetOp’s country.netop.org service deserves to be remembered even though the service itself is long gone: there is no need to invent an HTTP API for this at all. DNS is already a globally distributed, cached, highly efficient key-value lookup, and every language on earth can resolve a name.

The query works exactly like a DNSBL lookup. Reverse the octets of the address, append the zone, and read the answer out of a TXT record:

dig 171.106.226.84.country.netop.org TXT
;; ANSWER SECTION:
171.106.226.84.country.netop.org. 604800 IN TXT    "CH"

CH is Switzerland. Country granularity only, but fast, cacheable and trivial to consume — from PHP it is a single call:

<?php
// The zone of a DNS based country lookup service.
$nameserver = 'country.netop.org';

// In production: $ip = $_SERVER['REMOTE_ADDR'];
$ip = '84.226.106.171';

$reverse = implode('.', array_reverse(explode('.', $ip)));

$country = 'unknown';
$records = dns_get_record($reverse . '.' . $nameserver, DNS_TXT);
if (!empty($records[0]['txt'])) {
    $country = $records[0]['txt'];
}

echo $country . "\n";

The original version of this snippet shelled out to dig and parsed its output as a fallback for systems without dns_get_record(), and passed a bare TXT instead of the DNS_TXT constant — which is a fatal error on PHP 8. Neither is needed today.

Serving the data over DNS also means answers stay fresh without anybody re-downloading a database, which is the one real advantage this approach has over a local MMDB file.

The Other Services of the Day

Two more services were worth a look in 2008, and both are named here for completeness rather than as a recommendation:

  • HostIP.info was a community project that collected geolocation data from its users and published the whole database for download over HTTP and rsync, alongside a small HTTP API and a flag image endpoint. The project has since shut down.
  • InfoSniper offered a free tier of 15 lookups per day and a paid API that combined geolocation with a WHOIS query.

If you are looking for something today, the free databases worth evaluating are MaxMind’s GeoLite2, DB-IP and IP2Location LITE; for a hosted API, ipinfo.io and ipapi are the usual suspects. Whichever you pick, download the database and query it locally if you can: it is faster, it keeps working when the provider does not, and it does not hand your visitors’ addresses to a third party.