Quantcast
Channel: Network – Weberblog.net
Viewing all articles
Browse latest Browse all 253

DNSSEC Validation with Unbound on a Raspberry

$
0
0
Unbound RPi featured image

To overcome the chicken-or-egg problem for DNSSEC (“I don’t need a DNSSEC validating resolver if there are no signed zones”), let’s install the DNS server Unbound on a Raspberry Pi for home usage. Up then, domain names are DNSSEC validated. I am listing the commands to install Unbound on a Raspberry Pi as well as some further commands to test and troubleshoot it. Finally I am showing a few Wireshark screenshots from a sample iterative DNS capture. Here we go:

It is really simple to operate an Unbound DNS resolver locally on a Raspberry Pi. Merely an installation and some config changes. That’s it. The Unbound package on a Raspbian Linux of Unbound validates DNSSEC by default. Great!

Installation

I am using an “old” Raspberry Pi 1 Model B with Raspbian GNU/Linux 7 (wheezy) and kernel 4.1.13+. The version of Unbound which comes with this OS is not the newest one (1.4.17-3+deb7u2), but it fits. The installation is really simple:

sudo apt-get update
sudo apt-get install unbound

The Unbound server starts automatically. Have look at the listening ports with:

pi@jw-pi01 ~ $ sudo netstat -tulpen | grep unbound
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      0          7312680     27897/unbound
tcp        0      0 127.0.0.1:8953          0.0.0.0:*               LISTEN      0          7312684     27897/unbound
tcp6       0      0 ::1:53                  :::*                    LISTEN      0          7312676     27897/unbound
tcp6       0      0 ::1:8953                :::*                    LISTEN      0          7312682     27897/unbound
udp        0      0 127.0.0.1:53            0.0.0.0:*                           0          7312678     27897/unbound
udp6       0      0 ::1:53                  :::*                                0          7312674     27897/unbound

Unbound works out of the box for queries from the localhost. In order to allow queries from any host, the configuration file must be edited. It is stored at

/etc/unbound/unbound.conf
 . Note that the config has already DNSSEC validation enabled!
pi@jw-pi01 /etc/unbound $ cat unbound.conf
# Unbound configuration file for Debian.
#
# See the unbound.conf(5) man page.
#
# See /usr/share/doc/unbound/examples/unbound.conf for a commented
# reference config file.

server:
    # The following line will configure unbound to perform cryptographic
    # DNSSEC validation using the root trust anchor.
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

Now, to allow queries add the following lines within the “server:” paragraph:

interface: 0.0.0.0
interface: ::0
access-control: 0.0.0.0/0 allow
access-control: ::0/0 allow

check the config:

pi@jw-pi01 ~ $ unbound-checkconf
unbound-checkconf: no errors in /etc/unbound/unbound.conf

and restart the server:

pi@jw-pi01 ~ $ sudo service unbound restart
[ ok ] Restarting recursive DNS server: unbound.

That’s it! To see a list of all configuration options click here. If you only wanted to install Unbound you’re already done!

-> The following information are only for further analysis etc.

Root Hints & Root Key

Unbound uses a list of the root servers as well as the root dnskey for its DNSSEC validation. Both should be updated regularly to avoid DNS problems in case of real root server changes. To update and use the root-hints file (for the list of root-servers), download the official list:

sudo curl -o /etc/unbound/root.hints https://www.internic.net/domain/named.root

and use it within the unbound.conf configuration file:

root-hints: "/etc/unbound/root.hints"

To update the root.key, use the simple “unbound-anchor” program which downloads the root.key file into /etc/unbound/:

sudo unbound-anchor

And change the auto-trust-anchor-file within the unbound.conf from the default to:

auto-trust-anchor-file: "/etc/unbound/root.key"

Restart Unbound:

sudo service unbound restart
 .

Done. (Click here for more information about the root.hints etc.)

Tests & Status

Here’s a basic test from another Linux machine that queries the Unbound server. Note the ad flag in line 8 which indicates the DNSSEC validation:

pi@ntp1:~ $ dig @192.168.7.5 weberdns.de +noadditional +noauthority

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @192.168.7.5 weberdns.de +noadditional +noauthority
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43402
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;weberdns.de.                   IN      A

;; ANSWER SECTION:
weberdns.de.            3600    IN      A       80.154.108.230

;; Query time: 19 msec
;; SERVER: 192.168.7.5#53(192.168.7.5)
;; WHEN: Thu Jun 09 17:23:21 CEST 2016
;; MSG SIZE  rcvd: 186

Of course, a failure in DNSSEC leads to a SERVFAIL (line 7) without any answer:

pi@ntp1:~ $ dig @192.168.7.5 fail03.dnssec.works

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @192.168.7.5 fail03.dnssec.works
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 42531
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;fail03.dnssec.works.           IN      A

;; Query time: 111 msec
;; SERVER: 192.168.7.5#53(192.168.7.5)
;; WHEN: Thu Jun 09 17:24:25 CEST 2016
;; MSG SIZE  rcvd: 48

Good.

In order to view the status of Unbound, use the following commands: 

unbound-control status
  and
unbound-control stats_noreset
 :
