Setting up a FreeBSD Server on Hetzner, Part 2: DNS Nameserver

April 3, 2014 Brian Cunnie

[Editor’s note: This is the second post in a multi-part series covering the process of setting up a FreeBSD virtual server in the German Hetzner Cloud. The first blog post is here and reviews the base install and ssh configuration.]

We will now configure the DNS server as a secondary NS (nameserver) for the domain nono.com. We will use BIND as the nameserver, we will use git for revision control, and we will publish the DNS configuration and zone files to github.

Edit named.conf on shay.nono.com

cd /etc/namedb
 # alternative to using a heredoc when root privilege to write is needed
printf "slave/nrndc.keyn" | sudo tee .gitignore
sudo git init
sudo git add .
sudo -E git commit -m"Initial checkin"
sudo -E git remote add origin git@github.com:cunnie/shay.nono.com-etc-namedb.git
sudo -E git push -u origin master

[Alert readers may say, “Hey, we previously have placed /etc/ under revision control (in Setting up a FreeBSD Server on Hetzner, Part 1: Base Install and ssh). So if the DNS information is under /etc/namedb, and /etc is under revision control, then isn’t DNS also already under revision control?”. The answer is that /etc/namedb is a symbolic link to /var/named/etc/namedb [1], which is outside the /etc directory, and thus is not under /etc’s revision control]

We’re going to make several changes to named.conf:

  • allow queries to shay.nono.com’s IPv4 address
  • allow queries to shay.nono.com’s IPv6 address
  • configure shay.nono.com to be a secondary NS for the domain nono.com

[Editor’s note: prior to BIND 9.4, we needed to explicitly disallow recursive queries [2] from everywhere except localhost. With BIND 9.4 the behavior is changed, and the default behavior is a sensible one (i.e. no recursive queries except for localhost/localnets). In other words, we need to make fewer changes to named.conf.]

Let’s edit the file:

sudo vim named.conf

Let’s enable the external interfaces to accept queries. Note that there is an inconsistency between IPv4 and IPv6: to enable IPv4 on the external interface we comment-out the corresponding line, but to enable IPv6 we uncomment the corresponding line and write “any;” between the curly braces.

