Configuring unbound as a local DNS server

Unbound is a validating, recursive, and caching DNS resolver written in C and much more lightweight than its predecessor, BIND. It was developed with a focus on security and an assumption that every host it interacts with could be malicious. BIND, in comparison, has become too bloated, slow and complicated to maintain. I expect to see more distributions follow FreeBSD 10 in making unbound the default DNS server implementation. For most small and local networks, unbound can serve as a very good alternative. For my local network with 5-6 hosts, unbound is perfect.

Before we go any further, lets take a quick look at the different types of DNS servers (caching, authoritative, recursive). The figure below shows 3 different DNS clients making queries against a DNS caching server representing 3 different flows that DNS queries can take. This is in no way complete, since clients could also query the recursive or authoritative servers directly. Most DNS servers can work in a combination of these 3 modes, and will not necessarily take on just a singular role.

  • Flow 1 (BLACK): A DNS client queries the caching server for a hostname and the DNS server contains this mapping in its cache. Its important to remember that all caching servers usually have a configurable TTL (or time to live) for any mapping and will periodically query a recursive or authoritative server to obtain this information. DNS cache poisoning attacks are based on the premise of feeding incorrect information to such caching servers and thus redirecting clients to potentially malicious sites.
  • Flow 2 (RED): In this flow, the caching DNS server does not have the information requested for in its cache so it requests for it from a recursive DNS server. This type of server will start from the “root” DNS servers requesting the information that the client has asked for, and will recursively query the servers until it finds an authoritative server for the requested domain. This flow can also represent the client directly asking a recursive DNS server for the information. The public Google DNS server (8.8.8.8) falls into this category.
  • Flow 3 (BLUE): This flow represents a client query wherein the caching server is aware of the authoritative server (it could be acting as an authoritative server for the requested domain as well).
DNS_Servers1

DNS query flows

A validating DNS server like unbound can also utilize the secure DNSSEC protocol to check that all queries against DNSSEC protected zones are digitally signed and identical to those of the zone owner or the authoritative server.

Lets now look at how we can configure unbound on FreeBSD 10. First, use the pkg command to install unbound:

pkg install unbound

The configuration file is located at /etc/unbound/unbound.conf. Configure the interface to listen to using the “interface” directive. 0.0.0.0 will instruct unbound to listen on all interfaces.


interface: 0.0.0.0

Setup clients that may make recursive queries:


access-control: 127.0.0.0/8 allow
access-control: 192.168.1.0/24 allow

To require DNSSEC data for trust-anchored zones, use the “harden-dnssec-stripped” option:


harden-dnssec-stripped: yes

Configure the TTLs for the DNS cache in seconds. It is good practice to not keep the minimum higher than an hour since it could result in reading stale data which might have changed. This could especially be the case for the hostname resolutions to dynamic IP addresses.


cache-min-ttl: 3600
cache-max-ttl: 86400

Performance tuning parameters to tune unbound depending on the number of clients that will depend on this server as well as the hardware on which it is running. My unbound server is on a 512MB 1vcpu VM and will only serve requests for clients within my home network, so I have deliberately tuned these down


num-threads: 2
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
rrset-cache-size: 128m
msg-cache-size: 32m
so-rcvbuf: 1m

Lets now setup the private domain which this DNS server will be an authority for. You should add all your local hosts that are present within your network for which this server will act as an authority for as local-data entries similar to below.


private-domain: "home.asrivas.me"
local-zone: "home.asrivas.me" static
local-data: "webserver.home.asrivas.me IN A 192.168.1.143"

One really useful aspect of running your own DNS server is the ability to block a number of ad servers by creating a blackhole for those domains. This is especially useful for mobile devices where it is difficult to configure ad-blocking. The following servers actually server majority of the ads over the internet:


local-zone: "doubleclick.net" redirect
local-data: "doubleclick.net A 127.0.0.1"
local-zone: "googlesyndication.com" redirect
local-data: "googlesyndication.com A 127.0.0.1"
local-zone: "googleadservices.com" redirect
local-data: "googleadservices.com A 127.0.0.1"
local-zone: "google-analytics.com" redirect
local-data: "google-analytics.com A 127.0.0.1"
local-zone: "ads.youtube.com" redirect
local-data: "ads.youtube.com A 127.0.0.1"
local-zone: "adserver.yahoo.com" redirect
local-data: "adserver.yahoo.com A 127.0.0.1"
local-zone: "ask.com" redirect
local-data: "ask.com A 127.0.0.1"

Lastly, you should setup forwarding queries to the appropriate public DNS server for queries that cannot be answered by this server:


forward-zone:
name: "."
forward-addr: 8.8.8.8 # Google Public DNS 1
forward-addr: 8.8.4.4 # Google Public DNS 2
forward-addr: 4.2.2.4 # Level3 Verizon

Start the server using the rc.d script:


service local_unbound start

I would prefer to avoid posting my complete configuration file online but comment on this post or PM me if you want to take a look at it. Thanks for reading!

Leave a Reply

Your email address will not be published. Required fields are marked *