HOWTO setup your own caching nameserver using Unbound

From LinuxReviews
Jump to navigationJump to search

The best alternative for setting up a caching nameserver on your LAN or personal machine today is Unbound. It's written with that purpose in mind which makes it faster and simpler to setup than more full-featured alternatives such as named (called "BIND") or KNOT-resolver and such.

Basic installation and configuration

Start off by installing unbound with dnf install unbound or apt-get install unbound depending on distribution. On Arch you also have to manually install the expat package.

Now it's time to make a configuration file for it. Here is a most basic example of what you need:

File: /etc/unbound/unbound.conf
server:
  access-control: 10.0.0.0/8 allow
  access-control: 192.168.0.0/16 allow
  access-control: 127.0.0.0/8 allow
  access-control: ::1/128 allow
  interface: ::
  interface: 0.0.0.0
  aggressive-nsec: yes
  cache-max-ttl: 14400
  cache-min-ttl: 300
  hide-identity: yes
  hide-version: yes
  minimal-responses: yes
  prefetch: yes
  qname-minimisation: yes
  rrset-roundrobin: yes
  use-caps-for-id: yes
  verbosity: 0

The first few lines define who can query the server with access-control directives. They we define what to listen on with interface. The above example is very liberal and makes unbound listen on all interfaces.

Refer to the unbound.conf manual page for further details.

It is a good idea to run unbound-checkconf to check if it is valid once you are happy with your configuration.

Now you need to ensure that systemd-resolved is not occupying the DNS port. You can do this by giving it the following configuration file:

File: /etc/systemd/resolved.conf
[Resolve]
DNS=127.0.0.1
FallbackDNS=1.0.0.1
MulticastDNS=no
DNSStubListener=no

The DNSStubListener directive is essential to ensure it does not listen for DNS queries. You may actually want MulticastDNS if you do not use avahi-daemon for multicast-DNS purposes.

Restart systemd-resolved with systemctl restart systemd-resolved.service or stop it with code>systemctl stop systemd-resolved.service - Do be aware that it doesn't really matter if you stop it or re-start it. systemd will happily start it when applications make API requests for it even if you masked it.

Then run

systemctl start unbound.service

to start it and

systemctl enable unbound.service

to make it start on every boot.

Validating your queries

Once you have a basic unbound setup you will want to add validation. First, install the bind-utils package and copy the /etc/trusted-key.key to where unbound can read it with cp /etc/trusted-key.key /etc/unbound

Now add this line to your unbound.conf:

trust-anchor-file: "/etc/unbound/trusted-key.key"

And restart unbound. Now you should test using this command:

unbound-host -C /etc/unbound/unbound.conf -v sigok.verteiltesysteme.net

which should output

sigok.verteiltesysteme.net has address 134.91.78.139 (secure)
sigok.verteiltesysteme.net has IPv6 address 2001:638:501:8efc::139 (secure)
sigok.verteiltesysteme.net has no mail handler record (secure)

and NOT

sigok.verteiltesysteme.net has address 134.91.78.139 (insecure)
sigok.verteiltesysteme.net has IPv6 address 2001:638:501:8efc::139 (insecure)
sigok.verteiltesysteme.net has no mail handler record (insecure)

If get "secure" as in the first output then you're good, if you get "insecure" as in the last example then it is not working.

Maintaining a root "hints" file

A DNS query will first go to the DNS root and then the nameservers responsible for the top domain (.com/.org/etc) and then the server which is responsible for the domain you are querying. Thus; you need to know where to start. Unbound comes with a built-in list of root servers. That's great, but if your Unbound version gets wildly outdated and the root servers change those hints may no longer apply. It is considered "good practice" to keep a updated local copy of the hints. A simple way to do this is to create a good old cron file:

File: /etc/cron.monthly/update-unbound-hints.sh
#!/bin/bash
wget -q https://www.internic.net/domain/named.root -O /tmp/root.hints
if grep -q ROOT-SERVERS /tmp/root.hints ;then
  mv -f /tmp/root.hints /etc/unbound/root.hints ; chmod a+r /etc/unbound/root.hints
fi

make the file executable chmod a+x /etc/cron.monthly/update-unbound-hints.sh

