TL;DR: Ich betreibe bei Hetzner einen Wireguard VPN Server. Auf diesem läuft ein CoreDNS - Server mit dem ads Plugin. Auf den Endgeräten habe ich jeweils 3 Wireguard Profile: IPV6 - DNS Only; IPV6 - Full Redirect; IPV4 - Full Redirect eingerichtet. (Die IP Unterscheidung ist dabei nur in der Notation der Ziel-Adresse des Wireguard Servers zu erkennen. Der Tunnel selbst, tunnelt beide Versionen.)

Die Config-Dateien sind bisher kein Bestandteil des Posts. Bei Interesse gerne auf mich zukommen.

Motivation

Ich benutze in meinem Alltag hauptsächliche ein iPad Pro und ein Pixel 3a als Geräte zum Internet-Zugriff. Eher stationär kommt noch ein mit Windows 10 installiertes Thinkpad zum Einsatz.

Jede dieser Plattformen bzw. die darauf genutzten Anwendungen bieten unterschiedliche Möglichkeiten zum AdBlocking. Mir ist es wichtig, nicht nur im WebBrowser einen Schutz zu haben, sondern auch im E-Mail Client und anderen Anwendungen. Daher kommen die klassischen AdBlocking-Extensions nicht in Frage, da diese ja nur im Browser schützen. Für einen systemweiten Schutz gibt es auf den mobilen Plattformen Apps, die die VPN Schnittstelle nutzen. Damit sind diese in der Lage, den Netzwerkverkehr aller Anwendungen zu kontrollieren. Damit muss ich aber auch auf jedem Endgerät die entsprechende App konfigurieren. Außerdem kollidiert das mit der parallelen Nutzung eines VPNs zur Absicherung in offenen bzw. shared-Password Netzwerken.

Daher nutze einen VPN Tunnel, über den ich gleichzeitig einen von mir installierten und konfigurierten DNS Server vorgebe. Jetzt kann ich über verschiedene Client-Konfigurationen wahlweise nur DNS oder meinen gesamten Traffic über den Server laufen lassen.

Technische Motivation

