DNS plane
The DNS plane is one of the two halves of The Gateway’s dataplane (the other is the splitting / routing engine). Every DNS query from every LAN device is intercepted by the integrated resolver — either by being the network’s dnsmasq-advertised resolver, or by an iptables DNAT redirect for devices that try to talk to 8.8.8.8 directly.
What it does
Section titled “What it does”| Capability | Notes |
|---|---|
| Recursive resolver | Forwarding to upstream resolvers of your choice. upstream_mode: plain / doh / dot. |
| Per-device filter rules | Match by source IP, subnet, interface, device, or device group. Wildcard, suffix, exact, or regex. |
| Allowlist / blocklist | Curated and custom lists; mergeable; per-rule precedence. |
| Domain rewrite | Force a domain to NXDOMAIN or to a specific A / AAAA record. |
| Custom zones | Local A / AAAA / CNAME / MX / SOA / NS records (e.g. *.lan for LAN service discovery). |
| Upstream rotation | off / round-robin / random over a pool of upstream resolvers. Per-query when on. |
| ECS stripping | Strip EDNS Client Subnet on outbound queries — privacy by default, always on. |
| DNS leak prevention | iptables DNAT for hard-coded resolvers; nftables blocks for DoH / DoT bypass. |
| DoH / DoT block | DoH by SNI on TCP/443 against known providers; DoT by dropping TCP/853. |
| Telemetry preset blocks | Curated lists for common OS / app telemetry endpoints, organised by category. One-toggle enable/disable. |
| Cache with stats | Global hit / miss / eviction counters. Per-upstream RTT. |
| Pi-hole integration | Optional: front an existing Pi-hole v5 or v6 instance. Auto-detects API version, pushes blocklist adds/removes from the gateway side. |
Per-device filtering
Section titled “Per-device filtering”A filter rule lives in /api/v1/dns/filter-rules: pattern + match-type + action, scoped by source. action ∈ {block, allow, rewrite}, match_type ∈ {exact, wildcard, regex, contains, suffix}, source_type ∈ {all, ip, subnet, interface, device, device_group}. Rules are checked in ascending priority order; the first matching rule wins, so lower number = wins.
# Block ads only for the kids device groupcurl -X POST https://gateway.lan:8080/api/v1/dns/filter-rules \ -H "Authorization: Bearer $API_KEY" -d '{ "name":"block-ads-kids","priority":110,"enabled":true, "action":"block","match_type":"wildcard","pattern":"*.doubleclick.net", "source_type":"device_group","source_value":"kids" }'To rewrite a specific domain to a fixed answer for every client, use the simpler /api/v1/dns/rewrites endpoint (no priority, no source scope):
curl -X POST https://gateway.lan:8080/api/v1/dns/rewrites \ -H "Authorization: Bearer $API_KEY" -d '{ "domain":"mail.corp.example","answer":"10.20.0.5" }'For per-device-group rewrites, use /dns/filter-rules with action: rewrite instead. A query is matched against filter rules in priority order; the first matching rule wins.
Custom zones
Section titled “Custom zones”You can host arbitrary local zones in the integrated resolver. A zone (/api/v1/dns/zones) is just a name + enabled flag; records (/api/v1/dns/records) are a separate resource that reference the zone by name.
# 1. Create the zonecurl -X POST https://gateway.lan:8080/api/v1/dns/zones \ -H "Authorization: Bearer $API_KEY" -d '{"zone":"lan","enabled":true}'
# 2. Add records (one per call)curl -X POST https://gateway.lan:8080/api/v1/dns/records \ -H "Authorization: Bearer $API_KEY" -d '{ "zone":"lan", "name":"nas", "type":"A", "value":"10.0.0.5", "ttl":300, "enabled":true }'
curl -X POST https://gateway.lan:8080/api/v1/dns/records \ -H "Authorization: Bearer $API_KEY" -d '{ "zone":"lan", "name":"pihole", "type":"CNAME", "value":"gateway.lan", "ttl":300, "enabled":true }'Useful for hostname-based service discovery on the LAN without standing up dnsmasq or BIND. The integrated resolver synthesises SOA + NS automatically — no need to define them per zone.
Leak prevention
Section titled “Leak prevention”The integrated resolver is the only allowed DNS path. Three layers enforce this:
- DHCP hands out the gateway IP as the DNS server.
- iptables DNAT rewrites any UDP/53 destined for any other IP back to the gateway.
- nftables drop rules block DoH (
443/tcpto known DoH providers by SNI) and DoT (853/tcpto anywhere).
A device that hard-codes 1.1.1.1 still gets its queries answered — by The Gateway’s resolver, with filtering applied. A device that uses Firefox’s DoH gets blocked.
Pi-hole integration
Section titled “Pi-hole integration”If you already run a Pi-hole and want to keep its blocklist UI as the authoritative source for “what gets blocked at the network”, the daemon can front it. Set dns.backend: pihole in the bootstrap config and provide the Pi-hole admin URL plus credentials:
dns: backend: pihole pihole: url: "http://pihole.lan" password: "REDACTED" # Pi-hole v6+ web password (preferred) api_key: "" # Pi-hole v5 only — WEBPASSWORD from setupVars.conf sync_blocklist: true # allow the daemon to push add/removeThe client auto-detects v5 vs v6 — v6 uses a session token (POST /api/auth, then SID header on subsequent calls); v5 uses &auth=<key> in the query string. You only need to populate the credential field that matches your install.
What the gateway does, from the daemon side:
| Operation | API surface | Effect |
|---|---|---|
| Read status | GET /api/v1/dns/pihole/status |
Connected? Version, gravity size, queries / blocked today |
| Enable backend | POST /api/v1/dns/pihole/enable |
Re-enables Pi-hole if disabled |
| Disable backend | POST /api/v1/dns/pihole/disable |
Pauses Pi-hole filtering |
| Add to blocklist | (internal, triggered by filter-rule changes) | Pushes new deny entries into Pi-hole’s exact-match list |
| Remove from blocklist | (internal, triggered by filter-rule changes) | Removes deny entries; tolerates 404 (already gone) |
Push operations are gateway → Pi-hole only — the daemon does not poll Pi-hole’s UI for changes and merge them back. If an operator adds a block in the Pi-hole UI, it stays there as Pi-hole’s local state; the gateway is unaware of it. Treat the gateway’s filter-rules table as authoritative for what it will push, and Pi-hole’s UI as authoritative for everything Pi-hole adds on its own (gravity, adlists, manual entries).
Any non-2xx HTTP response (other than 401 which triggers re-auth, and 404 on delete which means “already gone”) surfaces as an error on the operator’s call — silent push failures were a previous source of state drift and are now treated as real failures.
API surface
Section titled “API surface”| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/dns/status |
Resolver health, upstream RTTs |
GET |
/api/v1/dns/cache |
Cache entries |
POST |
/api/v1/dns/cache/flush |
Flush cache (optional pattern filter) |
GET |
/api/v1/dns/log |
Query log |
GET |
/api/v1/dns/clients |
Per-client query counters |
GET/POST/PUT/DELETE |
/api/v1/dns/filter-rules |
Filter rule CRUD |
GET/POST/PUT/DELETE |
/api/v1/dns/zones |
Custom zones |
GET/POST/PUT/DELETE |
/api/v1/dns/records |
Per-zone records |
GET/POST/DELETE |
/api/v1/dns/rewrites |
NXDOMAIN / A-rewrite rules |
GET/POST/DELETE |
/api/v1/dns/allowlist |
Per-source allow entries |
POST/DELETE |
/api/v1/dns/blocklist |
Per-source block entries |
GET/POST/PUT/DELETE |
/api/v1/dns/forwarders |
Upstream-resolver pool |
GET/POST/PUT/DELETE |
/api/v1/dns/presets |
Curated preset blocklists |
GET/PUT |
/api/v1/dns/rotation |
Upstream rotation mode |
GET |
/api/v1/dns/pihole/status |
Pi-hole backend status (if configured) |
POST |
/api/v1/dns/pihole/enable |
Re-enable Pi-hole filtering |
POST |
/api/v1/dns/pihole/disable |
Pause Pi-hole filtering |
Next steps
Section titled “Next steps”After the resolver is healthy and serving the LAN:
- Confirm devices actually use it. Open the DNS log and filter by device IP — a device with zero queries is going around the resolver. See leak-prevention.
- Enable telemetry-preset blocks for the OS/app categories present on the LAN (Windows, macOS, iOS, smart TVs). One toggle each on the Telemetry page.
- Pair DoH/DoT blocking with the resolver. Filtering only works if devices can’t bypass via Firefox TRR or hard-coded
1.1.1.1:853. See Privacy → system-wide DNS protections. - Set per-device filter rules for device groups that need stricter posture (kids, guests) — same matching engine, narrower scope.
Related
Section titled “Related”- Privacy & kill-switch — how DNS filtering combines with leak protection.
- Routing policies — match traffic on destination domain (which the DNS plane resolves).
- Recipes → DNS — NXDOMAIN, wildcard blocks, rewrites in one place.
- Comparisons → vs Pi-hole — when Pi-hole alone is enough, when you need The Gateway.
- Use case: anti-censorship family router — a worked example with per-group DNS rules.