Eigenen DoT/DoH DNS Resolver betreiben
Ich beschreibe euch wie ihr einen eigenen DNS Resolver inklusive DoT und DoH für die Namensauflösung im Internet aufsetzen könnt.
So wurde auch der adminForge Service: dnsforge.de konfiguriert.
Aufbau des Setups:
- dnsdist – DNS Loadbalancer: DNS Port 53, DoT Port 853, DoH Port 443
- Pi-hole – Werbeblocker: 127.0.0.1:53
- PowerDNS Recursor – auflösender Nameserver: 127.0.0.1:5300
Punkt 1: PowerDNS Repositories hinzufügen
Zuerst fügen wir die beiden Repositories von dnsdist und PowerDNS Recursor hinzu: https://repo.powerdns.com/
Beispiel Debian 11:
1 2 3 | apt-get update apt-get install gnupg curl https://repo.powerdns.com/FD380FBB-pub.asc | apt-key add - |
1 2 3 4 | cat <<EOF > /etc/apt/sources.list.d/powerdns.list deb [arch=amd64] http://repo.powerdns.com/debian bullseye-dnsdist-17 main deb [arch=amd64] http://repo.powerdns.com/debian bullseye-rec-47 main EOF |
Punkt 2: Pakete installieren
Wir installieren die beiden Pakete.
1 2 | apt-get update apt-get install dnsdist pdns-recursor |
Punkt 3: Pi-hole installieren
Wir starten mit der Installation des Werbeblockers Pi-hole.
1 | curl -sSL https://install.pi-hole.net | bash |
Wenn ihr die eine vollständige Pi-hole Installation haben möchtet, mit Webserver und Webinterface, dann drückt die Installation mit ENTER durch.
Das Pi-hole Admin Interface ist dann unter http://YOUR-IP/admin/ zu erreichen. Ich empfehle eine zusätzliche Absicherung des Webinterfaces!
Punkt 4: dnsdist konfigurieren
Kopiert diesen Text in die Konsole um eine dnsdist Konfiguration zu erstellen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | cat <<EOF > /etc/dnsdist/dnsdist.conf setLocal('YOUR-IPv4:53') addLocal('[YOUR-IPv6]:53') setACL({'0.0.0.0/0', '::/0'}) --addDOHLocal('YOUR-IPv4', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') --addDOHLocal('YOUR-IPv6', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') --addTLSLocal('YOUR-IPv4', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') --addTLSLocal('YOUR-IPv6', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') newServer({address='127.0.0.1:53', pool='recursor', checkInterval='300', checkTimeout='5', maxCheckFailures='3'}) -- Block hosts that exceeded 100 queries in 10 seconds for 30 minutes function maintenance() addDynBlocks(exceedQRate(100, 10), "Exceeded query rate", 1800) end addAction(AllRule(), PoolAction('recursor')) EOF |
Ersetzt dann eure IPv4 und IPv6 Adressen in den markieten Zeilen.
Für einen öffentlichen Resolver könnt ihr diese Befehle verwenden:
1 2 | IPV4=$(curl -s 4.ipwho.de/ip); sed -i 's/YOUR-IPv4/'$IPV4'/g' /etc/dnsdist/dnsdist.conf IPV6=$(curl -s 6.ipwho.de/ip); sed -i 's/YOUR-IPv6/'$IPV6'/g' /etc/dnsdist/dnsdist.conf |
Punkt 5: Let’s Encrypt
Für Let’s Encrypt verwende ich gerne acme.sh, ihr könnt aber auch gerne eigene Zertifikate oder andere Let’s Encrypt Scripte verwenden.
1 2 | apt-get install socat curl https://get.acme.sh | sh |
Einen Ordner für die Zertifikate legen wir in folgender Datei fest, ich empfehle den bereits vorhandenen Ordner /etc/ssl/private
.
1 | CERT_HOME="/etc/ssl/private" |
Nun holen wir uns ein Zertifikat.
WICHTIG: Eure Domain sollte bereits jetzt einen A-Record mit der IP-Adresse eures Servers haben und auflösen!
Variante 1 (Pi-hole mit Webserver):
1 | /root/.acme.sh/acme.sh --issue -k ec-384 -w /var/www/html -d domain.de --reloadcmd "systemctl restart dnsdist.service" |
Variante 2 (Pi-hole ohne Webserver):
1 | /root/.acme.sh/acme.sh --issue -k ec-384 --standalone -d domain.de --reloadcmd "systemctl restart dnsdist.service" |
Punkt 6: dnsdist DoT und DoH aktivieren
In der /etc/dnsdist/dnsdist.conf
entfernen wir die --
und ersetzen domain.de mit unserer Domain YOUR-DOMAIN.de
aus dem Schritt zuvor.
1 2 | sed -i 's/--add/add/g' /etc/dnsdist/dnsdist.conf sed -i 's/domain.de/YOUR-DOMAIN.de/g' /etc/dnsdist/dnsdist.conf |
Änderungen sollten in etwa so ausschauen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | setLocal('YOUR-IPv4:53') addLocal('[YOUR-IPv6]:53') setACL({'0.0.0.0/0', '::/0'}) addDOHLocal('YOUR-IPv4', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') addDOHLocal('YOUR-IPv6', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') addTLSLocal('YOUR-IPv4', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') addTLSLocal('YOUR-IPv6', '/etc/ssl/private/domain.de_ecc/fullchain.cer', '/etc/ssl/private/domain.de_ecc/domain.de.key') newServer({address='127.0.0.1:53', pool='recursor', checkInterval='300', checkTimeout='5', maxCheckFailures='3'}) -- Block hosts that exceeded 100 queries in 10 seconds for 30 minutes function maintenance() addDynBlocks(exceedQRate(100, 10), "Exceeded query rate", 1800) end addAction(AllRule(), PoolAction('recursor')) |
Punkt 7: Pi-hole anpassen
Wir erweitern die Adlist.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | cat <<EOF > /etc/pihole/adlists.list https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt https://s3.amazonaws.com/lists.disconnect.me/simple_tracking.txt https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt https://justdomains.github.io/blocklists/lists/easylist-justdomains.txt https://justdomains.github.io/blocklists/lists/easyprivacy-justdomains.txt https://justdomains.github.io/blocklists/lists/adguarddns-justdomains.txt https://justdomains.github.io/blocklists/lists/nocoin-justdomains.txt https://adaway.org/hosts.txt https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-blocklist.txt https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt https://dbl.oisd.nl/basic/ https://blocklistproject.github.io/Lists/malware.txt https://blocklistproject.github.io/Lists/phishing.txt https://blocklistproject.github.io/Lists/ransomware.txt https://blocklistproject.github.io/Lists/tracking.txt EOF |
Passen /etc/pihole/setupVars.conf
unseren Wünschen an: Lokale IP-Adresse, Loopback Interface, deaktivieren Querry logging, stellen Pihole DNS auf unseren PowerDNS Recursor.
1 2 3 4 5 6 | sed -i 's/IPV4_ADDRESS=.*/IPV4_ADDRESS=127.0.0.1/' /etc/pihole/setupVars.conf sed -i 's/IPV6_ADDRESS=.*/IPV6_ADDRESS=::1/' /etc/pihole/setupVars.conf sed -i 's/QUERY_LOGGING=.*/QUERY_LOGGING=false/' /etc/pihole/setupVars.conf sed -i '$ a\DNSSEC=true' /etc/pihole/setupVars.conf sed -i 's/PIHOLE_DNS_1=.*/PIHOLE_DNS_1=127.0.0.1#5300/' /etc/pihole/setupVars.conf sed -i '/PIHOLE_DNS_2=.*/d' /etc/pihole/setupVars.conf |
Um sicher zu gehen, dass Pi-hole bei einem Update diese Variable nicht löscht, erstellen wir eine neue Datei um das Interface lo
zu binden.
1 2 3 4 | cat <<EOF > /etc/dnsmasq.d/02-bind.conf interface=lo bind-interfaces EOF |
Punkt 8: PowerDNS Recursor konfigurieren
Jetzt gehen wir das letzte Element der Kette an – dem Recursor von PowerDNS. Das kleine Programm schickt sämtliche DNS-Anfragen direkt an die DNS-Rootserver und behilft sich der vorinstallierten DNS-Rootserver Datei /usr/share/dns/root.hints
.
1 2 3 4 | sed -i 's/# dnssec=.*/dnssec=validate/' /etc/powerdns/recursor.conf sed -i 's/local-address=.*/local-address=127.0.0.1/' /etc/powerdns/recursor.conf sed -i 's/# local-port=.*/local-port=5300/' /etc/powerdns/recursor.conf sed -i 's/# query-local-address6=.*/query-local-address6=::/' /etc/powerdns/recursor.conf |
Punkt 9: Dienste starten
Nun ist es an der Zeit die Pi-hole Konfiguration zu übernehmen
1 | pihole -r |
und die Dienste neu zu starten.
1 | systemctl restart pihole-FTL.service pdns-recursor.service dnsdist.service |
WICHTIG: dnsdist zuletzt starten da wir ein checkInterval
von 5 Minuten eingestellt haben! Ansonsten ist der downstream Server 127.0.0.1:53 nicht direkt up
.
Punkt 10: DNS Auflösung testen
Zu guter Letzt überprüfen wir ob alle Dienste auf den korrekten Ports lauschen.
1 | netstat -ntupl | egrep "dnsdist|pdns|pihole" |
Soll:
dnsdist/tcp: 53, 443, 853
dnsdist/udp: 53
pihole/tcp+udp: 127.0.0.1:53, ::1:53
pdns_recursor/tcp+udp: 127.0.0.1:5300
Wenn alles stimmt können wir die ersten Namensauflösungen testen.
DNS:
Das Tool dig
ist unter Debian vorinstalliert. Tragt hinter dem @
die öffentliche IP-Adresse des Servers ein.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | dig adminforge.de @xxx.xxx.xx.xx ; <<>> DiG 9.11.5-P4-5.1-Debian <<>> adminforge.de @xxx.xxx.xx.xx ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17240 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;adminforge.de. IN A ;; ANSWER SECTION: adminforge.de. 277 IN A 5.9.68.168 ;; Query time: 0 msec ;; SERVER: xxx.xxx.xx.xx#53(xxx.xxx.xx.xx) ;; WHEN: Mon Jan 27 15:32:16 CET 2020 ;; MSG SIZE rcvd: 58 |
DNS over TLS:
Da PHP dank Pi-hole bereits installiert ist, nutzen wir am einfachsten dnstls zum testen. Anstelle domain.de
nehmt bitte eure Domain.
1 2 3 4 | wget https://raw.githubusercontent.com/dcid/dns-over-tls-php-client/master/dnstls.php php dnstls.php adminforge.de domain.de adminforge.de has address 5.9.68.168 |
DNS over HTTPS:
Über einen kleinen curl
Aufruf kann man prüfen ob DoH funktioniert. Angefragt wird hier example.com (verschlüsselt dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE).
1 2 3 4 5 6 | curl -I "https://domain.de/dns-query?ct&dns=q80BAAABAAAAAAAAB2V4YW1wbGUDY29tAAABAAE" HTTP/2 200 server: h2o/dnsdist date: Mon, 27 Jan 2020 15:12:00 GMT content-type: application/dns-message content-length: 45 |
Das Betreiben der Dienste, Webseite und Server machen wir gerne, kostet aber leider auch Geld. Unterstütze unsere Arbeit mit einer Spende. |
Hallo Dominion,
erstmal vielen Dank für die Anleitung. Ich habe in den letzten Tagen einen Pi-Hole mit DNSCrypt-Proxy (also DoH- und DNSCrypt-Forwarder) aufgesetzt.
Deshalb wundert es mich, dass Du empfiehlst, die /etc/dnsmasq.d/01-pihole.conf anzupassen.
In dieser Datei stehen folgende Hinweise:
„ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE“
„IF YOU WISH TO CHANGE THE UPSTREAM SERVERS, CHANGE THEM IN: /etc/pihole/setupVars.conf“
„ANY OTHER CHANGES SHOULD BE MADE IN A SEPARATE CONFIG FILE WITHIN /etc/dnsmasq.d/yourname.conf“
Habe ich hier etwas falsch verstanden oder übersehen?
Hallo Rayman,
ja richtig. Dort sollten auch keine Änderungen vorgenommen werden die nicht sowieso schon in
/etc/pihole/setupVars.conf
stehen.In
/etc/dnsmasq.d/01-pihole.conf
mache ich nur Änderungen, dapihole -g
nicht zu 100% alles übernimmt.Also keine Angst, ist alles korrekt so. Die wichtigste Einstellung ist in
/etc/dnsmasq.d/02-bind.conf
festgehalten. Dennbind-interfaces
ist nicht Bestandteil der Hauptkonfiguration und würde somit beim Update gelöscht werden.Gruß
Dominion
How can you get both dnsdist and pihole-ftl run on same port 53 ?
dnsdist/tcp: 53, 443, 853
dnsdist/udp: 53
pihole/tcp+udp: 127.0.0.1:53, ::1:53
Hi San,
thats possible because pihole is running on localhost and dnsdist on public ip.
Greetings
Dominion
by public ip do you mean a different host ?
setLocal(‚YOUR-IPv4:53‘) <– isn't this local IP referring to localhost that pi hole is using ?
then what this newServer is
newServer({address='127.0.0.1:53', pool='recursor', checkInterval='300', checkTimeout='5', maxCheckFailures='3'})
also in http://192.168.0.23/admin/settings.php?tab=dns
what would be UpStream DNS Server ?
I am able to dig using dnsdist but not able to use nslookup
$ nslookup @192.168.0.23 -port=53 yahoo.com << Fails.
Hi San,
you need to entere the public address of your system here.
You can get it with command „ip a ls“.
Greetings
Thank You Dominion,
which cloud service are you having your public up dnsdist running on ?
no cloud … dedicated servers
Hi,
ich habe das so umgesetzt, nur nutze ich unbound als Upstream DNS, soweit funktioniert alles.
Nur in Pi-Hole erscheinen alle Queries als „localhost“ auf euren Statistiken sieht man aber die IP der Clients.
Hallo LibertyX82,
was meinst du? „QUERY_LOGGING=false“ schaltet das Logging aus, wir beschreiben hier nirgends wie du die IP Adressen der Clients sehen kannst.
Gruß
Dominion
Hi,
Nein das meinte ich nicht, der dnsdist gibt die Client IP nicht an den Pi-Hole weiter, daher sieht es für den aus, als kommen alle Queries vom Localhost.
Ich habe die Lösung auch gefunden .) dnsdist hat da eine Funktion für.
Eure no logging Policy ist natürlich richtig, da mein Pi-hole allerdings nicht öffentlich sondern ausschließlich für mich ist, will ich das schon sehen 🙂
Ok prima 🙂
Hallo Dominion,
tolle Anleitung, hat bei mir auch sehr gut funktioniert. leider scheitere ich aber beim aktivieren den dnsdist Dienstes.
Ich hab bestimmt irgendwo einen Fehler beim eintragen gemacht sehe ihn aber nicht.
Als Fehlermeldung erhalte ich den Hinweis das meine eigetragene IP bereits in Verwendung ist:
localhost dnsdist: Fatal error: binding socket to 217.xxx.xxx.xxx:443: Address already in use
kannst du mir weiter helfen.
Mit freundlichen Grüßen
Hallo Kai,
evtl. läuft auf dem Port bereits ein Webserver?
Prüf das bitte mit netstat -ntpl.
Sollte das der Fall sein müsstest du dnsdist auf einer anderen IP laufen lassen, das wäre zumindest das einfachste.
Gruß
Dominion
Super vielen Dank.
Klar das es nicht funktioniert wenn Lighttpd (PiHole Webserver) den Port 443 für die Weboberfläche bereits belegt.
Ansonsten wirklich eine sehr gute Anleitung, echt Top!
Mit freundlichen Grüßen
Kai