# Copyright (c) 2009, Slide, Inc. (oss@slide.com) # # Versions <= 1.3: # Ken Brownfield (kb+bind@slide.com, krb1@irridia.com) # # CHANGE LOG: # # v1.3: 2009/12/18 # Add IPv6 insofar as MaxMind supports it # Add country_US; format for geodns patch backwards-compatibility # v1.2: 2009/11/09 # Emit database information upon initialization # v1.1: 2009/05/27 # First production version # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (kb/2009/11/09) DESCRIPTION This patch implements support for the MaxMind geo-location database (http://www.maxmind.com/app/ip-location) and uses the GeoIP C API. This patch was inspired by the patch at (http://www.caraytech.com/geodns/). The goals for this patch were to implement the City and other MaxMind databases and add thread safety. Support is implemented for all relevant MaxMind databases: Country City Region ISP Organization AS number Netspeed Domain Country IPv6 The Proxy and Accuracy Radius databases are not supported, since they should be used with the client's IP, not the IP address of the user-local DNS server (LDNS). Both threaded and non-threaded operation have been tested. >100B production queries have passed through this patch with neither crashes nor leaks. SUPPORTED BIND DISTRIBUTIONS This patch applies cleanly to and has been heavily tested on BIND production releases 9.6.0-P1 and above. We plan to continue porting the patch to the latest 9.6 and 9.7 BIND production releases, but back-ports for older BIND versions are *not* planned. TESTED UNIX DISTRIBUTIONS This patch has been heavily tested on Ubuntu 8.04 LTS. Other Linux platforms should prove equally stable. While we put significant effort into the portability of this patch, it has not been tested on BSD-derivatives, Solaris, other Unixes, or AIX. INSTALLATION To build BIND with GeoIP support, you will first need to build/install the GeoIP C API (linked above). We recommend 1.4.6 or later; 1.4.5 (at least) was observed to suffer from memory leaks. After unpacking the BIND distribution, cd into the untarred directory and run: patch -p0 -b < /bind-geoip-1.3.patch This will apply the required patches. You can ignore any conflict on version, but we recommend you change the RELEASEVER string to denote a patched version. autoconf (NOTE: patching configure is much less portable than configure.in. If you do not have access to autoconf, please let us know and we may provide patches against configure.) To add GeoIP support when running configure, there are two key options: --with-geoip This enables support for GeoIP functionality. It looks for GeoIP in standard locations, and will automatically detect if IPv6 support is available. You can also specify a path to the location of your GeoIP install (within which should exist lib and include directories): --with-geoip=/usr/local To enable debug output, use: --with-geoip-debug Starting named with "-d3" or higher will provide logging for all attempted GeoIP matching. Adding these debug logging calls is theoretically a performance hit, but even in heavy production, CPU usage does not change in any perceivable way. Enabling this is recommended to debug unexpected behavior. CONFIGURATION GeoIP matches are performed in the BIND match-clients{} clause in a BIND view. The match-client{} parameters follow this general pattern: geoip_DB__ For values that contain spaces, the '_' character should be used instead. For timezone values that contain the '/' character, the '|' character should be used instead. Note that match-clients{} options are ANDed. More complex logic must be obtained with multiple views (ORs) or careful use and solid understanding of the ! operator. Some examples: # Backwards compatibility for Caraytech/geodns and derived patches: country_US; # New syntax geoip_countryDB_country_US; geoip_cityDB_city_San_Francisco; geoip_cityDB_timezone_America|Chicago; geoip_cityDB_country3_JAP; geoip_cityDB_regionname_California; geoip_cityDB_postal_94118; # "Square" latitude/longitude area geoip_cityDB_lat_41.1_lat_43.1_lon_-82.0_lon_-84.1; # Latitudinal "stripe" area geoip_cityDB_lat_10_lat_11; # Longitudinal "stripe" area geoip_cityDB_lon_20_lon_21; # Lat/lon radius in degrees (adjusted for tapering longitude at the poles) geoip_cityDB_lat_80_lon_83.97_radius_1de; # Lat/lon radius in miles (adjusted) geoip_cityDB_lat_80_lon_73.97_radius_500mi; # Lat/lon radius in kilometers (adjusted) geoip_cityDB_lat_80_lon_73.97_radius_100km; geoip_orgDB_name_Slide; The mechanics of BIND views and other BIND details are beyond the scope of this document, but the following is an example: view "PARIS-FRANCE" { match-clients { geoip_cityDB_country_FR; geoip_cityDB_city_Paris; }; zone "example.com" in { type master; file "paris.france.example.com.dns"; }; }; # Note this will match ANY city named Paris! view "PARIS" { match-clients { geoip_cityDB_city_Paris; }; zone "example.com" in { type master; file "paris.example.com.dns"; }; }; view "FRANCE" { match-clients { geoip_cityDB_country_FR; }; zone "example.com" in { type master; file "france.example.com.dns"; }; }; view "GERMANY" { match-clients { geoip_cityDB_country_DE; }; zone "example.com" in { type master; file "germany.example.com.dns"; }; }; view "DEFAULT" { zone "example.com" in { type master; file "example.com.dns"; }; }; Views have precedence -- the first matching view will be used. LDNS servers in Paris, FR will see results from the first zone file, and any other city named Paris will see results from the second zone file. LDNS servers in the rest of FR and all of DE will then see their respective zones, and everyone else will see the final zone file. STARTUP Once you install and start BIND, syslog will report something like the following: Dec 18 17:00:11 u804 named[5162]: Initializing GeoIP Country DB Dec 18 17:00:11 u804 named[5162]: GEO-106FREE 20090201 Build 1 Copyright (c) 2007 MaxMind LLC All Rights Reserved Dec 18 17:00:11 u804 named[5162]: Initializing GeoIP City DB Revision 1 Dec 18 17:00:11 u804 named[5162]: GEO-133 20091215 Build 1 Copyright (c) 2009 MaxMind Inc All Rights Reserved Dec 18 17:00:11 u804 named[5162]: GeoIP Region DB Revision 0 or 1 not available Dec 18 17:00:11 u804 named[5162]: GeoIP ISP DB not available Dec 18 17:00:11 u804 named[5162]: Initializing GeoIP Organization DB Dec 18 17:00:11 u804 named[5162]: GEO-111 20091201 Build 1 Copyright (c) 2009 MaxMind Inc All Rights Reserved Dec 18 17:00:11 u804 named[5162]: Initializing GeoIP AS DB Dec 18 17:00:11 u804 named[5162]: GEO-117 20090321 Build 1 Copyright (c) 2007 MaxMind LLC All Rights Reserved Dec 18 17:00:11 u804 named[5162]: GeoIP NetSpeed DB not available Dec 18 17:00:11 u804 named[5162]: GeoIP Domain DB not available Dec 18 17:00:11 u804 named[5162]: Initializing GeoIP Country DB IPv6 Dec 18 17:00:11 u804 named[5162]: GEO-106FREE 20091201 Build 1 Copyright (c) 2009 MaxMind Inc All Rights Reserved GeoIP support was able to find the Country, City Rev1, Organization, AS, and Country IPv6 databases, but not the others. IMPORTANT NOTE: If you specify a geoip rule in match-clients{} that reflects an unavailable DB, it will be silently ignored. If you see a syslog message like: error while loading shared libraries: libGeoIP.so.1: cannot open shared object file: No such file or directory This means BIND can't find the GeoIP C API. You may need to specify its location via LD_LIBRARY_PATH. Alternatively, passing an argument to the "--with-geoip=" configure option will set the runtime library path. UPDATING THE MAXMIND DATABASES If you purchase the commercial version of the MaxMind databases (which we recommend) you can use the MaxMind "geoipupdate" tool to run in-place updates of the databases. Alternatively, you can periodically download updated versions of the free databases. Simply reload BIND (via "rndc reload" or SIGHUP) and the MaxMind databases will be reloaded without client impact, and the above messages should be repeated. We chose not to use GEOIP_CHECK_CACHE due to the performance hit of a stat() system call for every lookup. This also more closely follows the behavior of BIND, which does not auto-detect changes. CITY DATABASE OPTIMIZATION Results from City database lookups are cached for the duration of a query. City results are represented by a data structure that contains many data points that could be reused by future City lookups. For example, the following would generate two separate GeoIP calls: match-clients { geoip_countryDB_country_US; geoip_countryDB_country_FR; }; Whereas this will only generate one call: match-clients { geoip_cityDB_country_US; geoip_cityDB_country_FR; }; match-clients{} clauses that contain multiple cityDB lookups are free from an API perspective. Also, subsequent sequential DNS requests from the same LDNS IP can reuse this structure, though this usage pattern is not common. NOTE: This optimization will most likely not be implemented for a potential future City IPv6 database, since storing and comparing the necessary IPv6 IP struct (ip6_addr) in TLS will likely create more overhead than the cost of simply re-querying GeoIP. FEEDBACK Please email feedback to "oss@slide.com".