NSD and OpenDNSSEC under FreeBSD 10 [Part 2: NSD]

This is the second part in the series of articles explaining how to run NSD and OpenDNSSEC under FreeBSD 10.

Today, we’re going to deploy NS-FEED, NS-3 and NS-4 dealing with plain zones only. We’re not going to sign anything yet — we’ll deploy NS-FEED as a hidden master, configure it to feed NS-3 and NS-4 and configure NS-3/NS-4 to be masters for the ISP slave. This is probably the easiest part since configuration of NSD is quite easy.

For the sake of simplicity, let’s assume we’re going to host a zone called plain.org.

Let’s start with the installation of required software. Repeat the procedure below on all three servers:

  1. % cd /usr/ports/dns/nsd && make install clean

You’ll be prompted to configure additional options to compile NSD with: since I’m not planning to use IPv6 I uncheck it and check BIND8_STATS and CHECKING. BIND8_STATS is useful for statistical purposes (nsd-control stat).

  1. % cd /usr/ports/dns/bind-tools && make install clean

Installing bind-tools has nothing to do with NSD and could be omitted. I just like having dig present in the system for troubleshooting reasons. bind-tools will also install dnssec-keygen which will be later used to generate TSIG keys, however they could be generated using various methods.

Let’s create directories and fix permissions:

  1. % mkdir -p /usr/local/etc/nsd/var/db/nsd
  2. % mkdir -p /usr/local/etc/nsd/var/run/nsd
  3. % mkdir /usr/local/etc/nsd/var/log
  4. % mkdir /usr/local/etc/nsd/zones
  5.  
  6. % chown -R bind:bind /usr/local/etc/nsd/var

[20140909] : starting from version 4.1.0 NSD port in FreeBSD will create nsd user, hence bind is no longer needed:

  1. % chown -R nsd:nsd /usr/local/etc/nsd/var

Modify /etc/rc.conf to start NSD at boot:

  1. # enable nsd
  2. nsd_enable="YES"

The following steps should be followed from our hidden master NS-FEED:

We’re going to generate a TSIG key which will be used for secure zone transfers between NS-FEED and NS-3/4. TSIG or Transactional Signature is a mechanism to secure DNS messages (for example NOTIFY) and to enable secure server communication (for example zone transfer between master and slave):

  1. % cd /usr/local/etc/nsd
  2.  
  3. % dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST ns-feed-plain

I used ns-feed-plain as a hostname to separate the TSIG that will be used for plain zones from the TSIG that will be used for signed zones. The output of dnssec-keygen will be two files:

  1. Kns-feed-plain.+163+26684.key
  2. Kns-feed-plain.+163+26684.private

Take a note of the content of Kns-feed-plain.+163+26684.key file: we’re going to use it in nsd.conf:

  1. % cat Kns-feed-plain.+163+26684.key
  2.  
  3. ns-feed-plain. IN KEY 512 3 163 IseujRBzonAlWpVBLyyvn6ErSTp/CGui6+RIeXXLxb4=

Here is the alternative way to generate TSIG (it does require base64 installed though):

  1. % cd /usr/ports/converters/base64 && make install clean
  2. % rehash
  3.  
  4. % dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64

And one more using ldns-keygen (it does require ldns installed):

  1. % cd /usr/ports/dns/ldns && make install clean
  2. % rehash
  3.  
  4. % ldns-keygen -a hmac-sha256 -b 256 ns-feed-plain

Create nsd.conf in /usr/local/etc/nsd directory (use nsd.conf.sample as a reference). Here is nsd.conf of our hidden master:

  1. server:
  2.         ip-address: 10.9.128.1
  3.         do-ip4: yes
  4.         do-ip6: no
  5.         verbosity: 2
  6.         chroot: "/usr/local/etc/nsd"
  7.         zonesdir: "/usr/local/etc/nsd"
  8.         zonelistfile: "zone.list"
  9.         database: "var/db/nsd/nsd.db"
  10.         logfile: "var/log/nsd.log"
  11.         pidfile: "var/run/nsd.pid"
  12.         xfrdfile: "var/db/nsd/xfrd.state"
  13.         xfrdir: "var/db/nsd/"
  14.         hide-version: yes
  15.  
  16. remote-control:
  17.         control-enable: yes
  18.         control-interface: 127.0.0.1
  19.         control-port: 8952
  20.         server-key-file: "/usr/local/etc/nsd/nsd_server.key"
  21.         server-cert-file: "/usr/local/etc/nsd/nsd_server.pem"
  22.         control-key-file: "/usr/local/etc/nsd/nsd_control.key"
  23.         control-cert-file: "/usr/local/etc/nsd/nsd_control.pem"
  24.  
  25. key:
  26.         name: "tsig.sha256.plain"
  27.         algorithm: hmac-sha256
  28.         secret: "IseujRBzonAlWpVBLyyvn6ErSTp/CGui6+RIeXXLxb4="
  29.  
  30. pattern:
  31.         name: "plain-to-slaves"
  32.         zonefile: "zones/%s"
  33.         notify: 192.168.128.1 tsig.sha256.plain
  34.         notify: 192.168.128.2 tsig.sha256.plain
  35.         provide-xfr: 192.168.128.1-192.168.128.2 tsig.sha256.plain
  36.  
  37. zone:
  38.         name: "plain.org"
  39.         include-pattern: "plain-to-slaves"

