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.
There are two ways in which these tools can be run as services.
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.
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
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
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.
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).
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.