DNSSEC-validatie met Unbound en DNSSEC-Trigger

Unbound is een validerende, recursieve, caching DNS resolver. De software wordt ontwikkeld door NLnet Labs en is als open source beschikbaar voor Unix-achtigen en Windows.

Heb je alleen een validerende resolver nodig, dan is Unbound waarschijnlijk een betere optie dan BIND named, de meest gebruikte (autoritatieve) DNS-server die ook als validerende resolver ingezet kan worden. Unbound is een compacte, dedicated resolver die is ontwikkeld om helemaal onafhankelijk van BIND te functioneren. SIDN heeft bijgedragen aan de ontwikkeling van Unbound, en gebruikt deze resolver zelf ook. Andere alternatieven voor BIND als resolver zijn de PowerDNS Recursor en de KNOT Resolver.

In dit artikel bespreken we de configuratie van Unbound op een Linux-systeem (in deel I). Daarbij beperken we ons niet tot de setup van een validerende resolver als basis onder een DNS-dienst die door een hele organisatie gebruikt kan worden. Unbound is namelijk ook bij uitstek geschikt voor validatie op een endpoint — dat wil zeggen op het werkstation of de laptop van een eindgebruiker. Vandaar dat we in dit artikel ook aandacht besteden aan de omleiding van de standaard POSIX/C stub resolver en het gebruik van systemctl (systemd), ondanks dat een deel van deze informatie voor een beheerder al bekend zal zijn.

In deel II bespreken we DNSSEC-Trigger, een tool om Unbound automatisch te (her)configureren bij gebruik als validator op een systeem waarvan de netwerkconfiguratie regelmatig wijzigt. Systeembeheerders kunnen dit gedeelte overslaan; DNSSEC-Trigger is vooral handig voor mobiele gebruikers. Beheerders van vaste systemen zullen de DNS-queries meestal direct via het configuratiebestand /etc/resolv.conf of indirect via de NetworkManager naar Unbound omleiden.

Inhoudsopgave

Deel I — Unbound

1 Linux

Unbound is inmiddels de standaard resolver op diverse Linux-distributies, alsook op FreeBSD and OpenBSD. Versie 7 van RHEL/CentOS bevat Unbound versie 1.6.6, terwijl RHEL/CentOS versie 6 al een poosje stilstaat op release 1.4.20.

Via de GhettoForge Plus of de Psychotic Ninja Plus repository kun je de laatste versies van Unbound voor RHEL/CentOS 7 downloaden/installeren.

Fedora versies 27 en 28 zijn voorzien van Unbound versie 1.7.3, terwijl versie 29 (nog in ontwikkeling) komt met de net gereleasde versie 1.8.1.

Voor deze beschrijving hebben we gebruikgemaakt van CentOS 7.5 (1804), zoals gezegd voorzien van Unbound versie 1.6.6. Voor de verschillen tussen de releases verwijzen we naar de Changelog van Unbound.

Voor de installatie en configuratie van Unbound op Windows is een aparte handleiding beschikbaar. Een handleiding voor thuisgebruikers en kleine netwerken vind je hier.

2 POSIX/C stub resolver

In de standaardconfiguratie van Linux en andere Unix-achtigen wordt de traditionele POSIX/C stub resolver gebruikt om host-namen te vertalen naar IP-adressen. Applicaties kunnen tegenwoordig wel de AD-vlag controleren die door de bevraagde caching resolver samen met het antwoord wordt aangeleverd [1, 2]. De POSIX/C stub resolver zelf doet echter geen DNSSEC-validatie of check op de AD-vlag. De stub resolver van Windows kan wel zo geconfigureerd worden dat deze domeinen blokkeert als de AD-vlag niet gezet is door de bevraagde resolver.

Ook als een stub resolver of applicatie de AD-vlag wel controleert, moeten gebruikers van een dergelijke configuratie ervan uitgaan dat het laatste stuk van het DNS-transport — namelijk dat tussen de caching resolver en de stub resolver op hun eigen computer — veilig is. In een bedrijfsnetwerk waar de lokale computers gebruikmaken van een centrale DNS-server zal dit in het algemeen ook geen veiligheidsproblemen opleveren. Maar gebruik je je laptop op een openbaar wifi-netwerk, dan is deze onbeschermde "last mile" weldegelijk een probleem. Dan is het gebruik van een validerende resolver op het endpoint — dat wil zeggen: op jouw eigen computer — sterk aan te raden. We komen hier verderop op terug bij de beschrijving van DNSSEC-Trigger.

3 Resolv.conf

De file '/etc/resolv.conf' is de spil in de configuratie van de POSIX/C stub resolver. De belangrijkste informatie in dat bestand is een lijst met te gebruiken nameservers (via achtereenvolgende 'nameserver' statements). Zijn er geen nameservers gedefinieerd, dan wordt localhost gebruikt.

Waar deze lijst vroeger handmatig werd opgesteld, worden de nameservers tegenwoordig meestal automatisch (via de NetworkManager) door de DHCP-client ingevuld. Dan ziet de inhoud van '/etc/resolv.conf' er bijvoorbeeld als volgt uit:

  # Generated by NetworkManager  
  search example.nl  
  nameserver 192.0.2.5

Alternatief is om een eigen lijst van publieke resolvers in te vullen, in dit geval van de 1.1.1.1 DNS service:

  nameserver 1.1.1.1  
  nameserver 1.0.0.1

En voor IPv6:

  nameserver 2606:4700:4700::1111  
  nameserver 2606:4700:4700::1001

4 NetworkManager

De configuratie van de resolver gaat het makkelijkst via de NetworkManager, de grafische tool voor de configuratie van het netwerk op Linux.

