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 }