From fd0580bfddeb840597379034ab8bae509e7562ae Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Mar 2023 14:05:16 +0800 Subject: [PATCH] fix: sing_tun apply udpTimeout when using gvisor stack --- go.mod | 4 +-- go.sum | 8 +++--- listener/sing/sing.go | 49 ++++++++++++++++++++++++++----------- listener/sing_tun/server.go | 10 +++++--- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 661adc9a..2ae77925 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.0 + github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -42,7 +42,7 @@ require ( go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 golang.org/x/crypto v0.7.0 - golang.org/x/exp v0.0.0-20221205204356-47842c84f3db + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/net v0.8.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.6.0 diff --git a/go.sum b/go.sum index 6f3236f2..db54998b 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.0 h1:iyc4TaeXG5XYXixl48zSDDTw46C9NOEAVFq6ZE0dA2k= -github.com/sagernet/sing v0.2.0/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef h1:gCIUmEaAbTZnQU6DPcnJkqnD9D0W2f3mp/mx0HKiWI8= +github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= @@ -173,8 +173,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 9436fcfb..d6ff81c3 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -3,6 +3,7 @@ package sing import ( "context" "errors" + "go.uber.org/atomic" "golang.org/x/exp/slices" "net" "net/netip" @@ -14,6 +15,7 @@ import ( "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" + tun "github.com/metacubex/sing-tun" vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" @@ -25,10 +27,11 @@ import ( const UDPTimeout = 5 * time.Minute type ListenerHandler struct { - TcpIn chan<- C.ConnContext - UdpIn chan<- C.PacketAdapter - Type C.Type - Additions []inbound.Addition + TcpIn chan<- C.ConnContext + UdpIn chan<- C.PacketAdapter + Type C.Type + Additions []inbound.Addition + UDPTimeout time.Duration } type waitCloseConn struct { @@ -96,11 +99,23 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() + lastWrite := atomic.NewTime(time.Now()) + needTimeout := tun.NeedTimeoutFromContext(ctx) // gvisor stack call NewPacketConnection() with ContextWithNeedTimeout() + udpTimeout := h.UDPTimeout + if udpTimeout == 0 { + udpTimeout = UDPTimeout + } for { buff := buf.NewPacket() // do not use stack buffer + if needTimeout { + _ = conn.SetReadDeadline(time.Now().Add(udpTimeout)) + } dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() + if needTimeout && E.IsTimeout(err) && time.Now().Sub(lastWrite.Load()) < udpTimeout { + continue // someone write successful in time, so we continue read instead of return error + } if E.IsClosed(err) { break } @@ -108,11 +123,12 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } target := socks5.ParseAddr(dest.String()) packet := &packet{ - conn: &conn2, - mutex: &mutex, - rAddr: metadata.Source.UDPAddr(), - lAddr: conn.LocalAddr(), - buff: buff, + conn: &conn2, + mutex: &mutex, + rAddr: metadata.Source.UDPAddr(), + lAddr: conn.LocalAddr(), + buff: buff, + lastWrite: lastWrite, } select { case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...): @@ -127,11 +143,12 @@ func (h *ListenerHandler) NewError(ctx context.Context, err error) { } type packet struct { - conn *network.PacketConn - mutex *sync.Mutex - rAddr net.Addr - lAddr net.Addr - buff *buf.Buffer + conn *network.PacketConn + mutex *sync.Mutex + rAddr net.Addr + lAddr net.Addr + buff *buf.Buffer + lastWrite *atomic.Time } func (c *packet) Data() []byte { @@ -159,6 +176,10 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { return } err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) + if err != nil { + return + } + c.lastWrite.Store(time.Now()) return } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index d7f42c98..ada9d1c2 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -8,6 +8,7 @@ import ( "runtime" "strconv" "strings" + "time" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/component/dialer" @@ -151,10 +152,11 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte handler := &ListenerHandler{ ListenerHandler: sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, - Type: C.TUN, - Additions: additions, + TcpIn: tcpIn, + UdpIn: udpIn, + Type: C.TUN, + Additions: additions, + UDPTimeout: time.Second * time.Duration(udpTimeout), }, DnsAdds: dnsAdds, }