and run it /etc/cron.monthly/update-unbound-hints.sh

Then add the following line to /etc/unbound/unbound.conf :

root-hints: "/etc/unbound/root.hints

Forwarding queries

Asking a botnet DNS server ran by either CloudFlare or Google may actually be faster than doing your own recursive lookups depending on your network, location and distance to those.

If you would like to forward DNS queries to another nameserver on your LAN you need to add

forward-zone:
   name: "."
   forward-addr: 192.168.0.1@53

That is good enough on your LAN but you may want to add more if your DNS queries will be leaving your local network and going to the botnet. For this you would want to add the following:

  tls-upstream: yes                                                                                                                                                                                                            
  tls-cert-bundle: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem                                                                                                                                                                 
forward-zone:
   name: "."                                                                                                                                                                                                                          
   # Cloudflare DNS                                                                                                                                                                                                                    
   forward-addr: 2606:4700:4700::1111@853#cloudflare-dns.com                                                                                                                                                                           
   forward-addr: 1.1.1.1@853#cloudflare-dns.com                                                                                                                                                                                        
   forward-addr: 2606:4700:4700::1001@853#cloudflare-dns.com                                                                                                                                                                           
   forward-addr: 1.0.0.1@853#cloudflare-dns.com

Here we tell unbound to use TLS for queries leaving the LAN with tls-upstream: yes. Then we tell it what certificate package to check against with tls-cert-bundle. The file referred to should be installed by the ca-certificates package which you should have gotten installed as a dependency for unbound. Next we specify a set of forward-addr and here there is one detail one might get wrong: The names of those servers after the # are not comments. Those are used for the TLS certificate validation and must be present.

Combining the above a complete unbound configuration file which forwards DNS queries to the CloudFlare botnet looks like this:

File: /etc/unbound/unbound.conf
server:
  access-control: 10.0.0.0/8 allow
  access-control: 192.168.0.0/16 allow
  access-control: 127.0.0.0/8 allow
  access-control: ::1/128 allow
  interface: ::
  interface: 0.0.0.0
  aggressive-nsec: yes
  cache-max-ttl: 14400
  cache-min-ttl: 300
  hide-identity: yes
  hide-version: yes
  minimal-responses: yes
  prefetch: yes
  qname-minimisation: yes
  rrset-roundrobin: yes
  use-caps-for-id: yes
  verbosity: 0
  tls-upstream: yes                                                                                                                                                                                                            
  tls-cert-bundle: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem                                                                                                                                                                 
forward-zone:
   name: "."                                                                                                                                                                                                                          
   # Cloudflare DNS                                                                                                                                                                                                                    
   forward-addr: 2606:4700:4700::1111@853#cloudflare-dns.com                                                                                                                                                                           
   forward-addr: 1.1.1.1@853#cloudflare-dns.com                                                                                                                                                                                        
   forward-addr: 2606:4700:4700::1001@853#cloudflare-dns.com                                                                                                                                                                           
   forward-addr: 1.0.0.1@853#cloudflare-dns.com

Ensuring there is no systemd or networkmanager interference

This section is not for everyone. You may want to ensure that a local or LAN Unbound nameserver is always used regardless of systemd or networkmanager opinion. To accomplish this you first need to tell networkmanager to not interfere with your DNS settings, ever. This can be accomplished by changing the configuration file /etc/NetworkManager/NetworkManager.conf to only contain the following content:

File: /etc/NetworkManager/NetworkManager.conf
[main]
dns=none
systemd-resolved=false
[logging]

Now NetworkManager will not touch or overwrite or destroy your /etc/resolv.conf. By default that file is now a symbolic link on most distributions. You can remove that link and demand that only localhost, where you now have unbound, is (ab)used with these fine commands:

rm -f /etc/resolv.conf
echo 'nameserver 127.0.0.1' > /etc/resolv.conf

Note that you are now relying entirely on unbound running on localhost. That is fine if you are starting Unbound on boot and you want it to handle DNS regardless of what network you are using.

systemd-resolved will however be a pain to configure in this situation.


Add your comment
LinuxReviews welcomes all comments. If you do not want to be anonymous, register or log in. It is free.