Skip to content

Fix Linux TUN setup + dns answer from cooperate tailscale dns - #10

Closed
nhubaotruong wants to merge 6 commits into
maisem:mainfrom
nhubaotruong:main
Closed

nhubaotruong wants to merge 6 commits into
maisem:mainfrom
nhubaotruong:main

Conversation

@nhubaotruong

Copy link
Copy Markdown

Hi,

I've been using tailmix for a while at work on my linux laptop, but since v0.1.13 the tunnel setup is broken on Linux.

So I've taken a look and fix it as well as addressing some ipv6 warnings, and dns routing for the hosts behind company tailscale network.

Full disclosure: I use AI to debug and fix, but I've tested it on my machine, the codepaths only touch Linux code

The Linux TUN reconciliation added in 74e5e8f reads route state back from
the kernel and verifies it against the plan. Two kernel behaviors made
that verification reject every IPv6 route, so tailmixd could not
configure the aggregate TUN at all:

- The kernel records IP6_RT_PRIO_USER (1024) as the metric of an IPv6
  route that is added without an explicit metric, so every route tailmix
  installed read back as an unexpected route and was reinstalled on each
  Configure.
- The kernel adds a route of its own for each address on the device. For
  IPv6 that route lands in the main table, so verification reported it as
  an unexpected route and the next reconciliation deleted it as stale.

Install routes with an explicit family metric, expect that metric when
classifying kernel routes, and ignore kernel routes that target one of
the device's own addresses. IPv4 routes keep metric 0 and are unaffected.

Change-Id: Ibb491e59c8eced53f85bb1a5cdbfb3adfc581656
A profile DNS forwarder that could not get an answer from its upstream
dropped the query. The aggregate Tailscale resolver then waited out its
own ten second timeout, and the host resolver behind it waited again, so
one unanswerable name stalled host DNS. The reported "waiting for
response or error from [127.0.0.1:50690]: context deadline exceeded"
lines came from that path.

Bound each exchange to three seconds, answer SERVFAIL when it fails or
expires, and abandon a profile DNS query at the caller's deadline.
QueryDNS takes no context, so the query now runs in a goroutine that the
deadline can leave behind. A SERVFAIL response lets the OS resolver fail
over instead of waiting, and the Tailscale resolver maps it to a SERVFAIL
answer of its own.

A reconfiguration also replaced every forwarder and closed the old ones
immediately. Queries the aggregate resolver issued just before the switch
were still in flight against the closed loopback address and never got an
answer, which is how the reported timeouts arose during startup. Keep the
replaced forwarders open until the next reconfiguration instead.

RELNOTE: Fix host DNS stalls when a profile DNS resolver does not answer.
Change-Id: I7b0d0f4a0e2b3c6d9f8a1e5c4b7d2a3f6c9e0b18
The aggregate resolver turns a failed profile forwarder into a SERVFAIL
response for the host, so a name the tailnet cannot answer no longer
leaves the host resolver waiting out its own timeout. Cover that path end
to end: a packet service built from a route whose forwarder cannot reach
its profile DNS must answer SERVFAIL instead of nothing.

The test fails without the forwarder change, where the query produced no
response at all. Factor the packet service test harness so a test can
supply its own resolver configuration.

Change-Id: I3c5e1d9a7b2f4c8e0a6d1f3b5c7e9a2d4f6b8c01
Put the append call and its arguments on separate lines, matching the
surrounding subnet route entries. No behavior change.

Change-Id: I8d2f4b6a1c3e5f7092b4d6a8c0e2f4b6d8a0c2e4
The comment above the retire swap repeated, almost verbatim, the reason
recorded at the retiredDNSForwarders field. Keep the invariant in one
place and describe the local rotation order at the call site instead.

Change-Id: I2a7c4e6b8d0f1a3c5e7b9d1f3a5c7e9b0d2f4a68
An exit node is the DNS authority for queries that no other route covers.
Selecting a raw WireGuard profile as an exit node therefore planned a profile
DNS route for it, and every reconcile failed with "profile %q does not expose
its effective DNS resolver". That error is fatal during startup, so a daemon
that had the selection persisted could not start, which leaves the exit node
unusable.

Report the capability through Status instead: the tailscale engine resolves
queries through the profile's own DNS service, while a raw WireGuard profile
carries no resolver. The DNS policy only makes the selected exit node the DNS
authority when its profile has that capability, so the host keeps resolving
with its own resolvers, whose traffic already leaves through the exit node.
@maisem

maisem commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Can you please file an issue, I don't understand what's going on in the change. I have no issues with AI writing code, just need to know what's being fixed and want to come to an agreement first. I'm also not ready to accept PRs, so if you can write down your issue I'd be happy to have my agent fix it.

@maisem maisem closed this Oct 15, 2026
@maisem

maisem commented Oct 16, 2026

Copy link
Copy Markdown
Owner

I did figure out the problem and it should be fixed in the next release later today

@nhubaotruong

Copy link
Copy Markdown
Author

Thanks ! I've just tried the latest build and my issues are fixed. Thanks for the great project and sorry for my hasteful PR

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.

2 participants