mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-16 12:52:22 +08:00
155 lines
3.5 KiB
Go
155 lines
3.5 KiB
Go
package outbound
|
|
|
|
import (
|
|
"net"
|
|
"net/netip"
|
|
"sync"
|
|
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
N "github.com/sagernet/sing/common/network"
|
|
)
|
|
|
|
type loopBackDetector struct {
|
|
connAccess sync.RWMutex
|
|
packetConnAccess sync.RWMutex
|
|
connMap map[netip.AddrPort]bool
|
|
packetConnMap map[netip.AddrPort]bool
|
|
}
|
|
|
|
func newLoopBackDetector() *loopBackDetector {
|
|
return &loopBackDetector{
|
|
connMap: make(map[netip.AddrPort]bool),
|
|
packetConnMap: make(map[netip.AddrPort]bool),
|
|
}
|
|
}
|
|
|
|
func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
|
|
connAddr := M.AddrPortFromNet(conn.LocalAddr())
|
|
if !connAddr.IsValid() {
|
|
return conn
|
|
}
|
|
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
|
|
l.packetConnAccess.Lock()
|
|
l.packetConnMap[connAddr] = true
|
|
l.packetConnAccess.Unlock()
|
|
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connAddr: connAddr}
|
|
} else {
|
|
l.connAccess.Lock()
|
|
l.connMap[connAddr] = true
|
|
l.connAccess.Unlock()
|
|
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: connAddr}
|
|
}
|
|
}
|
|
|
|
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn) N.NetPacketConn {
|
|
connAddr := M.AddrPortFromNet(conn.LocalAddr())
|
|
if !connAddr.IsValid() {
|
|
return conn
|
|
}
|
|
l.packetConnAccess.Lock()
|
|
l.packetConnMap[connAddr] = true
|
|
l.packetConnAccess.Unlock()
|
|
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connAddr: connAddr}
|
|
}
|
|
|
|
func (l *loopBackDetector) CheckConn(connAddr netip.AddrPort) bool {
|
|
l.connAccess.RLock()
|
|
defer l.connAccess.RUnlock()
|
|
return l.connMap[connAddr]
|
|
}
|
|
|
|
func (l *loopBackDetector) CheckPacketConn(connAddr netip.AddrPort) bool {
|
|
l.packetConnAccess.RLock()
|
|
defer l.packetConnAccess.RUnlock()
|
|
return l.packetConnMap[connAddr]
|
|
}
|
|
|
|
type loopBackDetectWrapper struct {
|
|
net.Conn
|
|
detector *loopBackDetector
|
|
connAddr netip.AddrPort
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func (w *loopBackDetectWrapper) Close() error {
|
|
w.closeOnce.Do(func() {
|
|
w.detector.connAccess.Lock()
|
|
delete(w.detector.connMap, w.connAddr)
|
|
w.detector.connAccess.Unlock()
|
|
})
|
|
return w.Conn.Close()
|
|
}
|
|
|
|
func (w *loopBackDetectWrapper) ReaderReplaceable() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *loopBackDetectWrapper) WriterReplaceable() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *loopBackDetectWrapper) Upstream() any {
|
|
return w.Conn
|
|
}
|
|
|
|
type loopBackDetectPacketWrapper struct {
|
|
N.NetPacketConn
|
|
detector *loopBackDetector
|
|
connAddr netip.AddrPort
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func (w *loopBackDetectPacketWrapper) Close() error {
|
|
w.closeOnce.Do(func() {
|
|
w.detector.packetConnAccess.Lock()
|
|
delete(w.detector.packetConnMap, w.connAddr)
|
|
w.detector.packetConnAccess.Unlock()
|
|
})
|
|
return w.NetPacketConn.Close()
|
|
}
|
|
|
|
func (w *loopBackDetectPacketWrapper) ReaderReplaceable() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *loopBackDetectPacketWrapper) WriterReplaceable() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *loopBackDetectPacketWrapper) Upstream() any {
|
|
return w.NetPacketConn
|
|
}
|
|
|
|
type abstractUDPConn interface {
|
|
net.Conn
|
|
net.PacketConn
|
|
}
|
|
|
|
type loopBackDetectUDPWrapper struct {
|
|
abstractUDPConn
|
|
detector *loopBackDetector
|
|
connAddr netip.AddrPort
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func (w *loopBackDetectUDPWrapper) Close() error {
|
|
w.closeOnce.Do(func() {
|
|
w.detector.packetConnAccess.Lock()
|
|
delete(w.detector.packetConnMap, w.connAddr)
|
|
w.detector.packetConnAccess.Unlock()
|
|
})
|
|
return w.abstractUDPConn.Close()
|
|
}
|
|
|
|
func (w *loopBackDetectUDPWrapper) ReaderReplaceable() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *loopBackDetectUDPWrapper) WriterReplaceable() bool {
|
|
return true
|
|
}
|
|
|
|
func (w *loopBackDetectUDPWrapper) Upstream() any {
|
|
return w.abstractUDPConn
|
|
}
|