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.

Folgende Hardware bzw. Software wurde verwendet:
  • Spitz 4G LTE Smart Router - GL-X750C6
  • OpenWrt v22.03.2
  • Dnsmasq v2.86
  • Stubby v0.4.0
  • Notebook mit Arch Linux

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:

Stubby installieren & einrichten

Als erstes installieren wir Stubby auf unserem OpenWrt-Router:

opkg update
opkg install stubby
Terminal / Konsole

Anschließend öffnet die Konfigurationsdatei von Stubby /etc/config/stubby. Als erstes aktiviert nun DNSSEC:

config stubby 'global'
[...]
    option dnssec_return_status '1'
[...]
Datei: /etc/config/stubby

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='
[...]
Datei: /etc/config/stubby
Hinweis Konfiguration per UCI

Wenn ihr nicht direkt die Konfigurationsdateien bearbeiten möchtet, könnt ihr zum Konfigurieren auch die OpenWrt-API UCI verwenden:
OpenWrt-Doku: DoT with Dnsmasq and Stubby

Um die Konfiguration von Stubby abzuschließen, startet Stubby neu:

/etc/init.d/stubby restart
Terminal / Konsole

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'
[...]
Datei: /etc/config/stubby

Wie bei Stubby starten wir nun auch Dnsmasq neu, damit die angepasste Konfiguration angewendet wird:

/etc/init.d/dnsmasq restart
Terminal / Konsole

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
Terminal / Konsole

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
Terminal / Konsole

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
[...]
Terminal / Konsole

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
[...]
Terminal / Konsole

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
Terminal / Konsole

Wichtig ist auch, dass in der Zeile mit flags das Flag ad gesetzt ist. Das bedeutet, dass die DNSSEC-Validierung funktioniert.

Hinweis dig-Befehl unter OpenWrt verwenden

Damit dig unter OpenWrt verfügbar ist, muss das Paket bind-dig installiert sein.

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:

OpenWrt: DNS mit Stubby verschlüsseln

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.

Feedback

Für Feedback zum Beitrag, seien es Fragen, Korrigierungen und/oder Anregungen, könnt ihr mir gerne eine Nachricht per E-Mail oder Mastodon schreiben (siehe Kontakt).