Repository navigation
Conversation
Split-DNS servers inside a tailnet can answer with a peer's canonical tailnet address, which the host cannot route since tailmix only routes effective IPs. Give each DNS route the canonical to effective mapping of its own profile and have the profile forwarders rewrite matching A and AAAA records in upstream answers, using the same leases and host NAT addresses as the MagicDNS records. Unmapped addresses, CNAMEs, and authority and additional records pass through untouched, and responses without rewrites keep their original bytes. Change-Id: I5089876d1aba81f4ef30163f986c3bbeafd16a59
New profiles previously advertised a random tailmix- name. Use the sanitized first label of the OS hostname instead, matching upstream Tailscale, and keep the generated name only as a fallback. Update the profiles add help and profile-management docs, and cover the default plus the fallback in tests.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Split-DNS answers that point at a peer's canonical tailnet address are unreachable from a tailmix host.
A common setup runs a DNS server (dnsmasq, CoreDNS, …) on a tailnet node and advertises it as a split-DNS resolver for a private zone. It answers with the node's own tailnet IP:
With plain
tailscaledthis works because the canonical address is routed. tailmix only routes the effective IP it assigns to each peer (for example100.127.0.0/fd6d:6e65:7400::). It forwards split-DNS responses verbatim, so the host gets an address it has no route for:getent ahosts app.internal.example.com→100.101.102.103tailmixdlogsdrop outbound packet: no profile route for destination)server.tailnet-name.ts.netresolves to the effective IP and worksThe workarounds all have downsides: per-name
/etc/hostspins to an effective IP (which can change), CNAMEs to the MagicDNS name on the server (dnsmasq can't do this cleanly), or a separate subnet route per service. All of them push tailmix's address translation onto the tailnet operator or the host administrator.Solution
When tailmix already knows the address in an answer, translate it the same way MagicDNS answers are translated.
tailmixdns.Routegets aRewrites map[netip.Addr]netip.Addr. It maps the canonical address of every node or service of the route's profile to that node's effective IP. Self IPs use the host NAT address, likeaddRecordsdoes.tunDNSLiveConfigfills the map from the same leases it uses for MagicDNS records.configureDNSLockedpasses it to bothStartForwarderandStartProfileDNSForwarder. Forwarders are rebuilt on each reconcile, so the map follows lease changes.validateResponse, the forwarder rewrites matching A → IPv4 and AAAA → IPv6 records in the Answer section only.Safety properties:
docs/design.mdanddocs/profile-management.mdare updated. Addresses that aren't known tailnet nodes (subnet routes, public IPs) still follow host IP routing as before.Testing
dns/forwarder_test.go: A and AAAA rewrite, unmapped answers unchanged, per-profile isolation, CNAME chain followed by a rewritten A record, and byte-identical output when nothing changes.cmd/tailmixd/main_test.go:tunDNSLiveConfigfills each route's map from the correct profile's leases only.go test ./...,go vet ./...,staticcheck,govulncheck, andgo mod tidy -diffpass.I've seen the comment on #10 about preferring issues first. If you'd rather track this as an issue and have it reimplemented, feel free to close this PR and use the description as the issue.