Setting up a local DNS server with Unbound

Name Caddy

© Lead Image © Nataliia Natykach, 123RF.com

© Lead Image © Nataliia Natykach, 123RF.com

Author(s):

You don't have to be satisfied with your ISP's slow and cumbersome DNS server. Your own Unbound server could improve performance as well as security.

When you turn your home computer on, launch a web browser, and instruct it to visit the linux-magazine.com website, your computer sends a DNS query, asking for the IP address associated with the name linux-magazine.com. For many users, this query is sent to a DNS server provided by the user's Internet Service Provider (ISP).

Using your ISP's DNS server is an easy and low-stress option, but in many situations, it also has some disadvantages. The most popular reason why some users prefer a non-default DNS server is performance. Simply put: some servers have lower latency and faster query times than others. If your ISP's DNS servers are slow, switching to faster servers will lead to noticeable improvement in your web browsing experience.

Another reason for switching to a different server is to avoid (or enforce) soft censorship. For instance, a school administrator might wish to prevent students from accessing social networking sites such as facebook.com during the school day. The easiest way to prevent a user from reaching a website is to instruct the DNS server to return a bogus address or to return an NXDOMAIN message, which means the server doesn't think the domain exists. Another option is for the server to return the address of a webpage that displays a message such as "No Social Networking Allowed Here."

Many DNS providers offer anti-advertisement, anti-malware, and anti-phishing protection in such a way that, if your browser tries to resolve the address of some service known to serve advertisements or harmful code, it will be redirected to a bogus address or a site with a warning. Parental controls that filter sites deemed unsafe for kids are also offered by some DNS providers. See Table 1 for a list of some third-party DNS providers.

Table 1

Publicly Available DNS Servers

Address

Operator

Stated Purpose

37.235.1.174

FreeDNS

Offering DNS services that bypass ISP tampering.

37.235.1.177

FreeDNS

Offering DNS services that bypass ISP tampering.

8.8.4.4

Google

Improving DNS query times.

8.8.8.8

Google

Improving DNS query times.

208.67.222.222

OpenDNS

Improving DNS query times.

208.67.220.220

OpenDNS

Improving DNS query times.

208.67.222.123

OpenDNS

Blacklisting adult content.

208.67.220.123

OpenDNS

Blacklisting adult content.

8.26.56.26

Comodo

Blacklisting malware and harmful domains.

8.20.247.20

Comodo

Blacklisting malware and harmful domains.

84.200.69.80

DNS.WATCH

Offering uncensored DNS services.

84.200.70.40

DNS.WATCH

Offering uncensored DNS services.

A third-party provider could help you with performance and parental control, but if you want to customize the DNS environment, you will need to set up your own server.

Running your own DNS server in your own premises gives you a lot of flexibility. You could also get a performance boost. Imagine that there are four family members in a home LAN, and two are browsing the Internet at the same time. One person visits linux-magazine.com. Then a different person, sitting at a different computer, visits the same site. If this LAN has a local DNS server, the server that resolves the address for the first user could cache the address. When the second user visits the same site, the server could provide the address from the cache without having to pull the information from outside the network.

Running your own DNS servers allows you to have custom DNS entries. You can create your own blacklists (that block advertisements, for example). You can also assign names to local resources, such as your printer, your NAS, or your IP cameras.

Another benefit of a local DNS server is that it lets you take advantage of DNSSEC [1], which still has not been implemented by many ISPs. DNSSEC is a security overlay that protects users from having DNS traffic altered by malicious actors. Its actual usefulness is disputed, but some users prefer the protection of DNSSEC. This article describes how to set up your own DNSSEC-aware DNS configuration using the Unbound DNS server.

Enter Unbound

BIND is the undisputed king of free and open source DNS servers. The BIND DNS server is feature rich, well documented, and available on most distributions. On the other hand, BIND is too heavy for most small LANs, and it has some significant security concerns.

