GDNSD-PLUGIN-GEOIP(8)
π NAME π
ok so bestie, this is gdnsd-plugin-geoip β it's the gdnsd meta-plugin for GSLB + failover via MaxMind's GeoIP2 databases. πΊοΈβ¨
π¦ SYNOPSIS π¦
here's the minimal lil example gdnsd config file using this plugin, look at her go:
plugins => { geoip => {
maps => {
my_prod_map => {
geoip2_db => GeoIP2-City.mmdb,
datacenters => [dc-03, dc-02, dc-01, dc-fail],
map => {
EU => {
DE => [dc-03, dc-01, dc-fail],
CH => [dc-01, dc-03, dc-fail]
},
NA => { MX => [dc-02, dc-fail] }
}
},
my_auto_map => {
geoip2_db => GeoIP2-Country.mmdb,
datacenters => [dc1, dc2],
auto_dc_coords => {
dc1 => [ 38.9, -77 ],
dc2 => [ 50.1, 8.7 ],
}
}
},
resources => {
prod_www => {
map => my_prod_map
service_types => up
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 ],
dc-fail => last.resort.cname.example.net.
}
}
corp_www => {
map => my_auto_map
dcmap => {
dc1 => 192.0.2.100,
dc2 => 192.0.2.101
}
}
}
}}
and here are some example zonefile RRs in zone example.com, mwah π:
www 600 DYNA geoip!prod_www
www-dc01 600 DYNA geoip!prod_www/dc-01
www.corp 600 DYNA geoip!corp_www
π DESCRIPTION π
ok so gdnsd-plugin-geoip uses MaxMind's GeoIP2 binary databases to map address and CNAME results based on geography and monitored service availability. she's fully fluent in both IPv6 and the emerging edns-client-subnet standard. π
and here's the tea: if a request comes in carrying the edns-client-subnet option with a source netmask greater than zero, then the edns-client-subnet info gets used instead of the source IP of the request (aka the IP of the querying cache). yes ma'am, we respect the subnet.
she supports the GeoIP2 format databases, which typically end in .mmdb. she does not support the legacy GeoIP1 format databases (which typically end in .dat). sorry legacy girlies, that era is over π.
she can also run with no GeoIP database at all! in that case the only network-mapping input comes from the "nets" config data or an external "nets" file, which explicitly map subnets to datacenter lists. DIY queen. π
this plugin can operate in an automatic distance-based mode (using a City-level database's coordinate information). it can also operate coordinate-free and rely on you to configure a hierarchical map of cascading default user-location-to-datacenter mappings, starting at the continent level. pick your fighter.
and the two modes can also be effectively mixed at geographic boundaries. best of both worlds, no cap.
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. that's the glow-up β¨
π«Ά PLUGIN_METAFO π«Ά
ok real talk, the documentation for gdnsd-plugin-metafo(8) is required reading for understanding the geoip plugin documentation here. i'm not being dramatic, it literally is.
the geoip plugin is an exact superset of the metafo plugin, and re-uses almost all of the metafo plugin's source code. π€ metafo does failover along a single, global, ordered list of datacenters. 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. she said "one list? cute. i'll do it per-request." π
π FILE LOCATIONS π
the configuration of this plugin can reference several external configuration and/or data files. by default, all files referenced in this plugin's configuration are loaded from the geoip subdirectory of the daemon's configuration directory (default /etc/gdnsd). you can load from other locations by specifying absolute file paths. periodt. π
β¨ CONFIGURATION - TOP-LEVEL β¨
the top level of the geoip plugin's configuration (i.e. "plugins => { geoip => { ... } }") supports only three explicit keys. one is the optional setting "undefined_datacenters_ok".
the other two are required and expanded upon in detail in the next two sections: "maps", and "resources".
"maps"defines one or more named mappings of location information from GeoIP binary databases to ordered subsets of datacenter names. πΊοΈ"resources"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. inherit the vibe, bestie π§¬
π "undefined_datacenters_ok = false" π
Boolean, default false. if set to true, geoip resources are allowed to leave some of the datacenters specified in their "map" undefined in their resource-level "dcmap". for example, a map M might define 3 datacenters named A, B, and C, but a resource using map M might only define result addresses for datacenters B and C in its "dcmap". this would otherwise be a hard configuration error.
!!! DANGER !!! β οΈ β setting this value totrueis a good way to shoot yourself in the foot if you're not very careful about how your maps and resources are configured with respect to each other, especially in"City Auto Mode". maps are calculated without any knowledge of the resources that use them. if a specific network or location maps to a list of datacenters which contains none of the defined datacenters for a given resource, the results of runtime queries for that resource from that location or network will be the empty set (no answer records at all). this is virtually guaranteed to happen in"City Auto Mode"if the number of undefined datacenters in a resource is greater than or equal to the map's"auto_dc_limit". πππ
πΊοΈ CONFIGURATION - MAPS π
okay bestie so every single key at the maps level is literally just the name of a map you're choosing to define. and what even is a map? conceptually, it's a mapping between geography and/or network topology β varying ordered datacenter sub-sets. slay. π¦
the value of each named map has to be a hash, and these keys apply inside it:
geoip2_db = GeoIP2-City.mmdbβ string, filename, optional. this is the filename of a MaxMind GeoIP2 format database. it should hold either the City or the Country data model. ngl there's no distinction made here for IP version, and it's totally normal for these databases to carry both IPv4 and IPv6 data together. if one or the other is missing, clients using that address family will be defaulted. π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). rn there's a max limit of 254 datacenter names per map, though this could be raised if anyone needs it. the order you specify here is the fallback default result ordering in various default cases (like if no explicit top-level map default list is given). πignore_ecs = trueβ boolean, defaultfalse. if this is set totrue, all resources using this map will ignore EDNS Client Subnet (ECS) info when performing lookups against the map, relying solely on the DNS source IP for the lookup. if the client provided ECS in such a query, the response will also contain the ECS option to signal that we're ECS aware in general, but the response scope mask will be set to zero to signal the cache that the ECS data wasn't used and the result is globally cacheable. π
this is useful for situations where the map is intentionally meant to operate solely on recursor IPs rather than ECS IPs, but other maps serviced by the same authserver do make use of ECS data, and so the global edns_client_subnet config option can't be used to disable handling the option completely for the whole server. lowkey a life saver.
nets = { ... }β key-value hash, optional (see below for the alternate form). if specified, the contents should be key-value pairs ofnetwork/netmaskmapped 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's illegal to specify networks in the IPv4-like subspaces of IPv6 other thanv4compat, but it is legal to specify actual IPv4 networks (which are treated identically tov4compat). see the section on IPv4 Compatible Addresses later in this document for more deets. the order of the networks is unimportant; they'll 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's 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 (like 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 thatgeoip2_dbis 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/subdivision, or city information depending on depth), and the values are either an ordered datacenter array (like [ 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). π
π GeoIP2 Location Data Hierarchy π
the top level of the map hierarchy is comprised of MaxMind's seven continent codes: AF for Africa, AS for Asia, NA for North America, SA for South America, EU for Europe, OC for Oceania, and AN for Antarctica. the next level is the ISO 3166-1 2-letter country code. β
from here there are a number of Subdivision levels, the count of which varies for different network database entries. in the US, for example, there's only one level of subdivision data for the US States. in the Czech Republic there are two levels of subdivision: first into 14 regions, and then further into 91 districts. subdivisions are all specified using their ISO 3166-2 codes directly. π
after all subdivision levels, the final level is the City level. the City names are all in the UTF-8 character set. currently this plugin only uses the English city names from the database, even though other languages may be available depending on the database. π¦
as a pragmatic answer to the issues that can arise with multiple subdivision layers, the map automatically searches deeper in the database data when no map match is found at a given level of the map hierarchy beneath the Country level. this means you can skip over any levels of Subdivision detail in your map that are irrelevant to you. periodt. π
for example, this targets the New Zealand regional council subdivision of Otago without explicitly specifying the enclosing subdivision for the South Island:
{ OC => { NZ => { OTA => [...] } } }
as another example, this works correctly for targeting the city of Paris without caring about what layers of subdivisions lie between it and FR:
{ EU => { FR => { Paris => [...] } } }
πβ¨ 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. no cap. 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. this requires a City-level GeoIP2 database; the Country ones don't contain coordinate information. π€
auto_dc_coords = { ... }β key-value hash, optional. if this option is specified, the whole map's basic mode of operation changes tocity-auto-mode. the contents of the hash are a key for each datacenter named indatacenters, 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 GeoIP2 database(s) are required be City-level databases, and the special keywordautobecomes a legaldatacenter listin themapstanza. π
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, default3. when city-auto-mode is in effect, this is the upper length limit for auto-generated lists.3is 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's 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 (like 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 π
okay bestie, so the resource-level stuff inside the resources stanza? it's almost a carbon copy of how the metafo plugin does its resources. same basic behavior around synthesizing config for other plugins, or directly referencing other plugins' config, per-datacenter. all of that carries over. π«Ά
one difference though, and it's the important one:
- metafo's per-resource
datacentersarray is replaced here bymap => mapname, which points at one of the maps you defined in themapsstanza (yes, the one we went over in detail earlier π). - the set of datacenters defined in the
dcmapstanza must match the total set of datacenters defined by the referenced map β unlessundefined_datacenters_okis set totrue(peep the warnings and docs above for that one).
and there's also the skip_first flag, which you can set per resource. ngl it's way more useful with geoip than it is with the basic metafo plugin. here's the tea: if you set it, the first datacenter in the failover list for a given lookup gets skipped entirely. why would you want that? so you can define a "second choice" resource that reuses the same basic map definition as the first choice β¨. and in that case the original first choice is never a possible answer β like, never never. the rest of the logic (skipping datacenters marked as down, etc.) just proceeds as normal with whatever's left in the list.
lowkey important: if the map entry and/or the resource definition have already reduced the effective datacenter count down to one, this flag has no effect. it just vibes there.
π META-PLUGIN INTERACTION π
so both of the meta-plugins β metafo and geoip β can reference their own resources and each other's resources by direct reference inside a dcmap. the one rule: a resource can't directly refer to itself. that's it, that's the boundary. π
this unlocks plugin-layering configurations like:
geoip -> metafo -> weightedmetafo -> geoip -> multifo- or even
metafo -> metafo -> simplefo, etc.
it's giving stacked plugins, and honestly? iconic.
π¨ WARNING, fr fr π¨ β once you start using inter-meta-plugin references, you can absolutely create a reference loop. gdnsd does not currently detect or prevent such loops, and when they get queried they'll cause complete runtime failure β probably by running out of stack space during recursion. so likeβ¦ be careful, bestie. π
also, one-way street alert: geoip can synthesize configuration for metafo resources, but the reverse does not hold. metafo cannot synthesize configuration for geoip resources. periodt.
π¦ IPv4 Compatible Addresses π¦
okay so this plugin knows of six different relatively-trivial ways to map IPv4 addresses into IPv6 address space. here they are, in as much detail as actually matters to this plugin, with NNNN:NNNN standing in for the copied IPv4 address bytes:
::0000:NNNN:NNNN/96 # RFC 4291 - v4compat (deprecated)
::ffff:NNNN:NNNN/96 # RFC 4291 - v4mapped
::ffff:0000:NNNN:NNNN/96 # RFC 2765 - SIIT (obsoleted)
64:ff9b::NNNN:NNNN/96 # RFC 6052 - Well-Known Prefix
2001:0000:X:NNNN:NNNN/32 # RFC 4380 - Teredo (IPv4 bits are flipped)
2002:NNNN:NNNN::/16 # RFC 3056 - 6to4
(in the Teredo case above, "X" represents some variable non-zero bytes
that occupy the center 64 bits of the address).
btw, in the Teredo line up there, X is just some variable non-zero bytes chillin' in the center 64 bits of the address. π
okay so here's the whole vibe of how this works internally, and it matters:
all of this plugin's internal lookup databases are IPv6 databases, and any IPv4-like info is always stored in the v4compat space inside those databases. when a runtime lookup happens, all the other v4-like addresses (raw IPv4 addresses, v4mapped, SIIT, WKP, Teredo, and 6to4) get converted into the canonical v4compat IPv6 representation before querying the internal databases. the other representations (v4mapped, SIIT, WKP, Teredo, 6to4) are Undefined internally, and will never be referenced at lookup-time, thanks to that v4compat conversion we just talked about.
now for the rules:
- the
netsstanza is not allowed to specify entries in the five undefined v4-like IPv6 spaces (i.e. the ones other than v4compat). nope. specify those networks as normal IPv4 networks or v4compat networks instead. π« - legitimate IPv6
netsentries that happen to be a supernet of any v4-like spaces will not unduly affect v4-like lookups. so no worries there. - there is no functional difference between v4compat and native v4 forms in
nets. for example,192.0.2.0/24and::C000:0200/120are completely identical. same thing, different font π
and about the databases themselves:
- GeoIP databases that are natively IPv4-only get all of their data loaded into the v4compat space only.
- for normal IPv6 GeoIP databases, by default we load the v4compat space directly β which is where MaxMind stores IPv4 data in their IPv6 databases β but we ignore the v4mapped/SIIT/Teredo/6to4 spaces. (some of those are empty in MaxMind's databases, and some of them just alias the v4compat space anyway.)
β¨ ANOTHER CONFIG EXAMPLE β¨
okay here's a relatively-maximal example config, showing the maps and resources sections interacting like the besties they are:
service_types => {
xmpp_svc => { plugin => "tcp_connect", ... }
www_svc => { plugin => "http_status", ... }
}
plugins => {
geoip => {
maps => {
my_prod_map => {
geoip2_db => GeoIP2-City.mmdb,
datacenters => [us-01, de-01, sg-01],
map => {
# Hierarchy is Continent -> Country -> Region -> City
NA => {
US => {
Dallas => [sg-01],
}
}
SA => [us-01, sg-01, de-01],
EU => {
default => [de-01, us-01, sg-01],
CH => {
Geneve => {
Geneva => [sg-01],
}
}
}
AF => [de-01, us-01, sg-01],
AS => [sg-01, de-01, us-01],
OC => [sg-01, us-01, de-01],
}
nets => {
10.0.0.0/8 => [ de-01 ],
2001:DB8::/32 => [ us-01 ],
}
}
my_auto_map => {
geoip2_db => GeoIP2-City.mmdb,
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.net.
sg-01 => asia-cdn-provider.example.net.
de-01 => europe-cdn-provider.example.net.
}
}
}
}
}
and here are some example zonefile RRs in zone example.com:
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
π EXAMPLE OF METAFO->GEOIP CITY-AUTO-MODE w/ LAST RESORT CNAME π
this one's the chef's kiss combo β geoip picks the closest ones, and metafo catches the fall when everybody's down:
plugins => {
geoip => {
maps => {
auto_map => {
geoip2_db => GeoIP2-City.mmdb,
datacenters => [dc1, dc2, dc3, dc4],
auto_dc_coords => {
dc1 => [ 38.9, -77 ],
dc2 => [ 50.1, 8.7 ],
dc3 => [ 20.2, 88.9 ],
dc4 => [ 39.0, -20 ],
},
# only fail through the nearest 2 before giving up:
auto_dc_limit => 2,
}
},
resources => {
www_real => {
map => my_auto_map,
service_types => [ http, xmpp ],
dcmap => {
dc1 => 192.0.2.100,
dc2 => 192.0.2.101,
dc3 => 192.0.2.102,
dc4 => 192.0.2.103
}
}
}
},
metafo => {
resources => {
www => {
datacenters => [ real, backup ],
dcmap => {
real => %geoip!www_real,
backup => backup-host.example.net.
}
}
}
}
}
and in the example.com zonefile:
; This tries through the closest 2/4 datacenters to
; the client from the geoip map, and if both of
; those are down it returns a CNAME to backup-host.example.net.
; for a downtime message or something:
www DYNC metafo!www
π SEE ALSO π
and obviously, the gdnsd manual itself. go read it, bestie, it's right there π«Ά
π 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/>.
okay that's the whole page, we did it!! π this was the gdnsd 3.8.3 geoip plugin page, dated 2025-02-16, and honestly it ate. go set up some geographic failover, bestie, you've got this πβ¨πΈ
π¦ where this page comes from
- debian trixie: gdnsd 3.8.3-2 Β· GPL-3.0-or-later
- ubuntu questing: gdnsd 3.8.3-2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms