Blog-like notes

Dnssec-trigger on Slackware

Dnssec-trigger is a tool to enable DNSSEC validation on a desktop computer. It verifies that the host network DNS servers, as provided by DHCP, are able to perform DNSSEC validation, and instructs a local Unbound resolver to perform its own validation if necessary.

Dnssec-trigger needs a bit of integration within the system, as it needs to be informed of any change of network connectivity. It comes with the appropriate “hooks” for NetworkManager and Netconfig. I explain here how to install and integrate it within a Slackware system which uses neither of those.

Installation

I provide SlackBuild scripts for ldns (required for Unbound), Unbound, and Dnssec-trigger, you can use those instead of installing these programs from source manually. The SlackBuilds have been tested on Slackware64 14.0 and 14.1. They automatically create the appropriate user accounts and rc scripts.

If you use these SlackBuilds, you can skip this section and proceed with “Starting the local resolver” below.

Install ldns:

$ wget http://www.nlnetlabs.nl/downloads/ldns/ldns-1.6.16.tar.gz
$ tar xf ldns-1.6.16.tar.gz
$ cd ldns-1.6.16
$ ./configure --prefix=/usr --mandir=/usr/man --disable-static \
  --with-ca-files=/etc/ssl/certs/ca-certificates.crt --with-drill
$ make
# make install
# install -m 644 packaging/libldns.pc /usr/lib/pkgconfig/libldns.pc

Then install Unbound:

$ wget http://unbound.net/downloads/unbound-1.4.21.tar.gz
$ tar xf unbound-1.4.21.tar.gz
$ cd unbound-1.4.21
$ ./configure --prefix=/usr --mandir=/usr/man --disable-static \
  --with-conf-file=/var/lib/unbound/unbound.conf \
  --with-run-dir=/var/lib/unbound \
  --with-pidfile=/var/run/unbound.pid
$ make
# make install

Create a rc script to control the resolver daemon, in /etc/rc.d/rc.unbound:

#!/bin/sh

case "$1" in
start)
  /usr/sbin/unbound-control start
  ;;

stop)
  /usr/sbin/unbound-control stop
  ;;

reload)
  /usr/sbin/unbound-control reload
  ;;

status)
  /usr/sbin/unbound-control status
  ;;

*)
  echo "Usage: $0 {start|stop|reload|status}" 1>&2
  exit 1
  ;;
esac

Create a dedicated user account to run Unbound:

# groupadd -g 281 unbound
# useradd -u 281 -c Unbound -d /var/lib/unbound -g unbound unbound
# mkdir -p /var/lib/unbound
# chown unbound:unbound /var/lib/unbound

Finally, install Dnssec-trigger:

$ wget http://www.nlnetlabs.nl/downloads/dnssec-trigger/dnssec-trigger-0.11.tar.gz
$ tar xf dnssec-trigger-0.11.tar.gz
$ cd dnssec-trigger-0.11
$ ./configure --prefix=/usr --mandir=/usr/man \
  --with-hooks=none --with-keydir=/var/lib/dnssec-trigger \
  --with-config=/etc/dnssec-trigger.conf \
  --with-unbound-control=/usr/sbin/unbound-control
$ make
# make install

and the /etc/rc.d/rc.dnssec-triggerd control script:

#!/bin/sh

PIDFILE=/var/run/dnssec-trigger.pid

case "$1" in
start)
  /usr/sbin/dnssec-triggerd
  ;;

stop)
  /usr/sbin/dnssec-trigger-control stop
  ;;

status)
  if [ -f $PIDFILE ] && kill -0 $(cat $PIDFILE) 2>/dev/null ; then
    echo "dnssec-triggerd is running."
  else
    echo "dnssec-triggerd is not running."
  fi
  ;;

*)
  echo "Usage: $0 {start|stop|status}" 1>&2
  exit 1
  ;;
esac

Starting the local resolver

Before starting the Unbound resolver, run once the following couple of commands to setup the root trust anchor needed for DNSSEC validation, and to create the keys needed to control the daemon:

# /usr/sbin/unbound-anchor
# /usr/sbin/unbound-control-setup

Dnssec-trigger will also needs the same kind of initialization:

# /usr/sbin/dnssec-trigger-control-setup

Edit Unbound’s configuration file in /var/lib/unbound/unbound.conf to specify the location of the trust anchor file (just uncomment the corresponding line in the default configuration file) and to enable remote control:

server:
  auto-trust-anchor-file: "/var/lib/unbound/root.key"
…
remote-control:
  control-enable: yes

Now, you need to start the resolver daemon at bootup. On Slackware, the usual place to start daemons not provided by the core distribution is /etc/rc.d/rc.local, but this script is executed at the end of the init sequence and I think that in the case of Unbound, it is better to start the daemon at the same time the network is setup.

In fact, when used together, Unbound and Dnssec-trigger should be started after the loopback interface is made available (so that they can bind to a localhost socket), but before any physical interface is brought up (so that the daemons are already running when we receive a DHCP answer). Consequently, I suggest to start them somewhere in /etc/rc.d/rc.inet1, at the end of the lo_up function (which brings up the loopback interface):

lo_up() {
  if grep lo: /proc/net/dev 1> /dev/null ; then
    if ! /sbin/ifconfig | grep "^lo" 1> /dev/null ; then
      /sbin/ifconfig lo 127.0.0.1
      /sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo

      # Start local resolver
      if [ -x /etc/rc.d/rc.unbound ]; then
        /etc/rc.d/rc.unbound start
      fi
      if [ -x /etc/rc.d/rc.dnssec-triggerd ]; then
        /etc/rc.d/rc.dnssec-triggerd start
      fi
    fi
  fi
}

Then, as usual on Slackware, you decide whether you want to enable the daemons by setting (or not) the executable bit on the /etc/rc.d/rc.unbound and /etc/rc.d/rc.dnssec-triggerd scripts.

Automatic configuration of DNS forwarders

Once the daemons are in place, you need to modify the configuration of the DHCP client (dhcpcd). First, you must prevent it to fill the /etc/resolv.conf file with the addresses of the nameservers provided by the DHCP server—with Dnssec-trigger, the only nameserver that should be listed in this file is the Unbound resolver on localhost—, and second, you must instruct it to send instead the nameservers’ addresses to the Dnssec-trigger daemon so that it can test their DNSSEC capabilities.

Edit dhcpcd’s configuration file /etc/dhcpcd.conf and disable the resolv.conf hook script:

nohook resolv.conf

Then create (or modify, if you already have one) an “exit hook” script (/etc/dhcpcd.exit-hook that will be executed by dhcpcd upon each DHCP event. In this script, send the addresses of the nameservers (contained in the new_domain_name_servers, in the script’s environment) to the Dnssec-trigger daemon using the dnssec-trigger-control(8) command:

#!/bin/sh

if [ "x$reason" = xBOUND ]; then
  if [ -n "$new_domain_name_servers" ]; then
    /usr/sbin/dnssec-trigger-control submit "$new_domain_name_servers"
  fi
fi

That’s it. Now Dnssec-trigger will evaluate the DNSSEC awareness of the DHCP-provided nameservers and instruct Unbound to use them as forwaders (thus acting only as a caching nameserver) if they are DNSSEC-capable, or if they are not, to use directly the authority servers and to do the validation itself.