From f54235140405b41010a775e9c284c92ca3d8bc4a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 25 Nov 2022 12:43:23 +0800 Subject: [PATCH] chore: tuic add max_udp_relay_packet_size --- README.md | 1 + adapter/outbound/tuic.go | 63 ++++++++++++++++++++++++++-------------- docs/config.yaml | 1 + transport/tuic/client.go | 25 +++++++++++----- 4 files changed, 60 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 9a627673..c0f39939 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ proxies: # request_timeout: 8000 udp_relay_mode: native # Available: "native", "quic". Default: "native" # congestion_controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic" + # max_udp_relay_packet_size: 1500 # skip-cert-verify: true ``` diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 88dbf03d..502a751d 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -29,18 +29,19 @@ type Tuic struct { type TuicOption struct { BasicOption - Name string `proxy:"name"` - Server string `proxy:"server"` - Port int `proxy:"port"` - Token string `proxy:"token"` - Ip string `proxy:"ip,omitempty"` - HeartbeatInterval int `proxy:"heartbeat_interval,omitempty"` - ALPN []string `proxy:"alpn,omitempty"` - ReduceRtt bool `proxy:"reduce_rtt,omitempty"` - RequestTimeout int `proxy:"request_timeout,omitempty"` - UdpRelayMode string `proxy:"udp_relay_mode,omitempty"` - CongestionController string `proxy:"congestion_controller,omitempty"` - DisableSni bool `proxy:"disable_sni,omitempty"` + Name string `proxy:"name"` + Server string `proxy:"server"` + Port int `proxy:"port"` + Token string `proxy:"token"` + Ip string `proxy:"ip,omitempty"` + HeartbeatInterval int `proxy:"heartbeat_interval,omitempty"` + ALPN []string `proxy:"alpn,omitempty"` + ReduceRtt bool `proxy:"reduce_rtt,omitempty"` + RequestTimeout int `proxy:"request_timeout,omitempty"` + UdpRelayMode string `proxy:"udp_relay_mode,omitempty"` + CongestionController string `proxy:"congestion_controller,omitempty"` + DisableSni bool `proxy:"disable_sni,omitempty"` + MaxUdpRelayPacketSize int `proxy:"max_udp_relay_packet_size,omitempty"` SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` Fingerprint string `proxy:"fingerprint,omitempty"` @@ -152,6 +153,10 @@ func NewTuic(option TuicOption) (*Tuic, error) { option.UdpRelayMode = "native" } + if option.MaxUdpRelayPacketSize == 0 { + option.MaxUdpRelayPacketSize = 1500 + } + quicConfig := &quic.Config{ InitialStreamReceiveWindow: uint64(option.ReceiveWindowConn), MaxStreamReceiveWindow: uint64(option.ReceiveWindowConn), @@ -186,18 +191,32 @@ func NewTuic(option TuicOption) (*Tuic, error) { clientMapMutex.Lock() defer clientMapMutex.Unlock() - if client, ok := clientMap[o]; ok && client != nil { - return client + for key := range clientMap { + client := clientMap[key] + if client == nil { + delete(clientMap, key) // It is safe in Golang + continue + } + if key == o { + client.LastVisited = time.Now() + return client + } + if time.Now().Sub(client.LastVisited) > 30*time.Minute { + delete(clientMap, key) + continue + } } client := &tuic.Client{ - TlsConfig: tlsConfig, - QuicConfig: quicConfig, - Host: host, - Token: tkn, - UdpRelayMode: option.UdpRelayMode, - CongestionController: option.CongestionController, - ReduceRtt: option.ReduceRtt, - RequestTimeout: option.RequestTimeout, + TlsConfig: tlsConfig, + QuicConfig: quicConfig, + Host: host, + Token: tkn, + UdpRelayMode: option.UdpRelayMode, + CongestionController: option.CongestionController, + ReduceRtt: option.ReduceRtt, + RequestTimeout: option.RequestTimeout, + MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, + LastVisited: time.Now(), } clientMap[o] = client runtime.SetFinalizer(client, closeTuicClient) diff --git a/docs/config.yaml b/docs/config.yaml index 8688564a..d187a32d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -471,6 +471,7 @@ proxies: # request_timeout: 8000 udp_relay_mode: native # Available: "native", "quic". Default: "native" # congestion_controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic" + # max_udp_relay_packet_size: 1500 # skip-cert-verify: true # ShadowsocksR diff --git a/transport/tuic/client.go b/transport/tuic/client.go index eaa981ab..ad5cb7e9 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -6,6 +6,7 @@ import ( "context" "crypto/tls" "errors" + "fmt" "math/rand" "net" "net/netip" @@ -20,14 +21,17 @@ import ( ) type Client struct { - TlsConfig *tls.Config - QuicConfig *quic.Config - Host string - Token [32]byte - UdpRelayMode string - CongestionController string - ReduceRtt bool - RequestTimeout int + TlsConfig *tls.Config + QuicConfig *quic.Config + Host string + Token [32]byte + UdpRelayMode string + CongestionController string + ReduceRtt bool + RequestTimeout int + MaxUdpRelayPacketSize int + + LastVisited time.Time quicConn quic.Connection connMutex sync.Mutex @@ -237,6 +241,7 @@ func (t *Client) DialContext(ctx context.Context, metadata *C.Metadata, dialFn f } _, err = buf.WriteTo(stream) if err != nil { + _ = stream.Close() return nil, err } return stream, err @@ -379,6 +384,9 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err } func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + if len(p) > q.client.MaxUdpRelayPacketSize { + return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.client.MaxUdpRelayPacketSize) + } defer func() { q.client.deferQuicConn(q.quicConn, err) }() @@ -401,6 +409,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro } _, err = buf.WriteTo(stream) if err != nil { + _ = stream.Close() return } err = stream.Close()