Bisher habe ich auf den PiHole gesetzt. Dieser ist eigentlich zur Nutzung im lokalen Netzwerk mit einem Raspberry Pi gedacht. Er lief aber bisher auch sehr gut auf einem virtuellen Ubuntu-Server bei Hetzner. Mit der neuen Ubuntu Version 20.04 gibt es jetzt nativen Kernel-Support für Wireguard. Bisher war ich hier immer auf die Nutzung der DKMS Schnittstelle angewiesen. Dadurch dauerten die Updates länger, und ich musste auf das PPA von Wireguard ausweichen. Durch die Bereitstellung von Wireguard in den Ubuntu Paketquellen versprach das, angenehmer zu werden. Leider musste ich feststellen, dass PiHole noch nicht Ubuntu 20.04 unterstützt (Quelle: https://docs.pi-hole.net/main/prerequesites/). Ich hatte CoreDNS schon länger im Blick und wollte es ausprobieren. Ein graphisches Frontend wollte ich zwar wieder haben, jedoch habe ich das bereits beim PiHole mit Prometheus und Grafana gelöst. CoreDNS hat nativen Support zur Bereitstellung von Metriken für Prometheus.

Proof of Concept

Zum Test habe ich CoreDNS ohne die Nutzung von VPN testen wollen, aber auf Ubuntu 20.04 blockiert systemd-resolved den Port 53. Um den Port anderweitig zu nutzen, muss erst der DNS Stub Resolver in /etc/systemd/resolved.conf deaktiviert werden. (Quelle und Anleitung: https://medium.com/@niktrix/getting-rid-of-systemd-resolved-consuming-port-53-605f0234f32f) Die DNS Auflösung des Systems ist davon nicht beeinträchtigt.

Es gibt 2 Möglichkeiten bei CoreDNS Filterlisten zu nutzen:

  1. Das hosts Plugin. Hier lassen sich mehrere Dateien im Stil der etc/hosts Datei angeben und die darin eingetragenen DNS-Einträge ausliefern. Die hinterlegten Dateien können auch verändert werden, ohne die Notwendigkeit eines Neustarts von CoreDNS. Dieses Plugin ist offizieller Bestandteil von CoreDNS.
  2. Es gibt ein nicht-offizielles Plugin für CoreDNS namens ads. Diesem können in der Konfiguration die URLs der Blocklisten mitgegeben werden. Das Plugin kümmert sich um die turnusmäßige Aktualisierung der Listen. Außerdem stehen im Repository precompiled CoreDNS-Binaries mit dem Plugin bereit, sodass das Kompilieren für mich entfällt.

Ich habe beide Möglichkeiten ausprobiert und mich schließlich für den 2. Weg entschieden. Für mich standen dabei diese Gründe im Vordergrund:

  • Beim ersten Weg ist das Auswerten der Metriken schwierig, sodass ich letztendlich 2 CoreDNS Server laufen hatte, einen der blockt und bei Bedarf an den zweiten weiterleitet. Der zweite cacht die DNS Antworten und forwarded an einen lokalen Unbound zur eigentlichen rekursiven DNS-Auflösung. Im Gegensatz dazu reportet das ads-Plugin die Zahl der eingegangenen und geblockten Anfragen, sodass ich die einfach auswerten kann und keine 2 laufenden CoreDNS Instanzen benötige.
  • Bei der Nutzung des hosts-Plugin muss ich in irgendeiner Form die Listen von den URLs einsammeln, ggf. in das passende Format bringen und CoreDNS in einer Datei zur Verfügung stellen. Dies kann das ads-Plugin für mich übernehmen.

Da ich von beiden ein Single-Static-Binary bekomme ist die eigentliche Nutzung nicht kompliziert.

Umsetzung

Die Installation des Systems als VPN- und DNS-Server war dann nur noch:

  1. Bereitstellung eines neuen Ubuntu 20.04 VPS
  2. Installation von Wireguard und Übernahme der Config vom alten Server, sowie Aktivierung mittels systemd-Service
  3. Kopieren des CoreDNS-Ads Binary nach/usr/bin/coredns
  4. Anlage eines Corefiles in /etc/coredns/Corefile
  5. Anlage des systemd-Services (mit eigenem User für CoreDNS)
  6. In Prometheus die Adresse der Metriken angeben
  7. Für zusätzliche Metriken habe ich noch einen collectd installiert und konfiguriert.
  8. Im Client die passenden IP-Adressen vom neuen Wireguard Server angeben.
  9. In Grafana die Metriken eingeben.

Am Ende fällt in Grafana dann das Dashboard raus:

Grafana Dashboard meines Wireguard-CoreDNS Gateways. Zu sehen ist die Anzahl der blockierte, gecachten und aufgelösten Requests. Die geblockten Anfragen pro Client, die Auflösung der DNS Requests nach Art der Anfrage, sowie Graphen der Systemlast, Netzwerktraffic sowie Netzwerkdurchsatz.
Grafana Dashboard meines Wireguard-CoreDNS Gateways. Zu sehen ist die Anzahl der blockierte, gecachten und aufgelösten Requests. Die geblockten Anfragen pro Client, die Auflösung der DNS Requests nach Art der Anfrage, sowie Graphen der Systemlast, Netzwerktraffic sowie Netzwerkdurchsatz.

Kritik

Gerade mit dem letzten Update von PiHole (https://pi-hole.net/2020/05/10/pi-hole-v5-0-is-here/) sind einige spannende Verbesserungen dort eingezogen, die sich mit meinem Setup nicht umsetzen lassen. Zum Beispiel die Möglichkeit pro Client eigene Blocklisten zu verwenden oder die Deep CNAME Inspection um häufig wechselnde Aliase zu erkennen und zu blocken. Jedoch sind diese Features für mich nicht dringend notwendig.

Außerdem stellt der PiHole alleine bereits eine in sich gekapselte Lösung mit Web-Oberfläche bereit, während ich hier mehrere Tools zusammenführen muss, um das Ergebnis zu erreichen. Gleichzeitig wird die Grafana Instanz aber auch genutzt um meinen privaten DSL-Zugang, meine Nextcloud, etc. zu monitoren. Daher ist eine Einbindung in die Grafana Oberfläche für mich hilfreicher, als ein zusätzliches Web-Interface.

Das Web-Interface von PiHole ermöglicht eine Vielzahl von Funktionen, die ich jetzt nicht habe. Um zum Beispiel eine Adresse zu blocken oder von der Blockung auszunehmen, muss ich mich jetzt per SSH auf den Server aufschalten und die Konfiguration bearbeiten. Meine Erfahrung ist jedoch, dass ich diese Möglichkeit auch bisher seltenst wahrgenommen habe, sodass das für mich kein Problem darstellt.