DNSSEC validation at the router level with OpenWrt

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 :

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

; EDNS: version: 0, flags: do; udp: 4096
;statdns.net.			IN	A

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

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
;; 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.

Window Maker Nostalgia

Window Maker is one of the very few graphical user interfaces which I would call timeless. Despite the fact it hasn’t evolved graphically for almost 20 years, it still looks clean and beautiful by today standards, whereas AfterStep now looks terribly old and outdated.

In fact, it is one of those very few intemporal interfaces which left a huge impact on me over the years :

  • Early Macintosh System Software on the Macintosh Plus, the first GUI I ever used in the mid-eighties
  • GEM (Graphical Environment Manager), customized CGA version on an Amstrad PC 1512
  • FVWM (F Virtual Window Manager), my first X11 love story
  • BeOS, in the late nineties, a clean, bright, and colorful UI which still looks crisp and modern

I loved the default BeOS color scheme so much that I’m using it as my Window Maker theme :

Window Maker running on FreeBSD 10.0, screenshot taken in March 2014

In retrospect, I have very fond memories of the few years during which I used it as my sole window manager, circa 15 years ago. Window Maker allowed the rest of us to experience NeXTSTEP.

Luarocks on FreeBSD

As LuaRocks is unfortunately not part of the FreeBSD ports collection, it has to be compiled manually. As I’m going to need to repeat this process in the foreseeable future, I decided to document the required steps here.

The reason why I’m targeting Lua 5.1 specifically is that I’m installing Luarocks to build rocks to be used with the Nginx Lua module, as I plan to migrate the Telize server to FreeBSD.

Installing Lua and some required packages

pkg install lua51 gmake curl

Fetching, unpacking, and configuring using Curl as downloader

curl -O http://luarocks.org/releases/luarocks-2.2.0.tar.gz
tar xvfz luarocks-2.2.0.tar.gz
cd luarocks-2.2.0
./configure --with-lua-include=/usr/local/include/lua51 --with-downloader=curl
make build && make install
make bootstrap

Building and installing some Lua modules

luarocks build lua-cjson
luarocks build lua-iconv

Verifying that our modules have been built and installed successfully

ls /usr/local/lib/lua/5.1
cjson.so    iconv.so

FreeBSD CheatSheet

Here are some notes on how to bootstrap a FreeBSD workstation and keep it up-to-date using binary packages and/or the ports collection.

System configuration

Setting the timezone

cp /usr/share/zoneinfo/Europe/Warsaw /etc/localtime

Setting an alternative keymap in console

The keymap directive should be set in rc.conf :


Performing binary updates for the base system

freebsd-update fetch
freebsd-update install

Using pkg

Since FreeBSD 10.0, pkg is now the default tool for installing binary packages. Legacy pkg_* tools are now depreceated.

Installing pkg

To install pkg, simply invoke it and confirm action :

The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]: y
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/freebsd:10:x86:64/latest, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
Installing pkg-1.3.8_2: 100%
Message for pkg-1.3.8_2:
 If you are upgrading from the old package format, first run:

  # pkg2ng
pkg: not enough arguments
Usage: pkg [-v] [-d] [-l] [-N] [-j <jail name or id>|-c <chroot path>] [-C <configuration file>] [-R <repo config dir>] [-o var=value] [-4|-6] <command> [<args>]

For more information on available commands and options see 'pkg help'.

Installing packages

pkg install package

Updating package repository catalogues

pkg update         

Performing upgrade of packages

pkg upgrade    

Using the ports collection

Fetching and extracting the ports collection

portsnap fetch extract

Updating the ports collection

portsnap fetch update

Compiling a port and cleaning working directory and dependencies

make -C /usr/ports/category/name install clean clean-depends

Using the X.Org Server

Installing required packages

pkg install xorg

Required configuration directives

The hald_enable and dbus_enable directives should be set in rc.conf :


Minimal .xinitrc to launch a Window Manager

exec /usr/local/bin/wmaker

Setting an alternative keymap for X

The setxkbmap directive should be set in .xinitrc :

setxkbmap fr

Setting background and font colors for xterm

The following directives should be set in .Xdefaults :

xterm*background: #000
xterm*foreground: #aaa
xterm*pointerColor: #aaa
xterm*cursorColor:  #aaa

Installing Fonts

Installing TrueType core fonts for the Web :

pkg install cabextract 
make -C /usr/ports/x11-fonts/webfonts install clean clean-depends

Then follow instructions displayed after installation :

Make sure that the freetype module is loaded.  If it is not, add the following
line to the "Modules" section of xorg.conf or XF86Config:

	Load "freetype"

Add the following line to the "Files" section of xorg.conf or XF86Config:

	FontPath "/usr/local/lib/X11/fonts/webfonts/"

Allowing Chromium to start

The kern.ipc.shm_allow_removed directive should be set in sysctl.conf :


Testing a JSON API with Curl

I’ve been working a lot on JSON APIs during the past few years, and even more intensively lately. If testing GET requests is straightforward, for POST requests I often had to look at Curl documentation again for exact options names and parameter syntax for sending the desired HTTP headers.

So I decided to post some quick notes on doing unauthenticated POST requests, in order to have a quickly accessible reference.

Here is a list of some relevant Curl options :

-d, --data DATA     HTTP POST data (H)
-X, --request COMMAND  Specify request command to use
-H, --header LINE   Custom header to pass to server (H)

Doing an empty POST request

curl --request POST

Posting JSON data

curl --request POST --data "{ \"ip\": \"\", \"country_code\": \"NL\", \"country_code3\": \"NLD\", \"country\": \"Netherlands\", \"continent_code\": \"EU\", \"latitude\": 52.5, \"longitude\": 5.75, \"dma_code\": \"0\", \"area_code\": \"0\", \"asn\": \"AS196752\", \"isp\": \"Tilaa V.O.F.\", \"timezone\":\"Europe/Amsterdam\" }" --header "Content-Type: application/json"

Posting JSON data from a file

curl --request POST --data @filename --header "Content-Type: application/json"

This is particularly handy when working with large JSON objects.

Lastly, for a fully client-side JSON validator and formatter, check JSON.fr.