Unbound is a non-authoritative, recursive DNS server, with support for DNSSEC validation (see the box entitled "Authoritative Servers and Recursive Servers.") It is included in the default installation of the OpenBSD operating system and is available on the repositories of most serious Linux distributions. It is easy to configure and quick to set up.

Authoritative Servers and Recursive Servers

Authoritative DNS servers [2] are servers designed to answer DNS queries pertaining to a specific DNS zone. A DNS zone is a distinct portion of a DNS hierarchy (usually the global Internet one) that has been placed under the administration of a particular entity. This is to say, it is the sort of server Verisign uses to administrate the .com TDL and ensure that sites that use the .com zone can be found on the Internet. Definitively not the sort of DNS server you use in your home LAN.

There are 13 very special authoritative DNS servers, known as the root DNS servers. A root DNS server is a name server located in the root DNS zone, which is the highest zone in the DNS hierarchy (Figure 1). The root DNS servers are authoritative for the whole DNS space.

Figure 1: DNS is a hierarchical system. Zone administrators delegate parts of their zones to other administrators below them in the hierarchy.

In theory, the whole Internet could be managed by authoritative servers alone. A DNS resolver that has to depend exclusively on authoritative servers would first contact one of the root DNS servers. If the resolver were trying to solve, as an example, www.example.org, the root DNS server contacted would answer "I don't know the address of www.example.org, but this other authoritative server does" and guide it to some server responsible of the .org TDL. When the resolver asked this new server for an answer, it would either get a result or be told to look for an answer at some other authoritative server placed below in the DNS hierarchy (Figure 2).

Figure 2: An iterative DNS query against authoritative DNS servers.

If every resolver and DNS server worked like that, the Internet would collapse under the traffic load, since a very small number of root servers and authoritative servers for TDL zones would have to answer so many queries.

The sort of DNS server ISPs provide to their customers is usually a recursive caching server. Recursive servers are designed to answer DNS queries without overloading the root servers. When a DNS resolver asks a recursive server "where is www.example.org?", the server will ask other DNS servers on behalf of the resolver, and return an already valid and final answer. Since most recursive servers also have big caches, they may be able to extract an answer for the DNS resolver from their caches without having to send additional queries to other DNS servers.

Usually, local system administrators install their DNS servers on machines that run 24 hours a day. In a home environment, any machine that is continuously running torrent software, or a web proxy, or any infrastructure service, will be a perfect candidate. A small Single Board Computer (SBC) such as a Raspberry Pi will also do the trick, if you don't want to assign the task to a full featured computer.

In Devuan, you can install Unbound using the apt-get utility:

# apt-get install unbound

Services in Devuan are started upon installation by default. You might want to stop it right away and begin with the configuration:

# /etc/init.d/unbound stop

One of your first steps should be to install a root hints file. This file contains the location of the root DNS servers of the Internet. Unbound itself comes with a hardcoded set of root servers, but it is always a good idea to provide it with an up-to-date set, just in case. The hardcoded set is prone to become outdated.

You can obtain an updated list as follows:

# cd /etc/unbound
# curl -Lo /etc/unbound/root.hints https://www.internic.net/domain/named.cache

This file should be updated periodically. You can execute the update through a cron job or manually. A 6-month interval is adequate for home purposes.

Be careful which root list you use! If your list contains malicious servers, you will be vulnerable to certain attacks, like having DNS queries answered with malicious results.

Listing 1 shows a possible configuration file for Unbound. The /etc/unbound/unbound.conf file loads different directives from files located in /etc/unbound/unbound.conf.d.

Listing 1

unbound.conf

