Skip to content

fix(tailscale): take tailscale-rs from git to stop a UDP close panic - #1584

Merged
ibigbug merged 1 commit into
masterfrom
fix/tailscale-udp-close-panic
Nov 6, 2026
Merged

ibigbug merged 1 commit into
masterfrom
fix/tailscale-udp-close-panic

Conversation

@ibigbug

@ibigbug ibigbug commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

Why

With the tailscale outbound, clash-rs aborts with a smoltcp panic:

panicked at smoltcp-0.13.1/src/iface/socket_set.rs:116:
handle does not refer to a valid socket

It happens whenever a UDP socket on the outbound is closed while a receive is still pending. Two common triggers:

  • a DNS nameserver routed through the outbound (nameserver-policy: "+.ts.net": "100.100.100.100#<tailscale proxy>"). tailscale-rs doesn't implement MagicDNS, so the query is never answered, times out, and the socket is dropped.
  • any UDP flow through the outbound that ends without a reply.

On iOS / Android, where clash-rs runs inside the VPN process, this takes the whole tunnel down.

Root cause, in tailscale-rs 0.6.1 netcore: a Recv that returns WouldBlock is parked in blocked_commands. When the socket is dropped, its Close removes the handle from the smoltcp SocketSet, but the parked Recv stays queued. The next pump_blocked_commands calls SocketSet::get_mut on the removed handle, which panics.

tailscale/tailscale-rs@9f7cec0 ("netcore: configure requests to cancel on drop", closes tailscale/tailscale-rs#447) skips requests whose caller has gone away. It isn't released yet; crates.io is still at 0.6.1, and the git workspace is still versioned 0.6.1.

Changes

  • [patch.crates-io]: take tailscale from tailscale-rs git at 9f7cec0447.
  • ts_netmon moves from 2c67f76eab (added in fix(apple): build clash-lib for iOS/tvOS without patched dependencies #1583) to the same rev, which is 2 commits later. All tailscale-rs crates now come from one rev.
  • Lockfile: only tailscale-rs crates change. tailscale-rs main has merged the ts_netstack_smoltcp* crates into one, so those entries collapse, and smoltcp goes from 0.13.1 to 0.14.0 (the 0.12 copy used elsewhere is untouched).
  • Remove the patch after the next tailscale-rs release.

Testing

Live tests on macOS (clash-rs binary, mixed inbound, against a real tailnet with subnet routers):

case master this PR
TCP to a domain whose lookup goes to 100.100.100.100#tailscale and times out ❌ panic ✅ times out, process keeps running
5 SOCKS5 UDP flows to a subnet host that never replies ❌ panic ✅
HTTP to a subnet host through a subnet router (10 requests) ✅ ✅
UDP DNS query to a subnet host ✅ ✅

Builds, all with --locked:

  • cargo check --workspace on macOS
  • cargo check -p clash-lib --no-default-features -F ring,shadowsocks,tuic,ssh,tun,zero_copy,tailscale for aarch64-apple-ios and for aarch64-apple-tvos (nightly, -Zbuild-std)
  • cargo test -p clash-lib --lib -F tailscale,tuic tailscale: 10 passed
  • cargo clippy -p clash-lib --all-targets -F tailscale,tuic: clean

-F tuic is needed because without it the wind-tuic dev-dependency fails to compile (unresolved import crate::quinn::outbound), the same problem noted in #1583. The tailscale live test (tailscale_live_auth_key_supports_real_tcp_and_udp_traffic) is Linux-only and wasn't run.

Risk: the pinned rev is 35 commits past v0.6.1, and it applies on every platform. The behaviour checked above is TCP/UDP through the netstack, subnet routes, and auth-key login.

Summary by CodeRabbit

  • Chores
    • Updated internal project configuration. This update does not add or remove user-facing features, change app behavior, or alter how existing features are accessed. No changes to the user interface or user workflows are included.

tailscale-rs 0.6.1 panics with "handle does not refer to a valid socket"
when a UDP socket is closed while a recv is still pending, e.g. after a
DNS query through the tailscale outbound times out, or when any UDP flow
without a reply ends. tailscale/tailscale-rs@9f7cec0 skips requests
whose caller has gone away. Patch `tailscale` to that rev; `ts_netmon`
moves from 2c67f76 to the same rev (2 commits later).
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The Cargo patch configuration now pins ts_netmon and tailscale to revision 9f7cec0447 of tailscale-rs. Comments identify an iOS PlatformMon re-export fix and handling for netstack requests whose caller was dropped.

Changes: tailscale-rs patch pins

Layer / File(s) Summary
Update patch revisions
Cargo.toml
The patch configuration updates the ts_netmon pin and adds a tailscale pin at revision 9f7cec0447. Comments describe changes at that revision.

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: itsusinn

Merge Risk: Minimal · up to ea034

No concrete merge-blocking issue is identified in the dependency pin update. Merge readiness remains subject to normal build and test checks.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title describes the dependency pin and its purpose: preventing a UDP close panic.
Linked Issues check Passed [#447] is closed and supplies historical context only. No active directly linked issue coding requirements apply.
Out of Scope Changes check Passed The Cargo.toml pins support the stated UDP close panic fix. The PR description reports related dependency lockfile updates. Cargo.lock is excluded by !**/*.lock, so its contents were not reviewed.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 925426a0-b93a-41d0-880c-ff0bf5f83ef0
Commits

Reviewing files that changed from the base of the PR and between f10e4eb and ea0347b.

Files ignored due to path filters: 1

  • Cargo.lock is excluded by !**/*.lock
Files selected for processing: 1

  • Cargo.toml

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.

@ibigbug
ibigbug merged commit b356582 into master Nov 6, 2026
30 checks passed
@ibigbug
ibigbug deleted the fix/tailscale-udp-close-panic branch November 6, 2026 01:37
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.

netstack: a cancelled recv leaves a blocked command that consumes the next datagram

1 participant