paulgorman.org/technical

Authoritative DNS in General (and with an example with NSD in an Alpine Linux LXC container)

(February 2017)

Whereas a resolving nameserver, like Unbound, queries other nameservers to construct answers for clients, an authoritative nameserver maintains the official records for a zone (e.g. “com.”, “example.com.”). NSD is an authoritative nameserver.

$ dig columbia.edu NAPTR
;; ANSWER SECTION:
columbia.edu.           3600    IN      NAPTR   1 0 "s" "SIP+D2U" "" _sip._udp.columbia.edu.

$ dig _sip._udp.columbia.edu SRV
;; ANSWER SECTION:
_sip._udp.columbia.edu. 3600    IN      SRV     10 10 5060 lily.cc.columbia.edu.
_sip._udp.columbia.edu. 3600    IN      SRV     20 10 5060 laurel.cc.columbia.edu.

Forward dns maps names to IP addresses. Reverse dns maps IP addresses to names. If we’re not responsible for the IP range (e.g. we’re hosted on AWS), we don’t need a reverse zone file; our hosting company takes care of that.

The SOA (Start Of Authority) record defines default values for the zone.

Set up an NSD server

# lxc-create -n alpine-ns1 -t alpine -- -r v3.5
# lxc-start -n alpine-ns1
# lxc-attach -n alpine-ns1

# cat << EOF > /root/.profile
# When using lxc-attach, do "su -" to trigger a login shell that runs .profile.
export PS1='--- \h \w \\$ '
export PAGER='less'
alias l='ls'
alias ll='ls -lah'
alias la='ls -a'
EOF
	# apk update
	# apk upgrade
	# apk add nsd man nsd-doc tzdata s6 drill
	# cp /usr/share/zoneinfo/America/Detroit /etc/localtime
	# echo 'America/Detroit' > /etc/timezone
	# apk del tzdata
	# rc-update add s6-svscan boot
	# rc-update add nsd boot
	# cat << 'EOF' >> /etc/hosts
10.100.0.20  alpine-ns1.example.net  ns1
EOF

# cat << 'EOF' > /etc/hostname
alpine-ns1
EOF

# cat << 'EOF' > /etc/nsd/nsd.conf
server:
	ip-address: 10.100.0.20
	hide-version: yes
zone:
	name: example.net
	zonefile: example.net.zone
zone:
	name: 0.100.10.example.net
	zonefile: 0.100.10.example.net.zone
EOF

# cat << 'EOF' > /etc/nsd/example.net.zone
$ORIGIN example.net.
$TTL 86400
;
@ IN SOA ns1.example.net. hostmaster.example.net. (
20170130    ; Serial number we MUST increment each time we change the zone file
28800       ; Wait between refresh attempts by secondary
14400       ; Wait to retry failed zone refresh by secondary
604800      ; Expiration of secondary authority after contact lost with primary
14400       ; How long clients cache NEGATIVE results
)
;
@    NS    ns1.example.net.
@    MX    10    mail.example.net.
@    NAPTR    10    100    "s"    "SIP+D2U"    ""    _sip._udp.example.net.
@    NAPTR    10    100    "s"    "SIP+D2T"    ""    _sip._tcp.example.net.
;
ns1    IN    A    10.100.0.20
mail   IN    A    10.100.0.2
bag    IN    A    10.100.0.20
gab    IN    A    10.100.0.99
;
_sip._udp    SRV    10    100    5060    bag.example.net.
_sip._udp    SRV    20    100    5060    gab.example.net.
_sip._tcp    SRV    10    100    5061    gab.example.net.
_sip._tcp    SRV    20    100    5061    gab.example.net.
EOF

# lsof -i :53

Using nsd

Nsd compiles zone info into a binary the database /var/db/nsd/nsd.db. In old versions of nsd it was necessary to run nsdc rebuild after changing a zone file; nsd 4+ makes this unnecessary.

See the man pages nsd(8), nsd.conf(5), nsd-checkconf(8), nsd-control(8), and nsd-checkzone(8).

$ nsd-checkconf /etc/nsd/nsd.conf

Anatomy of a Zone File

Lines like $TTL 3600 and $INCLUDE /foo/example.org.zone are directives that usually appear at the head of a zone file. The @ symbol in zonefiles is a placeholder for the zone root, which is usually the most recent $ORIGIN directive in the zonefile.

TTL is the number of seconds a client should consider a name record valid, and after which the client should check again.

Any text on a line following a semi-colon is treated as a comment.

Zonefiles contain several types of resource records.

@  IN  SOA  primary-name-server hostmaster-email (
	   serial-number    ; A numerical value incremented whenever the zone file is altered that tells the nameserver to reload the zone
	   time-to-refresh  ; How long secondary nameservers wait between asking the primary for a refresh
	   time-to-retry    ; How long a secondary nameserver waits before trying another refresh request after the first request went unanswered.
	   time-to-expire   ; How long after a secondary nameserver looses contact with the primary before it no longer claims authority.
	   minimum-TTL )    ; How long other nameservers should cache NEGATIVE answers from this zone (max 3H). NB: This is NOT the default TTL for records from the zone; use the $TTL directive for that.

east IN  A  192.168.200.2
www  IN  CNAME  east.example.com.
example.com. IN  MX  10  mail-alpha.example.com.
@    IN  MX  20  mail-bravo.example.com.
	 IN  NS  ns-1.example.com.
	 IN  NS  ns-2.example.com.

(In the final two records above, the $ORIGIN is implicit in the first column. The final four records are functionally equivalent.)

https://lists.isc.org/pipermail/bind-users/2000-September/019170.html Regarding a widespread misunderstanding of minimum-TTL in SOA records:

