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
With remote VPN (WireGuard) enabled and a .conf that carries no DNS = line, Secure DNS (DoH) reports itself as active, the local DoH proxy runs, and the port-53 forward is installed — but not one query ever reaches it. Queries are handed to the WireGuard tunnel addressed to the public fallback resolver instead.
The setting is on, the UI says nothing is wrong, and the user's chosen resolver (e.g. a NextDNS profile) is silently unused.
Root cause
handle_ip diverts to WireGuard before the DNS redirect can be applied. The redirect is a property of the userspace NAT path, and a tunnelled packet never gets there:
isAddressAllowed duly returns new Allowed("127.0.0.1", 5353) for the query.
Back in handle_ip, the WireGuard fork runs on the packet's original destination: int wg_dest = !is_local_dest(version, daddr) || is_dns; — ip.c:487. is_dns is true, so wg_dest is true unconditionally.
write_wireguard_packet(...) succeeds and handle_ipreturns. handle_udp never runs, so the redirect is discarded.
The query leaves through the tunnel to whatever resolver getBuilder programmed — the public fallback, since the config named none.
Why this matters beyond the obvious
This is not a DNS leak: the query does go through the tunnel. The failure is that a security feature the user explicitly enabled is inert while claiming to be on.
It also means the analysis in #684 is not quite right. That issue was closed on the reasoning that lifting the DoH pause would send the DoH request "out over the plain underlying network with the device's real IP — same as it does today when WG has no DNS = line". In fact DoH does not function at all in that configuration; nothing is resolved over DoH, so there is no such request to leak. Worth re-reading #684 with that corrected, since the reporter accepted the outcome on the strength of it.
Scope
WireGuard enabled anddoh_enabledand the config carries no DNS = line. With a DNS = line, updateDnsProxyState stops the proxy deliberately and the behaviour is documented in summary_doh_enabled; that case is fine.
Either honour the redirect before the hijack (rewrite the destination, then let the routing fork see the rewritten local address, which is_local_dest would then keep off the tunnel), or — if DoH-alongside-WireGuard is not wanted at all — extend the updateDnsProxyState pause to cover the no-DNS = case so the UI stops claiming Secure DNS is active. The second is a one-line honesty fix; the first is the feature #684 actually asked for.
Root cause is shared with the two sibling issues linked below: handle_ip hands the packet to WireGuard before the DNS and session machinery runs, so everything that machinery provides disappears whenever the tunnel is on.
Summary
With remote VPN (WireGuard) enabled and a
.confthat carries noDNS =line, Secure DNS (DoH) reports itself as active, the local DoH proxy runs, and the port-53 forward is installed — but not one query ever reaches it. Queries are handed to the WireGuard tunnel addressed to the public fallback resolver instead.The setting is on, the UI says nothing is wrong, and the user's chosen resolver (e.g. a NextDNS profile) is silently unused.
Root cause
handle_ipdiverts to WireGuard before the DNS redirect can be applied. The redirect is a property of the userspace NAT path, and a tunnelled packet never gets there:prepareForwardinginstallsmapForward[53] → 127.0.0.1:5353whendoh_enabled && !hasActiveWireGuardDns(prefs)—ServiceSinkhole.java:2153.isAddressAllowedduly returnsnew Allowed("127.0.0.1", 5353)for the query.handle_ip, the WireGuard fork runs on the packet's original destination:int wg_dest = !is_local_dest(version, daddr) || is_dns;—ip.c:487.is_dnsis true, sowg_destis true unconditionally.write_wireguard_packet(...)succeeds andhandle_ipreturns.handle_udpnever runs, so the redirect is discarded.The query leaves through the tunnel to whatever resolver
getBuilderprogrammed — the public fallback, since the config named none.Why this matters beyond the obvious
This is not a DNS leak: the query does go through the tunnel. The failure is that a security feature the user explicitly enabled is inert while claiming to be on.
It also means the analysis in #684 is not quite right. That issue was closed on the reasoning that lifting the DoH pause would send the DoH request "out over the plain underlying network with the device's real IP — same as it does today when WG has no
DNS =line". In fact DoH does not function at all in that configuration; nothing is resolved over DoH, so there is no such request to leak. Worth re-reading #684 with that corrected, since the reporter accepted the outcome on the strength of it.Scope
doh_enabledand the config carries noDNS =line. With aDNS =line,updateDnsProxyStatestops the proxy deliberately and the behaviour is documented insummary_doh_enabled; that case is fine.master. Not introduced by Route apps around the remote VPN without leaving TrackerControl #730 — that PR preserves the same branch (is_dns && !dns_direct ⇒ tunnel).Direction
Either honour the redirect before the hijack (rewrite the destination, then let the routing fork see the rewritten local address, which
is_local_destwould then keep off the tunnel), or — if DoH-alongside-WireGuard is not wanted at all — extend theupdateDnsProxyStatepause to cover the no-DNS =case so the UI stops claiming Secure DNS is active. The second is a one-line honesty fix; the first is the feature #684 actually asked for.Root cause is shared with the two sibling issues linked below:
handle_iphands the packet to WireGuard before the DNS and session machinery runs, so everything that machinery provides disappears whenever the tunnel is on.