Zoals je in het window voor IPv6 kunt zien, kun je gebruik blijven maken van de automatische netwerkconfiguratie via DHCP, en daarbij toch je eigen nameservers specificeren. Daartoe dien je de 'DNS: Automatic' switch op 'off' te zetten.

  # Generated by NetworkManager  
  search example.nl  
  nameserver 1.1.1.1  
  nameserver 1.0.0.1  
  nameserver 2606:4700:4700::1111  
  # NOTE: the libc resolver may not support more than 3 nameservers.  
  # The nameservers listed below may not be recognized.  
  nameserver 2606:4700:4700::1001

Let op als je de file '/etc/resolv.conf' handmatig wijzigt dat deze overschreven wordt door de NetworkManager (die zijn configuratie opslaat in '/etc/sysconfig/network-scripts/').

5 Hook

Om een lokaal draaiende Unbound resolver te kunnen gebruiken, moeten we deze als hook installeren in de resolver-keten. Daartoe voegen we (via de NetworkManager) de 2 IP-adressen voor localhost toe aan de '/etc/resolv.conf' file. De eerder gedefinieerde nameservers fungeren nu als fallback.

  # Generated by NetworkManager  
  search example.nl  
  nameserver 127.0.0.1  
  nameserver 1.1.1.1  
  nameserver 1.0.0.1  
  # NOTE: the libc resolver may not support more than 3 nameservers.  
  # The nameservers listed below may not be recognized.  
  nameserver ::1  
  nameserver 2606:4700:4700::1111  
  nameserver 2606:4700:4700::1001

6 Unbound setup

De setup van Unbound zelf begint met de installatie van het RPM package:

  yum install unbound

Of op Fedora:

  dnf install unbound

Daarmee worden 4 systemd services op het systeem geïnstalleerd:

  • unbound-anchor.service

  • unbound-anchor.timer

  • unbound-keygen.service

  • unbound.service

7 Bootstrapping en RFC 5011

De unbound-anchor.service haalt de actuele root KSKtrust anchors voor DNSSEC binnen. Daarvoor maakt deze service gebruik van het 'unbound-anchor'-commando.

Bestaat de 'auto-trust-anchor-file' '/var/lib/unbound/root.key' nog niet, dan wordt deze geïnitieerd op basis van de hard in de software ingebouwde trust anchors. In ons geval is dit bestand al meegeleverd als onderdeel van het Unbound package.

Na deze eerste bootstrap zal de 'unbound-anchor.service' (getriggerd door de 'unbound-anchor.timer') elke dag middels het RFC 5011 protocol (ondersteund vanaf versie 1.4.0) bij de root servers controleren of er een nieuw trust anchor beschikbaar is (tracking). Is dat inderdaad het geval, dan wordt de handtekening van het DNSKEY record gecontroleerd en de betreffende sleutel als dynamisch trust anchor geïnstalleerd in de 'auto-trust-anchor-file'. De werking van het RFC 5011 protocol hebben we in dit artikel uitgebreider behandeld.

8 Fallback: RFC 7958

Lukt het om een of andere reden niet om op deze manier een geldig trust anchor geïnstalleerd te krijgen — de software is bijvoorbeeld verouderd of er zijn om veiligheidsredenen hele nieuwe sleutelparen voor de root geïntroduceerd — dan valt de 'unbound-anchor.service' terug op het RFC 7958 mechanisme. Daarbij worden de "well-known" trust anchors van de website van IANA binnengehaald en gevalideerd op basis van een certificaatketen van ICANN. Deze certificaten worden met het Unbound package meegeleverd als '/etc/unbound/icannbundle.pem', maar zijn als fallback ook hard ingebakken in de software.

Omdat de trust anchors de basis vormen onder de DNSSEC-validatie, geeft RFC 7958 een hele lijst van checks die je moet uitvoeren (of beter: laten uitvoeren door een installatie-script) alvorens een nieuw trust anchor als zodanig te accepteren. Het hele proces hebben we eerder beschreven in dit artikel.

9 KSK-2017 trust anchor

Het huidige trust anchor (KSK-2017) wordt met de Unbound-software meegeleverd vanaf versie 1.6.1 (in de file '/etc/unbound/root.key'). Maar ook in onze versie 1.4.0 zijn de actuele trust anchors al geïnstalleerd, in dit geval door de maintainer van het Unbound package voor RHEL/CentOS.

Controleer in elk geval of jouw nieuwe Unbound setup inderdaad ook is voorzien van een goed werkend KSK-2017 trust anchor. Dat begint bij het checken van de file '/etc/unbound/root.key' op de aanwezigheid van een publieke sleutel met key id 20326. Is dat om een of andere reden niet het geval, dan verwijzen we je naar de artikelenreeks zoals genoemd in dit bericht voor uitgebreide informatie over de root KSK roll-over en de installatie van het nieuwe trust anchor.

Heb je Unbound versie 1.6.5 of later, dan kun je het nieuwe trust anchor volgens RFC 7958 laten installeren door de file '/etc/unbound/root.key' weg te gooien en 'unbound-anchor' opnieuw te draaien. Voor oudere versies van Unbound moet je een ontbrekend KSK-2017 trust anchor handmatig installeren.

10 Meer trust anchors

Helemaal los van de root KSK trust anchors kun je additionele statische trust anchors installeren in de 'trust-anchor-file' (default: leeg), of in het configuratiebestand '/etc/unbound/unbound.conf' zelf middels de 'trust-anchor'-optie.

De 'unbound.service' bevat naast het commando voor het opstarten van de Unbound daemon zelf precies hetzelfde 'unbound-anchor' commando als de 'unbound-anchor.service'. Op die manier kunnen de trust anchors op een systeem up-to-date gehouden worden zonder dat Unbound in gebruik is, en wordt tegelijkertijd voorkomen dat Unbound opgestart wordt zonder dat de juiste trust anchors geïnstalleerd zijn.

Hoewel het RHEL/CentOS package ook het trust anchor voor ISC's oude DLV-dienst (Dynamic Lookaside Validation) meelevert (in de file /etc/unbound/dlv.isc.org.key), is die dienst inmiddels uitgefaseerd en buiten gebruik gesteld. In het standaard meegeleverde configuratiebestand staat de 'dlv-anchor-file'-optie al uitgecommentarieerd.

