fix: sing_tun apply udpTimeout when using gvisor stack

This commit is contained in:
gVisor bot 2023-03-23 14:05:16 +08:00
parent 26ed6eaf69
commit e36bb24b43
4 changed files with 47 additions and 24 deletions

4
go.mod
View file

@ -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

8
go.sum
View file

@ -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=

View file

@ -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
}

View file

@ -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,
}