OpenWrt: DNS-Abfragen mit Stubby verschlüsseln
Im Allgemeinen erfolgen DNS-Abfragen standardmäßig unverschlüsselt über Port 53 (UDP/TCP). Wenn im Router (oder im verwendeten Endgerät) nicht anders eingestellt, werden dabei zumeist die DNS-Server des eigenen Internet-Service-Provider (ISP) kontaktiert. Um bei Bedarf die eigene Privatssphäre und Sicherheit zu erhöhen, kann es sich anbieten, den DNS-Datenverkehr zu verschlüsseln und hierzu öffentliche DNS-Server, die DNS-over-TLS (DoT) als auch DNSSEC unterstützen, zu verwenden. Wie sich das mit dem eigenen OpenWrt-Router in Verbindung mit Dnsmasq und Stubby umsetzen lässt, erfahrt ihr in diesem Beitrag.
Ausgangslage & Zielstellung
OpenWrt verwendet standardmäßig Dnsmasq als lokalen DNS-Forwarder, welcher lokal auf Port 53 lauscht und alle eingehenden DNS-Anfragen an einen der im System hinterlegten externen DNS-Server weiterleitet. Die ausgehende Weiterleitung an den externen DNS-Server erfolgt dabei unverschlüsselt über Port 53 (UDP/TCP).
Bei Stubby handelt es sich um einen DNS-Resolver, der DNS-Anfragen verschlüsselt per TLS an (externe) DNS-Server senden kann. Die Technik wird auch als DNS-over-TLS (DoT) bezeichnet. Als Standardport für DoT kommt der Port 853 (TCP) zum Einsatz. Prinzipiell gibt es bspw. mit DNS-over-HTTPS (DoH) aber auch noch andere Möglichkeiten zur DNS-Verschlüsselung.
Ginge es nur um die Funktionalität der DNS-Auflösung, dann könnte man Dnsmasq 1:1 durch Stubby ersetzen. Dnsmasq ist unter OpenWrt aber auch für DHCP zuständig. Aus diesem Grund bietet es sich an, Stubby zwischen Dnsmasq und externe DNS-Server zwischenzuschalten. In diesem Fall wird Dnsmasq so konfiguriert, dass alle DNS-Anfragen an Stubby durchgereicht werden. Stubby sendet die DNS-Anfragen dann verschlüsselt an einen der konfigurierten externen DNS-Server und gibt die Antwort an Dnsmasq zurück.
Mithilfe der Verschlüsselung der DNS-Abfragen kann sichergestellt werden, dass diese kein Dritter im Klartext mitlesen kann. Um aber auch die Integrität sowie Authentizität der DNS-Antworten sicherzustellen, sollte zusätzlich DNSSEC Verwendung finden. So kann sichergestellt werden, dass die DNS-Anfragen nicht manipuliert wurden.
Die Validierung der DNS-Antworten per DNSSEC kann sowohl durch Dnsmasq als auch durch Stubby erfolgen. "Out of the box" setzt OpenWrt ein abgespecktes Dnsmasq ohne vollständige DNSSEC-Unterstützung ein. Wenn man also Dnsmasq zur DNSSEC-Validierung verwenden möchte, muss man das Standard-Paket dnsmasq durch dnsmasq-full ersetzen. Um diesem Aufwand zu umgehen, verwende ich Stubby für die DNSSEC-Validierung, wobei Dnsmasq dann nur die DNSSEC-Informationen von Stubby zu den Clients durchreicht.
Für verschlüsselte und mit DNSSEC abgesichterte DNS-Abfragen muss der verwendete externe DNS-Server DoT und DNSSEC unterstützen. Eine Liste empfehlenswerter öffentlicher DNS-Server, die diese Bedingungen erfüllen, finden sich hier:
- Kuketz-Blog: Empfehlungsecke - DNS-Server
- Privacy Handbuch - DNS-Server
- DNS Privacy Project - DNS-Server
Stubby installieren & einrichten
Als erstes installieren wir Stubby auf unserem OpenWrt-Router:
opkg update
opkg install stubby
Anschließend öffnet die Konfigurationsdatei von Stubby /etc/config/stubby. Als erstes aktiviert nun DNSSEC:
config stubby 'global'
[...]
option dnssec_return_status '1'
[...]Danach könnt ihr die externen DNS-Server eintragen, die ihr verwenden möchtet:
[...]
# Upstream resolvers are specified using 'resolver' sections.
config resolver
option address '5.9.164.112'
option tls_auth_name 'dns3.digitalcourage.de'
list spki 'sha256/2WFzfO2/56HpeR+v/l25NPf5dacfxLrudH5yZbWCfdo='
config resolver
option address '2a01:4f8:251:554::2'
option tls_auth_name 'dns3.digitalcourage.de'
list spki 'sha256/2WFzfO2/56HpeR+v/l25NPf5dacfxLrudH5yZbWCfdo='
config resolver
option address '159.69.114.157'
option tls_auth_name 'fdns2.dismail.de'
list spki 'sha256/yJYDim2Wb6tbxUB3yA5ElU/FsRZZhyMXye8sXhKEd1w='
[...]Um die Konfiguration von Stubby abzuschließen, startet Stubby neu:
/etc/init.d/stubby restart
Dnsmasq einrichten
Im nächsten Schritt konfigurieren Dnsmasq nun so, dass alle DNS-Anfragen an Stubby weitergeleitet und die DNSSEC-Daten an die Clients durchreicht werden. Stubby lauscht dabei standardmäßig auf Port 5453. Öffnet die Konfigurationsdatei von Dnsmasq /etc/config/dhcp und fügt folgende Zeilen hinzu:
config dnsmasq
[...]
option noresolv '1'
option localuse '1'
option proxydnssec '1'
list server '127.0.0.1#5453'
[...]Wie bei Stubby starten wir nun auch Dnsmasq neu, damit die angepasste Konfiguration angewendet wird:
/etc/init.d/dnsmasq restart
Konfiguration überprüfen und DNS-Auflösung testen
Als erstes stellen wir sicher, dass sowohl Dnsmasq und Stubby auf den entsprechenden Ports lauschen:
netstat -ntlp | grep LISTEN
tcp 0 0 127.0.0.1:5453 0.0.0.0:* LISTEN 3829/stubby
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN 3316/dnsmasq
tcp 0 0 192.168.2.1:53 0.0.0.0:* LISTEN 3316/dnsmasq
tcp 0 0 ::1:5453 :::* LISTEN 3829/stubby
Zusätzlich könnten wir auch noch mal kurz das OpenWrt-Logging starten, Dnsmasq und Stubby neu starten und das Log überprüfen:
/etc/init.d/log restart
/etc/init.d/dnsmasq restart
/etc/init.d/stubby restart
Dnsmasq-Log auslesen:
logread -e dnsmasq
Thu Nov 17 10:32:54 2022 daemon.info dnsmasq[1]: started, version 2.86 cachesize 150
[..]
Thu Nov 17 10:32:54 2022 daemon.info dnsmasq[1]: using nameserver 127.0.0.1#5453
[...]
Stubby-Log auslesen:
logread -e stubby
Thu Nov 17 10:46:16 2022 daemon.err stubby[8619]: [09:46:16.380976] STUBBY: Stubby version: Stubby 0.4.0
Thu Nov 17 10:46:16 2022 daemon.err stubby[8619]: [09:46:16.420817] STUBBY: Read config from file /var/etc/stubby/stubby.yml
Thu Nov 17 10:46:16 2022 daemon.err stubby[8619]: [09:46:16.425964] STUBBY: DNSSEC Validation is ON
Thu Nov 17 10:46:16 2022 daemon.err stubby[8619]: [09:46:16.427872] STUBBY: Transport list is:
Thu Nov 17 10:46:16 2022 daemon.err stubby[8619]: [09:46:16.428511] STUBBY: - TLS
[...]
Wenn das dann alles gut aussieht, können wir die eigentliche DNS-Auflösung testen:
dig dnssectest.sidn.nl +dnssec +multi @127.0.0.1
; <<>> DiG 9.18.7 <<>> dnssectest.sidn.nl +dnssec +multi @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34087
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
;; QUESTION SECTION:
;dnssectest.sidn.nl. IN A
;; ANSWER SECTION:
dnssectest.sidn.nl. 3600 IN A 212.114.120.64
dnssectest.sidn.nl. 3600 IN RRSIG A 13 3 3600 (
20221125170928 20221110165616 39816 sidn.nl.
lRPpEt6j7qM9Fa/g/YYNA8wshfnhtKtRpt09gsGNto1y
CdvOcBJ6Z5YX11/nxbLQXGtU/pZks55Wto22DBlWlw== )
;; Query time: 99 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sat Nov 19 11:49:58 CET 2022
;; MSG SIZE rcvd: 166
Wichtig ist auch, dass in der Zeile mit flags das Flag ad gesetzt ist. Das bedeutet, dass die DNSSEC-Validierung funktioniert.
Den gleichen Befehl ausgeführt auf einem eurer Clients bzw. Endgeräte, die mit eurem OpenWrt-Router verbunden sind, sollten zum gleichen Ergebnis führen (Ausnahme: explizit anderer DNS-Server im Client konfiguriert).
Abschließend kann noch z.B. mittels https://dnsleaktest.com getestet werden, dass die von euch hinterlegten DNS-Server angefragt werden:

