fix: pin claudenet's resolver — a box's DNS is not a function of the host's VPN #45

Merged
dan-claude-bot merged 1 commit from fix/pin-claudenet-resolver into main 2026-07-14 12:22:47 +00:00
dan-claude-bot commented 2026-07-14 12:15:47 +00:00 (Migrated from github.com)

Closes #33 — with every open question the issue posed answered by live measurement on the drill host, not reasoning:

  1. Is raw.dnsmasq the right lever? Yes, verified: doctor.sh --pin-dns applied it, the box resolved deb.debian.org immediately after, and the doctor has read the pin back ever since. The bridge exposes no first-class upstream key.
  2. Which upstreams? A setting with a sane default: BOX_DNS="ip ip…" at setup time, defaulting to 1.1.1.1 8.8.8.8.
  3. Conditional on Tailscale? Unconditional, as the issue itself argued — a box's DNS should not be a function of the host's VPN posture, whatever that posture is. Any host-level split-DNS (ZeroTier, corporate VPN, per-link systemd-resolved) is the same leak.

setup-host.sh now pins the resolver right next to dns.mode=none — the two measures close the same class of hole (connection blocked, enumeration wide open): one stops a box enumerating its siblings, the other stops it enumerating the host's tailnet and internal zones.

The doctor keeps its CGNAT detection but now points at re-running setup-host.sh as the durable fix, with --pin-dns demoted to the quick test it was.

Both fixes this closes were observed live: the cold-mint DNS death (run 6 era, dnsmasq flapping between the LAN router and MagicDNS in the Incus journal) and tailnet-name resolution from inside a box. And the pin's effect is already proven on the drill host: it has run pinned since this morning — runs 11 and 12 minted their boxes through it.

🤖 Generated with Claude Code

Closes #33 — with every open question the issue posed answered by live measurement on the drill host, not reasoning: 1. **Is `raw.dnsmasq` the right lever?** Yes, verified: `doctor.sh --pin-dns` applied it, the box resolved `deb.debian.org` immediately after, and the doctor has read the pin back ever since. The bridge exposes no first-class upstream key. 2. **Which upstreams?** A setting with a sane default: `BOX_DNS="ip ip…"` at setup time, defaulting to `1.1.1.1 8.8.8.8`. 3. **Conditional on Tailscale?** Unconditional, as the issue itself argued — a box's DNS should not be a function of the host's VPN posture, whatever that posture is. Any host-level split-DNS (ZeroTier, corporate VPN, per-link systemd-resolved) is the same leak. `setup-host.sh` now pins the resolver right next to `dns.mode=none` — the two measures close the same class of hole (connection blocked, **enumeration wide open**): one stops a box enumerating its siblings, the other stops it enumerating the host's tailnet and internal zones. The doctor keeps its CGNAT detection but now points at re-running `setup-host.sh` as the durable fix, with `--pin-dns` demoted to the quick test it was. Both fixes this closes were observed live: the cold-mint DNS death (run 6 era, dnsmasq flapping between the LAN router and MagicDNS in the Incus journal) and tailnet-name resolution from inside a box. And the pin's effect is already proven on the drill host: it has run pinned since this morning — runs 11 and 12 minted their boxes through it. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/box#45
No description provided.