[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#784963: jessie-pu: preapproval for gdnsd/2.1.2-1~deb8u1



On Mon, May 11, 2015 at 11:16:34AM +0100, Adam D. Barratt wrote:
>> (I can attach a full debdiff if requested, essentially all upstream and
>> same to jessie->stretch diff; let me know)
> 
> Yes, please. (Specifically a full debdiff from Jessie to 2.1.2-1~deb8u1.)

OK. The binary interdiff is a no-op (with the exception of -dbg
hash filenames).

Attached is the source debdiff. Since a bunch of pod files were renamed
and unified diffs aren't very good at representing that, I'm also
attaching the git diff. Diffstat is:
 .gitignore                    |    1 
 NEWS                          |   19 +++++++++++++
 configure.ac                  |   14 +++++++++-
 debian/changelog              |   13 +++++++++
 debian/gbp.conf               |    4 +-
 docs/Makefile.am              |   58 +++++++++++++++++++++---------------------
 docs/gdnsd.zonefile.podin     |   10 +++----
 gdnsd/conf.c                  |    2 -
 gdnsd/dnsio_udp.c             |   24 +++++------------
 gdnsd/statio.c                |    4 +-
 plugins/extmon/extmon_comms.c |   26 ++++++++++--------
 plugins/trivial/multifo.c     |    2 -
 12 files changed, 107 insertions(+), 70 deletions(-)

Regards,
Faidon
diff -Nru gdnsd-2.1.0/configure gdnsd-2.1.2/configure
--- gdnsd-2.1.0/configure	2014-10-15 00:25:28.000000000 +0000
+++ gdnsd-2.1.2/configure	2015-05-06 15:37:19.000000000 +0000
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for gdnsd 2.1.0.
+# Generated by GNU Autoconf 2.69 for gdnsd 2.1.2.
 #
 # Report bugs to <blblack@gmail.com>.
 #
@@ -590,8 +590,8 @@
 # Identity of this package.
 PACKAGE_NAME='gdnsd'
 PACKAGE_TARNAME='gdnsd'
-PACKAGE_VERSION='2.1.0'
-PACKAGE_STRING='gdnsd 2.1.0'
+PACKAGE_VERSION='2.1.2'
+PACKAGE_STRING='gdnsd 2.1.2'
 PACKAGE_BUGREPORT='blblack@gmail.com'
 PACKAGE_URL=''
 
@@ -1361,7 +1361,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures gdnsd 2.1.0 to adapt to many kinds of systems.
+\`configure' configures gdnsd 2.1.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1431,7 +1431,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of gdnsd 2.1.0:";;
+     short | recursive ) echo "Configuration of gdnsd 2.1.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1557,7 +1557,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-gdnsd configure 2.1.0
+gdnsd configure 2.1.2
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2212,7 +2212,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by gdnsd $as_me 2.1.0, which was
+It was created by gdnsd $as_me 2.1.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3076,7 +3076,7 @@
 
 # Define the identity of the package.
  PACKAGE='gdnsd'
- VERSION='2.1.0'
+ VERSION='2.1.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3325,6 +3325,11 @@
 AM_BACKSLASH='\'
 
 
+## Autoconf-2.63-Compat
+# Future reference: both of the below could be addressed by bumping our
+# AC_PREREQ() to 2.64.  It's just a question of at what point in the future
+# the 2.63-using distros are old enough that it's reasonable to do so.
+#---
 # We're compatible to autoconf 2.63, which doesn't have PACKAGE_URL
 #   as a final arg to AC_INIT.  We can't define it ourselves here
 #   with the same name as this causes compiler warnings that matter
@@ -3332,6 +3337,11 @@
 
 $as_echo "#define PKG_URL \"https://github.com/gdnsd/gdnsd/\""; >>confdefs.h
 
+#---
+# This hack makes PKG_CHECK_VARS from m4/pkg.m4 work on autoconf 2.63
+# ( courtesy of sunnybear in https://github.com/gdnsd/gdnsd/issues/85 )
+
+## End Autoconf-2.63-Compat
 
 # TODO: when/if a new autoconf release has a C11 macro,
 #    prefer that and fall back to requiring C99.
@@ -16113,7 +16123,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by gdnsd $as_me 2.1.0, which was
+This file was extended by gdnsd $as_me 2.1.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -16179,7 +16189,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-gdnsd config.status 2.1.0
+gdnsd config.status 2.1.2
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -Nru gdnsd-2.1.0/configure.ac gdnsd-2.1.2/configure.ac
--- gdnsd-2.1.0/configure.ac	2014-10-15 00:21:30.000000000 +0000
+++ gdnsd-2.1.2/configure.ac	2015-05-06 15:27:16.000000000 +0000
@@ -1,16 +1,28 @@
 AC_PREREQ([2.63])
-AC_INIT([gdnsd],[2.1.0],[blblack@gmail.com],[gdnsd])
+AC_INIT([gdnsd],[2.1.2],[blblack@gmail.com],[gdnsd])
 AC_CONFIG_SRCDIR([gdnsd/main.c])
 AC_CONFIG_AUX_DIR([acaux])
 AM_INIT_AUTOMAKE([1.11.1 dist-xz no-dist-gzip foreign tar-ustar -Wall])
 AC_CONFIG_MACRO_DIR([m4])
 AM_SILENT_RULES([yes])
 
+## Autoconf-2.63-Compat
+# Future reference: both of the below could be addressed by bumping our
+# AC_PREREQ() to 2.64.  It's just a question of at what point in the future
+# the 2.63-using distros are old enough that it's reasonable to do so.
+#---
 # We're compatible to autoconf 2.63, which doesn't have PACKAGE_URL
 #   as a final arg to AC_INIT.  We can't define it ourselves here
 #   with the same name as this causes compiler warnings that matter
 #   during other parts of ./configure.  So, pick a new name for now.
 AC_DEFINE([PKG_URL],["https://github.com/gdnsd/gdnsd/"],[Package URL])
+#---
+# This hack makes PKG_CHECK_VARS from m4/pkg.m4 work on autoconf 2.63
+# ( courtesy of sunnybear in https://github.com/gdnsd/gdnsd/issues/85 )
+m4_ifndef([AS_VAR_COPY],
+[m4_define([AS_VAR_COPY],
+[AS_LITERAL_IF([$1[]$2], [$1=$$2], [eval $1=\$$2])])])
+## End Autoconf-2.63-Compat
 
 # TODO: when/if a new autoconf release has a C11 macro,
 #    prefer that and fall back to requiring C99.
diff -Nru gdnsd-2.1.0/debian/changelog gdnsd-2.1.2/debian/changelog
--- gdnsd-2.1.0/debian/changelog	2014-10-20 23:07:56.000000000 +0000
+++ gdnsd-2.1.2/debian/changelog	2015-05-11 13:21:21.000000000 +0000
@@ -1,3 +1,16 @@
+gdnsd (2.1.2-1~deb8u1) stable; urgency=medium
+
+  * Backport as a stable update.
+
+ -- Faidon Liambotis <paravoid@debian.org>  Mon, 11 May 2015 13:18:45 +0000
+
+gdnsd (2.1.2-1) unstable; urgency=high
+
+  * New upstream stable release.
+    - Fixes FTBFS with newer pod2man, like in current sid.
+
+ -- Faidon Liambotis <paravoid@debian.org>  Thu, 07 May 2015 00:40:19 +0300
+
 gdnsd (2.1.0-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru gdnsd-2.1.0/debian/gbp.conf gdnsd-2.1.2/debian/gbp.conf
--- gdnsd-2.1.0/debian/gbp.conf	2014-10-20 23:07:56.000000000 +0000
+++ gdnsd-2.1.2/debian/gbp.conf	2015-05-11 13:21:21.000000000 +0000
@@ -1,6 +1,6 @@
-[git-buildpackage]
+[buildpackage]
 upstream-tree=tag
-debian-branch=debian
+debian-branch=jessie
 upstream-tag = v%(version)s
 overlay = True
 no-create-orig = True
diff -Nru gdnsd-2.1.0/docs/gdnsd.config.pod gdnsd-2.1.2/docs/gdnsd.config.pod
--- gdnsd-2.1.0/docs/gdnsd.config.pod	2014-10-14 15:51:52.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.config.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,1033 +0,0 @@
-
-=head1 NAME
-
-gdnsd.config - gdnsd configuration file
-
-=head1 SYNOPSIS
-
-  options => {
-    log_stats => 86400
-    tcp_timeout => 15 ; zonefile-style comment
-    include_optional_ns => true
-    listen => [ 127.0.0.1, 192.0.2.1 ]
-  }
-
-  # shell-style comment
-
-  service_types => {
-    foosvc => { plugin => http_status, vhost => www.example.com, url_path => "/checkme" }
-    barsvc => $include{bar-svc.cfg}
-    $include{other-services.cfg}
-  }
-
-  plugins => {
-    null => {}
-  }
-
-=head1 DESCRIPTION
-
-This man page describes the syntax of the primary gdnsd
-configuration file.  The primary config file is always the
-the file named F<config> in the configuration directory.
-The default configuration directory is F<@GDNSD_DEFPATH_CONFIG@>,
-but this can be overridden by the C<-c> commandline option.
-
-The lower-level syntax and structure of the configuration
-language is described in detail at the end of this document,
-but it should be fairly intuitive from the example above.  It
-is effectively a generic data structure language allowing
-arbitrarily-nested ordered hashes, ordered arrays, and scalar
-values.  Double-quotes are used to quote scalars containing
-whitespace or various ambiguous metacharacters.
-
-The top-level implicit hash of a gdnsd configuration file allows
-only 3 legal keys: B<options>, B<service_types>, and B<plugins>.
-
-Any of them which are present must have a Hash as their value.
-
-All of them are optional, as is the configuration file itself.
-If you're happy with an all-default configuration, you can
-simply not have a config file at all.
-
-=head1 OPTIONS HASH
-
-These options control the overall behavior of L<gdnsd(8)>.
-
-=over 4
-
-=item B<username>
-
-String, defaults to "gdnsd".  This is the username the daemon drops
-privileges to the uid/gid of on startup if started as root.
-
-=item B<zones_default_ttl>
-
-Integer seconds, default 86400.  This is the global default
-time-to-live for any record in any zonefile.  It can be overridden with
-a more specific default within zone files themselves via the C<$TTL>
-directive (see L<gdnsd.zonefile(5)>).
-
-=item B<max_ttl>
-
-Integer seconds, default 3600000 (~42 days),
-range 3600 - 268435455 (2^28-1, ~8.5 years).
-This is the global maximum TTL.  Any TTL found in a zone which
-exceeds this value will be clamped to this value with a warning.
-Note that the default maximum value is what the Internet's root
-nameservers currently use for A-record TTLs, and those are arguably
-the most stable records in the whole system.  It's hard to imagine
-good reasons to raise this value in practice.
-
-=item B<min_ttl>
-
-Integer seconds, default 5, range 1 - 86400 (1 day).
-This is the global minimum TTL.  Any TTL found in a zone which
-is below this value will be clamped to this value with a warning,
-including the minimum TTLs of DYN[AC] records and SOA ncache TTLs.
-This value must be less than or equal to max_ttl.
-
-=item B<max_ncache_ttl>
-
-Integer seconds, default 10800, range 10 - 86400.
-This is the global maximum for the SOA negative-cache TTL field.
-Values above this will be clamped with a warning.  This value
-must be greater than or equal to min_ttl.
-
-=item B<dns_port>
-
-Integer port, 1-65535, default 53.  This is the global default port
-number for DNS listener addresses which do not specify port numbers
-themselves.
-
-=item B<http_port>
-
-Integer port, 1-65535, default 3506.  This is the default HTTP port
-number for stats listener addresses which do not specify port numbers
-themselves.
-
-=item B<listen>
-
-The listen option specifies the socket addresses the server listens on
-for DNS requests.
-
-A listen-address specification is an IP (v4 or v6) address specified as
-a numeric string with standard formatting (anything numeric that
-C<getaddrinfo()> supports on your platform), optionally followed by a
-colon and a port number.  If no port number is specified, it defaults
-to the value from C<dns_port>, which defaults to C<53>.
-
-Due to various parsing ambiguities, if you wish to specify a
-non-default port number for an IPv6 listen address, you will have to
-enclose the address part in square brackets, and then enclose the
-entire string in double-quotes.
-
-The structure of the listen option as a whole can take one of three
-basic forms.  In its simplest form, it is just a single listen-address
-specification as a string, such as:
-
-  options => { listen = 192.0.2.1 }
-
-It can also take the form of an array of such addresses, as in:
-
-  options => {
-    listen = [
-      192.0.2.1,
-      192.0.2.2,
-      2001:DB8::1,
-      "[2001:DB8::1234]:5353",
-    ]
-  }
-
-Finally, it can also be a hash where the keys are listen addresses, and
-the values are per-address options, as in:
-
-  options => {
-    listen => {
-      192.0.2.1 => {
-        tcp_timeout = 7
-      },
-      192.0.2.2:5353 => {
-        udp_threads = 5
-      },
-    }
-  }
-
-The per-address options (which are identical to, and locally override,
-the global option of the same name) are C<tcp_threads>,
-C<tcp_timeout>, C<tcp_clients_per_thread>, C<udp_threads>, C<udp_recv_width>,
-C<udp_rcvbuf>, and C<udp_sndbuf>.
-
-There are also two special singular string values: C<any> and C<scan>.
-
-If set to C<any>, the daemon will listen on the C<dns_port> port (default 53)
-on C<0.0.0.0> and C<::>.  This is the default if no C<listen> option is provided.
-
-  options => { listen => any }
-
-If set to C<scan>, scan all available IP (v4 and v6) network interfaces
-via C<getifaddrs()> and set up a separate listener on the C<dns_port>
-port (again, default 53) for each address found.
-
-  options => { listen => scan }
-
-=item B<http_listen>
-
-Basically like B<listen> above, but used for the HTTP listener (serving
-stats information), and defaulting to port 3506.  The hash form isn't
-supported as there are no per-address options, and the any/all options
-don't exist here.  The default is to listen on the IPv4 and IPv6
-any-addresses (C<0.0.0.0> and C<::>).
-
-It makes common sense to restrict access to this service via firewall
-rules, as the data served leaks information about the rate and nature
-of your DNS traffic.  This is mostly intended for your own internal
-monitoring purposes.
-
-=item B<tcp_threads>
-
-Integer, default 1, min 0, max 1024.  This is the number of separate
-TCP listening sockets and corresponding listener threads that will be created
-for each DNS listener address.  On a multi-core host, increasing this
-parameter (up to at most a small multiple of the CPU core count) may
-increase overall performance.  Note that on hosts without SO_REUSEPORT
-support (notably Linux < 3.9, Solaris), any setting greater than 1 will
-be forced to 1 with a warning, as support multiple sockets/threads
-per-address are not supported without SO_REUSEPORT.
-
-=item B<udp_threads>
-
-Exactly like C<tcp_threads>, but for UDP sockets per DNS listening address.
-
-=item B<tcp_clients_per_thread>
-
-Integer, default 128, min 1, max 65535.  This is maximum number of tcp
-DNS connections gdnsd will allow to occur in parallel per listening tcp
-thread.  Once this limit is reached by a given thread, no new
-connections will be allowed to that thread until one of the existing
-ones closes or times out.  Note that sockets map 1:m to threads, and thus
-the total client limit for connecting to a given socket address would be
-C<tcp_clients_per_thread * tcp_threads>.
-
-=item B<tcp_timeout>
-
-Integer seconds, default 5, min 3, max 60.  TCP DNS connections will be
-forcibly shut down if they go idle without receiving and responding to
-a valid query for this many seconds.  L<gdnsd(8)> allows multiple
-requests per connection, and this idle timeout applies to the time
-between requests as well.
-
-=item B<udp_recv_width>
-
-Integer, default 8, min 1, max 64.  On supported Linux kernels this
-setting tunes the use of more efficient interfaces to receive and send
-multiple packets with a single syscall.  Higher values reduce syscall
-overhead and generally give the server higher throughput and better
-efficiency under high loads.
-
-I believe that this is basically always a win under load when
-supported, but values much larger than necessary do have a chance to
-increase average response latency very slightly.  The optimal setting
-is highly dependent on local hardware, software configuration, and
-network load conditions.
-
-Setting this to a value of 1 will completely disable this code, as if
-we were running on a platform that didn't support it.  On platforms
-that don't support it, this option has no effect and is ignored.  On
-Linux if we don't detect a 3.0 or higher kernel at runtime, we fall
-back to the same code as other platforms that don't support it.
-
-=item B<udp_rcvbuf>
-
-Integer, min 4096, max 1048576.  If set, this value will be used to set
-the C<SO_RCVBUF> socket option on the UDP listening socket(s).  Most
-users do not need to tune this value.  If left unset, the code
-takes a somewhat heuristic approach, trying to raise the value only if
-the OS-supplied default seems too low, and multiplying it a bit in the
-case of C<udp_recv_width> > 1.
-
-=item B<udp_sndbuf>
-
-Integer, min 4096, max 1048576.  If set, this value will be used to set
-the C<SO_SNDBUF> socket option on the UDP listening socket(s).  Tuning
-advice mirrors the above.
-
-=item B<max_http_clients>
-
-Integer, default 128, min 1, max 65535.  Maximum number of HTTP
-connections to allow in parallel at any given time.  Once this number
-is reached, no more new connections will be answered until an existing
-connection closes or times out.
-
-=item B<http_timeout>
-
-Integer seconds, default 5, min 3, max 60.  HTTP connections will be
-forcibly shut down if they go idle for more than this many seconds.
-
-=item B<zones_strict_data>
-
-Boolean, default C<false>
-
-If false (the default), reporting of many less-serious errors in zone
-data are emitted as mere logged warnings, and the zone data is still
-loaded and served.
-
-If this is set to true, such warnings will be upgraded and treated
-the same as the more-serious class of zone data errors which prevent
-successful loading of zone data.  The consequences of this are variable:
-on initial startup or checkconf, this results in a failed zonefile, which
-may either be ignored or abort execution, depending on C<zones_strict_startup>
-below.  During a runtime zone data reload, any existing good copy of the zone
-would continue to be served until the error is corrected in the source.
-
-=item B<zones_strict_startup>
-
-Boolean, default C<true>
-
-If true (the default), on daemon startup (via C<start> or C<restart>)
-if any zone fails to load correctly, the daemon will
-abort.  If false, the daemon will simply ignore the failed zone and
-continue operations.
-
-Runtime reloads via SIGUSR1 and/or periodic/inotify scanning always
-treat bad zone data non-fatally (leaving any existing good copy intact
-in memory for lookups).
-
-This also affects the C<checkconf> action.  It will only fail in terms
-of exit value on bad zonefiles if this is true (although it will note
-any failures to stderr regardless).
-
-=item B<zones_rfc1035_auto>
-
-Boolean, default C<true>.
-
-If auto is enabled (the default), the daemon will detect changes to
-zone data automatically at runtime and apply them as they appear.  In
-the general case this is done via periodically scanning C<lstat()> data
-on the contents of the zones directory and looking for metadata changes
-since last check.
-
-On recent Linux systems, the daemon may also use C<inotify()> to detect
-filesystem modifications in realtime and not need to run the periodic
-full directory scan, making the average delay much smaller (subject to
-compile- and run- time compatibility).  You will need a runtime Linux
-kernel version of 2.6.36 or higher to enable this feature.
-
-Regardless of whether this setting is true or false, you can always
-manually trigger a rescan of the zones directory for new data by
-sending the daemon a C<SIGUSR1> (or executing the "reload-zones"
-command, which sends SIGUSR1 for you).
-
-=item B<zones_rfc1035_auto_interval>
-
-Integer seconds, default 31, min 10, max 600.  Only applies when
-C<zones_rfc1035_auto> is C<true>.
-
-Sets the time interval for periodically checking the zonefile directory
-for changes.  On systems which support C<inotify()>, however, the
-automatic mode will almost always use that mechanism instead for even
-faster detection with less overhead.  In the C<inotify()> case, the
-interval is used only occasionally when recovering from temporary
-C<inotify()> failures.
-
-=item B<zones_rfc1035_min_quiesce>
-
-Floating-point seconds, default 0.0, min 0.0, max 5.0
-
-This short-duration quiescence timeout applies to certain internal
-cases when validating zonefile update activity.  (Specifically: delays
-after C<inotify()> events for atomic move/delete and delayed initial
-zonefile loading on daemon startup).
-
-At daemon start, a heuristic test of the mtime resolution on the zones
-filesystem will determine whether we can use a faster 0.01s or the
-default 1.02s as a basic sane minimum, and this config setting will be
-adjusted upwards to the detected minimum as necessary.
-
-Most users should not need to mess with this setting! The only reason
-to do so would be if you suspected operating system or filesystem bugs
-related to high-res mtimes (or bugs so severe that even ~1-second mtime
-resolution isn't reliable, in which case you might want to try values
-in the 3-5s range, or just find a new FS and/or OS...).
-
-=item B<zones_rfc1035_quiesce>
-
-Floating-point seconds, default 5.0, min 0.0, max 60.0
-
-This timer is related to the above, but is used in cases where we're
-not only worried about filesystem-level timestamp accuracy, but also
-waiting for additional intentional actions by scripts, programs, or
-users which might be actively modifying a zonefile.  It applies to all
-changes detected via SIGUSR1 or periodic automatic scanning, and to
-C<inotify()> events which do not indicate atomic operations (e.g.
-create/write/close, rather than move/delete.  In other words,
-someone/something is actually overwriting the data in-place or using an
-editor on the file in-place).
-
-It is recommended that whatever tools or scripts you use to manage
-zonefile updates use atomic operations to replace them.  First write
-the new data to a dotfile, e.g. F<.example.com.tmp1234>, in the same
-zones directory (gdnsd ignores all filenames with a leading dot), and
-then C<mv(1)> / C<rename(2)> the file to its final destination filename
-F<example.com>.
-
-If the value specified is less than the final runtime value of
-C<zones_rfc1035_min_quiesce> above, it will be adjusted upwards to that
-minimum value for correct operation.
-
-=item B<lock_mem>
-
-Boolean, default false.  Causes the daemon to do
-C<mlockall(MCL_CURRENT|MCL_FUTURE)>, which effectively locks all daemon
-memory into RAM, unable to be swapped.  Possibly helpful in some
-production cases to ensure swap-in doesn't affect DNS latency.
-
-When started as root with lock_mem set to true, the daemon will remove
-any ulimits on locked memory before dropping privileges.  When started
-as a regular user it may not be able to do so, and those limits could
-cause the server to abort execution at any time if they are set too low.
-
-=item B<priority>
-
-Signed integer, range -20 to +20, lower values are higher priority.  If
-explicitly set, gdnsd will attempt C<setpriority()> to this value on
-startup.  If left unset and gdnsd is started as a normal user, no
-C<setpriority()> call will be made.  If left unset and gdnsd is started
-as root, it will default to calling C<setpriority()> with the value
-C<-11>.
-
-=item B<disable_text_autosplit>
-
-Boolean, default false.  On the wire, C<TXT> records are encoded as
-discrete chunks of up to 255 characters per chunk.  The relevant RFCs
-state that multiple chunks should be treated by clients as if they are
-concatenated.  That is to say, it should make no difference to a client
-whether the C<TXT> data is sent as two 16-byte chunks or one 32-byte
-chunk.
-
-Ordinarily, you may specify chunk(s) of a C<TXT> record in gdnsd
-zonefiles as a string of any size up to the legal length (just short of
-64K in practice), and gdnsd will auto-split the data into 255-byte
-chunks for transmission over the DNS protocol correctly.  If you choose
-to manually break up your TXT record into multiple strings in the
-zonefile, gdnsd also honors these boundaries and will not attempt to
-merge them into larger chunks where possible.
-
-If you set this option to true, the auto-splitting behavior is
-disabled, and any single character string specified in a zonefile as
-part of a C<TXT> record which is larger than 255 bytes will
-be considered a syntax error.
-
-=item B<include_optional_ns>
-
-Boolean, default false.  Causes the daemon to include the optional NS
-records in the Authority section of simple authoritative responses
-containing actual response data.  Leaving this option in its default
-state results in smaller response packets and faster response packet
-generation in many common cases.  This is similar in nature to (but not
-exactly like) BIND's "minimal-responses" option, except that we default
-to the minimal mode.
-
-Regardless of this setting, all *necessary* Authority-section records
-are always included, such as when they are necessary for delegation
-responses, NXDOMAIN responses, and NOERROR responses containing no
-RRsets in the answer section.
-
-=item B<plugin_search_path>
-
-A single string or an array of strings, default empty.  Normally the
-daemon searches for plugins in the fixed path C<@GDNSD_DEFPATH_LIB@>,
-using filenames of the form C<plugin_${name}.so>.  If you define this
-parameter, all paths in this list will be searched in the given order
-for plugins *before* trying the default, fixed search path.
-
-=item B<realtime_stats>
-
-Boolean, default false.  Normally the daemon self-imposes a limit of
-not recalculating the daemon-wide statistics more often than once per
-second.  This improves efficiency in the case that the polling traffic
-on our HTTP interface gets high.
-
-For most uses the default should be fine.  If you set this option to
-true, the stats will be recalculated on the spot for every stats
-request.  The test suite uses this so that it can double-check
-statistics counters between every request it sends.  I don't imagine
-anyone else will need to use this option, and it could even be
-determinental to performance on SMP machines.
-
-=item B<max_response>
-
-Integer, default 16384, min 4096, max 64000.  This number is used to
-size the per-I/O-thread buffers that we construct response packets in.
-For any sane, normal use of the DNS, the default value is far more than
-enough.  For embedded or other low memory hosts, you might even
-consider setting this smaller than default to save a bunch of
-per-socket-context buffer space.
-
-However, if you have strange DNS data that's very large (giant RRsets,
-giant blobs of data in TXT records) which might generate response
-packets greater than the 16K default max here, you *must* set this
-parameter large enough to accommodate them or random very bad things
-will happen.  It should be noted that the odds are high whatever you're
-trying to do is misguided in the first place.  You can size this by
-setting it to the max and running some test queries via "dig" (or a
-similar tool) to find your limit.
-
-This number does not need to take into account UDP, IP, or any
-lower-level headers.  Typically when probing your data for the largest
-response sizes you should do C<ANY> queries and/or specific RR-type
-queries against the first CNAME in any CNAME chains leading to large
-RR-sets.  Keep in mind that the C<include_optional_ns> option will
-affect the sizing as well.  Also keep in mind that wildcards and
-delegations can match any child name, including ones of maximal overall
-length.
-
-=item B<max_edns_response>
-
-Integer, default 1410, min 512, max 64000.  This is the maximum size
-of a UDP edns response to a client, acting as a cap on the edns
-buffer size advertised by the client in its request.
-
-The default of 1410 is the largest size suggested in RFC 6891 when
-falling back from the inability to deliver 4K-sized packets, and it
-seems very likely to be a successful size for unfragmented delivery
-on most networks today even given IPv6 and some reasonable tunneling.
-
-The option obviously has no pragmatic effect if you do not have
-large response datasets in your zones in the first place.
-
-This value will be capped at the configured (or default) value of
-C<max_response> with a warning if configured above that value.
-
-=item B<max_addtl_rrsets>
-
-Integer, default 64, min 16, max 256.  This is the maximum number of RR
-sets that will ever be added to the Additional section of a response
-packet.  This sets a hard limit on the number of delegation glue NS
-records a subzone can have (which is checked at startup), and a runtime
-soft limit on other Additional section RR sets.  When the limit is
-reached at runtime, the remaining potential additional RR sets are
-simply not added to the packet.  Most users won't need to raise this
-value, and users on low-memory/embedded hosts might want to lower it to
-save more memory.
-
-=item B<max_cname_depth>
-
-Integer, default 16, min 4, max 24.  How deep CNAME -> CNAME chains are
-allowed to recurse within local data in a single zonefile.  If a chain
-longer than this is detected between normal static CNAME entries in the
-authoritative data of a single zonefile, an error will be thrown when
-loading the zonefile.
-
-If the limit is exceeded at runtime (due to C<DYNC> dynamic CNAME
-responses) the code will halt further recursive lookups for this
-request and return an empty B<NXDOMAIN> response, and log a loud
-message to syslog on every single request for this broken domainname.
-
-Note that this is the only thing preventing infinite CNAME loops caused
-by bad DYNC plugin configurations.  Also note that even in the C<DYNC>
-case, all of this applies only within a single zone.  The gdnsd code
-never crosses the boundary between two distinct local zonefiles when
-processing queries.
-
-=item B<edns_client_subnet>
-
-Boolean, default true.  Enables support for the edns-client-subnet
-option.  gdnsd only includes this EDNS option in responses to queries
-which also contained the option.  In the case of normal responses from
-static zone data, the scope mask will be set to zero.  Dynamic response
-plugins have access to the query's EDNS client-subnet data, and have
-full control over the response scope mask.
-
-If the option is set to false, gdnsd will ignore the option in queries,
-never set it in its responses, and plugins will not have access to any
-data provided by any ignored edns-client-subnet option in queries.
-
-Of the included standard plugins only C<reflect> and C<geoip> make use
-of edns-client-subnet information.  The rest will leave the scope mask
-at zero as normal for client-location-agnostic static data.
-
-Relevant links documenting edns-client-subnet:
-
-L<http://www.afasterinternet.com/>
-L<http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-00>
-
-=item B<chaos_response>
-
-String, default "gdnsd".  When gdnsd receives any query with the class
-C<CH> ("Chaos"), as opposed to the normal C<IN> ("Internet"), it will
-return a single response record of class C<CH> and type C<TXT>, which
-contains the string defined here.  This is something like BIND's
-version reporting, which responds to "version.bind" queries in the
-C<CH> class, and is what a client will see if they use such a query
-against a gdnsd server.
-
-=item B<log_stats>
-
-Integer, default 3600, min 0, max 86400.  The current stats counters
-will be emitted as log output (e.g. to syslog) every C<log_stats>
-seconds.  If set to zero, periodic stats logging is disabled.
-Regardless of this setting, stats counters are always emitted to the log
-once at the time of daemon shutdown.
-
-=item B<run_dir>
-
-String, defaults to F<@GDNSD_DEFPATH_RUN@>.  This is the directory
-which the daemon owns as its run directory.  It will create this
-directory and/or modify the permissions and ownership of it
-on startup.  If it does not exist and cannot be created, or the
-permissions and ownership cannot be set to acceptable values, the
-daemon will not start.
-
-The contents of this directory are private to the daemon and
-shouldn't be interfered with.  This can live on a filesystem that's
-volatile across reboots, and doesn't require much disk space.
-
-=item B<state_dir>
-
-String, defaults to F<@GDNSD_DEFPATH_STATE@>.  This is the directory
-which the daemon owns as its state directory.  It will create this
-directory and/or modify the permissions and ownership of it
-on startup.  If it does not exist and cannot be created, or the
-permissions and ownership cannot be set to acceptable values, the
-daemon will not start.
-
-The contents of this directory belong to the system administrator
-and are used to communicate persistent, stateful information to
-the daemon.  This should live on a filesystem which is preserved
-across reboots.
-
-=back
-
-=head1 SERVICE_TYPES
-
-service_types is used in conjunction with certain gdnsd plugins.  If
-you are not using such a plugin, you can safely ignore this section and
-omit it from your configuration.
-
-The service_types hash contains generic definitions for how to monitor
-a given types of service, independently of any specific address or
-hostname for that service.
-
-There are two trivial service_types internally defined as the names
-C<up> and C<down>, which do no actual monitoring and simply set the
-monitored state permanently C<UP> or C<DOWN>.  C<up> is the default
-service_type when no service_type is specified.
-
-Within the definition of a service_type there are several generic
-parameters related to timing and anti-flap, as well as plugin-specific
-parameters that vary per plugin.
-
-A service type does not, however, specify a name or address for a
-specific instance of a service.  Those would occur on a per-address
-basis in a resolving plugin's configuration down in the C<plugins>
-stanza, and the plugin's configuration would then reference a named
-service type to be used when monitoring said address.
-
-A service monitored through these mechanisms is always in either the
-C<UP> or C<DOWN> state at runtime from a monitoring perspective.  The
-C<UP> state is maintained in the face of intermittent or isolated failures
-until the anti-flap thresholds are crossed and the state moves to
-C<DOWN>.
-
-Any services monitored for plugins also have their state reported
-alongside the standard gdnsd statistics report, served by the built-in
-HTTP server (default port is 3506).
-
-The following are the generic parameters for all service_types:
-
-=over 4
-
-=item B<up_thresh>
-
-Integer, default 20, min 1, max 65535.  Number of monitoring requests
-which must succeed in a row without any failures to transition
-a given resource from the C<DOWN> state to the C<UP> state.
-
-=item B<ok_thresh>
-
-Integer, default 10, min 1, max 65535.  See below.
-
-=item B<down_thresh>
-
-Integer, default 10, min 1, max 65535.  The C<ok_thresh> and C<down_thresh>
-parameters control the transition from the C<UP> state to the C<DOWN>
-state while trying to prevent flappy behavior.  Their behavior is best
-described in terms of an internal failure counter for a resource
-which is currently in the C<UP> state.  The failure counter starts
-at zero on state transition into the C<UP> state.
-
-Every state poll that results in a failed response, even if other
-successful responses are interleaved between them, increments the
-failure counter.  If the failure counter reaches C<down_thresh>
-the resource is transitioned to the C<DOWN> state.  However, if
-C<ok_thresh> successes occur in a row with no failures between them,
-the failure counter is reset back to zero.
-
-So with the default values, the expected behavior is that if an C<UP>
-resource experiences 10 (possibly isolated or intermittent)
-monitor-polling failures over B<any> length of time, without a
-string of 10 successes in a row somewhere within the sequence to
-reset the counter, it will transition to the C<DOWN> state.
-Once C<DOWN>, it will require 20 successes in a row before
-transitioning back to the C<UP> state.
-
-=item B<interval>
-
-Integer seconds, default 10, min 1, max 255.  Number of seconds between
-successive monitoring requests for a given resource.
-
-=item B<timeout>
-
-Integer seconds, default interval/2, min 1, max 255.  Maximum time the
-monitoring code will wait for a successful response before giving up
-and considering the request to be a failure.  Defaults to half of the
-C<interval>, and must be less than C<interval>.
-
-=item B<plugin>
-
-String, required.  This indicates which specific plugin to use to execute
-the monitoring requests.  Any parameters other than the generic ones listed
-here are consumed by the plugin.
-
-=back
-
-There are six monitoring plugins included with gdnsd that can be used
-in a service_types definition, each of which may have additional,
-plugin-specific configuration options in addition to the generic ones
-above.  Each of these is documented in detail in its own manpage
-e.g. C<gdnsd-plugin-FOO>:
-
-=over 4
-
-=item B<tcp_connect>
-
-Checks TCP basic connectivity on a given port.  Only supports
-address resources, not CNAMEs.
-
-=item B<http_status>
-
-Checks HTTP connectivity, with options for the port, URL, and vhost
-to use in the request, and the acceptable HTTP status codes in
-the response.  Only supports address resources, not CNAMEs.
-
-=item B<extmon>
-
-Periodically executes a custom external commandline program
-to poll for the status of a resource.  Supports both address
-and CNAME resources.
-
-=item B<extfile>
-
-Reads the contents of a file on disk to import state monitoring data
-from another source.  Supports both address and CNAME resources.
-
-=item B<static>
-
-Configures a static monitoring result, mostly for testing / example code.
-Supports both address and CNAME resources.
-
-=item B<null>
-
-Configures an always-down static result, mostly for testing / example code.
-Supports both address and CNAME resources.
-
-=back
-
-=head1 PLUGINS
-
-The plugins hash is optional, and contains one key for every dynamic
-resolution plugin you wish to load and use.  The value must be a hash,
-and the contents of that hash are supplied to the plugin to use in
-configuring itself.  If the plugin requires no configuration, the empty
-hash C<{}> will suffice.  It is up to the plugin to determine whether
-the supplied hash of configuration data is legal or not.
-
-Monitoring-only plugins can also be given plugin-global level
-configuration here if the plugin author deemed it necessary.
-
-gdnsd ships with eight different monitoring plugins,
-all of which have their own separate manpage documentation (e.g. C<man
-gdnsd-plugin-FOO>):
-
-=over 4
-
-=item B<reflect>
-
-Reflects DNS client source IP and/or edns-client-subnet information
-back to the requestor as address data for debugging.
-
-=item B<simplefo>
-
-Simple primary->secondary failover of monitored addresses
-
-=item B<multifo>
-
-All-active failover of monitored round-robin address groups
-
-=item B<weighted>
-
-Weighted-round-robin responses with a variety of behavioral flavors,
-for both monitored addresses and CNAMEs.
-
-=item B<metafo>
-
-Static-ordered address(-group) meta-failover between 'datacenters',
-which are resources defined in terms of other plugins.  Supports
-both address and CNAME data.
-
-=item B<geoip>
-
-Combines metafo's functionality with MaxMind GeoIP databases to select
-different datacenter address(-group) preference/failover orderings for
-different clients based on approximate geographic location.  Supports
-both address and CNAME data.
-
-=item B<null>
-
-Returns all-zeros addresses or the CNAME C<invalid.> - mostly for
-testing and as simple example code.
-
-=item B<static>
-
-Configures static mappings of resources names to IP addresses or
-CNAMEs - mostly for testing and as simple example code.
-
-=back
-
-A configuration example showing the trivial plugins, as well as
-demonstrating the service_types described earlier:
-
-  service_types => {
-    corpwww_type => {
-      plugin => http_status
-      vhost => www.corp.example.com
-      url_path => /check_me
-      down_thresh => 5
-      interval => 5
-    }
-  }
-
-  plugins => {
-    null => {},
-    reflect => {},
-    static => {
-      foo = 192.0.2.2
-      bar = 192.0.2.123
-      somehost = somehost.example.net.
-    },
-    multifo => {
-      web-lb =>
-        service_types => [ corpwww_type, xmpp ],
-        lb01 => 192.0.2.200,
-        lb02 => 192.0.2.201,
-        lb03 => 192.0.2.202,
-      }
-    }
-  }
-
-And then in your example.com zonefile, you could have (among your other
-RRs):
-
-  zeros 600 DYNA null
-  reflect 10 DYNA reflect
-  reflect-both 10 DYNA reflect!both
-  pointless 42 DYNA static!foo
-  acname 400 DYNC static!somehost
-  www 300/45 DYNA multifo!web-lb
-
-=head1 LOW-LEVEL SYNTAX
-
-At the lowest level, the syntax of gdnsd config files roughly resembles
-an anonymous Perl data structure (using reference syntax).  There are
-three basic data types for values: ordered hashes (associative arrays
-mapping keys to values), ordered arrays of values, and simple strings.
-Hashes and arrays can be nested to arbitrary depth.  Generally
-speaking, whitespace is optional.  Single-line comments in both shell
-(C<#>) and DNS zonefile styles (C<;>) are allowed.  They run to the end
-of the current line and are considered to be whitespace by the parser.
-
-A hash is surrounded by curly braces (C<{> and C<}>).  Keys are
-separated from their values by either C<=E<gt>> or C<=> (at your
-stylistic discretion).  Hash keys follow the same rules as simple
-string values.  Hash values can be simple strings, arrays, or hashes.
-Key/value pairs can optionally have a trailing comma for stylistic
-clarity and separation.
-
-An array is surrounded by square braces (C<[> and C<]>).  Values can be
-simple strings, arrays, or hashes.  Values can optionally have a
-trailing comma for style.
-
-Strings (and thus keys) can be written in both quoted and unquoted
-forms.  In the quoted form, the string is surrounded by double-quotes
-(C<">), and can contain any literal byte value (even binary/utf-8
-stuff, or NUL) other than C<"> or C<\>.  Those two characters must be
-escaped by C<\>, i.e.  C<\"> and C<\\>.
-
-In the unquoted form, there are no surrounding quotes, and the allowed
-set of unescaped characters is further restricted.  The following are
-not allowed: C<][}{;#,"=\> (that is, square brackets, curly brackets,
-semicolons, octothorpes, commas, double quotes, equal signs, and
-backslashes).  Additionally, the first character cannot be a C<$>
-(dollar sign).
-
-Both forms use the same escaping rules, which are the same RFC-standard
-escaping rules used in zone files.  The escapes always start with C<\>.
-C<\> followed by any single byte other than a digit (C<0> - C<9>) is
-interepreted as that byte.  C<\> followed by exactly 3 digits
-interprets those digits as the unsigned decimal integer value of the
-desired byte (the 3 digit value cannot exceed C<255>).
-
-To illustrate the escaping and quoting, the following sets of example
-strings show different encodings of the same parsed value:
-
-  example
-  "example"
-  ex\097mpl\e
-  "ex\097mpl\e"
-
-  internal\"doublequote
-  "internal\"doublequote"
-
-  white\ space
-  "white space"
-
-  "braces{every[where]oh}my"
-  braces\{every\[where\]oh\}my
-
-  "\\==="
-  "\092==="
-  "\092\=\=\="
-  \\\=\=\=
-  \092\=\=\=
-
-The top level of the config file is an implicit hash with no bracing
-by default, but can also be an array bounded by square brackets.  This
-is not legal for the primary gdnsd configuration file, but could be
-useful in includefiles (see below).
-
-As a general rule, anywhere the higher-level syntax allows an array of
-values, you can substitute a single value.  The code will treat it as
-if it were an array of length 1.
-
-When we refer in other sections above to a value as being an "Integer"
-(or other specific scalar type), we're referring to constraints on the
-content of the character string value.  All scalar values are character
-strings.  "Boolean" values are characters strings which have the value
-"true" or "false", in any mix of upper or lower case.
-
-The following 3 example configuration files are identical in their
-parsed meanings, and should clarify anything miscommunicated above:
-
-Example 1 (simple and clean):
-
-  options = {
-    listen = [ 192.0.2.1, 192.0.2.2 ],
-    http_listen = 127.0.0.1,
-  }
-
-Example 2 (fat arrows, no commas, some arbitrary quoting):
-
-  "options" => {
-    listen => [ 192.0.2.1 192.0.2.2 ]
-    http_listen => "127.0.0.1"
-  }
-
-Example 3 (compressed and ugly):
-
-  options={listen=[192.0.2.1 192.0.2.2]http_listen=127.0.0.1}
-
-=head1 INCLUDING OTHER FILES
-
-vscf now has a mechanism for config includefiles.  The syntax is
-
-  $include{filename}
-
-where C<filename> can use the same kinds of escaping and/or
-double-quoting as normal scalar string data.  Whitespace between
-the filename and the surrounding brackets is optional.  Whitespace
-between C<$include> and the following C<{> is not allowed.  If the filename
-is relative (does not begin with F</>), it is interpreted as
-relative to the directory containing the parent file.  Include files
-can nest other include files to arbitrary depth.
-
-Keep in mind that at the top level of any given vscf file (even
-include files), the file must syntactically be either an implicit
-hash or an explicit, square-bracket-bounded, array.
-
-The include statement can be used in two distinct contexts within
-the syntax structure of a config file:
-
-=over 4
-
-=item B<Value Context>
-
-The include statement can replace any whole value (that is, the right
-hand side of a hash map entry or a member of an array) with its own
-contents, which are either a hash or an array.  Note that there is no
-mechanism for flattening an include-file's array into the parent array
-(the whole included array would be a single array item within the parent
-array).  Examples:
-
-  main config:
-    options => { listen => $include{foo} }
-  foo:
-    [ 127.0.0.1, 127.0.0.2 ]
-
-  main config:
-    plugins => $include{ "bar" }
-  bar:
-    geoip => { ... }
-    extmon => { ... }
-
-=item B<Hash-Merge Context>
-
-The include statement can also appear in a hash where a key would
-normally be expected.  In this case, the included file must be in hash
-(rather than array) form at the top level, and its contents are merged
-into the parent hash.  The merge is shallow, and conflicting keys are
-not allowed. Example:
-
-  main config:
-    options => { ... },
-    plugins => {
-        extmon => { ... },
-        metafo => { ... },
-        $include{geoip_cfg},
-        simplefo => { ... }
-    }
-  geoip_cfg:
-    geoip => { ... },
-    weighted => { ... }
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd(8)>, L<gdnsd.zonefile(5)>, L<gdnsd-plugin-simplefo(8)>,
-L<gdnsd-plugin-multifo(8)>, L<gdnsd-plugin-weighted(8)>,
-L<gdnsd-plugin-metafo(8)>, L<gdnsd-plugin-geoip(8)>,
-L<gdnsd-plugin-extmon(8)>, L<gdnsd-plugin-extfile(8)>
-L<gdnsd-plugin-api(3)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.config.podin gdnsd-2.1.2/docs/gdnsd.config.podin
--- gdnsd-2.1.0/docs/gdnsd.config.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.config.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,1033 @@
+
+=head1 NAME
+
+gdnsd.config - gdnsd configuration file
+
+=head1 SYNOPSIS
+
+  options => {
+    log_stats => 86400
+    tcp_timeout => 15 ; zonefile-style comment
+    include_optional_ns => true
+    listen => [ 127.0.0.1, 192.0.2.1 ]
+  }
+
+  # shell-style comment
+
+  service_types => {
+    foosvc => { plugin => http_status, vhost => www.example.com, url_path => "/checkme" }
+    barsvc => $include{bar-svc.cfg}
+    $include{other-services.cfg}
+  }
+
+  plugins => {
+    null => {}
+  }
+
+=head1 DESCRIPTION
+
+This man page describes the syntax of the primary gdnsd
+configuration file.  The primary config file is always the
+the file named F<config> in the configuration directory.
+The default configuration directory is F<@GDNSD_DEFPATH_CONFIG@>,
+but this can be overridden by the C<-c> commandline option.
+
+The lower-level syntax and structure of the configuration
+language is described in detail at the end of this document,
+but it should be fairly intuitive from the example above.  It
+is effectively a generic data structure language allowing
+arbitrarily-nested ordered hashes, ordered arrays, and scalar
+values.  Double-quotes are used to quote scalars containing
+whitespace or various ambiguous metacharacters.
+
+The top-level implicit hash of a gdnsd configuration file allows
+only 3 legal keys: B<options>, B<service_types>, and B<plugins>.
+
+Any of them which are present must have a Hash as their value.
+
+All of them are optional, as is the configuration file itself.
+If you're happy with an all-default configuration, you can
+simply not have a config file at all.
+
+=head1 OPTIONS HASH
+
+These options control the overall behavior of L<gdnsd(8)>.
+
+=over 4
+
+=item B<username>
+
+String, defaults to "gdnsd".  This is the username the daemon drops
+privileges to the uid/gid of on startup if started as root.
+
+=item B<zones_default_ttl>
+
+Integer seconds, default 86400.  This is the global default
+time-to-live for any record in any zonefile.  It can be overridden with
+a more specific default within zone files themselves via the C<$TTL>
+directive (see L<gdnsd.zonefile(5)>).
+
+=item B<max_ttl>
+
+Integer seconds, default 3600000 (~42 days),
+range 3600 - 268435455 (2^28-1, ~8.5 years).
+This is the global maximum TTL.  Any TTL found in a zone which
+exceeds this value will be clamped to this value with a warning.
+Note that the default maximum value is what the Internet's root
+nameservers currently use for A-record TTLs, and those are arguably
+the most stable records in the whole system.  It's hard to imagine
+good reasons to raise this value in practice.
+
+=item B<min_ttl>
+
+Integer seconds, default 5, range 1 - 86400 (1 day).
+This is the global minimum TTL.  Any TTL found in a zone which
+is below this value will be clamped to this value with a warning,
+including the minimum TTLs of DYN[AC] records and SOA ncache TTLs.
+This value must be less than or equal to max_ttl.
+
+=item B<max_ncache_ttl>
+
+Integer seconds, default 10800, range 10 - 86400.
+This is the global maximum for the SOA negative-cache TTL field.
+Values above this will be clamped with a warning.  This value
+must be greater than or equal to min_ttl.
+
+=item B<dns_port>
+
+Integer port, 1-65535, default 53.  This is the global default port
+number for DNS listener addresses which do not specify port numbers
+themselves.
+
+=item B<http_port>
+
+Integer port, 1-65535, default 3506.  This is the default HTTP port
+number for stats listener addresses which do not specify port numbers
+themselves.
+
+=item B<listen>
+
+The listen option specifies the socket addresses the server listens on
+for DNS requests.
+
+A listen-address specification is an IP (v4 or v6) address specified as
+a numeric string with standard formatting (anything numeric that
+C<getaddrinfo()> supports on your platform), optionally followed by a
+colon and a port number.  If no port number is specified, it defaults
+to the value from C<dns_port>, which defaults to C<53>.
+
+Due to various parsing ambiguities, if you wish to specify a
+non-default port number for an IPv6 listen address, you will have to
+enclose the address part in square brackets, and then enclose the
+entire string in double-quotes.
+
+The structure of the listen option as a whole can take one of three
+basic forms.  In its simplest form, it is just a single listen-address
+specification as a string, such as:
+
+  options => { listen = 192.0.2.1 }
+
+It can also take the form of an array of such addresses, as in:
+
+  options => {
+    listen = [
+      192.0.2.1,
+      192.0.2.2,
+      2001:DB8::1,
+      "[2001:DB8::1234]:5353",
+    ]
+  }
+
+Finally, it can also be a hash where the keys are listen addresses, and
+the values are per-address options, as in:
+
+  options => {
+    listen => {
+      192.0.2.1 => {
+        tcp_timeout = 7
+      },
+      192.0.2.2:5353 => {
+        udp_threads = 5
+      },
+    }
+  }
+
+The per-address options (which are identical to, and locally override,
+the global option of the same name) are C<tcp_threads>,
+C<tcp_timeout>, C<tcp_clients_per_thread>, C<udp_threads>, C<udp_recv_width>,
+C<udp_rcvbuf>, and C<udp_sndbuf>.
+
+There are also two special singular string values: C<any> and C<scan>.
+
+If set to C<any>, the daemon will listen on the C<dns_port> port (default 53)
+on C<0.0.0.0> and C<::>.  This is the default if no C<listen> option is provided.
+
+  options => { listen => any }
+
+If set to C<scan>, scan all available IP (v4 and v6) network interfaces
+via C<getifaddrs()> and set up a separate listener on the C<dns_port>
+port (again, default 53) for each address found.
+
+  options => { listen => scan }
+
+=item B<http_listen>
+
+Basically like B<listen> above, but used for the HTTP listener (serving
+stats information), and defaulting to port 3506.  The hash form isn't
+supported as there are no per-address options, and the any/all options
+don't exist here.  The default is to listen on the IPv4 and IPv6
+any-addresses (C<0.0.0.0> and C<::>).
+
+It makes common sense to restrict access to this service via firewall
+rules, as the data served leaks information about the rate and nature
+of your DNS traffic.  This is mostly intended for your own internal
+monitoring purposes.
+
+=item B<tcp_threads>
+
+Integer, default 1, min 0, max 1024.  This is the number of separate
+TCP listening sockets and corresponding listener threads that will be created
+for each DNS listener address.  On a multi-core host, increasing this
+parameter (up to at most a small multiple of the CPU core count) may
+increase overall performance.  Note that on hosts without SO_REUSEPORT
+support (notably Linux < 3.9, Solaris), any setting greater than 1 will
+be forced to 1 with a warning, as support multiple sockets/threads
+per-address are not supported without SO_REUSEPORT.
+
+=item B<udp_threads>
+
+Exactly like C<tcp_threads>, but for UDP sockets per DNS listening address.
+
+=item B<tcp_clients_per_thread>
+
+Integer, default 128, min 1, max 65535.  This is maximum number of tcp
+DNS connections gdnsd will allow to occur in parallel per listening tcp
+thread.  Once this limit is reached by a given thread, no new
+connections will be allowed to that thread until one of the existing
+ones closes or times out.  Note that sockets map 1:m to threads, and thus
+the total client limit for connecting to a given socket address would be
+C<tcp_clients_per_thread * tcp_threads>.
+
+=item B<tcp_timeout>
+
+Integer seconds, default 5, min 3, max 60.  TCP DNS connections will be
+forcibly shut down if they go idle without receiving and responding to
+a valid query for this many seconds.  L<gdnsd(8)> allows multiple
+requests per connection, and this idle timeout applies to the time
+between requests as well.
+
+=item B<udp_recv_width>
+
+Integer, default 8, min 1, max 64.  On supported Linux kernels this
+setting tunes the use of more efficient interfaces to receive and send
+multiple packets with a single syscall.  Higher values reduce syscall
+overhead and generally give the server higher throughput and better
+efficiency under high loads.
+
+I believe that this is basically always a win under load when
+supported, but values much larger than necessary do have a chance to
+increase average response latency very slightly.  The optimal setting
+is highly dependent on local hardware, software configuration, and
+network load conditions.
+
+Setting this to a value of 1 will completely disable this code, as if
+we were running on a platform that didn't support it.  On platforms
+that don't support it, this option has no effect and is ignored.  On
+Linux if we don't detect a 3.0 or higher kernel at runtime, we fall
+back to the same code as other platforms that don't support it.
+
+=item B<udp_rcvbuf>
+
+Integer, min 4096, max 1048576.  If set, this value will be used to set
+the C<SO_RCVBUF> socket option on the UDP listening socket(s).  Most
+users do not need to tune this value.  If left unset, the code
+takes a somewhat heuristic approach, trying to raise the value only if
+the OS-supplied default seems too low, and multiplying it a bit in the
+case of C<udp_recv_width> > 1.
+
+=item B<udp_sndbuf>
+
+Integer, min 4096, max 1048576.  If set, this value will be used to set
+the C<SO_SNDBUF> socket option on the UDP listening socket(s).  Tuning
+advice mirrors the above.
+
+=item B<max_http_clients>
+
+Integer, default 128, min 1, max 65535.  Maximum number of HTTP
+connections to allow in parallel at any given time.  Once this number
+is reached, no more new connections will be answered until an existing
+connection closes or times out.
+
+=item B<http_timeout>
+
+Integer seconds, default 5, min 3, max 60.  HTTP connections will be
+forcibly shut down if they go idle for more than this many seconds.
+
+=item B<zones_strict_data>
+
+Boolean, default C<false>
+
+If false (the default), reporting of many less-serious errors in zone
+data are emitted as mere logged warnings, and the zone data is still
+loaded and served.
+
+If this is set to true, such warnings will be upgraded and treated
+the same as the more-serious class of zone data errors which prevent
+successful loading of zone data.  The consequences of this are variable:
+on initial startup or checkconf, this results in a failed zonefile, which
+may either be ignored or abort execution, depending on C<zones_strict_startup>
+below.  During a runtime zone data reload, any existing good copy of the zone
+would continue to be served until the error is corrected in the source.
+
+=item B<zones_strict_startup>
+
+Boolean, default C<true>
+
+If true (the default), on daemon startup (via C<start> or C<restart>)
+if any zone fails to load correctly, the daemon will
+abort.  If false, the daemon will simply ignore the failed zone and
+continue operations.
+
+Runtime reloads via SIGUSR1 and/or periodic/inotify scanning always
+treat bad zone data non-fatally (leaving any existing good copy intact
+in memory for lookups).
+
+This also affects the C<checkconf> action.  It will only fail in terms
+of exit value on bad zonefiles if this is true (although it will note
+any failures to stderr regardless).
+
+=item B<zones_rfc1035_auto>
+
+Boolean, default C<true>.
+
+If auto is enabled (the default), the daemon will detect changes to
+zone data automatically at runtime and apply them as they appear.  In
+the general case this is done via periodically scanning C<lstat()> data
+on the contents of the zones directory and looking for metadata changes
+since last check.
+
+On recent Linux systems, the daemon may also use C<inotify()> to detect
+filesystem modifications in realtime and not need to run the periodic
+full directory scan, making the average delay much smaller (subject to
+compile- and run- time compatibility).  You will need a runtime Linux
+kernel version of 2.6.36 or higher to enable this feature.
+
+Regardless of whether this setting is true or false, you can always
+manually trigger a rescan of the zones directory for new data by
+sending the daemon a C<SIGUSR1> (or executing the "reload-zones"
+command, which sends SIGUSR1 for you).
+
+=item B<zones_rfc1035_auto_interval>
+
+Integer seconds, default 31, min 10, max 600.  Only applies when
+C<zones_rfc1035_auto> is C<true>.
+
+Sets the time interval for periodically checking the zonefile directory
+for changes.  On systems which support C<inotify()>, however, the
+automatic mode will almost always use that mechanism instead for even
+faster detection with less overhead.  In the C<inotify()> case, the
+interval is used only occasionally when recovering from temporary
+C<inotify()> failures.
+
+=item B<zones_rfc1035_min_quiesce>
+
+Floating-point seconds, default 0.0, min 0.0, max 5.0
+
+This short-duration quiescence timeout applies to certain internal
+cases when validating zonefile update activity.  (Specifically: delays
+after C<inotify()> events for atomic move/delete and delayed initial
+zonefile loading on daemon startup).
+
+At daemon start, a heuristic test of the mtime resolution on the zones
+filesystem will determine whether we can use a faster 0.01s or the
+default 1.02s as a basic sane minimum, and this config setting will be
+adjusted upwards to the detected minimum as necessary.
+
+Most users should not need to mess with this setting! The only reason
+to do so would be if you suspected operating system or filesystem bugs
+related to high-res mtimes (or bugs so severe that even ~1-second mtime
+resolution isn't reliable, in which case you might want to try values
+in the 3-5s range, or just find a new FS and/or OS...).
+
+=item B<zones_rfc1035_quiesce>
+
+Floating-point seconds, default 5.0, min 0.0, max 60.0
+
+This timer is related to the above, but is used in cases where we're
+not only worried about filesystem-level timestamp accuracy, but also
+waiting for additional intentional actions by scripts, programs, or
+users which might be actively modifying a zonefile.  It applies to all
+changes detected via SIGUSR1 or periodic automatic scanning, and to
+C<inotify()> events which do not indicate atomic operations (e.g.
+create/write/close, rather than move/delete.  In other words,
+someone/something is actually overwriting the data in-place or using an
+editor on the file in-place).
+
+It is recommended that whatever tools or scripts you use to manage
+zonefile updates use atomic operations to replace them.  First write
+the new data to a dotfile, e.g. F<.example.com.tmp1234>, in the same
+zones directory (gdnsd ignores all filenames with a leading dot), and
+then C<mv(1)> / C<rename(2)> the file to its final destination filename
+F<example.com>.
+
+If the value specified is less than the final runtime value of
+C<zones_rfc1035_min_quiesce> above, it will be adjusted upwards to that
+minimum value for correct operation.
+
+=item B<lock_mem>
+
+Boolean, default false.  Causes the daemon to do
+C<mlockall(MCL_CURRENT|MCL_FUTURE)>, which effectively locks all daemon
+memory into RAM, unable to be swapped.  Possibly helpful in some
+production cases to ensure swap-in doesn't affect DNS latency.
+
+When started as root with lock_mem set to true, the daemon will remove
+any ulimits on locked memory before dropping privileges.  When started
+as a regular user it may not be able to do so, and those limits could
+cause the server to abort execution at any time if they are set too low.
+
+=item B<priority>
+
+Signed integer, range -20 to +20, lower values are higher priority.  If
+explicitly set, gdnsd will attempt C<setpriority()> to this value on
+startup.  If left unset and gdnsd is started as a normal user, no
+C<setpriority()> call will be made.  If left unset and gdnsd is started
+as root, it will default to calling C<setpriority()> with the value
+C<-11>.
+
+=item B<disable_text_autosplit>
+
+Boolean, default false.  On the wire, C<TXT> records are encoded as
+discrete chunks of up to 255 characters per chunk.  The relevant RFCs
+state that multiple chunks should be treated by clients as if they are
+concatenated.  That is to say, it should make no difference to a client
+whether the C<TXT> data is sent as two 16-byte chunks or one 32-byte
+chunk.
+
+Ordinarily, you may specify chunk(s) of a C<TXT> record in gdnsd
+zonefiles as a string of any size up to the legal length (just short of
+64K in practice), and gdnsd will auto-split the data into 255-byte
+chunks for transmission over the DNS protocol correctly.  If you choose
+to manually break up your TXT record into multiple strings in the
+zonefile, gdnsd also honors these boundaries and will not attempt to
+merge them into larger chunks where possible.
+
+If you set this option to true, the auto-splitting behavior is
+disabled, and any single character string specified in a zonefile as
+part of a C<TXT> record which is larger than 255 bytes will
+be considered a syntax error.
+
+=item B<include_optional_ns>
+
+Boolean, default false.  Causes the daemon to include the optional NS
+records in the Authority section of simple authoritative responses
+containing actual response data.  Leaving this option in its default
+state results in smaller response packets and faster response packet
+generation in many common cases.  This is similar in nature to (but not
+exactly like) BIND's "minimal-responses" option, except that we default
+to the minimal mode.
+
+Regardless of this setting, all *necessary* Authority-section records
+are always included, such as when they are necessary for delegation
+responses, NXDOMAIN responses, and NOERROR responses containing no
+RRsets in the answer section.
+
+=item B<plugin_search_path>
+
+A single string or an array of strings, default empty.  Normally the
+daemon searches for plugins in the fixed path C<@GDNSD_DEFPATH_LIB@>,
+using filenames of the form C<plugin_${name}.so>.  If you define this
+parameter, all paths in this list will be searched in the given order
+for plugins *before* trying the default, fixed search path.
+
+=item B<realtime_stats>
+
+Boolean, default false.  Normally the daemon self-imposes a limit of
+not recalculating the daemon-wide statistics more often than once per
+second.  This improves efficiency in the case that the polling traffic
+on our HTTP interface gets high.
+
+For most uses the default should be fine.  If you set this option to
+true, the stats will be recalculated on the spot for every stats
+request.  The test suite uses this so that it can double-check
+statistics counters between every request it sends.  I don't imagine
+anyone else will need to use this option, and it could even be
+determinental to performance on SMP machines.
+
+=item B<max_response>
+
+Integer, default 16384, min 4096, max 64000.  This number is used to
+size the per-I/O-thread buffers that we construct response packets in.
+For any sane, normal use of the DNS, the default value is far more than
+enough.  For embedded or other low memory hosts, you might even
+consider setting this smaller than default to save a bunch of
+per-socket-context buffer space.
+
+However, if you have strange DNS data that's very large (giant RRsets,
+giant blobs of data in TXT records) which might generate response
+packets greater than the 16K default max here, you *must* set this
+parameter large enough to accommodate them or random very bad things
+will happen.  It should be noted that the odds are high whatever you're
+trying to do is misguided in the first place.  You can size this by
+setting it to the max and running some test queries via "dig" (or a
+similar tool) to find your limit.
+
+This number does not need to take into account UDP, IP, or any
+lower-level headers.  Typically when probing your data for the largest
+response sizes you should do C<ANY> queries and/or specific RR-type
+queries against the first CNAME in any CNAME chains leading to large
+RR-sets.  Keep in mind that the C<include_optional_ns> option will
+affect the sizing as well.  Also keep in mind that wildcards and
+delegations can match any child name, including ones of maximal overall
+length.
+
+=item B<max_edns_response>
+
+Integer, default 1410, min 512, max 64000.  This is the maximum size
+of a UDP edns response to a client, acting as a cap on the edns
+buffer size advertised by the client in its request.
+
+The default of 1410 is the largest size suggested in RFC 6891 when
+falling back from the inability to deliver 4K-sized packets, and it
+seems very likely to be a successful size for unfragmented delivery
+on most networks today even given IPv6 and some reasonable tunneling.
+
+The option obviously has no pragmatic effect if you do not have
+large response datasets in your zones in the first place.
+
+This value will be capped at the configured (or default) value of
+C<max_response> with a warning if configured above that value.
+
+=item B<max_addtl_rrsets>
+
+Integer, default 64, min 16, max 256.  This is the maximum number of RR
+sets that will ever be added to the Additional section of a response
+packet.  This sets a hard limit on the number of delegation glue NS
+records a subzone can have (which is checked at startup), and a runtime
+soft limit on other Additional section RR sets.  When the limit is
+reached at runtime, the remaining potential additional RR sets are
+simply not added to the packet.  Most users won't need to raise this
+value, and users on low-memory/embedded hosts might want to lower it to
+save more memory.
+
+=item B<max_cname_depth>
+
+Integer, default 16, min 4, max 24.  How deep CNAME -> CNAME chains are
+allowed to recurse within local data in a single zonefile.  If a chain
+longer than this is detected between normal static CNAME entries in the
+authoritative data of a single zonefile, an error will be thrown when
+loading the zonefile.
+
+If the limit is exceeded at runtime (due to C<DYNC> dynamic CNAME
+responses) the code will halt further recursive lookups for this
+request and return an empty B<NXDOMAIN> response, and log a loud
+message to syslog on every single request for this broken domainname.
+
+Note that this is the only thing preventing infinite CNAME loops caused
+by bad DYNC plugin configurations.  Also note that even in the C<DYNC>
+case, all of this applies only within a single zone.  The gdnsd code
+never crosses the boundary between two distinct local zonefiles when
+processing queries.
+
+=item B<edns_client_subnet>
+
+Boolean, default true.  Enables support for the edns-client-subnet
+option.  gdnsd only includes this EDNS option in responses to queries
+which also contained the option.  In the case of normal responses from
+static zone data, the scope mask will be set to zero.  Dynamic response
+plugins have access to the query's EDNS client-subnet data, and have
+full control over the response scope mask.
+
+If the option is set to false, gdnsd will ignore the option in queries,
+never set it in its responses, and plugins will not have access to any
+data provided by any ignored edns-client-subnet option in queries.
+
+Of the included standard plugins only C<reflect> and C<geoip> make use
+of edns-client-subnet information.  The rest will leave the scope mask
+at zero as normal for client-location-agnostic static data.
+
+Relevant links documenting edns-client-subnet:
+
+L<http://www.afasterinternet.com/>
+L<http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-00>
+
+=item B<chaos_response>
+
+String, default "gdnsd".  When gdnsd receives any query with the class
+C<CH> ("Chaos"), as opposed to the normal C<IN> ("Internet"), it will
+return a single response record of class C<CH> and type C<TXT>, which
+contains the string defined here.  This is something like BIND's
+version reporting, which responds to "version.bind" queries in the
+C<CH> class, and is what a client will see if they use such a query
+against a gdnsd server.
+
+=item B<log_stats>
+
+Integer, default 3600, min 0, max 86400.  The current stats counters
+will be emitted as log output (e.g. to syslog) every C<log_stats>
+seconds.  If set to zero, periodic stats logging is disabled.
+Regardless of this setting, stats counters are always emitted to the log
+once at the time of daemon shutdown.
+
+=item B<run_dir>
+
+String, defaults to F<@GDNSD_DEFPATH_RUN@>.  This is the directory
+which the daemon owns as its run directory.  It will create this
+directory and/or modify the permissions and ownership of it
+on startup.  If it does not exist and cannot be created, or the
+permissions and ownership cannot be set to acceptable values, the
+daemon will not start.
+
+The contents of this directory are private to the daemon and
+shouldn't be interfered with.  This can live on a filesystem that's
+volatile across reboots, and doesn't require much disk space.
+
+=item B<state_dir>
+
+String, defaults to F<@GDNSD_DEFPATH_STATE@>.  This is the directory
+which the daemon owns as its state directory.  It will create this
+directory and/or modify the permissions and ownership of it
+on startup.  If it does not exist and cannot be created, or the
+permissions and ownership cannot be set to acceptable values, the
+daemon will not start.
+
+The contents of this directory belong to the system administrator
+and are used to communicate persistent, stateful information to
+the daemon.  This should live on a filesystem which is preserved
+across reboots.
+
+=back
+
+=head1 SERVICE_TYPES
+
+service_types is used in conjunction with certain gdnsd plugins.  If
+you are not using such a plugin, you can safely ignore this section and
+omit it from your configuration.
+
+The service_types hash contains generic definitions for how to monitor
+a given types of service, independently of any specific address or
+hostname for that service.
+
+There are two trivial service_types internally defined as the names
+C<up> and C<down>, which do no actual monitoring and simply set the
+monitored state permanently C<UP> or C<DOWN>.  C<up> is the default
+service_type when no service_type is specified.
+
+Within the definition of a service_type there are several generic
+parameters related to timing and anti-flap, as well as plugin-specific
+parameters that vary per plugin.
+
+A service type does not, however, specify a name or address for a
+specific instance of a service.  Those would occur on a per-address
+basis in a resolving plugin's configuration down in the C<plugins>
+stanza, and the plugin's configuration would then reference a named
+service type to be used when monitoring said address.
+
+A service monitored through these mechanisms is always in either the
+C<UP> or C<DOWN> state at runtime from a monitoring perspective.  The
+C<UP> state is maintained in the face of intermittent or isolated failures
+until the anti-flap thresholds are crossed and the state moves to
+C<DOWN>.
+
+Any services monitored for plugins also have their state reported
+alongside the standard gdnsd statistics report, served by the built-in
+HTTP server (default port is 3506).
+
+The following are the generic parameters for all service_types:
+
+=over 4
+
+=item B<up_thresh>
+
+Integer, default 20, min 1, max 65535.  Number of monitoring requests
+which must succeed in a row without any failures to transition
+a given resource from the C<DOWN> state to the C<UP> state.
+
+=item B<ok_thresh>
+
+Integer, default 10, min 1, max 65535.  See below.
+
+=item B<down_thresh>
+
+Integer, default 10, min 1, max 65535.  The C<ok_thresh> and C<down_thresh>
+parameters control the transition from the C<UP> state to the C<DOWN>
+state while trying to prevent flappy behavior.  Their behavior is best
+described in terms of an internal failure counter for a resource
+which is currently in the C<UP> state.  The failure counter starts
+at zero on state transition into the C<UP> state.
+
+Every state poll that results in a failed response, even if other
+successful responses are interleaved between them, increments the
+failure counter.  If the failure counter reaches C<down_thresh>
+the resource is transitioned to the C<DOWN> state.  However, if
+C<ok_thresh> successes occur in a row with no failures between them,
+the failure counter is reset back to zero.
+
+So with the default values, the expected behavior is that if an C<UP>
+resource experiences 10 (possibly isolated or intermittent)
+monitor-polling failures over B<any> length of time, without a
+string of 10 successes in a row somewhere within the sequence to
+reset the counter, it will transition to the C<DOWN> state.
+Once C<DOWN>, it will require 20 successes in a row before
+transitioning back to the C<UP> state.
+
+=item B<interval>
+
+Integer seconds, default 10, min 1, max 255.  Number of seconds between
+successive monitoring requests for a given resource.
+
+=item B<timeout>
+
+Integer seconds, default interval/2, min 1, max 255.  Maximum time the
+monitoring code will wait for a successful response before giving up
+and considering the request to be a failure.  Defaults to half of the
+C<interval>, and must be less than C<interval>.
+
+=item B<plugin>
+
+String, required.  This indicates which specific plugin to use to execute
+the monitoring requests.  Any parameters other than the generic ones listed
+here are consumed by the plugin.
+
+=back
+
+There are six monitoring plugins included with gdnsd that can be used
+in a service_types definition, each of which may have additional,
+plugin-specific configuration options in addition to the generic ones
+above.  Each of these is documented in detail in its own manpage
+e.g. C<gdnsd-plugin-FOO>:
+
+=over 4
+
+=item B<tcp_connect>
+
+Checks TCP basic connectivity on a given port.  Only supports
+address resources, not CNAMEs.
+
+=item B<http_status>
+
+Checks HTTP connectivity, with options for the port, URL, and vhost
+to use in the request, and the acceptable HTTP status codes in
+the response.  Only supports address resources, not CNAMEs.
+
+=item B<extmon>
+
+Periodically executes a custom external commandline program
+to poll for the status of a resource.  Supports both address
+and CNAME resources.
+
+=item B<extfile>
+
+Reads the contents of a file on disk to import state monitoring data
+from another source.  Supports both address and CNAME resources.
+
+=item B<static>
+
+Configures a static monitoring result, mostly for testing / example code.
+Supports both address and CNAME resources.
+
+=item B<null>
+
+Configures an always-down static result, mostly for testing / example code.
+Supports both address and CNAME resources.
+
+=back
+
+=head1 PLUGINS
+
+The plugins hash is optional, and contains one key for every dynamic
+resolution plugin you wish to load and use.  The value must be a hash,
+and the contents of that hash are supplied to the plugin to use in
+configuring itself.  If the plugin requires no configuration, the empty
+hash C<{}> will suffice.  It is up to the plugin to determine whether
+the supplied hash of configuration data is legal or not.
+
+Monitoring-only plugins can also be given plugin-global level
+configuration here if the plugin author deemed it necessary.
+
+gdnsd ships with eight different monitoring plugins,
+all of which have their own separate manpage documentation (e.g. C<man
+gdnsd-plugin-FOO>):
+
+=over 4
+
+=item B<reflect>
+
+Reflects DNS client source IP and/or edns-client-subnet information
+back to the requestor as address data for debugging.
+
+=item B<simplefo>
+
+Simple primary->secondary failover of monitored addresses
+
+=item B<multifo>
+
+All-active failover of monitored round-robin address groups
+
+=item B<weighted>
+
+Weighted-round-robin responses with a variety of behavioral flavors,
+for both monitored addresses and CNAMEs.
+
+=item B<metafo>
+
+Static-ordered address(-group) meta-failover between 'datacenters',
+which are resources defined in terms of other plugins.  Supports
+both address and CNAME data.
+
+=item B<geoip>
+
+Combines metafo's functionality with MaxMind GeoIP databases to select
+different datacenter address(-group) preference/failover orderings for
+different clients based on approximate geographic location.  Supports
+both address and CNAME data.
+
+=item B<null>
+
+Returns all-zeros addresses or the CNAME C<invalid.> - mostly for
+testing and as simple example code.
+
+=item B<static>
+
+Configures static mappings of resources names to IP addresses or
+CNAMEs - mostly for testing and as simple example code.
+
+=back
+
+A configuration example showing the trivial plugins, as well as
+demonstrating the service_types described earlier:
+
+  service_types => {
+    corpwww_type => {
+      plugin => http_status
+      vhost => www.corp.example.com
+      url_path => /check_me
+      down_thresh => 5
+      interval => 5
+    }
+  }
+
+  plugins => {
+    null => {},
+    reflect => {},
+    static => {
+      foo = 192.0.2.2
+      bar = 192.0.2.123
+      somehost = somehost.example.net.
+    },
+    multifo => {
+      web-lb =>
+        service_types => [ corpwww_type, xmpp ],
+        lb01 => 192.0.2.200,
+        lb02 => 192.0.2.201,
+        lb03 => 192.0.2.202,
+      }
+    }
+  }
+
+And then in your example.com zonefile, you could have (among your other
+RRs):
+
+  zeros 600 DYNA null
+  reflect 10 DYNA reflect
+  reflect-both 10 DYNA reflect!both
+  pointless 42 DYNA static!foo
+  acname 400 DYNC static!somehost
+  www 300/45 DYNA multifo!web-lb
+
+=head1 LOW-LEVEL SYNTAX
+
+At the lowest level, the syntax of gdnsd config files roughly resembles
+an anonymous Perl data structure (using reference syntax).  There are
+three basic data types for values: ordered hashes (associative arrays
+mapping keys to values), ordered arrays of values, and simple strings.
+Hashes and arrays can be nested to arbitrary depth.  Generally
+speaking, whitespace is optional.  Single-line comments in both shell
+(C<#>) and DNS zonefile styles (C<;>) are allowed.  They run to the end
+of the current line and are considered to be whitespace by the parser.
+
+A hash is surrounded by curly braces (C<{> and C<}>).  Keys are
+separated from their values by either C<=E<gt>> or C<=> (at your
+stylistic discretion).  Hash keys follow the same rules as simple
+string values.  Hash values can be simple strings, arrays, or hashes.
+Key/value pairs can optionally have a trailing comma for stylistic
+clarity and separation.
+
+An array is surrounded by square braces (C<[> and C<]>).  Values can be
+simple strings, arrays, or hashes.  Values can optionally have a
+trailing comma for style.
+
+Strings (and thus keys) can be written in both quoted and unquoted
+forms.  In the quoted form, the string is surrounded by double-quotes
+(C<">), and can contain any literal byte value (even binary/utf-8
+stuff, or NUL) other than C<"> or C<\>.  Those two characters must be
+escaped by C<\>, i.e.  C<\"> and C<\\>.
+
+In the unquoted form, there are no surrounding quotes, and the allowed
+set of unescaped characters is further restricted.  The following are
+not allowed: C<][}{;#,"=\> (that is, square brackets, curly brackets,
+semicolons, octothorpes, commas, double quotes, equal signs, and
+backslashes).  Additionally, the first character cannot be a C<$>
+(dollar sign).
+
+Both forms use the same escaping rules, which are the same RFC-standard
+escaping rules used in zone files.  The escapes always start with C<\>.
+C<\> followed by any single byte other than a digit (C<0> - C<9>) is
+interepreted as that byte.  C<\> followed by exactly 3 digits
+interprets those digits as the unsigned decimal integer value of the
+desired byte (the 3 digit value cannot exceed C<255>).
+
+To illustrate the escaping and quoting, the following sets of example
+strings show different encodings of the same parsed value:
+
+  example
+  "example"
+  ex\097mpl\e
+  "ex\097mpl\e"
+
+  internal\"doublequote
+  "internal\"doublequote"
+
+  white\ space
+  "white space"
+
+  "braces{every[where]oh}my"
+  braces\{every\[where\]oh\}my
+
+  "\\==="
+  "\092==="
+  "\092\=\=\="
+  \\\=\=\=
+  \092\=\=\=
+
+The top level of the config file is an implicit hash with no bracing
+by default, but can also be an array bounded by square brackets.  This
+is not legal for the primary gdnsd configuration file, but could be
+useful in includefiles (see below).
+
+As a general rule, anywhere the higher-level syntax allows an array of
+values, you can substitute a single value.  The code will treat it as
+if it were an array of length 1.
+
+When we refer in other sections above to a value as being an "Integer"
+(or other specific scalar type), we're referring to constraints on the
+content of the character string value.  All scalar values are character
+strings.  "Boolean" values are characters strings which have the value
+"true" or "false", in any mix of upper or lower case.
+
+The following 3 example configuration files are identical in their
+parsed meanings, and should clarify anything miscommunicated above:
+
+Example 1 (simple and clean):
+
+  options = {
+    listen = [ 192.0.2.1, 192.0.2.2 ],
+    http_listen = 127.0.0.1,
+  }
+
+Example 2 (fat arrows, no commas, some arbitrary quoting):
+
+  "options" => {
+    listen => [ 192.0.2.1 192.0.2.2 ]
+    http_listen => "127.0.0.1"
+  }
+
+Example 3 (compressed and ugly):
+
+  options={listen=[192.0.2.1 192.0.2.2]http_listen=127.0.0.1}
+
+=head1 INCLUDING OTHER FILES
+
+vscf now has a mechanism for config includefiles.  The syntax is
+
+  $include{filename}
+
+where C<filename> can use the same kinds of escaping and/or
+double-quoting as normal scalar string data.  Whitespace between
+the filename and the surrounding brackets is optional.  Whitespace
+between C<$include> and the following C<{> is not allowed.  If the filename
+is relative (does not begin with F</>), it is interpreted as
+relative to the directory containing the parent file.  Include files
+can nest other include files to arbitrary depth.
+
+Keep in mind that at the top level of any given vscf file (even
+include files), the file must syntactically be either an implicit
+hash or an explicit, square-bracket-bounded, array.
+
+The include statement can be used in two distinct contexts within
+the syntax structure of a config file:
+
+=over 4
+
+=item B<Value Context>
+
+The include statement can replace any whole value (that is, the right
+hand side of a hash map entry or a member of an array) with its own
+contents, which are either a hash or an array.  Note that there is no
+mechanism for flattening an include-file's array into the parent array
+(the whole included array would be a single array item within the parent
+array).  Examples:
+
+  main config:
+    options => { listen => $include{foo} }
+  foo:
+    [ 127.0.0.1, 127.0.0.2 ]
+
+  main config:
+    plugins => $include{ "bar" }
+  bar:
+    geoip => { ... }
+    extmon => { ... }
+
+=item B<Hash-Merge Context>
+
+The include statement can also appear in a hash where a key would
+normally be expected.  In this case, the included file must be in hash
+(rather than array) form at the top level, and its contents are merged
+into the parent hash.  The merge is shallow, and conflicting keys are
+not allowed. Example:
+
+  main config:
+    options => { ... },
+    plugins => {
+        extmon => { ... },
+        metafo => { ... },
+        $include{geoip_cfg},
+        simplefo => { ... }
+    }
+  geoip_cfg:
+    geoip => { ... },
+    weighted => { ... }
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd(8)>, L<gdnsd.zonefile(5)>, L<gdnsd-plugin-simplefo(8)>,
+L<gdnsd-plugin-multifo(8)>, L<gdnsd-plugin-weighted(8)>,
+L<gdnsd-plugin-metafo(8)>, L<gdnsd-plugin-geoip(8)>,
+L<gdnsd-plugin-extmon(8)>, L<gdnsd-plugin-extfile(8)>
+L<gdnsd-plugin-api(3)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.djbdns.pod gdnsd-2.1.2/docs/gdnsd.djbdns.pod
--- gdnsd-2.1.0/docs/gdnsd.djbdns.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.djbdns.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,132 +0,0 @@
-
-=head1 NAME
-
-gdnsd.djbdns - gdnsd support for the djbdns tinydns zone data format
-
-=head1 SYNOPSIS
-
-  @GDNSD_DEFPATH_CONFIG@/djbdns/my-djbdns-datafile:
-    Zexample.com:a.ns.example.com:hostmaster.example.com::::::86400
-    &example.com:192.0.2.1:a.ns.example.com.:86400
-    &example.com:192.0.2.2:b.ns.example.com.:86400
-    =foo.example.com:192.0.2.100:86400
-
-=head1 DESCRIPTION
-
-This zone data backend implements the tinydns format described
-in L<http://cr.yp.to/djbdns/tinydns-data.html>.
-
-As of this writing, djbdns file format support is considered
-EXPERIMENTAL.  Feel free to submit issues and/or pull requests
-to make the implementation and documentation more correct and
-complete!  There are probably many legal djbdns zone datasets
-that do not load correctly (or at all) yet.  However, there are
-users loading data from this in production.
-
-The djbdns zone data backend loads all files found within
-the F<djbdns> subdirectory of the daemon config directory,
-default F<@GDNSD_DEFPATH_CONFIG@/djbdns/>.  Each file can contain
-multiple zones (identified by C<Z> records).
-
-At this time, unlike the RFC1035 zone data backend, the djbdns
-backend does not support automatic reloading of updates based on
-filesystem notification.  It only explicitly reloads any
-changed data on C<SIGUSR1> / C<gdnsd reload-zones>.
-
-=head1 SUPPORTED RECORD TYPES
-
-The following record types are implemented in the parser:
-
-=over 4
-
-=item B<Z> - SOA
-
-The C<Z> type denotes the existence of a zone and defines
-its SOA-record.  All records within a file must be contained within
-a zone defined by a C<Z> entry.
-
-=item B<&> - NS (+ A)
-
-Implemented.
-
-=item B<.> - NS + SOA (+ A)
-
-The C<.> type is meant to create an SOA along with the zone's
-NS records.  At this time, gdnsd doesn't support this record for
-defining the SOA or a zone's existence, and treats it just like C<&> above.
-
-=item B<@> - MX (+ A)
-
-Implemented.
-
-=item B<+> - A
-
-If the 5th field is C<~~>, this can be used to create C<DYNA>
-records as well, with the C<plugin!resource> part in the 2nd field.
-
-=item B<=> - A + PTR
-
-The autogeneration of PTR records for C<=> is not implemented yet,
-so this is treated identically to C<+> above.
-
-=item B<C> - CNAME
-
-If the 5th field is C<~~>, this can be used to create C<DYNC>
-records as well, with the C<plugin!resource> part in the 2nd field.
-
-=item B<\> - TXT
-
-Implemented.
-
-=item B<S> - SRV
-
-Implemented.
-
-=item B<N> - NAPTR
-
-Implemented.
-
-=item B<3> - AAAA
-
-Not yet implemented.
-
-=item B<6> - AAAA + PTR
-
-Not yet implemented.
-
-=item B<^> - PTR
-
-Not yet implemented.
-
-=item B<:> - Raw
-
-Not yet implemented.
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd(8)>, L<gdnsd.config(5)>, L<gdnsd.zonefile(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.djbdns.podin gdnsd-2.1.2/docs/gdnsd.djbdns.podin
--- gdnsd-2.1.0/docs/gdnsd.djbdns.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.djbdns.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,132 @@
+
+=head1 NAME
+
+gdnsd.djbdns - gdnsd support for the djbdns tinydns zone data format
+
+=head1 SYNOPSIS
+
+  @GDNSD_DEFPATH_CONFIG@/djbdns/my-djbdns-datafile:
+    Zexample.com:a.ns.example.com:hostmaster.example.com::::::86400
+    &example.com:192.0.2.1:a.ns.example.com.:86400
+    &example.com:192.0.2.2:b.ns.example.com.:86400
+    =foo.example.com:192.0.2.100:86400
+
+=head1 DESCRIPTION
+
+This zone data backend implements the tinydns format described
+in L<http://cr.yp.to/djbdns/tinydns-data.html>.
+
+As of this writing, djbdns file format support is considered
+EXPERIMENTAL.  Feel free to submit issues and/or pull requests
+to make the implementation and documentation more correct and
+complete!  There are probably many legal djbdns zone datasets
+that do not load correctly (or at all) yet.  However, there are
+users loading data from this in production.
+
+The djbdns zone data backend loads all files found within
+the F<djbdns> subdirectory of the daemon config directory,
+default F<@GDNSD_DEFPATH_CONFIG@/djbdns/>.  Each file can contain
+multiple zones (identified by C<Z> records).
+
+At this time, unlike the RFC1035 zone data backend, the djbdns
+backend does not support automatic reloading of updates based on
+filesystem notification.  It only explicitly reloads any
+changed data on C<SIGUSR1> / C<gdnsd reload-zones>.
+
+=head1 SUPPORTED RECORD TYPES
+
+The following record types are implemented in the parser:
+
+=over 4
+
+=item B<Z> - SOA
+
+The C<Z> type denotes the existence of a zone and defines
+its SOA-record.  All records within a file must be contained within
+a zone defined by a C<Z> entry.
+
+=item B<&> - NS (+ A)
+
+Implemented.
+
+=item B<.> - NS + SOA (+ A)
+
+The C<.> type is meant to create an SOA along with the zone's
+NS records.  At this time, gdnsd doesn't support this record for
+defining the SOA or a zone's existence, and treats it just like C<&> above.
+
+=item B<@> - MX (+ A)
+
+Implemented.
+
+=item B<+> - A
+
+If the 5th field is C<~~>, this can be used to create C<DYNA>
+records as well, with the C<plugin!resource> part in the 2nd field.
+
+=item B<=> - A + PTR
+
+The autogeneration of PTR records for C<=> is not implemented yet,
+so this is treated identically to C<+> above.
+
+=item B<C> - CNAME
+
+If the 5th field is C<~~>, this can be used to create C<DYNC>
+records as well, with the C<plugin!resource> part in the 2nd field.
+
+=item B<\> - TXT
+
+Implemented.
+
+=item B<S> - SRV
+
+Implemented.
+
+=item B<N> - NAPTR
+
+Implemented.
+
+=item B<3> - AAAA
+
+Not yet implemented.
+
+=item B<6> - AAAA + PTR
+
+Not yet implemented.
+
+=item B<^> - PTR
+
+Not yet implemented.
+
+=item B<:> - Raw
+
+Not yet implemented.
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd(8)>, L<gdnsd.config(5)>, L<gdnsd.zonefile(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd_geoip_test.pod gdnsd-2.1.2/docs/gdnsd_geoip_test.pod
--- gdnsd-2.1.0/docs/gdnsd_geoip_test.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd_geoip_test.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,60 +0,0 @@
-
-=head1 NAME
-
-gdnsd_geoip_test - Commandline test program for gdnsd-plugin-geoip maps
-
-=head1 SYNOPSIS
-
-  gdnsd_geoip_test [-c @GDNSD_DEFPATH_CONFIG@] [map_name addr]
-    -c            gdnsd config dir, see main gdnsd(8) manpage for details
-    map_name      Mapping name from geoip plugin config
-    addr          Client IP address to map.
-
-=head1 DESCRIPTION
-
-This is a simple commandline test program for C<gdnsd-plugin-geoip> map
-configurations.  It parses your standard gdnsd config file, extracts the
-relevant bits from the geoip plugin section, and processes the C<maps>
-section using the same core code as the plugin itself.  It then resolves
-the supplied IP address against the supplied map name, providing an
-ordered datacenter list (and edns scope netmask) result.
-
-The input IP addresses on the commandline do not accept CIDR subnet
-information.  This is intentional.  Because of the method by which
-C<gdnsd-plugin-geoip> builds, optimizes, and performs lookups on the
-internal data, the client subnet mask is irrelevant, and the response
-scope mask is always as specific or general as necessary.  To simulate
-different edns input masks on the same address data, simply zero out
-more of the right hand bits of the address.
-
-If no C<[map_name addr]> is given on the commandline, the program
-enters a REPL (Read-Eval-Print Loop) mode with a prompt, allowing
-you to interactively enter several C<[map_name addr]> pairs without
-reloading the configured database(s).
-
-=head1 SEE ALSO
-
-L<gdnsd-plugin-geoip(8)>, L<gdnsd.config(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2012 Brandon L Black <blblack@gmail.com>
-
-This file is part of gdnsd.
-
-gdnsd-plugin-geoip 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-plugin-geoip 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-plugin-geoip.  If not, see <http://www.gnu.org/licenses/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd_geoip_test.podin gdnsd-2.1.2/docs/gdnsd_geoip_test.podin
--- gdnsd-2.1.0/docs/gdnsd_geoip_test.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd_geoip_test.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,60 @@
+
+=head1 NAME
+
+gdnsd_geoip_test - Commandline test program for gdnsd-plugin-geoip maps
+
+=head1 SYNOPSIS
+
+  gdnsd_geoip_test [-c @GDNSD_DEFPATH_CONFIG@] [map_name addr]
+    -c            gdnsd config dir, see main gdnsd(8) manpage for details
+    map_name      Mapping name from geoip plugin config
+    addr          Client IP address to map.
+
+=head1 DESCRIPTION
+
+This is a simple commandline test program for C<gdnsd-plugin-geoip> map
+configurations.  It parses your standard gdnsd config file, extracts the
+relevant bits from the geoip plugin section, and processes the C<maps>
+section using the same core code as the plugin itself.  It then resolves
+the supplied IP address against the supplied map name, providing an
+ordered datacenter list (and edns scope netmask) result.
+
+The input IP addresses on the commandline do not accept CIDR subnet
+information.  This is intentional.  Because of the method by which
+C<gdnsd-plugin-geoip> builds, optimizes, and performs lookups on the
+internal data, the client subnet mask is irrelevant, and the response
+scope mask is always as specific or general as necessary.  To simulate
+different edns input masks on the same address data, simply zero out
+more of the right hand bits of the address.
+
+If no C<[map_name addr]> is given on the commandline, the program
+enters a REPL (Read-Eval-Print Loop) mode with a prompt, allowing
+you to interactively enter several C<[map_name addr]> pairs without
+reloading the configured database(s).
+
+=head1 SEE ALSO
+
+L<gdnsd-plugin-geoip(8)>, L<gdnsd.config(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2012 Brandon L Black <blblack@gmail.com>
+
+This file is part of gdnsd.
+
+gdnsd-plugin-geoip 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-plugin-geoip 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-plugin-geoip.  If not, see <http://www.gnu.org/licenses/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-api.pod gdnsd-2.1.2/docs/gdnsd-plugin-api.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-api.pod	2014-10-13 19:46:06.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-api.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,578 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-api - How to write gdnsd plugin code
-
-=head1 SYNOPSIS
-
-  Mandatory preamble macro+header your source must include at the top:
-    #define GDNSD_PLUGIN_NAME foo
-    #include <gdnsd/plugin.h>
-
-  Callback hooks you may implement (all are optional, and executed in this order):
-  (Letters in brackets denote callbacks applicable to: R for Resolver plugin role
-   and/or M for Monitor plugin role; a plugin may implement one or both).
-    -- startup/config stuff:
-    # only 'checkconf', 'start', 'restart', 'condrestart' invoke plugin callbacks at all
-    [RM] void plugin_foo_load_config(vscf_data_t* pc, const unsigned num_threads)
-    [ M] void plugin_foo_add_svctype(const char* name, vscf_data_t* svc_cfg, const unsigned interval, const unsigned timeout)
-    [ M] void plugin_foo_add_mon_addr(const char* desc, const char* svc_name, const char* cname, const dmn_anysin_t* addr, const unsigned idx);
-    [ M] void plugin_foo_add_mon_cname(const char* desc, const char* svc_name, const char* cname, const unsigned idx);
-    # only 'start', 'restart', and 'condrestart' continue past this point
-    [ M] void plugin_foo_init_monitors(struct ev_loop* mon_loop)
-    [ M] void plugin_foo_start_monitors(struct ev_loop* mon_loop)
-    [R ] void plugin_foo_pre_run(struct ev_loop* loop)
-    [R ] void plugin_foo_iothread_init(unsigned threadnum)
-
-    -- runtime stuff (called from main or zonefile thread)
-    --   (you won't get parallel calls to this, and in general it should be a readonly
-    --    operation anyways)
-    [R ] int plugin_foo_map_res(const char* resname, const uint8_t* origin)
-
-    -- runtime stuff (called from iothread context, anytime after iothread_init())
-    [R ] gdnsd_sttl_t plugin_foo_resolve(unsigned resnum, const uint8_t* origin, const client_info_t* cinfo, dyn_result_t* result)
-
-    -- cleanup stuff:
-    [RM] void plugin_foo_exit(void)
-
-=head1 WARNING
-
-Please note that in general, gdnsd's plugin API is poorly documented
-and unstable.  It often goes through fairly large and abrupt changes
-during development cycles, although it tends to be stable for a given
-stable release series.  Write code against it at your own peril
-(or at least, let me know so I can give you some warning on upcoming
-changes and/or solicit your feedback!).
-
-=head1 OVERVIEW
-
-This file documents versions 15-16 of the gdnsd plugin API.
-
-L<gdnsd>'s plugin API offers the ability to write plugins that can
-do either (or both) of two roles:
-
-1) Dynamically generate virtual C<A>, C<AAAA>, and/or C<CNAME> records
-according to whatever logic the plugin author wishes.  The plugin
-can make use of gdnsd's monitoring services for being failover-aware,
-and the actual zonefile records that trigger these lookups are C<DYNA>
-(for address-only data) and C<DYNC> (for which the plugin can return
-C<CNAME> or address results).
-
-2) Provide custom protocols and implementations for the back-end of the
-monitoring code for use by any plugin.  In this case you mostly just
-implement the protocol check code against a standard libev event loop
-and use a helper function to report the results of each status check,
-and the core takes care of the rest.
-
-All callbacks can be implemented by all plugins; it is possible to
-create a combined plugin that performs both roles.  There is no clear
-distinction between plugin "types" internally.
-
-=head1 USER-LEVEL CONFIGURATION FOR RESOLVER PLUGINS
-
-If you haven't read the documentation for the overall configuration
-file (L<gdnsd.config>) and the zonefiles (L<gdnsd.zonefile>), you might
-want to read those before continuing.
-
-From a user's perspective, there are two parts to configuring plugins.
-The first is configuring the plugin via the gdnsd config file.  The
-config file has an optional C<plugins> hash.  The keys of this hash are
-the names of plugins to load, and the values (which must be hashes) are
-the configuration data for the plugin itself.  e.g., to load two
-plugins named C<foo> and C<bar>, the plugins hash might look like this:
-
-  plugins => {
-    foo => {
-       opts => {
-          something = "quux\000<-an_embedded_null!",
-          somethingelse = { Z => z },
-       },
-       xyz = [x, y, z]
-    }
-    bar => { x => y }
-  }
-
-Note that a short-form plugin name (e.g. C<foo>) maps to a shared
-library named F<plugin_foo.so>.  Plugins will be loaded from the
-directory F<@GDNSD_DEFPATH_LIB@> by default, but this path can be
-overridden in the C<options> section of the gdnsd configuration.
-
-The basic syntactic structure of your plugin's config hash follows the
-same rules as the gdnsd config as a whole.  This is the C<vscf> syntax,
-which allows the user to specify nested data in the form of hashes,
-arrays, and simple values.  It's entirely up to the plugin author how
-the contents of the hash should be interpreted, and to document the
-plugin's config hash for users.
-
-The second part of the configuration is inserting C<DYNA> and/or
-C<DYNC> resource records into zonefiles.  C<DYNA> RRs use a plugin to
-dynamically generate C<A> and/or C<AAAA> RRs, while C<DYNC> RRs use a
-plugin to dynamically generate either C<A>/C<AAAA> RRs or C<CNAME> RRs.
-
-  www      300 DYNA foo!prod_web
-  www.test 300 DYNA foo!test_web
-  web      300 DYNC bar!test_web_cname
-
-The initial parts (the left-hand domainname, TTL, and RR-type) follow
-the usual zonefile norms, other than the fact that C<DYNA> is not a
-real resource record type in the DNS protocol.  The rdata section (e.g.
-C<foo!prod_web>) contains two parts separated by an C<!>: A plugin
-name, and a resource name.
-
-The meaning of the resource name is entirely up to the plugin.
-Typically it will reference a configuration key from the plugin's
-configuration hash as a mapping to a specific set of parameters for the
-plugin, but other uses of this field are possible.
-
-Plugins may implement just address results, just CNAME results, or
-both.
-
-=head1 USER-LEVEL CONFIGURATION FOR MONITORING
-
-DYNA/DYNC plugin code can optionally take advantage of monitoring
-services, e.g. to not return "dead" addresses from a pool.  Monitoring
-is configured as a set of C<service_types>, each representing a
-protocol, protocol-specific parameters, and some generic parameters
-related to timing and anti-flap.
-e.g.:
-
-    service_types = {
-        prod_web = {
-            plugin = http_status
-            # plugin-specific parameters
-            vhost = www.example.com
-            url_path = /checkme
-            ok_codes = [ 200, 201 ]
-            # generic parameters
-            up_thresh = 24
-            down_thresh = 16
-            ok_thresh = 8
-            interval = 8
-            timeout = 4
-        }
-    }
-
-A service type is meant to be re-used to monitor the same service at
-several different addresses or CNAMEs.
-
-One of the service type parameters is C<plugin>, naming a custom
-monitoring plugin to load.  If this plugin was not listed directly in
-the C<plugins> hash to give it global-level configuration, it will be
-loaded with no configuration at all (C<_load_config(NULL)>).
-
-=head1 PLUGIN SOURCE ORGANIZATION
-
-There must be one primary plugin source file which implements the
-callback hooks, and this file must include the following before any
-other code:
-
-    #define GDNSD_PLUGIN_NAME foo
-    #include <gdnsd/plugin.h>
-
-If you wish to split your implementation over multiple files, you can
-access the relevant API interfaces via the other C<gdnsd/*.h> headers
-directly.  However all of the actual callback hooks must be implemented
-in the primary source file, and your other source files should B<not>
-include C<gdnsd/plugin.h>.
-
-=head1 RUNTIME CALLBACK FLOW
-
-To understand how plugins operate and how to write plugins, it is
-necessary to understand the overall flow of gdnsd's execution, and
-where in that flow various callbacks are made into the code of the
-loaded plugins.  If you haven't yet read the main L<gdnsd> daemon
-documentation at this point, now would be a good time, as it covers
-some basic info about how gdnsd acts as its own initscript.  All
-callbacks have the name of the plugin in the function name, and we will
-use the example name C<foo> for documentation purposes.  A brief
-summary of all of the API interfaces and semantics follows in a later
-section, but it would be good to read through this lengthy prose
-explanation at least once.
-
-=head2 CONFIGURATION
-
-When gdnsd is started via actions such as C<start>, C<restart> or
-C<condrestart>, or when configuration is checked via C<checkconf>,
-at least some of the plugin callbacks will be executed.
-
-As soon as the configuration file as a whole has been validated and
-loaded, gdnsd goes about setting various internal parameters from this
-data.  When it encounters the C<plugins> hash, it will load and
-configure the named plugins.  Immediately after loading each plugin, it
-will execute the C<plugin_foo_load_config()> callback, providing the
-plugin code with its vscf configuration hash.  At this time the plugin
-should walk (and validate) the provided configuration data and set up
-its own internal parameters based on this data.  Any expensive
-configuration steps should be avoided in the load_config callback.
-Your goal in load_config is to validate your configuration data and
-store it somewhere, nothing more.
-
-There are 3 special API calls that are only valid during the execution
-of C<plugin_foo_load_config()> and only by resolver plugins, which are
-used by the plugin to feed some configuration-based data back to the core
-code.  These are C<gdnsd_mon_addr()> and C<gdnsd_mon_cname()> (which are
-used by resolver plugins to ask the monitoring system to monitor addresses
-and/or CNAMEs), and C<gdnsd_dyn_addr_max()>, which must be called to inform
-the core code of the maximum address counts this plugin configuration
-could ever return in a single response.  Failure to call C<gdnsd_dyn_addr_max()>
-results in the core assuming a maximum of 1 address per family.
-
-Next, C<service_types> are processed from the config.  These may
-autoload additional plugins that were not specified in the C<plugins>
-hash.  They will also receive a C<plugin_foo_load_config(NULL)> call if
-autoloaded.
-
-For each service type that uses a given plugin, the plugin will receive
-a C<plugin_foo_add_svctype()> callback.  Use this to set up local data
-structures for each service type you've been assigned.
-
-Next, all of the specific monitoring requested earlier by resolver plugins
-(via C<gdnsd_mon_addr()> and C<gdnsd_mon_cname()>) is passed to the
-monitoring plugins by invoking their C<plugin_foo_add_mon_addr()> and
-C<plugin_foo_add_mon_cname()>.  This is when a monitoring plugin sets up
-per-address/CNAME data structures.
-
-After all of the above, the daemon loads and parses all zonefiles,
-constructing the internal runtime DNS database.  During the zonefile
-loading phase, when it encounters C<DYNA> RRs in zonefiles, they will
-trigger the plugin callback C<plugin_foo_map_res> once for
-every C<DYNA> RR, with a C<NULL> C<origin> argument.  The same occurs
-with all C<DYNC> RRs, and they will get non-C<NULL> C<origin> arguments,
-which indicate the current C<$ORIGIN> in effect for the RR.  It is
-important to note that your plugin should treat it as an error if
-it gets a C<_map_res> call with a C<NULL> C<origin> (DYNA) for a resource
-which is configured to be capable of returning C<CNAME> results.
-
-If your DYNC plugin supports variable origins (e.g. the same resource
-name can be re-used in multiple zonefiles, and prepends some standard
-domainname fragment to origin in effect for the given RR), it is
-important that you validate that you can construct a legal domainname
-(length limits) from the given origin, resource name, and your own
-config at this time.
-
-Plugins should B<not> return different resource numbers for the same
-resname argument regardless of C<origin> value (or lack thereof).  You
-will break things if you do so.
-
-If your map_resource operation fails (e.g. unknown resource name, or
-illegal origin-based C<CNAME> construction, or a NULL origin argument (DYNA)
-for a resource that could return C<CNAME> data), log the error and return -1.
-Do B<not> fail fatally, as these calls happen at runtime during dynamic
-zonefile reloads.
-
-In the case of the action C<checkconf>, execution stops here.  Only the
-C<start> and C<restart> actions continue on to become full-fledged
-daemon instances.
-
-The first is C<plugin_foo_init_monitors()>.  You will be passed the
-event loop, and you are expected to set up events that will do a single
-monitoring check on all monitored resources and then clear themselves
-and not repeat.  When all plugins have done their init_monitors(), the
-loop will be run, and it is expected to terminate after a few seconds
-when all monitoring states have been initialized with real-world data.
-
-The next is C<plugin_foo_start_monitors()>.  Again you are passed the
-same libev loop, and you add all of your monitored resource callbacks,
-but this time it's permanent: they're expected to repeat their
-monitoring checks endlessly the next time the loop is invoked.
-
-When your libev monitoring callbacks have determined a success or
-failure for a monitored resource, they're expected to call the helper
-function C<gdnsd_mon_state_updater()> from F<gdnsd/mon.h> to send the
-state info upstream for anti-flap calculations and re-destribution to
-plugins which are monitoring the given resource.
-
-C<plugin_foo_pre_run> is executed next, giving a final chance to
-run any single-threaded setup code before threads are spawned
-and we enter runtime operations.
-
-After pre_run, gdnsd will spawn the runtime DNS I/O threads.  For each
-such thread, the callback C<plugin_foo_iothread_init> will be called
-from within each I/O thread with the global thread number as the only
-argument (0 through num_threads-1, where num_threads was provided to
-you back at C<plugin_foo_load_config()> time).  This would be the ideal
-time to xmalloc() writable per-thread data structures from within the
-threads themselves, so that a thread-aware malloc can avoid false sharing.
-
-=head2 RUNTIME
-
-At this point, gdnsd is ready to begin serving DNS queries.  After all
-I/O threads have finished initialization (and thus moved on to already
-serving requests), the primary thread will enter the libev loop
-mentioned above and remain under its control until daemon exit time.
-During this time the only direct callback your plugin will receive
-from I/O thread contexts is C<plugin_foo_resolve>.  If you registered
-any libev watchers during pre_run, you will also receive relevant
-callbacks there in the monitoring thread's execution context.
-
-As a general style rule, the runtime resolver callback is not allowed
-to block or fail.  It is expected to respond immediately with valid
-response data.  It is your job as the plugin author to ensure this is
-the case.  That means pre-allocating memory, pre-loading data, and/or
-pre-calculating anything expensive during earlier callbacks.  Worst
-case, you can return meaningless data, e.g. C<0.0.0.0> for C<DYNA> or
-some hostname like C<plugin.is.broken.> for C<DYNC>, but ideally all
-possible error conditions have been checked out beforehand.
-
-C<_resolve> is supplied with a resource number,
-a result structure your code can use to supply address information to
-the client, a C<client_info_t> structure giving network information
-about the querying client, and an C<origin> argument.
-
-The resource number and origin will match with earlier C<map_res>
-calls your plugin received.
-
-The C<client_info_t> structure contains the querying DNS cache's
-address as well as optional edns-client-subnet address+mask
-information.  If the mask is zero, there was no (useful)
-edns-client-subnet information, and the plugin must fall back to using
-the cache's address.  When edns-client-subnet information is present,
-the edns-client-subnet output "scope" mask must be set in the result
-structure (to zero if the information went unused, or to a specific
-scope as defined in the edns-client-subnet draft (could be shorter or
-longer than the client's specified mask)).
-
-There is no distinction between A and AAAA requests (for that matter,
-your plugin could be invoked to provide Additional-section addresses
-for other requested types like MX or SRV).  You must answer with all
-applicable IPv4 and IPv6 addresses on every call.  Generally speaking,
-gdnsd treats A and AAAA much like a single RR-set.  Both are always
-included in the additional section when appropriate.  In response to a
-direct query for A or AAAA, the daemon returns the queried address RR
-type in the answer section and the other in the additional section.
-
-Results are added to the opaque C<dyn_result_t*> via the various
-C<gdnsd_result_*()> calls.
-
-The C<gdnsd_sttl_t> return value of the resolve callback is used for your
-plugin to indicate the up/down state and TTL of the response placed
-in the C<dyn_result_t>, which is used to carry these values upwards
-through nested meta-plugins (e.g. multifo -> metafo -> geoip).
-
-When a signal is sent to stop the daemon, the primary thread's libev
-loop will return and no further watcher callbacks (set up via pre_run()
-or start_monitors()) will be invoked.  The main daemon will syslog()
-some final stats output and invoke C<exit()> to terminate the process.
-This in turn unwinds the stack of C<atexit()> handlers.  First will be
-a handler which cancels and joins all of the outstanding I/O threads,
-then comes another which invokes each plugin's C<plugin_foo_exit()>
-from the main thread's context.  You can log any stats output you wish
-here, and/or destruct any resources you wish (no worry about races from
-io thread access, they're all dead now).
-
-The C<map_res> callback may also be
-called at any time during normal runtime as a result of zonefiles being
-dynamically reloaded.  These should be readonly operations so there
-shouldn't be any locking concerns.  It's important that these calls
-never fail fatally.  Simply log an error and return -1.
-
-=head1 THREADING
-
-gdnsd uses POSIX threads.  Only the runtime resolve callback
-C<plugin_foo_resolve> needs to to concern itself with thread safety.
-It can and will be called from multiple POSIX threads simultaneously
-for runtime requests.
-
-The simplest (but least-performant) way to ensure thread-safety would
-be to wrap the contents of this function in a pthread mutex.
-However, for most imaginable cases, it should be trivial to structure
-your data and code such that this function can be both lock-free and
-thread-safe.
-
-=head1 CORE API DETAILS
-
-These are the functions exported by the core gdnsd code, which are
-available for your plugin to call at runtime.  They're implemented
-in a library named C<libgdnsd>, which the gdnsd daemon has already
-loaded before loading your plugin.  You don't need to (and shouldn't)
-explicitly link against libgdnsd.  The interfaces are defined in a set
-of header files grouped by functionality.  Note that in your
-primary plugin source file which includes F<gdnsd/plugin.h>, all of
-these header files have already been included for you indirectly.
-
-For now, the documentation of these interfaces exists solely in
-the header files themselves.  I'm still trying to sort out how to
-document them correctly, probably doxygen.
-
-=over 4
-
-=item gdnsd/compiler.h
-
-=item gdnsd/plugapi.h
-
-=item gdnsd/vscf.h
-
-=item gdnsd/net.h
-
-=item gdnsd/misc.h
-
-=item gdnsd/log.h
-
-=item gdnsd/mon.h
-
-=item gdnsd/dname.h
-
-=back
-
-=head1 GENERAL PLUGIN CODING CONVENTIONS, ETC
-
-=over 4
-
-=item logging and errors
-
-All syslog/stderr -type output should be handled via the thread-safe
-C<log_*()> and C<logf_*()> calls provided by gdnsd.  Do not attempt to
-use stderr (or stdout/stdin) or syslog directly.  To throw a fatal
-error and abort daemon execution, use C<log_fatal()>, which does not
-return.
-
-=item debugging
-
-Build your plugin with C<-DNDEBUG> unless you're actually debugging
-development code, and make liberal use of C<dmn_assert()> and
-C<log_debug()> where applicable.
-
-=item prototypes and headers
-
-You do not declare function prototypes for the callback functions
-(plugin_foo_*).  The prototypes are declared for you when you include
-the F<gdnsd/plugin.h> header.  You need merely define the functions
-themselves.
-
-=item API versioning
-
-There is an internal API version number documented at the top of this
-document and set in C<gdnsd/plugapi.h>.  This number is only
-incremented when incompatible changes are made to the plugin API
-interface or semantics which require recompiling plugins and/or
-updating their code.  When gdnsd is compiled this version number is
-hardcoded into the daemon binary.  When plugins are compiled the API
-version they were built against is also hardcoded into the plugin
-object automatically.  When gdnsd loads a plugin object, it checks for
-an exact match of plugin API version.  If the number does not match, a
-fatal error will be thrown telling the user the plugin needs to be
-rebuilt against the gdnsd version in use.
-
-The current API version number is available to your code as the macro
-C<GDNSD_PLUGIN_API_VERSION>.  If necessary, you can test this value via
-C<#if> macro logic to use alternate code for different API versions (or
-simply to error out if the API version is too old for your plugin code).
-
-=item map_res consistency
-
-The C<_map_res()> callback, if implemented, B<must> return a consistent,
-singular resource number for a given resource name, regardless of any
-C<origin> argument or the lack thereof.
-
-=item ignoring origin for address-only data
-
-If a plugin only handles addresses (for this resource, or in the general
-case), it should not fail on C<_map_res()> or C<_resolve()> just because an
-origin is defined, indicating a C<DYNC> RR.  It should instead simply ignore
-any origin argument and act as it always did.
-
-=item map_res DYNA validity checks
-
-If a resource name passed to C<_map_res()> is configured to be capable of
-returning C<CNAME> data and the C<origin> argument is C<NULL> (indicating
-a C<DYNA> RR), the plugin B<must> fail by returning -1.  One of the implications
-of this rule is that for any plugin which is capable of returning C<CNAME> data
-at all, C<_map_res()> B<must> be implemented.  Another implication of this
-(combined with the consistency rule) is that it's no longer legal to structure
-plugin resources such that they have unrelated sets of address and C<CNAME> data
-stored under the same resource name, as the weighted plugin originally did before
-its matching set of changes.
-
-=back
-
-=head1 RECENT API CHANGES
-
-=head2 Version 15/16
-
-This corresponds with the release of 2.0.0 and 2.1.0
-
-The changes below are versus Version 12 (final gdnsd 1.x API version).
-Versions 13 and 14 only existed in development releases and were moving
-targets.  The changes from Version 12 were rather sweeping.  This tries to
-cover the largest notable changes in the key callbacks, but likely doesn't
-note them all.  When in doubt, look at the source of the core plugins
-distributed with the main source for guidance.
-
-The data structures C<dynaddr_result_t> and C<dyncname_result_t> were
-merged and replaced with a single structure C<dyn_result_t>, which
-is an opaque data structure modified by the various C<gdnsd_result_*()>
-functions for adding or clearing address and/or CNAME results.
-
-The C<_map_res_dyna()> and C<_map_res_dync()> callbacks were merged
-and renamed to just C<_map_res()>.  The new call has an origin argument
-like the old C<_map_res_dync()>, which will be NULL when called for
-C<DYNA> RRs, and the C<result> argument's type was
-changed from C<dynaddr_result_t*> to C<dyn_result_t*>.
-
-The C<_resolve_dynaddr()> and C<_resolve_dyncname()> callbacks were
-merged and renamed to just C<_resolve()>.  The new call has an origin
-argument like the old C<_resolve_dyncame()>, which will be NULL when
-called for C<DYNA> RRs, and the C<result> argument's type was
-changed from C<dynaddr_result_t*> to C<dyn_result_t*>.  The new call
-also lacks the C<threadnum> argument, as any plugin which needs this
-information can work around it via the C<_iothread_init()> callback
-and/or thread-local storage.
-
-C<gdnsd_dynaddr_add_result_anysin()> was renamed to
-C<gdnsd_dyn_add_result_anysin()>, and the C<result> argument's type was
-changed from C<dynaddr_result_t*> to C<dyn_result_t*>.
-
-C<_load_config()> no longer has a C<mon_list_t*> return value; instead
-monitored resources are indicated to the core via the C<gdnsd_mon_addr()>
-and C<gdnsd_mon_cname()> functions during the execution of C<_load_config()>.
-
-Resolver plugins must now call C<gdnsd_dyn_addr_max()> during C<_load_config()>
-to inform the core of address limits.
-
-C<gdnsd_add_monitor> was replaced by C<gdnsd_add_mon_addr()> and
-C<gdnsd_add_mon_cname()>.
-
-The callbacks C<_post_daemonize()>, C<_pre_privdrop()>, C<_post_privdrop()>,
-and C<_full_config()> were removed.  With the current structure, code that logically
-fit in these can be placed elsewhere (e.g. C<_start_monitors()>, C<_pre_run()>, or
-C<_load_config()> as appropriate).
-
-The type C<vscf_data_t*> in callback arguments used to be C<const>, and now it is
-not.  Similar changes occured in many places in the vscf API in general.  Just remove
-const from your plugin's local vscf pointers and recompile.
-
-Version 16 was bumped just to require a recompile (some formerly-exported funcs
-became inlines, some const changes in signatures, etc), but is mostly the same
-as 15 otherwise.
-
-=head1 SEE ALSO
-
-The source for the included addr/cname-resolution plugins C<null>,
-C<reflect>, C<static>, C<simplefo>, C<multifo>, C<weighted>, C<metafo>,
-and C<geoip>.  The source for the included monitoring plugins
-C<http_status>, C<tcp_connect>, and C<extmon>.
-
-L<gdnsd(8)>, L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-api.podin gdnsd-2.1.2/docs/gdnsd-plugin-api.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-api.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-api.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,578 @@
+
+=head1 NAME
+
+gdnsd-plugin-api - How to write gdnsd plugin code
+
+=head1 SYNOPSIS
+
+  Mandatory preamble macro+header your source must include at the top:
+    #define GDNSD_PLUGIN_NAME foo
+    #include <gdnsd/plugin.h>
+
+  Callback hooks you may implement (all are optional, and executed in this order):
+  (Letters in brackets denote callbacks applicable to: R for Resolver plugin role
+   and/or M for Monitor plugin role; a plugin may implement one or both).
+    -- startup/config stuff:
+    # only 'checkconf', 'start', 'restart', 'condrestart' invoke plugin callbacks at all
+    [RM] void plugin_foo_load_config(vscf_data_t* pc, const unsigned num_threads)
+    [ M] void plugin_foo_add_svctype(const char* name, vscf_data_t* svc_cfg, const unsigned interval, const unsigned timeout)
+    [ M] void plugin_foo_add_mon_addr(const char* desc, const char* svc_name, const char* cname, const dmn_anysin_t* addr, const unsigned idx);
+    [ M] void plugin_foo_add_mon_cname(const char* desc, const char* svc_name, const char* cname, const unsigned idx);
+    # only 'start', 'restart', and 'condrestart' continue past this point
+    [ M] void plugin_foo_init_monitors(struct ev_loop* mon_loop)
+    [ M] void plugin_foo_start_monitors(struct ev_loop* mon_loop)
+    [R ] void plugin_foo_pre_run(struct ev_loop* loop)
+    [R ] void plugin_foo_iothread_init(unsigned threadnum)
+
+    -- runtime stuff (called from main or zonefile thread)
+    --   (you won't get parallel calls to this, and in general it should be a readonly
+    --    operation anyways)
+    [R ] int plugin_foo_map_res(const char* resname, const uint8_t* origin)
+
+    -- runtime stuff (called from iothread context, anytime after iothread_init())
+    [R ] gdnsd_sttl_t plugin_foo_resolve(unsigned resnum, const uint8_t* origin, const client_info_t* cinfo, dyn_result_t* result)
+
+    -- cleanup stuff:
+    [RM] void plugin_foo_exit(void)
+
+=head1 WARNING
+
+Please note that in general, gdnsd's plugin API is poorly documented
+and unstable.  It often goes through fairly large and abrupt changes
+during development cycles, although it tends to be stable for a given
+stable release series.  Write code against it at your own peril
+(or at least, let me know so I can give you some warning on upcoming
+changes and/or solicit your feedback!).
+
+=head1 OVERVIEW
+
+This file documents versions 15-16 of the gdnsd plugin API.
+
+L<gdnsd>'s plugin API offers the ability to write plugins that can
+do either (or both) of two roles:
+
+1) Dynamically generate virtual C<A>, C<AAAA>, and/or C<CNAME> records
+according to whatever logic the plugin author wishes.  The plugin
+can make use of gdnsd's monitoring services for being failover-aware,
+and the actual zonefile records that trigger these lookups are C<DYNA>
+(for address-only data) and C<DYNC> (for which the plugin can return
+C<CNAME> or address results).
+
+2) Provide custom protocols and implementations for the back-end of the
+monitoring code for use by any plugin.  In this case you mostly just
+implement the protocol check code against a standard libev event loop
+and use a helper function to report the results of each status check,
+and the core takes care of the rest.
+
+All callbacks can be implemented by all plugins; it is possible to
+create a combined plugin that performs both roles.  There is no clear
+distinction between plugin "types" internally.
+
+=head1 USER-LEVEL CONFIGURATION FOR RESOLVER PLUGINS
+
+If you haven't read the documentation for the overall configuration
+file (L<gdnsd.config>) and the zonefiles (L<gdnsd.zonefile>), you might
+want to read those before continuing.
+
+From a user's perspective, there are two parts to configuring plugins.
+The first is configuring the plugin via the gdnsd config file.  The
+config file has an optional C<plugins> hash.  The keys of this hash are
+the names of plugins to load, and the values (which must be hashes) are
+the configuration data for the plugin itself.  e.g., to load two
+plugins named C<foo> and C<bar>, the plugins hash might look like this:
+
+  plugins => {
+    foo => {
+       opts => {
+          something = "quux\000<-an_embedded_null!",
+          somethingelse = { Z => z },
+       },
+       xyz = [x, y, z]
+    }
+    bar => { x => y }
+  }
+
+Note that a short-form plugin name (e.g. C<foo>) maps to a shared
+library named F<plugin_foo.so>.  Plugins will be loaded from the
+directory F<@GDNSD_DEFPATH_LIB@> by default, but this path can be
+overridden in the C<options> section of the gdnsd configuration.
+
+The basic syntactic structure of your plugin's config hash follows the
+same rules as the gdnsd config as a whole.  This is the C<vscf> syntax,
+which allows the user to specify nested data in the form of hashes,
+arrays, and simple values.  It's entirely up to the plugin author how
+the contents of the hash should be interpreted, and to document the
+plugin's config hash for users.
+
+The second part of the configuration is inserting C<DYNA> and/or
+C<DYNC> resource records into zonefiles.  C<DYNA> RRs use a plugin to
+dynamically generate C<A> and/or C<AAAA> RRs, while C<DYNC> RRs use a
+plugin to dynamically generate either C<A>/C<AAAA> RRs or C<CNAME> RRs.
+
+  www      300 DYNA foo!prod_web
+  www.test 300 DYNA foo!test_web
+  web      300 DYNC bar!test_web_cname
+
+The initial parts (the left-hand domainname, TTL, and RR-type) follow
+the usual zonefile norms, other than the fact that C<DYNA> is not a
+real resource record type in the DNS protocol.  The rdata section (e.g.
+C<foo!prod_web>) contains two parts separated by an C<!>: A plugin
+name, and a resource name.
+
+The meaning of the resource name is entirely up to the plugin.
+Typically it will reference a configuration key from the plugin's
+configuration hash as a mapping to a specific set of parameters for the
+plugin, but other uses of this field are possible.
+
+Plugins may implement just address results, just CNAME results, or
+both.
+
+=head1 USER-LEVEL CONFIGURATION FOR MONITORING
+
+DYNA/DYNC plugin code can optionally take advantage of monitoring
+services, e.g. to not return "dead" addresses from a pool.  Monitoring
+is configured as a set of C<service_types>, each representing a
+protocol, protocol-specific parameters, and some generic parameters
+related to timing and anti-flap.
+e.g.:
+
+    service_types = {
+        prod_web = {
+            plugin = http_status
+            # plugin-specific parameters
+            vhost = www.example.com
+            url_path = /checkme
+            ok_codes = [ 200, 201 ]
+            # generic parameters
+            up_thresh = 24
+            down_thresh = 16
+            ok_thresh = 8
+            interval = 8
+            timeout = 4
+        }
+    }
+
+A service type is meant to be re-used to monitor the same service at
+several different addresses or CNAMEs.
+
+One of the service type parameters is C<plugin>, naming a custom
+monitoring plugin to load.  If this plugin was not listed directly in
+the C<plugins> hash to give it global-level configuration, it will be
+loaded with no configuration at all (C<_load_config(NULL)>).
+
+=head1 PLUGIN SOURCE ORGANIZATION
+
+There must be one primary plugin source file which implements the
+callback hooks, and this file must include the following before any
+other code:
+
+    #define GDNSD_PLUGIN_NAME foo
+    #include <gdnsd/plugin.h>
+
+If you wish to split your implementation over multiple files, you can
+access the relevant API interfaces via the other C<gdnsd/*.h> headers
+directly.  However all of the actual callback hooks must be implemented
+in the primary source file, and your other source files should B<not>
+include C<gdnsd/plugin.h>.
+
+=head1 RUNTIME CALLBACK FLOW
+
+To understand how plugins operate and how to write plugins, it is
+necessary to understand the overall flow of gdnsd's execution, and
+where in that flow various callbacks are made into the code of the
+loaded plugins.  If you haven't yet read the main L<gdnsd> daemon
+documentation at this point, now would be a good time, as it covers
+some basic info about how gdnsd acts as its own initscript.  All
+callbacks have the name of the plugin in the function name, and we will
+use the example name C<foo> for documentation purposes.  A brief
+summary of all of the API interfaces and semantics follows in a later
+section, but it would be good to read through this lengthy prose
+explanation at least once.
+
+=head2 CONFIGURATION
+
+When gdnsd is started via actions such as C<start>, C<restart> or
+C<condrestart>, or when configuration is checked via C<checkconf>,
+at least some of the plugin callbacks will be executed.
+
+As soon as the configuration file as a whole has been validated and
+loaded, gdnsd goes about setting various internal parameters from this
+data.  When it encounters the C<plugins> hash, it will load and
+configure the named plugins.  Immediately after loading each plugin, it
+will execute the C<plugin_foo_load_config()> callback, providing the
+plugin code with its vscf configuration hash.  At this time the plugin
+should walk (and validate) the provided configuration data and set up
+its own internal parameters based on this data.  Any expensive
+configuration steps should be avoided in the load_config callback.
+Your goal in load_config is to validate your configuration data and
+store it somewhere, nothing more.
+
+There are 3 special API calls that are only valid during the execution
+of C<plugin_foo_load_config()> and only by resolver plugins, which are
+used by the plugin to feed some configuration-based data back to the core
+code.  These are C<gdnsd_mon_addr()> and C<gdnsd_mon_cname()> (which are
+used by resolver plugins to ask the monitoring system to monitor addresses
+and/or CNAMEs), and C<gdnsd_dyn_addr_max()>, which must be called to inform
+the core code of the maximum address counts this plugin configuration
+could ever return in a single response.  Failure to call C<gdnsd_dyn_addr_max()>
+results in the core assuming a maximum of 1 address per family.
+
+Next, C<service_types> are processed from the config.  These may
+autoload additional plugins that were not specified in the C<plugins>
+hash.  They will also receive a C<plugin_foo_load_config(NULL)> call if
+autoloaded.
+
+For each service type that uses a given plugin, the plugin will receive
+a C<plugin_foo_add_svctype()> callback.  Use this to set up local data
+structures for each service type you've been assigned.
+
+Next, all of the specific monitoring requested earlier by resolver plugins
+(via C<gdnsd_mon_addr()> and C<gdnsd_mon_cname()>) is passed to the
+monitoring plugins by invoking their C<plugin_foo_add_mon_addr()> and
+C<plugin_foo_add_mon_cname()>.  This is when a monitoring plugin sets up
+per-address/CNAME data structures.
+
+After all of the above, the daemon loads and parses all zonefiles,
+constructing the internal runtime DNS database.  During the zonefile
+loading phase, when it encounters C<DYNA> RRs in zonefiles, they will
+trigger the plugin callback C<plugin_foo_map_res> once for
+every C<DYNA> RR, with a C<NULL> C<origin> argument.  The same occurs
+with all C<DYNC> RRs, and they will get non-C<NULL> C<origin> arguments,
+which indicate the current C<$ORIGIN> in effect for the RR.  It is
+important to note that your plugin should treat it as an error if
+it gets a C<_map_res> call with a C<NULL> C<origin> (DYNA) for a resource
+which is configured to be capable of returning C<CNAME> results.
+
+If your DYNC plugin supports variable origins (e.g. the same resource
+name can be re-used in multiple zonefiles, and prepends some standard
+domainname fragment to origin in effect for the given RR), it is
+important that you validate that you can construct a legal domainname
+(length limits) from the given origin, resource name, and your own
+config at this time.
+
+Plugins should B<not> return different resource numbers for the same
+resname argument regardless of C<origin> value (or lack thereof).  You
+will break things if you do so.
+
+If your map_resource operation fails (e.g. unknown resource name, or
+illegal origin-based C<CNAME> construction, or a NULL origin argument (DYNA)
+for a resource that could return C<CNAME> data), log the error and return -1.
+Do B<not> fail fatally, as these calls happen at runtime during dynamic
+zonefile reloads.
+
+In the case of the action C<checkconf>, execution stops here.  Only the
+C<start> and C<restart> actions continue on to become full-fledged
+daemon instances.
+
+The first is C<plugin_foo_init_monitors()>.  You will be passed the
+event loop, and you are expected to set up events that will do a single
+monitoring check on all monitored resources and then clear themselves
+and not repeat.  When all plugins have done their init_monitors(), the
+loop will be run, and it is expected to terminate after a few seconds
+when all monitoring states have been initialized with real-world data.
+
+The next is C<plugin_foo_start_monitors()>.  Again you are passed the
+same libev loop, and you add all of your monitored resource callbacks,
+but this time it's permanent: they're expected to repeat their
+monitoring checks endlessly the next time the loop is invoked.
+
+When your libev monitoring callbacks have determined a success or
+failure for a monitored resource, they're expected to call the helper
+function C<gdnsd_mon_state_updater()> from F<gdnsd/mon.h> to send the
+state info upstream for anti-flap calculations and re-destribution to
+plugins which are monitoring the given resource.
+
+C<plugin_foo_pre_run> is executed next, giving a final chance to
+run any single-threaded setup code before threads are spawned
+and we enter runtime operations.
+
+After pre_run, gdnsd will spawn the runtime DNS I/O threads.  For each
+such thread, the callback C<plugin_foo_iothread_init> will be called
+from within each I/O thread with the global thread number as the only
+argument (0 through num_threads-1, where num_threads was provided to
+you back at C<plugin_foo_load_config()> time).  This would be the ideal
+time to xmalloc() writable per-thread data structures from within the
+threads themselves, so that a thread-aware malloc can avoid false sharing.
+
+=head2 RUNTIME
+
+At this point, gdnsd is ready to begin serving DNS queries.  After all
+I/O threads have finished initialization (and thus moved on to already
+serving requests), the primary thread will enter the libev loop
+mentioned above and remain under its control until daemon exit time.
+During this time the only direct callback your plugin will receive
+from I/O thread contexts is C<plugin_foo_resolve>.  If you registered
+any libev watchers during pre_run, you will also receive relevant
+callbacks there in the monitoring thread's execution context.
+
+As a general style rule, the runtime resolver callback is not allowed
+to block or fail.  It is expected to respond immediately with valid
+response data.  It is your job as the plugin author to ensure this is
+the case.  That means pre-allocating memory, pre-loading data, and/or
+pre-calculating anything expensive during earlier callbacks.  Worst
+case, you can return meaningless data, e.g. C<0.0.0.0> for C<DYNA> or
+some hostname like C<plugin.is.broken.> for C<DYNC>, but ideally all
+possible error conditions have been checked out beforehand.
+
+C<_resolve> is supplied with a resource number,
+a result structure your code can use to supply address information to
+the client, a C<client_info_t> structure giving network information
+about the querying client, and an C<origin> argument.
+
+The resource number and origin will match with earlier C<map_res>
+calls your plugin received.
+
+The C<client_info_t> structure contains the querying DNS cache's
+address as well as optional edns-client-subnet address+mask
+information.  If the mask is zero, there was no (useful)
+edns-client-subnet information, and the plugin must fall back to using
+the cache's address.  When edns-client-subnet information is present,
+the edns-client-subnet output "scope" mask must be set in the result
+structure (to zero if the information went unused, or to a specific
+scope as defined in the edns-client-subnet draft (could be shorter or
+longer than the client's specified mask)).
+
+There is no distinction between A and AAAA requests (for that matter,
+your plugin could be invoked to provide Additional-section addresses
+for other requested types like MX or SRV).  You must answer with all
+applicable IPv4 and IPv6 addresses on every call.  Generally speaking,
+gdnsd treats A and AAAA much like a single RR-set.  Both are always
+included in the additional section when appropriate.  In response to a
+direct query for A or AAAA, the daemon returns the queried address RR
+type in the answer section and the other in the additional section.
+
+Results are added to the opaque C<dyn_result_t*> via the various
+C<gdnsd_result_*()> calls.
+
+The C<gdnsd_sttl_t> return value of the resolve callback is used for your
+plugin to indicate the up/down state and TTL of the response placed
+in the C<dyn_result_t>, which is used to carry these values upwards
+through nested meta-plugins (e.g. multifo -> metafo -> geoip).
+
+When a signal is sent to stop the daemon, the primary thread's libev
+loop will return and no further watcher callbacks (set up via pre_run()
+or start_monitors()) will be invoked.  The main daemon will syslog()
+some final stats output and invoke C<exit()> to terminate the process.
+This in turn unwinds the stack of C<atexit()> handlers.  First will be
+a handler which cancels and joins all of the outstanding I/O threads,
+then comes another which invokes each plugin's C<plugin_foo_exit()>
+from the main thread's context.  You can log any stats output you wish
+here, and/or destruct any resources you wish (no worry about races from
+io thread access, they're all dead now).
+
+The C<map_res> callback may also be
+called at any time during normal runtime as a result of zonefiles being
+dynamically reloaded.  These should be readonly operations so there
+shouldn't be any locking concerns.  It's important that these calls
+never fail fatally.  Simply log an error and return -1.
+
+=head1 THREADING
+
+gdnsd uses POSIX threads.  Only the runtime resolve callback
+C<plugin_foo_resolve> needs to to concern itself with thread safety.
+It can and will be called from multiple POSIX threads simultaneously
+for runtime requests.
+
+The simplest (but least-performant) way to ensure thread-safety would
+be to wrap the contents of this function in a pthread mutex.
+However, for most imaginable cases, it should be trivial to structure
+your data and code such that this function can be both lock-free and
+thread-safe.
+
+=head1 CORE API DETAILS
+
+These are the functions exported by the core gdnsd code, which are
+available for your plugin to call at runtime.  They're implemented
+in a library named C<libgdnsd>, which the gdnsd daemon has already
+loaded before loading your plugin.  You don't need to (and shouldn't)
+explicitly link against libgdnsd.  The interfaces are defined in a set
+of header files grouped by functionality.  Note that in your
+primary plugin source file which includes F<gdnsd/plugin.h>, all of
+these header files have already been included for you indirectly.
+
+For now, the documentation of these interfaces exists solely in
+the header files themselves.  I'm still trying to sort out how to
+document them correctly, probably doxygen.
+
+=over 4
+
+=item gdnsd/compiler.h
+
+=item gdnsd/plugapi.h
+
+=item gdnsd/vscf.h
+
+=item gdnsd/net.h
+
+=item gdnsd/misc.h
+
+=item gdnsd/log.h
+
+=item gdnsd/mon.h
+
+=item gdnsd/dname.h
+
+=back
+
+=head1 GENERAL PLUGIN CODING CONVENTIONS, ETC
+
+=over 4
+
+=item logging and errors
+
+All syslog/stderr -type output should be handled via the thread-safe
+C<log_*()> and C<logf_*()> calls provided by gdnsd.  Do not attempt to
+use stderr (or stdout/stdin) or syslog directly.  To throw a fatal
+error and abort daemon execution, use C<log_fatal()>, which does not
+return.
+
+=item debugging
+
+Build your plugin with C<-DNDEBUG> unless you're actually debugging
+development code, and make liberal use of C<dmn_assert()> and
+C<log_debug()> where applicable.
+
+=item prototypes and headers
+
+You do not declare function prototypes for the callback functions
+(plugin_foo_*).  The prototypes are declared for you when you include
+the F<gdnsd/plugin.h> header.  You need merely define the functions
+themselves.
+
+=item API versioning
+
+There is an internal API version number documented at the top of this
+document and set in C<gdnsd/plugapi.h>.  This number is only
+incremented when incompatible changes are made to the plugin API
+interface or semantics which require recompiling plugins and/or
+updating their code.  When gdnsd is compiled this version number is
+hardcoded into the daemon binary.  When plugins are compiled the API
+version they were built against is also hardcoded into the plugin
+object automatically.  When gdnsd loads a plugin object, it checks for
+an exact match of plugin API version.  If the number does not match, a
+fatal error will be thrown telling the user the plugin needs to be
+rebuilt against the gdnsd version in use.
+
+The current API version number is available to your code as the macro
+C<GDNSD_PLUGIN_API_VERSION>.  If necessary, you can test this value via
+C<#if> macro logic to use alternate code for different API versions (or
+simply to error out if the API version is too old for your plugin code).
+
+=item map_res consistency
+
+The C<_map_res()> callback, if implemented, B<must> return a consistent,
+singular resource number for a given resource name, regardless of any
+C<origin> argument or the lack thereof.
+
+=item ignoring origin for address-only data
+
+If a plugin only handles addresses (for this resource, or in the general
+case), it should not fail on C<_map_res()> or C<_resolve()> just because an
+origin is defined, indicating a C<DYNC> RR.  It should instead simply ignore
+any origin argument and act as it always did.
+
+=item map_res DYNA validity checks
+
+If a resource name passed to C<_map_res()> is configured to be capable of
+returning C<CNAME> data and the C<origin> argument is C<NULL> (indicating
+a C<DYNA> RR), the plugin B<must> fail by returning -1.  One of the implications
+of this rule is that for any plugin which is capable of returning C<CNAME> data
+at all, C<_map_res()> B<must> be implemented.  Another implication of this
+(combined with the consistency rule) is that it's no longer legal to structure
+plugin resources such that they have unrelated sets of address and C<CNAME> data
+stored under the same resource name, as the weighted plugin originally did before
+its matching set of changes.
+
+=back
+
+=head1 RECENT API CHANGES
+
+=head2 Version 15/16
+
+This corresponds with the release of 2.0.0 and 2.1.0
+
+The changes below are versus Version 12 (final gdnsd 1.x API version).
+Versions 13 and 14 only existed in development releases and were moving
+targets.  The changes from Version 12 were rather sweeping.  This tries to
+cover the largest notable changes in the key callbacks, but likely doesn't
+note them all.  When in doubt, look at the source of the core plugins
+distributed with the main source for guidance.
+
+The data structures C<dynaddr_result_t> and C<dyncname_result_t> were
+merged and replaced with a single structure C<dyn_result_t>, which
+is an opaque data structure modified by the various C<gdnsd_result_*()>
+functions for adding or clearing address and/or CNAME results.
+
+The C<_map_res_dyna()> and C<_map_res_dync()> callbacks were merged
+and renamed to just C<_map_res()>.  The new call has an origin argument
+like the old C<_map_res_dync()>, which will be NULL when called for
+C<DYNA> RRs, and the C<result> argument's type was
+changed from C<dynaddr_result_t*> to C<dyn_result_t*>.
+
+The C<_resolve_dynaddr()> and C<_resolve_dyncname()> callbacks were
+merged and renamed to just C<_resolve()>.  The new call has an origin
+argument like the old C<_resolve_dyncame()>, which will be NULL when
+called for C<DYNA> RRs, and the C<result> argument's type was
+changed from C<dynaddr_result_t*> to C<dyn_result_t*>.  The new call
+also lacks the C<threadnum> argument, as any plugin which needs this
+information can work around it via the C<_iothread_init()> callback
+and/or thread-local storage.
+
+C<gdnsd_dynaddr_add_result_anysin()> was renamed to
+C<gdnsd_dyn_add_result_anysin()>, and the C<result> argument's type was
+changed from C<dynaddr_result_t*> to C<dyn_result_t*>.
+
+C<_load_config()> no longer has a C<mon_list_t*> return value; instead
+monitored resources are indicated to the core via the C<gdnsd_mon_addr()>
+and C<gdnsd_mon_cname()> functions during the execution of C<_load_config()>.
+
+Resolver plugins must now call C<gdnsd_dyn_addr_max()> during C<_load_config()>
+to inform the core of address limits.
+
+C<gdnsd_add_monitor> was replaced by C<gdnsd_add_mon_addr()> and
+C<gdnsd_add_mon_cname()>.
+
+The callbacks C<_post_daemonize()>, C<_pre_privdrop()>, C<_post_privdrop()>,
+and C<_full_config()> were removed.  With the current structure, code that logically
+fit in these can be placed elsewhere (e.g. C<_start_monitors()>, C<_pre_run()>, or
+C<_load_config()> as appropriate).
+
+The type C<vscf_data_t*> in callback arguments used to be C<const>, and now it is
+not.  Similar changes occured in many places in the vscf API in general.  Just remove
+const from your plugin's local vscf pointers and recompile.
+
+Version 16 was bumped just to require a recompile (some formerly-exported funcs
+became inlines, some const changes in signatures, etc), but is mostly the same
+as 15 otherwise.
+
+=head1 SEE ALSO
+
+The source for the included addr/cname-resolution plugins C<null>,
+C<reflect>, C<static>, C<simplefo>, C<multifo>, C<weighted>, C<metafo>,
+and C<geoip>.  The source for the included monitoring plugins
+C<http_status>, C<tcp_connect>, and C<extmon>.
+
+L<gdnsd(8)>, L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-extfile.pod gdnsd-2.1.2/docs/gdnsd-plugin-extfile.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-extfile.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-extfile.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,200 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-extfile - gdnsd plugin for importing monitor data via file
-
-=head1 SYNOPSIS
-
-Example service_types config:
-
-  service_types => {
-    ext1 => {
-      plugin => "extfile",
-      file => "/var/tmp/ext1data", # required
-      direct => true, # default false
-      def_down => false, # default false
-      def_ttl => 600, # default max (limited by zonefile RRs)
-    }
-    ext2 => {
-      plugin => "extfile",
-      file => "ext2data", # def dir: @GDNSD_DEFPATH_STATE@/extfile/
-    },
-  }
-
-Example plugin config using these service_types:
-
-  plugins => {
-    multifo => {
-      www1 => {
-        service_types => ext2,
-        lb01 => 192.0.2.200,
-        lb02 => 192.0.2.201,
-        lb03 => 192.0.2.202,
-      }
-      www2 => {
-        service_types => [ ext1, http_status ],
-        lb01 => 192.0.2.203,
-        lb02 => 192.0.2.204,
-        lb03 => 192.0.2.205,
-      }
-    },
-    weighted => {
-      wwwcn => {
-        service_types => ext1,
-        lb01 = [ lb01.example.com., 99 ],
-        lb02 = [ lb02.example.com., 15 ],
-        lb03 = [ lb03, 1 ],
-      }
-      wwwz => {
-        service_types => ext1,
-        lb01 => [ 192.0.2.203, 10 ],
-        lb02 => [ 192.0.2.204, 15 ],
-        lb03 => [ 192.0.2.205, 20 ],
-      }
-    }
-  }
-
-Example extfile data defining the resource + service_types specified above:
-
-  /var/tmp/ext1data:
-    192.0.2.203 => UP/300
-    192.0.2.204 => DOWN/242
-    192.0.2.205 => DOWN/102
-    lb01.example.com. => UP/60
-    lb02.example.com. => UP/30
-    lb03 => UP/45
-
-  @GDNSD_DEFPATH_STATE@/extfile/ext2data:
-    192.0.2.200 => DOWN
-    192.0.2.201 => UP
-    192.0.2.202 => UP
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-extfile> is a monitor plugin that imports
-monitor results from an external file (which is probably
-populated by some script/tool from some other monitoring
-software).
-
-=head1 MODES
-
-An extfile service_type can operate in one of two basic
-modes:
-
-=over 4
-
-=item Monitor Mode (default)
-
-In monitor mode, the standard parameter C<interval> is used
-as a repeating timer.  At each interval, the file is loaded
-for state updates (but any direct TTL values in the file are
-ignored).
-
-The updates from the file are fed into the standard core
-monitoring system by the same mechanisms as normal monitoring
-plugins (e.g. http_status).  This means they will be subject
-to the standard anti-flap measures via the standard threshold
-parameters (C<up_thresh>, C<down_thresh>, C<ok_thresh>)
-before affecting the final status seen by resolution plugins.
-
-This mode is appropriate if the updates being processed are
-relatively-raw updates from individual monitor checks.
-
-=item Direct Mode
-
-In direct mode, the standard parameter C<interval> is used
-only as a B<hint> to the filesystem-watching code to try
-to check for updates no less often than the supplied interval.
-However in many cases (especially e.g. Linux with C<inotify()>
-support) updates to the file may be picked up much sooner, perhaps
-nearly instantly.
-
-There will be a short (~1 second) settling delay after detecting
-any update in order to coalesce any rapid-fire updates into a
-single transaction.
-
-The results contained in the file (state and/or TTL per-resource)
-are applied directly as final monitoring results and made immediately
-available to resolution plugins for decision-making.
-
-This mode is appropriate if the updates are from processed monitoring
-results that have already been through e.g. anti-flap measures
-before reaching gdnsd.
-
-=back
-
-=head1 FILE FORMAT
-
-The file is formatted using the same C<vscf> language that's used
-for the main config file and the geoip nets databases.  The expected
-data format is a simple key-value hash at the top level, where the
-keys are the monitored IP address or CNAME values from the monitor
-plugins and the values are of the form form C<state[/ttl]>, where
-state is either C<UP> or C<DOWN> and the optional ttl is an integer
-ttl value.  TTL values are only used for C<direct>-mode service_types;
-the TTL is calculated in the normal fashion based on intervals and
-thresholds for C<monitor>-mode.
-
-=head1 CONFIGURATION - PER-SERVICE-TYPE
-
-The universal, plugin-neutral service_type parameters all apply
-in their usual sense: C<up_thresh>, C<ok_thresh>, C<down_thresh>,
-and C<interval> (keeping in mind the notes above about how
-each mode uses C<interval>).  C<timeout> is ignored.
-extfile-specific parameters:
-
-=over 4
-
-=item B<direct>
-
-Boolean, default false.  Sets the monitoring mode to
-C<direct> if true, otherwise mode defaults to C<monitor>.
-
-=item B<file>
-
-String filename, required.  This sets the name of the file
-to load results from.  If the pathname is not absolute, it
-will be considered relative to F<@GDNSD_DEFPATH_STATE@/extfile/>.
-
-=item B<def_ttl>
-
-Integer TTL, default is max (which will be limited by zonefile
-RR TTL values).  In C<direct> mode this will be set as the monitored
-TTL if no optional TTL is supplied in the file data for a given
-resource.  It is ignored in C<monitor> mode.
-
-=item B<def_down>
-
-Boolean, default false.  This sets the default disposition of
-configured resources which are missing from the file data (which
-will generate warnings).  If true, these resources behave as if
-the file data marked them C<DOWN>, otherwise they default to C<UP>.
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-extfile.podin gdnsd-2.1.2/docs/gdnsd-plugin-extfile.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-extfile.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-extfile.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,200 @@
+
+=head1 NAME
+
+gdnsd-plugin-extfile - gdnsd plugin for importing monitor data via file
+
+=head1 SYNOPSIS
+
+Example service_types config:
+
+  service_types => {
+    ext1 => {
+      plugin => "extfile",
+      file => "/var/tmp/ext1data", # required
+      direct => true, # default false
+      def_down => false, # default false
+      def_ttl => 600, # default max (limited by zonefile RRs)
+    }
+    ext2 => {
+      plugin => "extfile",
+      file => "ext2data", # def dir: @GDNSD_DEFPATH_STATE@/extfile/
+    },
+  }
+
+Example plugin config using these service_types:
+
+  plugins => {
+    multifo => {
+      www1 => {
+        service_types => ext2,
+        lb01 => 192.0.2.200,
+        lb02 => 192.0.2.201,
+        lb03 => 192.0.2.202,
+      }
+      www2 => {
+        service_types => [ ext1, http_status ],
+        lb01 => 192.0.2.203,
+        lb02 => 192.0.2.204,
+        lb03 => 192.0.2.205,
+      }
+    },
+    weighted => {
+      wwwcn => {
+        service_types => ext1,
+        lb01 = [ lb01.example.com., 99 ],
+        lb02 = [ lb02.example.com., 15 ],
+        lb03 = [ lb03, 1 ],
+      }
+      wwwz => {
+        service_types => ext1,
+        lb01 => [ 192.0.2.203, 10 ],
+        lb02 => [ 192.0.2.204, 15 ],
+        lb03 => [ 192.0.2.205, 20 ],
+      }
+    }
+  }
+
+Example extfile data defining the resource + service_types specified above:
+
+  /var/tmp/ext1data:
+    192.0.2.203 => UP/300
+    192.0.2.204 => DOWN/242
+    192.0.2.205 => DOWN/102
+    lb01.example.com. => UP/60
+    lb02.example.com. => UP/30
+    lb03 => UP/45
+
+  @GDNSD_DEFPATH_STATE@/extfile/ext2data:
+    192.0.2.200 => DOWN
+    192.0.2.201 => UP
+    192.0.2.202 => UP
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-extfile> is a monitor plugin that imports
+monitor results from an external file (which is probably
+populated by some script/tool from some other monitoring
+software).
+
+=head1 MODES
+
+An extfile service_type can operate in one of two basic
+modes:
+
+=over 4
+
+=item Monitor Mode (default)
+
+In monitor mode, the standard parameter C<interval> is used
+as a repeating timer.  At each interval, the file is loaded
+for state updates (but any direct TTL values in the file are
+ignored).
+
+The updates from the file are fed into the standard core
+monitoring system by the same mechanisms as normal monitoring
+plugins (e.g. http_status).  This means they will be subject
+to the standard anti-flap measures via the standard threshold
+parameters (C<up_thresh>, C<down_thresh>, C<ok_thresh>)
+before affecting the final status seen by resolution plugins.
+
+This mode is appropriate if the updates being processed are
+relatively-raw updates from individual monitor checks.
+
+=item Direct Mode
+
+In direct mode, the standard parameter C<interval> is used
+only as a B<hint> to the filesystem-watching code to try
+to check for updates no less often than the supplied interval.
+However in many cases (especially e.g. Linux with C<inotify()>
+support) updates to the file may be picked up much sooner, perhaps
+nearly instantly.
+
+There will be a short (~1 second) settling delay after detecting
+any update in order to coalesce any rapid-fire updates into a
+single transaction.
+
+The results contained in the file (state and/or TTL per-resource)
+are applied directly as final monitoring results and made immediately
+available to resolution plugins for decision-making.
+
+This mode is appropriate if the updates are from processed monitoring
+results that have already been through e.g. anti-flap measures
+before reaching gdnsd.
+
+=back
+
+=head1 FILE FORMAT
+
+The file is formatted using the same C<vscf> language that's used
+for the main config file and the geoip nets databases.  The expected
+data format is a simple key-value hash at the top level, where the
+keys are the monitored IP address or CNAME values from the monitor
+plugins and the values are of the form form C<state[/ttl]>, where
+state is either C<UP> or C<DOWN> and the optional ttl is an integer
+ttl value.  TTL values are only used for C<direct>-mode service_types;
+the TTL is calculated in the normal fashion based on intervals and
+thresholds for C<monitor>-mode.
+
+=head1 CONFIGURATION - PER-SERVICE-TYPE
+
+The universal, plugin-neutral service_type parameters all apply
+in their usual sense: C<up_thresh>, C<ok_thresh>, C<down_thresh>,
+and C<interval> (keeping in mind the notes above about how
+each mode uses C<interval>).  C<timeout> is ignored.
+extfile-specific parameters:
+
+=over 4
+
+=item B<direct>
+
+Boolean, default false.  Sets the monitoring mode to
+C<direct> if true, otherwise mode defaults to C<monitor>.
+
+=item B<file>
+
+String filename, required.  This sets the name of the file
+to load results from.  If the pathname is not absolute, it
+will be considered relative to F<@GDNSD_DEFPATH_STATE@/extfile/>.
+
+=item B<def_ttl>
+
+Integer TTL, default is max (which will be limited by zonefile
+RR TTL values).  In C<direct> mode this will be set as the monitored
+TTL if no optional TTL is supplied in the file data for a given
+resource.  It is ignored in C<monitor> mode.
+
+=item B<def_down>
+
+Boolean, default false.  This sets the default disposition of
+configured resources which are missing from the file data (which
+will generate warnings).  If true, these resources behave as if
+the file data marked them C<DOWN>, otherwise they default to C<UP>.
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-extmon.pod gdnsd-2.1.2/docs/gdnsd-plugin-extmon.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-extmon.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-extmon.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,174 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-extmon - gdnsd plugin for monitoring via external commands
-
-=head1 SYNOPSIS
-
-Example plugin config:
-
-  service_types => {
-    pingit => {
-      plugin => "extmon",
-      timeout => 5,
-      cmd => ["/bin/ping", "-w", "2", "-c", "2", "%%ITEM%%"]
-    },
-    svc_alwaysok => {
-      plugin => "extmon",
-      timeout => 1,
-      direct => true,
-      cmd => ["/bin/sh", "-c", "exit 0"]
-    },
-    svc_alwaysfail_via_timeout => {
-      plugin => "extmon",
-      timeout => 2,
-      cmd => ["/bin/sh", "-c", "sleep 5"]
-    }
-  }
-
-  # optional, if installed path confuses the daemon...
-  plugins => {
-    extmon => { helper_path => "@GDNSD_DEFPATH_LIBEXEC@/gdnsd_extmon_helper" }
-  }
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-extmon> allows you to configure external commands
-to provide monitoring feedback to the dynamic address plugins.
-
-=head1 CONFIGURATION - GLOBAL
-
-These are plugin-global settings which are configured within
-C<plugins =E<gt> { extmon =E<gt> { ... } }>.
-
-=over 4
-
-=item B<helper_path>
-
-String pathname, optional.
-
-Normally, this plugin will successfully locate its helper
-binary F<gdnsd_extmon_helper> in the installation libexec
-directory at F<@GDNSD_DEFPATH_LIBEXEC@/gdnsd_extmon_helper>.
-If for some reason it can't do so, e.g. due to a relocated
-installation, you can set an explicit full pathname to the
-helper here.  Note that in this case you're probably also
-having to set the daemon-global config option
-C<plugin_search_path> as well, since locating plugin
-objects uses similar mechanisms to find the installation's
-plugin library path (default F<@GDNSD_DEFPATH_LIB@>) as well.
-
-=item B<helper_failure_action>
-
-String, either C<stasis> or C<kill_daemon>.
-Default is C<stasis>.
-
-This configures the behavior of the plugin if the helper
-process F<gdnsd_extmon_helper> unexpectedly dies, which prevents
-the gathering of any further legitimate monitoring state updates.
-
-Regardless of this setting, there will be at least one
-syslog message indicating the failure.
-
-If set to C<stasis>, all monitored states are left as-is with
-no further updates.  The downside is that unless someone notices
-the syslog message, this failure mode is hard to notice.
-
-If set to C<kill_daemon>, the whole gdnsd daemon will fail fatally.
-
-=back
-
-=head1 CONFIGURATION - PER-SERVICE-TYPE
-
-The universal, plugin-neutral service_type parameters all apply
-in their usual sense: C<up_thresh>, C<ok_thresh>, C<down_thresh>,
-C<interval>, C<plugin>, and C<timeout>.  See L<gdnsd.config(5)> for
-basic information on these.  The following are specific to this
-C<extmon> plugin:
-
-=over 4
-
-=item B<cmd>
-
-Array of one or more strings, required.
-
-This sets the command and arguments to execute for the monitoring check.
-The array is passed directly to C<execv()> for execution (with re-use of
-the first element as the pathname to execute).  If you need to use shell
-facilities, start the argument list with e.g. C<"/bin/sh", "-c", ...>.
-
-All argument strings are searched for the magic string C<%%ITEM%%> (which
-can appear multiple times per argument).  Everywhere this magic string is
-found, the IP address or CNAME text of the resource being monitored will
-be substituted in its place.
-
-The command must exit with an exit value of zero for success or non-zero
-for failure.
-
-=item B<direct>
-
-Boolean, default false.
-
-Normally extmon's results are processed by the same anti-flap state machine
-used for traditional monitors like the HTTP and TCP monitoring plugins.  This
-means the results are subject to the various thresholds (C<ok_thresh>, C<up_thresh>,
-C<down_thresh>) and it may take some time for a new persistent state to actually
-affect resolution.
-
-If C<direct> is set to C<true>, the results of extmon's monitoring are applied
-directly and immediately as the final state of the monitored resources after
-every monitoring check.  If your command flaps back and forther between success
-and failure on every run, so will the internal state and so will the resulting
-changes in resolution.  Useful if extmon is actually gathering state from an
-external complex monitoring environment that has already taken care of things
-like anti-flap measures.
-
-=back
-
-=head1 EXECUTION ENVIRONMENT
-
-The plugin launches a helper binary F<gdnsd_extmon_helper>
-during daemon startup, and this helper does
-the actual runtime command executions.  It manages the timeouts
-and intervals and feeds results back to the plugin over a pipe.  This
-communication is one-way at runtime (no daemon -> helper traffic)
-for security reasons (to help ensure that a compromised daemon can't
-easily leverage the helper to muck with the execution of the external
-commands).  This separation also prevents a class of functional and
-security bugs related to mixing runtime pthreads with routine forking
-to exec the child processes.
-
-The executed scripts will run with the same userid the daemon normally
-drops privileges to.
-
-The stdout, stdin, and stderr descriptors will usually be
-set to F</dev/null>.  stdout and stderr may be open to the current
-tty if the main daemon was started in foreground debugging mode
-via C<-f start>.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-extmon.podin gdnsd-2.1.2/docs/gdnsd-plugin-extmon.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-extmon.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-extmon.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,174 @@
+
+=head1 NAME
+
+gdnsd-plugin-extmon - gdnsd plugin for monitoring via external commands
+
+=head1 SYNOPSIS
+
+Example plugin config:
+
+  service_types => {
+    pingit => {
+      plugin => "extmon",
+      timeout => 5,
+      cmd => ["/bin/ping", "-w", "2", "-c", "2", "%%ITEM%%"]
+    },
+    svc_alwaysok => {
+      plugin => "extmon",
+      timeout => 1,
+      direct => true,
+      cmd => ["/bin/sh", "-c", "exit 0"]
+    },
+    svc_alwaysfail_via_timeout => {
+      plugin => "extmon",
+      timeout => 2,
+      cmd => ["/bin/sh", "-c", "sleep 5"]
+    }
+  }
+
+  # optional, if installed path confuses the daemon...
+  plugins => {
+    extmon => { helper_path => "@GDNSD_DEFPATH_LIBEXEC@/gdnsd_extmon_helper" }
+  }
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-extmon> allows you to configure external commands
+to provide monitoring feedback to the dynamic address plugins.
+
+=head1 CONFIGURATION - GLOBAL
+
+These are plugin-global settings which are configured within
+C<plugins =E<gt> { extmon =E<gt> { ... } }>.
+
+=over 4
+
+=item B<helper_path>
+
+String pathname, optional.
+
+Normally, this plugin will successfully locate its helper
+binary F<gdnsd_extmon_helper> in the installation libexec
+directory at F<@GDNSD_DEFPATH_LIBEXEC@/gdnsd_extmon_helper>.
+If for some reason it can't do so, e.g. due to a relocated
+installation, you can set an explicit full pathname to the
+helper here.  Note that in this case you're probably also
+having to set the daemon-global config option
+C<plugin_search_path> as well, since locating plugin
+objects uses similar mechanisms to find the installation's
+plugin library path (default F<@GDNSD_DEFPATH_LIB@>) as well.
+
+=item B<helper_failure_action>
+
+String, either C<stasis> or C<kill_daemon>.
+Default is C<stasis>.
+
+This configures the behavior of the plugin if the helper
+process F<gdnsd_extmon_helper> unexpectedly dies, which prevents
+the gathering of any further legitimate monitoring state updates.
+
+Regardless of this setting, there will be at least one
+syslog message indicating the failure.
+
+If set to C<stasis>, all monitored states are left as-is with
+no further updates.  The downside is that unless someone notices
+the syslog message, this failure mode is hard to notice.
+
+If set to C<kill_daemon>, the whole gdnsd daemon will fail fatally.
+
+=back
+
+=head1 CONFIGURATION - PER-SERVICE-TYPE
+
+The universal, plugin-neutral service_type parameters all apply
+in their usual sense: C<up_thresh>, C<ok_thresh>, C<down_thresh>,
+C<interval>, C<plugin>, and C<timeout>.  See L<gdnsd.config(5)> for
+basic information on these.  The following are specific to this
+C<extmon> plugin:
+
+=over 4
+
+=item B<cmd>
+
+Array of one or more strings, required.
+
+This sets the command and arguments to execute for the monitoring check.
+The array is passed directly to C<execv()> for execution (with re-use of
+the first element as the pathname to execute).  If you need to use shell
+facilities, start the argument list with e.g. C<"/bin/sh", "-c", ...>.
+
+All argument strings are searched for the magic string C<%%ITEM%%> (which
+can appear multiple times per argument).  Everywhere this magic string is
+found, the IP address or CNAME text of the resource being monitored will
+be substituted in its place.
+
+The command must exit with an exit value of zero for success or non-zero
+for failure.
+
+=item B<direct>
+
+Boolean, default false.
+
+Normally extmon's results are processed by the same anti-flap state machine
+used for traditional monitors like the HTTP and TCP monitoring plugins.  This
+means the results are subject to the various thresholds (C<ok_thresh>, C<up_thresh>,
+C<down_thresh>) and it may take some time for a new persistent state to actually
+affect resolution.
+
+If C<direct> is set to C<true>, the results of extmon's monitoring are applied
+directly and immediately as the final state of the monitored resources after
+every monitoring check.  If your command flaps back and forther between success
+and failure on every run, so will the internal state and so will the resulting
+changes in resolution.  Useful if extmon is actually gathering state from an
+external complex monitoring environment that has already taken care of things
+like anti-flap measures.
+
+=back
+
+=head1 EXECUTION ENVIRONMENT
+
+The plugin launches a helper binary F<gdnsd_extmon_helper>
+during daemon startup, and this helper does
+the actual runtime command executions.  It manages the timeouts
+and intervals and feeds results back to the plugin over a pipe.  This
+communication is one-way at runtime (no daemon -> helper traffic)
+for security reasons (to help ensure that a compromised daemon can't
+easily leverage the helper to muck with the execution of the external
+commands).  This separation also prevents a class of functional and
+security bugs related to mixing runtime pthreads with routine forking
+to exec the child processes.
+
+The executed scripts will run with the same userid the daemon normally
+drops privileges to.
+
+The stdout, stdin, and stderr descriptors will usually be
+set to F</dev/null>.  stdout and stderr may be open to the current
+tty if the main daemon was started in foreground debugging mode
+via C<-f start>.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-geoip.pod gdnsd-2.1.2/docs/gdnsd-plugin-geoip.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-geoip.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-geoip.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,616 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-geoip - gdnsd meta-plugin for GSLB + failover via MaxMind's
-GeoIP databases
-
-=head1 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, 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 => {
-        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 => 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
-        }
-      }
-    }
-  }}
-
-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
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-geoip> uses MaxMind's GeoIP binary databases to
-map address and CNAME results based on geography and
-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 C<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.
-
-=head1 PLUGIN_METAFO
-
-The documentation for L<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.  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.
-
-=head1 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 F<geoip> subdirectory
-of the daemon's configuration directory (default F<@GDNSD_DEFPATH_CONFIG@>).
-You can load from other locations by specifying absolute file paths.
-
-=head1 CONFIGURATION - TOP-LEVEL
-
-The top level of the geoip plugin's configuration (i.e. C<plugins =E<gt> {
-geoip =E<gt> { ... } }>) supports only two special keys, both of which are
-required and expanded upon in detail in the next two sections: C<maps>, and
-C<resources>.  The C<maps> section defines one or more named mappings of
-location information from GeoIP binary databases to ordered subsets of
-datacenter names.  The C<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 C<resources> stanza, acting as per-resource
-defaults for anything not defined explicitly there.
-
-=head1 CONFIGURATION - MAPS
-
-The C<maps> stanza supports one special configuration key at the top level:
-
-=head2 C<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 C<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. C<EU =E<gt> { CH
-=E<gt> { 07 =E<gt> { Geneva =E<gt> [ ... ] } } } }>.  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. C<EU
-=E<gt> { CH =E<gt> { Geneve =E<gt> { Geneva =E<gt> [ ... ] } } } }>.  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 C<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:
-L<http://www.maxmind.com/download/geoip/misc/region_codes.csv>.
-
-=head1 CONFIGURATION - PER-MAP
-
-All other C<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:
-
-=head2 C<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.
-
-=head2 C<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
-C<geoip_db>.  It must be a V4-format database, and C<geoip_db> must be
-defined as a V6-format database.  In all other respects, it is similar to
-C<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.
-
-=head2 C<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).
-
-=head2 C<city_no_region = true>
-
-Boolean, default C<false>.  If this key is set to C<true> and C<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 C<continent =E<gt> country =E<gt> city> rather than
-C<continent =E<gt> country =E<gt> region =E<gt> city>.
-
-=head2 C<nets = { ... }>
-
-Key-value hash, optional (see below for alternate form).  If specified, the
-contents should be key-value pairs of C<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.
-
-=head2 C<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.
-
-=head2 C<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 C<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. C<[ dc03, dc01,
-dc04 ]>), or a sub-hash containing a deeper level of distinction.  At each
-layer, a special key named C<default> is available, which sets the default
-for everything within the current scope.  The top-level default itself
-defaults to the ordered list from C<datacenters> in the normal case.  If
-the entire C<map> stanza is missing or empty, you just get the default
-behavior of C<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: C<AF> for Africa, C<AS>
-for Asia, C<NA> for North America, C<SA> for South America, C<EU> for
-Europe, C<OC> for Oceania, and C<AN> for Antarctica.  There is also an
-eighth continent-level code which is, literally, C<-->.  This is a sort of
-fallback "no information available" continent code, and it contains the
-special country codes C<A1>, C<A2>, C<O1>, and C<-->, 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 C<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 C<default>) available at
-all levels of the map hierarchy, a boolean named C<skip_level>, default
-C<false>.  If set within the hierarchical C<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 C<city_no_region>
-option, so e.g. setting that option and specifying C<skip_level> at the
-country-level would result in no further information being available within
-that country (as C<skip_level> would skip the remaining layer of city data).
-
-=head1 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 C<map>.  It can still be
-mixed with C<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 C<auto_dc_coords>, which
-enables city-auto-mode.
-
-=over 4
-
-=item C<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 C<datacenters>, with their
-values set to an array of C<[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
-C<auto> becomes a legal "datacenter list" in the C<map> stanza.
-
-With city-auto-mode enabled, the top-level map C<default> defaults to
-C<auto>, but can be overridden with a manual list.  For any location that
-maps to C<auto>, the coordinates specified here in C<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
-C<auto_dc_coords>, those datacenters will not be used in automatic results,
-but will still be available for manual use via C<map> and/or C<nets>
-entries.
-
-=item C<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).
-
-=back
-
-Under city-auto-mode, when the top-level default is (explicitly or
-implicitly) C<auto>, there is still a fallback static ordering which is the
-whole ordered C<datacenters> list, which is the normal static default
-C<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).
-
-=head1 MAP TESTING
-
-A binary program C<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 L<gdnsd_geoip_test(1)>.
-
-=head1 CONFIGURATION - RESOURCES
-
-Resource-level configuration within the C<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.  The only real difference
-is that metafo's per-resource C<datacenters> array is replaced with
-C<map =E<gt> mapname>, which references one of the maps defined in the
-C<maps> stanza, described in detail earlier.  The set of defined
-datacenters in the C<dcmap> stanza must match the total set of datacenters
-defined by the referenced map.
-
-=head1 META-PLUGIN INTERACTION
-
-Both of the meta-plugins (C<metafo> and C<geoip>) can reference their own
-as well as each others' resources by direct reference within a C<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, C<geoip> can synthesize configuration for C<metafo>
-resources, but the reverse does not hold; C<metafo> cannot synthesize
-configuration for C<geoip> resources.
-
-=head1 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
-C<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 C<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 C<nets>
-entries which happen to be a supernet of any v4-like spaces will *not*
-unduly affect v4-like lookups.  There is no functional difference between
-v4compat and native v4 forms in C<nets>, e.g. C<192.0.2.0/24> and
-C<::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.
-
-=head1 ANOTHER CONFIG EXAMPLE
-
-A relatively-maximal example config, showing the interaction of valid
-C<maps> and C<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
-
-=head1 EXAMPLE OF METAFO->GEOIP CITY-AUTO-MODE w/ LAST RESORT CNAME
-
-  plugins => {
-    geoip => {
-      maps => {
-        auto_map => {
-          geoip_db => GeoIPCityv6.dat,
-          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 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
-
-=head1 SEE ALSO
-
-L<gdnsd-plugin-metafo(8)>, L<gdnsd_geoip_test(1)>, L<gdnsd.config(5)>,
-L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-geoip.podin gdnsd-2.1.2/docs/gdnsd-plugin-geoip.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-geoip.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-geoip.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,616 @@
+
+=head1 NAME
+
+gdnsd-plugin-geoip - gdnsd meta-plugin for GSLB + failover via MaxMind's
+GeoIP databases
+
+=head1 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, 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 => {
+        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 => 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
+        }
+      }
+    }
+  }}
+
+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
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-geoip> uses MaxMind's GeoIP binary databases to
+map address and CNAME results based on geography and
+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 C<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.
+
+=head1 PLUGIN_METAFO
+
+The documentation for L<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.  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.
+
+=head1 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 F<geoip> subdirectory
+of the daemon's configuration directory (default F<@GDNSD_DEFPATH_CONFIG@>).
+You can load from other locations by specifying absolute file paths.
+
+=head1 CONFIGURATION - TOP-LEVEL
+
+The top level of the geoip plugin's configuration (i.e. C<plugins =E<gt> {
+geoip =E<gt> { ... } }>) supports only two special keys, both of which are
+required and expanded upon in detail in the next two sections: C<maps>, and
+C<resources>.  The C<maps> section defines one or more named mappings of
+location information from GeoIP binary databases to ordered subsets of
+datacenter names.  The C<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 C<resources> stanza, acting as per-resource
+defaults for anything not defined explicitly there.
+
+=head1 CONFIGURATION - MAPS
+
+The C<maps> stanza supports one special configuration key at the top level:
+
+=head2 C<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 C<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. C<EU =E<gt> { CH
+=E<gt> { 07 =E<gt> { Geneva =E<gt> [ ... ] } } } }>.  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. C<EU
+=E<gt> { CH =E<gt> { Geneve =E<gt> { Geneva =E<gt> [ ... ] } } } }>.  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 C<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:
+L<http://www.maxmind.com/download/geoip/misc/region_codes.csv>.
+
+=head1 CONFIGURATION - PER-MAP
+
+All other C<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:
+
+=head2 C<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.
+
+=head2 C<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
+C<geoip_db>.  It must be a V4-format database, and C<geoip_db> must be
+defined as a V6-format database.  In all other respects, it is similar to
+C<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.
+
+=head2 C<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).
+
+=head2 C<city_no_region = true>
+
+Boolean, default C<false>.  If this key is set to C<true> and C<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 C<continent =E<gt> country =E<gt> city> rather than
+C<continent =E<gt> country =E<gt> region =E<gt> city>.
+
+=head2 C<nets = { ... }>
+
+Key-value hash, optional (see below for alternate form).  If specified, the
+contents should be key-value pairs of C<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.
+
+=head2 C<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.
+
+=head2 C<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 C<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. C<[ dc03, dc01,
+dc04 ]>), or a sub-hash containing a deeper level of distinction.  At each
+layer, a special key named C<default> is available, which sets the default
+for everything within the current scope.  The top-level default itself
+defaults to the ordered list from C<datacenters> in the normal case.  If
+the entire C<map> stanza is missing or empty, you just get the default
+behavior of C<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: C<AF> for Africa, C<AS>
+for Asia, C<NA> for North America, C<SA> for South America, C<EU> for
+Europe, C<OC> for Oceania, and C<AN> for Antarctica.  There is also an
+eighth continent-level code which is, literally, C<-->.  This is a sort of
+fallback "no information available" continent code, and it contains the
+special country codes C<A1>, C<A2>, C<O1>, and C<-->, 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 C<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 C<default>) available at
+all levels of the map hierarchy, a boolean named C<skip_level>, default
+C<false>.  If set within the hierarchical C<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 C<city_no_region>
+option, so e.g. setting that option and specifying C<skip_level> at the
+country-level would result in no further information being available within
+that country (as C<skip_level> would skip the remaining layer of city data).
+
+=head1 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 C<map>.  It can still be
+mixed with C<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 C<auto_dc_coords>, which
+enables city-auto-mode.
+
+=over 4
+
+=item C<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 C<datacenters>, with their
+values set to an array of C<[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
+C<auto> becomes a legal "datacenter list" in the C<map> stanza.
+
+With city-auto-mode enabled, the top-level map C<default> defaults to
+C<auto>, but can be overridden with a manual list.  For any location that
+maps to C<auto>, the coordinates specified here in C<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
+C<auto_dc_coords>, those datacenters will not be used in automatic results,
+but will still be available for manual use via C<map> and/or C<nets>
+entries.
+
+=item C<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).
+
+=back
+
+Under city-auto-mode, when the top-level default is (explicitly or
+implicitly) C<auto>, there is still a fallback static ordering which is the
+whole ordered C<datacenters> list, which is the normal static default
+C<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).
+
+=head1 MAP TESTING
+
+A binary program C<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 L<gdnsd_geoip_test(1)>.
+
+=head1 CONFIGURATION - RESOURCES
+
+Resource-level configuration within the C<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.  The only real difference
+is that metafo's per-resource C<datacenters> array is replaced with
+C<map =E<gt> mapname>, which references one of the maps defined in the
+C<maps> stanza, described in detail earlier.  The set of defined
+datacenters in the C<dcmap> stanza must match the total set of datacenters
+defined by the referenced map.
+
+=head1 META-PLUGIN INTERACTION
+
+Both of the meta-plugins (C<metafo> and C<geoip>) can reference their own
+as well as each others' resources by direct reference within a C<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, C<geoip> can synthesize configuration for C<metafo>
+resources, but the reverse does not hold; C<metafo> cannot synthesize
+configuration for C<geoip> resources.
+
+=head1 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
+C<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 C<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 C<nets>
+entries which happen to be a supernet of any v4-like spaces will *not*
+unduly affect v4-like lookups.  There is no functional difference between
+v4compat and native v4 forms in C<nets>, e.g. C<192.0.2.0/24> and
+C<::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.
+
+=head1 ANOTHER CONFIG EXAMPLE
+
+A relatively-maximal example config, showing the interaction of valid
+C<maps> and C<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
+
+=head1 EXAMPLE OF METAFO->GEOIP CITY-AUTO-MODE w/ LAST RESORT CNAME
+
+  plugins => {
+    geoip => {
+      maps => {
+        auto_map => {
+          geoip_db => GeoIPCityv6.dat,
+          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 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
+
+=head1 SEE ALSO
+
+L<gdnsd-plugin-metafo(8)>, L<gdnsd_geoip_test(1)>, L<gdnsd.config(5)>,
+L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-http_status.pod gdnsd-2.1.2/docs/gdnsd-plugin-http_status.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-http_status.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-http_status.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,81 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-http_status - gdnsd HTTP monitoring plugin
-
-=head1 SYNOPSIS
-
-Example http_status service_types config:
-
-  service_types => {
-    webcheck => {
-      plugin => http_status,
-      port => 8080,             # default 80
-      url_path => /checkme      # default '/'
-      vhost => www.example.com  # default none
-      ok_codes => [ 200, 301 ], # default [ 200 ]
-      up_thresh => 20,
-      ok_thresh => 10,
-      down_thresh => 10,
-      interval => 10,
-      timeout => 3,
-    }
-  }
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-http_status> is a monitoring plugin that
-checks basic HTTP service.
-
-=head1 PARAMETERS
-
-=over 4
-
-=item port
-
-The numeric port number to connect on, default C<80>.
-
-=item url_path
-
-The string URL to GET from the remote service, default C</>
-
-=item vhost
-
-The string hostname to supply as a C<Host:> header with the
-request.  No default.  If unspecified, no C<Host:> header is
-sent at all.
-
-=item ok_codes
-
-An array of integer HTTP status codes which are acceptable
-as positive responses.  The default is C<[ 200 ]>.
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-http_status.podin gdnsd-2.1.2/docs/gdnsd-plugin-http_status.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-http_status.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-http_status.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,81 @@
+
+=head1 NAME
+
+gdnsd-plugin-http_status - gdnsd HTTP monitoring plugin
+
+=head1 SYNOPSIS
+
+Example http_status service_types config:
+
+  service_types => {
+    webcheck => {
+      plugin => http_status,
+      port => 8080,             # default 80
+      url_path => /checkme      # default '/'
+      vhost => www.example.com  # default none
+      ok_codes => [ 200, 301 ], # default [ 200 ]
+      up_thresh => 20,
+      ok_thresh => 10,
+      down_thresh => 10,
+      interval => 10,
+      timeout => 3,
+    }
+  }
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-http_status> is a monitoring plugin that
+checks basic HTTP service.
+
+=head1 PARAMETERS
+
+=over 4
+
+=item port
+
+The numeric port number to connect on, default C<80>.
+
+=item url_path
+
+The string URL to GET from the remote service, default C</>
+
+=item vhost
+
+The string hostname to supply as a C<Host:> header with the
+request.  No default.  If unspecified, no C<Host:> header is
+sent at all.
+
+=item ok_codes
+
+An array of integer HTTP status codes which are acceptable
+as positive responses.  The default is C<[ 200 ]>.
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-metafo.pod gdnsd-2.1.2/docs/gdnsd-plugin-metafo.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-metafo.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-metafo.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,289 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-metafo - gdnsd plugin for address meta-failover
-
-=head1 SYNOPSIS
-
-Minimal example gdnsd config file using this plugin:
-
-  plugins => {
-    metafo => {
-      resources => {
-        prod_www => {
-          datacenters => [ dc-01, dc-02, dc-03 ]
-          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 ]
-          }
-        },
-        prod_foo => {
-          datacenters => [ dc-01, dc-02, dc-bk ]
-          dcmap => {
-            dc-01 => { lb01 => 192.0.1.1, lb02 => 192.0.1.2 }
-            dc-02 => [ 192.0.5.1, 192.0.5.2, 192.0.5.3 ]
-            dc-bk => fallback.static.cname.example.com.
-          }
-        }
-      }
-    }
-  }
-
-Example zonefile RRs:
-
-  www      600 DYNA metafo!prod_www
-  www-dc01 600 DYNA metafo!prod_www/dc-01
-  foo      700 DYNC metafo!prod_foo
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-metafo> is a meta-plugin.  It does static-ordered
-address failover between multiple C<datacenters> (which may or may not
-correspond with real datacenters, it's just a convenient label).
-Each datacenter is defined in terms of other plugins such as
-C<multifo>, C<weighted>, etc, as described below.
-
-=head1 CONFIGURATION - TOP-LEVEL
-
-The top level of the metafo plugin's configuration (i.e. C<plugins =E<gt> {
-metafo =E<gt> { ... } }>) supports only one fixed, required key,
-C<resources>, whose value must be a hash.  The contents of C<resources> is
-a key per named resource, with the value defining that resource.
-
-Any other keys present at the top level will be inherited down inside of
-each per-resource hash inside the C<resources> stanza, acting as
-per-resource defaults for anything not defined explicitly there, as
-explained below.
-
-=head1 CONFIGURATION - RESOURCES
-
-All keys within the resources stanza represent named resources, which can
-be referenced by C<DYNA> RRs in zonefiles (e.g. C<www DYNA
-metafo!resource_name>).  Each resource's value must be a key-value hash
-configuring the resource itself.  Lightweight structural example:
-
-  plugins => {
-    metafo => {
-      resources => { resA => { ... }, resB => { ... } }
-    }
-  }
-
-Within a resource, there are only two specifically meaningful keys:
-
-=over 4
-
-=item C<datacenters = [ A, B, C, ... ]>
-
-Array of datacenter names, required.  This is the set of datacenter name
-labels used for this resource, in the order they will be checked for
-failover.
-
-=item C<dcmap = { ... }>
-
-Hash, required.  The C<dcmap> is a key-value hash where the keys must be
-exactly the list of datacenters defined in this resource's C<datacenters>
-list, and the values defined the address configuration of each datacenter.
-Another minimal structural example down to this level:
-
-  plugins => {
-    metafo => {
-      resources => {
-        resA => {
-          datacenters => [ dc01, dc02 ],
-          dcmap => {
-            dc01 => ???
-            dc02 => ???
-          }
-        }
-      }
-    }
-  }
-
-
-There are several forms the per-datacenter values (C<???> above) can take,
-documented in the next section.
-
-=back
-
-Any keys other than C<datacenters> and C<dcmap> at the per-resource level
-serve as inherited defaults for each per-datacenter configuration inside of
-the C<dcmap>.
-
-=head1 PER-DATACENTER RESOLUTION
-
-The value of the datacenters within the C<dcmap> section of a resource can
-take several forms.  It is important to understand that for the most part,
-plugin_metafo does not deal with this level of results itself, but instead
-delegates the work at this scope to other plugins.  These sub-plugins, in
-turn, also notify metafo of complete failure at their level, which is the
-information metafo uses to know to fail over to the next datacenter in the
-list.
-
-The most direct and obvious way to do this is with a direct reference of
-the form C<%plugin!resource>, as shown here:
-
-  plugins => {
-    metafo => {
-      resources => {
-        resA => {
-          datacenters => [ dc1, dc2 ],
-          dcmap => {
-            dc1 => %multifo!res_mfo1
-            dc2 => %multifo!res_mfo2
-          }
-        }
-      }
-    }
-    multifo => {
-      res_mfo1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
-      res_mfo2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
-    }
-  }
-
-However, to make life simpler in the simple cases, plugin_metafo can
-synthesize the lower-level plugin's configuration from a hash, like so:
-
-  plugins => {
-    metafo => {
-      resources => {
-        resA => {
-          datacenters => [ dc1, dc2 ],
-          dcmap => {
-            dc1 => { plugin => multifo, lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
-            dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
-            # the above are effectively treated as:
-            # dc1 => %multifo!metafo_resA_dc1
-            # dc2 => %multifo!metafo_resA_dc2
-          }
-        }
-      }
-    }
-    # below does not exist in your configfile, but is what plugin_metafo
-    #   synthesizes to support the above:
-    #multifo => {
-    #  metafo_resA_dc1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
-    #  metafo_resA_dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
-    #}
-  }
-
-Within a hash like the above, the special key C<plugin> will be stripped
-out internally and used to name the plugin we synthesize the config for.
-C<plugin> defaults to C<multifo> if not specified.  Note that C<plugin>
-could also be specified at the resource level (just inside of the C<resA>
-stanza) to change the default for all C<dcmap> entries in one resource, and
-could also be specified at the outer-most scope (just inside the C<metafo>
-stanza) to change the default for all resources.
-
-The defaulted-down C<plugin> is also the default for the direct-reference
-C<%plugin!resource> form discussed earlier.  With the correct default
-plugin name, it can be shortened to just C<!resource>.
-
-The same sort of key-value inheritance scheme (top-level -> per-resource
-level -> per-datacenter level) can also be used for any other parameter in
-synthesized resource configurations specific to the per-datacenter
-plugin(s) you are using.  A common example would be the C<service_types>
-parameter that most plugins which support monitored address results have.
-Note that these other values (e.g. service_types) would only apply to
-synthesized resources, B<not> to direct-references like C<%multifo!foo>,
-which must be configured entirely separately within that plugin's config.
-
-There are three other possible shortcut values for datacenters: a single
-direct address, an array of addresses, or a single CNAME hostname.  If a
-single IP address or an array of IP addresses are specified, plugin_metafo
-will synthesize a hash from them with the plugin forced to C<multifo>
-(since it cannot know the syntax of hashes for all other plugins, which
-may differ), and give them address labels C<1>, C<2>, etc.
-
-If the value for a datacenter is a single CNAME hostname, no sub-plugin
-is used, and that CNAME result is returned directly.  Note that any
-resource with such an entry can only be used with C<DYNC> RRs, and not
-C<DYNA> RRs (as is the case if any subplugin's configuration is capable
-of returning CNAME data).
-
-A much more complete example, showing off most of the features above:
-
-  plugins => {
-    metafo => {
-      plugin => multifo # change default for all resources
-      service_types => [ bar ] # default service_types for synthesized below
-      resources => {
-        resA => {
-          plugin => multifo # change default for this resource
-          service_types => [foo, bar] # services types for synthesized below:
-          datacenters => [ dc1, dc2, dc3, dc4, dc5, dc6, dc7, dc8 ],
-          dcmap => {
-            dc1 => { plugin => multifo, lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
-            dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
-            dc3 => %simplefo!foo
-            dc4 => { plugin => simplefo, primary => 192.0.2.100, secondary => 192.0.2.101 }
-            dc5 => !bar
-            dc6 => 192.0.2.150
-            dc7 => [ 192.0.2.180, 192.0.2.181 ]
-            dc8 => last.resort.example.com.
-          }
-        }
-      }
-    }
-    # below, commented-out sections show configuration synthesized
-    #   by plugin_metafo, whereas the rest are direct-references that
-    #   had to be manually specified here:
-    multifo => {
-      # metafo_resA_dc1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3, service_types => [foo, bar] }
-      # metafo_resA_dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113, service_types => [foo, bar] }
-      bar => { asd => 192.0.2.77, xyz => 192.0.2.88 }
-      # metafo_resA_dc6 => { 1 => 192.0.2.150, service_types => [foo, bar] }
-      # metafo_resA_dc7 => { 1 => 192.0.2.180, 2 => 192.0.2.181, service_types => [foo, bar] }
-    }
-    simplefo => {
-      foo => { primary => 192.0.2.80, secondary => 192.0.2.81 }
-      # metafo_resA_dc4 => { primary => 192.0.2.100, secondary => 192.0.2.101, service_types => [foo, bar] }
-    }
-  }
-
-Note in the example above that C<%multifo!bar> and C<%simplefo!foo> would
-have had their default C<service_types = up> rather than the one
-specified at the metafo level, because they were not synthesized.  It would
-be up to you to keep all of the service_types in sync when using direct
-references.
-
-=head1 SYNTHETIC PER-DATACENTER RESOURCES
-
-This plugin will synthesize additional, per-datacenter resource names from
-your configuration.  They are named as C<resname/dcname>.  For example, if
-you define a metafo resource named C<prodwww> with the datacenter list
-C<[ pri, sec ]>, the resource names C<prodwww/pri> and C<prodwww/sec> will
-be sythesized and can be used in zonefile records, e.g.:
-
-  www-backup 300 DYNA metafo!prodwww/sec
-
-When used, these per-datacenter synthetic resource names cause a given
-lookup to skip the normal failover process and directly return results from
-that particular datacenter.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-metafo.podin gdnsd-2.1.2/docs/gdnsd-plugin-metafo.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-metafo.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-metafo.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,289 @@
+
+=head1 NAME
+
+gdnsd-plugin-metafo - gdnsd plugin for address meta-failover
+
+=head1 SYNOPSIS
+
+Minimal example gdnsd config file using this plugin:
+
+  plugins => {
+    metafo => {
+      resources => {
+        prod_www => {
+          datacenters => [ dc-01, dc-02, dc-03 ]
+          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 ]
+          }
+        },
+        prod_foo => {
+          datacenters => [ dc-01, dc-02, dc-bk ]
+          dcmap => {
+            dc-01 => { lb01 => 192.0.1.1, lb02 => 192.0.1.2 }
+            dc-02 => [ 192.0.5.1, 192.0.5.2, 192.0.5.3 ]
+            dc-bk => fallback.static.cname.example.com.
+          }
+        }
+      }
+    }
+  }
+
+Example zonefile RRs:
+
+  www      600 DYNA metafo!prod_www
+  www-dc01 600 DYNA metafo!prod_www/dc-01
+  foo      700 DYNC metafo!prod_foo
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-metafo> is a meta-plugin.  It does static-ordered
+address failover between multiple C<datacenters> (which may or may not
+correspond with real datacenters, it's just a convenient label).
+Each datacenter is defined in terms of other plugins such as
+C<multifo>, C<weighted>, etc, as described below.
+
+=head1 CONFIGURATION - TOP-LEVEL
+
+The top level of the metafo plugin's configuration (i.e. C<plugins =E<gt> {
+metafo =E<gt> { ... } }>) supports only one fixed, required key,
+C<resources>, whose value must be a hash.  The contents of C<resources> is
+a key per named resource, with the value defining that resource.
+
+Any other keys present at the top level will be inherited down inside of
+each per-resource hash inside the C<resources> stanza, acting as
+per-resource defaults for anything not defined explicitly there, as
+explained below.
+
+=head1 CONFIGURATION - RESOURCES
+
+All keys within the resources stanza represent named resources, which can
+be referenced by C<DYNA> RRs in zonefiles (e.g. C<www DYNA
+metafo!resource_name>).  Each resource's value must be a key-value hash
+configuring the resource itself.  Lightweight structural example:
+
+  plugins => {
+    metafo => {
+      resources => { resA => { ... }, resB => { ... } }
+    }
+  }
+
+Within a resource, there are only two specifically meaningful keys:
+
+=over 4
+
+=item C<datacenters = [ A, B, C, ... ]>
+
+Array of datacenter names, required.  This is the set of datacenter name
+labels used for this resource, in the order they will be checked for
+failover.
+
+=item C<dcmap = { ... }>
+
+Hash, required.  The C<dcmap> is a key-value hash where the keys must be
+exactly the list of datacenters defined in this resource's C<datacenters>
+list, and the values defined the address configuration of each datacenter.
+Another minimal structural example down to this level:
+
+  plugins => {
+    metafo => {
+      resources => {
+        resA => {
+          datacenters => [ dc01, dc02 ],
+          dcmap => {
+            dc01 => ???
+            dc02 => ???
+          }
+        }
+      }
+    }
+  }
+
+
+There are several forms the per-datacenter values (C<???> above) can take,
+documented in the next section.
+
+=back
+
+Any keys other than C<datacenters> and C<dcmap> at the per-resource level
+serve as inherited defaults for each per-datacenter configuration inside of
+the C<dcmap>.
+
+=head1 PER-DATACENTER RESOLUTION
+
+The value of the datacenters within the C<dcmap> section of a resource can
+take several forms.  It is important to understand that for the most part,
+plugin_metafo does not deal with this level of results itself, but instead
+delegates the work at this scope to other plugins.  These sub-plugins, in
+turn, also notify metafo of complete failure at their level, which is the
+information metafo uses to know to fail over to the next datacenter in the
+list.
+
+The most direct and obvious way to do this is with a direct reference of
+the form C<%plugin!resource>, as shown here:
+
+  plugins => {
+    metafo => {
+      resources => {
+        resA => {
+          datacenters => [ dc1, dc2 ],
+          dcmap => {
+            dc1 => %multifo!res_mfo1
+            dc2 => %multifo!res_mfo2
+          }
+        }
+      }
+    }
+    multifo => {
+      res_mfo1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
+      res_mfo2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
+    }
+  }
+
+However, to make life simpler in the simple cases, plugin_metafo can
+synthesize the lower-level plugin's configuration from a hash, like so:
+
+  plugins => {
+    metafo => {
+      resources => {
+        resA => {
+          datacenters => [ dc1, dc2 ],
+          dcmap => {
+            dc1 => { plugin => multifo, lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
+            dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
+            # the above are effectively treated as:
+            # dc1 => %multifo!metafo_resA_dc1
+            # dc2 => %multifo!metafo_resA_dc2
+          }
+        }
+      }
+    }
+    # below does not exist in your configfile, but is what plugin_metafo
+    #   synthesizes to support the above:
+    #multifo => {
+    #  metafo_resA_dc1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
+    #  metafo_resA_dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
+    #}
+  }
+
+Within a hash like the above, the special key C<plugin> will be stripped
+out internally and used to name the plugin we synthesize the config for.
+C<plugin> defaults to C<multifo> if not specified.  Note that C<plugin>
+could also be specified at the resource level (just inside of the C<resA>
+stanza) to change the default for all C<dcmap> entries in one resource, and
+could also be specified at the outer-most scope (just inside the C<metafo>
+stanza) to change the default for all resources.
+
+The defaulted-down C<plugin> is also the default for the direct-reference
+C<%plugin!resource> form discussed earlier.  With the correct default
+plugin name, it can be shortened to just C<!resource>.
+
+The same sort of key-value inheritance scheme (top-level -> per-resource
+level -> per-datacenter level) can also be used for any other parameter in
+synthesized resource configurations specific to the per-datacenter
+plugin(s) you are using.  A common example would be the C<service_types>
+parameter that most plugins which support monitored address results have.
+Note that these other values (e.g. service_types) would only apply to
+synthesized resources, B<not> to direct-references like C<%multifo!foo>,
+which must be configured entirely separately within that plugin's config.
+
+There are three other possible shortcut values for datacenters: a single
+direct address, an array of addresses, or a single CNAME hostname.  If a
+single IP address or an array of IP addresses are specified, plugin_metafo
+will synthesize a hash from them with the plugin forced to C<multifo>
+(since it cannot know the syntax of hashes for all other plugins, which
+may differ), and give them address labels C<1>, C<2>, etc.
+
+If the value for a datacenter is a single CNAME hostname, no sub-plugin
+is used, and that CNAME result is returned directly.  Note that any
+resource with such an entry can only be used with C<DYNC> RRs, and not
+C<DYNA> RRs (as is the case if any subplugin's configuration is capable
+of returning CNAME data).
+
+A much more complete example, showing off most of the features above:
+
+  plugins => {
+    metafo => {
+      plugin => multifo # change default for all resources
+      service_types => [ bar ] # default service_types for synthesized below
+      resources => {
+        resA => {
+          plugin => multifo # change default for this resource
+          service_types => [foo, bar] # services types for synthesized below:
+          datacenters => [ dc1, dc2, dc3, dc4, dc5, dc6, dc7, dc8 ],
+          dcmap => {
+            dc1 => { plugin => multifo, lb01 => 192.0.2.1, lb02 => 192.0.2.3 }
+            dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113 }
+            dc3 => %simplefo!foo
+            dc4 => { plugin => simplefo, primary => 192.0.2.100, secondary => 192.0.2.101 }
+            dc5 => !bar
+            dc6 => 192.0.2.150
+            dc7 => [ 192.0.2.180, 192.0.2.181 ]
+            dc8 => last.resort.example.com.
+          }
+        }
+      }
+    }
+    # below, commented-out sections show configuration synthesized
+    #   by plugin_metafo, whereas the rest are direct-references that
+    #   had to be manually specified here:
+    multifo => {
+      # metafo_resA_dc1 => { lb01 => 192.0.2.1, lb02 => 192.0.2.3, service_types => [foo, bar] }
+      # metafo_resA_dc2 => { lb01 => 192.0.2.111, lb02 => 192.0.2.113, service_types => [foo, bar] }
+      bar => { asd => 192.0.2.77, xyz => 192.0.2.88 }
+      # metafo_resA_dc6 => { 1 => 192.0.2.150, service_types => [foo, bar] }
+      # metafo_resA_dc7 => { 1 => 192.0.2.180, 2 => 192.0.2.181, service_types => [foo, bar] }
+    }
+    simplefo => {
+      foo => { primary => 192.0.2.80, secondary => 192.0.2.81 }
+      # metafo_resA_dc4 => { primary => 192.0.2.100, secondary => 192.0.2.101, service_types => [foo, bar] }
+    }
+  }
+
+Note in the example above that C<%multifo!bar> and C<%simplefo!foo> would
+have had their default C<service_types = up> rather than the one
+specified at the metafo level, because they were not synthesized.  It would
+be up to you to keep all of the service_types in sync when using direct
+references.
+
+=head1 SYNTHETIC PER-DATACENTER RESOURCES
+
+This plugin will synthesize additional, per-datacenter resource names from
+your configuration.  They are named as C<resname/dcname>.  For example, if
+you define a metafo resource named C<prodwww> with the datacenter list
+C<[ pri, sec ]>, the resource names C<prodwww/pri> and C<prodwww/sec> will
+be sythesized and can be used in zonefile records, e.g.:
+
+  www-backup 300 DYNA metafo!prodwww/sec
+
+When used, these per-datacenter synthetic resource names cause a given
+lookup to skip the normal failover process and directly return results from
+that particular datacenter.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-multifo.pod gdnsd-2.1.2/docs/gdnsd-plugin-multifo.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-multifo.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-multifo.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,210 +0,0 @@
-=head1 NAME
-
-gdnsd-plugin-multifo - gdnsd plugin for multi-address, all-active failover
-groups
-
-=head1 SYNOPSIS
-
-Example plugin config:
-
-  plugins => {
-    multifo => {
-      up_thresh => 0.3
-      service_types => up,
-      v4www => {
-        lb01 => 192.0.2.200,
-        lb02 => 192.0.2.201,
-        lb03 => 192.0.2.202,
-      }
-      v6smtp => {
-        service_types => [ smtp ],
-        up_thresh => 0.1,
-        lb01_v6 => 2001:DB8::1,
-        lb02_v6 => 2001:DB8::2,
-        lb03_v6 => 2001:DB8::3,
-      }
-      pubwww => {
-        up_thresh => 0.5
-        service_types => corpwww_type
-        addrs_v4 => [ 192.0.2.100, 192.0.2.101, 192.0.2.102 ]
-        addrs_v6 => {
-          service_types => [ up ],
-          up_thresh => 0.7
-          lb01_v6 => 2001:DB8::1,
-          lb02_v6 => 2001:DB8::2,
-          lb03_v6 => 2001:DB8::3,
-        }
-      }
-    }
-  }
-
-Example zonefile RRs:
-
-  web4 180 DYNA multifo!v4www
-  smtp 180 DYNA multifo!v6smtp
-  www 180 DYNA multifo!pubwww
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-multifo> is designed to do multi-address all-active
-failover grouping.  Basically, for each configured resource name, you supply
-a labeled list of addresses.  multifo monitors these addresses
-according to C<service_types>, and answers C<DYNA> address queries
-using the non-C<DOWN> subset.  The core gdnsd code will round-robin
-rotate the records on the way out, as it does for all address
-RR-sets.
-
-=head1 TOP-LEVEL PLUGIN CONFIG
-
-At the top level of the plugin's configuration stanza, two special
-parameters C<up_thresh> and C<service_types> are supported. These set
-default per-resource options of the same name for any resources which do
-not define them explicitly.
-
-The rest of the hash entries at the top level are the names of the
-resources you define.  Each resource gets a configuration hash of its own
-for containing resource-specific parameters as well as the actual address
-data.
-
-=head1 RESOURCE CONFIG
-
-Within a resource, you have two basic options.  You can either directly
-specify a set of C<label =E<gt> address> pairs which are all the same
-family (IPv4 or IPv6), or you can use the sub-stanzas C<addrs_v4> and/or
-C<addrs_v6> to specify one or both families in the same resource.
-
-The C<up_thresh> and C<service_types> parameters are inherited through
-every level, and can be overridden at any level (even per-address-family):
-
-=over 4
-
-=item B<up_thresh>
-
-Floating point, default 0.5, range (0.0 - 1.0].  This configures the
-per-resource C<up_thresh> threshold.  More details in L</UP THRESH> below.
-
-=item B<service_types>
-
-Array of strings, or single string.  Default C<default>.  This sets the
-monitored service_types for this resource.  If an array of more than one is
-provided, all will be monitored for each address, and the net monitored
-state will be the minimum (worst) of the set.  See L<gdnsd.config(8)> for
-more details on service_types.
-
-=back
-
-=head1 SHORTCUT CONFIG
-
-If you have no parameters (service_types, up_thresh) to configure in a
-given stanza (single-family direct resource config, or addrs_v[46]), and do
-not care about the descriptive per-address labels used in monitoring, you
-can replace the hash with an array of addresses.  The labels will be
-generated for you as a series of integers starting with C<1>.  For example,
-the following are equivalent:
-
-   res1 => { addrs_v4 => [ 192.0.2.1, 192.0.2.2 ] }
-   res1 => { addrs_v4 => { 1 => 192.0.2.1, 2 => 192.0.2.2 } }
-
-=head1 OPERATIONAL MECHANICS
-
-All of the addresses for all of the resources are monitored using the
-per-address-family inherited C<service_types> specified (default would be
-the static virtual monitor C<up>).  When the core daemon
-requests a lookup for address records of a given family on one of this
-plugin's resources, it goes through essentially the following process to
-determine the set of response addresses for that address family: 1) Add all
-non-DOWN addresses to the result set.  2) If the set of non-DOWN addresses
-fail the up_thresh check, add *all* addresses to the result set as a
-fallback.  3) If any address is in the DOWN state, cut the
-zonefile-specified TTL in half
-
-This process is repeated independently for each of the IPv4 and IPv6
-address subsets, in the case that a resource has both address families
-configured (the TTL is only cut in half once of course).  Details on the
-up_thresh check follow:
-
-=head1 UP THRESH
-
-If there are not enough UP addresses to pass the threshold (per address family),
-all addresses (of a given address family) will be returned as a fallback.
-
-The threshold is implemented mathematically as in the following pseudo-code
-C<if(non_down E<gt>= ceil(thresh * total)) threshold_passed;>.  For
-example, if thresh is at the default value of C<0.5>, and there are 3 total
-IPv4 addresses, then 2 of them must be non-down to pass the threshold.  The
-net result is that with the default threshold, the plugin will never return
-an isolated single address from a set of 3.  It will either return all 3,
-or it will return 2/3 if a single address from the set has failed.
-
-When the threshold check fails (and all addresses are returned) for either
-address family, resource-level total failure will also be signaled to any
-applicable upstream meta-plugins such as metafo or geoip.
-
-General rules for the results of the up_thresh formula:
-
-=over 4
-
-=item * A threshold of 1.0 will only pass if B<all> addresses are not-down.
-This is mostly pointless, you might as well not monitor anything and set
-up these addresses as a static set in a zonefile.
-
-=item * A threshold of 0.01 will pass even if only one address is alive and
-return just that one address, even if it's e.g. the only one left out of 40.
-
-=item * Because a threshold of 0.0 is illegal, if all addresses are down
-the threshold will always fail, returning all addresses.
-
-=back
-
-Intermediate value examples: (threshold: non-down/total required to pass
-threshold):
-
-=over 4
-
-=item * 0.1: 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8 2/16
-
-=item * 0.2: 1/1 1/2 1/3 1/4 1/5 2/6 2/7 2/8 4/16
-
-=item * 0.3: 1/1 1/2 1/3 2/4 2/5 2/6 3/7 3/8 5/16
-
-=item * 0.4: 1/1 1/2 2/3 2/4 2/5 3/6 3/7 4/8 7/16
-
-=item * 0.5: 1/1 1/2 2/3 2/4 3/5 3/6 4/7 4/8 8/16
-
-=item * 0.6: 1/1 2/2 2/3 3/4 3/5 4/6 5/7 5/8 10/16
-
-=item * 0.7: 1/1 2/2 3/3 3/4 4/5 5/6 5/7 6/8 12/16
-
-=item * 0.8: 1/1 2/2 3/3 4/4 4/5 5/6 6/7 7/8 13/16
-
-=item * 0.9: 1/1 2/2 3/3 4/4 5/5 6/6 7/7 8/8 15/16
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>,
-L<gdnsd-plugin-simplefo(8)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-multifo.podin gdnsd-2.1.2/docs/gdnsd-plugin-multifo.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-multifo.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-multifo.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,210 @@
+=head1 NAME
+
+gdnsd-plugin-multifo - gdnsd plugin for multi-address, all-active failover
+groups
+
+=head1 SYNOPSIS
+
+Example plugin config:
+
+  plugins => {
+    multifo => {
+      up_thresh => 0.3
+      service_types => up,
+      v4www => {
+        lb01 => 192.0.2.200,
+        lb02 => 192.0.2.201,
+        lb03 => 192.0.2.202,
+      }
+      v6smtp => {
+        service_types => [ smtp ],
+        up_thresh => 0.1,
+        lb01_v6 => 2001:DB8::1,
+        lb02_v6 => 2001:DB8::2,
+        lb03_v6 => 2001:DB8::3,
+      }
+      pubwww => {
+        up_thresh => 0.5
+        service_types => corpwww_type
+        addrs_v4 => [ 192.0.2.100, 192.0.2.101, 192.0.2.102 ]
+        addrs_v6 => {
+          service_types => [ up ],
+          up_thresh => 0.7
+          lb01_v6 => 2001:DB8::1,
+          lb02_v6 => 2001:DB8::2,
+          lb03_v6 => 2001:DB8::3,
+        }
+      }
+    }
+  }
+
+Example zonefile RRs:
+
+  web4 180 DYNA multifo!v4www
+  smtp 180 DYNA multifo!v6smtp
+  www 180 DYNA multifo!pubwww
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-multifo> is designed to do multi-address all-active
+failover grouping.  Basically, for each configured resource name, you supply
+a labeled list of addresses.  multifo monitors these addresses
+according to C<service_types>, and answers C<DYNA> address queries
+using the non-C<DOWN> subset.  The core gdnsd code will round-robin
+rotate the records on the way out, as it does for all address
+RR-sets.
+
+=head1 TOP-LEVEL PLUGIN CONFIG
+
+At the top level of the plugin's configuration stanza, two special
+parameters C<up_thresh> and C<service_types> are supported. These set
+default per-resource options of the same name for any resources which do
+not define them explicitly.
+
+The rest of the hash entries at the top level are the names of the
+resources you define.  Each resource gets a configuration hash of its own
+for containing resource-specific parameters as well as the actual address
+data.
+
+=head1 RESOURCE CONFIG
+
+Within a resource, you have two basic options.  You can either directly
+specify a set of C<label =E<gt> address> pairs which are all the same
+family (IPv4 or IPv6), or you can use the sub-stanzas C<addrs_v4> and/or
+C<addrs_v6> to specify one or both families in the same resource.
+
+The C<up_thresh> and C<service_types> parameters are inherited through
+every level, and can be overridden at any level (even per-address-family):
+
+=over 4
+
+=item B<up_thresh>
+
+Floating point, default 0.5, range (0.0 - 1.0].  This configures the
+per-resource C<up_thresh> threshold.  More details in L</UP THRESH> below.
+
+=item B<service_types>
+
+Array of strings, or single string.  Default C<default>.  This sets the
+monitored service_types for this resource.  If an array of more than one is
+provided, all will be monitored for each address, and the net monitored
+state will be the minimum (worst) of the set.  See L<gdnsd.config(8)> for
+more details on service_types.
+
+=back
+
+=head1 SHORTCUT CONFIG
+
+If you have no parameters (service_types, up_thresh) to configure in a
+given stanza (single-family direct resource config, or addrs_v[46]), and do
+not care about the descriptive per-address labels used in monitoring, you
+can replace the hash with an array of addresses.  The labels will be
+generated for you as a series of integers starting with C<1>.  For example,
+the following are equivalent:
+
+   res1 => { addrs_v4 => [ 192.0.2.1, 192.0.2.2 ] }
+   res1 => { addrs_v4 => { 1 => 192.0.2.1, 2 => 192.0.2.2 } }
+
+=head1 OPERATIONAL MECHANICS
+
+All of the addresses for all of the resources are monitored using the
+per-address-family inherited C<service_types> specified (default would be
+the static virtual monitor C<up>).  When the core daemon
+requests a lookup for address records of a given family on one of this
+plugin's resources, it goes through essentially the following process to
+determine the set of response addresses for that address family: 1) Add all
+non-DOWN addresses to the result set.  2) If the set of non-DOWN addresses
+fail the up_thresh check, add *all* addresses to the result set as a
+fallback.  3) If any address is in the DOWN state, cut the
+zonefile-specified TTL in half
+
+This process is repeated independently for each of the IPv4 and IPv6
+address subsets, in the case that a resource has both address families
+configured (the TTL is only cut in half once of course).  Details on the
+up_thresh check follow:
+
+=head1 UP THRESH
+
+If there are not enough UP addresses to pass the threshold (per address family),
+all addresses (of a given address family) will be returned as a fallback.
+
+The threshold is implemented mathematically as in the following pseudo-code
+C<if(non_down E<gt>= ceil(thresh * total)) threshold_passed;>.  For
+example, if thresh is at the default value of C<0.5>, and there are 3 total
+IPv4 addresses, then 2 of them must be non-down to pass the threshold.  The
+net result is that with the default threshold, the plugin will never return
+an isolated single address from a set of 3.  It will either return all 3,
+or it will return 2/3 if a single address from the set has failed.
+
+When the threshold check fails (and all addresses are returned) for either
+address family, resource-level total failure will also be signaled to any
+applicable upstream meta-plugins such as metafo or geoip.
+
+General rules for the results of the up_thresh formula:
+
+=over 4
+
+=item * A threshold of 1.0 will only pass if B<all> addresses are not-down.
+This is mostly pointless, you might as well not monitor anything and set
+up these addresses as a static set in a zonefile.
+
+=item * A threshold of 0.01 will pass even if only one address is alive and
+return just that one address, even if it's e.g. the only one left out of 40.
+
+=item * Because a threshold of 0.0 is illegal, if all addresses are down
+the threshold will always fail, returning all addresses.
+
+=back
+
+Intermediate value examples: (threshold: non-down/total required to pass
+threshold):
+
+=over 4
+
+=item * 0.1: 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8 2/16
+
+=item * 0.2: 1/1 1/2 1/3 1/4 1/5 2/6 2/7 2/8 4/16
+
+=item * 0.3: 1/1 1/2 1/3 2/4 2/5 2/6 3/7 3/8 5/16
+
+=item * 0.4: 1/1 1/2 2/3 2/4 2/5 3/6 3/7 4/8 7/16
+
+=item * 0.5: 1/1 1/2 2/3 2/4 3/5 3/6 4/7 4/8 8/16
+
+=item * 0.6: 1/1 2/2 2/3 3/4 3/5 4/6 5/7 5/8 10/16
+
+=item * 0.7: 1/1 2/2 3/3 3/4 4/5 5/6 5/7 6/8 12/16
+
+=item * 0.8: 1/1 2/2 3/3 4/4 4/5 5/6 6/7 7/8 13/16
+
+=item * 0.9: 1/1 2/2 3/3 4/4 5/5 6/6 7/7 8/8 15/16
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>,
+L<gdnsd-plugin-simplefo(8)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-null.pod gdnsd-2.1.2/docs/gdnsd-plugin-null.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-null.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-null.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,66 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-null - gdnsd null plugin
-
-=head1 SYNOPSIS
-
-Example null service_types config:
-
-  service_types => {
-    my_null_mon => {
-      plugin => null,
-      # ... other generic service_type params
-    }
-  }
-
-Zonefile RRs using null resolution
-
-  foo 300 DYNA null
-  bar 300 DYNC null!whatever
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-null> exists mostly as an example of the minimum
-possible plugin of both types.  It is simultaneously both a
-monitoring plugin and a resolution plugin.
-
-When used as a resolution plugin in C<DNYA> or C<DYNC> RRs, it
-ignores any resource name provided.  With C<DYNA> it always
-returns the IPv4 address C<0.0.0.0> and the IPv6 address C<::>.
-With C<DYNC> it always returns a CNAME to to the domainname
-C<invalid.>
-
-When used as a monitoring plugin by defining a service_type as
-shown in the example above it emulates the behavior of a real
-monitoring plugin (updating at correct intervals, etc) but
-sends a C<DOWN> result at every monitoring check interval without
-actually checking anything.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-null.podin gdnsd-2.1.2/docs/gdnsd-plugin-null.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-null.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-null.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,66 @@
+
+=head1 NAME
+
+gdnsd-plugin-null - gdnsd null plugin
+
+=head1 SYNOPSIS
+
+Example null service_types config:
+
+  service_types => {
+    my_null_mon => {
+      plugin => null,
+      # ... other generic service_type params
+    }
+  }
+
+Zonefile RRs using null resolution
+
+  foo 300 DYNA null
+  bar 300 DYNC null!whatever
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-null> exists mostly as an example of the minimum
+possible plugin of both types.  It is simultaneously both a
+monitoring plugin and a resolution plugin.
+
+When used as a resolution plugin in C<DNYA> or C<DYNC> RRs, it
+ignores any resource name provided.  With C<DYNA> it always
+returns the IPv4 address C<0.0.0.0> and the IPv6 address C<::>.
+With C<DYNC> it always returns a CNAME to to the domainname
+C<invalid.>
+
+When used as a monitoring plugin by defining a service_type as
+shown in the example above it emulates the behavior of a real
+monitoring plugin (updating at correct intervals, etc) but
+sends a C<DOWN> result at every monitoring check interval without
+actually checking anything.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-reflect.pod gdnsd-2.1.2/docs/gdnsd-plugin-reflect.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-reflect.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-reflect.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,90 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-reflect - gdnsd cache reflector plugin
-
-=head1 SYNOPSIS
-
-Zonefile RRs using reflect resolution
-
-  reflect      10 DYNA reflect
-  reflect-dns  10 DYNA reflect!dns
-  reflect-edns 10 DYNA reflect!edns
-  reflect-both 10 DYNA reflect!both
-  reflect-best 10 DYNA reflect!best
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-reflect> is a resolution plugin that
-acts as a live debugging tool.  It reflects a view
-of the client's network address back in the response
-in the form of C<A> or C<AAAA> RRs.  It can be
-used with both C<DYNA> and C<DYNC> RRs, and will return
-address data in both cases.
-
-The plugin can operate in one of four modes named
-C<dns>, C<edns>, C<both>, and C<best>, which can
-be selected by using the mode name as a resource name
-in the zonefile, as shown in the example above.  The
-default mode is C<best>.  The modes operate as follows:
-
-=over 4
-
-=item dns
-
-In the C<dns> mode, the address in the response is
-always the source IP address of the request as seen
-by gdnsd.  Note that this is generally the public
-address of a central cache/resolver server rather
-than the end-user client itself.
-
-=item edns
-
-In the C<edns> mode, the address in the response is
-the address sent by the client in the C<edns-client-subnet>
-option.  If the client did not send such an option,
-the IPv4 address C<0.0.0.0> is returned.
-
-=item both
-
-In the C<both> mode, both of the above results
-are returned in the same response, but there is no
-artificial C<0.0.0.0> added if no C<edns-client-subnet>
-option was available.
-
-=item best
-
-In the C<best> (default) mode, if the C<edns-client-subnet>
-option was specified its data is returned as in the
-C<edns> case, otherwise the source IP address is returned
-as in the C<dns> case.
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-reflect.podin gdnsd-2.1.2/docs/gdnsd-plugin-reflect.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-reflect.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-reflect.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,90 @@
+
+=head1 NAME
+
+gdnsd-plugin-reflect - gdnsd cache reflector plugin
+
+=head1 SYNOPSIS
+
+Zonefile RRs using reflect resolution
+
+  reflect      10 DYNA reflect
+  reflect-dns  10 DYNA reflect!dns
+  reflect-edns 10 DYNA reflect!edns
+  reflect-both 10 DYNA reflect!both
+  reflect-best 10 DYNA reflect!best
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-reflect> is a resolution plugin that
+acts as a live debugging tool.  It reflects a view
+of the client's network address back in the response
+in the form of C<A> or C<AAAA> RRs.  It can be
+used with both C<DYNA> and C<DYNC> RRs, and will return
+address data in both cases.
+
+The plugin can operate in one of four modes named
+C<dns>, C<edns>, C<both>, and C<best>, which can
+be selected by using the mode name as a resource name
+in the zonefile, as shown in the example above.  The
+default mode is C<best>.  The modes operate as follows:
+
+=over 4
+
+=item dns
+
+In the C<dns> mode, the address in the response is
+always the source IP address of the request as seen
+by gdnsd.  Note that this is generally the public
+address of a central cache/resolver server rather
+than the end-user client itself.
+
+=item edns
+
+In the C<edns> mode, the address in the response is
+the address sent by the client in the C<edns-client-subnet>
+option.  If the client did not send such an option,
+the IPv4 address C<0.0.0.0> is returned.
+
+=item both
+
+In the C<both> mode, both of the above results
+are returned in the same response, but there is no
+artificial C<0.0.0.0> added if no C<edns-client-subnet>
+option was available.
+
+=item best
+
+In the C<best> (default) mode, if the C<edns-client-subnet>
+option was specified its data is returned as in the
+C<edns> case, otherwise the source IP address is returned
+as in the C<dns> case.
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-simplefo.pod gdnsd-2.1.2/docs/gdnsd-plugin-simplefo.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-simplefo.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-simplefo.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,135 +0,0 @@
-=head1 NAME
-
-gdnsd-plugin-simplefo - gdnsd plugin for simple primary->secondary address
-failover
-
-=head1 SYNOPSIS
-
-Example gdnsd config fragment using this plugin:
-
-  plugins => {
-    simplefo => {
-      service_types => [ www ],
-      pubwww => {
-        primary => 192.0.2.1
-        secondary => 192.0.2.100
-      }
-      www6 => {
-        primary => 2001:DB8::1
-        secondary => 2001:DB8::100
-      }
-      mixed => {
-        service_types => [ www, xmpp ]
-        addrs_v4 => {
-          primary => 192.0.2.1
-          secondary => 192.0.2.100
-        }
-        addrs_v6 => {
-          service_types => up
-          primary => 2001:DB8::1
-          secondary => 2001:DB8::100
-        }
-      }
-    }
-  }
-
-Example zonefile RRs:
-
-  www 180 DYNA simplefo!pubwww
-  www6 180 DYNA simplefo!www6
-  mix 180 DYNA simplefo!mixed
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-simplefo> is designed to do simple active/passive
-failover between one primary address and one secondary address.
-The status of the addresses are checked with standard gdnsd
-C<service_types> monitoring.  If you need more than a simple
-two-address failover list, the C<metafo> plugin is more appropriate.
-
-=head1 TOP-LEVEL PLUGIN CONFIG
-
-At the top level of the plugin's configuration stanza, the special
-parameter C<service_types> is supported. These sets the default
-per-resource C<service_types> for all resources.  The default default
-C<service_types> is C<[ up ]>, which simply sets them all C<UP>
-statically.
-
-The rest of the hash entries at the top level are the names of the
-resources you define.  Each resource gets a configuration hash of its own
-for containing resource-specific address info.
-
-=head1 RESOURCE CONFIG
-
-Within a resource, C<service_types> is again supported, to set the
-monitored service type(s) for this specific resource.
-
-If C<addrs_v4> is defined, it must be a hash containing two keys:
-C<primary> and C<secondary>, each of which has an IPv4 string address value.
-
-Similarly, if C<addrs_v6> is defined, it must be a hash containing two
-keys: C<primary> and C<secondary>, each of which has an IPv6 string address
-value.
-
-If neither of those two sub-stanzas is defined, you must define a single
-pair of C<primary> and C<secondary> addresses for the whole resource.
-These can be of either address family, so long as they are both the same
-family.
-
-When C<addrs_v4> and/or C<addrs_v6> are used, C<service_types> can also be
-overridden within each, for different behavior per-address-family (e.g.
-force one protocol always up/down).
-
-=head1 OPERATIONAL MECHANICS
-
-For each address family for which you have supplied data, the following
-logic is applied independently:
-
-=over 4
-
-=item * First, the worst monitored state of all C<service_types> checks for
-the primary address is obtained.  If this state is C<UP>, the
-primary address is used.
-
-=item * If the primary address was C<DOWN>, the secondary address is
-checked: If the secondary is C<UP>, it will be used.  If the
-secondary is also C<DOWN>, then the primary is used.
-
-=item * In any case other than the primary being exactly C<UP>, the
-response RR-set TTL from the zonefile will be cut in half for both address
-families.
-
-=back
-
-If both C<primary> and C<secondary> were C<DOWN> for B<either> address
-family, this plugin will signal total resource failure to any upstream
-module (geoip or metafo).  The cutting of the TTL only happens once for all
-address RRs, even if both families had a non-C<UP> primary.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>,
-L<gdnsd-plugin-multifo(8)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-simplefo.podin gdnsd-2.1.2/docs/gdnsd-plugin-simplefo.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-simplefo.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-simplefo.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,135 @@
+=head1 NAME
+
+gdnsd-plugin-simplefo - gdnsd plugin for simple primary->secondary address
+failover
+
+=head1 SYNOPSIS
+
+Example gdnsd config fragment using this plugin:
+
+  plugins => {
+    simplefo => {
+      service_types => [ www ],
+      pubwww => {
+        primary => 192.0.2.1
+        secondary => 192.0.2.100
+      }
+      www6 => {
+        primary => 2001:DB8::1
+        secondary => 2001:DB8::100
+      }
+      mixed => {
+        service_types => [ www, xmpp ]
+        addrs_v4 => {
+          primary => 192.0.2.1
+          secondary => 192.0.2.100
+        }
+        addrs_v6 => {
+          service_types => up
+          primary => 2001:DB8::1
+          secondary => 2001:DB8::100
+        }
+      }
+    }
+  }
+
+Example zonefile RRs:
+
+  www 180 DYNA simplefo!pubwww
+  www6 180 DYNA simplefo!www6
+  mix 180 DYNA simplefo!mixed
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-simplefo> is designed to do simple active/passive
+failover between one primary address and one secondary address.
+The status of the addresses are checked with standard gdnsd
+C<service_types> monitoring.  If you need more than a simple
+two-address failover list, the C<metafo> plugin is more appropriate.
+
+=head1 TOP-LEVEL PLUGIN CONFIG
+
+At the top level of the plugin's configuration stanza, the special
+parameter C<service_types> is supported. These sets the default
+per-resource C<service_types> for all resources.  The default default
+C<service_types> is C<[ up ]>, which simply sets them all C<UP>
+statically.
+
+The rest of the hash entries at the top level are the names of the
+resources you define.  Each resource gets a configuration hash of its own
+for containing resource-specific address info.
+
+=head1 RESOURCE CONFIG
+
+Within a resource, C<service_types> is again supported, to set the
+monitored service type(s) for this specific resource.
+
+If C<addrs_v4> is defined, it must be a hash containing two keys:
+C<primary> and C<secondary>, each of which has an IPv4 string address value.
+
+Similarly, if C<addrs_v6> is defined, it must be a hash containing two
+keys: C<primary> and C<secondary>, each of which has an IPv6 string address
+value.
+
+If neither of those two sub-stanzas is defined, you must define a single
+pair of C<primary> and C<secondary> addresses for the whole resource.
+These can be of either address family, so long as they are both the same
+family.
+
+When C<addrs_v4> and/or C<addrs_v6> are used, C<service_types> can also be
+overridden within each, for different behavior per-address-family (e.g.
+force one protocol always up/down).
+
+=head1 OPERATIONAL MECHANICS
+
+For each address family for which you have supplied data, the following
+logic is applied independently:
+
+=over 4
+
+=item * First, the worst monitored state of all C<service_types> checks for
+the primary address is obtained.  If this state is C<UP>, the
+primary address is used.
+
+=item * If the primary address was C<DOWN>, the secondary address is
+checked: If the secondary is C<UP>, it will be used.  If the
+secondary is also C<DOWN>, then the primary is used.
+
+=item * In any case other than the primary being exactly C<UP>, the
+response RR-set TTL from the zonefile will be cut in half for both address
+families.
+
+=back
+
+If both C<primary> and C<secondary> were C<DOWN> for B<either> address
+family, this plugin will signal total resource failure to any upstream
+module (geoip or metafo).  The cutting of the TTL only happens once for all
+address RRs, even if both families had a non-C<UP> primary.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>,
+L<gdnsd-plugin-multifo(8)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-static.pod gdnsd-2.1.2/docs/gdnsd-plugin-static.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-static.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-static.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,79 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-static - gdnsd static plugin
-
-=head1 SYNOPSIS
-
-Example static resources config for resolution:
-
-  plugins => {
-    static => {
-      foo => 192.0.2.1
-      bar => 2001:db8::1
-      baz => something.example.com.
-    }
-  }
-
-Example static service_types config for monitoring:
-
-  service_types => {
-    my_static_mon => {
-      plugin => static,
-      ttl => 123,
-      state => UP,
-      # ... other generic service_type params (ignored)
-    }
-  }
-
-Zonefile RRs using static plugin resolution
-
-  foo 300 DYNA static!foo
-  bar 300 DYNC static!bar
-  baz 300 DYNC static!baz
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-static> is a combined monitoring and resolution
-plugin that returns static data.  It is generally useless in
-real scenarios, and mostly serves only as an example/test plugin.
-
-For resolution, the configuration is a simple key/value hash
-where the keys are resource names and the values can be a single
-IP address (v4 or v6) or a domainname.  The domainname form can
-only be used with C<DYNC>, while the address form can be used with
-either C<DYNA> or C<DYNC>.
-
-For monitoring configuration as a service_type, the only two useful
-parameters are C<ttl> and C<state>, which set a fixed TTL and state
-for this static monitor result.  The other standard monitoring
-parameters (e.g. interval, timeout) are ignored, as static sets its
-states once at startup and never runs again.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-static.podin gdnsd-2.1.2/docs/gdnsd-plugin-static.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-static.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-static.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,79 @@
+
+=head1 NAME
+
+gdnsd-plugin-static - gdnsd static plugin
+
+=head1 SYNOPSIS
+
+Example static resources config for resolution:
+
+  plugins => {
+    static => {
+      foo => 192.0.2.1
+      bar => 2001:db8::1
+      baz => something.example.com.
+    }
+  }
+
+Example static service_types config for monitoring:
+
+  service_types => {
+    my_static_mon => {
+      plugin => static,
+      ttl => 123,
+      state => UP,
+      # ... other generic service_type params (ignored)
+    }
+  }
+
+Zonefile RRs using static plugin resolution
+
+  foo 300 DYNA static!foo
+  bar 300 DYNC static!bar
+  baz 300 DYNC static!baz
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-static> is a combined monitoring and resolution
+plugin that returns static data.  It is generally useless in
+real scenarios, and mostly serves only as an example/test plugin.
+
+For resolution, the configuration is a simple key/value hash
+where the keys are resource names and the values can be a single
+IP address (v4 or v6) or a domainname.  The domainname form can
+only be used with C<DYNC>, while the address form can be used with
+either C<DYNA> or C<DYNC>.
+
+For monitoring configuration as a service_type, the only two useful
+parameters are C<ttl> and C<state>, which set a fixed TTL and state
+for this static monitor result.  The other standard monitoring
+parameters (e.g. interval, timeout) are ignored, as static sets its
+states once at startup and never runs again.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-tcp_connect.pod gdnsd-2.1.2/docs/gdnsd-plugin-tcp_connect.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-tcp_connect.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-tcp_connect.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,66 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-tcp_connect - gdnsd TCP monitoring plugin
-
-=head1 SYNOPSIS
-
-Example tcp_connect service_types config:
-
-  service_types => {
-    tcp9000 => {
-      plugin => tcp_connect,
-      port => 9000, # required
-      up_thresh => 20,
-      ok_thresh => 10,
-      down_thresh => 10,
-      interval => 10,
-      timeout => 3,
-    }
-  }
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-tcp_connect> is a monitoring plugin that
-checks basic TCP connectivity to a given port.
-It establishes a basic TCP connection and then immediately
-closes without sending or receiving any data on each
-monitoring check.
-
-=head1 PARAMETERS
-
-=over 4
-
-=item port
-
-The numeric port number to connect on, required.
-
-=back
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-tcp_connect.podin gdnsd-2.1.2/docs/gdnsd-plugin-tcp_connect.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-tcp_connect.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-tcp_connect.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,66 @@
+
+=head1 NAME
+
+gdnsd-plugin-tcp_connect - gdnsd TCP monitoring plugin
+
+=head1 SYNOPSIS
+
+Example tcp_connect service_types config:
+
+  service_types => {
+    tcp9000 => {
+      plugin => tcp_connect,
+      port => 9000, # required
+      up_thresh => 20,
+      ok_thresh => 10,
+      down_thresh => 10,
+      interval => 10,
+      timeout => 3,
+    }
+  }
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-tcp_connect> is a monitoring plugin that
+checks basic TCP connectivity to a given port.
+It establishes a basic TCP connection and then immediately
+closes without sending or receiving any data on each
+monitoring check.
+
+=head1 PARAMETERS
+
+=over 4
+
+=item port
+
+The numeric port number to connect on, required.
+
+=back
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-weighted.pod gdnsd-2.1.2/docs/gdnsd-plugin-weighted.pod
--- gdnsd-2.1.0/docs/gdnsd-plugin-weighted.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-weighted.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,366 +0,0 @@
-
-=head1 NAME
-
-gdnsd-plugin-weighted - gdnsd plugin implementing "weighted" records
-
-=head1 SYNOPSIS
-
-Example plugin config:
-
-  plugins => {
-    weighted => {
-      multi = false # default
-      service_types = up
-      up_thresh => 0.5 # default
-      corpwww => {
-        lb01 = [ lb01.example.com., 99 ]
-        lb02 = [ lb02.example.com., 15 ]
-        lb03 = [ lb03, 1 ]
-      }
-      frontwww6 => {
-        service_types = up
-        multi = true
-        wwwhost01 = [ 2001:db8::123, 4 ]
-        wwwhost02 = [ 2001:db8::456, 1 ]
-        wwwhost03 = [ 2001:db8::789, 2 ]
-      }
-      pubwww => {
-        service_types = [ web_check, foo ]
-        up_thresh => 0.01,
-        pubhost01 = [ 192.0.2.1, 44 ]
-        pubhost02 = [ 192.0.2.2, 11 ]
-        pubhost03 = [ 192.0.2.3, 11 ]
-        pubhost04 = [ 192.0.2.4, 11 ]
-      }
-      cdnwww => {
-        service_types = web_check
-        datacenter1 => {
-          d1-lb1 = [ 127.0.0.1, 2 ]
-          d1-lb2 = [ 127.0.0.2, 2 ]
-        }
-        datacenter2 => {
-          d2-lb1 = [ 127.0.0.3, 2 ]
-          d2-lb2 = [ 127.0.0.4, 2 ]
-          d2-lb3 = [ 127.0.0.5, 1 ]
-        }
-      }
-      mixed => {
-        multi => false,
-        addrs_v4 => {
-          lb1 = [ 127.0.0.3, 2 ]
-          lb2 = [ 127.0.0.4, 2 ]
-        }
-        addrs_v6 => {
-          multi => true
-          www6set1 = {
-            lb01 => [ 2001:db8::123, 4 ]
-            lb02 => [ 2001:db8::456, 1 ]
-          }
-          www6set2 = {
-            lb01 => [ 2001:db8::789, 4 ]
-            lb02 => [ 2001:db8::ABC, 1 ]
-          }
-        }
-      }
-      cn => {
-        service_types = my_cn_check
-        foo = [ lb01.example.com., 99 ]
-        bar = [ lb02.example.com., 15 ]
-      }
-    }
-  }
-
-Zonefile RRs referencing the above:
-
-  www.corp   300 DYNC weighted!corpwww
-  www6.front 300 DYNA weighted!frontwww6
-  www        300 DYNC weighted!pubwww
-  cdn        300 DYNA weighted!cdnwww
-  mixed-a    300 DYNA weighted!mixed
-  cnames     300 DYNC weighted!cn
-
-=head1 DESCRIPTION
-
-B<gdnsd-plugin-weighted> can be used to return one (or a subset)
-of several address records, or one of several CNAME records
-based on dynamic-weighted probabilities.
-
-=head1 CONFIGURATION - TOP LEVEL
-
-At the top level, there are three special parameter keys: C<service_types>,
-C<up_thresh>, and C<multi>.  C<multi> is ignored for CNAME-based
-resources.  All of these keys are inherited and
-override-able at the per-resource and per-address-family levels.
-
-C<service_types> sets how the applicable addresses or CNAMEs are
-monitored.  The top-level default C<service_types> is C<up>, which is a
-built-in service type provided by gdnsd.  For more information about
-configuring non-default service type's, see the main L<gdnsd.config(5)>
-documentation.
-
-C<multi> is a boolean that can be C<true> or C<false>, and defaults to
-C<false>.  C<multi> controls the behavior of the algorithm
-for selecting result addresses, discussed in detail later.
-
-C<up_thresh> defines a floating point fraction of summed address weights
-in the range C<(0.0 - 1.0]>, defaulting to C<0.5>, and is used to
-influence failure/failover behavior.
-
-Other than those three, the rest of the top level keys are the names of
-your resources, and their values are the configuration of each resource.
-
-=head1 CONFIGURATION - PER-RESOURCE
-
-Inside a given resource's configuration hash, again the three
-address-related parameters C<services_types>, C<multi>, and C<up_thresh>
-may be specified to override their settings per-resource.
-
-There are two basic configuration modes within a resource:
-
-1) Explicit per-family address sub-stanzas.  In this mode, the resource
-contains one or more of the keys C<addrs_v4> and C<addrs_v6>.  Usually
-one would use both together, as it's simpler to use the second option
-when configuring a single address family.
-
-The contents of each stanza configure response RRs of the given address
-type for this resource, and the 3 behavioral parameters C<service_types>,
-C<multi>, and C<up_thresh> can be overridden per-address-family as well.
-
-2) Automatic top-level detection of just one address family or CNAMEs.
-In this mode, you can configure the top-level of a resource with direct
-entries, so long as they are matching set of a single type: all IPv4
-addresses, all IPv6 address, or all CNAMEs, and the type will be
-auto-detected.
-
-Resources which contain weighted lists of CNAMEs
-rather than addresses can only be used with C<DYNC> RRs in zonefiles, whereas
-those that contain only addresses can be used in either C<DYNC> or C<DYNA>
-RRs.
-
-=head1 CONFIGURATION - CNAMES
-
-When configuring cnames, the value of each item should be
-C<[ CNAME, WEIGHT ]>, and the resource will be useful for C<DYNC> zonefile
-records, resolving to a weighted CNAME record in responses.  The selection
-algorithm based on weights and monitoring results is as documented below
-for addresses in the B<THE UNGROUPED SINGLE CASE>, since groups of
-CNAMEs cannot be configured, and the C<multi> option is not valid for them.
-
-If the CNAMEs are not fully-qualified (do not end in "."), the current
-C<$ORIGIN> value for the zonefile RR being queried will be appended to
-complete the name, much as you would expect if the same not-fully-qualified
-name were substituted into the zonefiles everywhere the relevant DYNC record
-exists.  Monitoring will be based on the originally-configured CNAME text
-exactly as it was entered (including the terminal dot or the lack thereof).
-
-=head1 CONFIGURATION - ADDRESSES
-
-With the exception that C<addrs_v4> and C<addrs_v6> must contain only
-addresses of the correct family (or in the top-level auto-detect case,
-the top level entries must all be of the same family), the two stanzas
-behave identically.  When both are present, they are both used in every
-C<DYNA> response (as gdnsd always includes opposite-family records in
-the Additional section of A/AAAA queries).
-
-Within either address family type, there are two different binary
-dimensions (multi -> true/false, and grouped-vs-ungrouped) upon which the
-configuration and behavior hinge, leading to four different possible cases:
-ungrouped-single, ungrouped-multi, grouped-single, and grouped-multi.  Each
-will be discussed in detail below:
-
-=head1 THE UNGROUPED SINGLE CASE
-
-This is the simplest case.  The code detects this case when it sees that
-C<multi> is false (the default), and that the values of the keys are arrays
-rather than sub-hashes.  Each hash key is an address label, and each value
-is an array of C<[ IPADDR, WEIGHT ]>.
-
-When answering a query in this case, first the weights are converted to
-dynamic weights.  The dynamic weight of an address is its configured weight
-if the monitored state is C<UP>, or zero if the monitored
-state is C<DOWN>.  The dynamic weights are summed to produce a dynamic
-weight total, and then a single address to respond with is chosen from the
-set, with each address having the odds C<addr_dynamic_weight /
-total_dynamic_weight>.
-
-However, if the C<total_dynamic_weight> is less than C<ceil(up_thresh *
-total_configured_weight)>, then the dynamic weights are all reset to their
-configured full values so that the response odds are the same as if all
-were C<UP>, and resource-level failure is signalled to any upper-layer
-meta-plugin (e.g. metafo or geoip) when applicable.
-
-Example (X could be a whole resource, or an addrs_v4 stanza):
-
-  X => {
-    multi => false # default
-    # odds below assume no addresses are down:
-    lb01 => [ 192.0.2.1, 45 ] # 25% chance (45/180)
-    lb02 => [ 192.0.2.1, 60 ] # 33% chance (60/180)
-    lb03 => [ 192.0.2.1, 75 ] # 42% chance (75/180)
-  }
-
-=head1 THE UNGROUPED MULTI CASE
-
-This case is detected when, (as above) the values of the keys are arrays
-of C<[ IPADDR, WEIGHT]>, but the parameter C<multi> is true.  The change
-from the above behavior is primarily that multiple addresses from the
-weighted set can be returned in each response.  The C<maximum>, rather
-than the sum, of the dynamic weights (again, zero for down addresses,
-configured-weight otherwise), is found, and the odds of each address's
-inclusion in the response set is
-C<addr_dyanmic_weight / max_dynamic_weight>.
-
-This means all non-C<DOWN> addresses which share the group's maximum
-dynamic weight value will always be included, whereas others will be
-optionally included depending on the odds.  At least one address is always
-returned (because logically, at least one address has the maximum weight,
-giving it a 100% chance), and sometimes the full non-C<DOWN> set will be
-returned.
-
-C<up_thresh> behaves as in the previous case: If the sum of the dynamic
-weight values is less than C<ceil(up_thresh * total_configured_weight)>,
-then the dynamic weights are all set to their configured values and the
-result set is calculated as if all were C<UP>, while signalling
-resource-level failure to upstream meta-plugins (geoip or metafo).
-
-Example:
-
-  X => {
-    multi => true
-    # odds below assume no addresses are down:
-    lb01 => [ 192.0.2.1, 45 ] # 75% chance (45/60)
-    lb02 => [ 192.0.2.1, 60 ] # 100% chance (60/60)
-    lb03 => [ 192.0.2.1, 60 ] # 100% chance (60/60)
-    # overall possible result-sets:
-    # lb01,lb02,lb03 -> 75%
-    # lb02,lb03 -> 25%
-  }
-
-=head1 THE GROUPED SINGLE CASE
-
-The grouped cases are detected when the keys' values are sub-hashes at
-the outer level rather than arrays of C<[ IPADDR, WEIGHT]>.  In the grouped
-case, first the set is divided into named groups, and then within each group
-individual addresses are configured as
-C<addrlabel =E<gt> [ IPADDR, WEIGHT ]>.
-
-Example:
-
-   X => {
-     group1 => {
-       lb01 => [ 192.0.2.1, 10 ]
-       lb02 => [ 192.0.2.1, 20 ]
-       lb03 => [ 192.0.2.1, 30 ]
-     }
-     group2 => {
-       lb01 => [ 192.0.2.7, 10 ]
-       lb02 => [ 192.0.2.8, 20 ]
-       lb03 => [ 192.0.2.9, 30 ]
-     }
-   }
-
-The grouped single case, of course, occurs when the configuration layout
-is as shown above, and the C<multi> parameter is C<false> (the default).
-
-In grouped-single mode, essentially the groups are weighted against each
-other similarly to the single case for ungrouped addresses, resulting in
-the choice of a single group from the set of groups. Then the
-addresses within the chosen group are weighted against each other in
-multi-style, returning potentially more than one address from the chosen
-group.
-
-Specifically, each group's odds of being the single group chosen is
-C<group_dyn_weight / total_dyn_weight>, where the group's dynamic weight
-is the sum of the dynamic weights within it (C<DOWN> addresses are zero),
-and the total dynamic weight is the dynamic sum of all groups.  Then
-within each group, the odds of each address being included in the
-multi-response set is C<addr_dyn_weight / group_max_dyn_weight>.
-
-C<up_thresh> operates on all groups as a whole, and if the non-C<DOWN>
-sum of all weights in all groups fails to meet the standard
-of C<ceil(up_thresh * total_sum_configured_weight)>, then all addresses
-will be treated as if they are C<UP> for selection purposes, and
-resource-level failure will be signalled upstream.
-
-=head1 THE GROUPED MULTI CASE
-
-You can probably infer this one's behavior from reading about the
-previous three cases.  The difference from the previous grouped-single
-case is that the multi-vs-single behaviors are reversed.  Multiple
-groups are chosen based on the dynamic maximum weight between the
-groups, and a single weighted address is returned from the subset
-within each chosen group.  All of the details above logically apply
-in the way you would expect, as all of these four cases internally share
-the same code and logic, they just apply different bits of it to
-different subsets of the problem.
-
-=head1 GENERAL NOTES ON ADDRESS MODE CASES ABOVE
-
-Note that any time multi-selection is in effect at a layer
-(the top layer when multi is true, or within a group when
-when multi is false), the minimum count of chosen items will
-be the count of items that share the maximum weight within the set.
-e.g. a set of items with weights C<30, 30, 30, 20, 20> will always
-choose at least 3/5 items (because the first three have 100%
-odds of inclusion), and the total response set will range
-as high as all 5 items with some probability.
-
-A practical use-case example for grouped-single:
-
-Splitting groups on subnet boundaries in grouped-single mode
-gives the result that a single response packet never mixes subnets.
-This would enable your DNS-based balancing to defeat certain forms
-of client-level Destination Address Selection interference, while
-still returning multiple addresses per response (all from one
-subnet).
-
-A practical use-case for grouped-multi:
-
-Suppose you have a large set of addresses which can be logically grouped
-into subsets that have some shared failure risk (e.g. subpartitions of a
-datacenter which share infrastructure).  With grouped-multi behavior,
-clients will get up to N (count of groups) addresses in a round-robin
-response, but a given response set will never contain two addresses from
-the same group/subset.  This maximizes the chance that the client can
-successfully fail over to another address in the list when its primary
-selection fails, since the total set in each response does not share any
-per-subset failure mode.
-
-=head1 LIMITS
-
-All weights must be positive integer values greater than zero and
-less than 2^20 (1048576).
-
-There is a limit of 64 addresses, address-groups, or cnames at the
-top level of a resource (or per address family in the addrs_v4/addrs_v6
-cases), and a limit of 64 addresses within each address group in
-the grouped modes.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
-
-The gdnsd manual.
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2014 Anton Tolchanov <me@knyar.net>,
-Brandon L Black <blblack@gmail.com>, and Jay Reitz <jreitz@gmail.com>
-
-This file is part of gdnsd.
-
-gdnsd-plugin-weighted 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-plugin-weighted 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-plugin-weighted.  If not, see
-<http://www.gnu.org/licenses/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd-plugin-weighted.podin gdnsd-2.1.2/docs/gdnsd-plugin-weighted.podin
--- gdnsd-2.1.0/docs/gdnsd-plugin-weighted.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd-plugin-weighted.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,366 @@
+
+=head1 NAME
+
+gdnsd-plugin-weighted - gdnsd plugin implementing "weighted" records
+
+=head1 SYNOPSIS
+
+Example plugin config:
+
+  plugins => {
+    weighted => {
+      multi = false # default
+      service_types = up
+      up_thresh => 0.5 # default
+      corpwww => {
+        lb01 = [ lb01.example.com., 99 ]
+        lb02 = [ lb02.example.com., 15 ]
+        lb03 = [ lb03, 1 ]
+      }
+      frontwww6 => {
+        service_types = up
+        multi = true
+        wwwhost01 = [ 2001:db8::123, 4 ]
+        wwwhost02 = [ 2001:db8::456, 1 ]
+        wwwhost03 = [ 2001:db8::789, 2 ]
+      }
+      pubwww => {
+        service_types = [ web_check, foo ]
+        up_thresh => 0.01,
+        pubhost01 = [ 192.0.2.1, 44 ]
+        pubhost02 = [ 192.0.2.2, 11 ]
+        pubhost03 = [ 192.0.2.3, 11 ]
+        pubhost04 = [ 192.0.2.4, 11 ]
+      }
+      cdnwww => {
+        service_types = web_check
+        datacenter1 => {
+          d1-lb1 = [ 127.0.0.1, 2 ]
+          d1-lb2 = [ 127.0.0.2, 2 ]
+        }
+        datacenter2 => {
+          d2-lb1 = [ 127.0.0.3, 2 ]
+          d2-lb2 = [ 127.0.0.4, 2 ]
+          d2-lb3 = [ 127.0.0.5, 1 ]
+        }
+      }
+      mixed => {
+        multi => false,
+        addrs_v4 => {
+          lb1 = [ 127.0.0.3, 2 ]
+          lb2 = [ 127.0.0.4, 2 ]
+        }
+        addrs_v6 => {
+          multi => true
+          www6set1 = {
+            lb01 => [ 2001:db8::123, 4 ]
+            lb02 => [ 2001:db8::456, 1 ]
+          }
+          www6set2 = {
+            lb01 => [ 2001:db8::789, 4 ]
+            lb02 => [ 2001:db8::ABC, 1 ]
+          }
+        }
+      }
+      cn => {
+        service_types = my_cn_check
+        foo = [ lb01.example.com., 99 ]
+        bar = [ lb02.example.com., 15 ]
+      }
+    }
+  }
+
+Zonefile RRs referencing the above:
+
+  www.corp   300 DYNC weighted!corpwww
+  www6.front 300 DYNA weighted!frontwww6
+  www        300 DYNC weighted!pubwww
+  cdn        300 DYNA weighted!cdnwww
+  mixed-a    300 DYNA weighted!mixed
+  cnames     300 DYNC weighted!cn
+
+=head1 DESCRIPTION
+
+B<gdnsd-plugin-weighted> can be used to return one (or a subset)
+of several address records, or one of several CNAME records
+based on dynamic-weighted probabilities.
+
+=head1 CONFIGURATION - TOP LEVEL
+
+At the top level, there are three special parameter keys: C<service_types>,
+C<up_thresh>, and C<multi>.  C<multi> is ignored for CNAME-based
+resources.  All of these keys are inherited and
+override-able at the per-resource and per-address-family levels.
+
+C<service_types> sets how the applicable addresses or CNAMEs are
+monitored.  The top-level default C<service_types> is C<up>, which is a
+built-in service type provided by gdnsd.  For more information about
+configuring non-default service type's, see the main L<gdnsd.config(5)>
+documentation.
+
+C<multi> is a boolean that can be C<true> or C<false>, and defaults to
+C<false>.  C<multi> controls the behavior of the algorithm
+for selecting result addresses, discussed in detail later.
+
+C<up_thresh> defines a floating point fraction of summed address weights
+in the range C<(0.0 - 1.0]>, defaulting to C<0.5>, and is used to
+influence failure/failover behavior.
+
+Other than those three, the rest of the top level keys are the names of
+your resources, and their values are the configuration of each resource.
+
+=head1 CONFIGURATION - PER-RESOURCE
+
+Inside a given resource's configuration hash, again the three
+address-related parameters C<services_types>, C<multi>, and C<up_thresh>
+may be specified to override their settings per-resource.
+
+There are two basic configuration modes within a resource:
+
+1) Explicit per-family address sub-stanzas.  In this mode, the resource
+contains one or more of the keys C<addrs_v4> and C<addrs_v6>.  Usually
+one would use both together, as it's simpler to use the second option
+when configuring a single address family.
+
+The contents of each stanza configure response RRs of the given address
+type for this resource, and the 3 behavioral parameters C<service_types>,
+C<multi>, and C<up_thresh> can be overridden per-address-family as well.
+
+2) Automatic top-level detection of just one address family or CNAMEs.
+In this mode, you can configure the top-level of a resource with direct
+entries, so long as they are matching set of a single type: all IPv4
+addresses, all IPv6 address, or all CNAMEs, and the type will be
+auto-detected.
+
+Resources which contain weighted lists of CNAMEs
+rather than addresses can only be used with C<DYNC> RRs in zonefiles, whereas
+those that contain only addresses can be used in either C<DYNC> or C<DYNA>
+RRs.
+
+=head1 CONFIGURATION - CNAMES
+
+When configuring cnames, the value of each item should be
+C<[ CNAME, WEIGHT ]>, and the resource will be useful for C<DYNC> zonefile
+records, resolving to a weighted CNAME record in responses.  The selection
+algorithm based on weights and monitoring results is as documented below
+for addresses in the B<THE UNGROUPED SINGLE CASE>, since groups of
+CNAMEs cannot be configured, and the C<multi> option is not valid for them.
+
+If the CNAMEs are not fully-qualified (do not end in "."), the current
+C<$ORIGIN> value for the zonefile RR being queried will be appended to
+complete the name, much as you would expect if the same not-fully-qualified
+name were substituted into the zonefiles everywhere the relevant DYNC record
+exists.  Monitoring will be based on the originally-configured CNAME text
+exactly as it was entered (including the terminal dot or the lack thereof).
+
+=head1 CONFIGURATION - ADDRESSES
+
+With the exception that C<addrs_v4> and C<addrs_v6> must contain only
+addresses of the correct family (or in the top-level auto-detect case,
+the top level entries must all be of the same family), the two stanzas
+behave identically.  When both are present, they are both used in every
+C<DYNA> response (as gdnsd always includes opposite-family records in
+the Additional section of A/AAAA queries).
+
+Within either address family type, there are two different binary
+dimensions (multi -> true/false, and grouped-vs-ungrouped) upon which the
+configuration and behavior hinge, leading to four different possible cases:
+ungrouped-single, ungrouped-multi, grouped-single, and grouped-multi.  Each
+will be discussed in detail below:
+
+=head1 THE UNGROUPED SINGLE CASE
+
+This is the simplest case.  The code detects this case when it sees that
+C<multi> is false (the default), and that the values of the keys are arrays
+rather than sub-hashes.  Each hash key is an address label, and each value
+is an array of C<[ IPADDR, WEIGHT ]>.
+
+When answering a query in this case, first the weights are converted to
+dynamic weights.  The dynamic weight of an address is its configured weight
+if the monitored state is C<UP>, or zero if the monitored
+state is C<DOWN>.  The dynamic weights are summed to produce a dynamic
+weight total, and then a single address to respond with is chosen from the
+set, with each address having the odds C<addr_dynamic_weight /
+total_dynamic_weight>.
+
+However, if the C<total_dynamic_weight> is less than C<ceil(up_thresh *
+total_configured_weight)>, then the dynamic weights are all reset to their
+configured full values so that the response odds are the same as if all
+were C<UP>, and resource-level failure is signalled to any upper-layer
+meta-plugin (e.g. metafo or geoip) when applicable.
+
+Example (X could be a whole resource, or an addrs_v4 stanza):
+
+  X => {
+    multi => false # default
+    # odds below assume no addresses are down:
+    lb01 => [ 192.0.2.1, 45 ] # 25% chance (45/180)
+    lb02 => [ 192.0.2.1, 60 ] # 33% chance (60/180)
+    lb03 => [ 192.0.2.1, 75 ] # 42% chance (75/180)
+  }
+
+=head1 THE UNGROUPED MULTI CASE
+
+This case is detected when, (as above) the values of the keys are arrays
+of C<[ IPADDR, WEIGHT]>, but the parameter C<multi> is true.  The change
+from the above behavior is primarily that multiple addresses from the
+weighted set can be returned in each response.  The C<maximum>, rather
+than the sum, of the dynamic weights (again, zero for down addresses,
+configured-weight otherwise), is found, and the odds of each address's
+inclusion in the response set is
+C<addr_dyanmic_weight / max_dynamic_weight>.
+
+This means all non-C<DOWN> addresses which share the group's maximum
+dynamic weight value will always be included, whereas others will be
+optionally included depending on the odds.  At least one address is always
+returned (because logically, at least one address has the maximum weight,
+giving it a 100% chance), and sometimes the full non-C<DOWN> set will be
+returned.
+
+C<up_thresh> behaves as in the previous case: If the sum of the dynamic
+weight values is less than C<ceil(up_thresh * total_configured_weight)>,
+then the dynamic weights are all set to their configured values and the
+result set is calculated as if all were C<UP>, while signalling
+resource-level failure to upstream meta-plugins (geoip or metafo).
+
+Example:
+
+  X => {
+    multi => true
+    # odds below assume no addresses are down:
+    lb01 => [ 192.0.2.1, 45 ] # 75% chance (45/60)
+    lb02 => [ 192.0.2.1, 60 ] # 100% chance (60/60)
+    lb03 => [ 192.0.2.1, 60 ] # 100% chance (60/60)
+    # overall possible result-sets:
+    # lb01,lb02,lb03 -> 75%
+    # lb02,lb03 -> 25%
+  }
+
+=head1 THE GROUPED SINGLE CASE
+
+The grouped cases are detected when the keys' values are sub-hashes at
+the outer level rather than arrays of C<[ IPADDR, WEIGHT]>.  In the grouped
+case, first the set is divided into named groups, and then within each group
+individual addresses are configured as
+C<addrlabel =E<gt> [ IPADDR, WEIGHT ]>.
+
+Example:
+
+   X => {
+     group1 => {
+       lb01 => [ 192.0.2.1, 10 ]
+       lb02 => [ 192.0.2.1, 20 ]
+       lb03 => [ 192.0.2.1, 30 ]
+     }
+     group2 => {
+       lb01 => [ 192.0.2.7, 10 ]
+       lb02 => [ 192.0.2.8, 20 ]
+       lb03 => [ 192.0.2.9, 30 ]
+     }
+   }
+
+The grouped single case, of course, occurs when the configuration layout
+is as shown above, and the C<multi> parameter is C<false> (the default).
+
+In grouped-single mode, essentially the groups are weighted against each
+other similarly to the single case for ungrouped addresses, resulting in
+the choice of a single group from the set of groups. Then the
+addresses within the chosen group are weighted against each other in
+multi-style, returning potentially more than one address from the chosen
+group.
+
+Specifically, each group's odds of being the single group chosen is
+C<group_dyn_weight / total_dyn_weight>, where the group's dynamic weight
+is the sum of the dynamic weights within it (C<DOWN> addresses are zero),
+and the total dynamic weight is the dynamic sum of all groups.  Then
+within each group, the odds of each address being included in the
+multi-response set is C<addr_dyn_weight / group_max_dyn_weight>.
+
+C<up_thresh> operates on all groups as a whole, and if the non-C<DOWN>
+sum of all weights in all groups fails to meet the standard
+of C<ceil(up_thresh * total_sum_configured_weight)>, then all addresses
+will be treated as if they are C<UP> for selection purposes, and
+resource-level failure will be signalled upstream.
+
+=head1 THE GROUPED MULTI CASE
+
+You can probably infer this one's behavior from reading about the
+previous three cases.  The difference from the previous grouped-single
+case is that the multi-vs-single behaviors are reversed.  Multiple
+groups are chosen based on the dynamic maximum weight between the
+groups, and a single weighted address is returned from the subset
+within each chosen group.  All of the details above logically apply
+in the way you would expect, as all of these four cases internally share
+the same code and logic, they just apply different bits of it to
+different subsets of the problem.
+
+=head1 GENERAL NOTES ON ADDRESS MODE CASES ABOVE
+
+Note that any time multi-selection is in effect at a layer
+(the top layer when multi is true, or within a group when
+when multi is false), the minimum count of chosen items will
+be the count of items that share the maximum weight within the set.
+e.g. a set of items with weights C<30, 30, 30, 20, 20> will always
+choose at least 3/5 items (because the first three have 100%
+odds of inclusion), and the total response set will range
+as high as all 5 items with some probability.
+
+A practical use-case example for grouped-single:
+
+Splitting groups on subnet boundaries in grouped-single mode
+gives the result that a single response packet never mixes subnets.
+This would enable your DNS-based balancing to defeat certain forms
+of client-level Destination Address Selection interference, while
+still returning multiple addresses per response (all from one
+subnet).
+
+A practical use-case for grouped-multi:
+
+Suppose you have a large set of addresses which can be logically grouped
+into subsets that have some shared failure risk (e.g. subpartitions of a
+datacenter which share infrastructure).  With grouped-multi behavior,
+clients will get up to N (count of groups) addresses in a round-robin
+response, but a given response set will never contain two addresses from
+the same group/subset.  This maximizes the chance that the client can
+successfully fail over to another address in the list when its primary
+selection fails, since the total set in each response does not share any
+per-subset failure mode.
+
+=head1 LIMITS
+
+All weights must be positive integer values greater than zero and
+less than 2^20 (1048576).
+
+There is a limit of 64 addresses, address-groups, or cnames at the
+top level of a resource (or per address family in the addrs_v4/addrs_v6
+cases), and a limit of 64 addresses within each address group in
+the grouped modes.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd(8)>
+
+The gdnsd manual.
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (c) 2014 Anton Tolchanov <me@knyar.net>,
+Brandon L Black <blblack@gmail.com>, and Jay Reitz <jreitz@gmail.com>
+
+This file is part of gdnsd.
+
+gdnsd-plugin-weighted 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-plugin-weighted 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-plugin-weighted.  If not, see
+<http://www.gnu.org/licenses/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.pod gdnsd-2.1.2/docs/gdnsd.pod
--- gdnsd-2.1.0/docs/gdnsd.pod	2014-10-11 21:39:30.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,501 +0,0 @@
-
-=head1 NAME
-
-gdnsd - An authoritative DNS daemon
-
-=head1 SYNOPSIS
-
-  Usage: gdnsd [-fsSD] [-c @GDNSD_DEFPATH_CONFIG@] <action>
-    -D - Enable verbose debug output
-    -f - Foreground mode for [re]start actions
-    -s - Force 'zones_strict_startup = true' for this invocation
-    -S - Force 'zones_strict_data = true' for this invocation
-    -c - Configuration directory
-    -x - No syslog output (must use -f with this if [re]start)
-  Actions:
-    checkconf - Checks validity of config and zone files
-    start - Start as a regular daemon
-    stop - Stops a running daemon previously started by 'start'
-    reload-zones - Send SIGUSR1 to running daemon for zone data reload
-    restart - Equivalent to checkconf && stop && start, but faster
-    condrestart - Does 'restart' action only if already running
-    try-restart - Aliases 'condrestart'
-    status - Checks the status of the running daemon
-
-=head1 DESCRIPTION
-
-B<gdnsd> is very fast, light, and pluggable authoritative DNS daemon.
-
-=head1 BASIC SECURITY
-
-When started as the C<root> user, gdnsd will always attempt to drop
-privileges to another user, and will fail fatally if that does not
-succeed.  The default username for this is C<gdnsd>, but this can
-be overridden in the main config file.
-
-=head1 BASIC CONFIGURATION
-
-The primary configuration file is the file named F<config> in the
-configuration directory.
-
-Note that the configuration file does not have to exist for successful
-startup.  Without a configuration file, gdnsd will load all of the zones
-in the zones directory and listen on port 53 of C<0.0.0.0> and C<::>
-using default settings.  It will also, by default, automatically process
-changes (add/delete/update) to the set of zonefiles present in the zones
-directory, which defaults to the F<zones/> subdirectory of the configuration
-directory (C<@GDNSD_DEFPATH_CONFIG@/zones/>).
-
-=head1 COMMANDLINE OPTION FLAGS
-
-=over 4
-
-=item B<-c>
-
-Set the configuration directory, defaults to F<@GDNSD_DEFPATH_CONFIG@>.
-
-=item B<-f>
-
-Sets foreground mode for the start, restart, condrestart, or try-restart
-actions.  All other actions are implicitly foreground operations and
-ignore this flag.  When [re]starting with C<-f>, the new daemon will not
-use C<fork(); setsid(); fork();> to detach from the terminal, and will
-not close default stdio descriptors or stop mirroring its log output to
-the stdio descriptors at runtime.  Otherwise it behaves the same as an
-invocation without this flag.  See also C<-x> regarding syslog output.
-
-=item B<-s>
-
-Forces the C<zones_strict_startup> configuration option to true for
-this invocation, regardless of the setting in the config file.  This is
-mostly useful for validation during the C<checkconf> option.
-
-=item B<-S>
-
-Forces the C<zones_strict_data> configuration option to true for
-this invocation, regardless of the setting in the config file.  This is
-mostly useful for validation during the C<checkconf> option.
-
-=item B<-D>
-
-Enables additional debugging output to syslog and/or the terminal,
-as appropriate.
-
-=item B<-x>
-
-Disables syslog output completely.  By default, almost all possible
-output from all gdnsd invocations is sent to syslog, even if it is also
-mirrored to the terminal.  The only exception to this rule (well, apart
-from certain early fatal log outputs which are only triggered in the
-case of internal code bugs) is the commandline usage output on invalid
-commandline arguments.
-
-This flag is only legal for the start, restart, condrestart, and
-try-restart options if used in combination with the C<-f> flag (as
-otherwise the resulting daemon could end up with no error output channel
-at all).  It is legal for all other commands (which are all implicitly
-foreground actions, and all also output to syslog by default).
-
-Primarily intended for e.g. linting invocations of checkconf, the
-daemon's testsuite, etc, to avoid spamming syslog with things unrelated
-to a real runtime daemon.
-
-Do not use this flag for a start invocation within a systemd unit file.
-
-=back
-
-=head1 ACTIONS
-
-B<gdnsd> acts as its own initscript, internalizing daemon management
-functions.  All valid invocations of the gdnsd command include an
-B<action>, most of which model normal initscript actions.  You may
-still want a light initscript wrapper to comply with distribution
-standards for e.g. terminal output on success/failure, setting
-up resource and security limits, etc, but it's not necessary for
-basic functionality.
-
-=over 4
-
-=item B<checkconf>
-
-Checks the validity of the configuration file and zonefiles, setting
-the exit status appropriately (0 for success).
-
-The C<start>, and all C<restart>-like actions implicitly do
-the same checks as C<checkconf> as they load the configuration for
-runtime use.
-
-=item B<start>
-
-Starts gdnsd as a runtime DNS daemon.
-
-=item B<stop>
-
-Stops a gdnsd daemon previously started by start.
-
-=item B<restart>
-
-This is equivalent to the sequence C<checkconf && stop && start>.  What
-actually happens behind the scenes is a bit more complicated, with the
-goal of making restarts as seamless and downtime-free as possible.
-
-C<restart> is a special case of C<start> which first completely starts
-itself (including the acquisition of listening sockets, if possible, see
-below) and is ready to answer requests *before* it stops the previous
-instance of the daemon.  This eliminates any stop -> start delays from
-expensive startup steps like parsing large numbers of zonefiles and/or
-polling for initial monitoring results on a large number of resources.
-
-On platforms where C<SO_REUSEPORT> works correctly, the new daemon
-uses this option (as did the old) to start its listening sockets in
-parallel with those of the previous daemon just before sending the
-termination signal to it, to eliminate any window of true unavailability.
-However, keep in mind that a handful of requests will still be lost:
-those which were already in the local socket buffers for the old instance
-when it exited.
-
-If C<SO_REUSEPORT> isn't supported or doesn't work properly, the daemon
-will re-attempt its socket acquisition after the short delay of waiting
-for the previous daemon's pid to exit.  The delay should normally be
-fairly constant (does not scale up with zones/configuration) and minimal
-in these cases, on the order of <1s.
-
-C<SO_REUSEPORT> became available in Linux starting with kernel
-version 3.9.  BSDs have had it for much longer.
-
-Note: C<restart> will B<not> work correctly for a daemon that's running
-under systemd, no matter how it's executed.  Executing it from the
-commandline will sort-of work in that it will replace the daemon that's
-running as a systemd service with one that isn't a systemd service, but
-that probably isn't what you want to do.  Those running under systemd
-will need to use e.g.  C<systemctl restart gdnsd>, which will do a full
-serial stop -> start cycle, in order for configuration changes to take
-effect.
-
-=item B<reload-zones>
-
-Sends C<SIGUSR1> to the running daemon, forcing a manual re-check
-of the zones directory for updated files.  Generally this should
-only be necessary if the configuration option C<zones_rfc1035_auto>
-has been explicitly set to C<false>, disabling the default mode
-where gdnsd continuously monitors for and loads zonefile data
-changes.
-
-It is not advised to set up an initscript C<reload> action which
-invokes C<reload-zones>, as a future version of gdnsd will very likely
-include a true reload action for full re-configuration without
-restart.  It's better to leave the canonical reload action undefined
-for now to reduce incompatibilities and/or surprises when that update
-occurs.
-
-=item B<condrestart>
-
-This is basically "restart only if already running".
-
-Performs the same actions as C<restart>, but aborts early
-(with a successful exit value) if the daemon was not already
-running.
-
-=item B<try-restart>
-
-Alias for C<condrestart>.
-
-=item B<status>
-
-Checks the status of the running daemon, returning 0 if it
-is running or non-zero if it isn't.
-
-=back
-
-Any other commandline option will be treated as invalid,
-which will result in displaying a short help text to F<STDERR>
-and exiting with a non-zero exit status.  This includes
-things like the ubiquitous B<--help> and B<--version>.
-
-=head1 ZONE FILES - RFC1035
-
-The directory for standard RFC1035 zone files (the default
-zone data backend) is the subdirectory named C<zones> in the
-configuration directory, so the default would be
-F<@GDNSD_DEFPATH_CONFIG@/zones/>.
-
-RFC1035 zone files are the traditional zone file format that
-one typically uses with e.g. BIND.  For more information on
-the internal format and processing of these files, see
-L<gdnsd.zonefile(5)>.  This section is about how the directory
-itself is managed.
-
-All files in the zones directory are considered zone files.
-In general there should be exactly one file per zone, and the
-filename should match the zone name.  Filenames beginning with
-C<.> are ignored.  All zone file must be regular files
-(as opposed to directories, symlinks, sockets, etc).
-
-By default, the zones directory is handled dynamically: as files
-are added, modified, and deleted in this directory, zone data will
-automatically update at runtime.  This feature can be disabled
-(such that an explicit SIGUSR1 or C<gdnsd reload-zones> is required to
-re-scan for changes) in the config file via the directive
-C<zones_rfc1035_auto> (see L<gdnsd.config(5)>).  It is legal for
-the directory to be empty at startup, which results in all queries
-returning C<REFUSED>.
-
-In order to better support the special case of RFC 2137 -style
-classless in-addr.arpa delegation zones (which contain forward
-slashes), any C<@> symbol in the filename will be translated
-to a forward slash (C</>) when transforming a filename into
-its corresponding zone name.
-
-For similar reasons, if your server is intended to serve the
-root of the DNS, the filename for the root zone should be
-the special filename F<ROOT_ZONE>, rather than the impossible
-literal filename F<.>.  Because authoritative servers cannot
-serve two domains which have a parent<->child relationship
-correctly, a root server cannot serve any other zone, so this
-would be the sole zonefile.
-
-The standard DNS zone file escape sequences are recognized within
-the filenames (e.g. C<\.> for a dot within a label, or C<\NNN>
-where NNN is a decimal integer in the range 0 - 255), if for some
-reason you need a strange character in your zone name.
-
-Trailing dots on zonefile names are ignored; e.g. F<example.com>
-and F<example.com.> are functionally equivalent.
-
-Duplicate zones (e.g. having both of the above representations of
-C<example.com> present in the zones directory, and/or adding a
-different case-mapping such as F<EXample.Com>) are handled by
-loading both and giving runtime lookup priority to one of the copies
-based on a couple of simple rules: the highest C<serial> wins,
-and if more than one file has the highest serial, the highest
-filesystem C<mtime> value wins.  If the primary copy is later
-removed, any remaining copy of the zone will be promoted for
-runtime lookups according to that same ordering.
-
-Subzones (e.g. having zonefiles for both C<example.com> and
-C<subz.example.com>) are only marginally supported.  The child zone
-will be loaded into memory, but its data won't be available for
-lookup, as it is suppressed by the existence of the parent zone.
-If the parent zone is later removed, the subzone data will become
-available.  Logically, it is not possible for a single server to
-be authoritative for both a subzone and its parent zone at the
-same time, as each "role" (parent and child) requires different
-responses to requests for data within the child zone.  gdnsd
-choses to default to the "parent" role in these conflict cases.
-
-=head1 ZONE FILES - DJBDNS
-
-There is now experimental support for djbdns-format zonefiles
-in the F<djbdns> subdirectory of the config directory
-(default F<@GDNSD_DEFPATH_CONFIG@/djbdns/>.  For more information
-see L<gdnsd.djbdns(5)>.
-
-If the same zone is specified via more than one zone data backend
-(e.g. rfc1035 + djbdns), the same rules shown in the above section
-apply: both will be loaded and managed, but only one will be used
-for queries at any given time (based on mtime/serial).
-
-=head1 DIRECTORIES
-
-Important directory paths for the core daemon code:
-
-=over 4
-
-=item F<@GDNSD_DEFPATH_CONFIG@>
-
-Default configuration directory, unless overridden via C<-c>.  The
-primary configuration file is always the file F<config> in the
-configuration directory.
-
-=item F<@GDNSD_DEFPATH_RUN@>
-
-Default run_dir.  The daemon will store a pidfile here (which is
-not intended for reliable text-based consumption by third parties).
-See the entry for C<run_dir> in the L<gdnsd.config(5)> manpage
-for more information about this directory.
-
-=item F<@GDNSD_DEFPATH_STATE@>
-
-Default state_dir.  The F<admin_state> file is read from this directory
-for administrative state-overrides on monitored resouces, see below
-in the FILES section.  See the entry for C<state_dir> in the
-L<gdnsd.config(5)> manpage for more information about this directory.
-
-=item F<@GDNSD_DEFPATH_LIB@>
-
-This is the default path that plugin shared libraries are loaded from.
-Other directories can be prepended to the search path via the configuration
-option C<plugin_search_path>, documented in L<gdnsd.config(5)>.
-
-=item F<@GDNSD_DEFPATH_LIBEXEC@>
-
-This is the default path for daemon-private executables that users should
-not run.  The only current case is F<gdnsd_extmon_helper> for the
-extmon plugin and the path for this can be overridden in that plugin's
-configuration, documented in L<gdnsd-plugin-extmon(8)>.
-
-=back
-
-=head1 ADMIN STATE FILE - F<@GDNSD_DEFPATH_STATE@/admin_state>
-
-This file is the input for administrative state overrides affecting plugin
-resolution decisions.  The intent of this file is to allow explicit, human
-administrative decisions to temporarily override the states affecting plugin
-decision-making on issues of failover and/or geographic distribution.  A
-non-existent file is treated the same as an empty file.  The file is watched
-at runtime for changes, and any overridden state found is applied quickly.
-The file is expected to persist reboots and daemon restarts in order to
-preserve the administrator's intent through these events.
-
-A basic understanding of how both monitoring and resolution plugins in gdnsd
-work is assumed (see L<gdnsd.config(5)>).  This file is parsed as a vscf hash
-data structure (again, see L<gdnsd.config(5)> for deeper details of that format).
-The keys are the names of monitored or virtual resources, and the values are
-forced state values (optionally with monitored-TTL values as well).  Keys
-can also be wildcards using the shell glob syntax which affect multiple
-resources.
-
-For normal monitored resources, the typical form of a key would be
-C<THING/service_type>, where C<THING> is the monitored address or CNAME value
-and C<service_type> is the service_type configured to monitor that address
-or CNAME value by one or more resolver plugins.  The value portion takes
-the form of C<STATE[/TTL]>, where C<STATE> is C<UP> or C<DOWN> and the TTL
-portion is an optional override of the monitored TTL.
-
-The order of the lines in the file is important; they are processed and applied
-in-order such that later lines can override the actions of earlier lines.  This
-is especially handy for making exceptions to glob-matches.
-
-Example:
-
-    @GDNSD_DEFPATH_STATE@/admin_state:
-        2001:db8::2:123/my_http_check => DOWN # down a specific res+stype
-        foo.example.com./extmon_ping => UP # up a specific res+stype
-        192.0.2.1/* => DOWN # down all service_types for this address
-        */xmpp => UP/30 # up all resources monitored by xmpp w/ TTL 30 ...
-        192.0.2.2/xmpp => DOWN # ... except this one
-
-Some resolution plugins can also register virtual resources (which are not
-monitored by any C<service_type>) solely for the purpose of administrative
-override of decision-making.  Currently the geoip and metafo plugins do this
-for their C<datacenters>, and the keys they create take the form of
-C<plugin_name/resname/dcname> to force a datacenter's state at the
-per-resource level.  The geoip plugin also supports keys of the form
-C<plugin_name/mapname/dcname> to force a datacenter's state
-at the per-map level.  These forcings override the aggregate state passed
-up to geoip/metafo from per-datacenter plugins (e.g. multifo or weighted
-monitoring several addresses in a datacenter), and in the geoip case
-the more-specific per-resource forced state will override any per-map
-forced state.
-
-Example:
-
-    @GDNSD_DEFPATH_STATE@/admin_state:
-        geoip/map3/dc-us => DOWN # down dc-us in geoip map3
-        */dc-jp => DOWN # down all datacenters named dc-jp for geoip and metafo
-        metafo/res_www/dc-jp => UP # exception to above
-
-All of the available monitored and virtual keys that can be matched in this
-file are listed in the daemon's HTML, CSV, and JSON -format outputs from
-the built-in status http server (default port 3506), as are their current
-monitors and admin_state-forced states.
-
-=head1 SYSTEMD COMPATIBILITY
-
-This daemon is implicitly compatible with running as a systemd service
-on Linux, and should have come with a ready-made unit file during
-installation that works correctly.
-
-When the daemon detects that it's running underneath systemd as a unit
-(by detecting that systemd is the running init system and that gdnsd's
-initial parent pid is C<1>), it makes some changes to its default
-behaviors to be more systemd-friendly.  This includes shutting off stdio
-output very early (as soon as syslog is open) because the stdio and
-syslog output channels are redundant under systemd and lead to duplicate
-messages in the journal.  It also makes use of systemd's notification
-socket to coordinate operations with the init system.
-
-Because of these things, it is critical that the gdnsd unit file uses
-the C<NotifyAccess=all> setting, and that the C<ExecStart=> command for
-gdnsd uses a commandline that resembles C<gdnsd -f start> and
-does not use C<-x> (other extra options are ok).
-
-Example unit file contents for the Service section:
-
-    [Service]
-    Type=notify
-    NotifyAccess=all
-    ExecStart=@GDNSD_SBINDIR@/gdnsd -f start
-    ExecStop=@GDNSD_SBINDIR@/gdnsd stop
-
-It is not advised to set up C<ExecReload=@GDNSD_SBINDIR@/gdnsd reload-zones>
-to re-purpose the systemctl reload action for zone reloads, as a future
-version of gdnsd will very likely include a real option for full configuration
-reload under systemd, which would change this behavior.  It's better to leave
-the canonical reload action undefined for now to reduce incompatibilities
-and/or surprises when that update occurs.  It is even less advised to
-try to configure C<ExecReload=@GDNSD_SBINDIR@/gdnsd restart>, as this
-will B<not> work!
-
-In general, if you're running gdnsd as a systemd service, you should use
-the supplied style of unit file and use C<systemctl> for daemon control
-(e.g. start, stop, restart, status), and use C<@GDNSD_SBINDIR@/gdnsd reload-zones>
-for zone reloads.
-
-=head1 SIGNALS
-
-Any signal not explicitly mentioned is not explicitly handled.  That
-is to say, they will have their default actions, which often include
-aborting execution.
-
-=over 4
-
-=item B<SIGTERM>, B<SIGINT>
-
-Causes the daemon to exit gracefully with accompanying log output.
-
-=item B<SIGUSR1>
-
-Causes the daemon to attempt to load any new changes to the zone data.
-
-=item B<SIGHUP>
-
-Ignored during daemon runtime.
-
-=item B<SIGPIPE>
-
-Ignored always.
-
-=back
-
-=head1 EXIT STATUS
-
-An exit status of zero indicates success, anything else indicates
-failure.
-
-=head1 SEE ALSO
-
-L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd.djbdns(5)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.podin gdnsd-2.1.2/docs/gdnsd.podin
--- gdnsd-2.1.0/docs/gdnsd.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,501 @@
+
+=head1 NAME
+
+gdnsd - An authoritative DNS daemon
+
+=head1 SYNOPSIS
+
+  Usage: gdnsd [-fsSD] [-c @GDNSD_DEFPATH_CONFIG@] <action>
+    -D - Enable verbose debug output
+    -f - Foreground mode for [re]start actions
+    -s - Force 'zones_strict_startup = true' for this invocation
+    -S - Force 'zones_strict_data = true' for this invocation
+    -c - Configuration directory
+    -x - No syslog output (must use -f with this if [re]start)
+  Actions:
+    checkconf - Checks validity of config and zone files
+    start - Start as a regular daemon
+    stop - Stops a running daemon previously started by 'start'
+    reload-zones - Send SIGUSR1 to running daemon for zone data reload
+    restart - Equivalent to checkconf && stop && start, but faster
+    condrestart - Does 'restart' action only if already running
+    try-restart - Aliases 'condrestart'
+    status - Checks the status of the running daemon
+
+=head1 DESCRIPTION
+
+B<gdnsd> is very fast, light, and pluggable authoritative DNS daemon.
+
+=head1 BASIC SECURITY
+
+When started as the C<root> user, gdnsd will always attempt to drop
+privileges to another user, and will fail fatally if that does not
+succeed.  The default username for this is C<gdnsd>, but this can
+be overridden in the main config file.
+
+=head1 BASIC CONFIGURATION
+
+The primary configuration file is the file named F<config> in the
+configuration directory.
+
+Note that the configuration file does not have to exist for successful
+startup.  Without a configuration file, gdnsd will load all of the zones
+in the zones directory and listen on port 53 of C<0.0.0.0> and C<::>
+using default settings.  It will also, by default, automatically process
+changes (add/delete/update) to the set of zonefiles present in the zones
+directory, which defaults to the F<zones/> subdirectory of the configuration
+directory (C<@GDNSD_DEFPATH_CONFIG@/zones/>).
+
+=head1 COMMANDLINE OPTION FLAGS
+
+=over 4
+
+=item B<-c>
+
+Set the configuration directory, defaults to F<@GDNSD_DEFPATH_CONFIG@>.
+
+=item B<-f>
+
+Sets foreground mode for the start, restart, condrestart, or try-restart
+actions.  All other actions are implicitly foreground operations and
+ignore this flag.  When [re]starting with C<-f>, the new daemon will not
+use C<fork(); setsid(); fork();> to detach from the terminal, and will
+not close default stdio descriptors or stop mirroring its log output to
+the stdio descriptors at runtime.  Otherwise it behaves the same as an
+invocation without this flag.  See also C<-x> regarding syslog output.
+
+=item B<-s>
+
+Forces the C<zones_strict_startup> configuration option to true for
+this invocation, regardless of the setting in the config file.  This is
+mostly useful for validation during the C<checkconf> option.
+
+=item B<-S>
+
+Forces the C<zones_strict_data> configuration option to true for
+this invocation, regardless of the setting in the config file.  This is
+mostly useful for validation during the C<checkconf> option.
+
+=item B<-D>
+
+Enables additional debugging output to syslog and/or the terminal,
+as appropriate.
+
+=item B<-x>
+
+Disables syslog output completely.  By default, almost all possible
+output from all gdnsd invocations is sent to syslog, even if it is also
+mirrored to the terminal.  The only exception to this rule (well, apart
+from certain early fatal log outputs which are only triggered in the
+case of internal code bugs) is the commandline usage output on invalid
+commandline arguments.
+
+This flag is only legal for the start, restart, condrestart, and
+try-restart options if used in combination with the C<-f> flag (as
+otherwise the resulting daemon could end up with no error output channel
+at all).  It is legal for all other commands (which are all implicitly
+foreground actions, and all also output to syslog by default).
+
+Primarily intended for e.g. linting invocations of checkconf, the
+daemon's testsuite, etc, to avoid spamming syslog with things unrelated
+to a real runtime daemon.
+
+Do not use this flag for a start invocation within a systemd unit file.
+
+=back
+
+=head1 ACTIONS
+
+B<gdnsd> acts as its own initscript, internalizing daemon management
+functions.  All valid invocations of the gdnsd command include an
+B<action>, most of which model normal initscript actions.  You may
+still want a light initscript wrapper to comply with distribution
+standards for e.g. terminal output on success/failure, setting
+up resource and security limits, etc, but it's not necessary for
+basic functionality.
+
+=over 4
+
+=item B<checkconf>
+
+Checks the validity of the configuration file and zonefiles, setting
+the exit status appropriately (0 for success).
+
+The C<start>, and all C<restart>-like actions implicitly do
+the same checks as C<checkconf> as they load the configuration for
+runtime use.
+
+=item B<start>
+
+Starts gdnsd as a runtime DNS daemon.
+
+=item B<stop>
+
+Stops a gdnsd daemon previously started by start.
+
+=item B<restart>
+
+This is equivalent to the sequence C<checkconf && stop && start>.  What
+actually happens behind the scenes is a bit more complicated, with the
+goal of making restarts as seamless and downtime-free as possible.
+
+C<restart> is a special case of C<start> which first completely starts
+itself (including the acquisition of listening sockets, if possible, see
+below) and is ready to answer requests *before* it stops the previous
+instance of the daemon.  This eliminates any stop -> start delays from
+expensive startup steps like parsing large numbers of zonefiles and/or
+polling for initial monitoring results on a large number of resources.
+
+On platforms where C<SO_REUSEPORT> works correctly, the new daemon
+uses this option (as did the old) to start its listening sockets in
+parallel with those of the previous daemon just before sending the
+termination signal to it, to eliminate any window of true unavailability.
+However, keep in mind that a handful of requests will still be lost:
+those which were already in the local socket buffers for the old instance
+when it exited.
+
+If C<SO_REUSEPORT> isn't supported or doesn't work properly, the daemon
+will re-attempt its socket acquisition after the short delay of waiting
+for the previous daemon's pid to exit.  The delay should normally be
+fairly constant (does not scale up with zones/configuration) and minimal
+in these cases, on the order of <1s.
+
+C<SO_REUSEPORT> became available in Linux starting with kernel
+version 3.9.  BSDs have had it for much longer.
+
+Note: C<restart> will B<not> work correctly for a daemon that's running
+under systemd, no matter how it's executed.  Executing it from the
+commandline will sort-of work in that it will replace the daemon that's
+running as a systemd service with one that isn't a systemd service, but
+that probably isn't what you want to do.  Those running under systemd
+will need to use e.g.  C<systemctl restart gdnsd>, which will do a full
+serial stop -> start cycle, in order for configuration changes to take
+effect.
+
+=item B<reload-zones>
+
+Sends C<SIGUSR1> to the running daemon, forcing a manual re-check
+of the zones directory for updated files.  Generally this should
+only be necessary if the configuration option C<zones_rfc1035_auto>
+has been explicitly set to C<false>, disabling the default mode
+where gdnsd continuously monitors for and loads zonefile data
+changes.
+
+It is not advised to set up an initscript C<reload> action which
+invokes C<reload-zones>, as a future version of gdnsd will very likely
+include a true reload action for full re-configuration without
+restart.  It's better to leave the canonical reload action undefined
+for now to reduce incompatibilities and/or surprises when that update
+occurs.
+
+=item B<condrestart>
+
+This is basically "restart only if already running".
+
+Performs the same actions as C<restart>, but aborts early
+(with a successful exit value) if the daemon was not already
+running.
+
+=item B<try-restart>
+
+Alias for C<condrestart>.
+
+=item B<status>
+
+Checks the status of the running daemon, returning 0 if it
+is running or non-zero if it isn't.
+
+=back
+
+Any other commandline option will be treated as invalid,
+which will result in displaying a short help text to F<STDERR>
+and exiting with a non-zero exit status.  This includes
+things like the ubiquitous B<--help> and B<--version>.
+
+=head1 ZONE FILES - RFC1035
+
+The directory for standard RFC1035 zone files (the default
+zone data backend) is the subdirectory named C<zones> in the
+configuration directory, so the default would be
+F<@GDNSD_DEFPATH_CONFIG@/zones/>.
+
+RFC1035 zone files are the traditional zone file format that
+one typically uses with e.g. BIND.  For more information on
+the internal format and processing of these files, see
+L<gdnsd.zonefile(5)>.  This section is about how the directory
+itself is managed.
+
+All files in the zones directory are considered zone files.
+In general there should be exactly one file per zone, and the
+filename should match the zone name.  Filenames beginning with
+C<.> are ignored.  All zone file must be regular files
+(as opposed to directories, symlinks, sockets, etc).
+
+By default, the zones directory is handled dynamically: as files
+are added, modified, and deleted in this directory, zone data will
+automatically update at runtime.  This feature can be disabled
+(such that an explicit SIGUSR1 or C<gdnsd reload-zones> is required to
+re-scan for changes) in the config file via the directive
+C<zones_rfc1035_auto> (see L<gdnsd.config(5)>).  It is legal for
+the directory to be empty at startup, which results in all queries
+returning C<REFUSED>.
+
+In order to better support the special case of RFC 2137 -style
+classless in-addr.arpa delegation zones (which contain forward
+slashes), any C<@> symbol in the filename will be translated
+to a forward slash (C</>) when transforming a filename into
+its corresponding zone name.
+
+For similar reasons, if your server is intended to serve the
+root of the DNS, the filename for the root zone should be
+the special filename F<ROOT_ZONE>, rather than the impossible
+literal filename F<.>.  Because authoritative servers cannot
+serve two domains which have a parent<->child relationship
+correctly, a root server cannot serve any other zone, so this
+would be the sole zonefile.
+
+The standard DNS zone file escape sequences are recognized within
+the filenames (e.g. C<\.> for a dot within a label, or C<\NNN>
+where NNN is a decimal integer in the range 0 - 255), if for some
+reason you need a strange character in your zone name.
+
+Trailing dots on zonefile names are ignored; e.g. F<example.com>
+and F<example.com.> are functionally equivalent.
+
+Duplicate zones (e.g. having both of the above representations of
+C<example.com> present in the zones directory, and/or adding a
+different case-mapping such as F<EXample.Com>) are handled by
+loading both and giving runtime lookup priority to one of the copies
+based on a couple of simple rules: the highest C<serial> wins,
+and if more than one file has the highest serial, the highest
+filesystem C<mtime> value wins.  If the primary copy is later
+removed, any remaining copy of the zone will be promoted for
+runtime lookups according to that same ordering.
+
+Subzones (e.g. having zonefiles for both C<example.com> and
+C<subz.example.com>) are only marginally supported.  The child zone
+will be loaded into memory, but its data won't be available for
+lookup, as it is suppressed by the existence of the parent zone.
+If the parent zone is later removed, the subzone data will become
+available.  Logically, it is not possible for a single server to
+be authoritative for both a subzone and its parent zone at the
+same time, as each "role" (parent and child) requires different
+responses to requests for data within the child zone.  gdnsd
+choses to default to the "parent" role in these conflict cases.
+
+=head1 ZONE FILES - DJBDNS
+
+There is now experimental support for djbdns-format zonefiles
+in the F<djbdns> subdirectory of the config directory
+(default F<@GDNSD_DEFPATH_CONFIG@/djbdns/>.  For more information
+see L<gdnsd.djbdns(5)>.
+
+If the same zone is specified via more than one zone data backend
+(e.g. rfc1035 + djbdns), the same rules shown in the above section
+apply: both will be loaded and managed, but only one will be used
+for queries at any given time (based on mtime/serial).
+
+=head1 DIRECTORIES
+
+Important directory paths for the core daemon code:
+
+=over 4
+
+=item F<@GDNSD_DEFPATH_CONFIG@>
+
+Default configuration directory, unless overridden via C<-c>.  The
+primary configuration file is always the file F<config> in the
+configuration directory.
+
+=item F<@GDNSD_DEFPATH_RUN@>
+
+Default run_dir.  The daemon will store a pidfile here (which is
+not intended for reliable text-based consumption by third parties).
+See the entry for C<run_dir> in the L<gdnsd.config(5)> manpage
+for more information about this directory.
+
+=item F<@GDNSD_DEFPATH_STATE@>
+
+Default state_dir.  The F<admin_state> file is read from this directory
+for administrative state-overrides on monitored resouces, see below
+in the FILES section.  See the entry for C<state_dir> in the
+L<gdnsd.config(5)> manpage for more information about this directory.
+
+=item F<@GDNSD_DEFPATH_LIB@>
+
+This is the default path that plugin shared libraries are loaded from.
+Other directories can be prepended to the search path via the configuration
+option C<plugin_search_path>, documented in L<gdnsd.config(5)>.
+
+=item F<@GDNSD_DEFPATH_LIBEXEC@>
+
+This is the default path for daemon-private executables that users should
+not run.  The only current case is F<gdnsd_extmon_helper> for the
+extmon plugin and the path for this can be overridden in that plugin's
+configuration, documented in L<gdnsd-plugin-extmon(8)>.
+
+=back
+
+=head1 ADMIN STATE FILE - F<@GDNSD_DEFPATH_STATE@/admin_state>
+
+This file is the input for administrative state overrides affecting plugin
+resolution decisions.  The intent of this file is to allow explicit, human
+administrative decisions to temporarily override the states affecting plugin
+decision-making on issues of failover and/or geographic distribution.  A
+non-existent file is treated the same as an empty file.  The file is watched
+at runtime for changes, and any overridden state found is applied quickly.
+The file is expected to persist reboots and daemon restarts in order to
+preserve the administrator's intent through these events.
+
+A basic understanding of how both monitoring and resolution plugins in gdnsd
+work is assumed (see L<gdnsd.config(5)>).  This file is parsed as a vscf hash
+data structure (again, see L<gdnsd.config(5)> for deeper details of that format).
+The keys are the names of monitored or virtual resources, and the values are
+forced state values (optionally with monitored-TTL values as well).  Keys
+can also be wildcards using the shell glob syntax which affect multiple
+resources.
+
+For normal monitored resources, the typical form of a key would be
+C<THING/service_type>, where C<THING> is the monitored address or CNAME value
+and C<service_type> is the service_type configured to monitor that address
+or CNAME value by one or more resolver plugins.  The value portion takes
+the form of C<STATE[/TTL]>, where C<STATE> is C<UP> or C<DOWN> and the TTL
+portion is an optional override of the monitored TTL.
+
+The order of the lines in the file is important; they are processed and applied
+in-order such that later lines can override the actions of earlier lines.  This
+is especially handy for making exceptions to glob-matches.
+
+Example:
+
+    @GDNSD_DEFPATH_STATE@/admin_state:
+        2001:db8::2:123/my_http_check => DOWN # down a specific res+stype
+        foo.example.com./extmon_ping => UP # up a specific res+stype
+        192.0.2.1/* => DOWN # down all service_types for this address
+        */xmpp => UP/30 # up all resources monitored by xmpp w/ TTL 30 ...
+        192.0.2.2/xmpp => DOWN # ... except this one
+
+Some resolution plugins can also register virtual resources (which are not
+monitored by any C<service_type>) solely for the purpose of administrative
+override of decision-making.  Currently the geoip and metafo plugins do this
+for their C<datacenters>, and the keys they create take the form of
+C<plugin_name/resname/dcname> to force a datacenter's state at the
+per-resource level.  The geoip plugin also supports keys of the form
+C<plugin_name/mapname/dcname> to force a datacenter's state
+at the per-map level.  These forcings override the aggregate state passed
+up to geoip/metafo from per-datacenter plugins (e.g. multifo or weighted
+monitoring several addresses in a datacenter), and in the geoip case
+the more-specific per-resource forced state will override any per-map
+forced state.
+
+Example:
+
+    @GDNSD_DEFPATH_STATE@/admin_state:
+        geoip/map3/dc-us => DOWN # down dc-us in geoip map3
+        */dc-jp => DOWN # down all datacenters named dc-jp for geoip and metafo
+        metafo/res_www/dc-jp => UP # exception to above
+
+All of the available monitored and virtual keys that can be matched in this
+file are listed in the daemon's HTML, CSV, and JSON -format outputs from
+the built-in status http server (default port 3506), as are their current
+monitors and admin_state-forced states.
+
+=head1 SYSTEMD COMPATIBILITY
+
+This daemon is implicitly compatible with running as a systemd service
+on Linux, and should have come with a ready-made unit file during
+installation that works correctly.
+
+When the daemon detects that it's running underneath systemd as a unit
+(by detecting that systemd is the running init system and that gdnsd's
+initial parent pid is C<1>), it makes some changes to its default
+behaviors to be more systemd-friendly.  This includes shutting off stdio
+output very early (as soon as syslog is open) because the stdio and
+syslog output channels are redundant under systemd and lead to duplicate
+messages in the journal.  It also makes use of systemd's notification
+socket to coordinate operations with the init system.
+
+Because of these things, it is critical that the gdnsd unit file uses
+the C<NotifyAccess=all> setting, and that the C<ExecStart=> command for
+gdnsd uses a commandline that resembles C<gdnsd -f start> and
+does not use C<-x> (other extra options are ok).
+
+Example unit file contents for the Service section:
+
+    [Service]
+    Type=notify
+    NotifyAccess=all
+    ExecStart=@GDNSD_SBINDIR@/gdnsd -f start
+    ExecStop=@GDNSD_SBINDIR@/gdnsd stop
+
+It is not advised to set up C<ExecReload=@GDNSD_SBINDIR@/gdnsd reload-zones>
+to re-purpose the systemctl reload action for zone reloads, as a future
+version of gdnsd will very likely include a real option for full configuration
+reload under systemd, which would change this behavior.  It's better to leave
+the canonical reload action undefined for now to reduce incompatibilities
+and/or surprises when that update occurs.  It is even less advised to
+try to configure C<ExecReload=@GDNSD_SBINDIR@/gdnsd restart>, as this
+will B<not> work!
+
+In general, if you're running gdnsd as a systemd service, you should use
+the supplied style of unit file and use C<systemctl> for daemon control
+(e.g. start, stop, restart, status), and use C<@GDNSD_SBINDIR@/gdnsd reload-zones>
+for zone reloads.
+
+=head1 SIGNALS
+
+Any signal not explicitly mentioned is not explicitly handled.  That
+is to say, they will have their default actions, which often include
+aborting execution.
+
+=over 4
+
+=item B<SIGTERM>, B<SIGINT>
+
+Causes the daemon to exit gracefully with accompanying log output.
+
+=item B<SIGUSR1>
+
+Causes the daemon to attempt to load any new changes to the zone data.
+
+=item B<SIGHUP>
+
+Ignored during daemon runtime.
+
+=item B<SIGPIPE>
+
+Ignored always.
+
+=back
+
+=head1 EXIT STATUS
+
+An exit status of zero indicates success, anything else indicates
+failure.
+
+=head1 SEE ALSO
+
+L<gdnsd.config(5)>, L<gdnsd.zonefile(5)>, L<gdnsd.djbdns(5)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.zonefile.pod gdnsd-2.1.2/docs/gdnsd.zonefile.pod
--- gdnsd-2.1.0/docs/gdnsd.zonefile.pod	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.zonefile.pod	1970-01-01 00:00:00.000000000 +0000
@@ -1,233 +0,0 @@
-
-=head1 NAME
-
-gdnsd.zonefile - gdnsd zonefile syntax
-
-=head1 SYNOPSIS
-
-example.com:
-
-  $TTL 86400
-
-  @	SOA ns1 hostmaster (
-  	1      ; serial
-  	7200   ; refresh
-  	30M    ; retry
-  	3D     ; expire
-  	900    ; ncache
-  )
-
-  @	NS	ns1.example.com.
-  @	NS	ns2
-  @	NS	ns.example.net.
-
-  ns1	A	192.0.2.1 ; a comment
-  ns2.example.com.	A	192.0.2.2
-
-  @	7200	MX	10 mail-a
-  @	7200	MX	100 mail-b
-
-  $ttl 86400
-  ; a comment
-  mail-a	A 192.0.2.3
-  mail-b	A 192.0.2.4
-
-  subz		NS	ns1.subz
-  subz		NS	ns2.subz
-  ns1.subz	A	192.0.2.5
-  ns2.subz	A	192.0.2.6
-
-  www	600/10	DYNA	some_plugin!resource_name
-  alias		CNAME	www
-
-  _http._tcp	1800	SRV	5 500 80 www
-
-  foo		TXT	"blah blah" "blah"
-  _spf 		TXT	"v=spf1 ..."
-
-=head1 DESCRIPTION
-
-This is the primary zonefile syntax for L<gdnsd(8)>.  The syntax is
-designed to be as close as possible to the standard zonefile
-syntax from RFC 1035 (which is the "standard" format one
-typically sees with traditional BIND servers).  This document will
-just cover a few important highlights and/or deviations from the norm.
-
-=head1 DIRECTIVES
-
-The standard C<$TTL> and C<$ORIGIN> directives
-are supported with their normal syntax and semantics.
-
-C<$TTL> changes the default TTL of any records coming after it,
-and can occur multiple times.  Note that in the absence of a
-zonefile-level C<$TTL> setting, the default TTL comes from the
-global config option C<zones_default_ttl>, which in turn defaults
-to C<86400> (1 day).
-
-C<$ORIGIN> changes what is appended to unqualified hostnames
-(those lacking a final C<.>) seen in the zone file from that
-point forward, as well as any C<@> entries (which is an alias
-for the current origin).  C<$ORIGIN> itself may also be an unqualified
-name, in which case the previous origin is appended to it.
-Any fully-qualified C<$ORIGIN> must be within the zone described
-by this zonefile.  The default origin is the zone name itself.
-
-C<$ADDR_LIMIT_V4> is a non-standard, gdnsd-specific directive.
-It requires a single unsigned integer argument.  The argument
-limits the total number of C<A> records to include in the server's
-responses for any given C<A> rrset (whether static or dynamic).
-The default limit is zero, which is interpreted as no limit.
-Setting the limit via this directive affects all rrsets until
-the value is changed again by another directive.  gdnsd always
-rotates the RRs of an address RR-set in a round-robin fashion,
-and this rotation occurs before the limit is applied, allowing
-a small pseudo-random subset of a larger list to be delivered
-via this mechanism.
-
-C<$ADDR_LIMIT_V6> same as above, but for IPv6 C<AAAA> rrsets.
-
-The RFC-standard C<$INCLUDE> directive is not supported because
-it would greatly complicate the detection of zone update
-transactions with our current filesystem-based change detection
-scheme.  Most legitimate uses of C<$INCLUDE> to reduce redundancy
-should be replaced with a zonefile-generating script instead,
-perhaps using a template system.
-
-BIND's C<$GENERATE> extension is not supported at this time, but
-there's no fundamental reason it couldn't be added at a later
-date.
-
-=head1 SUPPORTED RESOURCE RECORD TYPES
-
-L<gdnsd(8)> supports the following standard RR types with their
-standard RDATA formats: SOA, A, AAAA, NS, PTR, CNAME, MX, SRV,
-TXT, and NAPTR.  All RRs must be in class C<IN>, which
-is the implicit default.
-
-It also supports the generic format for unknown RR types documented
-in RFC 3597, which has syntax like:
-
-  foo TYPE31337 \# 10 0123456789 ABCDEF0123
-
-... which indicates an RR of numeric type 31337 containing
-10 bytes of RDATA, specified as the final part of the RR as
-a pair of 5-byte hex strings.  See RFC 3597 itself for full
-details.  Note however that gdnsd does not allow using the
-RFC 3597 format for types gdnsd explicitly supports (all of
-which predate 3597 anyways), and that even in the RFC 3597 case
-we still only allow class C<IN> RRs.
-
-Additionally, gdnsd supports two special-case, non-standard
-virtual resource record types DYNA and DYNC:
-
-=head2 DYNA
-
-C<DYNA> is for dynamically-determined address records (both A
-and AAAA) via plugin code.  The right-hand-side of a C<DYNA>
-RR is a plugin name and a resource name separated by an exclamation
-mark.  The named plugin will be fed the resource name and
-the DNS client's IP address and/or edns-client-subnet information,
-and it is up to the plugin code which addresses of which types
-to return in the response.
-
-The dynamic plugin lookup for C<DYNA> will be used anywhere that
-regular C<A> and/or C<AAAA> records would be used.  This includes
-not only direct responses to C<A> and C<AAAA> queries, but also
-things like Additional-section RRs and C<ANY>-query output.
-C<DYNA> cannot co-exist with actual static A or AAAA records
-at the same name, but can co-exist with any other RR-type.
-
-Example:
-
-  ; asks plugin 'geoip' to provide address data from
-  ;  its resource named 'pubwww' for address queries.
-  foo DYNA geoip!pubwww
-  foo MX 10 mail
-
-=head2 DYNC
-
-C<DYNC> has the same syntax as C<DYNA> above, but different data
-rules.  Plugins results returned via C<DYNC> can be either addresses
-or a C<CNAME> record.  C<DYNC> cannot co-exist with B<any> other
-resource record at the same name, much like normal C<CNAME> RRs.
-This also implies that C<DYNC> cannot be used at the zone root,
-as the zone root requires C<NS> and C<SOA> RRs.  While C<DYNC>
-responses are included in C<ANY> queries for the given name,
-they are B<not> used in Additional-section processing, even
-when the plugin responds with address records rather than C<CNAME>.
-
-Example:
-
-  ; asks plugin 'geoip' to provide address data or a CNAME
-  ;  (at the plugin's discretion) for its resource named
-  ;  'www'.  No other RRs of any type for name 'foo' are
-  ;  legal alongside this record.
-  foo DYNC geoip!www
-
-=head2 DYNA/DYNC TTLs
-
-C<DYNA> and C<DYNC> TTL fields have a syntax extension and slightly
-different meanings than the TTL field of a traditional, fixed RR.
-The format for DYNA/DYNC TTLs is C<MAX[/MIN]>, with C<MIN> defaulting
-to half of C<MAX> if not specified explicitly.
-
-Based on the configuration and state of the underlying monitored services,
-(see "service_types" in L<gdnsd.config(8)>), gdnsd knows the minimum time
-to the next possible state-change which could affect a given C<DYNA> or
-C<DYNC> result.  For example, given the configuration and state, it may
-be known that in order for a currently C<DOWN> address to transition to
-the C<UP> state (and thus change the answer to a given query) would require
-7 more successful monitoring checks in a row at 8-second intervals, and
-therefore cannot happen in less than 56 seconds.  In this case 56 seconds
-would be the internally-calculated TTL.
-
-In cases where multiple monitored resources factor into a plugin's
-decision and/or response (e.g. multifo), the calculated TTL will generally
-be the minimum of all involved internal monitoring TTLs.  This calculated
-TTL is then clamped to the C<MAX> and C<MIN> limits from the zonefile.
-
-Examples:
-
-    ; Explicit range of 30 - 300:
-    www 300/30 DYNC weighted!foo
-    ; Implicit range of 150 - 300:
-    www 300 DYNA metafo!myservice
-    ; Avoid all TTL-mangling and use a fixed value of 10 minutes:
-    www 600/600 DYNA geoip!foo-dist
-
-=head2 TXT data auto-splitting
-
-gdnsd's C<TXT> RRs support the auto-splitting
-of long string constants.  Rather than manually breaking the
-data into 255-byte chunks as required by the protocol, you can
-specify a single long chunk and have the server break it at
-255 byte boundaries automatically.  (this behavior can be
-disabled via L<gdnsd.config(5)> as well, which will turn
-oversized chunks into zonefile parsing errors).
-
-=head1 SEE ALSO
-
-L<gdnsd(8)>, L<gdnsd.config(5)>
-
-The gdnsd manual.
-
-=head1 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/>.
-
-=cut
diff -Nru gdnsd-2.1.0/docs/gdnsd.zonefile.podin gdnsd-2.1.2/docs/gdnsd.zonefile.podin
--- gdnsd-2.1.0/docs/gdnsd.zonefile.podin	1970-01-01 00:00:00.000000000 +0000
+++ gdnsd-2.1.2/docs/gdnsd.zonefile.podin	2015-05-06 14:05:07.000000000 +0000
@@ -0,0 +1,233 @@
+
+=head1 NAME
+
+gdnsd.zonefile - gdnsd zonefile syntax
+
+=head1 SYNOPSIS
+
+example.com:
+
+  $TTL 86400
+
+  @	SOA ns1 hostmaster (
+        1      ; serial
+        7200   ; refresh
+        30M    ; retry
+        3D     ; expire
+        900    ; ncache
+  )
+
+  @	NS	ns1.example.com.
+  @	NS	ns2
+  @	NS	ns.example.net.
+
+  ns1	A	192.0.2.1 ; a comment
+  ns2.example.com.	A	192.0.2.2
+
+  @	7200	MX	10 mail-a
+  @	7200	MX	100 mail-b
+
+  $ttl 86400
+  ; a comment
+  mail-a	A 192.0.2.3
+  mail-b	A 192.0.2.4
+
+  subz		NS	ns1.subz
+  subz		NS	ns2.subz
+  ns1.subz	A	192.0.2.5
+  ns2.subz	A	192.0.2.6
+
+  www	600/10	DYNA	some_plugin!resource_name
+  alias		CNAME	www
+
+  _http._tcp	1800	SRV	5 500 80 www
+
+  foo		TXT	"blah blah" "blah"
+  _spf 		TXT	"v=spf1 ..."
+
+=head1 DESCRIPTION
+
+This is the primary zonefile syntax for L<gdnsd(8)>.  The syntax is
+designed to be as close as possible to the standard zonefile
+syntax from RFC 1035 (which is the "standard" format one
+typically sees with traditional BIND servers).  This document will
+just cover a few important highlights and/or deviations from the norm.
+
+=head1 DIRECTIVES
+
+The standard C<$TTL> and C<$ORIGIN> directives
+are supported with their normal syntax and semantics.
+
+C<$TTL> changes the default TTL of any records coming after it,
+and can occur multiple times.  Note that in the absence of a
+zonefile-level C<$TTL> setting, the default TTL comes from the
+global config option C<zones_default_ttl>, which in turn defaults
+to C<86400> (1 day).
+
+C<$ORIGIN> changes what is appended to unqualified hostnames
+(those lacking a final C<.>) seen in the zone file from that
+point forward, as well as any C<@> entries (which is an alias
+for the current origin).  C<$ORIGIN> itself may also be an unqualified
+name, in which case the previous origin is appended to it.
+Any fully-qualified C<$ORIGIN> must be within the zone described
+by this zonefile.  The default origin is the zone name itself.
+
+C<$ADDR_LIMIT_V4> is a non-standard, gdnsd-specific directive.
+It requires a single unsigned integer argument.  The argument
+limits the total number of C<A> records to include in the server's
+responses for any given C<A> rrset (whether static or dynamic).
+The default limit is zero, which is interpreted as no limit.
+Setting the limit via this directive affects all rrsets until
+the value is changed again by another directive.  gdnsd always
+rotates the RRs of an address RR-set in a round-robin fashion,
+and this rotation occurs before the limit is applied, allowing
+a small pseudo-random subset of a larger list to be delivered
+via this mechanism.
+
+C<$ADDR_LIMIT_V6> same as above, but for IPv6 C<AAAA> rrsets.
+
+The RFC-standard C<$INCLUDE> directive is not supported because
+it would greatly complicate the detection of zone update
+transactions with our current filesystem-based change detection
+scheme.  Most legitimate uses of C<$INCLUDE> to reduce redundancy
+should be replaced with a zonefile-generating script instead,
+perhaps using a template system.
+
+BIND's C<$GENERATE> extension is not supported at this time, but
+there's no fundamental reason it couldn't be added at a later
+date.
+
+=head1 SUPPORTED RESOURCE RECORD TYPES
+
+L<gdnsd(8)> supports the following standard RR types with their
+standard RDATA formats: SOA, A, AAAA, NS, PTR, CNAME, MX, SRV,
+TXT, and NAPTR.  All RRs must be in class C<IN>, which
+is the implicit default.
+
+It also supports the generic format for unknown RR types documented
+in RFC 3597, which has syntax like:
+
+  foo TYPE31337 \# 10 0123456789 ABCDEF0123
+
+... which indicates an RR of numeric type 31337 containing
+10 bytes of RDATA, specified as the final part of the RR as
+a pair of 5-byte hex strings.  See RFC 3597 itself for full
+details.  Note however that gdnsd does not allow using the
+RFC 3597 format for types gdnsd explicitly supports (all of
+which predate 3597 anyways), and that even in the RFC 3597 case
+we still only allow class C<IN> RRs.
+
+Additionally, gdnsd supports two special-case, non-standard
+virtual resource record types DYNA and DYNC:
+
+=head2 DYNA
+
+C<DYNA> is for dynamically-determined address records (both A
+and AAAA) via plugin code.  The right-hand-side of a C<DYNA>
+RR is a plugin name and a resource name separated by an exclamation
+mark.  The named plugin will be fed the resource name and
+the DNS client's IP address and/or edns-client-subnet information,
+and it is up to the plugin code which addresses of which types
+to return in the response.
+
+The dynamic plugin lookup for C<DYNA> will be used anywhere that
+regular C<A> and/or C<AAAA> records would be used.  This includes
+not only direct responses to C<A> and C<AAAA> queries, but also
+things like Additional-section RRs and C<ANY>-query output.
+C<DYNA> cannot co-exist with actual static A or AAAA records
+at the same name, but can co-exist with any other RR-type.
+
+Example:
+
+  ; asks plugin 'geoip' to provide address data from
+  ;  its resource named 'pubwww' for address queries.
+  foo DYNA geoip!pubwww
+  foo MX 10 mail
+
+=head2 DYNC
+
+C<DYNC> has the same syntax as C<DYNA> above, but different data
+rules.  Plugins results returned via C<DYNC> can be either addresses
+or a C<CNAME> record.  C<DYNC> cannot co-exist with B<any> other
+resource record at the same name, much like normal C<CNAME> RRs.
+This also implies that C<DYNC> cannot be used at the zone root,
+as the zone root requires C<NS> and C<SOA> RRs.  While C<DYNC>
+responses are included in C<ANY> queries for the given name,
+they are B<not> used in Additional-section processing, even
+when the plugin responds with address records rather than C<CNAME>.
+
+Example:
+
+  ; asks plugin 'geoip' to provide address data or a CNAME
+  ;  (at the plugin's discretion) for its resource named
+  ;  'www'.  No other RRs of any type for name 'foo' are
+  ;  legal alongside this record.
+  foo DYNC geoip!www
+
+=head2 DYNA/DYNC TTLs
+
+C<DYNA> and C<DYNC> TTL fields have a syntax extension and slightly
+different meanings than the TTL field of a traditional, fixed RR.
+The format for DYNA/DYNC TTLs is C<MAX[/MIN]>, with C<MIN> defaulting
+to half of C<MAX> if not specified explicitly.
+
+Based on the configuration and state of the underlying monitored services,
+(see "service_types" in L<gdnsd.config(8)>), gdnsd knows the minimum time
+to the next possible state-change which could affect a given C<DYNA> or
+C<DYNC> result.  For example, given the configuration and state, it may
+be known that in order for a currently C<DOWN> address to transition to
+the C<UP> state (and thus change the answer to a given query) would require
+7 more successful monitoring checks in a row at 8-second intervals, and
+therefore cannot happen in less than 56 seconds.  In this case 56 seconds
+would be the internally-calculated TTL.
+
+In cases where multiple monitored resources factor into a plugin's
+decision and/or response (e.g. multifo), the calculated TTL will generally
+be the minimum of all involved internal monitoring TTLs.  This calculated
+TTL is then clamped to the C<MAX> and C<MIN> limits from the zonefile.
+
+Examples:
+
+    ; Explicit range of 30 - 300:
+    www 300/30 DYNC weighted!foo
+    ; Implicit range of 150 - 300:
+    www 300 DYNA metafo!myservice
+    ; Avoid all TTL-mangling and use a fixed value of 10 minutes:
+    www 600/600 DYNA geoip!foo-dist
+
+=head2 TXT data auto-splitting
+
+gdnsd's C<TXT> RRs support the auto-splitting
+of long string constants.  Rather than manually breaking the
+data into 255-byte chunks as required by the protocol, you can
+specify a single long chunk and have the server break it at
+255 byte boundaries automatically.  (this behavior can be
+disabled via L<gdnsd.config(5)> as well, which will turn
+oversized chunks into zonefile parsing errors).
+
+=head1 SEE ALSO
+
+L<gdnsd(8)>, L<gdnsd.config(5)>
+
+The gdnsd manual.
+
+=head1 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/>.
+
+=cut
diff -Nru gdnsd-2.1.0/docs/Makefile.am gdnsd-2.1.2/docs/Makefile.am
--- gdnsd-2.1.0/docs/Makefile.am	2014-10-13 08:13:40.000000000 +0000
+++ gdnsd-2.1.2/docs/Makefile.am	2015-05-06 14:05:07.000000000 +0000
@@ -1,26 +1,26 @@
 # dist + install simple docs
 dist_doc_DATA = gdnsd_manual.txt
 
-PODS_1 = gdnsd_geoip_test.pod
-PODS_3 = gdnsd-plugin-api.pod
-PODS_5 = \
-	gdnsd.config.pod \
-	gdnsd.zonefile.pod \
-	gdnsd.djbdns.pod
-PODS_8 = \
-	gdnsd.pod \
-	gdnsd-plugin-extfile.pod \
-	gdnsd-plugin-extmon.pod \
-	gdnsd-plugin-geoip.pod \
-	gdnsd-plugin-http_status.pod \
-	gdnsd-plugin-metafo.pod \
-	gdnsd-plugin-multifo.pod \
-	gdnsd-plugin-null.pod \
-	gdnsd-plugin-reflect.pod \
-	gdnsd-plugin-simplefo.pod \
-	gdnsd-plugin-static.pod \
-	gdnsd-plugin-tcp_connect.pod \
-	gdnsd-plugin-weighted.pod
+PODS_IN_1 = gdnsd_geoip_test.podin
+PODS_IN_3 = gdnsd-plugin-api.podin
+PODS_IN_5 = \
+	gdnsd.config.podin \
+	gdnsd.zonefile.podin \
+	gdnsd.djbdns.podin
+PODS_IN_8 = \
+	gdnsd.podin \
+	gdnsd-plugin-extfile.podin \
+	gdnsd-plugin-extmon.podin \
+	gdnsd-plugin-geoip.podin \
+	gdnsd-plugin-http_status.podin \
+	gdnsd-plugin-metafo.podin \
+	gdnsd-plugin-multifo.podin \
+	gdnsd-plugin-null.podin \
+	gdnsd-plugin-reflect.podin \
+	gdnsd-plugin-simplefo.podin \
+	gdnsd-plugin-static.podin \
+	gdnsd-plugin-tcp_connect.podin \
+	gdnsd-plugin-weighted.podin
 
 # This translates default path variables in the pod sources
 MAN_SED = $(SED) \
@@ -31,24 +31,26 @@
 	-e 's|@GDNSD_DEFPATH_LIBEXEC[@]|$(GDNSD_DEFPATH_LIBEXEC)|g' \
 	-e 's|@GDNSD_SBINDIR[@]|$(sbindir)|g'
 
-# Gather up the .pod files (which are distributed but not installed)
-ALL_PODS = $(PODS_1) $(PODS_3) $(PODS_5) $(PODS_8)
+# Gather up the .podin files (which are distributed but not installed)
+ALL_PODS = $(PODS_IN_1) $(PODS_IN_3) $(PODS_IN_5) $(PODS_IN_8)
 EXTRA_DIST = $(ALL_PODS)
 
 # Manpages for installation, generated via sed templating then pod2man
 #  (the Makefile dep is for the sed command on change of --prefix, etc)
-nodist_man_MANS = $(PODS_1:.pod=.1) $(PODS_3:.pod=.3) $(PODS_5:.pod=.5) $(PODS_8:.pod=.8)
+nodist_man_MANS = $(PODS_IN_1:.podin=.1) $(PODS_IN_3:.podin=.3) $(PODS_IN_5:.podin=.5) $(PODS_IN_8:.podin=.8)
 $(nodist_man_MANS): Makefile
 clean-local:
 	rm -f $(nodist_man_MANS)
+.podin.pod:
+	$(AM_V_GEN)$(MAN_SED) <$< >$@
 .pod.8:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=8 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=8 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.5:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=5 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=5 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.3:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=3 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=3 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.1:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=1 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=1 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 
 # "make wikidocs" ->
 # Basically it renames all the podfiles from e.g. gdnsd-plugin-geoip.pod
@@ -63,7 +65,7 @@
 		$(MKDIR_P) $(WIKI_DIR); \
 	fi
 	@for podsrc in $(ALL_PODS); do \
-		wikifn=`echo $$podsrc | $(PERL) -pe 's/^([a-z])/uc($$1)/e; s/[_.-]([a-zA-Z0-9])/uc($$1)/ge; s/Pod$$/.pod/'`; \
+		wikifn=`echo $$podsrc | $(PERL) -pe 's/^([a-z])/uc($$1)/e; s/[_.-]([a-zA-Z0-9])/uc($$1)/ge; s/Podin$$/.pod/'`; \
 		echo Copying $$podsrc to $(WIKI_DIR)/$$wikifn ...; \
 		$(MAN_SED) <$$podsrc >$(WIKI_DIR)/$$wikifn; \
 	done
diff -Nru gdnsd-2.1.0/docs/Makefile.in gdnsd-2.1.2/docs/Makefile.in
--- gdnsd-2.1.0/docs/Makefile.in	2014-10-15 00:25:30.000000000 +0000
+++ gdnsd-2.1.2/docs/Makefile.in	2015-05-06 15:37:21.000000000 +0000
@@ -315,27 +315,27 @@
 
 # dist + install simple docs
 dist_doc_DATA = gdnsd_manual.txt
-PODS_1 = gdnsd_geoip_test.pod
-PODS_3 = gdnsd-plugin-api.pod
-PODS_5 = \
-	gdnsd.config.pod \
-	gdnsd.zonefile.pod \
-	gdnsd.djbdns.pod
-
-PODS_8 = \
-	gdnsd.pod \
-	gdnsd-plugin-extfile.pod \
-	gdnsd-plugin-extmon.pod \
-	gdnsd-plugin-geoip.pod \
-	gdnsd-plugin-http_status.pod \
-	gdnsd-plugin-metafo.pod \
-	gdnsd-plugin-multifo.pod \
-	gdnsd-plugin-null.pod \
-	gdnsd-plugin-reflect.pod \
-	gdnsd-plugin-simplefo.pod \
-	gdnsd-plugin-static.pod \
-	gdnsd-plugin-tcp_connect.pod \
-	gdnsd-plugin-weighted.pod
+PODS_IN_1 = gdnsd_geoip_test.podin
+PODS_IN_3 = gdnsd-plugin-api.podin
+PODS_IN_5 = \
+	gdnsd.config.podin \
+	gdnsd.zonefile.podin \
+	gdnsd.djbdns.podin
+
+PODS_IN_8 = \
+	gdnsd.podin \
+	gdnsd-plugin-extfile.podin \
+	gdnsd-plugin-extmon.podin \
+	gdnsd-plugin-geoip.podin \
+	gdnsd-plugin-http_status.podin \
+	gdnsd-plugin-metafo.podin \
+	gdnsd-plugin-multifo.podin \
+	gdnsd-plugin-null.podin \
+	gdnsd-plugin-reflect.podin \
+	gdnsd-plugin-simplefo.podin \
+	gdnsd-plugin-static.podin \
+	gdnsd-plugin-tcp_connect.podin \
+	gdnsd-plugin-weighted.podin
 
 
 # This translates default path variables in the pod sources
@@ -348,13 +348,13 @@
 	-e 's|@GDNSD_SBINDIR[@]|$(sbindir)|g'
 
 
-# Gather up the .pod files (which are distributed but not installed)
-ALL_PODS = $(PODS_1) $(PODS_3) $(PODS_5) $(PODS_8)
+# Gather up the .podin files (which are distributed but not installed)
+ALL_PODS = $(PODS_IN_1) $(PODS_IN_3) $(PODS_IN_5) $(PODS_IN_8)
 EXTRA_DIST = $(ALL_PODS)
 
 # Manpages for installation, generated via sed templating then pod2man
 #  (the Makefile dep is for the sed command on change of --prefix, etc)
-nodist_man_MANS = $(PODS_1:.pod=.1) $(PODS_3:.pod=.3) $(PODS_5:.pod=.5) $(PODS_8:.pod=.8)
+nodist_man_MANS = $(PODS_IN_1:.podin=.1) $(PODS_IN_3:.podin=.3) $(PODS_IN_5:.podin=.5) $(PODS_IN_8:.podin=.8)
 
 # "make wikidocs" ->
 # Basically it renames all the podfiles from e.g. gdnsd-plugin-geoip.pod
@@ -367,7 +367,7 @@
 all: all-am
 
 .SUFFIXES:
-.SUFFIXES: .1 .3 .5 .8 .pod
+.SUFFIXES: .1 .3 .5 .8 .pod .podin
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -760,20 +760,22 @@
 $(nodist_man_MANS): Makefile
 clean-local:
 	rm -f $(nodist_man_MANS)
+.podin.pod:
+	$(AM_V_GEN)$(MAN_SED) <$< >$@
 .pod.8:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=8 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=8 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.5:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=5 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=5 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.3:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=3 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=3 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.1:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=1 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=1 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 wikidocs:
 	@if [ ! -d $(WIKI_DIR) ]; then \
 		$(MKDIR_P) $(WIKI_DIR); \
 	fi
 	@for podsrc in $(ALL_PODS); do \
-		wikifn=`echo $$podsrc | $(PERL) -pe 's/^([a-z])/uc($$1)/e; s/[_.-]([a-zA-Z0-9])/uc($$1)/ge; s/Pod$$/.pod/'`; \
+		wikifn=`echo $$podsrc | $(PERL) -pe 's/^([a-z])/uc($$1)/e; s/[_.-]([a-zA-Z0-9])/uc($$1)/ge; s/Podin$$/.pod/'`; \
 		echo Copying $$podsrc to $(WIKI_DIR)/$$wikifn ...; \
 		$(MAN_SED) <$$podsrc >$(WIKI_DIR)/$$wikifn; \
 	done
diff -Nru gdnsd-2.1.0/gdnsd/conf.c gdnsd-2.1.2/gdnsd/conf.c
--- gdnsd-2.1.0/gdnsd/conf.c	2014-10-14 15:51:52.000000000 +0000
+++ gdnsd-2.1.2/gdnsd/conf.c	2015-05-06 14:05:03.000000000 +0000
@@ -402,7 +402,7 @@
             if(!vscf_is_hash(addr_opts))
                 log_fatal("DNS listen address '%s': per-address options must be a hash", lspec);
 
-            CFG_OPT_UINT_ALTSTORE(addr_opts, udp_recv_width, 1LU, 32LU, addrconf->udp_recv_width);
+            CFG_OPT_UINT_ALTSTORE(addr_opts, udp_recv_width, 1LU, 64LU, addrconf->udp_recv_width);
             CFG_OPT_UINT_ALTSTORE(addr_opts, udp_rcvbuf, 4096LU, 1048576LU, addrconf->udp_rcvbuf);
             CFG_OPT_UINT_ALTSTORE(addr_opts, udp_sndbuf, 4096LU, 1048576LU, addrconf->udp_sndbuf);
             CFG_OPT_UINT_ALTSTORE_NOMIN(addr_opts, udp_threads, 1024LU, addrconf->udp_threads);
diff -Nru gdnsd-2.1.0/gdnsd/dnsio_udp.c gdnsd-2.1.2/gdnsd/dnsio_udp.c
--- gdnsd-2.1.0/gdnsd/dnsio_udp.c	2014-10-13 16:42:56.000000000 +0000
+++ gdnsd-2.1.2/gdnsd/dnsio_udp.c	2015-05-06 14:05:03.000000000 +0000
@@ -472,23 +472,13 @@
                 }
             }
 
-            struct mmsghdr* dgptr = dgrams;
-            while(pkts) {
-                int sent = sendmmsg(fd, dgptr, pkts, 0);
-                dmn_assert(sent != 0);
-                dmn_assert(sent <= pkts);
-                if(unlikely(sent < pkts)) {
-                    int sockerr = 0;
-                    socklen_t sock_len = sizeof(sockerr);
-                    (void)getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sock_len);
-                    stats_own_inc(&stats->udp.sendfail);
-                    if(sent < 0) sent = 0;
-                    log_err("UDP sendmmsg() of %zu bytes to client %s failed: %s", dgptr[sent].msg_hdr.msg_iov[0].iov_len, dmn_logf_anysin(dgptr[sent].msg_hdr.msg_name), dmn_logf_strerror(sockerr));
-                    dgptr += sent; // skip past the successes
-                    dgptr++; // skip the failed one too
-                    pkts--; // drop one count for the failed message
-                }
-                pkts -= sent; // drop the count of all successes
+            int mmsg_rv = sendmmsg(fd, dgrams, pkts, 0);
+            if(unlikely(mmsg_rv < 0)) {
+                stats_own_inc(&stats->udp.sendfail);
+                int sockerr = 0;
+                socklen_t sock_len = sizeof(sockerr);
+                (void)getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sock_len);
+                log_err("UDP sendmmsg() failed: %s", dmn_logf_strerror(sockerr));
             }
         }
         else {
diff -Nru gdnsd-2.1.0/gdnsd/libgdnsd/vscf.c gdnsd-2.1.2/gdnsd/libgdnsd/vscf.c
--- gdnsd-2.1.0/gdnsd/libgdnsd/vscf.c	2014-10-15 00:25:50.000000000 +0000
+++ gdnsd-2.1.2/gdnsd/libgdnsd/vscf.c	2015-05-06 15:37:36.000000000 +0000
@@ -1379,7 +1379,7 @@
 			else if ( (*(     scnr->p)) > *_mid )
 				_lower = _mid + 1;
 			else {
-				_trans += (_mid - _keys);
+				_trans += (unsigned int)(_mid - _keys);
 				goto _match;
 			}
 		}
@@ -1402,7 +1402,7 @@
 			else if ( (*(     scnr->p)) > _mid[1] )
 				_lower = _mid + 2;
 			else {
-				_trans += ((_mid - _keys)>>1);
+				_trans += (unsigned int)((_mid - _keys)>>1);
 				goto _match;
 			}
 		}
diff -Nru gdnsd-2.1.0/gdnsd/statio.c gdnsd-2.1.2/gdnsd/statio.c
--- gdnsd-2.1.0/gdnsd/statio.c	2014-10-14 15:51:52.000000000 +0000
+++ gdnsd-2.1.2/gdnsd/statio.c	2015-05-06 14:05:03.000000000 +0000
@@ -663,12 +663,12 @@
 }
 
 bool statio_check_socks(bool soft) {
-    unsigned rv = true;
+    unsigned rv = false;
     for(unsigned i = 0; i < num_lsocks; i++)
         if(!socks_sock_is_bound_to(lsocks[i], &gconfig.http_addrs[i]) && !soft)
             log_fatal("Failed to bind() stats TCP socket to %s", dmn_logf_anysin(&gconfig.http_addrs[i]));
         else
-            rv = false;
+            rv = true;
     return rv;
 }
 
diff -Nru gdnsd-2.1.0/NEWS gdnsd-2.1.2/NEWS
--- gdnsd-2.1.0/NEWS	2014-10-15 00:21:21.000000000 +0000
+++ gdnsd-2.1.2/NEWS	2015-05-06 15:26:59.000000000 +0000
@@ -1,3 +1,22 @@
+2.1.2 - 2015-05-06
+    * Cherrypicked manpage title bugfix from v2.2.0 - (was f7672493 there)
+      (Because newer perl pod2man commands fail completely without
+      a valid title)
+
+2.1.1 - 2014-12-30
+  *** Bugfixes backported from master branch:
+    * Fixed incorrect error-handling code for the sendmmsg() syscall, which
+      could have caused an unecessary additional dropped packet and/or
+      bad error messages after failing to send one or more packets from a set.
+    * The per-address level udp_recv_width option is now correctly limited to
+      a value of 64 (previously it was being incorrectly limited to 32).
+    * plugin_multifo no longer pointlessly limits to 64 addrs per family
+    * plugin_extmon bugfix for bad timeout/interval behavior if either >255s
+    * if the stats http socket failed to bind() on startup, the daemon
+      could carry on anyways, causing it to bind to a different, arbitrary
+      port number
+    * Fixed autoconf 2.63 compat when running autoreconf (broken in 2.1.0)
+
 2.1.0 - 2014-10-14
   *** Bugfixes:
     * Fixed JSON stats output (was malformed; missing commas
diff -Nru gdnsd-2.1.0/plugins/extmon/extmon_comms.c gdnsd-2.1.2/plugins/extmon/extmon_comms.c
--- gdnsd-2.1.0/plugins/extmon/extmon_comms.c	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/plugins/extmon/extmon_comms.c	2015-05-06 14:05:03.000000000 +0000
@@ -92,10 +92,12 @@
     len += 4;
 
     // 2-byte index, 1-byte timeout, 1-byte interval
-    buf[len++] = cmd->idx >> 8;
-    buf[len++] = cmd->idx & 0xFF;
-    buf[len++] = cmd->timeout;
-    buf[len++] = cmd->interval;
+    buf[len++] = (char)(cmd->idx >> 8);
+    buf[len++] = (char)(cmd->idx & 0xFF);
+    buf[len++] = (char)(cmd->timeout >> 8);
+    buf[len++] = (char)(cmd->timeout & 0xFF);
+    buf[len++] = (char)(cmd->interval >> 8);
+    buf[len++] = (char)(cmd->interval & 0xFF);
 
     // skip 2-byte len for rest of packet at offset 8
     len += 2;
@@ -123,9 +125,9 @@
 
     // now go back and fill in the overall len
     //   of the variable area for desc/args.
-    const unsigned var_len = len - 10;
-    buf[8] = var_len >> 8;
-    buf[9] = var_len & 0xFF;
+    const unsigned var_len = len - 12;
+    buf[10] = (char)(var_len >> 8);
+    buf[11] = (char)(var_len & 0xFF);
 
     bool rv = emc_write_string(fd, buf, len);
     free(buf);
@@ -148,8 +150,8 @@
     extmon_cmd_t* cmd = NULL;
 
     {
-        uint8_t fixed_part[10];
-        if(emc_read_nbytes(fd, 10, fixed_part)
+        uint8_t fixed_part[12];
+        if(emc_read_nbytes(fd, 12, fixed_part)
             || strncmp((char*)fixed_part, "CMD:", 4)) {
             log_debug("emc_read_command() failed to read CMD: prefix");
             goto out_error;
@@ -157,13 +159,13 @@
 
         cmd = xmalloc(sizeof(extmon_cmd_t));
         cmd->idx = ((unsigned)fixed_part[4] << 8) + fixed_part[5];
-        cmd->timeout = fixed_part[6];
-        cmd->interval = fixed_part[7];
+        cmd->timeout = ((unsigned)fixed_part[6] << 8) + fixed_part[7];
+        cmd->interval = ((unsigned)fixed_part[8] << 8) + fixed_part[9];
         cmd->args = NULL;
         cmd->num_args = 0;
 
         // note we add an extra NULL at the end of args here, for execl()
-        const unsigned var_len = ((unsigned)fixed_part[8] << 8) + fixed_part[9];
+        const unsigned var_len = ((unsigned)fixed_part[10] << 8) + fixed_part[11];
         if(var_len < 4) {
             // 4 bytes would be enough for num_args, a single 1-byte argument
             //   and its NUL termiantor, and a zero-length NUL-terminated desc
diff -Nru gdnsd-2.1.0/plugins/trivial/multifo.c gdnsd-2.1.2/plugins/trivial/multifo.c
--- gdnsd-2.1.0/plugins/trivial/multifo.c	2014-10-02 05:59:32.000000000 +0000
+++ gdnsd-2.1.2/plugins/trivial/multifo.c	2015-05-06 14:05:03.000000000 +0000
@@ -183,8 +183,6 @@
 
     if(!num_addrs)
         log_fatal("plugin_multifo: resource '%s' (%s): must define one or more 'desc => IP' mappings, either directly or inside a subhash named 'addrs'", resname, stanza);
-    if(num_addrs > 64)
-        log_fatal("plugin_multifo: resource %s (%s): too many IPv%c addresses (limit 64)", resname, stanza, ipv6 ? '6' : '4');
 
     aset->count = num_addrs;
     aset->as = xcalloc(num_addrs, sizeof(addrstate_t));
diff --git a/.gitignore b/.gitignore
index 9be515b..02cd707 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,7 @@ clang_output_*
 
 # generated docs
 *.[0-9]
+*.pod
 /wikidocs/
 
 # generated systemd unit file
diff --git a/NEWS b/NEWS
index 9e2aa48..06aaa29 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,22 @@
+2.1.2 - 2015-05-06
+    * Cherrypicked manpage title bugfix from v2.2.0 - (was f7672493 there)
+      (Because newer perl pod2man commands fail completely without
+      a valid title)
+
+2.1.1 - 2014-12-30
+  *** Bugfixes backported from master branch:
+    * Fixed incorrect error-handling code for the sendmmsg() syscall, which
+      could have caused an unecessary additional dropped packet and/or
+      bad error messages after failing to send one or more packets from a set.
+    * The per-address level udp_recv_width option is now correctly limited to
+      a value of 64 (previously it was being incorrectly limited to 32).
+    * plugin_multifo no longer pointlessly limits to 64 addrs per family
+    * plugin_extmon bugfix for bad timeout/interval behavior if either >255s
+    * if the stats http socket failed to bind() on startup, the daemon
+      could carry on anyways, causing it to bind to a different, arbitrary
+      port number
+    * Fixed autoconf 2.63 compat when running autoreconf (broken in 2.1.0)
+
 2.1.0 - 2014-10-14
   *** Bugfixes:
     * Fixed JSON stats output (was malformed; missing commas
diff --git a/configure.ac b/configure.ac
index df390d0..bbc5227 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,16 +1,28 @@
 AC_PREREQ([2.63])
-AC_INIT([gdnsd],[2.1.0],[blblack@gmail.com],[gdnsd])
+AC_INIT([gdnsd],[2.1.2],[blblack@gmail.com],[gdnsd])
 AC_CONFIG_SRCDIR([gdnsd/main.c])
 AC_CONFIG_AUX_DIR([acaux])
 AM_INIT_AUTOMAKE([1.11.1 dist-xz no-dist-gzip foreign tar-ustar -Wall])
 AC_CONFIG_MACRO_DIR([m4])
 AM_SILENT_RULES([yes])
 
+## Autoconf-2.63-Compat
+# Future reference: both of the below could be addressed by bumping our
+# AC_PREREQ() to 2.64.  It's just a question of at what point in the future
+# the 2.63-using distros are old enough that it's reasonable to do so.
+#---
 # We're compatible to autoconf 2.63, which doesn't have PACKAGE_URL
 #   as a final arg to AC_INIT.  We can't define it ourselves here
 #   with the same name as this causes compiler warnings that matter
 #   during other parts of ./configure.  So, pick a new name for now.
 AC_DEFINE([PKG_URL],["https://github.com/gdnsd/gdnsd/"],[Package URL])
+#---
+# This hack makes PKG_CHECK_VARS from m4/pkg.m4 work on autoconf 2.63
+# ( courtesy of sunnybear in https://github.com/gdnsd/gdnsd/issues/85 )
+m4_ifndef([AS_VAR_COPY],
+[m4_define([AS_VAR_COPY],
+[AS_LITERAL_IF([$1[]$2], [$1=$$2], [eval $1=\$$2])])])
+## End Autoconf-2.63-Compat
 
 # TODO: when/if a new autoconf release has a C11 macro,
 #    prefer that and fall back to requiring C99.
diff --git a/debian/changelog b/debian/changelog
index 91ffae0..a2cf0d7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+gdnsd (2.1.2-1~deb8u1) stable; urgency=medium
+
+  * Backport as a stable update.
+
+ -- Faidon Liambotis <paravoid@debian.org>  Mon, 11 May 2015 13:18:45 +0000
+
+gdnsd (2.1.2-1) unstable; urgency=high
+
+  * New upstream stable release.
+    - Fixes FTBFS with newer pod2man, like in current sid.
+
+ -- Faidon Liambotis <paravoid@debian.org>  Thu, 07 May 2015 00:40:19 +0300
+
 gdnsd (2.1.0-1) unstable; urgency=medium
 
   * New upstream release.
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 058e03b..51de9e1 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,6 +1,6 @@
-[git-buildpackage]
+[buildpackage]
 upstream-tree=tag
-debian-branch=debian
+debian-branch=jessie
 upstream-tag = v%(version)s
 overlay = True
 no-create-orig = True
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 2da9d37..53efdf3 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -1,26 +1,26 @@
 # dist + install simple docs
 dist_doc_DATA = gdnsd_manual.txt
 
-PODS_1 = gdnsd_geoip_test.pod
-PODS_3 = gdnsd-plugin-api.pod
-PODS_5 = \
-	gdnsd.config.pod \
-	gdnsd.zonefile.pod \
-	gdnsd.djbdns.pod
-PODS_8 = \
-	gdnsd.pod \
-	gdnsd-plugin-extfile.pod \
-	gdnsd-plugin-extmon.pod \
-	gdnsd-plugin-geoip.pod \
-	gdnsd-plugin-http_status.pod \
-	gdnsd-plugin-metafo.pod \
-	gdnsd-plugin-multifo.pod \
-	gdnsd-plugin-null.pod \
-	gdnsd-plugin-reflect.pod \
-	gdnsd-plugin-simplefo.pod \
-	gdnsd-plugin-static.pod \
-	gdnsd-plugin-tcp_connect.pod \
-	gdnsd-plugin-weighted.pod
+PODS_IN_1 = gdnsd_geoip_test.podin
+PODS_IN_3 = gdnsd-plugin-api.podin
+PODS_IN_5 = \
+	gdnsd.config.podin \
+	gdnsd.zonefile.podin \
+	gdnsd.djbdns.podin
+PODS_IN_8 = \
+	gdnsd.podin \
+	gdnsd-plugin-extfile.podin \
+	gdnsd-plugin-extmon.podin \
+	gdnsd-plugin-geoip.podin \
+	gdnsd-plugin-http_status.podin \
+	gdnsd-plugin-metafo.podin \
+	gdnsd-plugin-multifo.podin \
+	gdnsd-plugin-null.podin \
+	gdnsd-plugin-reflect.podin \
+	gdnsd-plugin-simplefo.podin \
+	gdnsd-plugin-static.podin \
+	gdnsd-plugin-tcp_connect.podin \
+	gdnsd-plugin-weighted.podin
 
 # This translates default path variables in the pod sources
 MAN_SED = $(SED) \
@@ -31,24 +31,26 @@ MAN_SED = $(SED) \
 	-e 's|@GDNSD_DEFPATH_LIBEXEC[@]|$(GDNSD_DEFPATH_LIBEXEC)|g' \
 	-e 's|@GDNSD_SBINDIR[@]|$(sbindir)|g'
 
-# Gather up the .pod files (which are distributed but not installed)
-ALL_PODS = $(PODS_1) $(PODS_3) $(PODS_5) $(PODS_8)
+# Gather up the .podin files (which are distributed but not installed)
+ALL_PODS = $(PODS_IN_1) $(PODS_IN_3) $(PODS_IN_5) $(PODS_IN_8)
 EXTRA_DIST = $(ALL_PODS)
 
 # Manpages for installation, generated via sed templating then pod2man
 #  (the Makefile dep is for the sed command on change of --prefix, etc)
-nodist_man_MANS = $(PODS_1:.pod=.1) $(PODS_3:.pod=.3) $(PODS_5:.pod=.5) $(PODS_8:.pod=.8)
+nodist_man_MANS = $(PODS_IN_1:.podin=.1) $(PODS_IN_3:.podin=.3) $(PODS_IN_5:.podin=.5) $(PODS_IN_8:.podin=.8)
 $(nodist_man_MANS): Makefile
 clean-local:
 	rm -f $(nodist_man_MANS)
+.podin.pod:
+	$(AM_V_GEN)$(MAN_SED) <$< >$@
 .pod.8:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=8 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=8 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.5:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=5 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=5 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.3:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=3 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=3 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 .pod.1:
-	$(AM_V_GEN)$(MAN_SED) <$< | $(POD2MAN) --section=1 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) >$@
+	$(AM_V_GEN)$(POD2MAN) --section=1 --release="$(PACKAGE_NAME) $(VERSION)" --center=$(PACKAGE_NAME) $< $@
 
 # "make wikidocs" ->
 # Basically it renames all the podfiles from e.g. gdnsd-plugin-geoip.pod
@@ -63,7 +65,7 @@ wikidocs:
 		$(MKDIR_P) $(WIKI_DIR); \
 	fi
 	@for podsrc in $(ALL_PODS); do \
-		wikifn=`echo $$podsrc | $(PERL) -pe 's/^([a-z])/uc($$1)/e; s/[_.-]([a-zA-Z0-9])/uc($$1)/ge; s/Pod$$/.pod/'`; \
+		wikifn=`echo $$podsrc | $(PERL) -pe 's/^([a-z])/uc($$1)/e; s/[_.-]([a-zA-Z0-9])/uc($$1)/ge; s/Podin$$/.pod/'`; \
 		echo Copying $$podsrc to $(WIKI_DIR)/$$wikifn ...; \
 		$(MAN_SED) <$$podsrc >$(WIKI_DIR)/$$wikifn; \
 	done
diff --git a/docs/gdnsd-plugin-api.pod b/docs/gdnsd-plugin-api.podin
similarity index 100%
rename from docs/gdnsd-plugin-api.pod
rename to docs/gdnsd-plugin-api.podin
diff --git a/docs/gdnsd-plugin-extfile.pod b/docs/gdnsd-plugin-extfile.podin
similarity index 100%
rename from docs/gdnsd-plugin-extfile.pod
rename to docs/gdnsd-plugin-extfile.podin
diff --git a/docs/gdnsd-plugin-extmon.pod b/docs/gdnsd-plugin-extmon.podin
similarity index 100%
rename from docs/gdnsd-plugin-extmon.pod
rename to docs/gdnsd-plugin-extmon.podin
diff --git a/docs/gdnsd-plugin-geoip.pod b/docs/gdnsd-plugin-geoip.podin
similarity index 100%
rename from docs/gdnsd-plugin-geoip.pod
rename to docs/gdnsd-plugin-geoip.podin
diff --git a/docs/gdnsd-plugin-http_status.pod b/docs/gdnsd-plugin-http_status.podin
similarity index 100%
rename from docs/gdnsd-plugin-http_status.pod
rename to docs/gdnsd-plugin-http_status.podin
diff --git a/docs/gdnsd-plugin-metafo.pod b/docs/gdnsd-plugin-metafo.podin
similarity index 100%
rename from docs/gdnsd-plugin-metafo.pod
rename to docs/gdnsd-plugin-metafo.podin
diff --git a/docs/gdnsd-plugin-multifo.pod b/docs/gdnsd-plugin-multifo.podin
similarity index 100%
rename from docs/gdnsd-plugin-multifo.pod
rename to docs/gdnsd-plugin-multifo.podin
diff --git a/docs/gdnsd-plugin-null.pod b/docs/gdnsd-plugin-null.podin
similarity index 100%
rename from docs/gdnsd-plugin-null.pod
rename to docs/gdnsd-plugin-null.podin
diff --git a/docs/gdnsd-plugin-reflect.pod b/docs/gdnsd-plugin-reflect.podin
similarity index 100%
rename from docs/gdnsd-plugin-reflect.pod
rename to docs/gdnsd-plugin-reflect.podin
diff --git a/docs/gdnsd-plugin-simplefo.pod b/docs/gdnsd-plugin-simplefo.podin
similarity index 100%
rename from docs/gdnsd-plugin-simplefo.pod
rename to docs/gdnsd-plugin-simplefo.podin
diff --git a/docs/gdnsd-plugin-static.pod b/docs/gdnsd-plugin-static.podin
similarity index 100%
rename from docs/gdnsd-plugin-static.pod
rename to docs/gdnsd-plugin-static.podin
diff --git a/docs/gdnsd-plugin-tcp_connect.pod b/docs/gdnsd-plugin-tcp_connect.podin
similarity index 100%
rename from docs/gdnsd-plugin-tcp_connect.pod
rename to docs/gdnsd-plugin-tcp_connect.podin
diff --git a/docs/gdnsd-plugin-weighted.pod b/docs/gdnsd-plugin-weighted.podin
similarity index 100%
rename from docs/gdnsd-plugin-weighted.pod
rename to docs/gdnsd-plugin-weighted.podin
diff --git a/docs/gdnsd.config.pod b/docs/gdnsd.config.podin
similarity index 100%
rename from docs/gdnsd.config.pod
rename to docs/gdnsd.config.podin
diff --git a/docs/gdnsd.djbdns.pod b/docs/gdnsd.djbdns.podin
similarity index 100%
rename from docs/gdnsd.djbdns.pod
rename to docs/gdnsd.djbdns.podin
diff --git a/docs/gdnsd.pod b/docs/gdnsd.podin
similarity index 100%
rename from docs/gdnsd.pod
rename to docs/gdnsd.podin
diff --git a/docs/gdnsd.zonefile.pod b/docs/gdnsd.zonefile.podin
similarity index 98%
rename from docs/gdnsd.zonefile.pod
rename to docs/gdnsd.zonefile.podin
index 87a1464..9d97398 100644
--- a/docs/gdnsd.zonefile.pod
+++ b/docs/gdnsd.zonefile.podin
@@ -10,11 +10,11 @@ example.com:
   $TTL 86400
 
   @	SOA ns1 hostmaster (
-  	1      ; serial
-  	7200   ; refresh
-  	30M    ; retry
-  	3D     ; expire
-  	900    ; ncache
+        1      ; serial
+        7200   ; refresh
+        30M    ; retry
+        3D     ; expire
+        900    ; ncache
   )
 
   @	NS	ns1.example.com.
diff --git a/docs/gdnsd_geoip_test.pod b/docs/gdnsd_geoip_test.podin
similarity index 100%
rename from docs/gdnsd_geoip_test.pod
rename to docs/gdnsd_geoip_test.podin
diff --git a/gdnsd/conf.c b/gdnsd/conf.c
index a4b21da..f3a08f7 100644
--- a/gdnsd/conf.c
+++ b/gdnsd/conf.c
@@ -402,7 +402,7 @@ static void fill_dns_addrs(vscf_data_t* listen_opt, const dns_addr_t* addr_defs)
             if(!vscf_is_hash(addr_opts))
                 log_fatal("DNS listen address '%s': per-address options must be a hash", lspec);
 
-            CFG_OPT_UINT_ALTSTORE(addr_opts, udp_recv_width, 1LU, 32LU, addrconf->udp_recv_width);
+            CFG_OPT_UINT_ALTSTORE(addr_opts, udp_recv_width, 1LU, 64LU, addrconf->udp_recv_width);
             CFG_OPT_UINT_ALTSTORE(addr_opts, udp_rcvbuf, 4096LU, 1048576LU, addrconf->udp_rcvbuf);
             CFG_OPT_UINT_ALTSTORE(addr_opts, udp_sndbuf, 4096LU, 1048576LU, addrconf->udp_sndbuf);
             CFG_OPT_UINT_ALTSTORE_NOMIN(addr_opts, udp_threads, 1024LU, addrconf->udp_threads);
diff --git a/gdnsd/dnsio_udp.c b/gdnsd/dnsio_udp.c
index 261350d..5c988c3 100644
--- a/gdnsd/dnsio_udp.c
+++ b/gdnsd/dnsio_udp.c
@@ -472,23 +472,13 @@ static void mainloop_mmsg(const unsigned width, const int fd, void* dnsp_ctx, dn
                 }
             }
 
-            struct mmsghdr* dgptr = dgrams;
-            while(pkts) {
-                int sent = sendmmsg(fd, dgptr, pkts, 0);
-                dmn_assert(sent != 0);
-                dmn_assert(sent <= pkts);
-                if(unlikely(sent < pkts)) {
-                    int sockerr = 0;
-                    socklen_t sock_len = sizeof(sockerr);
-                    (void)getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sock_len);
-                    stats_own_inc(&stats->udp.sendfail);
-                    if(sent < 0) sent = 0;
-                    log_err("UDP sendmmsg() of %zu bytes to client %s failed: %s", dgptr[sent].msg_hdr.msg_iov[0].iov_len, dmn_logf_anysin(dgptr[sent].msg_hdr.msg_name), dmn_logf_strerror(sockerr));
-                    dgptr += sent; // skip past the successes
-                    dgptr++; // skip the failed one too
-                    pkts--; // drop one count for the failed message
-                }
-                pkts -= sent; // drop the count of all successes
+            int mmsg_rv = sendmmsg(fd, dgrams, pkts, 0);
+            if(unlikely(mmsg_rv < 0)) {
+                stats_own_inc(&stats->udp.sendfail);
+                int sockerr = 0;
+                socklen_t sock_len = sizeof(sockerr);
+                (void)getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sock_len);
+                log_err("UDP sendmmsg() failed: %s", dmn_logf_strerror(sockerr));
             }
         }
         else {
diff --git a/gdnsd/statio.c b/gdnsd/statio.c
index fcab1ff..7a3bc4e 100644
--- a/gdnsd/statio.c
+++ b/gdnsd/statio.c
@@ -663,12 +663,12 @@ void statio_bind_socks(void) {
 }
 
 bool statio_check_socks(bool soft) {
-    unsigned rv = true;
+    unsigned rv = false;
     for(unsigned i = 0; i < num_lsocks; i++)
         if(!socks_sock_is_bound_to(lsocks[i], &gconfig.http_addrs[i]) && !soft)
             log_fatal("Failed to bind() stats TCP socket to %s", dmn_logf_anysin(&gconfig.http_addrs[i]));
         else
-            rv = false;
+            rv = true;
     return rv;
 }
 
diff --git a/plugins/extmon/extmon_comms.c b/plugins/extmon/extmon_comms.c
index 4a6adab..b89e31d 100644
--- a/plugins/extmon/extmon_comms.c
+++ b/plugins/extmon/extmon_comms.c
@@ -92,10 +92,12 @@ bool emc_write_command(const int fd, const extmon_cmd_t* cmd) {
     len += 4;
 
     // 2-byte index, 1-byte timeout, 1-byte interval
-    buf[len++] = cmd->idx >> 8;
-    buf[len++] = cmd->idx & 0xFF;
-    buf[len++] = cmd->timeout;
-    buf[len++] = cmd->interval;
+    buf[len++] = (char)(cmd->idx >> 8);
+    buf[len++] = (char)(cmd->idx & 0xFF);
+    buf[len++] = (char)(cmd->timeout >> 8);
+    buf[len++] = (char)(cmd->timeout & 0xFF);
+    buf[len++] = (char)(cmd->interval >> 8);
+    buf[len++] = (char)(cmd->interval & 0xFF);
 
     // skip 2-byte len for rest of packet at offset 8
     len += 2;
@@ -123,9 +125,9 @@ bool emc_write_command(const int fd, const extmon_cmd_t* cmd) {
 
     // now go back and fill in the overall len
     //   of the variable area for desc/args.
-    const unsigned var_len = len - 10;
-    buf[8] = var_len >> 8;
-    buf[9] = var_len & 0xFF;
+    const unsigned var_len = len - 12;
+    buf[10] = (char)(var_len >> 8);
+    buf[11] = (char)(var_len & 0xFF);
 
     bool rv = emc_write_string(fd, buf, len);
     free(buf);
@@ -148,8 +150,8 @@ extmon_cmd_t* emc_read_command(const int fd) {
     extmon_cmd_t* cmd = NULL;
 
     {
-        uint8_t fixed_part[10];
-        if(emc_read_nbytes(fd, 10, fixed_part)
+        uint8_t fixed_part[12];
+        if(emc_read_nbytes(fd, 12, fixed_part)
             || strncmp((char*)fixed_part, "CMD:", 4)) {
             log_debug("emc_read_command() failed to read CMD: prefix");
             goto out_error;
@@ -157,13 +159,13 @@ extmon_cmd_t* emc_read_command(const int fd) {
 
         cmd = xmalloc(sizeof(extmon_cmd_t));
         cmd->idx = ((unsigned)fixed_part[4] << 8) + fixed_part[5];
-        cmd->timeout = fixed_part[6];
-        cmd->interval = fixed_part[7];
+        cmd->timeout = ((unsigned)fixed_part[6] << 8) + fixed_part[7];
+        cmd->interval = ((unsigned)fixed_part[8] << 8) + fixed_part[9];
         cmd->args = NULL;
         cmd->num_args = 0;
 
         // note we add an extra NULL at the end of args here, for execl()
-        const unsigned var_len = ((unsigned)fixed_part[8] << 8) + fixed_part[9];
+        const unsigned var_len = ((unsigned)fixed_part[10] << 8) + fixed_part[11];
         if(var_len < 4) {
             // 4 bytes would be enough for num_args, a single 1-byte argument
             //   and its NUL termiantor, and a zero-length NUL-terminated desc
diff --git a/plugins/trivial/multifo.c b/plugins/trivial/multifo.c
index f56b1f9..0ad5a30 100644
--- a/plugins/trivial/multifo.c
+++ b/plugins/trivial/multifo.c
@@ -183,8 +183,6 @@ static void config_addrs(const char* resname, const char* stanza, addrset_t* ase
 
     if(!num_addrs)
         log_fatal("plugin_multifo: resource '%s' (%s): must define one or more 'desc => IP' mappings, either directly or inside a subhash named 'addrs'", resname, stanza);
-    if(num_addrs > 64)
-        log_fatal("plugin_multifo: resource %s (%s): too many IPv%c addresses (limit 64)", resname, stanza, ipv6 ? '6' : '4');
 
     aset->count = num_addrs;
     aset->as = xcalloc(num_addrs, sizeof(addrstate_t));

Reply to: