github.com/sagernet/sing-box@v1.9.0-rc.20/inbound/tproxy.go (about) 1 package inbound 2 3 import ( 4 "context" 5 "net" 6 "net/netip" 7 "syscall" 8 "time" 9 10 "github.com/sagernet/sing-box/adapter" 11 "github.com/sagernet/sing-box/common/redir" 12 C "github.com/sagernet/sing-box/constant" 13 "github.com/sagernet/sing-box/log" 14 "github.com/sagernet/sing-box/option" 15 "github.com/sagernet/sing/common" 16 "github.com/sagernet/sing/common/buf" 17 "github.com/sagernet/sing/common/control" 18 E "github.com/sagernet/sing/common/exceptions" 19 M "github.com/sagernet/sing/common/metadata" 20 N "github.com/sagernet/sing/common/network" 21 "github.com/sagernet/sing/common/udpnat" 22 ) 23 24 type TProxy struct { 25 myInboundAdapter 26 udpNat *udpnat.Service[netip.AddrPort] 27 } 28 29 func NewTProxy(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TProxyInboundOptions) *TProxy { 30 tproxy := &TProxy{ 31 myInboundAdapter: myInboundAdapter{ 32 protocol: C.TypeTProxy, 33 network: options.Network.Build(), 34 ctx: ctx, 35 router: router, 36 logger: logger, 37 tag: tag, 38 listenOptions: options.ListenOptions, 39 }, 40 } 41 var udpTimeout time.Duration 42 if options.UDPTimeout != 0 { 43 udpTimeout = time.Duration(options.UDPTimeout) 44 } else { 45 udpTimeout = C.UDPTimeout 46 } 47 tproxy.connHandler = tproxy 48 tproxy.oobPacketHandler = tproxy 49 tproxy.udpNat = udpnat.New[netip.AddrPort](int64(udpTimeout.Seconds()), tproxy.upstreamContextHandler()) 50 tproxy.packetUpstream = tproxy.udpNat 51 return tproxy 52 } 53 54 func (t *TProxy) Start() error { 55 err := t.myInboundAdapter.Start() 56 if err != nil { 57 return err 58 } 59 if t.tcpListener != nil { 60 err = control.Conn(common.MustCast[syscall.Conn](t.tcpListener), func(fd uintptr) error { 61 return redir.TProxy(fd, M.SocksaddrFromNet(t.tcpListener.Addr()).Addr.Is6()) 62 }) 63 if err != nil { 64 return E.Cause(err, "configure tproxy TCP listener") 65 } 66 } 67 if t.udpConn != nil { 68 err = control.Conn(t.udpConn, func(fd uintptr) error { 69 return redir.TProxy(fd, M.SocksaddrFromNet(t.udpConn.LocalAddr()).Addr.Is6()) 70 }) 71 if err != nil { 72 return E.Cause(err, "configure tproxy UDP listener") 73 } 74 } 75 return nil 76 } 77 78 func (t *TProxy) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 79 metadata.Destination = M.SocksaddrFromNet(conn.LocalAddr()).Unwrap() 80 return t.newConnection(ctx, conn, metadata) 81 } 82 83 func (t *TProxy) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, oob []byte, metadata adapter.InboundContext) error { 84 destination, err := redir.GetOriginalDestinationFromOOB(oob) 85 if err != nil { 86 return E.Cause(err, "get tproxy destination") 87 } 88 metadata.Destination = M.SocksaddrFromNetIP(destination).Unwrap() 89 t.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) { 90 return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), &tproxyPacketWriter{ctx: ctx, source: natConn, destination: metadata.Destination} 91 }) 92 return nil 93 } 94 95 type tproxyPacketWriter struct { 96 ctx context.Context 97 source N.PacketConn 98 destination M.Socksaddr 99 conn *net.UDPConn 100 } 101 102 func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { 103 defer buffer.Release() 104 conn := w.conn 105 if w.destination == destination && conn != nil { 106 _, err := conn.WriteToUDPAddrPort(buffer.Bytes(), M.AddrPortFromNet(w.source.LocalAddr())) 107 if err != nil { 108 w.conn = nil 109 } 110 return err 111 } 112 var listener net.ListenConfig 113 listener.Control = control.Append(listener.Control, control.ReuseAddr()) 114 listener.Control = control.Append(listener.Control, redir.TProxyWriteBack()) 115 packetConn, err := listener.ListenPacket(w.ctx, "udp", destination.String()) 116 if err != nil { 117 return err 118 } 119 udpConn := packetConn.(*net.UDPConn) 120 if w.destination == destination { 121 w.conn = udpConn 122 } else { 123 defer udpConn.Close() 124 } 125 return common.Error(udpConn.WriteToUDPAddrPort(buffer.Bytes(), M.AddrPortFromNet(w.source.LocalAddr()))) 126 } 127 128 func (w *tproxyPacketWriter) Close() error { 129 return common.Close(common.PtrOrNil(w.conn)) 130 }