github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/app/proxyman/inbound/worker.go (about) 1 package inbound 2 3 import ( 4 "context" 5 "sync" 6 "sync/atomic" 7 "time" 8 9 "github.com/v2fly/v2ray-core/v5/app/proxyman" 10 "github.com/v2fly/v2ray-core/v5/common" 11 "github.com/v2fly/v2ray-core/v5/common/buf" 12 "github.com/v2fly/v2ray-core/v5/common/environment" 13 "github.com/v2fly/v2ray-core/v5/common/environment/envctx" 14 "github.com/v2fly/v2ray-core/v5/common/net" 15 "github.com/v2fly/v2ray-core/v5/common/serial" 16 "github.com/v2fly/v2ray-core/v5/common/session" 17 "github.com/v2fly/v2ray-core/v5/common/signal/done" 18 "github.com/v2fly/v2ray-core/v5/common/task" 19 "github.com/v2fly/v2ray-core/v5/features/routing" 20 "github.com/v2fly/v2ray-core/v5/features/stats" 21 "github.com/v2fly/v2ray-core/v5/proxy" 22 "github.com/v2fly/v2ray-core/v5/transport/internet" 23 "github.com/v2fly/v2ray-core/v5/transport/internet/tcp" 24 "github.com/v2fly/v2ray-core/v5/transport/internet/udp" 25 "github.com/v2fly/v2ray-core/v5/transport/pipe" 26 ) 27 28 type worker interface { 29 Start() error 30 Close() error 31 Port() net.Port 32 Proxy() proxy.Inbound 33 } 34 35 type tcpWorker struct { 36 address net.Address 37 port net.Port 38 proxy proxy.Inbound 39 stream *internet.MemoryStreamConfig 40 recvOrigDest bool 41 tag string 42 dispatcher routing.Dispatcher 43 sniffingConfig *proxyman.SniffingConfig 44 uplinkCounter stats.Counter 45 downlinkCounter stats.Counter 46 47 hub internet.Listener 48 49 ctx context.Context 50 } 51 52 func getTProxyType(s *internet.MemoryStreamConfig) internet.SocketConfig_TProxyMode { 53 if s == nil || s.SocketSettings == nil { 54 return internet.SocketConfig_Off 55 } 56 return s.SocketSettings.Tproxy 57 } 58 59 func (w *tcpWorker) callback(conn internet.Connection) { 60 ctx, cancel := context.WithCancel(w.ctx) 61 sid := session.NewID() 62 ctx = session.ContextWithID(ctx, sid) 63 64 if w.recvOrigDest { 65 var dest net.Destination 66 switch getTProxyType(w.stream) { 67 case internet.SocketConfig_Redirect: 68 d, err := tcp.GetOriginalDestination(conn) 69 if err != nil { 70 newError("failed to get original destination").Base(err).WriteToLog(session.ExportIDToError(ctx)) 71 } else { 72 dest = d 73 } 74 case internet.SocketConfig_TProxy: 75 dest = net.DestinationFromAddr(conn.LocalAddr()) 76 } 77 if dest.IsValid() { 78 ctx = session.ContextWithOutbound(ctx, &session.Outbound{ 79 Target: dest, 80 }) 81 } 82 } 83 ctx = session.ContextWithInbound(ctx, &session.Inbound{ 84 Source: net.DestinationFromAddr(conn.RemoteAddr()), 85 Gateway: net.TCPDestination(w.address, w.port), 86 Tag: w.tag, 87 }) 88 content := new(session.Content) 89 if w.sniffingConfig != nil { 90 content.SniffingRequest.Enabled = w.sniffingConfig.Enabled 91 content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride 92 content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly 93 } 94 ctx = session.ContextWithContent(ctx, content) 95 if w.uplinkCounter != nil || w.downlinkCounter != nil { 96 conn = &internet.StatCouterConnection{ 97 Connection: conn, 98 ReadCounter: w.uplinkCounter, 99 WriteCounter: w.downlinkCounter, 100 } 101 } 102 if err := w.proxy.Process(ctx, net.Network_TCP, conn, w.dispatcher); err != nil { 103 newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) 104 } 105 cancel() 106 if err := conn.Close(); err != nil { 107 newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx)) 108 } 109 } 110 111 func (w *tcpWorker) Proxy() proxy.Inbound { 112 return w.proxy 113 } 114 115 func (w *tcpWorker) Start() error { 116 ctx := context.Background() 117 proxyEnvironment := envctx.EnvironmentFromContext(w.ctx).(environment.ProxyEnvironment) 118 transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("transport") 119 if err != nil { 120 return newError("unable to narrow environment to transport").Base(err) 121 } 122 ctx = envctx.ContextWithEnvironment(ctx, transportEnvironment) 123 hub, err := internet.ListenTCP(ctx, w.address, w.port, w.stream, func(conn internet.Connection) { 124 go w.callback(conn) 125 }) 126 if err != nil { 127 return newError("failed to listen TCP on ", w.port).AtWarning().Base(err) 128 } 129 w.hub = hub 130 return nil 131 } 132 133 func (w *tcpWorker) Close() error { 134 var errors []interface{} 135 if w.hub != nil { 136 if err := common.Close(w.hub); err != nil { 137 errors = append(errors, err) 138 } 139 if err := common.Close(w.proxy); err != nil { 140 errors = append(errors, err) 141 } 142 } 143 if len(errors) > 0 { 144 return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) 145 } 146 147 return nil 148 } 149 150 func (w *tcpWorker) Port() net.Port { 151 return w.port 152 } 153 154 type udpConn struct { 155 lastActivityTime int64 // in seconds 156 reader buf.Reader 157 writer buf.Writer 158 output func([]byte) (int, error) 159 remote net.Addr 160 local net.Addr 161 done *done.Instance 162 uplink stats.Counter 163 downlink stats.Counter 164 inactive bool 165 } 166 167 func (c *udpConn) setInactive() { 168 c.inactive = true 169 } 170 171 func (c *udpConn) updateActivity() { 172 atomic.StoreInt64(&c.lastActivityTime, time.Now().Unix()) 173 } 174 175 // ReadMultiBuffer implements buf.Reader 176 func (c *udpConn) ReadMultiBuffer() (buf.MultiBuffer, error) { 177 mb, err := c.reader.ReadMultiBuffer() 178 if err != nil { 179 return nil, err 180 } 181 c.updateActivity() 182 183 if c.uplink != nil { 184 c.uplink.Add(int64(mb.Len())) 185 } 186 187 return mb, nil 188 } 189 190 func (c *udpConn) Read(buf []byte) (int, error) { 191 panic("not implemented") 192 } 193 194 // Write implements io.Writer. 195 func (c *udpConn) Write(buf []byte) (int, error) { 196 n, err := c.output(buf) 197 if c.downlink != nil { 198 c.downlink.Add(int64(n)) 199 } 200 if err == nil { 201 c.updateActivity() 202 } 203 return n, err 204 } 205 206 func (c *udpConn) Close() error { 207 common.Must(c.done.Close()) 208 common.Must(common.Close(c.writer)) 209 return nil 210 } 211 212 func (c *udpConn) RemoteAddr() net.Addr { 213 return c.remote 214 } 215 216 func (c *udpConn) LocalAddr() net.Addr { 217 return c.local 218 } 219 220 func (*udpConn) SetDeadline(time.Time) error { 221 return nil 222 } 223 224 func (*udpConn) SetReadDeadline(time.Time) error { 225 return nil 226 } 227 228 func (*udpConn) SetWriteDeadline(time.Time) error { 229 return nil 230 } 231 232 type connID struct { 233 src net.Destination 234 dest net.Destination 235 } 236 237 type udpWorker struct { 238 sync.RWMutex 239 240 proxy proxy.Inbound 241 hub *udp.Hub 242 address net.Address 243 port net.Port 244 tag string 245 stream *internet.MemoryStreamConfig 246 dispatcher routing.Dispatcher 247 sniffingConfig *proxyman.SniffingConfig 248 uplinkCounter stats.Counter 249 downlinkCounter stats.Counter 250 251 checker *task.Periodic 252 activeConn map[connID]*udpConn 253 254 ctx context.Context 255 } 256 257 func (w *udpWorker) getConnection(id connID) (*udpConn, bool) { 258 w.Lock() 259 defer w.Unlock() 260 261 if conn, found := w.activeConn[id]; found && !conn.done.Done() { 262 return conn, true 263 } 264 265 pReader, pWriter := pipe.New(pipe.DiscardOverflow(), pipe.WithSizeLimit(16*1024)) 266 conn := &udpConn{ 267 reader: pReader, 268 writer: pWriter, 269 output: func(b []byte) (int, error) { 270 return w.hub.WriteTo(b, id.src) 271 }, 272 remote: &net.UDPAddr{ 273 IP: id.src.Address.IP(), 274 Port: int(id.src.Port), 275 }, 276 local: &net.UDPAddr{ 277 IP: w.address.IP(), 278 Port: int(w.port), 279 }, 280 done: done.New(), 281 uplink: w.uplinkCounter, 282 downlink: w.downlinkCounter, 283 } 284 w.activeConn[id] = conn 285 286 conn.updateActivity() 287 return conn, false 288 } 289 290 func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest net.Destination) { 291 id := connID{ 292 src: source, 293 } 294 if originalDest.IsValid() { 295 id.dest = originalDest 296 } 297 conn, existing := w.getConnection(id) 298 299 // payload will be discarded in pipe is full. 300 conn.writer.WriteMultiBuffer(buf.MultiBuffer{b}) 301 302 if !existing { 303 common.Must(w.checker.Start()) 304 305 go func() { 306 ctx := w.ctx 307 sid := session.NewID() 308 ctx = session.ContextWithID(ctx, sid) 309 310 if originalDest.IsValid() { 311 ctx = session.ContextWithOutbound(ctx, &session.Outbound{ 312 Target: originalDest, 313 }) 314 } 315 ctx = session.ContextWithInbound(ctx, &session.Inbound{ 316 Source: source, 317 Gateway: net.UDPDestination(w.address, w.port), 318 Tag: w.tag, 319 }) 320 content := new(session.Content) 321 if w.sniffingConfig != nil { 322 content.SniffingRequest.Enabled = w.sniffingConfig.Enabled 323 content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride 324 content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly 325 } 326 ctx = session.ContextWithContent(ctx, content) 327 if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil { 328 newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) 329 } 330 conn.Close() 331 // conn not removed by checker TODO may be lock worker here is better 332 if !conn.inactive { 333 conn.setInactive() 334 w.removeConn(id) 335 } 336 }() 337 } 338 } 339 340 func (w *udpWorker) removeConn(id connID) { 341 w.Lock() 342 delete(w.activeConn, id) 343 w.Unlock() 344 } 345 346 func (w *udpWorker) handlePackets() { 347 receive := w.hub.Receive() 348 for payload := range receive { 349 w.callback(payload.Payload, payload.Source, payload.Target) 350 } 351 } 352 353 func (w *udpWorker) clean() error { 354 nowSec := time.Now().Unix() 355 w.Lock() 356 defer w.Unlock() 357 358 if len(w.activeConn) == 0 { 359 return newError("no more connections. stopping...") 360 } 361 362 for addr, conn := range w.activeConn { 363 if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { // TODO Timeout too small 364 if !conn.inactive { 365 conn.setInactive() 366 delete(w.activeConn, addr) 367 } 368 conn.Close() 369 } 370 } 371 372 if len(w.activeConn) == 0 { 373 w.activeConn = make(map[connID]*udpConn, 16) 374 } 375 376 return nil 377 } 378 379 func (w *udpWorker) Start() error { 380 w.activeConn = make(map[connID]*udpConn, 16) 381 ctx := context.Background() 382 proxyEnvironment := envctx.EnvironmentFromContext(w.ctx).(environment.ProxyEnvironment) 383 transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("transport") 384 if err != nil { 385 return newError("unable to narrow environment to transport").Base(err) 386 } 387 ctx = envctx.ContextWithEnvironment(ctx, transportEnvironment) 388 h, err := udp.ListenUDP(ctx, w.address, w.port, w.stream, udp.HubCapacity(256)) 389 if err != nil { 390 return err 391 } 392 393 w.checker = &task.Periodic{ 394 Interval: time.Second * 16, 395 Execute: w.clean, 396 } 397 398 w.hub = h 399 go w.handlePackets() 400 return nil 401 } 402 403 func (w *udpWorker) Close() error { 404 w.Lock() 405 defer w.Unlock() 406 407 var errors []interface{} 408 409 if w.hub != nil { 410 if err := w.hub.Close(); err != nil { 411 errors = append(errors, err) 412 } 413 } 414 415 if w.checker != nil { 416 if err := w.checker.Close(); err != nil { 417 errors = append(errors, err) 418 } 419 } 420 421 if err := common.Close(w.proxy); err != nil { 422 errors = append(errors, err) 423 } 424 425 if len(errors) > 0 { 426 return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) 427 } 428 return nil 429 } 430 431 func (w *udpWorker) Port() net.Port { 432 return w.port 433 } 434 435 func (w *udpWorker) Proxy() proxy.Inbound { 436 return w.proxy 437 } 438 439 type dsWorker struct { 440 address net.Address 441 proxy proxy.Inbound 442 stream *internet.MemoryStreamConfig 443 tag string 444 dispatcher routing.Dispatcher 445 sniffingConfig *proxyman.SniffingConfig 446 uplinkCounter stats.Counter 447 downlinkCounter stats.Counter 448 449 hub internet.Listener 450 451 ctx context.Context 452 } 453 454 func (w *dsWorker) callback(conn internet.Connection) { 455 ctx, cancel := context.WithCancel(w.ctx) 456 sid := session.NewID() 457 ctx = session.ContextWithID(ctx, sid) 458 459 ctx = session.ContextWithInbound(ctx, &session.Inbound{ 460 Source: net.DestinationFromAddr(conn.RemoteAddr()), 461 Gateway: net.UnixDestination(w.address), 462 Tag: w.tag, 463 }) 464 content := new(session.Content) 465 if w.sniffingConfig != nil { 466 content.SniffingRequest.Enabled = w.sniffingConfig.Enabled 467 content.SniffingRequest.OverrideDestinationForProtocol = w.sniffingConfig.DestinationOverride 468 content.SniffingRequest.MetadataOnly = w.sniffingConfig.MetadataOnly 469 } 470 ctx = session.ContextWithContent(ctx, content) 471 if w.uplinkCounter != nil || w.downlinkCounter != nil { 472 conn = &internet.StatCouterConnection{ 473 Connection: conn, 474 ReadCounter: w.uplinkCounter, 475 WriteCounter: w.downlinkCounter, 476 } 477 } 478 if err := w.proxy.Process(ctx, net.Network_UNIX, conn, w.dispatcher); err != nil { 479 newError("connection ends").Base(err).WriteToLog(session.ExportIDToError(ctx)) 480 } 481 cancel() 482 if err := conn.Close(); err != nil { 483 newError("failed to close connection").Base(err).WriteToLog(session.ExportIDToError(ctx)) 484 } 485 } 486 487 func (w *dsWorker) Proxy() proxy.Inbound { 488 return w.proxy 489 } 490 491 func (w *dsWorker) Port() net.Port { 492 return net.Port(0) 493 } 494 495 func (w *dsWorker) Start() error { 496 ctx := context.Background() 497 proxyEnvironment := envctx.EnvironmentFromContext(w.ctx).(environment.ProxyEnvironment) 498 transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("transport") 499 if err != nil { 500 return newError("unable to narrow environment to transport").Base(err) 501 } 502 ctx = envctx.ContextWithEnvironment(ctx, transportEnvironment) 503 hub, err := internet.ListenUnix(ctx, w.address, w.stream, func(conn internet.Connection) { 504 go w.callback(conn) 505 }) 506 if err != nil { 507 return newError("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err) 508 } 509 w.hub = hub 510 return nil 511 } 512 513 func (w *dsWorker) Close() error { 514 var errors []interface{} 515 if w.hub != nil { 516 if err := common.Close(w.hub); err != nil { 517 errors = append(errors, err) 518 } 519 if err := common.Close(w.proxy); err != nil { 520 errors = append(errors, err) 521 } 522 } 523 if len(errors) > 0 { 524 return newError("failed to close all resources").Base(newError(serial.Concat(errors...))) 525 } 526 527 return nil 528 }