From d2a25d654dbac2e624265546e4d5871d42bc002e Mon Sep 17 00:00:00 2001 From: adam Date: Tue, 13 Oct 2026 19:38:25 +0100 Subject: [PATCH] Encrypted DNS: test with BIND's dig, not kdig or curl's JSON API The client hints and docs tested DoT with kdig (Knot's, often not installed) and DoH with curl's application/dns-json, which named's DoH doesn't speak (RFC 8484 wire format only). They use dig +tls / dig +https with +tls-ca and +tls-hostname now, with the port when it isn't the default. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 +++ docs/encrypted-dns.md | 15 +++++++++++---- internal/web/static/assets/pages/encdns.js | 6 ++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa9af64..07244a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,9 @@ All notable changes to Jarl are documented here. The format follows ### Fixed +- Encrypted DNS: the client hints tested with kdig (Knot's, often not + installed) and with curl's JSON API, which named's DoH doesn't speak; + they use BIND's `dig +tls` / `dig +https` now. - Server options → Added by Jarl: long statements didn't wrap, and the browser console reported a Content Security Policy violation (an inline style the page's policy blocks). diff --git a/docs/encrypted-dns.md b/docs/encrypted-dns.md index 553e323..6d8db86 100644 --- a/docs/encrypted-dns.md +++ b/docs/encrypted-dns.md @@ -111,14 +111,21 @@ For DoH clients: https://dns.adbraun.lol/dns-query | Chrome, Edge | Settings → Privacy and security → Security → Use secure DNS → custom: the DoH URL | | Windows 11 | Settings → Network → your connection → DNS server assignment → Edit: the server's address, DNS over HTTPS on (manual template), the DoH URL | -Test from a machine on your network: +Test from a machine on your network, with BIND's own `dig` (9.18 or +later; `bind9-dnsutils` on Debian): ```sh -kdig +tls-ca +tls-host=dns.adbraun.lol @10.0.10.5 example.com -dig +https @10.0.10.5 example.com -curl -s -H 'accept: application/dns-json' 'https://dns.adbraun.lol/dns-query?name=example.com' +dig +tls +tls-ca +tls-hostname=dns.adbraun.lol @10.0.10.5 example.com # DoT, port 853 +dig +https +tls-ca +tls-hostname=dns.adbraun.lol @10.0.10.5 example.com # DoH, port 443, /dns-query ``` +`+tls-ca` checks the certificate against the system's CAs and +`+tls-hostname` against the host name, as clients do; add `-p PORT` for +another port. Without `+tls-ca` the query is still encrypted, but the +certificate isn't checked. named's DoH speaks the standard wire format +(RFC 8484), not the JSON API some public resolvers also offer, so +`curl ... accept: application/dns-json` doesn't work against it. + **Android away from home.** Private DNS in hostname mode applies on every network. Away from home, your server can't be reached, and Android then resolves nothing at all ("Private DNS server cannot be accessed"). Use a diff --git a/internal/web/static/assets/pages/encdns.js b/internal/web/static/assets/pages/encdns.js index 67e8259..94c50fc 100644 --- a/internal/web/static/assets/pages/encdns.js +++ b/internal/web/static/assets/pages/encdns.js @@ -35,13 +35,15 @@ function statusPanel(s) { ]; const addr = (s.dot[0] || s.doh[0] || {}).address || "ADDRESS"; const dotPortArg = s.dot[0] && s.dot[0].port !== 853 ? " -p " + s.dot[0].port : ""; + const dohPortArg = s.doh[0] && s.doh[0].port !== 443 ? " -p " + s.doh[0].port : ""; const clients = []; if (s.dot_host) { clients.push(h("h3", null, "DNS over TLS"), copyBox(s.dot_host), h("ul", { class: "small" }, h("li", null, h("strong", null, "Android: "), "Settings → Network → Private DNS → hostname: ", h("code", null, s.hostname), ". Away from home Android can't reach this server and then resolves nothing, so use a VPN home (WireGuard) or switch Private DNS to Automatic when you leave."), h("li", null, h("strong", null, "Linux (systemd-resolved): "), h("code", null, "DNS=" + addr + "#" + s.hostname), " and ", h("code", null, "DNSOverTLS=yes"), " in /etc/systemd/resolved.conf (", h("code", null, "opportunistic"), " falls back to plain DNS away from home)."), - h("li", null, h("strong", null, "Test: "), h("code", null, "kdig +tls-ca +tls-host=" + s.hostname + dotPortArg + " @" + addr + " example.com")))); + h("li", null, h("strong", null, "Test: "), h("code", null, "dig +tls +tls-ca +tls-hostname=" + s.hostname + dotPortArg + " @" + addr + " example.com"), + " (BIND's dig; +tls-ca checks the certificate against the system's CAs)"))); } if (s.doh_url) { clients.push(h("h3", null, "DNS over HTTPS"), copyBox(s.doh_url), @@ -49,7 +51,7 @@ function statusPanel(s) { h("li", null, h("strong", null, "Firefox: "), "Settings → Privacy & Security → DNS over HTTPS → Increased protection (falls back to normal DNS) → Custom: the URL above."), h("li", null, h("strong", null, "Chrome, Edge: "), "Settings → Privacy and security → Security → Use secure DNS → custom: the URL above."), h("li", null, h("strong", null, "Windows 11: "), "Settings → Network → your connection → DNS server assignment → Edit: " + addr + ", DNS over HTTPS on (manual template), the URL above."), - h("li", null, h("strong", null, "Test: "), h("code", null, "curl -s -H 'accept: application/dns-json' '" + s.doh_url + "?name=example.com'"), " (or ", h("code", null, "dig +https @" + addr + " example.com"), ")"))); + h("li", null, h("strong", null, "Test: "), h("code", null, "dig +https +tls-ca +tls-hostname=" + s.hostname + dohPortArg + " @" + addr + " example.com")))); } return [ h("div", { class: "panel" }, h("h2", null, "Set up ", badge("on", "ok")), h("dl", { class: "kv" }, rows)),