DragonFly On-Line Manual Pages
GDNSD-PLUGIN-GEOIP(8) gdnsd GDNSD-PLUGIN-GEOIP(8)
NAME
gdnsd-plugin-geoip - gdnsd meta-plugin for GSLB + failover via
MaxMind's GeoIP databases
SYNOPSIS
Minimal example gdnsd config file using this plugin:
plugins => { geoip => {
maps => {
my_prod_map => {
geoip_db => GeoIPCity.dat,
datacenters => [dc-03, dc-02, dc-01],
map => {
EU => {
DE => [dc-03, dc-01],
CH => [dc-01, dc-03]
},
NA => { MX => [dc-02] }
}
},
my_auto_map => {
geoip_db => GeoIPCityv6.dat,
datacenters => [dc1, dc2],
auto_dc_coords => {
dc1 => [ 38.9, -77 ],
dc2 => [ 50.1, 8.7 ],
}
}
},
resources => {
prod_www => {
map => my_prod_map
service_types => default
dcmap => {
dc-01 => 192.0.2.1,
dc-02 => { lb01 => 192.0.2.2, lb02 => 192.0.2.3 },
dc-03 => [ 192.0.2.4, 192.0.2.5, 192.0.2.6 ]
}
}
corp_www => {
map => my_auto_map
dcmap => {
dc1 => 192.0.2.100,
dc2 => 192.0.2.101
}
}
}
}}
Example zonefile RRs:
www 600 DYNA geoip!prod_www
www-dc01 600 DYNA geoip!prod_www/dc-01
www.corp 600 DYNA geoip!corp_www
DESCRIPTION
gdnsd-plugin-geoip uses MaxMind's GeoIP binary databases to map address
and CNAME results based on geography and (in the address case)
monitored service availability. It fully supports both IPv6 and the
emerging edns-client-subnet standard. If a request contains the edns-
client-subnet option with a source netmask greater than zero, the edns-
client-subnet information will be used instead of the source IP of the
request (the IP of the querying cache).
This plugin can operate in an automatic distance-based mode (using
City-level coordinate information rather than an external file and a
Region-level db). It can also operate coordinate-free and rely on the
user to configure a hierarchical map of cascading default user-
location-to-datacenter mappings, starting at the continent level.
The two modes can also be effectively mixed at geographic boundaries.
For each "map" you define (which maps geographic location codes to
preference-ordered lists of your datacenter locations), this plugin
merges all of the raw GeoIP subnets into the largest possible supernets
which contain identical responses in your configuration. These in turn
are used to set larger edns-client-subnet scope masks than you'd see
simply returning raw GeoIP results.
PLUGIN_METAFO
The documentation for gdnsd-plugin-metafo(8) is required reading for
understanding the geoip plugin documentation here. The geoip plugin is
an exact superset of the metafo plugin, and re-uses almost all of the
metafo plugin's source code. What plugin_geoip adds on top of the
functionality of metafo is the ability to have the order of the
datacenter failover list become dynamic per-request based on geographic
hints derived from the client's network address, as well as the ability
to do geographic selection of DYNC (CNAME) resources.
FILE LOCATIONS
The configuration of this plugin can reference several external
configuration and/or data files. The location of these files is
dependent, of course, on whether the daemon is running in chroot or
"system paths" mode. In system paths mode, the directory for these
files is commonly, e.g. /etc/gdnsd/geoip/ given autoconf $sysconfdir of
/etc. In chroot mode, the directory would be /srv/gdnsd/etc/geoip/
given a chroot directory of /srv/gdnsd. If any of the pathnames are
specified as absolute paths, they will be taken literally (although
this will still be relative to the chroot in the chroot case).
CONFIGURATION - TOP-LEVEL
The top level of the geoip plugin's configuration (i.e. "plugins => {
geoip => { ... } }") supports only two special keys, both of which are
required and expanded upon in detail in the next two sections: "maps",
and "resources". The "maps" section defines one or more named mappings
of location information from GeoIP binary databases to ordered subsets
of datacenter names. The "resources" section defines one or more named
resources, each of which references one of the named maps and resolves
datacenter names to specific sets of addresses or CNAMEs.
Any other keys present at this level will be inherited down inside of
each per-resource hash inside the "resources" stanza, acting as per-
resource defaults for anything not defined explicitly there.
CONFIGURATION - MAPS
The "maps" stanza supports one special configuration key at the top
level:
"city_region_names = region_codes.csv"
String, filename, optional. GeoIP City databases use FIPS 10-4 codes
for the names of Regions outside of the US and Canada, and two-letter
national alpha codes within the US and Canada. For example the Geneve
region of Switzerland is identified as 07 in the database. By default
you would have to use these relatively confusing region codes in your
hierarchical maps that make use of Region-level information (e.g. "EU
=> { CH => { 07 => { Geneva => [ ... ] } } } }". If this option is
specified, it points to a text file that maps these FIPS codes to
canonical, memorable full names for clearer map configuration (e.g. "EU
=> { CH => { Geneve => { Geneva => [ ... ] } } } }". Note that while
older versions of this data did not map the US/Canadian two-letter
alpha codes, newer versions do (e.g. TX -> Texas).
This setting does not affect the GeoIP "Region" -format databases,
which have no region codes outside of the US and Canada, and always
need the two-letter alpha codes in the map.
The file format is a simple subset of the CSV format with 3 fields: ISO
3166-1 country code, FIPS 10-4 region code (or two-letter alpha in
US/Canada), and the region name in double-quotes. It is recommended
you download this file directly from MaxMind's reference copy in this
format. As of this writing, it is available from them at the following
URL: <http://www.maxmind.com/download/geoip/misc/region_codes.csv>.
CONFIGURATION - PER-MAP
All other "maps"-level configuration keys are the names of the maps you
choose to define. A map, conceptually, is a mapping between geography
and/or network topology to varying ordered datacenter sub-sets. The
value of each named map must be a hash, and the following configuration
keys apply within:
"geoip_db = GeoIPv6.dat"
String, filename, optional. This is the filename of one of the
supported MaxMind GeoIP database types. It will be reloaded at runtime
(without any significant query interruptions) if a change to the
database file is detected.
"geoip_db_v4_overlay = GeoIP.dat"
String, pathname, optional. This specifies an optional IPv4-level
GeoIP database to overwrite the IPv4 sub-space of the IPv6 data loaded
from "geoip_db". It must be a V4-format database, and "geoip_db" must
be defined as a V6-format database. In all other respects, it is
similar to "geoip_db".
As of this writing, MaxMind doesn't sell a commercial GeoIPv6 database.
What they offer are free IPv6 GeoLite database downloads, which include
the IPv4 subset in the less-accurate GeoLite form. This option allows
you to use these GeoLitev6 databases for IPv6 coverage, and then
overlay your paid commercial GeoIPv4 data on top for more accurate IPv4
results.
"datacenters = [ one, two, three, ... ]"
Array of strings, required. This is the total set of datacenter names
used by this map. You must define at least one datacenter name
(although 2 or more would be infinitely more useful). At this time,
there is a maximum limit of 254 datacenter names per map, although this
could be raised if anyone requires it. The order specified here is the
fallback default result ordering in various default cases (e.g. if no
explicit top-level map default list is given).
"city_no_region = true"
Boolean, default "false". If this key is set to "true" and "geoip_db"
references a City-level database, the Region-level information within
it will be completely ignored for mapping purposes. Your hierarchical
map structure will now be "continent => country => city" rather than
"continent => country => region => city".
"nets = { ... }"
Key-value hash, optional (see below for alternate form). If specified,
the contents should be key-value pairs of "network/netmask" mapped to a
datacenter name (or an array of datacenter names). Any network-to-
datacenter mappings specified here will override mappings determined
via GeoIP. Note that it is illegal to specify networks in the
IPv4-like subspaces of IPv6 other than v4compat, but it is legal to
specify actual IPv4 networks (which are treated identically to
v4compat). See the section on IPv4 Compatible Addresses later in this
document for more details. The order of the networks is unimportant;
they will always be sorted and inserted such that an entry which is a
subnet of another entry is not obliterated by the parent supernet.
nets => {
10.0.0.0/8 => [ dc1, dc2 ],
192.0.2.128/25 => dc3
2001:DB8::/32 => [ dc4, dc5, dc6 ],
}
In the case that one entry is a subnet of another with a different
result dclist, the entries are merged correctly such that the supernet
surrounds the subnet. In the case of an exact duplicate entry (or an
effective one, after merging smaller subnets) with a different dclist,
it is arbitrary which one "wins" and the condition is warned about. If
you care about this case, you should sanitize your nets data beforehand
with an external tool and/or parse for the warning message in log
outputs.
"nets = nets_file_name"
String pathname, optional. A variant of the above, but the contents of
the key-value hash are loaded from the named external file. This makes
life easier for external tools and scripts generating large sets of
nets entries (e.g. from BGP data). The file will be monitored for
changes and reloaded at runtime much like the GeoIP databases.
"map = { ... }"
Key-value hash, optional. This is the heart of a named map which uses
GeoIP: the map itself, which maps places to ordered lists of
datacenters. It requires that "geoip_db" is also specified, and makes
no sense without it.
This is a nested key-value hash. At each level, the keys are location
codes (continent, country, region, or city information depending on
depth), and the values are either an ordered datacenter array (e.g. "[
dc03, dc01, dc04 ]"), or a sub-hash containing a deeper level of
distinction. At each layer, a special key named "default" is
available, which sets the default for everything within the current
scope. The top-level default itself defaults to the ordered list from
"datacenters" in the normal case. If the entire "map" stanza is
missing or empty, you just get the default behavior of "default". A
datacenter array can also be empty, which implies that this location is
mapped to receive no response data (the server will still respond to
the query, and will not issue an NXDOMAIN. It will simply be a
NODATA/NOERROR response like you'd get if there were no records of this
type, but could be records of other types for the same name).
The meaningful location keys at the top level are continent codes, of
which there are primarily seven in MaxMind's databases: "AF" for
Africa, "AS" for Asia, "NA" for North America, "SA" for South America,
"EU" for Europe, "OC" for Oceania, and "AN" for Antarctica. There is
also an eighth continent-level code which is, literally, "--". This is
a sort of fallback "no information available" continent code, and it
contains the special country codes "A1", "A2", "O1", and "--", which
represent Anonymous Proxies, Satellite Providers, Other, and Unknown,
respsectively.
The next layer (the sub-hash beneath any continent code) maps
ISO-3166-1 2-letter country codes, which as with continents can map
directly to datacenters, or to yet another recursive layer.
The next two layers deep are for Region and City level information,
only available from the Region and City type databases. The Region
database type only provides region information for the US and Canada,
using the standard local 2-letter abbrevations (e.g. AB for Alberta, OK
for Oklahama). The City databases use those same region abbrevations
for the US and Canada, but use either FIPS 10-4 2-letter codes or full
region names for the rest of the world's regions (as detailed earlier
in, and controlled by, the "city_region_names" option).
The actual City names at the final layer appear to be encoded using
some form of ISO8859-1 and/or CP1252 character set in the databases
themselves, and your map entries will have to match byte-for-byte in
the case of non-ASCII characters. May come up with a better solution
for this down the road.
There is also one other special key (aside from "default") available at
all levels of the map hierarchy, a boolean named "skip_level", default
"false". If set within the hierarchical "map" at any layer, it causes
the next layer of detail to be skipped for this portion of the map.
For example, setting this at the very top layer would mean that the top
layer would contain country-level codes directly, without an enclosing
continent-level hierarchy. Setting it within a country would mean that
city names are used directly within that country, without an
intervening layer of region names. This option is not aware of the
"city_no_region" option, so e.g. setting that option and specifying
"skip_level" at the country-level would result in no further
information being available within that country (as "skip_level" would
skip the remaining layer of city data).
CONFIGURATION - MAPS - CITY AUTO MODE
"City-auto-mode" is a special mode of operation that automatically maps
out the world to your datacenters based on coordinate math, so that you
don't have to manually construct a complex hierarchical "map". It can
still be mixed with "map" of course, allowing you to use auto-mode for
only select geographic areas if you wish (or disabling it for select
areas by specifying manual lists). The key parameter is
"auto_dc_coords", which enables city-auto-mode.
"auto_dc_coords = { ... }"
Key-value hash, optional. If this option is specified, the whole
map's basic mode of operation changes to "city-auto-mode". The
contents of the hash are a key for each datacenter named in
"datacenters", with their values set to an array of "[lat, lon]" in
decimal degree units. When city-auto-mode is enabled by this, the
following configuration-validation changes occur from the default,
static-mapping mode: the loaded GeoIP database(s) are required be
City-level databases, and the special keyword "auto" becomes a
legal "datacenter list" in the "map" stanza.
With city-auto-mode enabled, the top-level map "default" defaults
to "auto", but can be overridden with a manual list. For any
location that maps to "auto", the coordinates specified here in
"auto_dc_coords" will be compared with the coordinates from the
City-level database(s) to determine an automatic distance-sorted
datacenter list.
If you omit one or more defined datacenters from the coordinate
list in "auto_dc_coords", those datacenters will not be used in
automatic results, but will still be available for manual use via
"map" and/or "nets" entries.
"auto_dc_limit = N"
Unsigned integer, optional, default 3. When city-auto-mode is in
effect, this is the upper length limit for auto-generated lists. 3
is a reasonable default even if you have a considerably longer set
of datacenters, as this provides a primary as well as two
fallbacks. Raising this to a large number in the presence of a
long datacenter list will cause the set of unique result datacenter
lists to increase rapidly, and thus reduce the optimization of the
final result database for edns-client-subnet purposes. It's really
not worth raising this value in almost any case, unless you really
need to handle more than 3 random datacenters going offline at the
same time and still have clients fail elsewhere. The value zero is
treated as unlimited (highly un-recommended).
Under city-auto-mode, when the top-level default is (explicitly or
implicitly) "auto", there is still a fallback static ordering which is
the whole ordered "datacenters" list, which is the normal static
default "default" when not in city-auto-mode. This fallback is used
when no location information is available at all (e.g. IPv6 client vs
IPv4 GeoIP DB, Anonymous Proxies, etc).
MAP TESTING
A binary program "gdnsd_geoip_test" is included. This can be used
directly from the commandline, parses the relevant bits of your gdnsd
config file for geoip map info, and then provides datacenter list
results for IP address + map combinations supplied by the user. Useful
for debugging your maps and testing the mapping of client IPs. It has
a separate manpage gdnsd_geoip_test(1).
CONFIGURATION - RESOURCES
Resource-level configuration within the "resources" stanza is nearly
identical to the resources configuration of the metafo plugin, with all
of the same basic behaviors about synthesizing or directly referencing
the configuration of other plugins per-datacenter. Only the key
differences will be covered here:
o metafo's per-resource "datacenters" array is replaced with "map =>
mapname", which references one of the maps defined in the "maps"
stanza, described in detail earlier. The set of defined
datacenters in the "dcmap" stanza must match the total set of
datacenters defined by the referenced map.
o metafo's restriction to just address-based (DYNA) results is
lifted. If the per-resource sub-plugin configurations used by a
geoip resource support CNAME (DYNC) results, then that geoip
resource will also support DYNC results. Because there is no DYNC
monitoring, only the first datacenter from each datacenter sub-list
in the "map" will be used for the result; there is no failover,
only geographic differentiation.
o For the common case of a single CNAME result per-datacenter, the
CNAME data can be supplied directly as the singular string value of
each datacenter in the "dcmap", without involving a sub-plugin at
all.
META-PLUGIN INTERACTION
Both of the meta-plugins ("metafo" and "geoip") can reference their own
as well as each others' resources by direct reference within a "dcmap",
so long as a resource does not directly refer to itself. This allows
plugin-layering configurations such as geoip -> metafo -> weighted, or
metafo -> geoip -> multifo, or even metafo -> metafo -> simplefo, etc.
Bear in mind that once you begin using inter-meta-plugin references,
you could create a reference loop. gdnsd does not currently detect or
prevent such loops, and they will cause complete runtime failure when
queried, probably by running out of stack space during recursion.
Additionally, "geoip" can synthesize configuration for "metafo"
resources, but the reverse does not hold; "metafo" cannot synthesize
configuration for "geoip" resources.
IPv4 Compatible Addresses
This plugin knows of five different relatively-trivial ways to map IPv4
addresses into the IPv6 address space. These are shown below, with
"NNNN:NNNN" in place of the copied IPv4 address bytes:
::NNNN:NNNN/96 # v4compat - canonical form for this plugin
::FFFF:NNNN:NNNN/96 # v4mapped
::FFFF:0:NNNN:NNNN/96 # SIIT
2001::NNNN:NNNN/32 # Teredo (NNNN:NNNN is xor'd with FFFF:FFFF)
2002:NNNN:NNNN::/16 # 6to4
All of this plugin's internal lookup databases are IPv6 databases, and
any IPv4-like information is always stored in the v4compat space within
these databases. When doing runtime lookups all other v4-like
addresses (raw IPv4 addresses, v4mapped, SIIT, Teredo, and 6to4) are
converted to the canonical v4compat IPv6 representation before querying
the internal databases. The other representations (v4mapped, SIIT,
Teredo, 6to4) are Undefined internally, and will never be referenced at
lookup-time due to the v4compat conversion mentioned earlier.
The "nets" stanza is not allowed to specify entries in the four
undefined v4-like IPv6 spaces (those other than v4compat). Specify
those networks as normal IPv4 networks or v4compat networks instead.
Legitimate IPv6 "nets" entries which happen to be a supernet of any
v4-like spaces will *not* undely affect v4-like lookups. There is no
functional difference between v4compat and native v4 forms in "nets",
e.g. "192.0.2.0/24" and "::C000:0200/120" are completely identical.
GeoIP databases that are natively IPv4-only get all of their data
loaded into the v4compat space only. For IPv6 GeoIP databases, by
default we load the v4compat space directly (which is where MaxMind
stores IPv4 data in their IPv6 databases), but ignore the
v4mapped/SIIT/Teredo/6to4 spaces (some of which are empty in MaxMind's
databases, and some of which simply alias the v4compat space). When
using an IPv6 GeoIP database combined with an IPv4 GeoIP overlay
(geoip_db_v4_overlay config), the v4compat space of the IPv6 database
is also ignored on loading, and the direct IPv4 data from the IPv4
databasee takes its place.
ANOTHER CONFIG EXAMPLE
A relatively-maximal example config, showing the interaction of valid
"maps" and "resources" sections:
service_types => {
xmpp_svc => { plugin => "tcp_connect", ... }
www_svc => { plugin => "http_status", ... }
}
plugins => {
geoip => {
maps => {
city_region_names => fips_include,
my_prod_map => {
geoip_db => GeoIPCityv6.dat,
geoip_db_v4_overlay => GeoIPCity.dat,
city_no_region => false, # default
datacenters => [us-01, de-01, sg-01],
map => {
# Hierarchy is Continent -> Country -> Region -> City
NA => {
US => {
skip_level => 1, # skip past region level
Dallas => [sg-01],
}
}
SA => [us-01, sg-01, de-01],
EU => {
default => [eu-01, us-01, sg-01],
CH => {
Geneve => {
Geneva => [sg-01],
}
}
}
AF => [eu-01, us-01, sg-01],
AS => [sg-01, eu-01, us-01],
OC => [sg-01, us-01, eu-01],
}
nets => {
10.0.0.0/8 => [ eu-01 ],
2001:DB8::/32 => [ us-01 ],
}
}
my_auto_map => {
geoip_db => GeoIPCityv6.dat,
geoip_db_v4_overlay => GeoIPCity.dat,
datacenters => [us-01, de-01, sg-01],
auto_dc_coords => {
us-01 => [ 38.9, -77 ],
de-01 => [ 50.1, 8.7 ],
sg-01 => [ 1.3, 103.9 ],
}
}
}
resources => {
prod_app => {
map => my_auto_map
# these two are inherited multifo config keys
# for all of the dcmap below:
service_types => [www_svc, xmpp_svc],
up_thresh => 0.4,
dcmap => {
us-01 => {
lb01 => 192.0.2.1,
lb02 => 192.0.2.2,
lb03 => 192.0.2.3,
lb01.v6 => 2001:DB8::1,
lb02.v6 => 2001:DB8::2,
lb03.v6 => 2001:DB8::3,
},
sg-01 => {
lb01 => 192.0.2.4,
lb02 => 192.0.2.5,
lb03 => 192.0.2.6,
lb01.v6 => 2001:DB8::4,
lb02.v6 => 2001:DB8::5,
lb03.v6 => 2001:DB8::6,
},
de-01 => {
lb01 => 192.0.2.7,
lb02 => 192.0.2.8,
lb03 => 192.0.2.9,
lb01.v6 => 2001:DB8::7,
lb02.v6 => 2001:DB8::8,
lb03.v6 => 2001:DB8::9,
},
}
},
prod_cdn => {
map => my_prod_map,
dcmap => {
us-01 => us-cdn-provider.example.com.
sg-01 => asia-cdn-provider.example.com.
de-01 => europe-cdn-provider.example.com.
}
}
}
}
}
Example zonefile RRs:
app 600 DYNA geoip!prod_app
app.us 600 DYNA geoip!prod_app/us-01
app.sg 600 DYNA geoip!prod_app/sg-01
app.de 600 DYNA geoip!prod_app/de-01
content 600 DYNC geoip!prod_cdn
SEE ALSO
gdnsd-plugin-metafo(8), gdnsd_geoip_test(1), gdnsd.config(5),
gdnsd.zonefile(5), gdnsd(8)
The gdnsd manual.
COPYRIGHT AND LICENSE
Copyright (c) 2012 Brandon L Black <blblack@gmail.com>
This file is part of gdnsd.
gdnsd is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your
option) any later version.
gdnsd is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with gdnsd. If not, see <http://www.gnu.org/licenses/>.
gdnsd 1.11.4 2014-07-18 GDNSD-PLUGIN-GEOIP(8)