fix: sing_tun apply udpTimeout when using gvisor stack

This commit is contained in:
wwqgtxx
2023-03-23 14:05:16 +08:00
parent 5737fbc23c
commit fd0580bfdd
4 changed files with 47 additions and 24 deletions

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