Bypass DNS under systemd-resolved #58
Loading…
Reference in a new issue
No description provided.
Delete branch "mysticalsoap/fix/bypass-dns-resolved"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Two halves of #31:
cgroup_vpncallsset_dnswith no tunnel interface, which under resolved logs an error and does nothing. That call is the resolv.conf-era complement of per-link DNS: on resolv.conf systems it is still needed, under resolved it is redundant by design — the tunnel link already carries its DNS from tunnel-up.For reference, Mullvad documents this exact limitation and leaves it ("it will still use the DNS server on the Mullvad server that you are connected to"); Proton's daemon has no per-process DNS handling at all. The redirect+dnsmasq mechanism already exceeds both — this PR makes it point the right way.
Fix
Commit 1 — the no-tun
set_dnscalls are now explicitly resolv.conf-only (dns_manager.resolved_active(), also used internally byset_dns). No more error-log noise; the design is stated at the call sites.Commit 2 — the bypass dnsmasq joins the bypass cgroup, so its upstream queries carry the fwmark and leave through the physical link like the apps it resolves for:
_join_bypass_cgrouppolls the pid file (stale files unlinked pre-spawn) and writes the pid intocgroup.procs; on timeout it logs and degrades to the old behavior--user=nobody) — without them its upstream queries would redirect back into itselfcgroup_vpnreordered socreate_cgroupruns before the dnsmasq spawn (the join raced the cgroup teardown/recreate)Known boundary (documented, not fixable from here): apps resolving through nss-resolve/varlink never touch port 53, so they still get resolved's answer via the tunnel. Arch's default nsswitch puts
resolvefirst, so plain glibc apps fall in that bucket; browsers and Electron apps use their own resolvers against the stub and are covered.Verification
tests/test_dns_manager.py: cgroup join from pid file, poll-until-appears, timeout degradation,--user=nobodypinned, join only when a uid is passediptables-legacy -t nat -L OUTPUT -nshows the two RETURNs above the two REDIRECTs;cat /proc/$(cat /var/run/dnsmasq_aqomui_bypass.pid)/cgroupends inbypass_aqomui; a DNS query from a bypassed app shows up intcpdump -i <physical> port 53instead of the tunCloses #31
Assisted-by: claude-fable-5