Provided by: gdnsd_1.11.1-1_amd64 bug


       gdnsd.config - gdnsd configuration file


         options => {
           log_stats => 86400
           tcp_timeout => 15 ; zonefile-style comment
           include_optional_ns => true
           listen => [, ]

         # shell-style comment

         service_types => {
           foosvc => { vhost =>, url_path => "/checkme" }
           barsvc => $include{bar-svc.cfg}

         plugins => {
           null => {}


       This man page describes the syntax of the primary gdnsd configuration file.

       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:
       options, service_types, and 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.


       These options control the overall behavior of gdnsd(8).

           String, defaults to "gdnsd".  This is the username the daemon drops privileges to the
           uid/gid of on startup if started as root.

           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 $TTL directive (see gdnsd.zonefile(5)).

           Integer port, 1-65535, default 53.  This is the global default port number for DNS
           listener addresses which do not specify port numbers themselves.

           Integer port, 1-65535, default 3506.  This is the default HTTP port number for stats
           listener addresses which do not specify port numbers themselves.

           The listen option specifies the socket addresses the server listens on for DNS

           A listen-address specification is an IP (v4 or v6) address specified as a numeric
           string with standard formatting (anything numeric that "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 "dns_port", which defaults to 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

             options => { listen = }

           It can also take the form of an array of such addresses, as in:

             options => {
               listen = [

           Finally, it can also be a hash where the keys are listen addresses, and the values are
           per-address options, as in:

             options => {
               listen => {
        => {
                   tcp_timeout = 7
        => {
                   udp_threads = 5

           The per-address options (which are identical to, and locally override, the global
           option of the same name) are "tcp_threads", "tcp_timeout", "tcp_clients_per_thread",
           "udp_threads", "udp_recv_width", "udp_rcvbuf", and "udp_sndbuf".

           There are also two special singalur string values: "any" and "scan".

           If set to "any", the daemon will listen on the "dns_port" port (default 53) on
           and "::" (if IPv6 support is detected).

             options => { listen => any }

           If set to "scan", scan all available IP (v4 and v6) network interfaces via
           "getifaddrs()" and set up a separate listener on the "dns_port" port (again, default
           53) for each address found.

             options => { listen => scan }

           If the listen option isn't specified at all, for historical compatibility reasons the
           current default is "scan".  However, this default is expected to change to "any" in a
           future version, so you should specify "scan" explicitly if you require this behavior.

           Basically like 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.  Also, the default addresses are the IPv4 and IPv6 (if
           supported) any-addresses ( and "::"), rather than the iterated per-interface
           addresses that the DNS listener uses.

           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.

           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.

           Exactly like "tcp_threads", but for UDP sockets per DNS listening address.

           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 socket.  Once this limit is
           reached by a given socket, no new connections will be allowed to that socket until one
           of the existing ones closes or times out.  Note that sockets map 1:1 to threads, and
           thus the total client limit for connecting to a given address would be
           "tcp_clients_per_thread * tcp_threads" for a given address.

           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.  gdnsd(8) allows multiple requests per connection, and this idle timeout
           applies to the time between requests as well.

           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.

           Integer, min 4096, max 1048576.  If set, this value will be used to set the
           "SO_RCVBUF" socket option on the UDP listening socket(s).  Most users do not need to
           tune this value.  If left unset, the code only 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 "udp_recv_width" > 1.

           Integer, min 4096, max 1048576.  If set, this value will be used to set the
           "SO_SNDBUF" socket option on the UDP listening socket(s).  Tuning advice mirrors the

           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.

           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.

           Boolean, default "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 fatal error (failure to start, or non-zero exit code, respectively).  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.

           Boolean, default "true"

           If true (the default), on daemon startup (via "start" or "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 SIGHUP 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 "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

           Boolean, default "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 "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 "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 "SIGHUP" (or
           executing the "reload" command / initscript action, which sends SIGHUP for you).

           Integer seconds, default 31, min 10, max 600.  Only applies when "zones_rfc1035_auto"
           is "true".

           Sets the time interval for periodically checking the zonefile directory for changes.
           On systems which support "inotify()", however, the automatic mode will almost always
           use that mechanism instead for even faster detection with less overhead.  In the
           "inotify()" case, the interval is used only occasionally when recovering from
           temporary "inotify()" failures.

           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 "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

           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...).

           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 SIGHUP or periodic automatic scanning, and to
           "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.
 , in the same zones directory (gdnsd ignores all filenames with a
           leading dot), and then mv(1) / rename(2) the file to its final destination filename

           If the value specified is less than the final runtime value of
           "zones_rfc1035_min_quiesce" above, it will be adjusted upwards to that minimum value
           for correct operation.

           Boolean, default false.  Causes the daemon to do "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.

           Signed integer, range -20 to +20, lower values are higher priority.  If explicitly
           set, gdnsd will attempt "setpriority()" to this value on startup.  If left unset and
           gdnsd is started as a normal user, no "setpriority()" call will be made.  If left
           unset and gdnsd is started as root, it will default to calling "setpriority()" with
           the value "-11".

           Boolean, default false.  On the wire, "TXT" (and "SPF", which are identical in wire-
           format other than the RR-type) 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 "TXT" data is sent as two 16-byte chunks or one 32-byte chunk.

           Ordinarily, you may specify chunk(s) of a "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 "TXT" or "SPF" record
           which is larger than 255 bytes will be considered a syntax error.

           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.

           A single string or an array of strings, default empty.  Normally the daemon searches
           for plugins in the fixed path "$PREFIX/lib/gdnsd", using filenames of the form
           "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

           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.

           Integer, default 16384, min 4096, max 62464.  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 "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 "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.

           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.

           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 "DYNC" dynamic CNAME responses) the code
           will halt further recursive lookups for this request and return an empty NXDOMAIN
           response, and log a loud message to syslog on every single request for this broken

           Note that this is the only thing preventing infinite CNAME loops caused by bad DYNC
           plugin configurations.  Also note that even in the "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.

           Boolean, default false.  If (and only if) gdnsd was built in debug mode
           (--enable-developer, which slows things down with a ton of assertion checks among
           other things), setting this option to "true" will cause additional debugging output to

           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 "reflect" and "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:


           Boolean, default false.  Forces all monitored resources with IPv6 addresses
           permanently to the UP state, and does not actually send them monitoring requests.
           Useful if some of your DNS servers don't have working or reliable IPv6 routing, which
           would otherwise fail IPv6 polls and force the related addresses to be marked DOWN.  A
           better alternative would be to only host DNS for v6-capable services on v6-capable DNS
           hosts, or install a Tunnelbroker/Sixxs/Teredo/Miredo/etc tunnel to get v6 routability.

           String, default "gdnsd".  When gdnsd receives any query with the class "CH" ("Chaos"),
           as opposed to the normal "IN" ("Internet"), it will return a single response record of
           class "CH" and type "TXT", which contains the string defined here.  This is something
           like BIND's version reporting, which responds to "version.bind" queries in the "CH"
           class, and is what a client will see if they use such a query against a gdnsd server.


       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 the given types of
       service.  Each service type uses a protocol-specific plugin, and the default is the
       included plugin "http_status", which checks HTTP status code responses.

       The other included monitoring plugins are "tcp_connect" (documented below alongside
       "http_status", just checks TCP), and "extmon", which executes external monitoring
       commands/scripts and has its own documentation at gdnsd-plugin-extmon(8).

       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 "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 can be in one of three states at runtime:
       "UP", "DANGER", or "DOWN".  The UP state means that all is perfectly well.  The DANGER
       state means that some isolated failures have been seen in the recent past (perhaps even
       just one), but that gdnsd has not yet seen a consistent enough pattern of failure to
       declare the service dead.  The DOWN state, obviously, means that gdnsd does consider the
       service dead.  These states are presented to the plugin that requested the monitoring.  It
       is up to the plugin to determine how this affects DNS responses.

       Any services monitored for plugins are also have their state reported alongside the
       standard gdnsd statistics report, served by the built-in HTTP server (default port is

       There are five built-in service types that can't be overridden:

       One built-in service type is implicitly named "default".  It uses the default
       "http_status" plugin and is defined to all of the default parameters shown below.

       The other four are named "none", "up", "danger", and "down".

       These do no actual monitoring, and simply force the state of resources using these
       service_types to a fixed state.  "none" is just an alias for "up".

       The following are the generic parameters for all service_types:

           Integer, default 20, min 1, max 255.  Number of monitoring requests which must succeed
           with no intervening failures to transition a given IP for this resource from the DOWN
           state to the UP state.

           Integer, default 10, min 1, max 255.  Number of monitoring requests which must succeed
           with no intervening failures to transition a given IP for this resource from the
           DANGER state to the UP state.

           Integer, default 10, min 1, max 255.  Number of monitoring requests which must fail,
           regardless of any intervening successes, to transition a given IP for this resource
           from the DANGER state to the DOWN state.

           Integer seconds, default 10, min 1, max 255.  Number of seconds between successive
           monitoring requests to a given IP address for this resource.

           Integer seconds, default 3, 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.  Must be less than 90% of interval.

           String, default "http_status".  This indicates which protocol-specific plugin to use
           to execute the monitoring requests.  Any parameters other than the generic ones listed
           here are consumed by the plugin.

       The "tcp_connect" plugin has just one plugin-specific parameter:

           Integer, required.  This is the port number to contact on the remote host to check
           this service type.  It has no default and must be specified.

       The following are the plugin-specific parameters for the default monitoring plugin

           Integer, default 80.  This is the port number to contact on the remote host to check
           this service type.

           String, default "/".  This is the URL that should be used when checking this service

           Hostname, no default.  If defined, the HTTP/1.0 monitoring request will include this
           as a "Host:" header in the monitoring request.  If not defined, no "Host:" header will
           be sent.

           Array of 3-digit HTTP status codes, default "[ 200 ]".  This defines the HTTP status
           codes in responses that will be accepted as successful.


       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 "{}" 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 3 very trivial dynamic resolution plugins named "null", "static", and

       "null" simply returns all-zeros addresses for DYNA records, and "invalid." as the RHS of
       DYNC records.  It does not pay attention to any plugin-specific configuration.

       The "static" plugin can be configured with a map of resource names to IPv4 addresses or
       CNAME hostnames, and it will do the obvious: map those resource names statically for use
       in either DYNA or DYNC zonefile records.

       "reflect" is primarily for real-world testing and debugging.  It attempts to reflect back
       to the query originator an address answer showing the server's view of where the client is
       located on the network.  Currently in the common case this will be the address of the
       intermediate cache server which communicated directly with gdnsd.  However, if the query
       contains the draft edns-client-subnet option, the response can reflect that as well.

       It accepts 4 fixed resource names at the zonefile level: "dns", "edns", "best", and
       "both".  "dns" means to ignore edns-client-subnet and always return the cache's address.
       "edns" means to ignore the cache's address and always return edns-client-subnet
       information, (or if not available).  "best" will return the edns-client-subnet
       information if available, or the cache's address if not.  "both" returns both addresses if
       edns-client-subnet is available, or just the cache otherwise.  The default behavior is

       gdnsd also includes five other plugins that are more production-useful, all of which have
       their own separate manpage documentation (e.g. "man gdnsd-plugin-FOO"):

           Simple primary->secondary failover of monitored addresses

           All-active failover of monitored round-robin address groups

           Weighted-round-robin responses with a variety of behavioral flavors, for both
           monitored addresses and CNAMEs

           Static-ordered address(-group) meta-failover between 'datacenters', which are
           resources defined in terms of other plugins

           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 geographically-differentiated CNAME
           resolution as well.

       A configuration example showing the trivial plugins, as well as demonstrating the
       service_types described earlier:

         service_types => {
           corpwww_type => {
             vhost =>
             url_path => /check_me
             down_thresh => 5
             interval => 5

         plugins => {
           null => {},
           reflect => {},
           static => {
             foo =
             bar =
             somehost =

       And then in your 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


       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 ("#") and DNS zonefile styles
       (";") 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 ("{" and "}").  Keys are separated from their values
       by either "=>" or "=" (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 ("[" and "]").  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 ("""), and can contain any literal byte
       value (even binary/utf-8 stuff, or NUL) other than """ or "\".  Those two characters must
       be escaped by "\", i.e.  "\"" and "\\".

       In the unquoted form, there are no surrounding quotes, and the allowed set of unescaped
       characters is further restricted.  The following are not allowed: "][}{;#,"=\" (that is,
       square brackets, curly brackets, semicolons, octothorpes, commas, double quotes, equal
       signs, and backslashes).  Additionally, the first character cannot be a "$" (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 "\".  "\" followed by any single byte
       other than a digit (0 - 9) is interepreted as that byte.  "\" followed by exactly 3 digits
       interprets those digits as the unsigned decimal integer value of the desired byte (the 3
       digit value cannot exceed 255).

       To illustrate the escaping and quoting, the following sets of example strings show
       different encodings of the same parsed value:



         white\ space
         "white space"



       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 = [, ],
           http_listen =,

       Example 2 (fat arrows, no commas, some arbitrary quoting):

         "options" => {
           listen => [ ]
           http_listen => ""

       Example 3 (compressed and ugly):



       vscf now has a mechanism for config includefiles.  The syntax is


       where "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 $include and the following "{" is not.  If the filename is relative
       (does not begin with /), 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,

       The include statement can be used in two distinct contexts within the syntax structure of
       a config file:

       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} }
               [, ]

             main config:
               plugins => $include{ "bar" }
               geoip => { ... }
               extmon => { ... }

       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.  Example:

             main config:
               options => { ... },
               plugins => {
                   extmon => { ... },
                   metafo => { ... },
                   simplefo => { ... }
               geoip => { ... },
               weighted => { ... }


       gdnsd(8), gdnsd.zonefile(5), gdnsd-plugin-simplefo(8), gdnsd-plugin-multifo(8),
       gdnsd-plugin-weighted(8), gdnsd-plugin-metafo(8), gdnsd-plugin-geoip(8),
       gdnsd-plugin-extmon(8), gdnsd-plugin-api(3)

       The gdnsd manual.


       Copyright (c) 2012 Brandon L Black <>

       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 <>.