DNS over TLS in Debian

2017 schrieb ich über die Einrichtung von DNSCrypt in Debian, mittlerweile nutze ich aber DNS-over-TLS (DoT) mit einem eigenen server. Sowohl auf Server-, als auch auf Client-Seite nutze ich knot-resolver.

Einrichtung

Server

Zuerst muss das Paket knot-resolver installiert werden:

apt install knot-resolver

Danach muss /etc/knot-resolver/kresd.conf editiert werden:

net.listen('127.0.0.1', 53)
net.listen('IP4', 853, { kind = 'tls' })
net.listen('IP6', 853, { kind = 'tls' })
user('knot-resolver','knot-resolver')
cache.size = 2*GB

modules = {
  'view',
  'hints > iterate',
  'serve_stale < cache',
  'workarounds < iterate'
}

Statt IP4 und IP6 muss natürlich die IP-Adresse eingegeben werden, auf der der server über DoT erreichbar sein soll. Ggf. muss man natürlich auch noch den Port 853 in der firewall für Zugriffe von Außen freigeben.

Anschließend aktiviert man den server folgendermaßen:

systemctl enable --now kresd@{1..4}.service

Zugriff auf TLS-Zertifkate

Ohne weitere Konfiguration benutzt kresd selbstsignierte Zertifikate für DoT. Ich habe auf meinem server bereits Zertifikate von Let’s Encrypt und möchte diese auch für DoT nutzen. Um die Zertifikate für kresd erreichbar zu machen habe ich ein kleines Skript geschrieben:

cp /etc/letsencrypt/live/mdosch.de/privkey.pem /var/lib/knot-resolver
cp /etc/letsencrypt/live/mdosch.de/fullchain.pem /var/lib/knot-resolver
chown -R knot-resolver:knot-resolver /var/lib/knot-resolver 
chmod 700 /var/lib/knot-resolver
systemctl restart kresd@{1..4}.service

Die Pfade der Zertifikate sind natürlich anzupassen und das Skript muss nach dem Speichern ausführbar gemacht werden:

chmod +x /pfad/zum/script.sh

Damit das Skript auch ausgeführt wird wenn certbot die Zertifikate erneuert, lasse ich es mittels --renew-hook aufrufen.

Nun muss die Konfiguration abgeändert werden (Zeile 1) damit kresd die Zertifikate auch nutzt:

net.tls("/var/lib/knot-resolver/fullchain.pem", "/var/lib/knot-resolver/privkey.pem")
net.listen('127.0.0.1', 53)
net.listen('IP4', 853, { kind = 'tls' })
net.listen('IP6', 853, { kind = 'tls' })
user('knot-resolver','knot-resolver')
cache.size = 2*GB

modules = {    
  'view',                   
  'hints > iterate',         
  'serve_stale < cache',     
  'workarounds < iterate'
}

Danach muss kresd neu gestart werden:

systemctl restart kresd@{1..4}.service

Werbung und Tracking filtern

Ich möchte Werbung und Tracking direkt auf DNS-Ebene blocken und nutze dafür die Blocklisten von hBlock. Wenn man das hBlock-repo klont und dort make hosts ausführt erhält man u.a. eine Datei hosts_rpz.txt im Ordner dist. Diese Datei kann kresd einlesen und die dort gelisteten hosts bei DNS-Abfragen blockieren. Die Konfiguration muss folgendermaßen angepasst werden (Zeilen 13 und 16):

net.tls("/var/lib/knot-resolver/fullchain.pem", "/var/lib/knot-resolver/privkey.pem")
net.listen('127.0.0.1', 53)
net.listen('IP4', 853, { kind = 'tls' })
net.listen('IP6', 853, { kind = 'tls' })
user('knot-resolver','knot-resolver')
cache.size = 2*GB

modules = {    
  'view',                   
  'hints > iterate',         
  'serve_stale < cache',     
  'workarounds < iterate',
  'policy'
}

policy.add(policy.rpz(policy.DENY, '/pfad/zu/hosts_rpz.txt'))

Danach muss kresd wieder neu gestart werden:

systemctl restart kresd@{1..4}.service

Rekursives Blocken

