sing-tun/system_nat.go
2022-09-08 18:11:26 +08:00

68 lines
1.3 KiB
Go

package tun
import (
"net/netip"
"sync"
)
type TCPNat struct {
portIndex uint16
portAccess sync.RWMutex
addrAccess sync.RWMutex
addrMap map[netip.AddrPort]uint16
portMap map[uint16]*TCPSession
}
type TCPSession struct {
Source netip.AddrPort
Destination netip.AddrPort
}
func NewNat() *TCPNat {
return &TCPNat{
portIndex: 10000,
addrMap: make(map[netip.AddrPort]uint16),
portMap: make(map[uint16]*TCPSession),
}
}
func (n *TCPNat) LookupBack(port uint16) *TCPSession {
n.portAccess.RLock()
defer n.portAccess.RUnlock()
return n.portMap[port]
}
func (n *TCPNat) Lookup(source netip.AddrPort, destination netip.AddrPort) uint16 {
n.addrAccess.RLock()
port, loaded := n.addrMap[source]
n.addrAccess.RUnlock()
if loaded {
return port
}
n.addrAccess.Lock()
nextPort := n.portIndex
if nextPort == 0 {
nextPort = 10000
n.portIndex = 10001
} else {
n.portIndex++
}
n.addrMap[source] = nextPort
n.addrAccess.Unlock()
n.portAccess.Lock()
n.portMap[nextPort] = &TCPSession{
Source: source,
Destination: destination,
}
n.portAccess.Unlock()
return nextPort
}
func (n *TCPNat) Revoke(natPort uint16, session *TCPSession) {
n.addrAccess.Lock()
delete(n.addrMap, session.Source)
n.addrAccess.Unlock()
n.portAccess.Lock()
delete(n.portMap, natPort)
n.portAccess.Unlock()
}