github.com/metacubex/mihomo@v1.18.5/listener/sing/sing.go (about) 1 package sing 2 3 import ( 4 "context" 5 "errors" 6 "net" 7 "net/netip" 8 "sync" 9 "time" 10 11 "github.com/metacubex/mihomo/adapter/inbound" 12 "github.com/metacubex/mihomo/adapter/outbound" 13 N "github.com/metacubex/mihomo/common/net" 14 C "github.com/metacubex/mihomo/constant" 15 "github.com/metacubex/mihomo/log" 16 17 vmess "github.com/metacubex/sing-vmess" 18 mux "github.com/sagernet/sing-mux" 19 "github.com/sagernet/sing/common/buf" 20 "github.com/sagernet/sing/common/bufio" 21 "github.com/sagernet/sing/common/bufio/deadline" 22 E "github.com/sagernet/sing/common/exceptions" 23 M "github.com/sagernet/sing/common/metadata" 24 "github.com/sagernet/sing/common/network" 25 "github.com/sagernet/sing/common/uot" 26 ) 27 28 const UDPTimeout = 5 * time.Minute 29 30 type ListenerConfig struct { 31 Tunnel C.Tunnel 32 Type C.Type 33 Additions []inbound.Addition 34 UDPTimeout time.Duration 35 MuxOption MuxOption 36 } 37 38 type MuxOption struct { 39 Padding bool `yaml:"padding" json:"padding,omitempty"` 40 Brutal BrutalOptions `yaml:"brutal" json:"brutal,omitempty"` 41 } 42 43 type BrutalOptions struct { 44 Enabled bool `yaml:"enabled" json:"enabled"` 45 Up string `yaml:"up" json:"up,omitempty"` 46 Down string `yaml:"down" json:"down,omitempty"` 47 } 48 49 type ListenerHandler struct { 50 ListenerConfig 51 muxService *mux.Service 52 } 53 54 func UpstreamMetadata(metadata M.Metadata) M.Metadata { 55 return M.Metadata{ 56 Source: metadata.Source, 57 Destination: metadata.Destination, 58 } 59 } 60 61 func ConvertMetadata(metadata *C.Metadata) M.Metadata { 62 return M.Metadata{ 63 Protocol: metadata.Type.String(), 64 Source: M.SocksaddrFrom(metadata.SrcIP, metadata.SrcPort), 65 Destination: M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort), 66 } 67 } 68 69 func NewListenerHandler(lc ListenerConfig) (h *ListenerHandler, err error) { 70 h = &ListenerHandler{ListenerConfig: lc} 71 h.muxService, err = mux.NewService(mux.ServiceOptions{ 72 NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context { 73 return ctx 74 }, 75 Logger: log.SingLogger, 76 Handler: h, 77 Padding: lc.MuxOption.Padding, 78 Brutal: mux.BrutalOptions{ 79 Enabled: lc.MuxOption.Brutal.Enabled, 80 SendBPS: outbound.StringToBps(lc.MuxOption.Brutal.Up), 81 ReceiveBPS: outbound.StringToBps(lc.MuxOption.Brutal.Down), 82 }, 83 }) 84 return 85 } 86 87 func (h *ListenerHandler) IsSpecialFqdn(fqdn string) bool { 88 switch fqdn { 89 case mux.Destination.Fqdn, 90 vmess.MuxDestination.Fqdn, 91 uot.MagicAddress, 92 uot.LegacyMagicAddress: 93 return true 94 default: 95 return false 96 } 97 } 98 99 func (h *ListenerHandler) ParseSpecialFqdn(ctx context.Context, conn net.Conn, metadata M.Metadata) error { 100 switch metadata.Destination.Fqdn { 101 case mux.Destination.Fqdn: 102 return h.muxService.NewConnection(ctx, conn, UpstreamMetadata(metadata)) 103 case vmess.MuxDestination.Fqdn: 104 return vmess.HandleMuxConnection(ctx, conn, h) 105 case uot.MagicAddress: 106 request, err := uot.ReadRequest(conn) 107 if err != nil { 108 return E.Cause(err, "read UoT request") 109 } 110 metadata.Destination = request.Destination 111 return h.NewPacketConnection(ctx, uot.NewConn(conn, *request), metadata) 112 case uot.LegacyMagicAddress: 113 metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} 114 return h.NewPacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata) 115 } 116 return errors.New("not special fqdn") 117 } 118 119 func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { 120 if h.IsSpecialFqdn(metadata.Destination.Fqdn) { 121 return h.ParseSpecialFqdn(ctx, conn, metadata) 122 } 123 124 if deadline.NeedAdditionalReadDeadline(conn) { 125 conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline 126 } 127 128 cMetadata := &C.Metadata{ 129 NetWork: C.TCP, 130 Type: h.Type, 131 } 132 inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) 133 inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) 134 inbound.ApplyAdditions(cMetadata, h.Additions...) 135 136 h.Tunnel.HandleTCPConn(conn, cMetadata) // this goroutine must exit after conn unused 137 return nil 138 } 139 140 func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { 141 defer func() { _ = conn.Close() }() 142 mutex := sync.Mutex{} 143 conn2 := bufio.NewNetPacketConn(conn) // a new interface to set nil in defer 144 defer func() { 145 mutex.Lock() // this goroutine must exit after all conn.WritePacket() is not running 146 defer mutex.Unlock() 147 conn2 = nil 148 }() 149 rwOptions := network.ReadWaitOptions{} 150 readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) 151 if isReadWaiter { 152 readWaiter.InitializeReadWaiter(rwOptions) 153 } 154 for { 155 var ( 156 buff *buf.Buffer 157 dest M.Socksaddr 158 err error 159 ) 160 if isReadWaiter { 161 buff, dest, err = readWaiter.WaitReadPacket() 162 } else { 163 buff = rwOptions.NewPacketBuffer() 164 dest, err = conn.ReadPacket(buff) 165 if buff != nil { 166 rwOptions.PostReturn(buff) 167 } 168 } 169 if err != nil { 170 buff.Release() 171 if ShouldIgnorePacketError(err) { 172 break 173 } 174 return err 175 } 176 cPacket := &packet{ 177 conn: &conn2, 178 mutex: &mutex, 179 rAddr: metadata.Source.UDPAddr(), 180 lAddr: conn.LocalAddr(), 181 buff: buff, 182 } 183 184 cMetadata := &C.Metadata{ 185 NetWork: C.UDP, 186 Type: h.Type, 187 } 188 inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) 189 inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) 190 inbound.ApplyAdditions(cMetadata, h.Additions...) 191 192 h.Tunnel.HandleUDPPacket(cPacket, cMetadata) 193 } 194 return nil 195 } 196 197 func (h *ListenerHandler) NewError(ctx context.Context, err error) { 198 log.Warnln("%s listener get error: %+v", h.Type.String(), err) 199 } 200 201 func ShouldIgnorePacketError(err error) bool { 202 // ignore simple error 203 if E.IsTimeout(err) || E.IsClosed(err) || E.IsCanceled(err) { 204 return true 205 } 206 return false 207 } 208 209 type packet struct { 210 conn *network.NetPacketConn 211 mutex *sync.Mutex 212 rAddr net.Addr 213 lAddr net.Addr 214 buff *buf.Buffer 215 } 216 217 func (c *packet) Data() []byte { 218 return c.buff.Bytes() 219 } 220 221 // WriteBack wirtes UDP packet with source(ip, port) = `addr` 222 func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { 223 if addr == nil { 224 err = errors.New("address is invalid") 225 return 226 } 227 228 c.mutex.Lock() 229 defer c.mutex.Unlock() 230 conn := *c.conn 231 if conn == nil { 232 err = errors.New("writeBack to closed connection") 233 return 234 } 235 236 return conn.WriteTo(b, addr) 237 } 238 239 // LocalAddr returns the source IP/Port of UDP Packet 240 func (c *packet) LocalAddr() net.Addr { 241 return c.rAddr 242 } 243 244 func (c *packet) Drop() { 245 c.buff.Release() 246 } 247 248 func (c *packet) InAddr() net.Addr { 249 return c.lAddr 250 }