Close can hang and leak the WireGuard engine and DERP connection: bump tailscale.com past the netstack close fix, and close the backend regardless
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 22/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- go
- Lĩnh vực
- backend, networking
Hướng nghiên cứu
Start with locoBackend.Close in tailcat.go (around lines 374-392), where the WireGuard engine, network monitor, dialer and event bus only close after ns.Close() returns, and with Client.Close (around lines 2003-2010), which holds startMu across lb.Close. Bumping the tailscale.com version in go.mod is the first step, and the backend-teardown change needs a test that makes netstack close block. Done means a close that hangs in the netstack still releases the remaining resources and does not block other Client use. The TCP option and abortive-close requests are API design and should be scoped separately.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
What is the issue?
Tailcat v0.7.0 requires tailscale.com v1.103.0-pre.0.20260916030321-a2263542f260, and main (52fbad3) requires v1.103.0-pre.0.20260929142145-a0e471a35b8f. Both predate tailscale/tailscale#21668 (merged as fb79793 on 2026-10-13), which fixes tailscale/tailscale#21631: wgengine/netstack.(*Impl).Close blocks forever once more TCP endpoints need a reset than its 512-packet outbound queue holds.
We hit that through Tailcat. A Server holding 497 endpoints in TIME-WAIT closed in about 1 ms; one holding 539 never returned. A server that carried a few hundred short connections in the last minute is enough, since gVisor keeps TIME-WAIT for 60 s.
Requests, roughly in order of value:
- Bump tailscale.com past fb79793.
- Close the rest of the backend even when the netstack's close blocks.
locoBackend.Close(tailcat.go:374-392, v0.7.0) closes the WireGuard engine, the network monitor, the dialer and the event bus only afterns.Close()returns. When that blocks, the process keeps the magicsock UDP sockets, the DERP connection (with its keepalive every 60 to 65 s, reconnecting after each relay restart) and their goroutines until it exits. Measured per stuckClient: about 104 goroutines, 7.5 MiB of live heap and one DERP connection. A program that closes aClientwhenever a peer goes away leaks one of these per peer change. Client.CloseholdsstartMuacrosslb.Close(tailcat.go:2003-2010), so a close stuck in the backend also blocks any concurrent use of thatClient.- A way to set the netstack's TCP options, at least
tcpip.TCPTimeWaitTimeoutOption. tailscale.com'snetstack.Implalready hasSetTransportProtocolOption; aServer/Clientfield for the TIME-WAIT timeout, or the accessor the TODO attcpipStackOf(tailcat.go:960-963) asks for, would do. - Optionally, an exported abortive close (linger 0) for the conns Tailcat returns. Related to google/gvisor#15013:
Serveraccepts throughtcp.Forwarder, and gVisor drops a new SYN on a 4-tuple the server still holds in TIME-WAIT until TIME-WAIT expires. A client that makes one short connection per request, with the server closing first, sees about 60 x R / 49,536 of its dials stall (R connections a second over one client/server pair): we measured 2.4% at 20/s, 9.7% at 80/s and 36% at 300/s, each stalled dial waiting out the caller's timeout. Setting linger 0 on the client's conn before closing it (through gonet's unexportedep, the field Tailcat's owngonetTCPConnInternalsreads) removed the stalls and left no TIME-WAIT on either side: 60,000 short connections over one pair in 4.2 s, none failed. An exported option would avoid the reflection.
Environment
Tailcat v0.7.0; tailscale.com v1.103.0-pre.0.20260916030321-a2263542f260; gVisor v0.0.0-20260915211658-a6f909f08a72; Go 1.27.2; Linux (Docker 29.8) and macOS. Measured with Tailcat's Server and Client in one process over an in-process relay, and between containers.
- Ngôn ngữ chính
- Go
- Star
- 8.8k
- Fork
- 404
- Merge trung bình
- 3 giờ 48 phút
- Pull request đã merge (30 ngày)
- 1
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của tailscale/tailcat
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 69/100
-
Shring the homebrew binariesĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
-
macOS: tailcat's traffic goes through a co-located Tailscale exit node because netns is offCó thể đã có người làm @chphch đã nhận hôm nay. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 18/100
-
Độ khó 3/5 Nửa ngày Mức phù hợp với người mới 30/100
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 42/100
Tất cả issue của tailscale/tailcat
Issue tương tự
-
area: interop area: sip-core v3
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
fonoster/routr#705 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
deadfin-org/deadfin#35 ·
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
-
enhancement priority: low
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
labmonkeys-space/nl6#1037 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Setup Guide Go tab: say it needs Go 1.26 (the unversioned go get pulls OpenTelemetry Go v1.47.0)Đang mởenhancement follow-up
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
Maintainer thường phản hồi trong vòng 1 ngày