Fix flow close reasons

This commit is contained in:
世界 2026-07-08 18:44:57 +08:00
parent 2de01a4c29
commit dcfbe83ca6
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
3 changed files with 29 additions and 24 deletions

13
flow.go
View file

@ -41,27 +41,16 @@ const (
FlowCloseReset FlowCloseReason = iota FlowCloseReset FlowCloseReason = iota
FlowCloseFinished FlowCloseFinished
FlowCloseTimeout FlowCloseTimeout
FlowCloseEvicted
FlowCloseShutdown
FlowCloseInterrupted
) )
func (r FlowCloseReason) String() string { func (r FlowCloseReason) String() string {
switch r { switch r {
case FlowCloseReset:
return "connection reset"
case FlowCloseFinished: case FlowCloseFinished:
return "finished" return "finished"
case FlowCloseTimeout: case FlowCloseTimeout:
return "idle timeout" return "idle timeout"
case FlowCloseEvicted:
return "evicted"
case FlowCloseShutdown:
return "stack closed"
case FlowCloseInterrupted:
return "interrupted"
default: default:
return "unknown" return "connection reset"
} }
} }

View file

@ -59,15 +59,16 @@ type forwardFlow struct {
dnatAddress bool dnatAddress bool
dnatPort bool dnatPort bool
finForward bool finForward atomic.Bool
established atomic.Bool established atomic.Bool
finReverse atomic.Bool finReverse atomic.Bool
reported atomic.Bool
closed atomic.Bool closed atomic.Bool
lastReverse atomic.Int64 lastReverse atomic.Int64
} }
func (f *forwardFlow) close(reason FlowCloseReason) { func (f *forwardFlow) report(reason FlowCloseReason) {
if !f.closed.CompareAndSwap(false, true) { if !f.reported.CompareAndSwap(false, true) {
return return
} }
if f.tracker != nil { if f.tracker != nil {
@ -75,8 +76,15 @@ func (f *forwardFlow) close(reason FlowCloseReason) {
} }
} }
func (f *forwardFlow) close(reason FlowCloseReason) {
if !f.closed.CompareAndSwap(false, true) {
return
}
f.report(reason)
}
func (f *forwardFlow) CloseFlow() { func (f *forwardFlow) CloseFlow() {
f.close(FlowCloseInterrupted) f.close(FlowCloseReset)
} }
func (f *forwardFlow) observeReverse(packet *forwardPacket, now int64) { func (f *forwardFlow) observeReverse(packet *forwardPacket, now int64) {
@ -93,6 +101,8 @@ func (f *forwardFlow) observeReverse(packet *forwardPacket, now int64) {
} }
if packet.tcpFlags&header.TCPFlagFin != 0 { if packet.tcpFlags&header.TCPFlagFin != 0 {
f.finReverse.Store(true) f.finReverse.Store(true)
} else if f.finReverse.Load() && f.finForward.Load() {
f.report(FlowCloseFinished)
} }
} }
@ -159,7 +169,7 @@ func (d *ForwardDispatcher) Close() {
d.returnPath.closed.Store(true) d.returnPath.closed.Store(true)
for _, entry := range d.table { for _, entry := range d.table {
if entry.flow != nil { if entry.flow != nil {
entry.flow.close(FlowCloseShutdown) entry.flow.close(FlowCloseReset)
} }
} }
for port, nat := range d.ports { for port, nat := range d.ports {
@ -202,6 +212,7 @@ func (d *ForwardDispatcher) handleHit(key flowKey, entry *flowEntry, packet *for
d.tombstoneEntry(entry, now) d.tombstoneEntry(entry, now)
return true return true
} }
var flowFinished bool
if packet.protocol == uint8(header.TCPProtocolNumber) { if packet.protocol == uint8(header.TCPProtocolNumber) {
if packet.tcpFlags&header.TCPFlagRst != 0 { if packet.tcpFlags&header.TCPFlagRst != 0 {
d.forwardToPort(flow, packet, raw) d.forwardToPort(flow, packet, raw)
@ -210,12 +221,17 @@ func (d *ForwardDispatcher) handleHit(key flowKey, entry *flowEntry, packet *for
return true return true
} }
if packet.tcpFlags&header.TCPFlagFin != 0 { if packet.tcpFlags&header.TCPFlagFin != 0 {
flow.finForward = true flow.finForward.Store(true)
} else if flow.finForward.Load() && flow.finReverse.Load() {
flowFinished = true
} }
} }
entry.idle = d.flowIdle(flow) entry.idle = d.flowIdle(flow)
entry.deadline = now + int64(entry.idle) entry.deadline = now + int64(entry.idle)
d.forwardToPort(flow, packet, raw) d.forwardToPort(flow, packet, raw)
if flowFinished {
flow.report(FlowCloseFinished)
}
return true return true
case ActionAccept: case ActionAccept:
if packet.protocol == uint8(header.TCPProtocolNumber) { if packet.protocol == uint8(header.TCPProtocolNumber) {
@ -302,13 +318,13 @@ func (d *ForwardDispatcher) idleTimeout(protocol uint8, established bool) time.D
} }
func (d *ForwardDispatcher) flowIdle(flow *forwardFlow) time.Duration { func (d *ForwardDispatcher) flowIdle(flow *forwardFlow) time.Duration {
if flow.protocol == uint8(header.TCPProtocolNumber) && flow.finForward && flow.finReverse.Load() { if flow.protocol == uint8(header.TCPProtocolNumber) && flow.finForward.Load() && flow.finReverse.Load() {
return tcpClosingTimeout return tcpClosingTimeout
} }
if flow.udpTimeout > 0 { if flow.udpTimeout > 0 {
return flow.udpTimeout return flow.udpTimeout
} }
established := flow.established.Load() && !flow.finForward && !flow.finReverse.Load() established := flow.established.Load() && !flow.finForward.Load() && !flow.finReverse.Load()
return d.idleTimeout(flow.protocol, established) return d.idleTimeout(flow.protocol, established)
} }
@ -569,7 +585,7 @@ func (d *ForwardDispatcher) tombstoneEntry(entry *flowEntry, now int64) {
func (d *ForwardDispatcher) removeEntry(key flowKey, entry *flowEntry, reason FlowCloseReason) { func (d *ForwardDispatcher) removeEntry(key flowKey, entry *flowEntry, reason FlowCloseReason) {
delete(d.table, key) delete(d.table, key)
if entry.flow != nil { if entry.flow != nil {
if reason == FlowCloseTimeout && entry.flow.finForward && entry.flow.finReverse.Load() { if reason == FlowCloseTimeout && entry.flow.finForward.Load() && entry.flow.finReverse.Load() {
reason = FlowCloseFinished reason = FlowCloseFinished
} }
entry.flow.close(reason) entry.flow.close(reason)
@ -605,7 +621,7 @@ func (d *ForwardDispatcher) evictEntries(now int64) {
} }
} }
if freed == 0 && oldest != nil { if freed == 0 && oldest != nil {
d.removeEntry(oldestKey, oldest, FlowCloseEvicted) d.removeEntry(oldestKey, oldest, FlowCloseReset)
} }
} }

View file

@ -57,7 +57,7 @@ func (f *icmpFlow) close(reason FlowCloseReason) {
} }
func (f *icmpFlow) CloseFlow() { func (f *icmpFlow) CloseFlow() {
f.close(FlowCloseInterrupted) f.close(FlowCloseReset)
} }
func NewICMPForwarder(stack *stack.Stack, handler Handler, logger logger.Logger) *ICMPForwarder { func NewICMPForwarder(stack *stack.Stack, handler Handler, logger logger.Logger) *ICMPForwarder {
@ -77,7 +77,7 @@ func (f *ICMPForwarder) Close() error {
f.flowAccess.Lock() f.flowAccess.Lock()
defer f.flowAccess.Unlock() defer f.flowAccess.Unlock()
for key, flow := range f.flows { for key, flow := range f.flows {
flow.close(FlowCloseShutdown) flow.close(FlowCloseReset)
delete(f.flows, key) delete(f.flows, key)
} }
for port := range f.attachedPorts { for port := range f.attachedPorts {