Skip to content

djbdns.7

Manvendra Bhangui edited this page Feb 25, 2024 · 2 revisions

NAME

djbdns - overview

Overview

djbdns is a collection of Domain Name System tools. It includes software for all the fundamental DNS operations:

  • DNS cache: finding addresses of Internet hosts. When a browser wants to contact www.hotwired.com, it first asks a DNS cache, such as djbdns's dnscache, to find the IP address of www.hotwired.com. Internet service providers run dnscache to find IP addresses requested by their customers. If you're running a home computer or a workstation, you can run your own dnscache to speed up your web browsing.

  • DNS server: publishing addresses of Internet hosts. The IP address of www.hotwired.com is published by HotWired's DNS servers. djbdns includes a general-purpose DNS server, tinydns; network administrators run tinydns to publish the IP addresses of their computers. djbdns also includes special-purpose servers for publishing DNS walls and RBLs.

  • DNS client: talking to a DNS cache. djbdns includes a DNS client C library and several command-line DNS client utilities. Programmers use these tools to send requests to DNS caches.

djbdns also includes several DNS debugging tools, notably dnstrace, which administrators use to diagnose misconfigured remote servers.

Security

Security features:

  • dnscache runs as a dedicated non-root uid inside a chroot jail, so it can't touch the rest of the machine.

  • tinydns runs as another dedicated non-root uid inside its own chroot jail.

  • walldns runs as another dedicated non-root uid inside its own chroot jail.

  • dnscache discards DNS queries from outside a specified list of IP addresses.

  • dnscache and the dns library use a new query ID and a new UDP port for each query packet. They discard DNS responses from any IP address other than the one that the corresponding query was just sent to.

  • dnscache uses a cryptographic generator to select unpredictable port numbers and IDs.

  • dnscache is immune to cache poisoning.

  • tinydns and walldns never cache information. They do not support recursion.

Security metafeatures:

  • Security was, and is, one of the primary motivations for the development of djbdns. Every step of the design and implementation has been carefully evaluated from a security perspective.

  • The djbdns package has been structured to minimize the complexity of security-critical code. The package is modularized for easy review.

  • Bug-prone coding practices and libraries have been systematically identified and rejected.

Code complexity

The djbdns code is small, with under 7000 instructions. In contrast, BIND 9 has nearly 100000 (not 10000) instructions.

Why is BIND so much larger than djbdns? There are several big reasons:

  • djbdns uses easy-to-parse configuration file formats. BIND uses hard-to-parse configuration file formats. This is not an accident: the BIND company likes the fact that its complicated, unstable formats are difficult for competitors to handle reliably. In contrast, I'm doing my best to cooperate with external tools.

  • djbdns relies on external tools to manage files: for example, rsync provides immediate compressed incremental replication. BIND reinvents the wheel: the BIND company developed DNS-specific mechanisms, NOTIFY and IXFR, for (almost) immediate incremental replication. This isn't an accident either.

  • djbdns relies on external tools, such as ssh and IPSEC, to protect local communications against forgery. BIND again reinvents the wheel: the BIND company developed a DNS-specific anti-forgery mechanism, TSIG.

  • BIND supports DNSSEC. The BIND company would like you to believe that DNSSEC prevents forgeries; in fact, DNSSEC does not prevent forgeries. (DNSSEC was disabled in the latest BIND release in March 2003; did anyone notice?)

  • djbdns has much better internal data structures than BIND. For example, if you're an experienced programmer, you'll find it amusing to compare djbdns's cache.c to the sophomoric tree structures in the BIND code.

  • The BIND company keeps claiming that BIND 9 is ``auditable'' but never claims to have actually audited it. ``History has shown that most large projects have bugs, and that some of these bugs will be security related or otherwise critical,'' Paul Vixie says. ``ISC lacks the hubris needed to announce that there will never be another security-related or otherwise critical bug in BIND.''

The dnscache program

Sensible caching

dnscache(8) maintains a limited-size cache of DNS information, 1 megabyte by default. When the cache fills up, dnscache smoothly discards old cache entries. It doesn't crash; like the Energizer Bunny, it keeps going, and going, and going. In contrast, BIND keeps growing, and growing, and growing. BIND has no limits on cache size; it tries to cache every record until the record expires. Under heavy load, BIND will chew up all your physical memory, start thrashing, chew up all your virtual memory, and then commit hara-kiri, if it doesn't dump core first.

I did 968355 random PTR lookups for an Internet survey in December 1999, using alpha versions of dnsfilter and dnscache. The survey finished in 4.5 hours on a Pentium-133. In contrast, when I tried BIND instead of dnscache, BIND chewed up 32 megabytes of memory and crashed after barely more than 100000 lookups.

According to the BIND company, BIND 9 stays within a memory resource limit without crashing. Unfortunately, when the cache fills up, BIND 9 discards new cache entries. Performance drops dramatically. The server begins failing under moderate loads.

Domain server lists

You can easily configure dnscache to send queries for a particular domain to a particular set of servers, such as ``split DNS'' internal servers behind a firewall. All you have to do is put the server IP addresses into a file named after the domain. When the servers delegate a subdomain to another server, dnscache automatically contacts that server. In contrast, BIND sends recursive queries to the servers, demanding that they act as caches and contact any relevant subdomain servers. This doesn't work with non-recursive servers, and it's a disaster for large domains. (As stated in the ``DNS and BIND'' book, third edition, pages 385-386: ``The forwarders will have an enormous query load placed on them.'') The only workaround is to change the configuration of every BIND cache on your network every time you delegate a subdomain.

Robust query handling

Sometimes, while resolving a user's query, BIND encounters a server name whose IP address it doesn't know. In this case it discards the query. It starts a background ``sysquery'' for the name, hoping to have the results cached a moment later. Consequently the user experiences a strange delay, even when the network is healthy and all servers are running smoothly. The BIND company announced in 1995 that they were going to ``restart'' queries, eliminating this problem. Five years later, they still hadn't succeeded. ``It's too hard,'' says a comment in the BIND code. The BIND internals are too much of a mess.

dnscache doesn't have this problem. It doesn't cut corners in its resolution algorithm.

The tinydns, walldns, rbldns programs

Simplicity and power

The djbdns package includes three servers that publish local host information: tinydns(8), walldns(8), and rbldns(8). Every aspect of configuration was rethought from the perspective of an overworked administrator who has better things to do than play with DNS.

tinydns handles basic DNS service. The tinydns-data(8) file format combines the flexibility of zone files with the convenience of modern zone-building tools. Host information is stored in one file. PTR records are handled automatically. Changes can be scheduled in advance, with TTLs handled automatically.

tinydns has several load-balancing features. It automatically selects a random set of 8 servers from a cluster of any size. It allows easy removal of dead servers by external monitoring tools. It also supports client differentiation, checking the client's IP address and choosing one of several clusters accordingly.

walldns is a reverse DNS wall. It lets firewalled sites access name-checking servers without revealing true host information.

rbldns publishes lists of IP addresses, such as DUL or RBL, through DNS. This could be done with a general-purpose server, but rbldns uses much less memory and much less disk space. For example, John Levine reported in September 2001 that DUL, RSS, and RBL took only 4.9MB, 1.4MB, and 89K in rbldns-data format.

Speed

Databases for tinydns and rbldns are compiled into cdb format. The servers start responding immediately, even if the database is a gigabyte or more. (In contrast: BIND cannot answer questions until it has loaded all your data into memory.) One site reported tinydns answering 6000 queries per second on a dual Pentium III-1000 using 40% of one CPU. That's real queries, not peak performance in lab tests.

While a new database is being compiled, the servers continue to answer queries from the old database. There is no gap in DNS service when the new database is finished. The old database is left in place if anything goes wrong.

Database compilation is very fast. One site reported tinydns-data taking under a minute on a Pentium III-550 to create a 350-megabyte data.cdb covering almost 300000 domains.

The dns library

The djbdns package features a new client library designed to replace the old BIND res_*/dn_* library.

High-level lookups

The dns library provides several easy-to-use DNS lookup routines: dns_ip4, dns_ip4_qualify, dns_name4, dns_mx, and dns_txt. dns_ip4_qualify supports the traditional configuration mechanisms for hostname rewriting: $LOCALDOMAIN, /etc/resolv.conf, and gethostname. It also supports a powerful new user-controlled rewriting mechanism.

The functions that read /etc/resolv.conf automatically reread it every ten minutes, so system administrators don't have to kill long-running programs.

Low-level lookups

The dns_domain_* and dns_packet_* functions make it easy to safely parse DNS packets. The dns_transmit_* functions send DNS queries of arbitrary types to arbitrary servers. These are the functions used in the dnscache program.

Internationalization

The dns library, unlike the BIND client library, has no problems looking up addresses for non-ASCII domain names.

Asynchronous lookups

UNIX offers three levels of support for parallel DNS lookups:

Multiple processes. Any client library can be used here.

[step]
Multiple threads. The client library must be threadable. (This means that, in functions that wait for responses, global variables are protected with mutexes, and are not used while the function is waiting. Other functions can be mutexed by the caller.) Thread creation is generally faster than process creation.

[step]
Event handling with poll or select. The client library must be asynchronous. (This means that none of the functions wait for responses. Event information is passed to the caller.) Event handling is generally the fastest solution, but puts the most stringent requirements on the client library. Asynchronous libraries are automatically threadable.

The dns_transmit_* functions are asynchronous. The high-level features of dns_ip4, dns_name4, etc. are available as asynchronous functions: dns_ip4_packet, dns_name4_packet, etc. There is a sample dnsfilter(1) program that shows how to do many PTR lookups in parallel.

Memory use

The old res_query function places its packets in a user-supplied buffer. The buffer is inevitably much too large for typical results, wasting memory, and too small for large results, making lookups fail on occasion. In contrast, the dns functions dynamically allocate the right amount of space for incoming DNS packets and for final results.

How does DNS work?

Suppose your computer wants to find the IP address of network-surveys.cr.yp.to. It contacts a series of DNS servers around the Internet. There are several DNS servers with information about network-surveys.cr.yp.to. A central root server (located at Internet HQ in Virginia) has the following data in a file on disk:

.:198.41.0.4 &to:198.6.1.82

The root server's IP address is 198.41.0.4; your computer also has this address in a file on disk. Your computer sends its question to the root server, and receives a response from the root server's data:

+--------+ network-surveys.cr.yp.to? +-----------+ | Your | --------------------------> |198.41.0.4 | |computer| <--------------- |root server| +--------+ &to:198.6.1.82 +-----------+

The response &to:198.6.1.82 is a delegation. It says ``For information about .to, ask the DNS server at IP address 198.6.1.82.'' The DNS server at 198.6.1.82 (also located somewhere in Virginia) has the following data in a file on disk:

.to:198.6.1.82 &yp.to:131.193.178.160

Your computer sends its question to that DNS server, and receives a response:

+--------+ network-surveys.cr.yp.to? +----------+ | Your | --------------------------> |198.6.1.82| |computer| <------------------------ |.to server| +--------+ &yp.to:131.193.178.160 +----------+

The response &yp.to:131.193.178.160 is another delegation. It says ``For information about .yp.to, ask the DNS server at IP address 131.193.178.160.'' The DNS server at 131.193.178.160 (located in my office in Chicago) has the following data in a file on disk:

.yp.to:131.193.178.160 =network-surveys.cr.yp.to:131.193.178.100

Your computer sends its question to that DNS server, and receives a response:

+--------+ network-surveys.cr.yp.to? +---------------+ | Your | ------------------------------------------> |131.193.178.160| |computer| <------------------------------------------ | .yp.to server | +--------+ =network-surveys.cr.yp.to:131.193.178.100 +---------------+

The response =network-surveys.cr.yp.to:131.193.178.100 finally answers the original question: the IP address of network-surveys.cr.yp.to is 131.193.178.100. All of this work is handled by a DNS cache running on your computer. Your computer remembers everything that it learned (for a limited amount of time; information changes!) to save time later. As an alternative, your computer can contact an external DNS cache operated by your Internet service provider; the external DNS cache will do all the work and report the answer.

Multiple servers

To protect against computer failure, there are actually several root servers, several .to servers, and two yp.to servers. Each of the root servers has the following information:

    .:198.41.0.4:a
    .:128.9.0.107:b
    .:192.33.4.12:c
    .:128.8.10.90:d
    .:192.203.230.10:e
    .:192.5.5.241:f
    .:192.112.36.4:g
    .:128.63.2.53:h
    .:192.36.148.17:i
    .:192.58.128.30:j
    .:193.0.14.129:k
    .:198.32.64.12:l
    .:202.12.27.33:m
    &to:128.250.1.21:a
    &to:193.0.0.193:b
    &to:196.7.0.139:c
    &to:206.184.59.10:d
    &to:198.6.1.82:e
    &to:206.86.247.253:f
    &to:148.59.19.11:g

