The dnscache, tinydns, axfrdns, and walldns services

# 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:

-     rcctl set dnscache CACHESIZE 1000000

-     system-control print-service-env tinydns IP

The exceptions are:

- the listening IP address of the `axfrdns` service, which is hardwired to `::0` in the service's `run` program

- the data resource limit of the `dnscache` service, which is set with a hardwired use of `hardlimit` in the service's `run` program

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`:

- For each of the network addresses listed as `dnscache_network_addresses` it generates a `dnscache@`address service. If is no network address setting, it generates `dnscache@127.0.0.1`. (To not set up any such dnscache services at all, the `dnscache_network_addresses` setting must exist and be blank.)

- For each of the network addresses listed as `tinydns_network_addresses` it generates `tinydns@`address and `axfrdns@`address services. If is no network address setting, it generates `tinydns@127.53.0.1` and `axfrdns@127.53.0.1`. (To not set up any such tinydns services at all, the `tinydns_network_addresses` setting must exist and be blank.) This is the IP address that the external formats import subsystem

in turn sets as the default root content DNS server for all of the `dnscache@`address services.

- For each of the network addresses listed as `walldns_network_addresses` it generates a `walldns@`address service. If is no network address setting, it generates `walldns@127.53.1.1`. (To not set up any such walldns services at all, the `walldns_network_addresses` setting must exist and be blank.)

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:

- Make `root` a symbolic link to a common shared `root` directory somewhere, just like each `axfrdns` service does with its related `tinydns` service.

- Modify the `ROOT` environment variable for the service, by default set in the environment directory to "`root`" and thus naming the `service/root` directory, to name a common shared `root` directory somewhere.

  The common shared directory will be a common shared changed-root area for all services sharing it. It can be anywhere that one likes, with the proviso that the `tinydns` and `axfrdns` user accounts must have the privileges to change directory to it (from their service directories) and the privileges to search it for the `data.cdb` and to read that file. One choice, for example, is to use a `dns` subdirectory next to the area used by the Bernstein publicfile servers for their data (e.g. `/home/publicfile/dns`).

- Modify the `Makefile` to duplicate a common shared `data.cdb` instead of compiling it from the local `data` source file.

  You might be doing this anyway if the content DNS server is supposed to be one of a cluster of such servers, sharing their `data.cdb` files from a single database "master". Or you might be sharing bits and pieces of the source `data` file around and have a `Makefile` that concatenates them together before compiling them to the `data.cdb` 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.

- Until you change it, the only front-end client that will be recognized according to `service/root/ip` will be the client with IP address 127.0.0.1. You have to explicitly turn on client access to your proxy DNS server to the world. It is not automatically turned on for you.

  Note: You have to turn on a `dnscache@`address server that listens on something other than 127.0.0.1, too.

  The `dnscache@127.0.0.1` service provides proxy DNS service to clients on your local machine, which will all talk to it via the IP address 127.0.0.1 which is the one already recognized client.

  Note: If they are configured to talk to it, that is. You must have the equivalent of `nameserver 127.0.0.1` in `/etc/resolv.conf` configured somehow. Again, exactly how to configure your DNS client library to talk to 127.0.0.1 is well beyond the scope of this Guide, involving all sorts of complexities and details from DHCP leases to how `resolvconf` and `NetworkManager` work. On the BSDs, if you don't have any `nameserver` directives, 127.0.0.1 is the default where the DNS client library goes looking for proxy DNS service; so, again, things should just work with the defaults.

- Until you change it, the `service/root/servers/@` file in the `dnscache@127.0.0.1` service bundle will direct all back-end queries made by `dnscache` to a private `.` (i.e. root) content DNS server presumed to be listening on 127.53.0.1.

  The `tinydns@127.53.0.1` content DNS server is set up as a private root content DNS server. It has delegations in its database for all of the (ICANN) top-level domains, and will direct `dnscache` to the second-level content DNS servers appropriately.

  It also contains data that will cause it to answer (same-host and same-site originated) queries for reverse lookups of 10.0.0.0/8, 127.0.0.0/8, and 192.168.0.0/16 IP addresses, and some others.

  Keeping this as the configured `service/root/servers/@` is a good idea for several reasons. It is generally good practice to run one's own private root content DNS server.

  - It stops a whole lot of DNS traffic for nonexistent stuff leaking out of one's personal computer, or one's organization, onto the public Internet. (Surprising domain search mechanisms in DNS client libraries, the inabilities of some applications to take IP addresses where they take domain names but users giving them IP addresses anyway, and several other factors all lead to spurious DNS queries that can and should be dealt with entirely locally.)

  - It also means that one is in ultimate control of one's own root, rather than relying upon the altruism of an outside party. (It's not something that North Americans tend to appreciate; but the fact that ICANN is sponsored and controlled by the U.S.A. government is a worry for people in other countries and on other continents.)

  - It's also resilient even if the machine's own immediate network connection is lost, and available in the bootstrap even before a machine has gained DHCP leases.

  For even better results, one can not only make `tinydns@127.53.0.1` serve root data but also have it serve additional static data for one's own domains, in particular for any "split-horizon" domains; meaning that domain name resolution for things on the LAN is available on-machine as soon as the loopback network interface is up, and does not wait until other network interfaces are configured and up. The `/usr/local/share/examples/tinydns/` directory does this.