Recently, our local Linux Users Group was talking about DNS servers.  Some folks in the group claimed that their ISP’s DNS servers were very slow.

In a group like this, there is usually a camp that are strong supporters of running BIND.  Somehow, I have never been able to wrap my head around BIND.  Instead, I have been using dnsmasq.  These two packages are very different.

BIND

BIND is a fully recursive DNS resolver.  When you look up a name like “www.cnn.com”, it goes to “com” to ask who “cnn” is, and then it goes to “cnn.com” to ask who “www.cnn.com” is.  BIND has a steep learning curve, and that has always discouraged me from really tinkering with it.  It also misses a very important point that my home network needs — local name resolution of DHCP-assigned addresses.

dnsmasq

Dnsmasq is more of a caching DNS server for a local network.  It has a built-in DHCP server, so devices on my home network get their addresses from dnsmasq.  When I make a DNS request, dnsmasq looks in its local DHCP table first.  For example, if I want to talk to another device in the same room, like a Roku or a printer, dnsmasq knows the addresses of the local devices and it responds immediately.  If the request is not a local name, it simply passes on the request to some other name server… maybe your ISP’s, or maybe a free server like OpenDNS or Google’s 8.8.8.8.  Dnsmasq caches all DNS requests, so if you make repeated requests to the same site, they are answered pretty quickly.

I really like dnsmasq.

It is super flexible, and you configure it through a single configuration file which is super easy to understand.  In fact, many home routers use dnsmasq under the hood.

unbound

But during the discussion in our LUG, someone mentioned unbound, another fully recursive DNS server that is super easy to set up.  So I had to try it out.  It did not disappoint.

My Setup

So how do these two tools work together?

Actually, it’s quite elegant.  Dnsmasq listens on port 53 of all addresses on my router.  It is the primary DNS server for all machines on my local network.  If the request is for a local device, then it fills the request immediately.  But if the request is for some site on the internet, then it passes the request off to unbound, which is also running on the router, but listening on a different address/port combination.

Here is how I configured dnsmasq.

/etc/dnsmasq.conf

# --- DNS ----------------------------

# Be a good netizen, keep local stuff local.
domain-needed
bogus-priv
filterwin2k

# Do not listen on "all" interfaces and just filter.
bind-interfaces
# Listen on port 53 on in-home network (eth1) and localhost (lo).
# Do not listen on internet interface (eth0).
interface=lo
interface=eth1

# Upstream servers are not listed in resolv.conf, they are listed here.
no-resolv
server=127.0.0.1#10053 # unbound

# Add this domain to all simple names in the hosts file.
# (Also sets the domain (15) option for DHCP).
expand-hosts
domain=home.alanporter.com

# Special treatments for some domains and hosts.
local=/local/ # dnsmasq handles these itself
server=/alanporter.com/69.93.127.10 # look up via ns1.linode.com
address=/doubleclick.net/127.0.0.1 # return this address immediately
address=/sentosa.us/108.161.130.139 # return this address immediately
cname=oldname.home.alanporter.com,newname.home.alanporter.com

# Logging
log-queries
log-facility=local1

# Caching
cache-size=1000

# --- DHCP ---------------------------

dhcp-range=FunkyNet,172.31.1.100,172.31.1.199,10m
dhcp-option=FunkyNet,1,255.255.255.0 # subnet mask - 1
dhcp-option=FunkyNet,3,172.31.1.1 # default router - 3
dhcp-option=FunkyNet,6,172.31.1.1 # DNS server - 6
dhcp-option=FunkyNet,15,home.alanporter.com # domain name - 15
dhcp-option=FunkyNet,28,172.31.1.255 # broadcast address - 28

dhcp-leasefile=/var/lib/dnsmasq.leases
read-ethers

# reserved names and addresses
dhcp-host=d8:5d:4c:93:32:41,chumby
dhcp-host=00:50:43:00:02:02,sheeva,172.31.1.3,10m

# --- PXE ----------------------------

dhcp-boot=pxelinux.0,bender,172.31.1.1

So dnsmasq listens on the local network for requests, answers what it can: local DHCP addresses, cached addresses and special overrides from the config file. And anything it can’t handle itself, it sends on upstream to unbound.

/etc/unbound/unbound.conf

server:
    # perform cryptographic DNSSEC validation using the root trust anchor.
    auto-trust-anchor-file: "/var/lib/unbound/root.key"
    # listen on local network, allow local network access
    interface: 127.0.0.1
    access-control: 127.0.0.0/8 allow
    # NOT listening on IPv6
    # interface: ::1
    # access-control: ::1 allow
    port: 10053
    # logging
    chroot: ""
    logfile: "/var/log/unbound.log"
    log-time-ascii: yes
    log-queries: yes
    verbosity: 2

As you can see, unbound does not require much configuration.

Notice that I am NOT listening on the IPv6 interface. It turns out, there is no need. Dnsmasq listens on both, and it forwards A requests and AAAA requests to unbound over an IPv4 connection on the local “lo” adaptor.

How it stacks up

So how well does this setup work? Are there advantages or disadvantages to using dnsmasq and unbound together?

Disadvantages

I tested this setup using “namebench“, a Google “20 percent” project that measures DNS lookup times. It told me that Google’s public DNS (8.8.8.8) was 250% faster than my in-home DNS. Furthermore, it said I would be better off using my ISP’s DNS servers. I am guessing that this is because these larger DNS servers cache a much larger pool of addresses, bypassing full recursive lookups of most common names.

Advantages of dnsmasq + unbound

If my setup is slower than using a single upstream DNS, then why should I run mine this way? I have a few reasons.

  • First and foremost, I learn a lot about DNS this way.
  • But also worth considering, ISP nameservers are notoriously flaky. Just because the ISP beat my nameserver on a single test, that does not mean it will always do so. That’s like comparing the bus to driving your own car… it might be better sometimes, but really bad other times.
  • One compelling reason to run a recursive DNS server like unbound is that you know you’re getting the right answer. When you use an ISP’s DNS server, they may hijack some domains and give you an incorrect answer on purpose. For example, they may censor content, and return a bogus landing page address for addresses that are on their black list. OpenDNS touts this as a feature… it is more “family-friendly” than raw DNS.
  • If you’re the tinfoil hat type, you might not want to use a DNS service from someone like Google, who makes their money from knowing more about your browsing habits than you do. Or from your ISP, who is always trying to up-sell you with something.

Advantages of dnsmasq + any upstream DNS

  • Dnsmasq (whether I use an upstream DNS or unbound) gives me control over how stuff is looked up. For example, when I was working on a new web site, I could tell dnsmasq to use the hosting company’s DNS for that one domain, so I did not have to wait for caches to expire between me and the host.
  • Dnsmasq caches lookups. Actually, unbound does, too. I am still playing with both.
  • Dnsmasq make switching DNS providers really easy. Say your ISP’s nameservers are acting up… just change one line in dnsmasq.conf and start getting results from somewhere else.