Frederic Cambus

Home · Archives · Text Mode · GitHub · Twitter · RSS

DNSSEC validation at the router level with OpenWrt

· DNS

Over the past few years, I have been exploring various options for doing local DNSSEC validation. Validating locally is necessary in order to avoid DNS answers being forged on the path from the ISP resolvers (or from open validating resolvers) to the local network.

If validating on servers and laptops is a solved problem, doing so on mobile devices such as phones and tablets is still an open question. For these use cases, having a validating resolver running directly on a router is convenient. As it turns out, it's a pretty simple two steps process to achieve this with OpenWrt.

Disabling Dnsmasq DNS component

Dnsmasq is used within OpenWrt as both DHCP and DNS server, but we only want to use its DHCP component and let Unbound perform DNS resolution.

For doing so, after logging into LuCI, please go to: Network => DHCP and DNS => Advanced Settings.

Set the DNS server port to 0, as shown in the following screenshot:

Listening port for inbound DNS queries set to 0

Installing and configuring Unbound

Using opkg install:

opkg install unbound

The bundled init script supports the following commands:

/etc/init.d/unbound
Syntax: /etc/init.d/unbound [command]

Available commands:
	start	Start the service
	stop	Stop the service
	restart	Restart the service
	reload	Reload configuration files (or restart if that fails)
	enable	Enable service autostart
	disable	Disable service autostart

We start Unbound and enable autostart at boot time:

/etc/init.d/unbound start
/etc/init.d/unbound enable

We also need to fetch (or update) the root anchor manually:

opkg install unbound-anchor
unbound-anchor -a "/etc/unbound/root.key"

Configuring Unbound to validate answers:

# If you want to perform DNSSEC validation, run unbound-anchor before
# you start unbound (i.e. in the system boot scripts).  And enable:
# Please note usage of unbound-anchor root anchor is at your own risk
# and under the terms of our LICENSE (see that file in the source).
auto-trust-anchor-file: "/etc/unbound/root.key"

We can easily verify that our local Unbound instance is answering queries:

dig version.bind CH txt +short
"unbound 1.4.17"

Finally, let's try to resolve a DNSSEC secured domain:

dig statdns.net +dnssec

; <<>> DiG 9.8.3-P1 <<>> statdns.net +dnssec
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28028
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;statdns.net.			IN	A

;; ANSWER SECTION:
statdns.net.		594	IN	A	46.19.37.108
statdns.net.		594	IN	RRSIG	A 7 2 600 20150901000000 20140901115509 23348 statdns.net. bxWP9OzGs8v6gb9zEJHecQaBkU+BLKr8qRUi6VFPFVoKbZpHwiqkGatb rq7ov2AlnUrjs/a46xiu+bNNx8K9xQvY0f6QrBb/7RUPKPYSRNFiyLkb w9p92QFt5qr4LQL5kpddf/bnJYrVBDP3b6KZ2ph5X5x+C1hDq0HjgqZz EQg=

;; AUTHORITY SECTION:
statdns.net.		594	IN	NS	ns1.statdns.com.
statdns.net.		594	IN	NS	ns2.statdns.com.
statdns.net.		594	IN	RRSIG	NS 7 2 600 20150901000000 20140901115509 23348 statdns.net. FOEKRnI3VkI8EOmBj5xqqSKwdWwdFS24FroZMwBJisN4wSbDrz/EFWaa H0UqPZKKi0ViLM2z0sg1BfEvrDxFb2G4RDGpVsx6uh4BKXeaQ/1KK2Cc IF9gCSGvgyGZMCHd/DI0EeWRU9In3JK+YVI5AGA5qG2oY3IzQl4F1ho9 8RM=

;; Query time: 4 msec
;; SERVER: 10.0.0.1#53(10.0.0.1)
;; WHEN: Sat Oct  4 17:53:53 2014
;; MSG SIZE  rcvd: 445

As we notice, the AD flag is set in the header, meaning the answer is secure.