mapping an IP address to an ASN

The internet is made of thousands of inter-connected routers (at the time of
writing, there are 40180 routers on the internet). Each of these routers
is assigned a number called ASN (Autonomous System Number).

The routers use a protocol called BGP (Border Gateway Protocol). BGP helps
routers agree on how to talk to each other and how to find each other.
BGP also automatically finds new routes when one or more routers goes away or
when new routers are added to the network.

Every public internet IP address is connected to one of these routers. It
is therefore possible to map an IP address to its router's ASN.

You might wonder what's the value in having the ASN? If you are running
a website with a login or a spam filtering system, knowning the ASN of your
users can be used as part of a global risk analysis. The ASN number is pretty
stable (e.g. it should be the same for an entire university campus, or for all
the users of an ISP, even when the IP addresses are assigned dynamically).

You can use the ASN (as well as other signals) to prompt for a secondary
password at login-time or throw a captcha at content submission time.

This article is going to show you how to build this mapping. The mapping
only needs to be updated once in a while, and the lookup takes less than 1ms.

getting the internet's BGP table

Unless you run your own border router, you most likely don't have direct
access to the BGP data. You can however download the data from
thyme.apnic.net, a website hosted by APNIC.

Note: This data is for ipv4. There are many other routers exposing their BGP tables, some include
the ipv6 network.

choosing a data representation

The BGP table is fairly large, so we want to choose a data representation which will let us
quickly find the mapping from IP to ASN. We could use various types of trees, but for now
a simple hash table is fast enough.

We store the netmask -> ASN mapping in a hash table. Given an IP address, we generate all
possible netmasks and stop as soon as we have a match.

the code

Here is what the code looks like. I removed some caching related stuff.