Skip to content

Fix forwarding packets on flows closed on attach - #94

Open
chasylexus wants to merge 25 commits into
SagerNet:devfrom
chasylexus:icmp-closed-on-attach
Open

chasylexus wants to merge 25 commits into
SagerNet:devfrom
chasylexus:icmp-closed-on-attach

Conversation

@chasylexus

Copy link
Copy Markdown

Summary

  • FlowTracker.AttachFlow receives the flow's FlowHandle, so a tracker can close the flow right there, for example when it finds the judged route is no longer usable. None of the trackers in sing-box do this today; this covers trackers that do.
  • ForwardStage.judgeAndInstall and ICMPForwarder.installFlow still wrote the flow's first packet to the port after AttachFlow returned, so that packet went out on a flow that was already closed.
  • In the dispatcher, later packets were already dropped by the closed-flow check in handleHit. In the ICMP forwarder, forwardCached drops the closed flow and the next echo request installs a new one, so every echo request went out while the tracker kept closing the flow.
  • Check the existing closed flag before that first write. The packet is dropped, and the closed flow is cleaned up the same way as before.

Test plan

  • TestForwardFlowClosedOnAttach: a tracker that closes the flow in AttachFlow; no packet reaches the port after Flush (fails without the fix)
  • TestICMPForwarderClosedOnAttach (with_gvisor): the same check for the ICMP forwarder (fails without the fix)
  • go build ./... and go vet with and without with_gvisor; go test -race for the new tests; the rest of go test -tags with_gvisor ./... fails the same way with and without this change (integration tests that need socket permissions)

nekohasekai and others added 25 commits September 29, 2026 23:21
Apple M2, internal/checksum_test, median of 3 runs:

  length   generic   NEON
  64 B     5.47 ns   3.76 ns
  128 B    6.63 ns   4.96 ns
  512 B    14.8 ns   8.46 ns
  1460 B   52.4 ns   16.7 ns
  8500 B   341 ns    85.4 ns
  65535 B  2661 ns   609 ns
A FlowTracker may close its flow through the FlowHandle from
AttachFlow. The forward dispatcher and the gVisor ICMP forwarder still
wrote the packet that created the flow to the port after AttachFlow
returned, so it went out on a flow that was already closed. For ICMP
this happened to every echo request, because a closed cached flow is
dropped and the next request installs a new one.

Check the flow's closed state before that first write.
@nekohasekai
nekohasekai force-pushed the dev branch 2 times, most recently from 7539c98 to 5c2edb1 Compare October 9, 2026 03:10
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