The tinydns GeoIP patch - Making djbdns Geographically Aware
For quite some time I have been looking for a more robust way to make djbdns respond differently depending on the source IP of the requester. This kind of thing would be useful, for example, when running a service out of geographically disparate areas like New York and Los Angeles. Ideally, users would go to their most local server, East coast US users to New York and West coast US users to Los Angeles. But without somehow knowing where the source IP is geographically, constructing the most appropriate reply is impossible.
djbdns has the ability to "name" network ranges through the use of "%" or "client location" records. For example, the lines:
%in:192.168
%ex
denote 192.168.0.0 through 192.168.255.255 as a block named "in". Everything else is in a block called "ex". Now when given the lines:
+www.example.com:192.168.1.2:::in
+www.example.com:1.2.3.4:::ex
clients requesting from within the range 192.168.0.0 through 192.168.255.255 get the IP "192.168.1.2" while everyone else gets the IP "1.2.3.4".
This might work well when running a split-horizon DNS server on internal and external network segments but it doesn't work very well when dealing with the ultra-fractured IP space on the real Internet. Unfortunately, for example, the West coast of the United States can't even be described within a block like this. It couldn't even be done within thousands of blocks because the data doesn't break down on block boundaries.
What is needed is a mechanism within tinydns for describing IP ranges that can be flexible enough to support the level of fracture on the Internet today. Thankfully, such an option now exists. Adrian Ilarion Ciobanu wrote a GeoIP patch for djbdns which can tailor answers for arbitrary IP ranges. Generally, the GeoIPDNS patch enhances the "%" record to accept an IP range like this:
%US:1.2.3.240:1.2.3.247:user
In other words, the 8 IPs from 1.2.3.240 to 1.2.3.247 belong to the 2 letter code "US". Granted, with this small of a breakdown, the full list is going to be very long. Because of this, the patch also optionally supports the use of separate data files for the location map database.
But where would we find all this data to put in this format? As it turns out, a company called MaxMind has released a free version of their GeoLite IP to Country and IP to City databases that are very useful for this need. The data they supply is far more accurate than actually needed for a geographically aware DNS service. For purposes of dividing users in the United States between East and West coast, the GeoLite City database is most useful. (I have written a perl script that combines the GeoLite City CSV files. - sample output)
All that is left is to load the data in a suitable format and build the CDB file for the patched version of tinydns to use. How you actually do this depends on how much you want to fracture the responses. The East coast / West coast example is fairly simple but what if you wanted to serve localized pages on a per country basis? Using two character country codes would work but it also might give you a bit too many cases to satisfy. A better answer might be to only pull the ranges for the countries where you had distinct records and use a catchall record for everything else.
Ultimately I've decided on a "both-and" scenario. By loading a database of country codes, a databse of timezones and a database of US states, I can cover most of the cases that I can think of. The most useful for me at the outset is the timezone scenario. This covers my East coast / West coast issue while allowing for a new server farm in the middle of the country in the future without recreating the location database.
In the SIP context, where I'm using this code, geographically aware DNS is only part of the overall solution. While East coast users get the New York proxy, I still want to list the Los Angeles proxy in the event that the New York proxy is unreachable. I'm doing this with SRV records that list the New York proxy at a higher preference for East coast users than the Los Angeles proxy and vice-versa. As we bring up our Dallas proxy, I will re-fracture the IP ranges to send the center of the country to Dallas with New York and Los Angeles as backups.
My thanks to Adrian Ilarion Ciobanu and MaxMind for making this possible.
Tags
tinydns GeoIP patch djbdns Geographically AwareTrackbacks
To send a trackback, use the URL of this story appending ?page=tb at the end.Comments (5)
daniel albe from BsAs - Argentina
Hey!, great article.
Seems you have it working....maybe you can point me to the correct way.
I cannot find any info about how to integrate maxmind with these new version.
I have the last one working and running with maxmind, and doing geoipdns, but I would like to test these new version.
The new site is unavailable, and all mailing list/forums are empty (I made already a post in the mailing list)
If you have any info, would be great. You have my email if is needed.
Thanks!
daniel from rivo.com.ar
Anders from RTP
Daniel: To integrate MaxMind, you need to write a script that dumps only the data you care about. In my example perl script, I dump everything. The idea is that you only dump the ip range and the entity you want to use to split things up in this format:
%AR:1.1.1.0:1.1.1.255
%US:2.2.2.0:2.2.2.255
So here, I'm saying that the IPs between 1.1.1.0 and 1.1.1.255 are in the country "AR" or Argentina and the IPs between 2.2.2.0 and 2.2.2.254 are in the country "US" or the United States. In the simplest form, you put this data into your data file like this:
+www.example.com:11.11.11.11:3600::AR
+www.example.com:22.22.22.22:3600::US
Now tinydns will respond differently for requests made from various sources. Requests for www.example.com coming from within blocks designated as Argentina get 11.11.11.11 and requests made from the US get 22.22.22.22 for www.example.com.
Make sure you set the IPMAP environment variable before starting tinydns:
echo 1 > /service/tinydns/env/IPMAP
You probably also want to have a default record if an IP comes to you that doesn't fit inside one of your IP ranges:
+www.example.com:11.11.11.11:::~~
Note: I also patched a bug in geoipdns-1.0r5.diff that was causing some unpredictability in responding in scope properly. Here's the patch:
diff djbdns-1.05-geoip-orig/ipdb.c djbdns-1.05-geoip-anders/ipdb.c
65c65
< unsigned int j;
---
> unsigned int j = 0;
Anders from RTP
Here's a script that builds a tinydns friendly data file from the MaxMind Country database. (The one above processes the MaxMind City database and doesn't end up in the tinydns data format.) Example output:
%GB:2.6.190.56:2.6.190.63
%US:3.0.0.0:4.17.135.31
%CA:4.17.135.32:4.17.135.63
...
So if your tinydns server was at 1.2.3.4, you would add entries in the data file like this:
.example.com:1.2.3.4:a:300
+www.example.com:11.11.11.11:::US
+www.example.com:22.22.22.22:::GB
+www.example.com:33.33.33.33:::CA
+www.example.com:99.99.99.99:::~~
So for www.example.com, IPs in the United States (US) will get 11.11.11.11, IPs in the United Kingdom (GB) would get 22.22.22.22, IPs in Canada would get 33.33.33.33 and all other requests would get the default record of 99.99.99.99.
daniel albe from BsAs - Argentina
GREAT GREAT! So easy!.
My missunderstanding was to find the way Adrian replaced the berkley database maxmind integration, cause i was looking for some kind of similar approach. But integrating the data in the same tinydns config file, helps a lot and simplify the process.
Now is so natural... Super easy!
I'm doing geolocalization at ISP level with database I've purchased from maxmind. The DB is similar to the country one, so I will make my own script based on yours, and will post too, maybe someone could use it.
Also, I have entered in contact with Adrian, after being in contact with you. He was kindly enough to answer my email and change all the data at Google dev site with an updated patch (now 1.0 r6) and with a lot of info too. I have seen also he answered your post about the bug and the ~~ trick.
Well, as you can see, I could not resist and I'm also working in my long weekend!
Thanks a lot again. I think next week I can have my dns full functional at ISP level.
please, keep in contact! was very nice to talk with you.
daniel from rivo.com.ar
Anders from RTP
There is some new documentation covering the updated version of this patch available. Additional features in the new rev include speed enhancements through superfast hash and a "record type" based map to determine if a geoip lookup should be done for a particular name. (speeding up lookups for names where no geoip lookup is required.
Leave a Comment
To create links in comments:
[link:http://www.anders.com/] becomes http://www.anders.com/
[link:http://www.anders.com/|Anders.com] becomes Anders.com
Notice there is no rel="nofollow" in these hrefs. Links in comments will carry page rank from this site so only link to things worthy of people's attention.