The dnscache, tinydns, axfrdns, and walldns services

The Bernstein dnscache, tinydns, axfrdns, and walldns tools from djbdns can be run as services, and the proxy and content DNS services are preconfigured with certain defaults.

Ways to run the services

There are two ways in which these tools can be run as services.

One global instance each

The service bundles package comes with one predefined system-level service bundle for each of dnscache, tinydns, axfrdns, and walldns; and an associated service bundle for each of the associated log services cyclog@dnscache, cyclog@tinydns, cyclog@axfrdns, and cyclog@walldns. The external formats import subsystem enables these service bundles according to the usual presets such as a dnscache_enable="YES" flag in /etc/rc.conf.

These service bundles have to be hand-configured in the conventional ways for djbdns services: variables named ROOT, IP, CACHESIZE and so forth stored in an environment variable directory in the conventional place for a service. These can be accessed and modified in the conventional ways:

The exceptions are:

In both cases this is because the run program is not a shell script and does not have shell variable expansion mechanisms for parameterizing what it passes to hardlimit and tcp-socket-listen. The axfrdns service uses ucspi-socket-rules-check, though, which is how one can arrange to restrict client access.

One generated instance per network address

This is a more fine-grained system, where the external formats import subsystem driven by more detailed settings in /etc/rc.conf:

This requires the modified dnscache and tinydns tools from djbwares, because service management arranges to pass in their listening socket(s), already opened and bound to address, as open file descriptors. The djbwares versions of the dnscache and tinydns tools have been enhanced to be capable of this (the former requiring two open file descriptors, one a TCP listening socket and one a UDP listening socket).

Again, the service bundles are configured in the conventional ways for djbdns services: variables in a conventionally-placed environment variable directory, read by envdir and understood by rcctl and other tools. However, the IP environment variables are ignored by the djbwares versions of the programs, when they find that they have been supplied the listening socket file descriptors already opened. The DATALIMIT variable is also ignored in favour of a hardwired hardlimit invocation.

The generated per-address services are set up to have their log outputs directed into the log services of the single global services.

The external formats import subsystem again enables these service bundles according to the usual presets, although a flag in /etc/rc.conf is less convenient than (say) a systemd-style preset file in /etc/system-control/presets/20-dns.preset containing:

enable dnscache@127.0.0.1
enable cyclog@dnscache
enable axfrdns@127.53.0.1
enable cyclog@axfrdns
enable tinydns@127.53.0.1
enable cyclog@tinydns
enable walldns@127.53.0.1
enable cyclog@walldns

Content server databases

By default, each tinydns service bundle is set up with its own private service/root directory, and each axfrdns is set up with its service/root symbolically linked to that. Each service/root directory contains an individual Makefile, data source file, and tools such as add-ns (which are short convenience scripts wrapping tinydns-edit, that need Laurent Bercot's execlineb script interpreter). However, they can be pointed at shared databases in three simple ways, if one wants content served from a common shared database:

How and what one does in this area, and the tradeoffs and design decisions, are well beyond the scope of this Guide however.

An example of a service/root directory for a private content DNS server, with basic split-horizon service and also mirroring a few top-level domains, is supplied in the /usr/local/share/examples/tinydns/ directory. This combines data obtained from the official well-known sources of public root data with a private main file where one can put one's own additional data. It is pre-configured to serve the private root data to any IP addresses mapped to the the lo and si location codes, but not serve it to other (by implication not machine-local nor site-local) IP addresses. It can thus double as a public content DNS server, where the private root (and any other data in main tagged as either lo and si) is invisible to Internet at large.

Proxy server configuration

By default, each dnscache service bundle is set up with its own private service/root/ip and service/root/servers directories telling it whom to contact with back-end queries and whom to answer on the front end. It is a rare configuration where one wants to share these amongst multiple dnscache services, and usually one will not want to do so.

Note: service/seed files are not used by these services. A fresh seed is copied directly from /dev/urandom for every invocation of the dæmon and sent through a pipe from which it can only be read once. dnscache does not require seeds to remain the same from run to run of the server, and a seed in a file has to be (a) only readable by the superuser, (b) specifically not readable by the dnscache user, and (c) not shared amongst multiple dnscache services. This makes use of the pipe utility which can set up a pipeline with the main dæmon process as one of the elements of the pipe (something which cannot be done directly in shell script).

What one gets with the default setup

The intended default if the aforementioned network address variables are not set up in /etc/rc.conf and there is nothing in /etc/resolv.conf supplies a working system, of DNS client libraries talking to a machine-local resolving caching proxy DNS server, in turn talking to a machine-local private root content DNS server.

You do not have to turn anything else on if the content DNS server on 127.53.0.1 is the tinydns@127.53.0.1 service, the proxy DNS server on 127.0.0.1 is the dnscache@127.0.0.1 service, and your DNS client library defaults to contacting 127.0.0.1 for proxy DNS service.