First Adventure with FreeBSD DNS Servers

Written by Michael Cole - July 18th 2015


Some times it seems pretty busy, or even something fun comes up and you just want to do that instead. But with the jail management well in hand it was time to work on something else. So I decided to tackle DNS. On FreeBSD bind is still an option like it is under Linux. But as always it's kind of fun to try something new or different. Also FreeBSD favors the unbound commands in base, such as drill instead of dig for example. So I decided to do some research into using unbound as a DNS server.

Well as it turns out "Unbound is a validating, recursive, and caching DNS resolver." to quote their main page (as of this moment). What does that mean? I think to explain it the best, I will say that there are 2 main functions of DNS servers.

The first function is to server up DNS entries for your own domains. This is what they call authoritative. So basically if your domain name is "mydomain.mine" and someone wants to go to www.mydomain.mine then your DNS server would respond with the IP address of your main web server. But the second function that we will talk about in a bit would also do that. A few things make the authoritative server different though. Firstly it gets the answer directly from its database and doesn't ask anyone else. Secondly (without getting into the low level DNS workings) when other servers ask anything about this domain they get redirected to the authoritative server for the domain. You can look up root dns servers and domain registrars if you would like to know more on that. I will also note that this works for reverse DNS too. If someone owns an IP range then they can setup an authoritative record that the IP points to a given host name. This type of traffic is mainly from DNS server to DNS server.

The second function is to provide DNS to clients. So you hook up your computer to the Internet for the first time, for most people (as of today's technology) this is calling up a Cable or DSL provider and saying "I moved into this house at this address and I would like your service.". You then get your router/modem from the company and some wiring in your house. You connect a computer to the router/modem and you are good to go. Now you can check your email, browse the web and even look at cat pictures all day. But what does all this have to do with DNS. Well under the hood, your computer basically asked your ISP for an IP Address, and along with that came DNS servers (usually two). So now when you type a web address (or anything else), your machine goes to your ISP's DNS servers and gets the IP back. This type of server is the same type that unbound is (validating, recursive, and caching). This type of traffic is mainly from DNS clients to DNS servers.

Some servers can do both (like bind). Unbound can't (read that as shouldn't, as it can provide local-zone). Or I should say at least not by itself. The makers of unbound also make NSD (name server daemon) and it is an authoritative only name server.

So there were some options I had to recreate my current setup over to these technologies (which I am currently still working on, but I will cover the portion I have completed). Method 1 would be to simply use bind on FreeBSD copy files across call it good. That would work, but where is the fun in that. Method 2, setup NSD on a different port (not udp 53 the standard DNS port), then setup unbound on the normal port and have unbound forward to NSD for local LAN domains. This would work fine for my current setup, but I would like the ability to have external domains in the future. Method 3 is the same as Method 2, But adding some firewall redirection to the other port on the NSD from the standard port from external sources. But honestly I just think that is a kludge. Method 4, have a dedicated NSD setup and a dedicated unbound setup.

I selected Method 4. This method also seems to be the creators intent. Since as we described above the traffic is usually from DNS server to DNS server for authoritative DNS, and from DNS clients to DNS servers for recursive DNS, we have the ability to secure these in different ways. Servers tend to have a standard implementation, and generally a better over all setup than clients. Clients are basically every random device setup to use a network. A lot of these devices are very small, and you have no way to configure how they work.

With all of this in mind, I'm going to discuss the NSD setup. I haven't completed all of the actual zone configuration as of writing this, but my testing of this configuration has been very positive so far. Of course this doesn't cover a lot of things, like how to buy a domain, how to setup the zone file, or even recommended security or firewall changes. You will need to take into account all of your network and security factors. I am not responsible for anything that may occur as a result of using this information. Also keep in mind this is a snapshot of a current point in time, configurations change, security and key standards change as well.

So first things first. Install NSD. On FreeBSD to use the binary package this is:

pkg install nsd
			

