mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-12-04 20:36:37 +00:00
187 lines
4.5 KiB
Go
187 lines
4.5 KiB
Go
package outbound
|
|
|
|
import (
|
|
"net"
|
|
"net/netip"
|
|
"sync"
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
N "github.com/sagernet/sing/common/network"
|
|
)
|
|
|
|
type loopBackDetector struct {
|
|
router adapter.Router
|
|
connAccess sync.RWMutex
|
|
packetConnAccess sync.RWMutex
|
|
connMap map[netip.AddrPort]netip.AddrPort
|
|
packetConnMap map[uint16]uint16
|
|
}
|
|
|
|
func newLoopBackDetector(router adapter.Router) *loopBackDetector {
|
|
return &loopBackDetector{
|
|
router: router,
|
|
connMap: make(map[netip.AddrPort]netip.AddrPort),
|
|
packetConnMap: make(map[uint16]uint16),
|
|
}
|
|
}
|
|
|
|
func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
|
|
source := M.AddrPortFromNet(conn.LocalAddr())
|
|
if !source.IsValid() {
|
|
return conn
|
|
}
|
|
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
|
|
if !source.Addr().IsLoopback() {
|
|
_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
|
|
if err != nil {
|
|
return conn
|
|
}
|
|
}
|
|
if !N.IsPublicAddr(source.Addr()) {
|
|
return conn
|
|
}
|
|
l.packetConnAccess.Lock()
|
|
l.packetConnMap[source.Port()] = M.AddrPortFromNet(conn.RemoteAddr()).Port()
|
|
l.packetConnAccess.Unlock()
|
|
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connPort: source.Port()}
|
|
} else {
|
|
l.connAccess.Lock()
|
|
l.connMap[source] = M.AddrPortFromNet(conn.RemoteAddr())
|
|
l.connAccess.Unlock()
|
|
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: source}
|
|
}
|
|
}
|
|
|
|
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn, destination M.Socksaddr) N.NetPacketConn {
|
|
source := M.AddrPortFromNet(conn.LocalAddr())
|
|
if !source.IsValid() {
|
|
return conn
|
|
}
|
|
if !source.Addr().IsLoopback() {
|
|
_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
|
|
if err != nil {
|
|
return conn
|
|
}
|
|
}
|
|
l.packetConnAccess.Lock()
|
|
l.packetConnMap[source.Port()] = destination.AddrPort().Port()
|
|
l.packetConnAccess.Unlock()
|
|
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connPort: source.Port()}
|
|
}
|
|
|
|
func (l *loopBackDetector) CheckConn(source netip.AddrPort, local netip.AddrPort) bool {
|
|
l.connAccess.RLock()
|
|
defer l.connAccess.RUnlock()
|
|
destination, loaded := l.connMap[source]
|
|
return loaded && destination != local
|
|
}
|
|
|
|
func (l *loopBackDetector) CheckPacketConn(source netip.AddrPort, local netip.AddrPort) bool {
|
|
if !source.IsValid() {
|
|
return false
|
|
}
|
|
if !source.Addr().IsLoopback() {
|
|
_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
|
|
if err != nil {
|
|
return false
|
|
}
|
|
}
|
|
if N.IsPublicAddr(source.Addr()) {
|
|
return false
|
|
}
|
|
l.packetConnAccess.RLock()
|
|
defer l.packetConnAccess.RUnlock()
|
|
destinationPort, loaded := l.packetConnMap[source.Port()]
|
|
return loaded && destinationPort != local.Port()
|
|
}
|
|
|
|
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
|
|
connPort uint16
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func (w *loopBackDetectPacketWrapper) Close() error {
|
|
w.closeOnce.Do(func() {
|
|
w.detector.packetConnAccess.Lock()
|
|
delete(w.detector.packetConnMap, w.connPort)
|
|
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
|
|
connPort uint16
|
|
closeOnce sync.Once
|
|
}
|
|
|
|
func (w *loopBackDetectUDPWrapper) Close() error {
|
|
w.closeOnce.Do(func() {
|
|
w.detector.packetConnAccess.Lock()
|
|
delete(w.detector.packetConnMap, w.connPort)
|
|
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
|
|
}
|