+++
title = "using unbound and dnsmasq"
date = "2014-12-09T22:13:58+00:00"
author = "Gibheer"
draft = false
+++

After some time of using an [Almond](http://www.securifi.com/almond) as our router
and always having trouble with disconnects, I bought a small [apu1d4](http://www.pcengines.ch/apu1d4.htm),
an AMD low power board, as our new router.
It is now running FreeBSD and is very stable. Not a single connection was
dropped yet.

As we have some services in our network, like a fileserver and a printer, we
always wanted to use names instead of IPs, but not a single router yet could
provide that. So this was the first problem I solved.

FreeBSD comes with unbound preinstalled. Unbound is a caching DNS resolver, which
helps answer DNS queries faster, when they were already queried before. I
wanted to use unbound as the primary source for DNS queries, as the caching
functionality is pretty nice.
Further I wanted an easy DHCP server, which would also function as a DNS server.
For that purpose dnsmasq fits best. There are also ways to use dhcpd, bind and
some glue to get the same result, but I wanted as few services as possible.

So my setup constellation looks like this:

    client -> unbound -> dnsmasq
                 +-----> ISP dns server

For my internal tld, I will use zero. The dns server is called cerberus.zero and
has the IP 192.168.42.2. The network for this setup is 192.168.42.0/24.

## configuring unbound

For this to work, first we configure unbound to make name resolution work at
all. Most files already have pretty good defaults, so we will overwrite these
with a file in `/etc/unbound/conf.d/`, in my case `/etc/unbound/conf.d/zero.conf`.

    server:
      interface: 127.0.0.1
      interface: 192.168.42.2
      do-not-query-localhost: no
      access-control: 192.168.42.0/24 allow
      local-data: "cerberus. 86400 IN A 192.168.42.2"
      local-data: "cerberus.zero. 86400 IN A 192.168.42.2"
      local-data: "2.42.168.192.in-addr.arpa 86400 IN PTR cerberus.zero."
      local-zone: "42.168.192.in-addr.arpa" nodefault
      domain-insecure: "zero"

    forward-zone:
      name: "zero"
      forward-addr: 127.0.0.1@5353

    forward-zone:
      name: "42.168.192.in-addr.arpa."
      forward-addr: 127.0.0.1@5353

So what happens here is the following. First we tell unbound, on which addresses
it should listen for incoming queries.
Next we staate, that querying dns servers in localhost is totally okay. This is
needed to later be able to resolve addresses on the local dnsmasq. If your dnsmasq
is running on a different machine, you can leave this out.
With `access-control` we allow the network `192.168.42.0/24` to query the dns
server.
The next three lines tell unbound, that the name cerberus and cerberus.zero are one
and the same machine, the DNS server. Without these two lines unbound would not
resolve the name of the local server, even if its name would be stated in `/etc/hosts`.
With the last line we enable name resolution for the local network.
The key domain-insecure tells unbound, that this domain has no support for DNSSEC.
DNSSEC is enabled by default on unbound.

The two `forward-zone` entries tell unbound, where it should ask for queries regarding
the `zero` tld and the reverse entries of the network. The address in this case points
to the dnsmasq instance. In my case, that is running on localhost and port 5353.

Now we can add unbound to `/etc/rc.conf` and start unbound for the first time
with the following command

    $ sysrc local_unbound_enable=YES && service local_unbound start

Now you should be able to resolve the local hostname already

    $ host cerberus.zero
    cerberus.zero has address 192.168.42.2

## configuring dnsmasq

The next step is to configure dnsmasq, so that it provides DHCP and name resolution
for the network. When adjusting the config, please read the comments for each
option in your config file carefully.
You can find an example config in `/usr/local/etc/dnsmasq.conf.example`. Copy
it to `/usr/local/etc/dnsmasq.conf` and open it in your editor:

    port=5353
    domain-needed
    bogus-priv
    no-resolv
    no-hosts
    local=/zero/
    except-interface=re0
    bind-interfaces
    local-service
    expand-hosts
    domain=zero
    dhcp-range=192.168.42.11,192.168.42.200,255.255.255.0,48h
    dhcp-option=option:router,192.168.42.2
    dhcp-option=option:dns-server,192.168.42.2
    dhcp-host=00:90:f5:f0:fc:13,0c:8b:fd:6b:04:9a,sodium,192.168.42.23,96h

First we set the port to 5353, as defined in the unbound config. On this port
dnsmasq will listen for incoming dns requests.
The next two options are to avoid forwarding dns requests needlessly.
The option `no-resolv` avoids dnsmasq knowning of any other dns server. `no-hosts`
does the same for `/etc/hosts`. Its sole purpose is to provide DNS for the
local domain, so it needn't to know.

The next option tells dnsmasq for which domain it is responsible. It will also
avoid answering requests for any other domain.

`except-interfaces` tells dnsmasq on which interfaces _not_ to listen on. You
should enter here all external interfaces to avoid queries from the wide web
detecting hosts on your internal network.
The option `bind-interfaces` will try to listen only on the interfaces allowed
instead of listening on all interfaces and filtering the traffic. This makes
dnsmasq a bit more secure, as not listening at all is better than listening.

The two options `expand-hosts` and `domain=zero` will expand all dns requests
with the given domain part, if it is missing. This way, it is easier to resolv
hosts in the local domain.

The next three options configure the DHCP part of dnsmasq. First is the range.
In this example, the range starts from `192.168.42.11` and ends in `192.168.42.200`
and all IPs get a 48h lease time.
So if a new hosts enters the network, it will be given an IP from this range.
The next two lines set options sent with the DHCP offer to the client, so it
learns the default route and dns server. As both is running on the same machine
in my case, it points to the same IP.

Now all machines which should have a static name and/or IP can be set through
dhcp-host lines. You have to give the mac address, the name, the IP and the
lease time.
There are many examples in the example dnsmasq config, so the best is to read
these.

When your configuration is done, you can enable the dnsmasq service and start it

    $ sysrc dnsmasq_enable=YES && service dnsmasq start

When you get your first IP, do the following request and it should give you
your IP

    $ host $(hostname)
    sodium.zero has address 192.168.42.23

With this, we have a running DNS server setup with DHCP.