Einige Trackingfirmen nutzen für ihre Kunden subdomains um die üblichen Schutzmaßnahmen zu umgehen, z.B. zn0lxkzethotizctx-bahn.siteintercept.qualtrics.com. Um den Schutz vor Tracking zu verbessern kann man auch rekursiv alle subdomains der domains in der Blockliste sperren.

Mit Hilfe von hBlock kann man eine Blockliste erstellen, die über wildcards auch die Subdomains umfasst:

hblock --output ./hosts_rpz.txt --header none --footer none --redirection '.' --template '%D CNAME %R\n*.%D CNAME %R' --comment ';' --filter-subdomains

Durch rekursives Blocken wird aber auch eine zufällig generierte subdomain in der Form <random>-dnsotls-ds.metric.gstatic.com geblockt, die bei Benutzung von DoT in Android genutzt wird. Um die resultierende Fehlermeldung in Android zu vermeiden wird diese subdomain gezielt erlaubt und folgendes in /etc/knot-resolver/kresd.conf eingetragen:

policy.add(policy.pattern(
	policy.PASS,
	'%w+%-dnsotls%-ds\006metric\007gstatic\003com\000$'
))

Client

Linux

Auf dem client muss ebenfalls das Paket knot-resolver installiert werden:

apt install knot-resolver

Die Konfiguration /etc/knot-resolver/kresd.conf gestaltet sich auf dem client recht simpel:

net.listen('127.0.0.1', 53, { kind = 'dns' })

modules = {
        'policy',
}

policy.add(policy.all(policy.TLS_FORWARD({
    {'5.181.50.75', hostname='mdosch.de'},
    {'2a03:4000:3f:1c8:8839:33ff:feba:fe4a', hostname='mdosch.de'},
})))

Die IPs und der hostname müssen natürlich gegen eure IPs und domain ausgetauscht werden.

Auch hier muss kresd aktiviert werden:

systemctl enable --now kresd@{1..4}.service

Anschließend muss man dem System mitteilen, den DNS-forwarder unter 127.0.0.1:53 zu nutzen. Das tut man indem man die Datei /etc/resolv.conf folgendermaßen editiert:

nameserver 127.0.0.1

Ggf. muss man noch den NetworkManager zähmen, damit dieser nicht die Datei /etc/resolv.conf überschreibt.

Android

Unter Android kann der DoT server folgendermaßen konfiguriert werden:

Einstellungen → Netzwerk & Internet → Erweitert → Privates DNS

Dort ist dann die domain, in meinem Fall z.B. mdosch.de, einzutragen.

Test

Zum testen kann man den Befehl dig aus dem Paket bind9-dnsutils nutzen. Mit z.B. dig debian.org bekommt man folgende Ausgabe:

dig debian.org      

; <<>> DiG 9.17.19-1-Debian <<>> debian.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13249
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;debian.org.			IN	A

;; ANSWER SECTION:
debian.org.		280	IN	A	128.31.0.62
debian.org.		280	IN	A	130.89.148.77
debian.org.		280	IN	A	149.20.4.15

;; Query time: 240 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sun Oct 31 11:00:57 CET 2021
;; MSG SIZE  rcvd: 87

Hier wurde die domain debian.org erfolgreich aufgelöst und die Zeile ;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP) zeigt, dass der lokale DNS-forwarder benutzt wurde.

Man kann natürlich auch Webseiten, wie z.B. dnsleaktest.com, benutzen um zu sehen welche DNS-server benutzt werden.

Mit dig google-analytics.com kann getestet werden ob das Blocken von Werbung und Tracking auch funktioniert:

dig google-analytics.com

; <<>> DiG 9.17.19-1-Debian <<>> @127.0.0.1 google-analytics.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 19517
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;google-analytics.com.		IN	A

;; Query time: 220 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Sun Oct 31 11:03:38 CET 2021
;; MSG SIZE  rcvd: 49

Hier wurde google-analytics nicht aufgelöst (status: SERVFAIL), die Blockliste wird also genutzt.

Updates

  • 2022-03-06: Abschnitt Rekursives Blocken hinzugefügt.

Inhalt

Teilen: E-Mail

Hinterlasse einen Kommentar oder diskutiere im OSBN-Chat.


In den Kommentaren können folgende Formatierungen genutzt werden.