# /etc/unbound/unbound.conf
# The include directive loads
# configuration parameters
# from the indicated files.
server:
include: /etc/unbound/unbound.conf.d/access_options.conf
include: /etc/unbound/unbound.conf.d/name_solving.conf
include: /etc/unbound/unbound.conf.d/privacy_options.conf
include: /etc/unbound/unbound.conf.d/cache_options.conf
include: /etc/unbound/unbound.conf.d/dnssec_options.conf
include: /etc/unbound/unbound.conf.d/blacklist.conf
include: /etc/unbound/unbound.conf.d/local_names.conf
include: /etc/unbound/unbound.conf.d/opennic_names.conf
include: /etc/unbound/unbound.conf.d/forwarders.conf
remote-control:
        #Disable remote control which we don't intend to use.
        control-enable: no

Listing 2 shows an example of how to configure Unbound to use the root hints file. The root-hints parameter tells the server the name of the root hints file.

Listing 2

name_solving.conf

# /etc/unbound/unbound.conf.d/name_solving.conf
root-hints: /etc/unbound/root.hints

Enabling DNSSEC

DNSSEC is a protocol designed to prevent man-in-the-middle attacks against DNS queries that could result in the DNS resolver getting a maliciously crafted DNS response. See the box "How Does DNSSEC Work?" for more information.

How Does DNSSEC Work?

The whole DNS system was designed in such a way that every connection was sent unencrypted over the network. Worse yet, there was no way to ensure that the traffic between DNS servers and DNS resolvers was not tampered with. For example, if you want to visit mybankwebsite.com and your web browser tries to resolve that domain, it is theoretically possible for some evil entity to intercept that DNS request and give you a fake response.

DNSSEC is an extension for the DNS protocol that lets DNS entries be cryptographically signed in such a way that the validity of a DNS response can be verified.

DNSSEC uses PKI (Public Key Infrastructure) in order to accomplish its goal. Each zone (including the Root Zone) has its public/private keypair. Keypairs are certified in a hierarchical way. The keypair of the .com zone has been signed with a key belonging to the administration of the root zone. The children zones directly below the .com zone are signed by the administrator of the .com zone, and so on. This builds what is called a chain of trust, and the public key that sits at the top of the hierarchy is known as the trust-anchor – it has no superior entity certifying its validity.

Most DNSSEC-aware resolvers use the root DNS public keying as their trust-anchor. When such a resolver needs to validate a DNS entry, it asks for the public keys of the administrator of its zone to the adequate authoritative server. If this public key needs validation, the resolver asks for the public key of its parent zone to an authoritative server of the parent zone, and this process continues until the trust-anchor is reached. Once the whole chain is fetched, it can be validated. After the validity of the chain is accepted, the public key at the end of the line may be used to check the authenticity of the cryptographic signature attached to the DNS entry.

DNSSEC has many drawbacks [3][4]. For one, it is argued that private keys related to popular TDLs (like .com or .net) are indirectly under the control of governments and are therefore compromised. Also, having to retrieve the public keys necessary for validating the chain increases the time the DNS query takes. Finally, many DNS zones have not enabled DNSSEC at all, which means that the domains under their management cannot have their validity verified.

This has lead to the creation of many alternatives, with different degrees of success and acceptance. DNS over TLS [5] and DNSCrypt [6] are two of the best known.

The DNSSEC trust anchor can be retrieved and initialized by issuing the following command:

# unbound-anchor -a "/var/lib/unbound/root.key"
# chown unbound:unbound "/var/lib/unbound/root.key"
# chmod 500 "/var/lib/unbound/root.key"

Listing 3 displays an example configuration that enables DNSSEC validation. The auto-trust-anchor-file parameter points at the root key of the DNSSEC trust anchor. This key is stored in a file. As long as the user running the Unbound server has read and write permissions over the trust anchor file and the folder that contains it, Unbound itself will be able to keep the trust anchor updated automatically. The domain-insecure parameters in Listing 3 disables DNSSEC verification for the unofficial DNS zones .dyn and .geek.

Listing 3

dnssec_options.conf

# /etc/unbound/unbound.conf.d/dnssec_options.conf
auto-trust-anchor-file: "/var/lib/unbound/root.key"
domain-insecure: "dyn."
domain-insecure: "geek."