11 Unbound Control Key And Certificate Generator

Als laatste service is er nog de 'unbound-keygen.service' (de Unbound Control Key And Certificate Generator). Die wordt eenmalig uitgevoerd voor het aanmaken van de (self-signed) certificaten en sleutels voor het 'unbound-control'-commando. Daarmee kan Unbound over een TLS-beveiligde verbinding in run-time ge(her)configureerd worden (vergelijkbaar met BIND's 'rndc'-opdracht). Meer hierover verderop in dit artikel bij de beschrijving van DNSSEC-Trigger.

12 Opstarten

Hiermee zijn we aanbeland bij het activeren van de zojuist besproken services. Voordat we Unbound daadwerkelijk opstarten, checken we eerst wat de status van de verschillende services is:

[root@localhost ~]# systemctl status unbound.service unbound-anchor.service unbound-anchor.timer unbound-keygen.service
● unbound.service - Unbound recursive Domain Name Server
  Loaded: loaded (/usr/lib/systemd/system/unbound.service; disabled; vendor preset: disabled)
  Active: inactive (dead)
● unbound-anchor.service - update of the root trust anchor for DNSSEC validation in unbound
  Loaded: loaded (/usr/lib/systemd/system/unbound-anchor.service; static; vendor preset: disabled)
  Active: inactive (dead)
  Docs: man:unbound-anchor(8)
● unbound-anchor.timer - daily update of the root trust anchor for DNSSEC
  Loaded: loaded (/usr/lib/systemd/system/unbound-anchor.timer; disabled; vendor preset: disabled)
  Active: inactive (dead)
  Docs: man:unbound-anchor(8)
● unbound-keygen.service - Unbound Control Key And Certificate Generator
  Loaded: loaded (/usr/lib/systemd/system/unbound-keygen.service; disabled; vendor preset: disabled)
  Active: inactive (dead)

Hieruit blijkt dat alle 4 services op dit moment uitgeschakeld zijn en niet actief. Om op te starten geven we het volgende commando:

[root@localhost ~]# systemctl start unbound.service unbound-anchor.service unbound-anchor.timer unbound-keygen.service

En om te zorgen dat alles ook blijft lopen na een herstart van het systeem:

[root@localhost ~]# systemctl enable unbound.service unbound-anchor.service unbound-anchor.timer unbound-keygen.service
Created symlink from /etc/systemd/system/multi-user.target.wants/unbound.service to /usr/lib/systemd/system/unbound.service.
Created symlink from /etc/systemd/system/timers.target.wants/unbound-anchor.timer to /usr/lib/systemd/system/unbound-anchor.timer.
Created symlink from /etc/systemd/system/multi-user.target.wants/unbound-keygen.service to /usr/lib/systemd/system/unbound-keygen.service.

Controleren we nu de status van deze 4 services, dan zien we dat alles succesvol is verlopen, en dat alle services aangeschakeld (enabled) en actief zijn:

[root@localhost unbound]# systemctl status unbound.service unbound-anchor.service unbound-anchor.timer unbound-keygen.service
● unbound.service - Unbound recursive Domain Name Server
  Loaded: loaded (/usr/lib/systemd/system/unbound.service; enabled; vendor preset: disabled)
  Active: active (running) since Sat 2018-09-08 21:17:16 CEST; 2min 23s ago
  Main PID: 9746 (unbound)
    CGroup: /system.slice/unbound.service
            └─9746 /usr/sbin/unbound -d

Sep 08 21:17:15 localhost.localdomain systemd[1]: Starting Unbound recursive Domain Name Server...
Sep 08 21:17:16 localhost.localdomain unbound-checkconf[9741]: unbound-checkconf: no errors in /etc/unbound/unbound.conf
Sep 08 21:17:16 localhost.localdomain systemd[1]: Started Unbound recursive Domain Name Server.
Sep 08 21:17:16 localhost.localdomain unbound[9746]: [9746:0] notice: init module 0: ipsecmod
Sep 08 21:17:16 localhost.localdomain unbound[9746]: [9746:0] notice: init module 1: validator
Sep 08 21:17:16 localhost.localdomain unbound[9746]: [9746:0] notice: init module 2: iterator
Sep 08 21:17:16 localhost.localdomain unbound[9746]: [9746:0] info: start of service (unbound 1.6.6).

● unbound-anchor.service - update of the root trust anchor for DNSSEC validation in unbound
  Loaded: loaded (/usr/lib/systemd/system/unbound-anchor.service; static; vendor preset: disabled)
  Active: inactive (dead) since Sat 2018-09-08 21:17:15 CEST; 2min 23s ago
  Docs: man:unbound-anchor(8)
  Main PID: 9723 (code=exited, status=0/SUCCESS)

Sep 08 21:17:15 localhost.localdomain systemd[1]: Starting update of the root trust anchor for DNSSEC validation in ...nd...
Sep 08 21:17:15 localhost.localdomain systemd[1]: Started update of the root trust anchor for DNSSEC validation in unbound.

● unbound-anchor.timer - daily update of the root trust anchor for DNSSEC
  Loaded: loaded (/usr/lib/systemd/system/unbound-anchor.timer; enabled; vendor preset: disabled)
  Active: active (waiting) since Sat 2018-09-08 21:17:15 CEST; 2min 24s ago
  Docs: man:unbound-anchor(8)

Sep 08 21:17:15 localhost.localdomain systemd[1]: Started daily update of the root trust anchor for DNSSEC.
Sep 08 21:17:15 localhost.localdomain systemd[1]: Starting daily update of the root trust anchor for DNSSEC.

● unbound-keygen.service - Unbound Control Key And Certificate Generator
  Loaded: loaded (/usr/lib/systemd/system/unbound-keygen.service; enabled; vendor preset: disabled)
  Active: active (exited) since Sat 2018-09-08 21:17:15 CEST; 2min 23s ago
  Main PID: 9739 (code=exited, status=0/SUCCESS)
  CGroup: /system.slice/unbound-keygen.service

Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: unable to write 'random state'
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: e is 65537 (0x10001)
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: create unbound_server.pem (self signed certificate)
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: create unbound_control.pem (signed client certificate)
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: Signature ok
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: subject=/CN=unbound-control
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: Getting CA Private Key
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: unable to write 'random state'
Sep 08 21:17:15 localhost.localdomain unbound-control-setup[9722]: Setup success. Certificates created. Enable in unbo...use
Sep 08 21:17:15 localhost.localdomain systemd[1]: Started Unbound Control Key And Certificate Generator.
Hint: Some lines were ellipsized, use -l to show in full.

13 Resultaten

Kijken we wat er nu op ons systeem draait, dan zien we dat de Unbound daemon 4 threads ('num-threads: 4') heeft opgestart voor zowel UDP als TCP, en dat voor zowel IPv4 als IPv6. Daarnaast luistert Unbound voor beide IP-versies ook op TCP-poort 8953, de management-ingang voor 'unbound-control'.

 [root@localhost ~]# ps aux | grep unbound
unbound   9746  0.0  0.4 284228 33312 ?        Ssl  21:17   0:00 /usr/sbin/unbound -d

[root@localhost unbound]# ss -nlput | grep unbound
udp    UNCONN    0    0      127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=17))
udp    UNCONN    0    0      127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=13))
udp    UNCONN    0    0      127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=9))
udp    UNCONN    0    0      127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=5))
udp    UNCONN    0    0        ::1:53          :::*    users:(("unbound",pid=9746,fd=15))
udp    UNCONN    0    0        ::1:53          :::*    users:(("unbound",pid=9746,fd=11))
udp    UNCONN    0    0        ::1:53          :::*    users:(("unbound",pid=9746,fd=7))
udp    UNCONN    0    0        ::1:53          :::*    users:(("unbound",pid=9746,fd=3))
tcp    LISTEN    0    128    127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=18))
tcp    LISTEN    0    128    127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=14))
tcp    LISTEN    0    128    127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=10))
tcp    LISTEN    0    128    127.0.0.1:53       *:*    users:(("unbound",pid=9746,fd=6))
tcp    LISTEN    0    128    127.0.0.1:8953     *:*    users:(("unbound",pid=9746,fd=20))
tcp    LISTEN    0    128      ::1:53          :::*    users:(("unbound",pid=9746,fd=16))
tcp    LISTEN    0    128      ::1:53          :::*    users:(("unbound",pid=9746,fd=12))
tcp    LISTEN    0    128      ::1:53          :::*    users:(("unbound",pid=9746,fd=8))
tcp    LISTEN    0    128      ::1:53          :::*    users:(("unbound",pid=9746,fd=4))
tcp    LISTEN    0    128      ::1:8953        :::*    users:(("unbound",pid=9746,fd=19))

