You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
webserver: serve every configured TLS port, and DoH behind a reverse proxy
Three gaps in how the front terminator exposes TLS:
1. `split_terminator_ports()` only ever captured the *first* secure entry of
`webserver.port`. Every further "...s" entry was still dropped from the list
handed to CivetWeb, so nothing served it and nothing reported it. A
documented configuration such as "80or,443os,8080,4443s" - the example in the
`webserver.port` help text itself - silently lost 4443.
The terminator now takes an array of listeners and its accept thread polls
all of them, so every configured TLS port is served and reported in the API
port list. Entries that would bind the same socket are collapsed first: the
default "443os,[::]:443os" names one dual-stack socket and then its IPv6
half, and binding both is simply `EADDRINUSE`. HTTP/3 stays on the first
port, as the QUIC listener is a single socket - Alt-Svc names the HTTP/3 port
explicitly, so advertising it from the other ports remains correct.
2. The IPv4 and IPv6 halves of one port could not coexist. `fill_bind_addr()`
maps "0.0.0.0" to the v4-mapped `::ffff:0.0.0.0`, which accepts IPv4 only,
while every socket was bound dual-stack - so "0.0.0.0:443s,[::]:443s" served
IPv4 only, with no way to express the split. `IPV6_V6ONLY` is now set for an
explicit IPv6 literal and cleared otherwise, so the two halves bind as
separate sockets.
This is a behavior change: a configuration naming *only* a bracketed TLS
entry, e.g. "[::]:443s", no longer answers over IPv4 through v4-mapped
addresses. That matches what `webserver.port` documents ("[::]:80" is IPv6
only) and what CivetWeb does for plaintext ports; the default port list is
unaffected, as it names both a bare and a bracketed entry.
3. Plaintext `/dns-query` was always refused with 426, leaving no way to put
Pi-hole's DoH behind an external TLS-terminating reverse proxy. The new
`dns.dohReverseProxy` (off by default) serves DoH on the plaintext
`webserver.port` entries for exactly that deployment: the client-facing
connection is still HTTPS, terminated at the proxy, which then forwards plain
HTTP over a trusted hop. With the option off, the 426 is unchanged.
Queries arriving this way are attributed to the proxy rather than to the end
client. Honoring `X-Forwarded-For` would need a trusted-proxy list to not be
spoofable, so that is left for later.
Signed-off-by: DL6ER <dl6er@dl6er.de>
conf->dns.dohReverseProxy.h="Also serve DoH on the plaintext (non-TLS) webserver.port entries. Enable this only when an external reverse proxy (nginx, Traefik, Caddy, HAProxy, ...) terminates TLS in front of Pi-hole and forwards plain HTTP to it over a trusted hop such as localhost or a protected LAN segment. The client-facing connection stays HTTPS; the proxy handles the encryption. Disabled by default: without such a proxy this would expose DNS queries in cleartext to anyone on the path, which is exactly what DoH exists to prevent. Bind the plaintext port to the proxy's network only, e.g. webserver.port = \"127.0.0.1:8080,443s\".";
623
+
conf->dns.dohReverseProxy.t=CONF_BOOL;
624
+
conf->dns.dohReverseProxy.d.b= false;
625
+
conf->dns.dohReverseProxy.f=FLAG_RESTART_FTL;
626
+
conf->dns.dohReverseProxy.c=validate_stub;
627
+
621
628
conf->dns.dot.k="dns.dot";
622
629
conf->dns.dot.h="Enable the inbound DNS-over-TLS (DoT) server on port 853. When enabled, FTL terminates DoT connections directly (RFC 7858) so downstream clients can use this Pi-hole as their encrypted resolver. Requires a valid TLS certificate (the same one configured for the webserver).";
0 commit comments