pi@jw-pi01 ~ $ sudo unbound-control status
version: 1.4.17
verbosity: 1
threads: 1
modules: 2 [ validator iterator ]
uptime: 11744 seconds
unbound (pid 28021) is running...
pi@jw-pi01 ~ $ sudo unbound-control stats_noreset
thread0.num.queries=120
thread0.num.cachehits=18
thread0.num.cachemiss=102
thread0.num.prefetch=0
thread0.num.recursivereplies=102
thread0.requestlist.avg=0.54902
thread0.requestlist.max=18
thread0.requestlist.overwritten=0
thread0.requestlist.exceeded=0
thread0.requestlist.current.all=0
thread0.requestlist.current.user=0
thread0.recursion.time.avg=0.201798
thread0.recursion.time.median=0.17367
total.num.queries=120
total.num.cachehits=18
total.num.cachemiss=102
total.num.prefetch=0
total.num.recursivereplies=102
total.requestlist.avg=0.54902
total.requestlist.max=18
total.requestlist.overwritten=0
total.requestlist.exceeded=0
total.requestlist.current.all=0
total.requestlist.current.user=0
total.recursion.time.avg=0.201798
total.recursion.time.median=0.17367
time.now=1465816919.018412
time.up=460.981236
time.elapsed=460.981236

To list the current values of options, e.g. the default values, use unbound-checkconf with the “-o parameter” option, such as:

pi@jw-pi01 ~ $ sudo unbound-checkconf -o use-syslog
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o verbosity
1
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-ip6
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-ip4
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-udp
yes
pi@jw-pi01 ~ $ sudo unbound-checkconf -o do-tcp
yes

To dump the cache for further investigations, use this:

pi@jw-pi01 ~ $ sudo unbound-control dump_cache | less
pi@jw-pi01 ~ $ sudo unbound-control dump_cache | grep webernetz.net

Per default, the log messages are sent to syslog. That is, they are stored in the default /var/log/syslog file which can be followed with:

pi@jw-pi01 ~ $ tail -f /var/log/syslog | grep unbound

To increase the verbosity level, add/change the verbosity line in the unbound.conf file. The default is “1”. A level of “2” already logs every DNS request. Use it for troubleshooting but be careful with it!

verbosity: 2

All other details about the Unbound options are listed here.

DNS Server on LAN

To use this Unbound DNS server for all clients in the LAN, it must be announced via DHCP as the DNS server. In my home network I have an AVM FRITZ!Box router which connects to the Internet via FTTH. The settings are as follows. I am using the static IPv4 address as well as the link-local IPv6 address as the DNS server address:

IPv4 local DNS server. And IPv6, too.

Tested from another Raspberry Pi, this leads to the following resolv.conf entries:

pi@ntp1:~ $ cat /etc/resolv.conf
# Generated by resolvconf
domain fritz.box
nameserver 192.168.7.5
nameserver fe80::ba27:ebff:fec9:1637%eth0

This is a test from a Linux client. Once more, note the “ad” flag in line 7:

pi@ntp1:~ $ dig pa.weberdns.de +noadditional +noauthority

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> pa.weberdns.de +noadditional +noauthority
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58151
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 5

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;pa.weberdns.de.                        IN      A

;; ANSWER SECTION:
pa.weberdns.de.         3592    IN      A       80.154.108.228

;; Query time: 10 msec
;; SERVER: 192.168.7.5#53(192.168.7.5)
;; WHEN: Thu Jun 09 16:45:47 CEST 2016
;; MSG SIZE  rcvd: 189

However, there are problems when querying the IPv6 address via the “-6” switch:

pi@ntp1:~ $ dig -6 dnssec.works

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> -6 dnssec.works
;; global options: +cmd
;; connection timed out; no servers could be reached

But it works when the link-local IPv6 address is specified (with the %eth0 interface suffix) directly:

pi@ntp1:~ $ dig @fe80::ba27:ebff:fec9:1637%eth0 dnssec.works +noadditional +noauthority

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @fe80::ba27:ebff:fec9:1637%eth0 dnssec.works +noadditional +noauthority
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48062
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;dnssec.works.                  IN      A

;; ANSWER SECTION:
dnssec.works.           3600    IN      A       5.45.109.212

;; Query time: 71 msec
;; SERVER: fe80::ba27:ebff:fec9:1637%2#53(fe80::ba27:ebff:fec9:1637%2)
;; WHEN: Thu Jun 09 16:48:44 CEST 2016
;; MSG SIZE  rcvd: 113

So maybe it’s not a good idea to use the link-local address for the DNS server. Maybe I will disable the “IPv6 DNS Server” option in my home network since the availability of a legacy IP DNS server perfectly fits for dual-stacked clients.

And a web browser GUI test to http://dnssec.vs.uni-due.de looks like that:

DNSSEC Resolver Test okGreat!

Sample Wireshark Screenshots

This is a small tcpdump capture on the Raspberry Pi, displayed with Wireshark. It shows an iterative (!) lookup of “licher.de” with its initial request from the client to the Raspberry Pi, the iterative lookup and the final answer to the client. Also note the “Statistics -> DNS” summary within Wireshark which can be used for troubleshooting, too:

Initial request from the client. Iterative query (1). Iterative query (2). Reply to the client. Wireshark DNS Statistics.

Conclusion

Now, all DNS answers are DNSSEC validated. Really all DNS answer? Well, actually, no. Only those which are DNSSEC signed. However, we solved the chicken-egg problem and are now able to validate DNSSEC answers.


Viewing all articles
Browse latest Browse all 253

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>