Using Multiple Forwarders

By default, your Unbound server will try to resolve DNS entries by asking the root DNS servers for an answer. This is OK, but sometime you want to adopt a different approach.

You may want to have a list of recursive DNS servers to send DNS queries to, like, for example, the ones provided by your ISP. You can set forward zones, which designate DNS zones that will have queries related to them forwarded to servers you designate.

Suppose that, for any reason, you want all your queries for domains in the .geek zone sent to an Opennic server instead of to the root DNS servers. The example configuration at Listing 4 ensures that queries for domains under the .geek and .dyn extraofficial TDLs are forwarded to a DNS server of the Opennic Project.

Listing 4

opennic_names.conf

# /etc/unbound/unbound.conf.d/opennic_names.conf
forward-zone:
        name: "dyn."
        forward-addr: 193.183.98.66     #opennic
        forward-addr: 87.98.175.85    #opennic
        forward-addr: 5.135.183.146   #opennic
        forward-addr: 51.254.25.115     #opennic
forward-zone:
        name: "geek."
        forward-addr: 193.183.98.66     #opennic
        forward-addr: 87.98.175.85   #opennic
        forward-addr: 5.135.183.146   #opennic
        forward-addr: 51.254.25.115     #opennic

Why is this feature useful? For two main reasons. The first one is that you might want to connect to an alternative, unofficial DNS infrastructure, such as the Opennic Project [7], which carries unofficial TDLs that are not recognized by the IANA.

The second reason is that you may not want to use the root servers at all. In fact, end users are not expected to use them and depend on recursive servers instead. The example at Listing 5 instructs Unbound to use two recursive DNS servers from DNS.WATCH [8] when attempting to resolve any domain name located under the root zone, which, in practice, means every domain.

Listing 5

forwarders.conf

# /etc/unbound/unbound.conf.d/forwarders.conf
forward-zone:
        name: "."
        forward-addr: 84.200.69.80      #DNS.WATCH
        forward-addr: 84.200.70.40      #DNS.WATCH
        forward-addr: 51.254.25.115     #opennic

In any case, remember that, as long as DNSSEC is enabled, DNSSEC verification will be attempted in any DNS query Unbound initiates, including queries that use forward servers. If you select forward servers that don't support DNSSEC, the queries will fail because verification is not possible, and your whole name resolution system will become inoperative. As demonstrated in Listing 3, you can disable DNSSEC validation for domains and zones that are problematic.

Blacklists

One big reason for running your own DNS server is to be able to blacklist sites you don't want the users of your LAN to visit. In a home environment, that's advertisers. In a small office, that might include time-wasting sites, such as social networks or digital sport journals. Your easiest option is to return bogus addresses or NXDOMAIN messages when asked about domains you don't want users to visit.

Something important to take into account is that DNS blacklisting is easy to set up but also very easy to bypass. Users in your LAN may try to configure their computers to use a different DNS server, use Tor, set up a VPN, or use a web proxy. A user can also bypass DNS if they already know the target IP address. A DNS blacklist thus works best when it is combined with other measures.

A simple way of blacklisting a domain is to add an entry like the following to your Unbound configuration:

local-zone: "example.org" always_nxdomain

When a client asks the Unbound server where example.org is, it will get an NXDOMAIN response.

Adding hosts manually to the configuration files can be tiresome. If you want to have good malware, phishing, and advertisement protection, getting an existing list of bad domains and adapting the list to Unbound is a good start. Many good lists of bad domains exist on the Internet. The StevenBlack blacklist [9] is very complete, so I will use it as a demonstration. The following commands will download the list and convert it to Unbound format:

$ curl -o hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts
$ su
[password]
# grep '^0\.0\.0\.0' hosts |
awk '{print "local-zone: \""$2"\"always_nxdomain"}' > /etc/unbound/unbound.conf.d/blacklist.conf

