Fix system stack TCP NAT collision

This commit is contained in:
世界 2026-06-19 20:24:41 +08:00
parent 3b51857024
commit 8caaa93f8d
No known key found for this signature in database
GPG key ID: CD109927C34A63C4

View file

@ -15,10 +15,15 @@ type TCPNat struct {
portIndex uint16 portIndex uint16
portAccess sync.RWMutex portAccess sync.RWMutex
addrAccess sync.RWMutex addrAccess sync.RWMutex
addrMap map[netip.AddrPort]uint16 addrMap map[tcpNatKey]uint16
portMap map[uint16]*TCPSession portMap map[uint16]*TCPSession
} }
type tcpNatKey struct {
Source netip.AddrPort
Destination netip.AddrPort
}
type TCPSession struct { type TCPSession struct {
sync.Mutex sync.Mutex
Source netip.AddrPort Source netip.AddrPort
@ -30,7 +35,7 @@ func NewNat(ctx context.Context, timeout time.Duration) *TCPNat {
natMap := &TCPNat{ natMap := &TCPNat{
timeout: timeout, timeout: timeout,
portIndex: 10000, portIndex: 10000,
addrMap: make(map[netip.AddrPort]uint16), addrMap: make(map[tcpNatKey]uint16),
portMap: make(map[uint16]*TCPSession), portMap: make(map[uint16]*TCPSession),
} }
go natMap.loopCheckTimeout(ctx) go natMap.loopCheckTimeout(ctx)
@ -59,7 +64,7 @@ func (n *TCPNat) checkTimeout() {
for natPort, session := range n.portMap { for natPort, session := range n.portMap {
session.Lock() session.Lock()
if now.Sub(session.LastActive) > n.timeout { if now.Sub(session.LastActive) > n.timeout {
delete(n.addrMap, session.Source) delete(n.addrMap, tcpNatKey{Source: session.Source, Destination: session.Destination})
delete(n.portMap, natPort) delete(n.portMap, natPort)
} }
session.Unlock() session.Unlock()
@ -81,8 +86,9 @@ func (n *TCPNat) LookupBack(port uint16) *TCPSession {
} }
func (n *TCPNat) Lookup(source netip.AddrPort, destination netip.AddrPort, handler Handler) (uint16, error) { func (n *TCPNat) Lookup(source netip.AddrPort, destination netip.AddrPort, handler Handler) (uint16, error) {
key := tcpNatKey{Source: source, Destination: destination}
n.addrAccess.RLock() n.addrAccess.RLock()
port, loaded := n.addrMap[source] port, loaded := n.addrMap[key]
n.addrAccess.RUnlock() n.addrAccess.RUnlock()
if loaded { if loaded {
return port, nil return port, nil
@ -99,7 +105,7 @@ func (n *TCPNat) Lookup(source netip.AddrPort, destination netip.AddrPort, handl
} else { } else {
n.portIndex++ n.portIndex++
} }
n.addrMap[source] = nextPort n.addrMap[key] = nextPort
n.addrAccess.Unlock() n.addrAccess.Unlock()
n.portAccess.Lock() n.portAccess.Lock()
n.portMap[nextPort] = &TCPSession{ n.portMap[nextPort] = &TCPSession{