In root mode, DNS (port 53) is marked into the tun and reaches the
core's SOCKS inbound as a UDP relay to the original resolver address
(e.g. 192.168.1.1:53). The core's routing rule
{inboundTag=socks, port=53, outboundTag=dns-out} should intercept it
and resolve via the configured remote DNS (e.g. Cloudflare DoH).
However, when the system DNS server is a private/LAN IP and the user
has a geoip:private → direct routing rule, that rule matches the
destination IP (192.168.1.1) and sends the DNS query straight to the
LAN resolver (ISP DNS) — bypassing dns-out entirely. This causes:
- DNS poisoning for domains the ISP blocks/poisons
- CDN mis-resolution (wrong POP)
- Intermittent 'some sites work, some don't' behavior
Fix: add iptables nat OUTPUT DNAT to rewrite DNS queries destined for
private/LAN CIDRs to the configured remote DNS server (or 1.1.1.1
fallback), mirroring the existing tethered-client DNAT in
buildLanShareSetup. This prevents geoip:private from matching, so
dns-out can resolve via the proxy.
Verified on OnePlus 13R (OxygenOS 16, WildKernel v2.2.0-r4):
- Before: youtube.com → 185.45.5.35 (fake ISP IP), timeout
- After DNAT to 1.1.1.1: youtube.com → 142.251.45.14 (real), 301
- tcpdump confirms response source changes from 192.168.1.1 to
correct resolution through the proxy