Optional: DNS-Hijacking
Die aktuelle Umsetzung hat einen Nachteil: Clients können die sichere und verschlüsselte DNS-Auflösung des Routers umgehen. Wenn auf Clientseite alternative DNS-Server explizit hinterlegt sind, kann es je nach verwendeter Software passieren, das der Client DNS-Anfragen nicht an den lokalen DNS-Server des Routers, sondern direkt an die auf Clientseite konfigurierten DNS-Server sendet. Um diesem Problem zu begegnen, kann man auf Routerseite sogenanntes DNS-Hijacking betreiben. Dazu werden alle DNS-Abfragen abgefangen und an den eigenen lokalen DNS-Forwarder/Resolver weitergereicht. Details hierzu siehe: OpenWrt-Doku: DNS-Hijacking
Optional: DNS-Leak beim Start verhindern
Es kann passieren, dass beim Start von OpenWrt bereits DNS-Abfragen nötig sind, noch bevor Dnsmasq und Stubby gestartet sind. In diesem Fall würden die DNS-Anfragen weiterhin an den DNS-Server des ISPs gesendet werden. Wenn man auch das verhindern möchte, muss man die DNS-Option für das WAN-Interface deaktivieren. Hierzu siehe z.B. Kuketz-Blog - Abschnitt: 4.2 DNS-Anfragen nicht an ISP-DNS übermitteln, wobei Folgendes beachtet werden sollte: https://github.com/openwrt/packages/issues/15765.
Fazit
Ohne großen Aufwand könnt ihr euren OpenWrt-Router mithilfe von Stubby so einrichten, dass DNS-Abfragen verschlüsselt und mit DNSSEC abgesichert durchgeführt werden.