Skip to content

fix(wg-client): route unqualified names to Docker DNS, dotted names upstream - #117

Open
shejnowicz wants to merge 1 commit into
masterfrom
fix/113-dnsmasq-unqualified
Open

shejnowicz wants to merge 1 commit into
masterfrom
fix/113-dnsmasq-unqualified

Conversation

@shejnowicz

Copy link
Copy Markdown
Collaborator

Fixes #113. Implements the dnsmasq configuration proposed by @jiramares — thank you for the precise diagnosis and the ready-to-use config.

Problem

The old config assumed the container's search domains are the compose network domain and routed them to Docker's embedded resolver, while domain-needed dropped dotless queries. But Docker copies the host's search domains into containers, so in corporate setups they are intranet zones. Result: sibling-container lookups failed (search expansion produced name.<intranet> → NXDOMAIN, and the final bare-name attempt was dropped), and intranet FQDNs were black-holed via the compose dns: sink.

Fix

server=//127.0.0.11    # ONLY unqualified single-label names → Docker's resolver
server=<upstream>      # every dotted name → dns.conf upstream, via wg0 → mitmproxy

(domain-needed removed.) Search domains in resolv.conf now do their real job — short intranet names — and the exfiltration posture is unchanged: unknown single-label names are forwarded by Docker's resolver to the unroutable dns: sink and never leave the host; dotted names stay subject to mitmproxy's DNS policy.

Test plan

  • bats: wg-client 19/19 (three tests rewritten for the new semantics, with dnsmasq configuration is wrong #113 regression guards: no per-search-domain routes, no domain-needed); full suite 16/16 green.
  • Hands-on integration with an intranet simulation (dedicated DNS container on a separate network, joined by mitmproxy; dns_servers pointed at it):
    • live wg-client config shows server=//127.0.0.11 + the intranet upstream, no domain-needed;
    • sibling containers resolve by bare name (mitmproxy, wg-client) — the exact failure from the issue;
    • nexus.corp.test resolves to 203.0.113.42 — an address only the intranet server knows, and its network is not agent-local, so the query provably went agent → wg0 → mitmproxy → intranet DNS;
    • public names + policy unregressed (example.com resolves, GET 200, POST 403);
    • unknown single-label name does not resolve (sink) — no host-leaving leak.
  • Known trade-off: a nonexistent single-label lookup now fails after the sink timeout (~16 s in the test) instead of instantly (domain-needed used to drop it at dnsmasq) — the cost of making sibling resolution work at all.

🤖 Generated with Claude Code

…pstream

Fixes #113. Implements the dnsmasq configuration proposed by @jiramares.

The old config routed each search domain to Docker's embedded resolver and
dropped dotless queries (domain-needed). That assumed search domains are the
compose network domain — but Docker copies the HOST's search domains into
containers, so in corporate setups they are intranet zones. Consequences:
sibling-container lookups failed (libc's search expansion produced
name.<intranet> → NXDOMAIN, and the final bare-name attempt was dropped by
domain-needed), and intranet FQDNs were black-holed (routed to Docker's
resolver, which forwards unknown names to the compose `dns:` exfiltration
sink).

New config: `server=//127.0.0.11` sends ONLY unqualified single-label names
(sibling containers) to Docker's resolver; every dotted name — including
hosts under the search domains — goes to the upstream from dns.conf through
wg0 → mitmproxy, so intranet zones resolve via `dns_servers` and stay
subject to the DNS policy. Search domains in resolv.conf now serve their
real purpose: short intranet names.

The exfiltration posture is unchanged: unknown single-label names are
forwarded by Docker's resolver to the unroutable `dns:` sink and fail
without leaving the host; dotted names were already policy-gated.

Tests updated with #113 regression guards (no per-search-domain routes, no
domain-needed); docs (Container-to-container DNS) rewritten to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dnsmasq configuration is wrong

1 participant