The Steven Black site has some tools for customizing the list, which are totally worth the time it takes to check them out.

Configuring Local Zones

Suppose you have a printer in your LAN. You can connect to that printer by using its known IP address, like, for example, 192.168.1.2. However, wouldn't you rather give a human readable name to that printer?

Unbound is not an authoritative server, so it cannot manage a full zone with all its bells and whistles directly. However, it has horsepower enough for managing a small home LAN. Listing 6 shows an example configuration for a home LAN zone. It assumes that the LAN is using 192.168.1.0/24 as the network.

Listing 6

local_names.conf

# /etc/unbound/unbound.conf.d/local_names.conf
private-address: 192.168.1.0/24
local-zone: "mylan.dyn." static
        local-data: "gateway.mylan.dyn. IN A 192.168.1.1"
        local-data: "printer.mylan.dyn. IN A 192.168.1.2"
        local-data: "computer.mylan.dyn. IN A 192.168.1.3"
        local-data: "server.mylan.dyn. IN A 192.168.1.100"
        local-data-ptr: "192.168.1.1 gateway.mylan.dyn"
        local-data-ptr: "192.168.1.2 printer.mylan.dyn"
        local-data-ptr: "192.168.1.3 computer.mylan.dyn"
        local-data-ptr: "192.168.1.100 server.mylan.dyn"

The private-address directive prevents addresses in your LAN from being returned for public Internet names. This step prevents DNS rebinding attacks [10].

The local-zone directive defines all domains under mylan.dyn as local. The static word means that the static entries defined in the configuration file are used as DNS entries. Each of the local-data entries assigns a name to an address. For example, 192.168.1.2 would be assigned the name printer.mylan.dyn. If you queried the Unbound server for a name in the mylan.dyn zone that did not exist, it would be answered with a NXDOMAIN message. Alternatively, transparent could be used instead of static. A transparent local zone is one in which the server tries to resolve the name of a host by other means if it has no static entry for it in its configuration.

The local-data-ptr entries are optional and define reverse DNS information. Reverse DNS is, as the expression implies, the opposite of DNS. A reverse DNS query asks "What is the name of the host with the address 192.168.1.2?"

Configuring Access

Listing 7 shows how to grant access to the Unbound server to hosts on your LAN and to the machine running the server. This example assumes that the LAN sits at 192.168.1.0/24.

Listing 7

access_options.conf

# /etc/unbound/unbound.conf.d/access_options.conf
access-control: "0.0.0.0/0" allow
access-control: "127.0.0.0/8" allow
access-control: "192.168.1.0/24" allow

There are many good reasons for restricting access to your DNS server. The first one is that a DNS server may be used as part of a denial of service attack. A common technique is to send queries with spoofed IP addresses to exposed recursive DNS servers, which will send their responses to what they think is the computer that made the query in the first place. In practice, it means that an attacker can ask the recursive server for a DNS record using a fake IP, and the owner of the IP address that was faked will get the response. This means that an evil entity can force a recursive server to flood a victim with DNS responses and therefore use the server as a proxy for a denial of service attack. Another reason is that a local DNS server might contain sensitive DNS entries that are not intended to be known by outsiders. If you are using a local zone for naming local resources, such as printers, cameras, and NAS servers, it is better to have that information protected from outsiders.

In addition to the Unbound configuration presented here, it is a good idea to block access to your DNS server by using appropriate firewall rules. DNS servers listen for queries at port 53 and may support both UDP and TCP.

The access-control directives are self-explanatory.

Cache Configuration

For most home users, the best reason for using a local DNS server is caching DNS entries and speeding up web browsing. Listing 8 shows an example configuration for a simple, yet powerful, DNS cache.

Listing 8

cache_options.conf

# /etc/unbound/unbound.conf.d/cache_options.conf
prefetch: yes # Fetch things before they expire from cache.
prefetch-key: yes # Fetch DNSSEC keys early in the validation process.
cache-min-ttl: 1200 # Seconds it takes for items in cache to die at minimum.

