Skip to content

group: Fix interrupt_exist_connections for routed connections - #4285

Open
xxspa wants to merge 162 commits into
SagerNet:testingfrom
xxspa:fix-selector-interrupt-routed
Open

group: Fix interrupt_exist_connections for routed connections#4285
xxspa wants to merge 162 commits into
SagerNet:testingfrom
xxspa:fix-selector-interrupt-routed

Conversation

@xxspa

@xxspa xxspa commented Jul 12, 2026

Copy link
Copy Markdown

Fixes #4281.

Root cause

Connections routed to a selector (as a route target or route.final) enter through the ConnectionHandler path (Selector.NewConnection / NewPacketConnection). Neither branch of that path goes through Selector.DialContext / ListenPacket, so these connections were never registered in the selector's interrupt group. SelectOutbound then interrupted an empty set, and existing connections kept flowing over the previously selected outbound — making interrupt_exist_connections a near no-op for user traffic.

URLTest is not affected on this path because its NewConnection passes itself as the dialer, so dialing goes through URLTest.DialContext, which registers the connection.

Fix

  • Register the inbound connection in the selector's interrupt group (as an external connection) at the top of NewConnection / NewPacketConnection, covering both the nested-handler branch and the connection-manager branch. Simply passing the selector as the dialer (URLTest-style) would not be enough: members that only implement ConnectionHandler (e.g. the dns outbound) need the handler branch, and connections handled by nested group members are only registered in the inner group.
  • Add SingPacketConn / Group.NewSingPacketConn to common/interrupt so an N.PacketConn can be registered, mirroring the existing wrappers (with Upstream / ReaderReplaceable / WriterReplaceable pass-through).

Tests

New end-to-end tests in test/group_test.go (full box instance, SOCKS inbound, selector as route.final, direct members, local echo servers):

  • TestSelectorInterruptRoutedConnection: an established TCP connection must be closed after SelectOutbound when interrupt_exist_connections is enabled — failed before this fix (read timed out), passes now.
  • TestSelectorInterruptRoutedPacketConnection: a UDP session must be re-established over a new outbound socket after switching — failed before this fix (same source observed by the echo server), passes now.
  • TestSelectorKeepRoutedConnection: with interrupt_exist_connections disabled, existing connections must survive switching — passes before and after, guarding the default semantics.

Note: the test module's go.mod / go.sum are currently behind the main module (missing entries for sing-tun/gtcpip/checksum imported by common/tlsspoof), so running the tests requires a go mod tidy in test/ first; that sync is intentionally not included in this PR.

@nekohasekai
nekohasekai force-pushed the testing branch 18 times, most recently from 41f736e to 5d744ad Compare July 23, 2026 13:08
@nekohasekai
nekohasekai force-pushed the testing branch 12 times, most recently from fcd1c18 to 3429352 Compare July 28, 2026 01:07
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.

selector 的 interrupt_exist_connections 对经路由的连接不生效(切换所选成员后存量连接不被中断)

4 participants