Skip to content

dns: add scoped nameservers.use_with_exit_node selectors - #3376

Open
NelsonJeppesen wants to merge 5 commits into
juanfont:mainfrom
NelsonJeppesen:dns-use-with-exit-node
Open

dns: add scoped nameservers.use_with_exit_node selectors#3376
NelsonJeppesen wants to merge 5 commits into
juanfont:mainfrom
NelsonJeppesen:dns-use-with-exit-node

Conversation

@NelsonJeppesen

@NelsonJeppesen NelsonJeppesen commented Jul 9, 2026

Copy link
Copy Markdown

Fixes #2816

What

Add scoped dns.nameservers.use_with_exit_node selectors for global and split DNS resolvers:

dns:
  override_local_dns: true
  nameservers:
    global:
      - 100.64.0.53
    split:
      homelab.example.com:
        - 100.64.0.54
    use_with_exit_node:
      global:
        - 100.64.0.53
      split:
        homelab.example.com:
          - 100.64.0.54

Selected resolvers are sent with Tailscale dnstype.Resolver.UseWithExitNode, so supported clients keep using them after selecting an exit node.

Compatibility

  • Existing stable scalar YAML for global and split is unchanged.
  • The exported Nameservers.Global and Nameservers.Split Go fields retain their existing types.
  • Global and split selections are independent, so one address can be enabled for a split domain without enabling its global occurrence.
  • Selectors are validated against the matching configured resolver scope.
  • Global selectors require dns.override_local_dns: true; split selectors do not.
  • Clients older than capability version 125 ignore the wire field.

Why

By default, a Tailscale client delegates DNS to the selected exit node. That can add an unnecessary round trip for a resolver reachable through a tailnet or subnet route. This option preserves selected global or split resolvers while normal routing still determines how resolver traffic travels.

Testing

  • Unit coverage verifies global and split propagation, including the same address with different scoped behavior.
  • Validation coverage rejects unmatched selectors and ineffective global selectors without DNS override.
  • Environment-variable coverage verifies the global selector form.
  • TestExitNodeUseWithExitNodeDNS uses Tailscale 1.98, activates an exit node, performs a real tailscale dns query --json, and asserts both the effective direct resolver and returned DNS answer.
  • go test ./hscontrol/types ./integration
  • go vet ./...
  • golangci-lint run --new-from-rev=048308511c72fa77da103e932f9b857a6e5247b9 --timeout=5m
  • nix flake check --no-build
  • Integration workflow generation is clean.

Local Docker execution was unavailable: go run ./cmd/hi doctor reported that no Docker daemon was running. The integration scenario is registered in CI. A repository-wide go test ./... run timed out after 10 minutes in existing TestLogoutReloginWithPollChurn; that test passed alone in 64 seconds, and all changed packages passed.


Add a per-nameserver list that marks the listed resolvers with
Tailscale's dnstype.Resolver.UseWithExitNode flag, so those resolvers
keep being used when a client selects an exit node instead of having
all DNS delegated to the exit node. This lets a self-hosted resolver on
the tailnet be reached directly.

The flag requires client capability version 125 (Tailscale v1.88);
older clients ignore it. Default is empty, preserving current behaviour.

Fixes juanfont#2816
Add TestExitNodeUseWithExitNodeDNS: with an exit node selected, a
resolver listed in dns.nameservers.use_with_exit_node keeps its
UseWithExitNode flag in the client netmap, while an unlisted resolver
does not. Register it in the SQLite CI matrix via the workflow
generator.

The client feature needs Tailscale v1.88+, so the scenario pins the
head version.
Assert a listed split-domain resolver keeps UseWithExitNode while an
unlisted split resolver in another domain does not, matching the client's
per-resolver useWithExitNodeRoutes filtering.
@NelsonJeppesen
NelsonJeppesen force-pushed the dns-use-with-exit-node branch from 82db786 to 96c49fe Compare July 9, 2026 19:59
@NelsonJeppesen NelsonJeppesen changed the title dns: add nameservers.use_with_exit_node to keep DNS off the exit node dns: add scoped nameservers.use_with_exit_node selectors Jul 31, 2026
@NelsonJeppesen
NelsonJeppesen marked this pull request as ready for review July 31, 2026 01:59
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.

[Feature] Support "Use with exit node" feature for nameservers

1 participant