github.com/sagernet/sing-box@v1.9.0-rc.20/outbound/direct_loopback_detect.go (about)

     1  package outbound
     2  
     3  import (
     4  	"net"
     5  	"net/netip"
     6  	"sync"
     7  
     8  	"github.com/sagernet/sing-box/adapter"
     9  	M "github.com/sagernet/sing/common/metadata"
    10  	N "github.com/sagernet/sing/common/network"
    11  )
    12  
    13  type loopBackDetector struct {
    14  	router           adapter.Router
    15  	connAccess       sync.RWMutex
    16  	packetConnAccess sync.RWMutex
    17  	connMap          map[netip.AddrPort]netip.AddrPort
    18  	packetConnMap    map[uint16]uint16
    19  }
    20  
    21  func newLoopBackDetector(router adapter.Router) *loopBackDetector {
    22  	return &loopBackDetector{
    23  		router:        router,
    24  		connMap:       make(map[netip.AddrPort]netip.AddrPort),
    25  		packetConnMap: make(map[uint16]uint16),
    26  	}
    27  }
    28  
    29  func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
    30  	source := M.AddrPortFromNet(conn.LocalAddr())
    31  	if !source.IsValid() {
    32  		return conn
    33  	}
    34  	if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
    35  		if !source.Addr().IsLoopback() {
    36  			_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
    37  			if err != nil {
    38  				return conn
    39  			}
    40  		}
    41  		if !N.IsPublicAddr(source.Addr()) {
    42  			return conn
    43  		}
    44  		l.packetConnAccess.Lock()
    45  		l.packetConnMap[source.Port()] = M.AddrPortFromNet(conn.RemoteAddr()).Port()
    46  		l.packetConnAccess.Unlock()
    47  		return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connPort: source.Port()}
    48  	} else {
    49  		l.connAccess.Lock()
    50  		l.connMap[source] = M.AddrPortFromNet(conn.RemoteAddr())
    51  		l.connAccess.Unlock()
    52  		return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: source}
    53  	}
    54  }
    55  
    56  func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn, destination M.Socksaddr) N.NetPacketConn {
    57  	source := M.AddrPortFromNet(conn.LocalAddr())
    58  	if !source.IsValid() {
    59  		return conn
    60  	}
    61  	if !source.Addr().IsLoopback() {
    62  		_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
    63  		if err != nil {
    64  			return conn
    65  		}
    66  	}
    67  	l.packetConnAccess.Lock()
    68  	l.packetConnMap[source.Port()] = destination.AddrPort().Port()
    69  	l.packetConnAccess.Unlock()
    70  	return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connPort: source.Port()}
    71  }
    72  
    73  func (l *loopBackDetector) CheckConn(source netip.AddrPort, local netip.AddrPort) bool {
    74  	l.connAccess.RLock()
    75  	defer l.connAccess.RUnlock()
    76  	destination, loaded := l.connMap[source]
    77  	return loaded && destination != local
    78  }
    79  
    80  func (l *loopBackDetector) CheckPacketConn(source netip.AddrPort, local netip.AddrPort) bool {
    81  	if !source.IsValid() {
    82  		return false
    83  	}
    84  	if !source.Addr().IsLoopback() {
    85  		_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
    86  		if err != nil {
    87  			return false
    88  		}
    89  	}
    90  	if N.IsPublicAddr(source.Addr()) {
    91  		return false
    92  	}
    93  	l.packetConnAccess.RLock()
    94  	defer l.packetConnAccess.RUnlock()
    95  	destinationPort, loaded := l.packetConnMap[source.Port()]
    96  	return loaded && destinationPort != local.Port()
    97  }
    98  
    99  type loopBackDetectWrapper struct {
   100  	net.Conn
   101  	detector  *loopBackDetector
   102  	connAddr  netip.AddrPort
   103  	closeOnce sync.Once
   104  }
   105  
   106  func (w *loopBackDetectWrapper) Close() error {
   107  	w.closeOnce.Do(func() {
   108  		w.detector.connAccess.Lock()
   109  		delete(w.detector.connMap, w.connAddr)
   110  		w.detector.connAccess.Unlock()
   111  	})
   112  	return w.Conn.Close()
   113  }
   114  
   115  func (w *loopBackDetectWrapper) ReaderReplaceable() bool {
   116  	return true
   117  }
   118  
   119  func (w *loopBackDetectWrapper) WriterReplaceable() bool {
   120  	return true
   121  }
   122  
   123  func (w *loopBackDetectWrapper) Upstream() any {
   124  	return w.Conn
   125  }
   126  
   127  type loopBackDetectPacketWrapper struct {
   128  	N.NetPacketConn
   129  	detector  *loopBackDetector
   130  	connPort  uint16
   131  	closeOnce sync.Once
   132  }
   133  
   134  func (w *loopBackDetectPacketWrapper) Close() error {
   135  	w.closeOnce.Do(func() {
   136  		w.detector.packetConnAccess.Lock()
   137  		delete(w.detector.packetConnMap, w.connPort)
   138  		w.detector.packetConnAccess.Unlock()
   139  	})
   140  	return w.NetPacketConn.Close()
   141  }
   142  
   143  func (w *loopBackDetectPacketWrapper) ReaderReplaceable() bool {
   144  	return true
   145  }
   146  
   147  func (w *loopBackDetectPacketWrapper) WriterReplaceable() bool {
   148  	return true
   149  }
   150  
   151  func (w *loopBackDetectPacketWrapper) Upstream() any {
   152  	return w.NetPacketConn
   153  }
   154  
   155  type abstractUDPConn interface {
   156  	net.Conn
   157  	net.PacketConn
   158  }
   159  
   160  type loopBackDetectUDPWrapper struct {
   161  	abstractUDPConn
   162  	detector  *loopBackDetector
   163  	connPort  uint16
   164  	closeOnce sync.Once
   165  }
   166  
   167  func (w *loopBackDetectUDPWrapper) Close() error {
   168  	w.closeOnce.Do(func() {
   169  		w.detector.packetConnAccess.Lock()
   170  		delete(w.detector.packetConnMap, w.connPort)
   171  		w.detector.packetConnAccess.Unlock()
   172  	})
   173  	return w.abstractUDPConn.Close()
   174  }
   175  
   176  func (w *loopBackDetectUDPWrapper) ReaderReplaceable() bool {
   177  	return true
   178  }
   179  
   180  func (w *loopBackDetectUDPWrapper) WriterReplaceable() bool {
   181  	return true
   182  }
   183  
   184  func (w *loopBackDetectUDPWrapper) Upstream() any {
   185  	return w.abstractUDPConn
   186  }