Domain names have an official time to live assigned by the manager of that domain. This time to live is the time that recursive DNS servers are supposed to keep the DNS entries in their caches before deleting them. Imagine that your Unbound server resolved richard-falken.com, which at the time of this writing has a TTL of 86400 seconds. It would remember the DNS entry for richard-falken.com for 24 hours.

Some domains have very short TTLs. The cache-min-ttl directive in the example defines the minimum time a cached DNS entry will be allowed to live in the cache. If Unbound comes across a domain with a TTL shorter than 1200 seconds, the official TTL will be ignored, and 1200 seconds will be used instead. Beware that DNS entries that are conserved in the cache for too long may become stalled and outdated, which could be counterproductive and lead to problems. Use this directive wisely.

prefetch-key instructs Unbound to fetch DNSSEC keys earlier than usual in the DNSSEC validation process. It saves time at the expense of CPU load.

prefetch instructs the server to try to resolve cached entries that are about to expire from the cache in order to keep the cache fresh. This option might increase bandwidth consumption by about 10 percent, but response times will be better.

Privacy

Listing 9 has some privacy options. The most important is qname-minimisation. Enabling this option makes the queries sent by Unbound to other DNS servers more compact and less prone to leak private information.

Listing 9

privacy_options.conf

# /etc/unbound/unbound.conf.d/privacy_options.conf
hide-identity: yes # If enabled id.server and hostname.bind queries are refused.
hide-version: yes # If enabled version.server and version.bind queries are refused.
qname-minimisation: yes # Send minimum amount of information to upstream servers to enhance privacy.

hide-identity and hide-version are less relevant in LAN scenarios, since they prevent the DNS server from replying to internal special queries that attempt to obtain information, such as the hostname of the server or the software version.

Query Times

You may want to check the query times for a server provided by your ISP, another open DNS server on the Internet, or any server you configure on your own LAN.

Proper DNS benchmarking is difficult. A quick and dirty way to check the connection latency for a DNS server is using icmp echo requests with the ping utility:

$ ping -c 4 $address_of_server

The time stat for each reply indicates the time it took to get a "pong" response from the server. The bigger the time, the longer it takes for the server to reply to you when you ask it to.

The dig utility (Figure 3) performs name resolution, and it is very useful for retrieving DNS records and checking query times.

$ dig @$address_of_dns_server example.org
Figure 3: This command uses dig to test how quickly server 8.8.4.4 can give an answer.

If you are serious about benchmarking a DNS server, you will need heavier tools for the job. Google's namebench [11] is a popular option.

Finishing Up

When your configuration is ready, just boot your server up with the following command:

# /etc/init.d/unbound start

This command will bring up a caching DNS server with anti-advertisement, anti-malware, and anti-phishing capabilities, as well as a limited capability for validating the authenticity of the DNS responses it takes. Not bad at all.

The only task left to do is to configure the devices in your LAN to use this server. There are three main ways to do this. You can manually configure each one to use your DNS server, which is usually impractical. The second option is to configure your network router to assign your server via DHCP to each device that connects to the network. This is the easiest way, and it will work most of the time, as long as your router supports assigning custom DNS servers to the devices in your LAN.

There is a third, evil option, that I like to use when I have to deal with devices that will ignore DNS servers provided by DHCP. This method is to instruct the router to redirect queries to unauthorized DNS servers to your local DNS instance, using ds-nat. In practice, you are performing a man-in-the-middle attack by letting your local DNS server pretend to be the DNS server the rogue device is trying to connect to. This requires a router capable of advanced firewall configuration. But such mean deeds are the subject for another article.

The Author

Rubén Llorente is a mechanical engineer whose job is to ensure that the security measures for the IT infrastructure of a small clinic are law compliant and safe. He is also an OpenBSD enthusiast and a weapon collector.