Each of the .to servers has the following information:

    .to:128.250.1.21:a
    .to:193.0.0.193:b
    .to:196.7.0.139:c
    .to:206.184.59.10:d
    .to:198.6.1.82:e
    .to:206.86.247.253:f
    .to:148.59.19.11:g
    &yp.to:131.193.178.181:a
    &yp.to:131.193.178.160:b
    # or, in BIND master zone-file format:
    # yp.to IN NS a.ns.yp.to
    # yp.to IN NS b.ns.yp.to
    # a.ns.yp.to IN A 131.193.178.181
    # b.ns.yp.to IN A 131.193.178.160

Your computer tries the root servers in a random order. When it receives a response from some root server, it moves to the .to servers, and tries them in a random order. It eventually receives the answer from one of the two yp.to servers. Reverse lookups

Suppose your computer sees the IP address 208.33.217.122 and wants to know the corresponding computer name. Your computer asks a series of DNS servers about the name 122.217.33.208.in-addr.arpa. The root servers have the following information:

    &33.208.in-addr.arpa:206.228.179.10:c
    &33.208.in-addr.arpa:144.228.254.10:b
    &33.208.in-addr.arpa:144.228.255.10:a

The DNS server at IP address 144.228.254.10 has the following information:

    .33.208.in-addr.arpa:144.228.255.10:a
    .33.208.in-addr.arpa:206.228.179.10:c
    .33.208.in-addr.arpa:144.228.254.10:b
    &217.33.208.in-addr.arpa:209.191.164.20:a
    &217.33.208.in-addr.arpa:206.253.194.65:b

The DNS server at IP address 209.191.164.20 has the following information:

    .217.33.208.in-addr.arpa:209.191.164.20:a
    .217.33.208.in-addr.arpa:206.253.194.65:b
    =mm-outgoing.amazon.com:208.33.217.122

The answer is mm-outgoing.amazon.com. Looking up the address for a name, and then the computer name for that address, doesn't necessarily produce the original name. Looking up the computer name for an address, and then the address for that name, doesn't necessarily produce the original address.

How to run a cache on a workstation

Here is how to set up your computer so that it can find addresses of Internet hosts. Exceptions:

  • If your computer has a slow Internet connection, you should use the home computer instructions instead.

  • If you want your computer to find addresses on behalf of other computers on your network, you should use the external cache instructions instead.

  • If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, and if your DHCP client cannot be configured to discard external DNS cache information, you will have to use the no-cache instructions instead.

These instructions assume that you have already installed indimail, indimail-mta, tinydnssec or daemontools and djbdns, and that svscan is already running.

Check that your computer can talk to DNS servers around the Internet:

    dnsq a www.aol.com 192.203.230.10
    dnsq a www.aol.com 192.48.79.30

