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.