Fix deadlock between flow judgement and close

This commit is contained in:
世界 2026-07-29 13:45:28 +08:00
parent e5c21070ae
commit 2d9b8aed5f
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -201,8 +201,8 @@ func (d *ForwardDispatcher) Dispatch(packet []byte) bool {
return false return false
} }
d.access.RLock() d.access.RLock()
defer d.access.RUnlock()
if d.returnPath.closed.Load() { if d.returnPath.closed.Load() {
d.access.RUnlock()
return false return false
} }
key := parsed.flowKey() key := parsed.flowKey()
@ -213,13 +213,16 @@ func (d *ForwardDispatcher) Dispatch(packet []byte) bool {
loaded = false loaded = false
} }
if loaded { if loaded {
return d.handleHit(key, entry, &parsed, packet, now) handled := d.handleHit(key, entry, &parsed, packet, now)
d.access.RUnlock()
return handled
} }
d.access.RUnlock()
if parsed.protocol == uint8(header.TCPProtocolNumber) && if parsed.protocol == uint8(header.TCPProtocolNumber) &&
(parsed.tcpFlags&header.TCPFlagSyn == 0 || parsed.tcpFlags&header.TCPFlagAck != 0) { (parsed.tcpFlags&header.TCPFlagSyn == 0 || parsed.tcpFlags&header.TCPFlagAck != 0) {
return false return false
} }
return d.judgeAndInstall(key, &parsed, packet, now) return d.judgeAndInstall(key, &parsed, packet)
} }
func (d *ForwardDispatcher) handleHit(key flowKey, entry *flowEntry, packet *forwardPacket, raw []byte, now int64) bool { func (d *ForwardDispatcher) handleHit(key flowKey, entry *flowEntry, packet *forwardPacket, raw []byte, now int64) bool {
@ -273,12 +276,18 @@ func (d *ForwardDispatcher) handleHit(key flowKey, entry *flowEntry, packet *for
} }
} }
func (d *ForwardDispatcher) judgeAndInstall(key flowKey, packet *forwardPacket, raw []byte, now int64) bool { func (d *ForwardDispatcher) judgeAndInstall(key flowKey, packet *forwardPacket, raw []byte) bool {
var firstPacket []byte var firstPacket []byte
if packet.protocol == uint8(header.UDPProtocolNumber) { if packet.protocol == uint8(header.UDPProtocolNumber) {
firstPacket = header.UDP(packet.transport).Payload() firstPacket = header.UDP(packet.transport).Payload()
} }
verdict := d.handler.JudgeFlow(packet.protocol, packet.source, packet.destination, firstPacket) verdict := d.handler.JudgeFlow(packet.protocol, packet.source, packet.destination, firstPacket)
d.access.RLock()
defer d.access.RUnlock()
if d.returnPath.closed.Load() {
return false
}
now := d.now()
switch verdict.Action { switch verdict.Action {
case ActionFlow: case ActionFlow:
if verdict.Port != nil { if verdict.Port != nil {