Normally each dnsq command will instantly print various lines such as ``authority: aol.com 172800 NS dns-07.ns.aol.com.'' If dnsq instead pauses for a minute and prints ``timed out,'' your computer is not properly attached to the Internet (or some of the Internet's central servers are down, which is unlikely). You may have a firewall interfering with your computer's Internet access; if so, tell your firewall to allow UDP and TCP from this computer's ports 1024 through 65535 to any computer's port 53.

[step]
As root, create UNIX accounts named Gdnscache and Gdnslog.

[step]
As root, create an /etc/dnscache service directory:

    dnscache-conf Gdnscache Gdnslog /etc/dnscache
    This directory contains logs and a few configuration files that you can change later.

[step]
As root, tell svscan about the new service, and use svstat to check that the service is up:

    ln -s /etc/dnscache /service/dnscache
    sleep 5
    svstat /service/dnscache

[step]
If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, configure the DHCP client to discard external DNS cache information.

[step]
As root, put

    nameserver 127.0.0.1

into /etc/resolv.conf, replacing any previous nameserver lines. You can skip this step if there are no nameserver lines or if /etc/resolv.conf doesn't exist.

[step]
Check whether you can look up addresses of some Internet hosts:

    dnsip www.cnn.com
    dnsip www.fsf.org

Then try surfing the web. If you want to see what dnscache is doing behind the scenes, read /service/dnscache/log/main/current.

How to run a computer without a cache

Here is how to set up your computer so that it uses another computer to find addresses of Internet hosts. The other computer is set up by your Internet service provider to run an external DNS cache. With these instructions, every time your computer needs an address, it will contact the other computer. In contrast, with the home computer instructions, your computer will remember addresses for future use, speeding up your Internet access. The only advantage of these instructions is their simplicity.

If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, configure the DHCP client to put external DNS cache information into /etc/resolv.conf, and skip to step 5. Most DHCP clients are configured this way by default, so you don't have to do anything.

[step]
Find out the IP address of your ISP's external DNS cache. Many ISPs call this the ``DNS server address.''

[step]
Check that your computer can talk to the external DNS cache. For example, if the IP address of the external DNS cache is 10.53.0.1:

    env DNSCACHEIP=10.53.0.1 dnsqr a www.aol.com

Normally dnsqr will instantly print various lines such as ``answer: www.aol.com 3600 CNAME www.gwww.aol.com.'' If dnsqr instead pauses for a minute and prints ``timed out,'' your computer is not properly attached to your ISP's network (or the DNS cache is down). You may have a firewall interfering with your computer's Internet access; if so, tell your firewall to allow UDP and TCP from this computer's ports 1024 through 65535 to the external DNS cache's port 53.

[step]
As root, put the IP address of the external DNS cache into /etc/resolv.conf on a nameserver line, replacing any previous nameserver lines. For example, if the IP address of the external DNS cache is 10.53.0.1, put

    nameserver 10.53.0.1

into /etc/resolv.conf.

[step]
Check whether you can look up addresses of some Internet hosts:

    dnsip www.cnn.com
    dnsip www.fsf.org

Then try surfing the web.

How to run a forwarding cache on a home computer

Here is how to set up your computer so that it uses another computer to find addresses of Internet hosts, and remembers the addresses for future use. The other computer is set up by your Internet service provider to run an external DNS cache. These instructions are more complicated than the workstation instructions, but they provide better performance if your computer has a slow Internet connection. If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, and if your DHCP client cannot be configured to make external DNS cache information available to dnscache, you will have to use the workstation instructions instead of these instructions.

These instructions assume that you have already installed daemontools and djbdns (version 1.03 or above), and that svscan is already running.

As root, create UNIX accounts named Gdnscache and Gdnslog.

[step]
As root, create an /etc/dnscache service directory:

    dnscache-conf Gdnscache Gdnslog /etc/dnscache

This directory contains logs and a few configuration files that you can change later.

[step]
If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, configure the DHCP client to make external DNS cache information available to dnscache, and skip to step 7.

[step]
Find out the IP address of the external DNS cache. Many ISPs call this the ``DNS server address.''

[step]
Check that your computer can talk to the external DNS cache. For example, if the IP address of the external DNS cache is 10.53.0.1:

    env DNSCACHEIP=10.53.0.1 dnsqr a www.aol.com

Normally dnsqr will instantly print various lines such as ``answer: www.aol.com 3600 CNAME www.gwww.aol.com.'' If dnsqr instead pauses for a minute and prints ``timed out,'' your computer is not properly attached to your ISP's network (or the DNS cache is down). You may have a firewall interfering with your computer's Internet access; if so, tell your firewall to allow UDP and TCP from this computer's ports 1024 through 65535 to the external DNS cache's port 53.

[step]
As root, put the IP address of the external DNS cache into /etc/dnscache/root/servers/@, replacing the previous contents of that file. For example, if the IP address of the external DNS cache is 10.53.0.1:

    echo 10.53.0.1 > /etc/dnscache/root/servers/@

[step]
As root, create /etc/dnscache/env/FORWARDONLY:

    echo 1 > /etc/dnscache/env/FORWARDONLY

[step]
8. As root, tell svscan about the new service, and use svstat to check that the service is up:

    ln -s /etc/dnscache /service/dnscache
    sleep 5
    svstat /service/dnscache

[step]
As root, put

    nameserver 127.0.0.1

into /etc/resolv.conf, replacing any previous nameserver lines. You can skip this step if there are no nameserver lines or if /etc/resolv.conf doesn't exist.

[step]
Check whether you can look up addresses of some Internet hosts:

    dnsip www.cnn.com
    dnsip www.fsf.org

Then try surfing the web. If you want to see what dnscache is doing behind the scenes, read /service/dnscache/log/main/current.

How to run an external cache for your network

Here is how to set up your computer so that it can find addresses of Internet hosts. With these instructions, your computer will run an external cache that other computers can use. In contrast, with the workstation instructions, your computer's cache will be used only by your computer.

These instructions assume that you have already installed daemontools and djbdns, and that svscan is already running.

Check that your computer can talk to DNS servers around the Internet:

    dnsq a www.aol.com 192.203.230.10
    dnsq a www.aol.com 192.48.79.30

Normally each dnsq command will instantly print various lines such as ``authority: aol.com 172800 NS dns-07.ns.aol.com.'' If dnsq instead pauses for a minute and prints ``timed out,'' your computer is not properly attached to the Internet (or some of the Internet's central servers are down, which is unlikely). You may have a firewall interfering with your computer's Internet access; if so, tell your firewall to allow UDP and TCP from this computer's ports 1024 through 65535 to any computer's port 53.

[step]
As root, create UNIX accounts named Gdnscache and Gdnslog.

[step]
Figure out the IP address that you want to use for your external cache. This address must be configured on your computer and accessible to the other computers on your network. The following instructions assume that your network uses private 10.* addresses and that your external cache will use the address 10.53.0.1.

[step]
As root, create an /etc/dnscache service directory, with your IP address on the end of the line:

    dnscache-conf Gdnscache Gdnslog /etc/dnscache 10.53.0.1

This directory contains logs and a few configuration files that you can change later.

[step]
As root, tell svscan about the new service, and use svstat to check that the service is up:

    ln -s /etc/dnscache /service/dnscache
    sleep 5
    svstat /service/dnscache

[step]
As root, create entries in /etc/dnscache/root/ip showing which client IP addresses are authorized to use this cache. For example,

    touch /etc/dnscache/root/ip/10

authorizes all clients with IP address 10.* to use this cache. You can add or remove addresses later.

[step]
Whenever you add a client computer, set it up to use this external cache: as root, on the client computer, put

    nameserver 10.53.0.1

into /etc/resolv.conf, replacing any previous nameserver lines.

[step]
Check whether your computers can look up addresses of some Internet hosts:

    dnsip www.cnn.com
    dnsip www.fsf.org

Then try surfing the web. If you want to see what dnscache is doing behind the scenes, read /service/dnscache/log/main/current.

How to run an external forwarding cache

Here is how to set up your computer so that it uses another computer to find addresses of Internet hosts, and remembers the addresses for future use. The other computer is set up by your Internet service provider to run an external DNS cache. These instructions are more complicated than the non-forwarding external cache instructions, but they provide better performance if your computer has a slow Internet connection. With these instructions, your computer will run an external cache that other computers can use. This means that there will be two external caches: your new external cache, and your ISP's external cache. In contrast, with the internal forwarding cache instructions, your computer's cache will be used only by your computer.

If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, and if your DHCP client cannot be configured to make external DNS cache information available to dnscache, you will have to use the non-forwarding external cache instructions instead of these instructions.

These instructions assume that you have already installed daemontools and djbdns (version 1.03 or above), and that svscan is already running.

As root, create UNIX accounts named Gdnscache and Gdnslog.

[step]
Figure out the IP address that you want to use for your new external cache. This address must be configured on your computer and accessible to the other computers on your network. The following instructions assume that your network uses private 10.* addresses and that your new external cache will use the address 10.53.0.1.

[step]
As root, create an /etc/dnscache service directory, with your IP address on the end of the line:

    dnscache-conf Gdnscache Gdnslog /etc/dnscache 10.53.0.1

This directory contains logs and a few configuration files that you can change later.

[step]
If your computer is running a DHCP client to obtain a dynamically assigned IP address from your ISP, configure the DHCP client to make external DNS cache information available to dnscache, and skip to step 8.

[step]
Find out the IP address of the ISP's external cache. Many ISPs call this the ``DNS server address.''

[step]
Check that your computer can talk to the ISP's external cache. For example, if the IP address of the ISP's cache is 1.2.3.4:

    env DNSCACHEIP=1.2.3.4 dnsqr a www.aol.com

Normally dnsqr will instantly print various lines such as ``answer: www.aol.com 3600 CNAME www.gwww.aol.com.'' If dnsqr instead pauses for a minute and prints ``timed out,'' your computer is not properly attached to your ISP's network (or the ISP's cache is down). You may have a firewall interfering with your computer's Internet access; if so, tell your firewall to allow UDP and TCP from this computer's ports 1024 through 65535 to the ISP's cache's port 53.

[step]
As root, put the IP address of the ISP's external cache into /etc/dnscache/root/servers/@, replacing the previous contents of that file. For example, if the IP address of the ISP's external cache is 1.2.3.4:

    echo 1.2.3.4 > /etc/dnscache/root/servers/@

[step]
As root, create /etc/dnscache/env/FORWARDONLY:

    echo 1 > /etc/dnscache/env/FORWARDONLY

[step]
As root, tell svscan about the new service, and use svstat to check that the service is up:

    ln -s /etc/dnscache /service/dnscache
    sleep 5
    svstat /service/dnscache

[step]
As root, create entries in /etc/dnscache/root/ip showing which client IP addresses are authorized to use your new cache. For example,

    touch /etc/dnscache/root/ip/10

authorizes all clients with IP address 10.* to use this cache. You can add or remove addresses later.

[step]
Whenever you add a client computer, set it up to use this cache: as root, on the client computer, put

    nameserver 10.53.0.1

into /etc/resolv.conf, replacing any previous nameserver lines.

[step]
Check whether you can look up addresses of some Internet hosts:

    dnsip www.cnn.com
    dnsip www.fsf.org

Then try surfing the web. If you want to see what dnscache is doing behind the scenes, read /service/dnscache/log/main/current.

How to adjust the cache size

By default, dnscache uses 1 megabyte of memory for its cache. You can restart it with a 100-megabyte cache as follows:

    echo 100000000 > /service/dnscache/env/CACHESIZE
    echo 104857600 > /service/dnscache/env/DATALIMIT
    svc -t /service/dnscache

dnscache services created with djbdns 1.00 or earlier do not have the /env directory. Instead edit /service/dnscache/run; change CACHESIZE=1000000 to CACHESIZE=100000000 and -d3000000 to -d104857600.

Measuring the effects of the cache size

dnscache frequently logs a stats line in /service/dnscache/log/main/current. The second number after stats on the line is the cache motion. The cache motion is the number of bytes of cache entries that have been written to the cache since dnscache started. Look at this number now, and again in 24 hours; subtract to see the 1-day cache motion. (Or extrapolate, using ps to see how long the dnscache process has been running.) Now divide the cache size by the 1-day cache motion:

  • 0.01: The cache cycle time is roughly 15 minutes. Almost all DNS records have larger TTL (``time to live'') settings; they could be cached longer if the cache were larger.

  • 0.1: The cache cycle time is roughly 2 hours. This is above the AOL address TTL, but it's below the TTL of most records.

  • 1: The cache cycle time is roughly 1 day. There's still some benefit to a larger cache.

  • 10: The cache cycle time is over a week. This leaves ample room for growth; the maximum common TTL is 3 days. dnscache won't save records for more than a week in any case.

Another way to measure cache effectiveness is to divide the cache motion by the query count, which is the first number after stats. When the cache is very large, this ratio will be at its minimum possible value, measuring unavoidable DNS traffic; when the cache is too small, the ratio is too high.

If you're switching from BIND to dnscache, you might be tempted to look at BIND's memory use, and set the dnscache cache size to the same amount. In most cases this is excessive.

User's guide to name resolution

Resolution means conversion of a host name that you type, such as www.cnn.com, into an IP address, such as 64.236.16.84. Internet computers actually contact each other using IP addresses; your browser needs to resolve www.cnn.com before it can contact www.cnn.com. Most of the effort in name resolution is carried out by DNS caches such as dnscache. DNS clients (sometimes called stub resolvers), such as your browser, resolve names by contacting a nearby DNS cache.

This page explains the djbdns client-cache communication procedure. This procedure is followed by the dns_ip4, dns_ip4_qualify, dns_name4, dns_mx, and dns_txt library routines in djbdns, and by programs that use those routines.

Cache selection

The client finds the IP address of the DNS cache on a nameserver line in /etc/resolv.conf:

    nameserver 10.53.0.1

If /etc/resolv.conf does not exist or does not list any IP addresses, the client uses IP address 127.0.0.1: in other words, it contacts a DNS cache on the same computer. The system administrator can list several DNS caches in /etc/resolv.conf by including several nameserver lines. Servers after the 16th are ignored.

You can override /etc/resolv.conf by setting the $DNSCACHEIP environment variable. For example,

    env DNSCACHEIP=127.0.0.1 dnsip www.aol.com

will use IP address 127.0.0.1 no matter what is listed in /etc/resolv.conf.

Retransmission

The client sends a request to the first DNS cache, waits 3 seconds for a response, sends the same request to the second DNS cache, waits 3 seconds for a response, etc. It then sends a request to each cache again, but waits 11 seconds for each response. It then tries each cache one last time, waiting 45 seconds. Compatibility notes

Different DNS client programs use different procedures for contacting caches. Three differences between the djbdns procedure and other procedures:

  • Most programs use only /etc/resolv.conf. They don't know anything about $DNSCACHEIP.

  • Most programs use a different retransmission strategy.

  • Most long-running programs don't notice changes in /etc/resolv.conf; they read /etc/resolv.conf when they start, and they don't reread it until they are restarted. In contrast, the djbdns procedure checks for changes every 10 minutes or 10000 uses.

User's guide to name qualification

Qualification means conversion of a short host name that you type, such as cheetah, into a complete (``fully qualified'') domain name, such as cheetah.heaven.af.mil. This page explains the djbdns qualification procedure. These rules are followed by the dns_ip4_qualify library routine in djbdns, and by programs that use the dns_ip4_qualify routine.

Rewriting instructions

Normally the djbdns qualification procedure follows instructions listed in /etc/dnsrewrite, a file created by your system administrator. You can override /etc/dnsrewrite by creating your own file and setting the $DNSREWRITEFILE environment variable to the name of that file.

Sample instructions:

    # anything.local -> me
    -.local:me
    # me -> 127.0.0.1
    =me:127.0.0.1
    # any.name.a -> any.name.af.mil
    *.a:.af.mil
    # any-name-without-dots -> any-name-without-dots.heaven.af.mil
    ?:.heaven.af.mil
    # remove trailing dot
    *.:

Instructions are followed in order, each at most once. There are four types of instructions:

  • =post:new means that the host name post is replaced by new.

  • *post:new means that any name of the form prepost is replaced by prenew.

  • ?post:new means that any name of the form prepost, where pre does not contain dots or brackets, is replaced by prenew.

  • -post:new means that any name of the form prepost is replaced by new.

Searching

The djbdns qualification procedure can search through DNS for several possible qualifications of a name. For example, the name

    cheetah+.heaven.af.mil+.af.mil

is qualified as cheetah.heaven.af.mil if that name has IP addresses listed in DNS, or cheetah.af.mil otherwise.

In general, x+y1+y2+y3 is qualified as xy1 if xy1 has IP addresses listed in DNS; otherwise, as xy2 if xy2 has IP addresses listed in DNS; otherwise, as xy3. You can list any number of +'s.

Searching is applied after rewriting, so you can use a rewriting instruction such as

    ?:+.heaven.af.mil+.af.mil

to have lion qualified as lion.heaven.af.mil or lion.af.mil, and tiger qualified as tiger.heaven.af.mil or tiger.af.mil, and so on.

Searching is generally not a recommended feature. If you rely on gw being qualified as gw.af.mil, and someone suddenly adds a new gw.heaven.af.mil, you'll end up talking to the wrong host. It's better to rely on syntactic rules that you control.

Compatibility mechanisms

If the rewriting-instructions file does not exist, the djbdns qualification procedure looks for a local domain name in three places:

the $LOCALDOMAIN environment variable, if it is set; or

[step]
the first domain or search line in /etc/resolv.conf, if /etc/resolv.conf exists and has such a line; or

[step]
everything after the first dot in the system's hostname.

It then creates rewriting instructions of the form

    ?:.domain
    *.:

so that .domain is added to any name without dots or brackets.

You can specify searching in $LOCALDOMAIN by using several domain names separated by spaces. Your system administrator can specify searching in /etc/resolv.conf by putting several domains on a search line.

Compatibility notes

Different DNS client programs use different qualification procedures. Two major differences between the djbdns qualification procedure and other qualification procedures:

  • Most programs use only /etc/resolv.conf. They don't know anything about /etc/dnsrewrite and $DNSREWRITEFILE.

  • Most long-running programs don't notice changes in /etc/resolv.conf; they read /etc/resolv.conf when they start, and they don't reread it until they are restarted. In contrast, the djbdns qualification procedure checks for changes every 10 minutes or 10000 uses.

Two minor differences:

  • Some programs interpret a domain line in /etc/resolv.conf as specifying a search list consisting of various suffixes of the domain.

  • Many programs will search the local domain for names with dots.

If you want the local domain searched for names with dots, you can set it up with rewriting:

    # aol.com -> aol.com or aol.com.heaven.af.mil
    *:++.heaven.af.mil
    # but skip directly to heaven.af.mil if no dots
    ?++.heaven.af.mil:.heaven.af.mil

Command-line tools to look up DNS information

Look up the man page for the following dnsip(1), dnsipq(1), dnsname(1), dnsnamex(1), dnsmx(1), dnstxt(1), dnsfilter(1)

Command-line tools to debug DNS configuration

Look up the man page for the following dnsqr(1) dnsq(1), tinydns-get(1), dnstrace(1), dnstracesort(1)

Command-line tools to configure DNS services

Look up the man pages for the following axfrdns-conf(8), curvedns-conf(8), dnscache-conf(8), dqcache-conf(8), pickdns-conf(8), rbldns-conf(8), tinydns-conf(8), walldns-conf(8)

The dns library interface

These are DNS client library routines. They are meant to be used in browsers and other programs that resolve domain names. There is a separate blurb explaining advantages of this library over the libresolv library.

Host name to IP addresses

    #include <dns.h>

    dns_ip4(&out,&fqdn);
    dns_ip4_packet(&out,buf,len);

    stralloc out = {0};
    stralloc fqdn = {0};
    char *buf;
    unsigned int len;

dns_ip4 looks up 4-byte IP addresses for the fully-qualified domain name in fqdn. It puts the concatenation of the IP addresses into out and returns 0. If the domain does not exist in DNS, or has no IP addresses, out will be empty.

If dns_ip4 has trouble with the DNS lookup or runs out of memory, it returns -1, setting errno appropriately. It may or may not change out.

If fqdn is a dotted-decimal IP address, dns_ip4 puts that IP address into out without checking DNS. More generally, if fqdn is a dot-separated sequence of dotted-decimal IP addresses, dns_ip4 puts those IP addresses into out without checking DNS. Brackets may appear inside the dotted-decimal IP addresses; they are ignored.

dns_ip4_packet is a low-level component of dns_ip4, designed to support asynchronous DNS lookups. It reads a DNS packet of length len from buf, extracts IP addresses from the answer section of the packet, puts the addresses into out, and returns 0 or -1 the same way as dns_ip4.

Qualification

    #include <dns.h>

    dns_ip4_qualify(&out,&fqdn,&udn);

    stralloc out = {0};
    stralloc fqdn = {0};
    stralloc udn = {0};

dns_ip4_qualify feeds the name udn through qualification and looks up 4-byte IP addresses for the result. It puts the fully qualified domain name into fqdn, puts the concatenation of the IP addresses into out, and returns 0. If the domain does not exist in DNS, or has no IP addresses, out will be empty.

If dns_ip4_qualify has trouble with the qualification, has trouble with DNS, or runs out of memory, it returns -1, setting errno appropriately. It may or may not change out and fqdn.

IP address to host name

    #include <dns.h>

    dns_name4(&out,ip);
    dns_name_packet(&out,buf,len);
    dns_name4_domain(q,ip);

    stralloc out = {0};
    char ip[4];
    char q[DNS_NAME4_DOMAIN];
    char *buf;
    unsigned int len;

dns_name4 looks up the domain name for the 4-byte IP address in ip. It puts the (first) domain name into out and returns 0. If the relevant in-addr.arpa domain does not exist in DNS, or has no PTR records, out will be empty.

If dns_name4 has trouble with the DNS lookup or runs out of memory, it returns -1, setting errno appropriately. It may or may not change out.

dns_name_packet is a low-level component of dns_name4, designed to support asynchronous DNS lookups. It reads a DNS packet of length len from buf, extracts the first PTR record from the answer section of the packet, puts the result into out, and returns 0 or -1 the same way as dns_name4.

dns_name4_domain is another low-level component of dns_name4. It converts an IP address such as 1.2.3.4 into a domain name such as 4.3.2.1.in-addr.arpa and places the packet-encoded domain name into q.

MX records

    #include <dns.h>

    dns_mx(&out,&fqdn);
    dns_mx_packet(&out,buf,len);

    stralloc out = {0};
    stralloc fqdn = {0};
    char *buf;
    unsigned int len;

dns_mx looks up MX records for the fully-qualified domain name in fqdn. It puts the MX records into out and returns 0. Each MX record is a two-byte MX distance followed by a  -terminated dot-encoded domain name. If the domain does not exist in DNS, or has no MX records, out will be empty.

If dns_mx has trouble with the DNS lookup or runs out of memory, it returns -1, setting errno appropriately. It may or may not change out.

dns_mx_packet is a low-level component of dns_mx, designed to support asynchronous DNS lookups. It reads a DNS packet of length len from buf, extracts the MX records from the answer section of the packet, puts the results into out, and returns 0 or -1 the same way as dns_mx.

TXT records

    #include <dns.h>

    dns_txt(&out,&fqdn);
    dns_txt_packet(&out,buf,len);

    stralloc out = {0};
    stralloc fqdn = {0};
    char *buf;
    unsigned int len;

dns_txt looks up TXT records for the fully-qualified domain name in fqdn. It puts the concatenation of the TXT records into out and returns 0. If the domain does not exist in DNS, or has no TXT records, out will be empty.

If dns_txt has trouble with the DNS lookup or runs out of memory, it returns -1, setting errno appropriately. It may or may not change out.

dns_txt_packet is a low-level component of dns_txt, designed to support asynchronous DNS lookups. It reads a DNS packet of length len from buf, extracts the TXT records from the answer section of the packet, puts the results into out, and returns 0 or -1 the same way as dns_txt.

The dns_domain library interface

    #include <dns.h>

    len = dns_domain_length(dn);

    char *dn;
    unsigned int len;

A DNS domain name is a sequence of components. Each component is a string of bytes, of length between 1 and 63 inclusive. The total length of all the components, plus the number of components, is between 0 and 254 inclusive.

A component is packet-encoded as a self-delimiting sequence of bytes, the first byte being the length of the component, the remaining bytes being the bytes in the component. A DNS domain name is packet-encoded as a sequence of bytes obtained by concatenating the encodings of the components and a terminating  . Beware that   can appear inside components. The total length of a packet-encoded DNS domain name is between 1 and 255 inclusive.

dns_domain_length returns the number of bytes in the packet-encoded DNS name that dn points to.

    #include <dns.h>

    dns_domain_equal(dn,dn2);

    char *dn;
    char *dn2;

dns_domain_equal compares the packet-encoded DNS names that dn and dn2 point to. It returns 1 if the names are the same, 0 if not. Lowercase ASCII and uppercase ASCII are considered the same.

    #include <dns.h>

    dns_domain_copy(&dn,in);

    char *dn = 0;
    char *in;

dns_domain_copy reads the packet-encoded DNS name that in points to, copies the name into dynamically allocated space, points dn to that space, and returns 1. If not enough memory is available, dns_domain_copy returns 0, setting errno appropriately, and leaves dn alone.

You can call dns_domain_copy repeatedly. If dn is nonzero, dns_domain_copy frees it before replacing it with the new pointer. Initially dn must be 0.

    #include <dns.h>

    dns_domain_fromdot(&dn,buf,len);

    char *dn = 0;
    char *buf;
    unsigned int len;

dns_domain_fromdot reads a dot-encoded DNS name of length len from buf, copies the name in packet-encoded format into dynamically allocated space, points dn to that space, and returns 1.

If buf violates DNS name length restrictions, or if not enough memory is available, dns_domain_fromdot leaves dn alone and returns 0, setting errno appropriately.

Like dns_domain_copy, dns_domain_fromdot frees dn before changing it, if dn is nonzero.

The dns_packet library interface

    #include <dns.h>

    newpos = dns_packet_copy(buf,len,pos,out,outlen);

    char *buf;
    unsigned int len;
    unsigned int pos;
    unsigned int newpos;
    char *out;
    unsigned int outlen;

dns_packet_copy reads outlen bytes from position pos of a DNS packet stored at buf, copies the bytes into out, and returns pos+outlen. However, if reading the bytes would require reading past the first len bytes of the packet, dns_packet_copy returns 0, setting errno appropriately.

    #include <dns.h>

    newpos = dns_packet_getname(buf,len,pos,&dn);

    char *buf;
    unsigned int len;
    unsigned int pos;
    unsigned int newpos;
    char *dn = 0;

dns_packet_getname reads a compressed domain name from position pos of a DNS packet stored at buf, copies the name into dn, and returns the position in the packet immediately after the name.

If the name is misformatted, or if reading the name would require reading past the first len bytes of the packet, or if there is not enough memory for dn, dns_packet_getname returns 0, setting errno appropriately, and leaves dn alone.

    #include <dns.h>

    newpos = dns_packet_skipname(buf,len,pos);

    char *buf;
    unsigned int len;
    unsigned int pos;
    unsigned int newpos;

dns_packet_skipname is like dns_packet_getname but discards the resulting domain name. It does not allocate memory.

Beware that, even if dns_packet_skipname returns nonzero, a future dns_packet_getname from the same position may fail: it may run out of memory, or encounter a format error not detected by dns_packet_skipname.

The dns_transmit library interface

    #include <dns.h>

    dns_transmit_start(&dt,s,flagrecursive,q,t,localip);
    dns_transmit_io(&dt,x,&deadline);
    dns_transmit_get(&dt,x,&stamp);
    dns_transmit_free(&dt);

    struct dns_transmit dt = {0};

    char s[64];
    int flagrecursive;
    char *q;
    char t[2];
    char localip[4];

    iopause_fd x[1];
    struct taia deadline;
    struct taia stamp;

The dns_transmit functions send a DNS query to some DNS servers. They save the first useful response inside dt.

The query asks for Internet records of type t for the domain name packet-encoded in q. It requests server recursion if flagrecursive is nonzero.

The IP addresses of the DNS servers are listed in s. The dns_transmit functions skip IP addresses of 0.0.0.0. The dns_transmit functions record only a pointer to the contents of s, not a copy of s, so you must leave s in place and unchanged.

The dns_transmit functions send outgoing packets from a local IP address of localip.

The dns_transmit functions act asynchronously. They are designed to be used in an iopause event loop:

    if (dns_transmit_start(&dt,s,flagrecursive,q,t,localip) == -1)
      return -1;

    for (;;) {
      int r;
      taia_now(&stamp);
      taia_uint(&deadline,120);
      taia_add(&deadline,&deadline,&stamp);
      dns_transmit_io(&dt,x,&deadline);
      iopause(x,1,&deadline,&stamp);
      r = dns_transmit_get(&dt,x,&stamp);
      if (r == -1) return -1;
      if (r == 1) break;
    }

    dosomething(dt.packet,dt.packetlen);
    dns_transmit_free(&dt);
    return 0;

dns_transmit_start begins the query; it returns 0 on success, or -1 on failure. dns_transmit_get continues the query; it returns 1 if the response has arrived, 0 if the response has not yet arrived, or -1 on failure. Here ``failure'' means a socket creation failure, a memory allocation failure, a timeout after the final query attempt, an empty list of servers (reported as EIO), a query longer than 65535 bytes (reported as EIO), a malformed response to the final query attempt (reported as EIO), or a server declaration of failure in response to the final query attempt (reported as EAGAIN).

The dns_transmit functions communicate through dt. They dynamically allocate a socket for network communication, memory for the DNS request, and memory for the DNS response; these resources are freed when you call dns_transmit_free, or when you call dns_transmit_start again with the same dt to handle another query. You must zero-initialize dt before calling dns_transmit_start the first time.

If dns_transmit_get returns 1, the DNS response is a byte string of length dt.packetlen; dt.packet points to the first byte. The IP address of the server that provided the response is stored at dt.servers + 4 * dt.curserver.

Transmission details

The dns_transmit functions send the query by UDP to the first address, wait 1 second for a response, send the query by UDP to the second address, wait 1 second for a response, etc.; then send the query by UDP to each address again, but waiting 3 seconds for each response; then again, waiting 11 seconds; then one last time, waiting 45 seconds. Recursive queries skip the 1-second step.

dns_transmit_get does not always return the first packet it sees:

If the packet has the wrong ID, shows the wrong query name, shows the wrong query type, or has qdcount different from 1: dns_transmit_get discards the packet as irrelevant, and continues waiting for packets from the same server.

[step]
If the packet has rcode different from 0 or 3: dns_transmit_get discards the packet, and moves immediately to the next server.

[step]
If the packet has the tc bit set: dns_transmit_get tries a TCP connection to each address, waiting 10 seconds for the connection and, if a connection is established, 10 more seconds for a response.

dns_transmit_get does not listen to several servers simultaneously for responses for the same query. Each query transmission uses a new random port number and query ID.

The dns_random library interface

    #include <dns.h>

    dns_random_init(seed);
    r = dns_random(m);

    char seed[128];
    unsigned int r;
    unsigned int m;

dns_random computes a pseudorandom 32-bit integer and returns that integer modulo m. It returns 0 if m is 0.

dns_random_init initializes the pseudorandom number generator, taking account of seed, the current process ID, and the current time.

Notes on DNS query security

A DNS client will accept any response that shows up at the right time, is addressed from the IP address of the legitimate server, is addressed to the UDP port used in the DNS query, repeats the query name and type used in the DNS query, and repeats the 16-bit ID used in the DNS query.

An active sniffing attacker can easily forge responses by copying information from queries. Blind attackers need to guess the time, UDP port, and ID for the targeted query name.

The dns_transmit functions use dns_random to create query IDs and UDP ports. The dns_random generator is designed to be extremely difficult to predict for an attacker who cannot guess seed. Note, however, that there are only about a billion possible ID-port pairs, so a prolonged blind attack will succeed eventually.

How to run a DNS server

Here is how to set up your computer so that it publishes your IP addresses. If you're upgrading from a BIND DNS server, you should follow the upgrade instructions instead.

These instructions assume that you have already installed daemontools and djbdns, and that svscan is already running.

As root, create UNIX accounts named Gtinydns and Gdnslog.

[step]
As root, create an /etc/tinydns service directory configured with the IP address of the DNS server:

    tinydns-conf Gtinydns Gdnslog /etc/tinydns 1.8.7.200

This directory contains logs and configuration files that you will change later. The IP address must be configured on this computer. The IP address must not have a DNS cache or any other port-53 service. One computer can run a DNS server alongside a DNS cache as long as they are on separate IP addresses. The standard setup for small networks is to put a DNS cache on a private address such as 127.0.0.1 or 10.53.0.1, and a DNS server on a public address.

[step]
As root, tell svscan about the new service, and use svstat to check that the service is up:

    ln -s /etc/tinydns /service/tinydns
    sleep 5
    svstat /service/tinydns

[step]
Set up your desired DNS data, as described on the rest of this page.

Replicating your DNS service

Here is how to set up a second computer as a DNS server providing the same information as your first DNS server. DNS caches around the Internet will try both servers (in a random order), so they will receive answers even if one server crashes.

You don't have to set up two DNS servers. Your DNS servers don't have to be more highly replicated than your web servers, mail servers, etc. As an extreme, if you have just one computer for your web server, mail server, and DNS server, then setting up a second DNS server is silly. (Third-party DNS servers are almost always a bad idea.) However, if you're running a large site with many services, you should set up two DNS servers.

For concreteness, these instructions assume that your first DNS server is on IP address 1.8.7.200, and that the second computer has IP address 1.8.7.201.

On the second computer, as root, create UNIX accounts named Gtinydns and Gdnslog.

[step]
On the second computer, as root, create an /etc/tinydns service directory configured with the second IP address:

    tinydns-conf Gtinydns Gdnslog /etc/tinydns 1.8.7.201

[step]
On the first computer, as root, edit /service/tinydns/root/Makefile to replicate /service/tinydns/root/data from the first computer to the second:

    remote: data.cdb
      rsync -az -e ssh data.cdb 1.8.7.201:/service/tinydns/root/data.cdb

    data.cdb: data
      /usr/local/bin/tinydns-data

Alternatively, if you don't have rsync:

    remote: data.cdb
      scp data.cdb 1.8.7.201:/service/tinydns/root/data.cdb.tmp
      ssh 1.8.7.201 mv /service/tinydns/root/data.cdb.tmp       /service/tinydns/root/data.cdb

    data.cdb: data
      /usr/local/bin/tinydns-data

Now any changes made on the first computer will be copied to the second.

[step]
On the second computer, as root, edit /service/tinydns/root/data to remind yourself that DNS data is replicated from the first computer to the second:

    # Do not edit data on this computer! data.cdb is copied from 1.8.7.200.
    # The following line protects data.cdb by stopping make.
    9

[step]
On the second computer, as root, tell svscan about the new service, and use svstat to check that the service is up:

ln -s /etc/tinydns /service/tinydns sleep 5 svstat /service/tinydns

Receiving delegations

There are two crucial steps in arranging for a name to be delegated to and handled by your DNS servers. There are separate web pages explaining the two steps of this process in more detail for .com and .net and .org, .at, .br, .ch, .de, .dk, .fr, .hu, .it, .nl, .no, .ru, .us, .in-addr.arpa, and local names. Other top-level domains include .aero, .biz, .coop, .edu, .gov, .info, .int, .mil, .museum, and .name.

First, your server needs to accept the delegation. Your server will not answer questions about a name unless it knows that it is in charge of that name. The following commands tell the server that it is in charge of all names ending with heaven.af.mil and 7.8.1.in-addr.arpa:

    cd /service/tinydns/root
    ./add-ns heaven.af.mil 1.8.7.200
    ./add-ns heaven.af.mil 1.8.7.201
    ./add-ns 7.8.1.in-addr.arpa 1.8.7.200
    ./add-ns 7.8.1.in-addr.arpa 1.8.7.201
    make

These commands also tell the server

  • to advertise a.ns.heaven.af.mil with IP address 1.8.7.200 and b.ns.heaven.af.mil with IP address 1.8.7.201 as the heaven.af.mil DNS servers, and

  • to advertise a.ns.7.8.1.in-addr.arpa with IP address 1.8.7.200 and b.ns.7.8.1.in-addr.arpa with IP address 1.8.7.201 as the 7.8.1.in-addr.arpa DNS servers.

Second, the parent server needs to delegate the name to your servers. Caches around the Internet will not ask your server about a name unless that name has been delegated to your servers. In the above example,

  • the administrator of af.mil needs to delegate heaven.af.mil to the server a.ns.heaven.af.mil running on IP address 1.8.7.200 and the server b.ns.heaven.af.mil running on IP address 1.8.7.201, and

  • the administrator of 8.1.in-addr.arpa needs to delegate 7.8.1.in-addr.arpa to the server a.ns.7.8.1.in-addr.arpa running on IP address 1.8.7.200 and the server b.ns.7.8.1.in-addr.arpa running on IP address 1.8.7.201.

To avoid triggering a BIND bug, the parent server must use the a.ns and b.ns names, not alternate names with the same IP addresses. You can tell tinydns to use different names; in that case, the parent server will have to use those names.

Publishing addresses of your computers

Once a name such as heaven.af.mil has been delegated to your servers, you can publish an IP address for heaven.af.mil and for any name ending with .heaven.af.mil.

Common practice is to set up two types of names:

  • Computer names. Choose a name for each computer, and run add-host with the computer's name and IP address. You also have to tell the computer to respond to that IP address.

  • Service names. For each service (www, pop, etc.), run add-alias with the service's name and IP address.

Distinguishing computer names from service names is helpful if you decide later to move a service from one computer to another.

For example, let's say you're the heaven.af.mil administrator; you have three computers, with IP addresses 1.8.7.4, 1.8.7.5, and 1.8.7.6; you have a web server running on the first computer; and you have an FTP server running on the first computer. You could name the computers lion, tiger, and bear, and run the following commands:

    cd /service/tinydns/root
    ./add-host lion.heaven.af.mil 1.8.7.4
    ./add-host tiger.heaven.af.mil 1.8.7.5
    ./add-host bear.heaven.af.mil 1.8.7.6
    ./add-alias www.heaven.af.mil 1.8.7.4
    ./add-alias ftp.heaven.af.mil 1.8.7.4
    make

The add-host and add-alias programs edit the file /service/tinydns/root/data, which is in tinydns-data format. make runs the tinydns-data program to tell tinydns(8) about the new information. If anything goes wrong, tinydns-data prints an error message, and tinydns continues providing the old information.

Now anyone around the Internet looking up lion.heaven.af.mil or www.heaven.af.mil or ftp.heaven.af.mil will see IP address 1.8.7.4. Anyone looking up the computer name for 1.8.7.4 will see lion.heaven.af.mil.

As an alternative to add-host and add-alias, you can edit /service/tinydns/root/data manually, adding the following lines:

    =lion.heaven.af.mil:1.8.7.4
    =tiger.heaven.af.mil:1.8.7.5
    =bear.heaven.af.mil:1.8.7.6
    +www.heaven.af.mil:1.8.7.4
    +ftp.heaven.af.mil:1.8.7.4

There are two reasons to use the add-host and add-alias programs instead of editing data manually. First, add-host will prevent you from accidentally reusing a previous computer name, or reusing a previous computer IP address. Second, if you want to protect data against a sudden power outage, you have to copy it to data.tmp, edit data.tmp, sync data.tmp to disk, and use mv to rename data.tmp as data; add-host and add-alias do all this automatically.

More on choosing names. You should end up running add-host exactly once for each IP address, giving a different computer name to each IP address. You should not run add-alias for a computer name; there should be exactly one IP address for the computer name.

Here are some good sources of computer names:

  • Animals: lion, tiger, bear, etc. But don't use these if you're a biologist studying animals! Computer names should be words that you don't normally use in other contexts.

  • Planets: mercury, venus, mars, etc. But don't use these if you're an astronomer!

  • Deities: zeus, athena, hermes, etc.

  • Elements: hydrogen, helium, lithium, etc.

  • Flowers: tulip, rose, lilac, etc.

If you add a second IP address to a computer, it's generally a good idea to use add-host with a new name, as if the second IP address were actually on a separate computer:

    ./add-host zebra.heaven.af.mil 1.8.7.240

Then you won't have to change anything if that IP address is, in fact, moved to a separate computer.

Checking addresses of your computers

Here is how to systematically verify that tinydns is publishing the right IP address for a name: for example, that it is publishing IP address 1.8.7.4 for www.heaven.af.mil.

First, check that the address is in /service/tinydns/root/data in tinydns-data format:

    +www.heaven.af.mil:1.8.7.4

IP addresses can be assigned by + lines, = lines, @ lines, . lines, and & lines.

Second, use tinydns-get to check that the address is in /service/tinydns/root/data.cdb:

    cd /service/tinydns/root
    tinydns-get a www.heaven.af.mil

The output will have a line saying

    answer: www.heaven.af.mil 86400 A 1.8.7.4

although perhaps with a number other than 86400. Common reasons that this answer is missing or obsolete: you didn't run make after changing data; you don't have . lines (or Z lines) in data specifying relevant name servers.

If you want to check reverse lookups, replace a www.heaven.af.mil with ptr 4.7.8.1.in-addr.arpa.

Third, check that the IP address of tinydns is one of this computer's addresses:

    cat /service/tinydns/env/IP
    netstat -n -i

Fourth, check that the tinydns service is up:

    svstat /service/tinydns

If tinydns-get reported more than 512 bytes, you also need TCP service; check that the axfrdns service is up.

Fifth, ask tinydns about the name:

    dnsq a www.heaven.af.mil 1.8.7.200
    dnsq a www.heaven.af.mil 1.8.7.201

Here 1.8.7.200 and 1.8.7.201 are the IP addresses of your DNS servers. The output of dnsq should be identical to the previous output of tinydns-get.

Sixth, ask your DNS cache for the address:

    dnsqr a www.heaven.af.mil

If dnscache can't find the address, the problem is almost certainly that the parent servers haven't delegated the relevant domains to your tinydns. Read the log in /service/dnscache/log/main/current to see which servers dnscache is contacting and what information they are providing. For a thorough debugging scan, use dnstrace.

Do not use nslookup to test your DNS servers.

Publishing mail server addresses

When an Internet mail transfer agent wants to deliver mail addressed to heaven.af.mil, it looks up the IP address of heaven.af.mil, and tries to connect to an SMTP server at that IP address. You can use add-mx to specify a different IP address:

    cd /service/tinydns/root
    ./add-mx heaven.af.mil 1.8.7.193
    make

(mx stands for ``mail exchanger.'') As an alternative to add-mx, you can edit data manually, adding the following line:

    @heaven.af.mil:1.8.7.193:a

If you add several mail servers for heaven.af.mil, use a for the first, b for the second, etc. add-mx handles this automatically.

Delegating names to another server

To delegate a name to a child server, run add-childns with the name being delegated and the IP address of the child server:

    cd /service/tinydns/root
    ./add-childns elysium.heaven.af.mil 1.2.3.144
    make

As an alternative to add-childns, you can edit data manually, adding the following line:

    &elysium.heaven.af.mil:1.2.3.144:a

If you delegate heaven.af.mil to several IP addresses, use a for the first, b for the second, etc. add-childns handles this automatically.

You can select a server name other than the default a.ns.elysium.heaven.af.mil. To avoid triggering a BIND bug, the parent server and the child server must use the same name for the child server. For example, if the child server is using

    .elysium.heaven.af.mil:1.2.3.144:dns1.elysium.heaven.af.mil

then the parent server must use the same name:

    &elysium.heaven.af.mil:1.2.3.144:dns1.elysium.heaven.af.mil

Omit the IP address if the name already has an IP address assigned in another data line:

    &elysium.heaven.af.mil::dns1.elysium.heaven.af.mil

Setting up independent DNS servers

You can run several servers (on different IP addresses) with different data files. For example, you could set up four servers, with two servers publishing heaven.af.mil information, and two servers publishing panic.mil information. Changes to heaven.af.mil would be made on the first server and copied to the second. Changes to panic.mil would be made on the third server and copied to the fourth. Of course, a single server can publish both heaven.af.mil and panic.mil. However, if you have a gigabyte of DNS data, you should consider running several independent servers, each with a fraction of the data.

Moving a zone to an independent DNS server

Here is how to move heaven.af.mil from two DNS servers on IP addresses 1.8.7.200 and 1.8.7.201 to two independent DNS servers on IP addresses 1.8.11.50 and 1.8.11.51.

Copy all the heaven.af.mil data from the old servers to the new servers.

[step]
On the new servers, change the IP address of a.ns.heaven.af.mil from 1.8.7.200 to 1.8.11.50, by changing

    .heaven.af.mil:1.8.7.200:a

to

    .heaven.af.mil:1.8.11.50:a

in /service/tinydns/root/data. Similarly, change the IP address of b.ns.heaven.af.mil from 1.8.7.201 to 1.8.11.51. Type

    make

so that the new servers start publishing the new IP addresses.

[step]
Make the same changes on the parent servers.

[step]
Make the same changes on the old servers. This is important because caches can continue talking to the old servers for any length of time; caches are under no obligation to double-check with the parent servers.

[step]
Wait a few days for caches to stop contacting the old servers. If you make any changes to the heaven.af.mil data during this time, make the same changes on the old servers.

[step]
Remove the heaven.af.mil data from the old servers. That's it.

How to create local DNS names

Here is how to configure your DNS cache to contact your DNS servers for information about particular names. This feature has two common uses:

  • Local names. For example, you can set up the name pop.3 in your DNS server, and tell your DNS cache to contact your DNS server for all .3 information. Clients using your DNS cache can see pop.3.

  • More reliable access to global names. For example, if www.x.org is published by your DNS servers, you can tell your DNS cache to contact your DNS servers for all .x.org information. Clients using your DNS cache can see www.x.org even if your connection to the Internet is down.

It isn't easy to choose a safe top-level local name. The global root operators add new top-level names every once in a while: for example, .info was added in 2001, so people using .info as a local name were unable to reach global .info sites. Software authors sometimes set aside top-level names; for example, I'm told that Mac OS 9 does something weird with .local, so it can't access local names in .local. Here are some reasonable choices of top-level local names:

     .0       (good for machine-specific names)
     .1
     .2
     .3       (good for department-specific names)
     .4
     .5
     .6       (good for corporation-specific names)
     .7
     .8
     .9
     .internal

For concreteness, these instructions assume that you're creating .internal, and that you have two computers running DNS servers, the first server on IP address 1.8.7.200 and the second server on IP address 1.8.7.201.

Tell your DNS servers that they should answer questions about .internal, and that they should announce 1.8.7.200 and 1.8.7.201 as the DNS server addresses for .internal:

    cd /service/tinydns/root
    ./add-ns internal 1.8.7.200
    ./add-ns internal 1.8.7.201
    make

[step]
Tell your DNS cache that it should contact your DNS servers for information about .internal:

    cd /service/dnscache
    echo 1.8.7.200 > root/servers/internal
    echo 1.8.7.201 >> root/servers/internal
    chmod 644 root/servers/internal
    svc -t .

The file root/servers/internal applies to the name internal and all names ending with .internal. However, if there is a more specific file such as root/servers/corp.internal listing another server, or if the .internal servers delegate corp.internal to another server, dnscache will contact the other server for information about corp.internal.

How to answer TCP queries

Here is how to configure your DNS server to answer TCP queries. Note that most DNS servers do not need to answer TCP queries.

These instructions assume that you are already running tinydns as a DNS server. If you followed the instructions for upgrading from BIND, you're already answering TCP queries, so you don't need to do anything.

As root, create UNIX accounts named Gaxfrdns and Gdnslog.

[step]
As root, create an /etc/axfrdns service directory, configured with the name of your existing tinydns service directory and the IP address of your DNS server:

axfrdns-conf Gaxfrdns Gdnslog /etc/axfrdns /etc/tinydns 1.8.7.200

[step]
As root, create /etc/axfrdns/tcp as follows:

echo ':allow,AXFR=""' > /etc/axfrdns/tcp

[step]
If you want to allow an IP address to transfer a zone from your DNS server, add it to /etc/axfrdns/tcp:

echo '131.193.178.160:allow,AXFR="heaven.af.mil"' >> /etc/axfrdns/tcp

Here 131.193.178.160 is the IP address, and heaven.af.mil is the zone to be transferred. You can list several zones separated by slashes:

echo '131.193.178.160:allow,AXFR="heaven.af.mil/panic.mil"' >> /etc/axfrdns/tcp

If you want to allow transfers of all zones, omit the ,AXFR="...":

        echo '131.193.178.160:allow' >> /etc/axfrdns/tcp

[step]
As root, compile /etc/axfrdns/tcp into a hashed database:

cd /etc/axfrdns
make

You will need to repeat this step if you change /etc/axfrdns/tcp.

[step]
As root, tell svscan about the new service, and use svstat to check that the service is up:

ln -s /etc/axfrdns /service
sleep 5
svstat /service/axfrdns

When are TCP queries sent?

If you're in one of the following situations, you need to configure your DNS server to answer TCP queries:

  • You want to publish record sets larger than 512 bytes. (This is almost always a mistake.)

  • You want to allow outgoing zone transfers, for example to a third-party server.

  • A parent server refuses to delegate a name to you until you set up TCP service.

If you aren't in any of those situations, you have no need to provide TCP service, and you should not set it up. DNS-over-TCP is much slower than DNS-over-UDP and is inherently much more vulnerable to denial-of-service attacks. (This applies to BIND too.)

What are zone transfers?

When you edit the host information on one of your DNS servers (the ``master'' or ``primary''), you have to copy it to the other DNS servers (the ``slaves'' or ``secondaries'').

There are several easy-to-use standard tools that copy files. The scp program, part of OpenSSH [www.openssh.com], provides secure, compressed file transfers. You can use rsync [rsync.samba.org] to perform incremental copies, which transmit only a small amount of data through the network for a small change to a large file.

Zone transfers are an archaic alternative mechanism for copying DNS information. Instead of immediately sending new data to the slaves, you run a zone-transfer service that accepts periodic connections from the slaves; your users complain while they're waiting for the slaves to check for new data. The zone-transfer protocol isn't a modular file-transfer system; it is an ad-hoc system tied to the details of DNS. The protocol has terrible compression and no security. Every new zone on the master requires manual reconfiguration of the slaves. Zone transfers lose all information about client differentiation and scheduled record changes.

Zone transfers have one redeeming feature: zone-transfer software is very widespread. You may be forced to use zone transfers if your slaves don't support anything better. (On the other hand, you could choose better slaves.)

There has been some work on improving the zone-transfer protocol: a NOTIFY mechanism that wakes up the slaves (after a delay, and without a failure notice when something goes wrong); an experimental IXFR mechanism for incremental zone transfers (although the BIND implementation doesn't work for zone files modified by hand or by external tools); and several proposed security mechanisms, notably TSIG. BIND's May 2001 IXFR and TSIG implementations are supposedly free of the bugs that caused crashes, data corruption, and root exploits in previous versions of BIND. The BIND company occasionally mumbles about imaginary tools to handle new zones and client differentiation. By combining all these tools, you can finally approach the functionality of a trivial rsync script. Wow.

How to balance load among many web servers

These instructions assume that you are already running tinydns, version 1.04 or later, as a DNS server. Suppose you have 50 identical www.heaven.af.mil web servers running on IP addresses 1.2.3.150, 1.2.3.151, and so on. You can simply list all their addresses in /service/tinydns/root/data:

    +www.heaven.af.mil:1.2.3.150
    +www.heaven.af.mil:1.2.3.151
    +www.heaven.af.mil:1.2.3.152
    # etc.

When a DNS cache asks for the IP address of www.heaven.af.mil, tinydns will automatically return a random set of 8 addresses.

If one of your web servers crashes, the effect on users will depend on how their browsers behave:

  • Silly behavior: I've heard rumors of obsolete browsers that give up after a single IP address.

  • Standard behavior: Most browsers move on to the next IP address after the first connection attempt times out. A server outage produces a long delay but not a failure.

  • Smart behavior: To reduce the delay, smart browsers try each address with a two-second timeout before retrying each address with a long timeout.

You can eliminate delays by removing IP addresses of web servers that have crashed. tinydns is designed to work with external programs that monitor the health of your servers. Specify each address with a 5-second TTL:

    +www.heaven.af.mil:1.2.3.150:5
    +www.heaven.af.mil:1.2.3.151:5
    +www.heaven.af.mil:1.2.3.152:5

An external program can remove an address by simply changing + to - on the relevant line, then running make. Later, when that server has recovered, the program can change - back to +.

How to set up a reverse DNS wall

Here is how to avoid publishing the names and IP addresses of your computers.

You could simply leave the relevant data out of DNS. Unfortunately, some silly Internet servers look up the computer name for each incoming IP address, and drop connections from any unlisted computer. A reverse DNS wall lets you connect to these servers: it creates an artificial computer name for every IP address.

These instructions assume that you have already installed daemontools and djbdns, and that svscan is already running.

As root, create UNIX accounts named Gwalldns and Gdnslog.

[step]
As root, create an /etc/walldns service directory configured with the IP address of the reverse DNS wall:

    walldns-conf Gwalldns Gdnslog /etc/walldns 1.8.7.205

The IP address must be configured on this computer. The IP address must not have a DNS cache, a DNS server, or any other port-53 service.

[step]
As root, tell svscan about the new service, and use svstat to check that the service is up:

    ln -s /etc/walldns /service
    sleep 5
    svstat /service/walldns

[step]
Arrange for the relevant in-addr.arpa names to be delegated to the reverse DNS wall. For example, tell the administrator of 8.1.in-addr.arpa to delegate 7.8.1.in-addr.arpa to the server 205.7.8.1.in-addr.arpa running on IP address 1.8.7.205.

How to receive a delegation from .com or .net or .org

Here is how to create a new second-level name under .com or .net or .org. These instructions assume that you are already running tinydns as a DNS server.

For concreteness, these instructions assume that you're creating x.org, and that you have two computers running DNS servers, the first server on IP address 1.8.7.200 and the second server on IP address 1.8.7.201.

Second-level names in .com etc. are not free. You will need to pay for the name. Current fees (October 2002) are around US$10/year, depending on which company you use to register the name. These instructions assume that you use Joker to register the name.

Tell your DNS servers that they should answer questions for x.org, and that they should announce 1.8.7.200 and 1.8.7.201 as the DNS server addresses for x.org:

    cd /service/tinydns/root
    ./add-ns x.org 1.8.7.200
    ./add-ns x.org 1.8.7.201
    make

[step]
Register your email address with Joker: on http://www.joker.com, type your email address under ``Register yourself'' and click Go. You will receive email confirmation from Joker showing you an account-activation URL. Visit that URL to receive your Joker password.

[step]
Log in to Joker using your email address and password, and go to the Joker Servicezone. Find Contacts and click on Create. Fill out the form to register your ``cno'' (com, net, org) contact information.

[step]
In the Servicezone, find Nameservers and click on Create. Fill out the form to register server name a.ns.x.org with IP address 1.8.7.200. Do it again to register server name b.ns.x.org with IP address 1.8.7.201. Make sure that you put the server names a.ns, b.ns, etc. in exactly the order of the add-ns commands.

(A big problem here has now been fixed. The problem was that Network Solutions, which manages .com etc., insisted on IP uniqueness: if anyone had already registered the same IP address for another server name, you wouldn't be allowed to use the IP address. However, company representative Matt Larson wrote the following on 4 April 2002:

The limitation of only one name server (i.e., A record) per IP address was an unfortunate Registry-based restriction that was removed on January 19 of this year. ... There were several reasons for relaxing this restriction, not the least of which was that there wasn't a good reason for it in the first place. An immediate positive benefit is that it's no longer possible for someone to hold a given IP address hostage by registering a name server at that address. Another problem with IP uniqueness is that it often forces glueless delegations, which slow down and sometimes destroy DNS lookups.)

[step]
On the Joker home page, click on Register Domains, and type in x.org. Follow the instructions to register and pay for x.org, using the DNS servers a.ns.x.org and b.ns.x.org, and using the contact information that you registered.

How to receive a delegation from .in-addr.arpa

If you are in charge of a block of IP addresses, and you want to provide reverse lookups for those IP addresses, you will need a corresponding name in the in-addr.arpa domain. For example, if you are in charge of IP addresses 1.8.7.0 through 1.8.7.255, the domain 7.8.1.in-addr.arpa should be delegated to you.

For concreteness, these instructions assume that the name is 7.8.1.in-addr.arpa, and that you have two computers running DNS servers, the first server on IP address 1.8.7.200 and the second server on IP address 1.8.7.201.

The normal procedure has two steps. First, tell your DNS servers that they should answer questions for 7.8.1.in-addr.arpa, and that they should announce 1.8.7.200 and 1.8.7.201 as the DNS server addresses for 7.8.1.in-addr.arpa:

    cd /service/tinydns/root
    ./add-ns 7.8.1.in-addr.arpa 1.8.7.200
    ./add-ns 7.8.1.in-addr.arpa 1.8.7.201
    make

Second, tell the parent server administrator to delegate 7.8.1.in-addr.arpa to the server a.ns.7.8.1.in-addr.arpa on IP address 1.8.7.200 and the server b.ns.7.8.1.in-addr.arpa on IP address 1.8.7.201. Fees for this delegation are typically included in the fees for allocating the IP addresses in the first place.

Unfortunately, some parent administrators impose extra restrictions that prevent the normal procedure from working. In particular, ARIN (IP addresses in America) and RIPE (IP addresses in Europe) both insist that all their delegations be glueless. This means that the DNS servers need names outside in-addr.arpa. Gluelessness is bad practice, because it slows down DNS lookups and sometimes destroys DNS lookups, but ARIN and RIPE don't care. (Reported May 2001.)

To deal with ARIN and RIPE, edit /service/tinydns/root/data manually to specify server names in some other domain that you control, let's say x.org:

    .7.8.1.in-addr.arpa:1.8.7.200:a.reversens.x.org
    .7.8.1.in-addr.arpa:1.8.7.201:b.reversens.x.org

Then tell the parent server administrator to delegate 7.8.1.in-addr.arpa to the server a.reversens.x.org on IP address 1.8.7.200 and the server b.reversens.x.org on IP address 1.8.7.201.

APNIC (IP addresses in Asia and Australia) doesn't insist on glueless delegations, but it does insist that you set up TCP service. (Reported June 2001.)

Reverse delegations for individual IP addresses

If you have are being given a block of fewer than 256 IP addresses, your parent server should delegate each address to you separately.

For example, let's say you want your DNS servers on 1.8.7.200 and 1.8.7.201 to publish computer names for the IP addresses 1.2.3.144 and 1.2.3.145. The administrator of 3.2.1.in-addr.arpa should do

    cd /service/tinydns/root
    ./add-childns 144.3.2.1.in-addr.arpa 1.8.7.200
    ./add-childns 144.3.2.1.in-addr.arpa 1.8.7.201
    ./add-childns 145.3.2.1.in-addr.arpa 1.8.7.200
    ./add-childns 145.3.2.1.in-addr.arpa 1.8.7.201
    make

and you should do

    cd /service/tinydns/root
    ./add-ns 144.3.2.1.in-addr.arpa 1.8.7.200
    ./add-ns 144.3.2.1.in-addr.arpa 1.8.7.201
    ./add-ns 145.3.2.1.in-addr.arpa 1.8.7.200
    ./add-ns 145.3.2.1.in-addr.arpa 1.8.7.201
    make

to create the lines

    .144.3.2.1.in-addr.arpa:1.8.7.200:a
    .144.3.2.1.in-addr.arpa:1.8.7.201:b
    .145.3.2.1.in-addr.arpa:1.8.7.200:a
    .145.3.2.1.in-addr.arpa:1.8.7.201:b

in /service/tinydns/root/data. Then the line

    =phoenix.elysium.heaven.af.mil:1.2.3.144

will declare that phoenix.elysium.heaven.af.mil has IP address 1.2.3.144 and that the computer name for 1.2.3.144 is phoenix.elysium.heaven.af.mil. Beware that some in-addr.arpa administrators instead do RFC 2317 ``classless'' reverse delegation, sending your reverse domains through a single delegation:

    C144.3.2.1.in-addr.arpa:144.144-145.3.2.1.in-addr.arpa
    C145.3.2.1.in-addr.arpa:145.144-145.3.2.1.in-addr.arpa
    &144-145.3.2.1.in-addr.arpa:1.8.7.200:a
    &144-145.3.2.1.in-addr.arpa:1.8.7.201:b
    # or, in BIND master zone-file format:
    # 144.3.2.1.in-addr.arpa. CNAME 144.144-145.3.2.1.in-addr.arpa.
    # 145.3.2.1.in-addr.arpa. CNAME 145.144-145.3.2.1.in-addr.arpa.
    # 144-145.3.2.1.in-addr.arpa. NS a.ns.144-145.3.2.1.in-addr.arpa.
    # 144-145.3.2.1.in-addr.arpa. NS b.ns.144-145.3.2.1.in-addr.arpa.
    # a.ns.144-145.3.2.1.in-addr.arpa. A 1.8.7.200
    # b.ns.144-145.3.2.1.in-addr.arpa. A 1.8.7.201

In this case your data file should contain lines such as

    .144-145.3.2.1.in-addr.arpa:1.8.7.200:a
    .144-145.3.2.1.in-addr.arpa:1.8.7.201:b
    =phoenix.elysium.heaven.af.mil:1.2.3.144
    ^144.144-145.3.2.1.in-addr.arpa:phoenix.elysium.heaven.af.mil
    =bogey.elysium.heaven.af.mil:1.2.3.145
    ^145.144-145.3.2.1.in-addr.arpa:bogey.elysium.heaven.af.mil

using the same name 144-145.3.2.1.in-addr.arpa selected by the parent administrator. Normally ^ lines are unnecessary, because they are automatically generated by = lines, but classless reverse delegation breaks this feature.

Why would anyone want to use classless reverse delegation? Answer: If you were running BIND, you'd find it only a little bit painful to receive a classless reverse delegation (setting up one zone file), while you'd find it much more painful to receive separate reverse delegations (setting up many zone files).

How to run a DNS server in place of an existing BIND server

Here is how to upgrade your DNS servers from BIND to tinydns. The data currently published through your BIND servers will be published through tinydns instead.

These instructions assume that you have already installed daemontools, ucspi-tcp, and djbdns; that svscan is already running; and that you have already stopped using BIND as a DNS cache.

These instructions assume that you have already installed ssh. These instructions can also take advantage of rsync, but rsync is not required.

For concreteness, these instructions assume that you have two BIND DNS servers: dns1.panic.mil on IP address 1.8.7.200, and dns2.panic.mil on IP address 1.8.7.201. You use these servers to publish panic.mil information.

These instructions assume for simplicity that you do not have any incoming zone transfers. All changes are made on dns1.panic.mil; you transfer zones from dns1.panic.mil to dns2.panic.mil, and perhaps to third-party servers, but you do not provide secondary service for zones whose primaries are at other sites.

On dns1, as root, create UNIX accounts named Gtinydns, Gaxfrdns, and Gdnslog. Repeat on dns2.

[step]
On dns1, as root, create service directories /etc/tinydns and /etc/axfrdns using the IP address of dns1.panic.mil:

     tinydns-conf Gtinydns Gdnslog /etc/tinydns 1.8.7.200
     axfrdns-conf Gaxfrdns Gdnslog /etc/axfrdns /etc/tinydns 1.8.7.200

Repeat on dns2 using the IP address of dns2.panic.mil.

[step]
On dns1, as root, create /etc/axfrdns/tcp to allow zone transfers from your network (1.8.7.*), to allow zone transfers from any authorized third-party servers (let's say 131.193.178.*), and to allow non-zone-transfer TCP connections from anywhere:

     1.8.7.:allow
     131.193.178.:allow
     :allow,AXFR=""

Compile tcp into a hashed database:

     cd /etc/axfrdns
     make

Repeat on dns2.

[step]
On dns1, as root, edit /etc/tinydns/root/Makefile to replicate /etc/tinydns/root/data from dns1 to dns2:

     remote: data.cdb
             rsync -az -e ssh data.cdb 1.8.7.201:/etc/tinydns/root/data.cdb

     data.cdb: data
             /usr/local/bin/tinydns-data

Alternatively, if you don't have rsync:

     remote: data.cdb
             scp data.cdb 1.8.7.201:/etc/tinydns/root/data.cdb.tmp
             ssh 1.8.7.201 mv /etc/tinydns/root/data.cdb.tmp              /etc/tinydns/root/data.cdb

     data.cdb: data
             /usr/local/bin/tinydns-data

[step]
On dns2, as root, edit /etc/tinydns/root/data to remind yourself that DNS data is replicated from dns1 to dns2:

     # Do not edit data on dns2! data.cdb is copied from dns1.
     # The following line protects data.cdb by stopping make.
     9

[step]
On dns1, as root, transfer the panic.mil zone from BIND:

     cd /etc/tinydns/root
     tcpclient dns1.panic.mil 53 axfr-get panic.mil zone-panic zone-panic.tmp

Do the same for all your other zones: for example,

     tcpclient dns1.panic.mil 53 axfr-get 8.1.in-addr.arpa zone-8 zone-8.tmp

Merge the zones into a data file, and compile the data file into a hashed database for tinydns:

     sort -u zone* > data
     make

[step]
On dns1, check whether tinydns has the same data that BIND is providing:

     cd /etc/tinydns/root
     tinydns-get a www.panic.mil
     dnsq a www.panic.mil dns1.panic.mil

Replace www.panic.mil with various names in your BIND zone files, and replace a with mx and other types in your BIND zone files. You may see some minor differences between the behavior of tinydns, as shown in the tinydns-get output, and the behavior of BIND, as shown in the dnsq output. Don't worry about the following differences: BIND repeating answer lines as additional lines when tinydns doesn't; BIND and tinydns putting lines in a different order.

[step]
On dns1, as root, find and kill the BIND process. Then tell svscan about the new services:

     ln -s /etc/tinydns /etc/axfrdns /service

The services will start within five seconds. You don't have to rush; caches will talk to dns2 when dns1 isn't responding.

[step]
Check whether tinydns on dns1 is responding with the same data as BIND on dns2:

     dnsq a www.panic.mil dns1.panic.mil
     dnsq a www.panic.mil dns2.panic.mil

As in step 7, try various names.

[step]
On dns1, as root, make sure that BIND won't be restarted after reboot. For example, under FreeBSD, simply add named_enable=NO to /etc/rc.conf.

[step]
Repeat steps 8 and 10 on dns2.

[step]
Set up a public web page saying that your DNS servers are powered by djbdns, so that a Google search for powered djbdns will find your page in a few months. These public statements will encourage other people to deploy djbdns, provide djbdns support services, and develop djbdns-related tools. Please also consider making a donation to the Bernstein Writing Fund.

Congratulations! You have escaped your BINDs.

Administration

After you make changes to data, type make to tell tinydns to publish the new information. If there's a syntax error, make will print a message on your screen, and tinydns will continue using the old information. You can maintain data the same way you maintained your BIND zone files. Each line produced by axfr-get (except for the initial # ... auto axfr-get line, which you can remove) corresponds to a line in a BIND zone file:

     # panic.mil. 3600 IN SOA dns1.panic.mil. hostmaster.panic.mil. 10455 7200 3600 604800 3600
     Zpanic.mil:dns1.panic.mil.:hostmaster.panic.mil.:10455:7200:3600:604800:3600:3600
     # panic.mil. 86400 IN NS dns1.panic.mil.
     &panic.mil::dns1.panic.mil.:86400
     # panic.mil. 86400 IN MX 0 mail.panic.mil.
     @panic.mil::mail.panic.mil.:0:86400
     # www.panic.mil. 86400 IN A 1.8.7.99
     +www.panic.mil:1.8.7.99:86400
     # 99.7.8.1.in-addr.arpa. 86400 IN PTR www.panic.mil.
     ^99.7.8.1.in-addr.arpa:www.panic.mil.:86400

However, you can make your data much more concise and easier to manage by taking advantage of more features of tinydns-data, as described below.

Automatic serial numbers. With BIND-style administration, you have to increase the serial number in your Z line, 10455 in the above example, every time you change another line. (You don't have to worry about this if you aren't transferring zones to third-party servers; server replication through rsync to dns2.panic.mil doesn't rely on serial numbers.)

You can instead replace :10455: by :: and let tinydns-data generate a serial number from the modification time of the data file. WARNING: If your serial number is around 2000000000, you'll have to set it to 4000000000, and wait for your secondary servers to get the new zone, before you switch to the tinydns-data serial number. See RFC 2182, section 7, for further discussion of this silly procedure. (You don't have to worry about this if your secondary servers are using axfr-get for zone transfers.)

Automatic TTLs. You can remove the time-to-live field at the end of each line: e.g., +www.panic.mil:1.8.7.99: instead of +www.panic.mil:1.8.7.99:86400. tinydns-data will generate sensible TTLs for you.

Automatic colons. You can remove any colon at the end of a line: e.g., +www.panic.mil:1.8.7.99 instead of +www.panic.mil:1.8.7.99:.

Combined A and PTR records. You can merge +www.panic.mil:1.8.7.99 and ^99.7.8.1.in-addr.arpa:www.panic.mil. into =www.panic.mil:1.8.7.99. This also tells add-host to avoid reusing that host name or IP address.

Combined MX and A records. You can merge @panic.mil::mail.panic.mil.:0 and +mail.panic.mil:1.8.7.88 into @panic.mil:1.8.7.88:mail.panic.mil.:0.

Automatic MX preferences. You can omit MX preferences of 0: e.g., @panic.mil:1.8.7.88:mail.panic.mil. instead of @panic.mil:1.8.7.88:mail.panic.mil.:0.

Automatic final dots. mail.panic.mil and mail.panic.mil. are equivalent: e.g., @panic.mil:1.8.7.88:mail.panic.mil instead of @panic.mil:1.8.7.88:mail.panic.mil.. The final dot doesn't matter in any name that has a dot in the middle. A name without any dots, such as z, will be interpreted as z.mx.panic.mil in this context.

Combined NS and A records. You can merge &panic.mil::dns2.panic.mil and +dns2.panic.mil:1.8.7.55 into &panic.mil:1.8.7.55:dns2.panic.mil.

Automatic SOA timers. In your Z line you can replace the timers by blanks: e.g., Zpanic.mil:dns1.panic.mil:hostmaster.panic.mil instead of Zpanic.mil:dns1.panic.mil:hostmaster.panic.mil::7200:3600:604800:3600. tinydns-data will choose sensible timers for you.

More automatic SOA information. A simple Zpanic.mil means Zpanic.mil:a.ns.panic.mil:hostmaster.panic.mil. It isn't worth changing the server names for existing zones, but you can take advantage of the abbreviation for new zones.

Combined SOA, NS, and A records. You can merge Zpanic.mil and &panic.mil:1.8.7.55:dns2.panic.mil into .panic.mil:1.8.7.55:dns2.panic.mil.

How to run an external cache in place of an existing BIND cache, strategy 1

These instructions assume that your network already has a computer using BIND to find addresses of Internet hosts (BIND as a ``DNS cache'') and to publish addresses of your own hosts (BIND as a ``DNS server''). Here is how to use dnscache instead of BIND to find addresses of Internet hosts.

These instructions assume that you can easily change /etc/resolv.conf on all your client machines. If you can't, use strategy 2 or strategy 3 instead.

For concreteness, let's say you have four servers, and any number of client computers:

Name	IP address	Currently running	The plan
wobbly	1.8.7.33	BIND cache+server	BIND server
shaky	1.8.7.55	BIND cache+server	BIND server
lion	1.8.7.91	nothing	dnscache
tiger	1.8.7.92	nothing	dnscache

All your computers have nameserver 1.8.7.33 and nameserver 1.8.7.55 in /etc/resolv.conf.

These instructions assume that you have already installed daemontools and djbdns, and that svscan is already running, on both lion and tiger.

On lion, as root, create UNIX accounts named Gdnscache and Gdnslog. Repeat on tiger.

[step]
On lion, as root, create an /etc/dnscache service directory for IP address 1.8.7.91, and tell svscan about the new service:

     dnscache-conf Gdnscache Gdnslog /etc/dnscache 1.8.7.91
     ln -s /etc/dnscache /service/dnscache

Repeat on tiger with the IP address 1.8.7.92.

[step]
On lion, as root, create entries in /etc/dnscache/root/ip showing which client IP addresses are authorized to use this cache. For example,

     touch /etc/dnscache/root/ip/1.8.7

authorizes all clients with IP address 1.8.7.* to use this cache. You can add or remove addresses later. Repeat on tiger.

[step]
On one of your client computers, as root, put

     nameserver 1.8.7.91
     nameserver 1.8.7.92

into /etc/resolv.conf, replacing the previous nameserver lines.

[step]
Check whether that computer can look up addresses of some Internet hosts:

     dnsip www.cnn.com
     dnsip www.fsf.org

Then try surfing the web. If you want to see what dnscache is doing behind the scenes, read /service/dnscache/log/main/current on lion and tiger.

[step]
Repeat steps 4 and 5 on your other client computers.

[step]
Optionally, disable BIND's caching features: On wobbly and shaky, as root, put

     options {
       recursion no;
       fetch-glue no;
     };

into named.conf, and restart BIND. You can skip this step if you're going to eliminate BIND anyway, switching to tinydns to publish information about your own hosts.

How to run an external cache in place of an existing BIND cache, strategy 2

These instructions assume that your network already has a computer using BIND to find addresses of Internet hosts (BIND as a ``DNS cache'') and to publish addresses of your own hosts (BIND as a ``DNS server''). Here is how to use dnscache instead of BIND to find addresses of Internet hosts.

If you have taken the recommended approach of having different computers (or at least different IP addresses) for your DNS caches (listed in /etc/resolv.conf) and your DNS servers (listed in NS records), use strategy 3 instead. Strategy 3 is simpler than strategy 2.

If you can easily change /etc/resolv.conf on all your client machines, use strategy 1 instead. Strategy 2 is more complicated but avoids changing /etc/resolv.conf. If you're an ISP and you've given your cache IP address to thousands of client computers, use strategy 2.

Separating DNS service from DNS caching

For concreteness, let's say you're running BIND on two computers, dns1.panic.mil and dns2.panic.mil, with IP addresses 1.8.7.33 and 1.8.7.55. These computers have two functions:

  • They are DNS servers, publishing information about your own hosts. You are editing that information on dns1.panic.mil; dns2.panic.mil is using zone transfers to copy the information from 1.8.7.33.

  • They are DNS caches, finding addresses of other Internet hosts. Your client computers have nameserver 1.8.7.33 and nameserver 1.8.7.55 in /etc/resolv.conf.

Before you upgrade from BIND, you will have to put these two different functions on different IP addresses, as explained here.

Allocate two new public IP addresses in your network, let's say 1.8.7.91 and 1.8.7.92.

[step]
On dns1.panic.mil, as root: Set up 1.8.7.91 as an IP alias. Restart BIND.

[step]
On dns2.panic.mil, as root: Set up 1.8.7.92 as an IP alias. Change 1.8.7.33 to 1.8.7.91 in the masters lines in named.conf. Restart BIND.

[step]
On dns1.panic.mil, as root: In your BIND zone files, change the IP address of dns1.panic.mil from 1.8.7.33 to 1.8.7.91, create a new dnscache1.panic.mil name with IP address 1.8.7.33, change the IP address of dns2.panic.mil from 1.8.7.55 to 1.8.7.92, and create a new dnscache2.panic.mil name with IP address 1.8.7.55. Tell BIND to read the new zone files.

[step]
Contact the .mil parent server to make the same changes in the IP addresses of dns1.panic.mil and dns2.panic.mil.

[step]
If you have other NS names pointing to BIND (for example, if dns1.panic.mil is also known as dns1.panic.edu), repeat steps 4 and 5 for those names.

[step]
Wait a few days for the modified DNS records to spread through the Internet.

Upgrading the cache

Here's the current situation:

  • You have one computer with IP addresses 1.8.7.33 (dnscache1.panic.mil) and 1.8.7.91 (dns1.panic.mil), and another computer with IP addresses 1.8.7.55 (dnscache2.panic.mil) and 1.8.7.92 (dns2.panic.mil).

  • You have DNS servers running on 1.8.7.91 and 1.8.7.92. Computers around the Internet are contacting 1.8.7.91 and 1.8.7.92 for the addresses of your hosts.

  • You have DNS caches running on 1.8.7.33 and 1.8.7.55. Your clients are contacting 1.8.7.33 and 1.8.7.55 for the addresses of Internet hosts.

  • You can now follow the strategy 3 instructions. Those instructions will switch the DNS-cache software from BIND to dnscache, leaving BIND in place as the DNS-server software.

How to run an external cache in place of an existing BIND cache, strategy 3

These instructions assume that your network already has a computer using BIND as a DNS cache, i.e., using BIND to find addresses of Internet hosts. Here is how to use dnscache instead of BIND to find addresses of Internet hosts.

These instructions also assume that you have taken the recommended approach of using different IP addresses for DNS caches (listed in /etc/resolv.conf) and DNS servers (listed in NS records). Otherwise you will have to use strategy 1 or strategy 2. Strategy 3 is simpler than strategy 2, and it avoids the strategy 1 requirement to change /etc/resolv.conf.

For concreteness, let's say you have BIND caches running on two computers: dnscache1.panic.mil with IP address 1.8.7.33, and dnscache2.panic.mil with IP address 1.8.7.55. Your client computers have nameserver 1.8.7.33 and nameserver 1.8.7.55 in /etc/resolv.conf.

These instructions assume that you have already installed daemontools and djbdns, and that svscan is already running, on both computers.

On the first computer, as root, create UNIX accounts named Gdnscache and Gdnslog.

[step]
On the first computer, as root, create an /etc/dnscache service directory for IP address 1.8.7.33:

     dnscache-conf Gdnscache Gdnslog /etc/dnscache 1.8.7.33

[step]
On the first computer, as root, create entries in /etc/dnscache/root/ip showing which client IP addresses are authorized to use this cache. For example,

     touch /etc/dnscache/root/ip/1.8.7

authorizes all clients with IP address 1.8.7.* to use this cache.

[step]
On the first computer, as root, put

     options {
       interface-interval 0;
       listen-on { 1.8.7.91 };
     };

into named.conf. This tells BIND to stop listening on the 1.8.7.33 address.

[step]
On the first computer, as root, restart BIND. At this point there is no cache running on the first computer; your clients are relying on the second computer.

[step]
On the first computer, as root, tell svscan about the new caching service:

     ln -s /etc/dnscache /service/dnscache

dnscache will start running on the first computer within five seconds.

[step]
Check whether you can look up addresses of some Internet hosts through the new cache:

     env DNSCACHEIP=1.8.7.33 dnsip www.cnn.com
     env DNSCACHEIP=1.8.7.33 dnsip www.fsf.org

Then try surfing the web from your client computers. If you want to see what dnscache is doing behind the scenes, read /service/dnscache/log/main/current.

[step]
Repeat steps 1 through 7 on the second computer, using 1.8.7.55 instead of 1.8.7.33, and using 1.8.7.92 instead of 1.8.7.91.

The importance of separating DNS caches from DNS servers

DNS caches should always have separate IP addresses from DNS servers. In other words, the IP addresses listed in /etc/resolv.conf should never match any IP addresses listed in NS records.

This separation is widely recognized as the right way to run DNS. As stated in the ``DNS and BIND'' book, third edition, ``Securing Your Name Server,'' page 255:

Some of your name servers answer nonrecursive queries from other name servers on the Internet, because your name servers appear in NS records delegating your zones to them. ... You should make sure that these servers don't receive any recursive queries (that is, you don't have any resolvers configured to use these servers, and no name servers use them as forwarders).

BIND promoter Brad Knowles, who is usually willing to say anything to try to scare people away from djbdns, admitted in slide 45 of a 2002.11 presentation that servers should be separated from caches:

Split functions onto separate machines or IP addresses. Authoritative servers should be authoritative-only. ... Recursive/caching servers should not be authoritative.

The BIND company (which has always separated its own f.root-servers.net server from its caches) issued a statement in 2002.12 saying the same thing:

Although BIND can provide both functions (authoritative and non-authoritative) in single instance, ISC recommends always separating these two functions. In other words, you should run one server for your authoritative zones, and another that caches non-authoritative data.

If you've made the mistake of setting up a BIND site with a cache and a server on the same IP address, fix it! Step-by-step instructions for this fix are included in the djbdns upgrade instructions. You should correct the mistake even if you aren't upgrading.

Unfortunately, the idea of combining a cache with a server hasn't been stamped out yet. Brad Knowles, in slide 74 of the same presentation, listed as a ``djbdns Con'' the fact that dnscache and tinydns are separate programs that cannot run on the same IP address. The BIND company's software-installation instructions continue to fool unsuspecting users into putting a cache and a server on the same IP address.

The rest of this page explains several reasons that it's important to separate caches from servers.

Security and reliability

Suppose an attacker seizes control of your DNS cache. If that same program is also running your DNS server, the attacker can control not only your incoming DNS data, but also your outgoing DNS data. The attacker can misdirect not only your site's outgoing web connections, but also your site's incoming web connections.

As another example, suppose that a local user floods your DNS cache with more work than it can handle. If that same program is also running your DNS server, the flood will disrupt not only your site's outgoing web connections, but also your site's incoming web connections.

By separating DNS caches from DNS servers, you protect your DNS servers from DNS cache problems, and vice versa.

This is why RFC 2010 and RFC 2870 tell root server operators to use separate caches, and why the ``DNS and BIND'' book tells all server operators to use separate caches. In the words of the book, this separation ``eliminates a major vector of attack.''

Modularity

Most DNS cache programs do only one thing: retrieve DNS data. They don't publish data. By separating DNS caches from DNS servers, you allow yourself to easily replace your DNS cache software without any effect on your DNS servers. (Analogy: you can upgrade from Squid to another HTTP cache without any effect on Apache.)

Similarly, most DNS server programs do only one thing: publish DNS data. They aren't caches. By separating DNS caches from DNS servers, you allow yourself to easily replace your DNS server software without any effect on your DNS caches. (Analogy: you can upgrade from Apache to another HTTP server without any effect on Squid.)

In short, the separation gives you extra flexibility in choosing software. You aren't tied to monolithic server+cache programs. Look at the picture in RFC 1035, page 6: you can choose different software for the ``user program'' (client), the ``resolver'' (cache), and the ``name server'' (server).

This extra flexibility allows easier competition among DNS implementations. It makes new DNS servers much easier to write, because server implementors don't have to worry about all the complications of caching. Similarly, it makes new DNS caches easier to write.

This competition means that the software evolves more quickly. It keeps implementors on their toes. In the long term, everybody benefits from modularity, flexibility, competition, and evolution; you should support modularity even if you're satisfied with a monolithic server+cache program right now.

See Also

resolver(3) curvedns(8), curvedns-conf(8), dnscache(8), dnscache-conf(8), axfrdns(8), axfrdns-conf(8), axfrdns-get(8) tinydns(8), tinydns-data(8), tinydns-edit(8), tinydns-get(1), tinydns-data(8), tinydns-sign(8), cdb(3), dnsfilter(1), dnsip(1), dnsipq(1), dnsname(1), dnsnamex(1), dnsmx(1), dnstxt(1), dnsqr(1), dnsq(1), dnstrace(1), dnstracesort(1), dq(1) dqcache(8) dqcache-conf(8) dqcache-makekey(1) pickdns(8), pickdns-conf(8), pickdns-data(8), rbldns(8), rbldns-conf(8), rbldns-data(8), walldns(8), walldns-conf(8), qualifications(5)

Clone this wiki locally