Now that the root DNS servers are signed, I thought it was time I started using DNSSEC on my own PC. However, not wanting to wait for my ISP to enable it, I decided to setup a private recursive DNS resolver for myself using Unbound.

Installing Unbound

Being already packaged in Debian and Ubuntu, unbound is only an apt-get away:

apt install unbound ca-certificates

Optional settings

In /etc/unbound/unbound.conf.d/francois.conf, I enabled the following security options:

server:
    harden-below-nxdomain: yes
    harden-referral-path: yes
    harden-algo-downgrade: no # false positives with improperly configured zones
    use-caps-for-id: no # makes lots of queries fail
    hide-identity: yes
    hide-version: yes

and turned on prefetching to hopefully keep in cache the sites I visit regularly:

server:
    prefetch: yes
    prefetch-key: yes
    msg-cache-size: 128k
    msg-cache-slabs: 2
    rrset-cache-size: 8m
    rrset-cache-slabs: 2
    key-cache-size: 32m
    key-cache-slabs: 2
    cache-min-ttl: 3600
    num-threads: 2

Finally, I also enabled the control interface:

remote-control:
    control-enable: yes
    control-interface: 127.0.0.1

and increased the amount of debugging information:

server:
    val-log-level: 2
    use-syslog: yes
    verbosity: 1

before running sudo unbound-control-setup to generate the necessary keys.

Once unbound is restarted (sudo service unbound restart) stats can be queried to make sure that the DNS resolver is working:

unbound-control stats

Overriding DHCP settings

In order to use my own unbound server for DNS lookups and not the one received via DHCP, I added this line to /etc/dhcp/dhclient.conf:

supersede domain-name-servers 127.0.0.1;

and restarted dhclient:

sudo killall dhclient
sudo killall dhclient
sudo /etc/init.d/network-manager restart

If you're not using DHCP, then you simply need to put this in your /etc/resolv.conf:

nameserver 127.0.0.1

or on more recent distros, the following in /etc/systemd/resolved.conf:

[Resolve]
DNS=127.0.0.1
DNSSEC=no

Yes, you need DNSSEC=no because otherwise it will break insecure delegations and you'll see messages like this one in your logs:

systemd-resolved[1161]: DNSSEC validation failed for question dyn.fmarier.org IN SOA: no-signature

You can test that systemd-resolved is configured properly using:

systemd-resolve --status

Testing DNSSEC resolution

Once everything is configured properly, the best way I found to test that this setup was actually working is to use a web browser to visit these sites:

and using dig:

$ dig +dnssec A www.dnssec.cz | grep ad ;; flags: qr rd ra <b>ad</b>; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 1

Are there any other ways of making sure that DNSSEC is fully functional?

Using DNS-over-TLS using Cloudflare's 1.1.1.1

In order to make use of DNS over TLS and effectively hide DNS queries from anybody looking at your network traffic, one option is to forward your queries to Cloudflare's 1.1.1.1:

server:
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt

forward-zone:
    name: "."
    forward-tls-upstream: yes
    # 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

While Unbound appears to support DNS over TLS natively, it's not clear to me that it will connect to DNS servers over TLS while doing a recursive name resolution. Additionally, it will leak queries to non-encrypted servers to your ISP and other potential on-path attackers. Therefore, forwarding traffic to a non-logging trusted recursive resolver appears to be the best solution at the moment.

To test that DNS queries are being correctly forwarded to Cloudflare, use their official test page.

Integration with OpenVPN

If you are running your own OpenVPN server, you can tell clients to connect to the local unbound DNS client by putting the following in /etc/unbound/unbound.conf.d/openvpn.conf:

server:
    interface: 127.0.0.1
    interface: 10.8.0.1
    access-control: 127.0.0.1 allow
    access-control: 10.8.0.1/24 allow

the following in /etc/openvpn/server.conf:

push "dhcp-option DNS 10.8.0.1"
push "register-dns"

and opening the following port on your firewall (typically /etc/network/iptables.up.rules on Debian):

-A INPUT -p udp --dport 53 -s 10.8.0.0/24 -j ACCEPT

Then restart both services and everything should work:

systemctl restart unbound.service
systemctl restart openvpn.service