This can be installed in a jail or on an actual host. The majority of files you will be interested in are in /usr/local/etc/nsd/. In there, copy the sample nsd.conf over or create one from scratch. Your server settings will be specific to your network, such as what IP to bind to and if you are doing IPv4 and/or 6.

NSD has a remote-control section, this can be used to control it locally as well. To set this up, first we generate keys, by running the following command:

nsd-control-setup
			

Once that is complete, edit the nsd.conf file. Go to the remote-control section and make it look similar to this:

remote-control:
        control-enable: yes
        control-interface: 127.0.0.1
        control-port: 8952
        server-key-file: "/usr/local/etc/nsd/nsd_server.key"
        server-cert-file: "/usr/local/etc/nsd/nsd_server.pem"
        control-key-file: "/usr/local/etc/nsd/nsd_control.key"
        control-cert-file: "/usr/local/etc/nsd/nsd_control.pem"
			

You can do other interfaces if you so chose. I just wanted to control mine from the local machine.

Now save that, and get back to the command line. I wanted to have a master/slave or primary/secondary DNS configuration. Basically running two servers that work together. To do this you generate a key, so that they can talk to each other. First run the following command (you may need to install the base64 package):

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

The output returned will look similar to the following, but with a different last line:

1+0 records in
1+0 records out
32 bytes transferred in 0.000082 secs (390168 bytes/sec)
zkugYYmW7dvW/T/mQRuP1rHONzORfcUsE+VT0wPTO8M=
			

This is actually the command suggested in my version of the sample configuration file, if this has updated run the new line instead. That last line is the key. Copy that, and edit the nsd.conf again. This time go to the key section. Make it look similar to this:

key:
        name: "keyname"
        algorithm: hmac-sha256
        secret: "zkugYYmW7dvW/T/mQRuP1rHONzORfcUsE+VT0wPTO8M="
			

The key algorithm is from this moment in time, if it has support for a better one use that. I'm going to save you time here. The first time you are setting NSD up, you may not realize what patterns are for. Basically if you find yourself typing the same thing over and over again, use a pattern. In my case each zone would either need to be sent to the slave or master depending on which server I was on. So I setup two patterns (one for each server). These are in the pattern section of nsd.conf, and look like this:

pattern:
    name: "replicatetoslave"
    notify: *slave ip* keyname
    provide-xfr: *slave ip* keyname
			

And:

pattern:
        name: "replicatefrommaster"
        allow-notify: *master ip* keyname
        request-xfr: AXFR *master ip* keyname
			

Of course replace with the appropriate IP addresses for your network. And the "AXFR" is not needed, but it gets rid of errors in your logs when it tries to use IXFR first. If you don't do this you can just add the lines into each zone, I'm just trying to make your life easier. Now on the master setup your zone configuration. I'll give you one example of both a forward and reverse zone configuration, but not the zone file itself, you can look those up later. In the nsd.conf add something similar to the following for forward:

zone:
    name: "domain.lan"
    zonefile: "domain.lan.zone"
    include-pattern: "replicatetoslave"
			

And for reverse:

zone:
    name: "99.168.192.in-addr.arpa"
    zonefile: "192.168.99.zone"
    include-pattern: "replicatetoslave"
			

On the slave you simply replace replicatetoslave with replicatefrommaster. I always recommend checking your configuration. For nsd you simply type:

nsd-checkconf nsd.conf
			

If this comes back without any errors, you should be good to go. Now you can set it up to start at boot with the following in rc.conf:

nsd_enable="YES"
			

Now you can edit a zone on the master server (always remember to update the serial number). And use the following command:

nsd-control reload
			

It will read the changes in from the disk and because of the notify lines send the configuration to the slave DNS as well. The slave will answer because it is setup to allow. You now have 2 authoritative DNS servers for your domain.

I'm going to state this again. Of course this didn't cover a lot of things, like how to buy a domain, how to setup the zone file, or even recommended security or firewall changes. You will need to take into account all of your network and security factors. I am not responsible for anything that may occur as a result of using this information. Also keep in mind this is a snapshot of a current point in time, configurations change, security and key standards change as well.