Netzwerkweites DNS-Sinkhole: Pi-hole v6 Embedded Engine, FTL-Tuning & DoH/DoT-Prävention
Erstellt: 06.11.2026 Aktualisiert: 06.11.2026
Management Summary: Client-seitige Browser-Werbeblocker können weder IoT-Geräte, Smart-TVs noch mobile Hintergrund-Telemetrie oder Firmware daran hindern, Verhaltensdaten zu exfiltrieren. Dieser Leitfaden beschreibt das Produktiv-Deployment von Pi-hole v6. Im Fokus stehen die C-basierte FTL (
pihole-FTL) Engine mit integriertemdnsmasqund Civetweb-REST-API-Server, die SQLite3 Gravity-Datenbankoptimierung, VLAN-fähige Client-Gruppenrichtlinien sowie Firewall-Regeln gegen hartcodierte DoH-Bypässe.
-
Pi-hole v6 Monolithisches FTL
Ersetzt veraltete Lighttpd/PHP-Stacks durch den einheitlichen pihole-FTL-Daemon mit nativen REST-Endpunkten, Embedded TLS und Shared-Memory-Abfrageverarbeitung.
-
B-Tree Gravity Engine
Prüft Millionen von Blocklist-Einträgen und kompilierte POSIX Extended Regular Expressions (
regex_blacklist) in Sub-Millisekunden-Latenz via SQLite3 (gravity.db). -
VLAN-Clientgruppen-Richtlinien
Weist IoT-Subnetzen, Gastnetzwerken und Workstations differenzierte Filterprofile über MAC-Adressen oder CIDR-Gruppen zu.
-
Anti-Bypass-Firewalling
Fängt hartcodierte
8.8.8.8:53-Abfragen via DNAT ab und blockiert ausgehendes DoT (853/tcp) sowie DoH-Canary-Resolver am Gateway.
1. Architektonische Evolution: Pi-hole v6 & FTL Shared Memory
In Pi-hole v6 wurde die frühere Architektur aus Lighttpd und PHP-FPM vollständig abgelöst. Das Binary pihole-FTL (Faster Than Light) bündelt einen angepassten Fork von dnsmasq, einen hochgradig nebenläufigen Civetweb-HTTP/HTTPS-Server und einen In-Memory-Ringpuffer in einem einzigen Prozess.
%%{init: {'flowchart': {'wrappingWidth': 600, 'subGraphTitleMargin': {'top': 15, 'bottom': 15}}}}%%
flowchart TB
subgraph LANClients["Interne VLAN-Subnetze"]
Workstation["Workstation VLAN 10<br/>Gruppe: Engineering"]
IoT["IoT-Subnetz VLAN 30<br/>Gruppe: Strikter Sinkhole"]
end
subgraph PiholeEngine["Pi-hole v6 (pihole-FTL Daemon)"]
FTLDNS["Embedded dnsmasq<br/>UDP/TCP Port 53"]
GravityDB[("gravity.db (SQLite3)<br/>Domains + Regex-Regeln")]
SHM["POSIX Shared Memory<br/>In-RAM Query-Cache"]
FTLDB[("pihole-FTL.db<br/>Langzeit-Query-Log")]
end
subgraph UpstreamDNS["Souveräner rekursiver Resolver"]
Unbound["Lokaler Unbound Daemon<br/>127.0.0.1:5335 (DNSSEC)"]
end
Workstation -->|"DNS-Anfrage A/AAAA"| FTLDNS
IoT -->|"Telemetrie-Lookup"| FTLDNS
FTLDNS <-->|"Sub-ms B-Tree Abgleich"| GravityDB
FTLDNS <-->|"Zero-Disk Cache"| SHM
FTLDNS -.->|"Asynchroner Batch-Commit"| FTLDB
FTLDNS -->|"Zulässiger Cache-Miss"| Unbound
Blocking-Modus-Semantik (NULL vs. NXDOMAIN)
Pi-hole verwendet standardmäßig BLOCKINGMODE=NULL, wodurch für blockierte Domains 0.0.0.0 (IPv4) und :: (IPv6) zurückgegeben werden:
| Blocking-Modus | DNS-Antwort | Verhalten des Client-Betriebssystems | Empfohlener Einsatzbereich |
|---|---|---|---|
NULL (Standard) |
0.0.0.0 / :: |
Sofortiger Verbindungsabbruch (ECONNREFUSED / ENETUNREACH in < 1 ms). |
Produktionsstandard: Vermeidet Verbindungs-Timeouts und Retry-Wellen. |
NXDOMAIN |
RCODE=3 (Non-Existent Domain) |
RFC-konforme Signalisierung, dass die Domain nicht existiert. | Sinnvoll für RFC-strikte Tests; manche unsaubere IoT-Firmware wiederholt Anfragen aggressiv. |
NODATA |
RCODE=0 mit 0 Answer-Records |
Zeigt an, dass Domain existiert, aber nicht für den angefragten Typ (A/HTTPS). |
Intern für Canary-Domains (use-application-dns.net) verwendet. |
2. Container-Deployment & Host-Tuning (systemd-resolved)
Auf modernen Linux-Distributionen bindet der lokale Stub-Listener von systemd-resolved Port 53 auf 127.0.0.53. Deaktivieren Sie diesen Stub-Listener, bevor Pi-hole an Port 53 gebunden wird:
sudo mkdir -p /etc/systemd/resolved.conf.d
cat << 'EOF' | sudo tee /etc/systemd/resolved.conf.d/disable-stub.conf
[Resolve]
DNSStubListener=no
EOF
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
Produktions-Compose-Spezifikation (Pi-hole v6 + Unbound)
services:
pihole:
image: pihole/pihole:latest
container_name: pihole-ftl
hostname: dns-sinkhole
restart: unless-stopped
ports:
- "53:53/tcp"
- "53:53/udp"
- "127.0.0.1:8080:80/tcp"
- "127.0.0.1:8443:443/tcp"
environment:
TZ: "Europe/Berlin"
FTLCONF_webserver_api_password: "${PIHOLE_API_PASSWORD}"
FTLCONF_dns_upstreams: "127.0.0.1#5335"
FTLCONF_dns_dnssec: "true"
FTLCONF_dns_listeningMode: "single"
FTLCONF_dns_cache_size: "25000"
volumes:
- ./etc-pihole:/etc/pihole:Z
cap_add:
- NET_BIND_SERVICE
- NET_RAW
shm_size: "256m"
3. FTL-Konfiguration (pihole.toml) & SSD/NVMe-Verschleißschutz
Pi-hole v6 bündelt alle früheren Konfigurationsdateien (setupVars.conf, pihole-FTL.conf, dnsmasq.d) in einer zentralen /etc/pihole/pihole.toml.
[dns]
upstreams = [ "127.0.0.1#5335" ]
CNAMEdeepInspect = true
blockESNI = true
EDNS0ECS = true
dnssec = true
listeningMode = "local"
[dns.cache]
size = 25000
optimizer = 3600
[dns.rateLimit]
count = 1500
interval = 60
[database]
# In-Memory-Abfragen alle 600s (10 min) statt 60s committen, um Flash-Speicher zu schonen
DBimport = true
maxDBdays = 90
DBinterval = 600
useWAL = true
[misc]
privacylevel = 0
CNAME Cloaking Deep Inspection (CNAMEdeepInspect = true)
Werbenetzwerke umgehen einfache Domain-Blocklisten oft, indem Website-Betreiber eine Subdomain der eigenen Domain (z. B. metrics.example.com) per CNAME-Record auf Tracker-Server delegieren. Mit CNAMEdeepInspect = true prüft pihole-FTL jedes Zwischen- und Endziel der CNAME-Kette gegen gravity.db, bevor eine Antwort zurückgeliefert wird.
4. SQLite3 Gravity-Verwaltung & Präzise Regex-Filter
Statt ausschließlich über die Web-Oberfläche können Gravity-Blocklisten, Gruppenrichtlinien und kompilierte POSIX-Regex-Muster direkt via SQLite3 gesteuert werden:
-- Spezifische IoT-Quarantäne-Filtergruppe anlegen
INSERT OR IGNORE INTO "group" (enabled, name, description)
VALUES (1, 'IoT_Quarantine', 'Block all telemetry and cloud phone-home endpoints');
-- Hochwirksame kompilierte Regex-Filter gegen Smart-TV- und OS-Telemetrie eintragen
INSERT OR IGNORE INTO domainlist (type, domain, enabled, comment) VALUES
(3, '(^|\.)(metrics|telemetry|analytics|adservice|doubleclick)\.', 1, 'Generische Telemetrie-Subdomains'),
(3, '^.*(acr|samsungcloudsolution|samsungelectronics|lgad)\.com$', 1, 'Smart-TV ACR-Fingerprinting'),
(3, '(^|\.)wpad\.', 1, 'WPAD-Proxy-Auto-Discovery-Vergiftung verhindern');
Gravity-Datenbank im Shared Memory ohne Neustart des DNS-Sockets neu laden:
5. Hartcodiertes DNS & DoH/DoT-Bypässe an der Firewall unterbinden
Zahlreiche IoT-Geräte (Chromecast, Smart-TVs) ignorieren DHCP Option 6 und senden DNS-Anfragen direkt an 8.8.8.8:53 oder nutzen verschlüsseltes DoT (853/tcp). Mit nftables lässt sich die DNS-Lufthoheit am Router erzwingen:
table inet dns_enforcement {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
# Alle externen Port-53-Anfragen aus dem LAN transparent auf Pi-hole (192.168.10.2) umleiten
iifname "lan0" ip saddr != 192.168.10.2 udp dport 53 dnat to 192.168.10.2:53
iifname "lan0" ip saddr != 192.168.10.2 tcp dport 53 dnat to 192.168.10.2:53
}
chain forward {
type filter hook forward priority filter; policy accept;
# Ausgehendes DNS-over-TLS (Port 853) für alle Clients außer dem DNS-Server sperren
iifname "lan0" ip saddr != 192.168.10.2 tcp dport 853 reject with tcp reset
iifname "lan0" ip saddr != 192.168.10.2 udp dport 853 reject
}
}
6. Verifikation & Diagnostik
Prüfen Sie FTL-Cache-Metriken über die lokale DNS-Chaos-Klasse (CHAOS TXT) und testen Sie DNSSEC sowie Sinkhole-Antworten:
# 1. Prüfen, ob blockierte Domain in < 1ms 0.0.0.0 liefert
dig @127.0.0.1 doubleclick.net A +short
# 2. Live FTL-Cache-Metriken über CHAOS TXT abfragen
dig +short chaos txt cachesize.bind @127.0.0.1
dig +short chaos txt hits.bind @127.0.0.1
dig +short chaos txt misses.bind @127.0.0.1
# 3. Verifizieren, dass DNSSEC bei ungültiger Signatur mit SERVFAIL abbricht
dig @127.0.0.1 sigfail.verteiltesysteme.net A