options {
    ...
//      listen-on       { 127.0.0.1; };
    ...
        listen-on-v6    { any; };

Now we append the zone information to the end of named.conf. We will use the IPv6 address of the primary nameserver (SOA) to test the IPv6 transport layer:

zone "nono.com" {
        type slave;
        masters {
                2001:558:6045:109:15c7:4a76:5824:6c51;
        };
};

Now let’s check in and push:

sudo git add -u
sudo -E git commit -m"nono.com secondary NS"
sudo -E git push origin master

The resulting named.conf file can be viewed here

Edit named.conf on nono.com’s Primary DNS Server

We need to make sure the primary (master) nameserver will allow zone transfers (AXFR) [3] from the secondary (i.e. shay.nono.com). Here’s the security ACLs of the named.conf file on our primary nameserver (ns-he is a mnemonic for nameserver-Hetzner):

acl ns-he { 2a01:4f8:d12:148e::2; };

zone "nono.com" in {
        type master; file "/etc/namedb/master/nono.com";
        allow-transfer { ns-he; };
  • Restart named on the primary nameserver to pick up the new ACLs (i.e. sudo /etc/rc.d/named restart).

Start the Nameserver Daemon on Hetzner and Test

Back on the Hetzner machine: configure the nameserver daemon to start on boot, and the bring it up manually:

printf "# enable BINDnnamed_enable="YES"n" | sudo tee -a /etc/rc.conf
sudo /etc/rc.d/named start

Test to make sure it’s resolving properly from shay.nono.com:

nslookup shay.nono.com 127.0.0.1
nslookup shay.nono.com ::1
nslookup google.com 127.0.0.1
nslookup google.com ::1

Now we test from a third-party machine (to make sure that recursion has been disabled). Note that we explicitly specify shay.nono.com’s IPv4 and IPv6 addresses in order to test on both protocols:

nslookup shay.nono.com 78.47.249.19
nslookup shay.nono.com 2a01:4f8:d12:148e::2
nslookup google.com 78.47.249.19  # should fail, "REFUSED/NXDOMAIN"
nslookup google.com 2a01:4f8:d12:148e::2  # should fail "REFUSED/NXDOMAIN"

Update the Domain Registrar with the New Nameserver

This procedure depends upon the registrar with whom you’ve registered your domain. In this case, the registrar is joker.com (coincidentally another German establishment), and updating the nameservers is accomplished by logging in and clicking on the Service Zone link. Other popular registrars include GoDaddy and easyDNS.

Check that the whois Information Has Propagated

Once we’ve submitted the new nameserver information to our registrar, we use the whois command to verify that the changes have rippled through. We grep for the nameservers because we are not interested in the other information. Do not be concerned if your nameservers are capitalized: DNS is a case-insensitve protocol, at least as far as our purposes are concerned.

We look for the Hetzner nameserver (ns-he). We make sure that we see both its IPv4 address and its iPv6 address:

 whois nono.com | grep "Name Server:"
   Name Server: NS-AWS.NONO.COM
   Name Server: NS-HE.NONO.COM
Name Server: ns-aws.nono.com 54.235.96.196
Name Server: ns-he.nono.com 78.47.249.19 2a01:4f8:d12:148e::2

Update the NS Records on the Primary Nameserver

We’re still not finished: even though the Internet knows that ns-he.nono.com is a nameserver for the nono.com domain, the nono.com nameservers do not yet know that ns-he.nono.com is a nameserver. In other words, we need to update the nono.com zone file. We need to add an NS record for the new ns-he.nono.com nameserver.

We log into the Master/Primary nameserver, and edit the zone file (in this case, /etc/namedb/master/nono.com). We make sure to increment the serial number otherwise the change won’t propagate to the secondary nameservers (the secondaries use the serial number as a mechanism to determine if there has been a change to the zone file. If there has been a change, then they download, via AXFR, a new copy of the zone file). Once we’ve finished editing the zone file we restart the nameserver so that the changes take effect.

sudo vim /etc/namedb/master/nono.com
    nono.com                IN SOA  ns-an.nono.com. cunnie.nono.com. (
                                    1395637545 ; serial
                                    10800      ; refresh (3 hours)
                                    3600       ; retry (1 hour)
                                    604800     ; expire (1 week)
                                    21600      ; minimum (6 hours)
                                    )
                            NS      ns-he.nono.com.
                            NS      ns-aws.nono.com.
     ...
sudo /etc/rc.d/named restart

Check that the DNS NS Information Has Propagated

DNS information can take 30 minutes or more to propagate (it depends upon the TTL value for the DNS records and whether the records have been cached). In this example, we use the nslookup command to return the NS (nameserver) records for the nono.com domain.

nslookup -query=ns nono.com
Server:     10.9.9.1
Address:    10.9.9.1#53

nono.com    nameserver = ns-aws.nono.com.
nono.com    nameserver = ns-he.nono.com.

Notice ns-he.nono.com in the output; we have successfully configured a secondary nameserver and now feel the warm glow of accomplishment of a job well done.


1 Until the early 2000’s /etc/namedb was not a symbolic link to /var/named/etc/namedb but a normal directory. With the advent of security concerns and at least one BIND exploit (of which this author was a victim), the FreeBSD security team decided to add an additional layer of security by running the BIND daemon in a chroot environment; however, given that the BIND daemon would, on occasion, write to disk in its chrooted environment, a better home would be the /var filesystem. To make the transition easier for systems administrators who were habituated to configuring BIND in /etc/namedb, a symbolic link was created.

2 DNS nameservers that allow recursive queries can be used for malicious purposes. In fact, Godaddy reserves the right to suspend your account if you configure a recursive nameserver.

A recursive query is one that asks the nameserver to resolve a record for a domain for which the nameserver is not authoritative; for example, shay.nono.com is authoritative only for the nono.com domain (not quite true, it’s authoritative for other domains as well, e.g. 127.in-addr.arpa, but let’s not get lost in the details), so a query directed to it for home.nono.com’s A (address) record would be an iterative, not recursive, query, and would be allowed; however, a query for google.com’s A record would be a recursive query (it’s not within the nono.com domain), and would not be honored by shay.nono.com’s nameserver.

3 Note that unlike other DNS queries, AXFR requests take place over TCP connections, not UDP. In other words, you must make sure that your firewall on your primary nameserver allows inbound TCP connections on port 53 from your secondary nameservers in order for the zone transfer to succeed.

Daniel J. Bernstein has written an excellent piece on how AXFR works. He is the author of a popular nameserver daemon (djb-dns). Daniel J. Bernstein was called the the greatest programmer in the history of the world by Aaron Swartz, who was no mean programmer himself, having helped develop the format of RSS (web feed), the Creative Commons organization, and Reddit. Aaron unfortunately took his own life in January 2013.

About the Author

Biography

Previous
Getting Started on Your First iOS App – Part II
Getting Started on Your First iOS App – Part II

This blog was co-authored by Yulia Tolskaya. The full source can be found here. In our last post, we cover...

Next
Getting Started on Your First iOS App – Part I
Getting Started on Your First iOS App – Part I

The app we’ll be building in this blog is a simple score keeping app. The requirements are simple: I want t...