RFC 2308 clarified that the last field of the SOA record is the Negative Caching TTL, not the default or minimum TTL. That’s why BIND 9 requires the presence of a $TTL directive (also specified in RFC 2308), or an explicit TTL on the first record in the zone file; otherwise it doesn’t know what TTL to use for the record(s).

FAILING TO INCREMENT THE SERIAL NUMBER after editing a zone file leads to ZONE UPDATE PROBLEMS. The serial number can be any unique value. Using YYYMMDDv is common, where “v” is a version number in case of multiple update in one day.

Note the final dot on the end of some names. If there’s a dot at the end of a name in a resource record or directive, the name is qualified. If it’s the whole name, including the hostname, it’s fully qualified. If qualified, the nameserver uses the name unchanged. If there’s no dot at the end of a name, the nameserver considers it unqualified, and appends the value of the most recent $ORIGIN directive.

A reverse name resolution zone file for 10.0.1.0 looks like:

$ORIGIN 1.0.10.in-addr.arpa.
$TTL 3600
@  IN  SOA  dns1.example.com.  hostmaster.example.com. (
	20170130    ; Serial number we MUST increment each time we change the zone file
	28800       ; Wait between refresh attempts by secondary
	14400       ; Wait to retry failed zone refresh by secondary
	604800      ; Expiration of secondary authority after contact lost with primary
	14400       ; How long clients cache NEGATIVE results
)
;
@  IN  NS   dns1.example.com.
;
1  IN  PTR  dns1.example.com.
2  IN  PTR  dns2.example.com.

It’s safest to use fully-qualified names in reverse zone files for the non-reversed names.

Primary/Master and Secondaries/Slaves

Run at two (or more) authoritative nameservers to avoid unnecessary outages. One nameserver acts as the primary authority. One or more other nameservers act as secondaries. A secondary requests regular zone updates from the primary nameserver.

/etc/nsd/nsd.conf on the primary server:

server:
	hide-version: yes
key:
	name: "mykey"
	algorithm: hmac-sha256
	secret: "+a4BkO0Vu69C+Q9bEzMy3TIZVLH+fgT=8"
pattern:
	name: tosecondary
	notify: 10.100.0.99 mykey
	provide-xfr: 10.100.0.99 mykey
zone:
	name: example.net
	zonefile: example.net.zone
	include-pattern: tosecondary
zone:
	name: 0.100.10.example.net
	zonefile: 0.100.10.example.net.zone
	include-pattern: tosecondary

/etc/nsd/nsd.conf on the secondary server:

server:
	hide-version: yes
key:
	name: "mykey"
	algorithm: hmac-sha256
	secret: "+a4BkO0Vu69C+Q9bEzMy3TIZVLH+fgT=8"
pattern:
	name: fromprimary
	notify: 10.100.0.99 mykey
	provide-xfr: 10.100.0.99 mykey
zone:
	name: example.net
	zonefile: example.net.zone
	include-pattern: fromprimary
zone:
	name: 0.100.10.example.net
	zonefile: 0.100.10.example.net.zone
	include-pattern: fromprimary

Glue Records and Registrars

When we delegate a domain like “example.com” from the “com” TLD, we must tell “com” which nameservers are authoritative for “example.com”. If the nameservers are part of the domain (e.g. “ns2.example.com”), we must also provide “com” with a glue record linking the each nameserver with an IP address (i.e. create an A record for the nameservers on “com”). We create these glue records through the domain name registrar.

TTL Values

TTL values are a balance between concerns:

A recent analysis of records at 500 popular domains found a mean TTL of 7200 (two hours) and a median TTL of 300 (five minutes); the maximum TTL found was ninety days, the minimum was one second.

So, maybe:

The SOA time-to-expire might well be set to two weeks or more.

Zone files traditionally specify TTL values in seconds, but contemporary nameservers also support minutes (M), hours (H), days (D), and weeks (W).

Seconds      60  1800  3600  86400  604800
Other Units  1M   30M    1H     1D      1W

Security of zone transfers between primary and secondary

TSIG (Transaction SIGnature, defined in RFC 2845) uses shared secret keys and one-way hashing to provide a cryptographically secure means of authenticating updates to a DNS database (i.e. zone transfers).

Generate a secret:

$ dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64

An algorithm may be specified for the TSIG key. By default, it uses hmac-sha256.

The /etc/nsd/nsd.conf on the primary (10.0.1.10):

server:
	hide-version: yes
key:
	name: "example.net-tsig"
	secret: j53z1gs4nCH7P+/ab3JZkqB9HKVg9CDQPhaE2JzDEWo=
zone:
	name: example.net
	zonefile: example.net.zone
	notify: 10.0.2.20 example.net-tsig
	provide-xfr: 10.0.2.20 example.net-tsig

The /etc/nsd/nsd.conf on the secondary (10.0.2.20):

server:
	hide-version: yes
key:
	name: "example.net-tsig"
	secret: j53z1gs4nCH7P+/ab3JZkqB9HKVg9CDQPhaE2JzDEWo=
zone:
	name: example.net
	zonefile: example.net.zone
	allow-notify: 10.0.1.10 example.net-tsig
	request-xfr: 10.0.1.10 example.net-tsig

SRV records

A SRV record lets DNS return information about services, as defined in RFC 2782. Newer clients of services like SIP and XMPP make significant use of SRV records. SRV records take the form:

 _service._protocol.domain  TTL   class SRV  priority  weight  port  target
 _sip._udp.example.com.     300   IN    SRV  10        100     5060  sipserver.example.com.

nslookup, dig, drill

Some platforms switched from the Bind-based dnsutils package to the ldnsutils package. drill replaces dig, and accepts most of the same arguments. nslookup is inferior to dig and drill.