Several points of interest and extra care:

chroot: instructs NSD to drop privileges to a non-privileged user (in the case of FreeBSD it’s going to be bindnsd) after it binds to port 53. Note that this is also going to be our BASE directory, so all path definitions after chroot: should be relative to /usr/local/etc/nsd. You can still use full paths, just make sure all directories are inside /usr/local/etc/nsd.

key: take a note of the name. Once we start configuring our slaves the name of the key should be identical to the one configured on the master. There might be multiple keys defined in nsd.conf.

pattern: allows you to bundle a set of zone config statements. For example, notify: and provide-xfr: statements are normally defined in the zone: section. If you host multiple zones that share the same slaves you can bundle it together in the pattern and include in the zone: section. Next time you add a new zone, you just define the name of the zone and append with include-pattern:.

zonefile: “zones/%s” instructs NSD to look for the zone name (%s) in /usr/local/etc/nsd/zones directory where %s is a name: configured in zone: section. In our example, NSD will look for /usr/local/etc/nsd/zones/plain.org file. Here you can find more detailed explanation of pattern use.

Let’s continue with the configuration of NS-FEED. Create the private and public keys for nsd-control. nsd-control is a utility to manage the NSD daemon.

  1. % cd /usr/local/etc/nsd
  2.  
  3. % nsd-control-setup

This will result in creating of four files that are already defined in nsd.conf under remote-control: section.

We’re almost done with our hidden master. Before we start the daemon we need to prepare the zone file for our domain. Create a file called plain.org under /usr/local/etc/nsd/zones directory:

  1.  
  2. $ORIGIN plain.org.
  3. $TTL 1h
  4. @       IN      SOA     plain.org.      hostmaster.plain.org. (
  5.                         2014082701              ; serial number
  6.                         3600                    ; refresh
  7.                         900                     ; retry
  8.                         1209600                 ; expire
  9.                         1800                    ; ttl
  10.                         )
  11. ; Name servers
  12.                     IN      NS      ns1.plain.org.
  13.                     IN      NS      ns2.plain.org.
  14.  
  15. ; A records for name servers
  16. ns1                 IN      A       192.168.128.1
  17. ns2                 IN      A       192.168.128.2
  18.  
  19. ; Additional A records
  20. @                   IN      A       192.168.128.20
  21. www                 IN      A       192.168.128.20

That’s it! We’re ready to fire up NSD:

  1. % /usr/local/etc/rc.d/nsd start

Verify that’s it’s up and running and you can query it:

  1. % sockstat -4 | grep 53
  2.  
  3. bind     nsd        46557 4  udp4   10.9.128.1:53      *:*
  4. bind     nsd        46557 5  tcp4   10.9.128.1:53      *:*
  5.  
  6. % dig @10.9.128.1 plain.org soa
  7.  
  8. ; <<>> DiG 9.10.0-P2 <<>> @10.9.128.1 plain.org soa
  9. ; (1 server found)
  10. ;; global options: +cmd
  11. ;; Got answer:
  12. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24606
  13. ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3
  14. ;; WARNING: recursion requested but not available
  15.  
  16. ;; OPT PSEUDOSECTION:
  17. ; EDNS: version: 0, flags:; udp: 4096
  18. ;; QUESTION SECTION:
  19. ;plain.org.                      IN      SOA
  20.  
  21. ;; ANSWER SECTION:
  22. plain.org.               3600    IN      SOA     plain.org. hostmaster.plain.org. 2014082701 3600 900 1209600 1800
  23.  
  24. ;; AUTHORITY SECTION:
  25. plain.org.               3600    IN      NS      ns1.plain.org.
  26. plain.org.               3600    IN      NS      ns2.plain.org.
  27.  
  28. ;; ADDITIONAL SECTION:
  29. ns1.plain.org.           3600    IN      A       192.168.128.1
  30. ns2.plain.org.           3600    IN      A       192.168.128.2
  31.  
  32. ;; Query time: 1 msec
  33. ;; SERVER: 10.9.128.1#53(10.9.128.1)
  34. ;; WHEN: Wed Aug 27 15:59:41 CEST 2014
  35. ;; MSG SIZE  rcvd: 164

