diff --git a/common/listener/listener.go b/common/listener/listener.go index 8a4cad34..7d49d664 100644 --- a/common/listener/listener.go +++ b/common/listener/listener.go @@ -32,6 +32,7 @@ type Listener struct { disablePacketOutput bool setSystemProxy bool systemProxySOCKS bool + tproxy bool tcpListener net.Listener systemProxy settings.SystemProxy @@ -54,6 +55,7 @@ type Options struct { DisablePacketOutput bool SetSystemProxy bool SystemProxySOCKS bool + TProxy bool } func New( @@ -71,6 +73,7 @@ func New( disablePacketOutput: options.DisablePacketOutput, setSystemProxy: options.SetSystemProxy, systemProxySOCKS: options.SystemProxySOCKS, + tproxy: options.TProxy, } } diff --git a/common/listener/listener_tcp.go b/common/listener/listener_tcp.go index b8ecc1db..8b2f7e71 100644 --- a/common/listener/listener_tcp.go +++ b/common/listener/listener_tcp.go @@ -3,9 +3,11 @@ package listener import ( "net" "net/netip" + "syscall" "time" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/redir" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing/common/control" @@ -51,6 +53,13 @@ func (l *Listener) ListenTCP() (net.Listener, error) { } setMultiPathTCP(&listenConfig) } + if l.tproxy { + listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error { + return control.Raw(conn, func(fd uintptr) error { + return redir.TProxy(fd, M.ParseSocksaddr(address).IsIPv6(), false) + }) + }) + } tcpListener, err := ListenNetworkNamespace[net.Listener](l.listenOptions.NetNs, func() (net.Listener, error) { if l.listenOptions.TCPFastOpen { var tfoConfig tfo.ListenConfig diff --git a/common/listener/listener_udp.go b/common/listener/listener_udp.go index d189bf13..61db69ce 100644 --- a/common/listener/listener_udp.go +++ b/common/listener/listener_udp.go @@ -5,8 +5,10 @@ import ( "net" "net/netip" "os" + "syscall" "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/redir" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" @@ -36,6 +38,13 @@ func (l *Listener) ListenUDP() (net.PacketConn, error) { if !udpFragment { listenConfig.Control = control.Append(listenConfig.Control, control.DisableUDPFragment()) } + if l.tproxy { + listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error { + return control.Raw(conn, func(fd uintptr) error { + return redir.TProxy(fd, M.ParseSocksaddr(address).IsIPv6(), true) + }) + }) + } udpConn, err := ListenNetworkNamespace[net.PacketConn](l.listenOptions.NetNs, func() (net.PacketConn, error) { return listenConfig.ListenPacket(l.ctx, M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.String()) }) diff --git a/common/redir/tproxy_linux.go b/common/redir/tproxy_linux.go index ccf94037..a3ccade0 100644 --- a/common/redir/tproxy_linux.go +++ b/common/redir/tproxy_linux.go @@ -12,7 +12,7 @@ import ( "golang.org/x/sys/unix" ) -func TProxy(fd uintptr, isIPv6 bool) error { +func TProxy(fd uintptr, isIPv6 bool, isUDP bool) error { err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) if err == nil { err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1) @@ -20,11 +20,13 @@ func TProxy(fd uintptr, isIPv6 bool) error { if err == nil && isIPv6 { err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1) } - if err == nil { - err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1) - } - if err == nil && isIPv6 { - err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1) + if isUDP { + if err == nil { + err = syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, 1) + } + if err == nil && isIPv6 { + err = syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_RECVORIGDSTADDR, 1) + } } return err } diff --git a/common/redir/tproxy_other.go b/common/redir/tproxy_other.go index 5869a195..42e31fee 100644 --- a/common/redir/tproxy_other.go +++ b/common/redir/tproxy_other.go @@ -9,7 +9,7 @@ import ( "github.com/sagernet/sing/common/control" ) -func TProxy(fd uintptr, isIPv6 bool) error { +func TProxy(fd uintptr, isIPv6 bool, isUDP bool) error { return os.ErrInvalid } diff --git a/protocol/redirect/tproxy.go b/protocol/redirect/tproxy.go index 1b3e8dae..f0b82bb1 100644 --- a/protocol/redirect/tproxy.go +++ b/protocol/redirect/tproxy.go @@ -4,7 +4,6 @@ import ( "context" "net" "net/netip" - "syscall" "time" "github.com/sagernet/sing-box/adapter" @@ -17,7 +16,6 @@ import ( "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/control" - E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/udpnat2" @@ -57,6 +55,7 @@ func NewTProxy(ctx context.Context, router adapter.Router, logger log.ContextLog Listen: options.ListenOptions, ConnectionHandler: tproxy, OOBPacketHandler: tproxy, + TProxy: true, }) return tproxy, nil } @@ -65,27 +64,7 @@ func (t *TProxy) Start(stage adapter.StartStage) error { if stage != adapter.StartStateStart { return nil } - err := t.listener.Start() - if err != nil { - return err - } - if listener := t.listener.TCPListener(); listener != nil { - err = control.Conn(common.MustCast[syscall.Conn](listener), func(fd uintptr) error { - return redir.TProxy(fd, M.SocksaddrFromNet(listener.Addr()).Addr.Is6()) - }) - if err != nil { - return E.Cause(err, "configure tproxy TCP listener") - } - } - if conn := t.listener.UDPConn(); conn != nil { - err = control.Conn(conn, func(fd uintptr) error { - return redir.TProxy(fd, M.SocksaddrFromNet(conn.LocalAddr()).Addr.Is6()) - }) - if err != nil { - return E.Cause(err, "configure tproxy UDP listener") - } - } - return nil + return t.listener.Start() } func (t *TProxy) Close() error { @@ -154,10 +133,10 @@ func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socks return err } } - var listener net.ListenConfig - listener.Control = control.Append(listener.Control, control.ReuseAddr()) - listener.Control = control.Append(listener.Control, redir.TProxyWriteBack()) - packetConn, err := w.listener.ListenPacket(listener, w.ctx, "udp", destination.String()) + var listenConfig net.ListenConfig + listenConfig.Control = control.Append(listenConfig.Control, control.ReuseAddr()) + listenConfig.Control = control.Append(listenConfig.Control, redir.TProxyWriteBack()) + packetConn, err := w.listener.ListenPacket(listenConfig, w.ctx, "udp", destination.String()) if err != nil { return err }