De 'unbound-keygen.service' heeft nieuwe sleutels en certificaten voor 'unbound-control' gegenereerd in de directory '/etc/unbound/':

  -rw-r-----. 1 root unbound  2459 Sep  8 21:17 unbound_control.key
  -rw-r-----. 1 root unbound  1330 Sep  8 21:17 unbound_control.pem
  -rw-r-----. 1 root unbound  2459 Sep  8 21:17 unbound_server.key
  -rw-r-----. 1 root unbound  1318 Sep  8 21:17 unbound_server.pem

En de trust anchors in de file '/var/lib/unbound/root.key' zijn gecontroleerd/opgewaardeerd:

; autotrust trust anchor file
;;id: . 1
;;last_queried: 1536434236 ;;Sat Sep  8 21:17:16 2018
;;last_success: 1536434236 ;;Sat Sep  8 21:17:16 2018
;;next_probe_time: 1536474633 ;;Sun Sep  9 08:30:33 2018
;;query_failed: 0
;;query_interval: 43200
;;retry_time: 8640
.    98799  IN    DNSKEY  257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU= ;{id = 20326 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1536235443 ;;Thu Sep  6 14:04:03 2018
.    98799  IN    DNSKEY  257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0= ;{id = 19036 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1536235443 ;;Thu Sep  6 14:04:03 2018

14 Goede werking

De bereikbaarheid van de Unbound daemon en zijn goede werking kunnen we op verschillende manieren controleren. We gebruiken 'dig' om te kijken of onze setup inderdaad bereikbaar is en zelfstandig valideert:

  [root@localhost ~]# dig @localhost example.nl +dnssec +multi

  ; <<>> DiG 9.9.4-RedHat-9.9.4-37.el7 <<>> @localhost example.nl +dnssec +multi
  ; (2 servers found)
  ;; global options: +cmd
  ;; Got answer:
  ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60799
  ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

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

  ;; ANSWER SECTION:
  example.nl.    3600 IN    A 94.198.159.35
  example.nl.    3600 IN    RRSIG A 5 2 3600 (
                            20180930184802 20180831175708 15516 example.nl.
                            lPbrdO4oHqwhuAcSMNY1fMAMdLLsPuoUmQKTF1UEk+cL
                            biFgYqrDixiinHIxp7D8AJdm7IHJ/KbxcqS9DSpHJUY9
                            Xx7lhDjobPkz1OnZw9Y9lSYfCowPBm0aIFwZL14DQxEO
                            Ybm2g+vVf8gU7S2T/JVN3Ijx4ZwaCHik2sf0ReM= )

  ;; Query time: 818 msec
  ;; SERVER: ::1#53(::1)
  ;; WHEN: Sat Sep 08 21:35:13 CEST 2018
  ;; MSG SIZE  rcvd: 225

Door de DO-vlag te zetten (DNSSEC OK) middels '+dnssec' voeren we een query uit waarbij we ook om validatie vragen. In het antwoord krijgen we de AD-vlag (Authentic Data) AD-vlag (Authentic Data) terug, wat betekent dat de resolver voor ons gevalideerd heeft. Naast de Resource Record set (RRset) is ook de digitale handtekening zelf (het RRSIG record) bijgevoegd.

Unbound biedt ook een alternatief voor 'dig', genaamd 'unbound-host'. Daarmee ziet bovenstaande query er als volgt uit:

  [root@localhost ~]# unbound-host -vDr example.nl
  example.nl has address 94.198.159.35 (secure)
  example.nl has IPv6 address 2a00:d78:0:712:94:198:159:35 (secure)
  example.nl mail is handled by 0 . (secure)

Maar let op: als je niet de 'D'-optie meegeeft (check DNSSEC), dan is het resultaat altijd insecure (wat dus niet noodzakelijk zo hoeft te zijn).

Helaas heeft dit commando niet de mogelijkheid om expliciet de te gebruiken DNS-server op te geven (zoals 'dig' met de '@'-optie doet).

15 Unbound configuratie-opties

Het configuratiebestand '/etc/unbound/unbound.conf' bestaat uit name/value-paren onderverdeeld in verschillende secties. De file die met het Unbound package voor RHEL/CentOS/Fedora wordt meegeleverd biedt een goed uitgangspunt voor een standaard setup. Zoals je in de file zelf kunt zien, wordt daarbij meestal vertrouwd op de default-waarden. De meegeleverde configuratie bevat vooral een heleboel uitleg en maar weinig ingeschakelde opties.

In de tabel hieronder hebben we de belangrijkste (server) configuratie-opties op een rijtje gezet.

Optie

Beschrijving

server:

num-threads:

aantal op te starten threads

num-queries-per-thread: <number>

maximaal aantal queries per thread

port: (default: 53)

poortnummer waarop beschikbaar

interface: (default: localhost)

netwerk-interface waarop beschikbaar

outgoing-interface: <IP address/range>

netwerk-interface voor uitgaande queries

outgoing-range: <number of ports>

aantal te openen poorten per thread

outgoing-port-permit: <port number/range>

te gebruiken reeks van uitgaande poorten

outgoing-port-avoid: <port number/range>

niet te gebruiken reeks van uitgaande poorten

cache-max-ttl: <seconds> (default: 1 day)

maximale TTL voor items in de cache

cache-min-ttl: <seconds>

minimale TTL voor items in de cache (default: 0; de TTL van de upstream DNS-server wordt gebruikt)

cache-max-negative-ttl: <seconds>

maximale TTL voor NXDOMAIN entries in cache

do-ip4: <yes|no> (default: yes)

gebruik IPv4 voor service en eigen queries

do-ip6: <yes|no> (default: yes)

gebruik IPv6 voor service en eigen queries

prefer-ip6: <yes|no> (default: no)

gebruik bij voorkeur IPv6

do-daemonize: <yes|no> (default: yes)

start unbound als daemon (default: yes)

access-control: <IP netblock> <action>

access control voor service; per adresblok; blokkeren, toestaan, wel/niet recursief (default: localhost mag alles); access control instellingen kunnen in groepen gedefinieerd worden (bijvoorbeeld voor verschillende localzones) m.b.v. tags, en die worden vervolgens aan acties gekoppeld

chroot: <directory>

het volledige pad naar het unbound configuratiebestand; alleen nodig als unbound in een chroot-omgeving draait

username: <username> (default: unbound)

verlaag gebruikersrechten na opstarten daemon

directory: <directory>

working directory

pidfile: <path>

locatie van de PID file

trust-anchor-signaling: <yes|no>

verstuur key id's van actieve trust anchors volgens RFC 8145

trust-anchor-file: <path>

file(s) met statische trust anchors (als DS/DNSKEY records)

trust-anchor: <key record>

statisch trust anchor (als DS/DNSKEY record)

trusted-keys-file: <path>

file(s) met statische trust anchors (in BIND 'trusted-keys'-formaat) ("/etc/unbound/keys.d/*.key")

auto-trust-anchor-file: <path>

locatie waar de (dynamische) trust anchors worden opgeslagen (via RFC 5011) ("/var/lib/unbound/root.key")

domain-insecure: <domain>

negatief trust anchor (domein wordt behandeld als zijnde onbeveiligd)

add-holddown: <seconds>

wachttijd voordat een nieuwe publieke sleutel (via RFC 5011) als trust anchor in gebruik genomen mag worden

del-holddown: <seconds>

wachttijd voor het verwijderen van een nieuwe publieke sleutel als deze niet meer zichtbaar is (via RFC 5011)

keep-missing: <seconds>

wachttijd voordat een trust anchor wordt verwijderd als deze niet meer zichtbaar is (via RFC 5011)

remote-control:

control-enable: <yes|no>

zet de management-ingang voor 'unbound-control' aan

control-interface: <IP address>

netwerk-interface waarop de management-ingang beschikbaar

control-port: <port number> (default: 8953)

poortnummer waarop de management-ingang beschikbaar

server-key-file: <path>

locaties van de certificaten en sleutels voor unbound en 'unbound-control'

server-cert-file: <path>

control-key-file: <path>

control-cert-file: <path>

Naast deze lijst bevat de Unbound-configuratie nog vele tientallen andere opties. Zo kun je bijvoorbeeld tweaken aan de instellingen voor de buffers en caches om de prestaties van je setup (de snelheid, schaalbaarheid en efficiëntie) te optimaliseren. Meer opties zijn er voor logging en allerlei protocol-specifieke switches. Maar daarvoor verwijzen we je naar de man page voor unbound.conf en de toelichting in het configuratiebestand zelf.

Hoewel alle opties in de '/etc/unbound/unbound.conf' file zelf zijn opgesomd en van commentaar zijn voorzien, zijn met name de finetuning-instellingen nog steeds behoorlijk obscuur voor niet-specialisten. Unbound werd om die reden ooit meer een academische exercitie dan een praktisch bruikbare DNS-resolver genoemd. Maar met de goed werkende standaardinstellingen en defaults is Unbound nu snel en makkelijk inzetbaar als validerende resolver voor zowel grote installaties als stand-alone computers.

Voor het verifiëren van de configuratiebestand is het commando 'unbound-checkconf' beschikbaar. Dat wordt ook automatisch gerund bij (voor) het opstarten van de 'unbound.service'.

16 Aandachtspunten voor deployment

Unbound ondersteunt weliswaar chroot (via de 'chroot' configuratie-optie), maar je moet de omgeving daarvoor wel zelf opzetten. Een chroot-versie van BIND named is wel als standaard pakket (bind-chroot) opgenomen in alle RHEL/CentOS/Fedora-repositories.

Normaal gesproken doet Unbound zelf recursieve resolving en validatie vanaf de root. Maar je kunt Unbound ook zo configureren dat deze voor zogenaamde Forward Zones gebruikmaakt van andere caching resolvers (voor de DNS records, niet voor de validatie zelf). Wil je dat instellen voor alle queries, dan specificeer je daartoe een 'forward-host' of 'forward-addr' voor de root zone.

Stub Zones lijken op de Forward Zones, maar wijzen naar (lokale) autoritatieve servers, waarvoor dus geen validatie hoeft te worden gedaan.

Op vergelijkbare wijze kun je ook Authority Zones opgeven en verwijzen naar een zone file (of een master server), waarvoor Unbound vervolgens als autoritatieve server fungeert.

Hieraan gerelateerd is de mogelijkheid om specifieke records voor bepaalde zones te definiëren middels 'local-zone' en 'local-data' statements, en daar ook verschillende acties aan te koppelen.

Hoewel je deze bijzondere zones ook direct in het configuratiebestand zelf kunt specificeren, is de (include) directory '/etc/unbound/local.d/' de geëigende locatie hiervoor.

17 Netwerkconfiguratie

Per default luistert Unbound alleen naar de loopback interface (localhost), waarmee deze resolver direct inzetbaar is op een persoonlijke computer. Wil je de daemon op alle interfaces laten luisteren, dan moet je daarvoor deze statements in de configuratie opnemen:

  server:
    interface: 0.0.0.0
    interface: ::0

Moet deze Unbound-installatie alleen het lokale netwerk bedienen, dan ziet de configuratie er bijvoorbeeld zo uit:

  server:
    interface: 192.0.2.5
    interface: 2001:db8::2:5

Vervolgens kun je ongewenst/onverwacht verkeer blokkeren als volgt:

  server:
    access-control: 192.0.2.0/24 allow
    access-control: 2001:db8::/64 allow

De interface voor de management-ingang configureer je op vergelijkbare wijze:

  remote-control:
    control-enable: yes
    control-interface: 127.0.0.1
    control-interface: ::1
    control-port: 8953

Vervolgens kun je de Unix-permissies op de certificaat- en sleutel-bestanden gebruiken om de toegang te regelen (client en server gebruiken dezelfde files).

18 Firewall

Rest ons alleen nog de firewall voor poort 53 (TCP en UDP) open te zetten. Op RHEL/CentOS/Fedora doe je dat het makkelijkst door de Firewall Configuration te openen: System -> Administration -> Firewall, en daar de Service 'dns' aan te vinken voor die Zones waarvoor je dit systeem als DNS-server wilt laten fungeren.

Vergeet daarbij niet deze configuratie te bewaren naar Permanent (in plaats van alleen Runtime).

19 Statistieken

Statistieken van je Unbound setup kun je verzamelen met behulp van Munin of Cacti. Hier lees je hoe je dat configureert. Een kant-en-klaar package hiervoor ('unbound-munin') is onderdeel van de Fedora-repository. Voor RHEL/CentOS versie 7 is een package beschikbaar via de eerder genoemde Ghettoforge Plus en Psychotic Ninja Plus repositories.

Deel II — DNSSEC-Trigger

Tot hier toe ging het vooral om de configuratie van Unbound als breed inzetbare validerende resolver in een statische omgeving — dat wil zeggen als DNS-server in een lokaal netwerk of als zelfstandig draaiende, validerende vervanger van de stub resolver op een server of vast werkstation. Voor netwerk- en systeembeheerders is de rest van dit artikel wellicht minder interessant. In dit laatste gedeelte behandelen we DNSSEC-Trigger, waarmee Unbound automatisch (via de management-ingang) geherconfigureerd wordt op het moment dat de netwerkinstellingen van het systeem veranderen. Zo kan Unbound ook op een laptop verbonden met wisselende wifi-netwerken voor end-to-end validatie ingezet worden.

Net als Unbound wordt DNSSEC-Trigger ook als open-source software ontwikkeld door NLnet Labs. Het pakket is er voor Linux, Windows en macOS. Voor die laatste 2 is Unbound integraal onderdeel van het DNSSEC-Trigger-pakket.

Voor de RHEL/CentOS-distributies zijn alleen oudere versies van DNSSEC-Trigger direct beschikbaar: release 0.11 voor RHEL/CentOS 7 en 0.10 voor RHEL/CentOS 6 (via de EPEL repository). Fedora versies 27, 28 en 29 zijn alle voorzien van release 0.15. Op moment van schrijven is release 0.16 de meest recente versie, maar deze is nog niet opgenomen in bovengenoemde repositories.

20 Werking

DNSSEC-Trigger is specifiek ontwikkeld om de Unbound validator ononderbroken zijn werk te laten doen. Dat houdt in dat de 'dnssec-triggerd' daemon bij veranderingen in de netwerkconfiguratie de Unbound-configuratie on-the-fly daarop aanpast (via het 'unbound-control'-commando).

Daarbij voert DNSSEC-Trigger via localhost achtereenvolgens verschillende tests uit (probes), net zo lang totdat er een werkende — dat wil zeggen validerende — configuratie tot stand is gekomen:

  • DNSSEC-Trigger probeert eerst de via DHCP aangeleverde (caching) resolvers te gebruiken. Daarbij wordt niet vertrouwd op AD-vlag meegeleverd met de DNS-antwoorden, maar worden de antwoorden en bijbehorende handtekeningen zelf gevalideerd. Op deze manier heb je wel end-to-end validatie, maar profiteer je van een gedeelde externe cache.

  • Lukt dit niet, dan wordt Unbound zo ingesteld dat deze via de autoritatieve nameservers zelf de hele recursie vanaf de root uitvoert.

  • Lukt het niet om via poort 53 naar buiten te gaan — typisch omdat het betreffende systeem achter een firewall zit — dan stuurt Unbound zijn DNS-queries naar een openbare DNS-dienst op poort 80.

  • Lukt dat ook niet, dan wordt hetzelfde nog eens geprobeerd via HTTPS op poort 443.

Succes betekent in dit geval dat DNSSEC-Trigger een bepaalde webpagina kan bereiken. Standaard wijst de configuratie naar een pagina onderhouden door NLnet Labs. Hetzelfde geldt voor de openbare DNS-dienst op poort 80 en 443: deze wijzen standaard naar een service — uiteraard gebaseerd op Unbound — aangeboden door NLnet Labs.

Kan DNSSEC-Trigger die speciale webpagina niet bereiken, dan wordt de gebruiker gevraagd of hij misschien eerst moet inloggen op een verwijspagina om het netwerk te activeren. Dergelijke setups worden vaak gebruikt bij publieke hotspots, waar men je eerst reclame of de gebruikersvoorwaarden wil voorschotelen voordat je het Internet op mag. Is dat ook niet het probleem, dan geeft DNSSEC-Trigger het op en biedt deze de gebruiker via een pop-up aan om DNSSEC-validatie tijdelijk uit te schakelen.

21 Opbouw

De opbouw van de DNSSEC-Trigger software lijkt op die van Unbound. Het RPM package installeert 3 systemd services op je systeem:

  • dnssec-triggerd-resolvconf-handle.service: Deze service roept een script aan dat de oude '/etc/resolv.conf' file bewaart bij het opstarten van DNSSEC-Trigger, en weer terugzet bij het afsluiten daarvan.

  • dnssec-triggerd-keygen.service: Deze dnssec-triggerd Control Key And Certificate Generator wordt (net als de 'unbound-keygen.service') eenmalig aangeroepen om het 'dnssec-trigger-control-setup'-commando uit te voeren. Dit script creëert vier files met certificaten en sleutels in de directory '/etc/dnssec-trigger/'. Deze worden gebruikt voor de toegang tot de 'dnssec-triggerd' daemon via het 'dnssec-trigger-control'-commando.

  • dnssec-triggerd.service: De DNSSEC-Trigger daemon 'dnssec-triggerd' wordt opgestart na het opstarten van de Unbound service.

De verbinding tussen DNSSEC-Trigger en de NetworkManager wordt gelegd door het script '/etc/NetworkManager/dispatcher.d/01-dnssec-trigger-hook'. Dat wordt aangeroepen elke keer als een netwerk-event wordt gesignaleerd.

Hoewel je DNSSEC-Trigger ook via de command line kunt beheren middels het 'dnssec-trigger-control'-commando, is het makkelijker om dat via het status icon (de 'dnssec-trigger-panel' applet) te doen. Deze applet sluit aan op 'dnssec-trigger-control' via een TLS-beveiligde verbinding. Je vindt het status icon van DNSSEC-Trigger in de Notification Area in de vorm van een anker.

22 Installatie en opstarten

Ook de installatie en configuratie van DNSSEC-Trigger zijn vergelijkbaar met die van Unbound. Hieronder zie je commando's voor de installatie, en het opstarten, bestendigen en controleren van DNSSEC-Trigger:

  yum/dnf install dnssec-trigger
  systemctl start dnssec-triggerd.service
      dnssec-triggerd-resolvconf-handle.service dnssec-triggerd-keygen.service
  [root@localhost ~]# systemctl enable dnssec-triggerd.service dnssec-triggerd-resolvconf-handle.service dnssec-triggerd-keygen.service
  Created symlink from /etc/systemd/system/dnssec-trigger.service to /usr/lib/systemd/system/dnssec-triggerd.service.
  Created symlink from /etc/systemd/system/multi-user.target.wants/dnssec-triggerd.service to /usr/lib/systemd/system/dnssec-triggerd.service.
  Created symlink from /etc/systemd/system/multi-user.target.wants/dnssec-triggerd-keygen.service to /usr/lib/systemd/system/dnssec-triggerd-keygen.service.
[root@localhost ~]# systemctl status dnssec-triggerd.service dnssec-triggerd-keygen.service dnssec-triggerd-resolvconf-handle.service
● dnssec-triggerd.service - Reconfigure local DNS(SEC) resolver on network change
  Loaded: loaded (/usr/lib/systemd/system/dnssec-triggerd.service; enabled; vendor preset: disabled)
  Active: active (running) since Thu 2018-09-20 13:46:21 CEST; 6s ago
  Process: 8615 ExecStopPost=/usr/bin/chattr -i /etc/resolv.conf (code=exited, status=0/SUCCESS)
  Process: 8850 ExecStartPost=/etc/NetworkManager/dispatcher.d/01-dnssec-trigger-hook (code=exited, status=0/SUCCESS)
  Main PID: 8849 (dnssec-triggerd)
    CGroup: /system.slice/dnssec-triggerd.service
            └─8849 /usr/sbin/dnssec-triggerd -d

Sep 20 13:46:21 localhost.localdomain 01-dnssec-trigger-hook[8850]: Global forwarders added: 127.0.0.1 1.1.1.1 1.0.0.1...001
Sep 20 13:46:21 localhost.localdomain systemd[1]: Started Reconfigure local DNS(SEC) resolver on network change.
Sep 20 13:46:22 localhost.localdomain dnssec-triggerd[8849]: ok

● dnssec-triggerd-keygen.service - dnssec-triggerd Control Key And Certificate Generator
  Loaded: loaded (/usr/lib/systemd/system/dnssec-triggerd-keygen.service; enabled; vendor preset: disabled)
  Active: active (exited) since Thu 2018-09-20 13:46:21 CEST; 7s ago
  Process: 8847 ExecStart=/sbin/restorecon /etc/dnssec-trigger/* (code=exited, status=0/SUCCESS)
  Process: 8826 ExecStart=/usr/sbin/dnssec-trigger-control-setup -d /etc/dnssec-trigger/ (code=exited, status=0/SUCCESS)
  Main PID: 8847 (code=exited, status=0/SUCCESS)
    CGroup: /system.slice/dnssec-triggerd-keygen.service

Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: subject=/CN=dnssec-trigger-control
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: Getting CA Private Key
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: unable to write 'random state'
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: Setup success. Certificates created.
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: run this script again with -i to:
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: - enable remote-control in unbound.conf
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: - start unbound-control-setup
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: - add root trust anchor to unbound.conf
Sep 20 13:46:21 localhost.localdomain dnssec-trigger-control-setup[8826]: if you have not done this already
Sep 20 13:46:21 localhost.localdomain systemd[1]: Started dnssec-triggerd Control Key And Certificate Generator.

● dnssec-triggerd-resolvconf-handle.service - Backups and restores /etc/resolv.conf after dnssec-trigger starts/stops
  Loaded: loaded (/usr/lib/systemd/system/dnssec-triggerd-resolvconf-handle.service; static; vendor preset: disabled)
  Active: active (exited) since Thu 2018-09-20 13:46:21 CEST; 7s ago
  Process: 8617 ExecStop=/usr/libexec/dnssec-triggerd-resolvconf-handle.sh restore (code=exited, status=0/SUCCESS)
  Process: 8827 ExecStart=/usr/libexec/dnssec-triggerd-resolvconf-handle.sh backup (code=exited, status=0/SUCCESS)
  Main PID: 8827 (code=exited, status=0/SUCCESS)
    CGroup: /system.slice/dnssec-triggerd-resolvconf-handle.service

Sep 20 13:46:21 localhost.localdomain systemd[1]: Starting Backups and restores /etc/resolv.conf after dnssec-trigge...ps...
Sep 20 13:46:21 localhost.localdomain systemd[1]: Started Backups and restores /etc/resolv.conf after dnssec-trigger...tops.
Hint: Some lines were ellipsized, use -l to show in full.

23 Resultaten

Na het uitvoeren van deze opdrachten heeft de 'dnssec-triggerd-keygen.service' nieuwe sleutels en certificaten voor 'dnssec-trigger-control' gegenereerd in de directory '/etc/dnssec-trigger/':

  -rw-r--r--. 1 root root 1277 Sep 20 13:46 dnssec_trigger_control.key
  -rw-r--r--. 1 root root  822 Sep 20 13:46 dnssec_trigger_control.pem
  -rw-r-----. 1 root root 1281 Sep 20 13:46 dnssec_trigger_server.key
  -rw-r--r--. 1 root root  810 Sep 20 13:46 dnssec_trigger_server.pem

De inhoud van de file '/etc/resolv.conf' zoals die eerder was gegenereerd door de NetworkManager is vervangen door een configuratie van DNSSEC-Trigger:

  # Generated by dnssec-trigger 0.11
  nameserver 127.0.0.1

En de DNSSEC-Trigger daemon is inderdaad actief:

[root@localhost ~]# ps aux |grep dnssec
root  30380  0.0  0.0  41156  3548 ?  Ss  22:37  0:00  /usr/sbin/dnssec-triggerd -d

Hier kunnen we tenslotte zien dat DNSSEC-Trigger voor zowel IPv4 als IPv6 luistert naar TCP-poort 8955, de management-ingang voor 'dnssec-trigger-control':

[root@localhost dnssec-trigger]# ss -nlput | grep dnssec
tcp    LISTEN    0    15    127.0.0.1:8955     *:*    users:(("dnssec-triggerd",pid=8849,fd=3))
tcp    LISTEN    0    15      ::1:8955        :::*    users:(("dnssec-triggerd",pid=8849,fd=3))

24 Configuratiebestanden

De configuratie van DNSSEC-Trigger bestaat uit 2 bestanden. De eerste is '/etc/dnssec.conf' en specificeert of de eerder genoemde Forward Zones wel of niet gevalideerd worden. Daarmee kun je een lokale caching resolver opzetten die niet alleen voor de RRsets en handtekeningen meelift met een upstream resolver maar ook voor de validatie.

Het bestand '/etc/dnssec-trigger/dnssec-trigger.conf' bevat de instellingen voor de DNSSEC-Trigger daemon, met daarin zaken als logging, de PID file, de chroot directory, diverse paden naar scripts en andere configuratiebestanden, en de instellingen voor de probes. De vorm van deze file is vergelijkbaar met het configuratiebestand van Unbound, maar deze is veel kleiner.

Voor beide configuratiebestanden geldt dat de standaard-instellingen een goed uitgangspunt vormen voor direct gebruik.

Conclusie

Met Unbound heb je een validerende resolver die in ieder geval op Linux een direct bruikbare default configuratie levert. De belangrijkste opties hebben we in dit artikel behandeld. Voor de details — en dat zijn er heel veel — verwijzen we je naar de uitgebreide documentatie op de website. Daar vind je ook meerdere installatie- en setup-handleidingen. Red Hat biedt nog een meer generieke documentatiepagina met informatie over DNSSEC en de installatie/configuratie van Unbound en DNSSEC-Trigger.

In combinatie met DNSSEC-Trigger biedt Unbound bovendien een hele makkelijke oplossing voor end-to-end validatie door mobiele gebruikers.