Finally, check the NSD log file (/usr/local/etc/nsd/var/log/nsd.log):

  1. [1409155342] nsd[46556]: info: setup SSL certificates
  2. [1409155350] nsd[46558]: notice: nsd started (NSD 4.0.3), pid 46557
  3. [1409155410] nsd[46557]: error: xfrd: zone plain.org: max notify send count reached, 192.168.128.1 unreachable
  4. [1409155425] nsd[46557]: error: xfrd: zone plain.org: max notify send count reached, 192.168.128.2 unreachable

We’re done with the hidden master! You see those errors — that’s because our slaves are not yet configured. Also, NSD writes logs with Unix timestamps. You can use the following to display it in a human-readable format:

  1. % less /usr/local/etc/nsd/var/log/nsd.log | perl -p -e 's/^\[(.*)\]/"[". localtime($1) . "]"/e'

[20140909] : starting from version 4.1.0 NSD will log in a readable timestamp by default.

Let’s configure our slaves now: NS-3 and NS-4. I’m going to do it for NS-3 only — just duplicate the same changes on the secondary slave (NS-4).

There is no need to generate TSIG on the slave, so we go straight to nsd.conf. Here is the content of nsd.conf from NS-3:

  1. server:
  2.         ip-address: 192.168.128.1
  3.         do-ip4: yes
  4.         do-ip6: no
  5.         verbosity: 2
  6.         chroot: "/usr/local/etc/nsd"
  7.         zonesdir: "/usr/local/etc/nsd"
  8.         zonelistfile: "zone.list"
  9.         database: "var/db/nsd/nsd.db"
  10.         logfile: "var/log/nsd.log"
  11.         pidfile: "var/run/nsd.pid"
  12.         xfrdfile: "var/db/nsd/xfrd.state"
  13.         xfrdir: "var/db/nsd/"
  14.         hide-version: yes
  15.  
  16. remote-control:
  17.         control-enable: yes
  18.         control-interface: 127.0.0.1
  19.         control-port: 8952
  20.         server-key-file: "/usr/local/etc/nsd/nsd_server.key"
  21.         server-cert-file: "/usr/local/etc/nsd/nsd_server.pem"
  22.         control-key-file: "/usr/local/etc/nsd/nsd_control.key"
  23.         control-cert-file: "/usr/local/etc/nsd/nsd_control.pem"
  24.  
  25. key:
  26.         name: "tsig.sha256.plain"
  27.         algorithm: hmac-sha256
  28.         secret: "IseujRBzonAlWpVBLyyvn6ErSTp/CGui6+RIeXXLxb4="
  29.  
  30. pattern:
  31.         name: "from-master"
  32.         zonefile: "zones/%s"
  33.         request-xfr: AXFR 10.9.128.1 tsig.sha256.plain
  34.         provide-xfr: 172.16.128.1 tsig.sha256.plain
  35.         allow-notify: 10.9.128.1 tsig.sha256.plain
  36.         notify: 172.16.128.1 tsig.sha256.plain
  37.  
  38. zone:
  39.         name: "plain.org"
  40.         include-pattern: "from-master"

The important change in the slaves’ nsd.conf is request-xfr: and allow-notify: — those directives instruct NSD to become a slave for plain.org zone. provide-xfr: and notify: directives, on the other hand, makes NS-3 a master for 172.16.128.1, which is our ISP DNS. You will have to provide your ISP with the name of TSIG key (tsig.sha256.plain), algorithm and secret, in order to allow successful zone transfer.

Note that zonefile: directive is irrelevant for the slave. This file doesn’t exist and never will therefore you will get an info message in the logs. Once the zone is transferred from the master it’s compiled into a binary database file (/usr/local/etc/nsd/var/db/nsd/nsd.db) and that makes NSD pretty fast to initialize.

Execute nsd-control-setup on the slave and start the daemon. You should see a successful zone transfer logged:

  1.  nsd[25856]: info: setup SSL certificates
  2.  nsd[25858]: info: zonefile plain.org does not exist
  3.  nsd[25858]: notice: nsd started (NSD 4.0.3), pid 25857
  4.  nsd[25857]: info: xfrd: zone plain.org committed "received update to serial 2014082701 at 2014-08-27T17:36:09 from 10.9.128.1 TSIG verified with key tsig.sha256.plain"
  5.  nsd[25860]: info: zone plain.org. received update to serial 2014082701 at 2014-08-27T17:36:09 from 10.9.128.1 TSIG verified with key tsig.sha256.plain of 2496 bytes in 0.000179 seconds
  6.  nsd[25857]: info: Zone plain.org serial 0 is updated to 2014082701.

To double-check, go to NS-FEED, increase the serial of plain.org and reload the zone:

  1. % nsd-control reload plain.org

Your zone should be transferred immediately. Use ‘dig @192.168.128.1 plain.org soa’ to prove that.

That’s it for today. In the next article we’re going to introduce NS-SIGN and start signing zones with OpenDNSSEC.

Tags: , , , , , , ,

Leave a Reply