diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index b6335fa8..d2f2b5e9 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -42,16 +42,17 @@ type TuicOption struct { DisableSni bool `proxy:"disable-sni,omitempty"` MaxUdpRelayPacketSize int `proxy:"max-udp-relay-packet-size,omitempty"` - FastOpen bool `proxy:"fast-open,omitempty"` - MaxOpenStreams int `proxy:"max-open-streams,omitempty"` - SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` - Fingerprint string `proxy:"fingerprint,omitempty"` - CustomCA string `proxy:"ca,omitempty"` - CustomCAString string `proxy:"ca-str,omitempty"` - ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"` - ReceiveWindow int `proxy:"recv-window,omitempty"` - DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"` - SNI string `proxy:"sni,omitempty"` + FastOpen bool `proxy:"fast-open,omitempty"` + MaxOpenStreams int `proxy:"max-open-streams,omitempty"` + SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` + Fingerprint string `proxy:"fingerprint,omitempty"` + CustomCA string `proxy:"ca,omitempty"` + CustomCAString string `proxy:"ca-str,omitempty"` + ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"` + ReceiveWindow int `proxy:"recv-window,omitempty"` + DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"` + MaxDatagramFrameSize int `proxy:"max-datagram-frame-size,omitempty"` + SNI string `proxy:"sni,omitempty"` } // DialContext implements C.ProxyAdapter @@ -175,6 +176,15 @@ func NewTuic(option TuicOption) (*Tuic, error) { option.MaxOpenStreams = 100 } + if option.MaxDatagramFrameSize == 0 { + option.MaxDatagramFrameSize = option.MaxUdpRelayPacketSize + tuic.PacketOverHead + } + + if option.MaxDatagramFrameSize > 1400 { + option.MaxDatagramFrameSize = 1400 + } + option.MaxUdpRelayPacketSize = option.MaxDatagramFrameSize - tuic.PacketOverHead + // ensure server's incoming stream can handle correctly, increase to 1.1x quicMaxOpenStreams := int64(option.MaxOpenStreams) quicMaxOpenStreams = quicMaxOpenStreams + int64(math.Ceil(float64(quicMaxOpenStreams)/10.0)) @@ -187,6 +197,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { MaxIncomingUniStreams: quicMaxOpenStreams, KeepAlivePeriod: time.Duration(option.HeartbeatInterval) * time.Millisecond, DisablePathMTUDiscovery: option.DisableMTUDiscovery, + MaxDatagramFrameSize: int64(option.MaxDatagramFrameSize), EnableDatagrams: true, } if option.ReceiveWindowConn == 0 { diff --git a/go.mod b/go.mod index 2404ff99..0f44f260 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.33.1 + github.com/metacubex/quic-go v0.33.2 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 github.com/metacubex/sing-tun v0.1.2 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb diff --git a/go.sum b/go.sum index 64264a0f..881d2b70 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be h1:zg8lXHo8t+dCSPHQ/wCJui1V+eO9TSh9NoIjKNvUykA= github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.33.1 h1:ZIxZFGivpSLOEZuuNkLy+aPvo1RP4uRBjNg3SAkXwIg= -github.com/metacubex/quic-go v0.33.1/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +github.com/metacubex/quic-go v0.33.2 h1:DsDdTaLvGI0eVV0C/jzPrw5MBwK5VR20r5Mt9uU5Djw= +github.com/metacubex/quic-go v0.33.2/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= github.com/metacubex/sing-tun v0.1.2 h1:rQzy+11rt2ZCpCNIsFab5lWoYDTqkdaurofHo8f97yU= diff --git a/listener/config/tuic.go b/listener/config/tuic.go index c584bbf5..991a04c9 100644 --- a/listener/config/tuic.go +++ b/listener/config/tuic.go @@ -15,6 +15,7 @@ type TuicServer struct { AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` ALPN []string `yaml:"alpn" json:"alpn,omitempty"` MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` + MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` } func (t TuicServer) String() string { diff --git a/listener/tuic/server.go b/listener/tuic/server.go index a7ad69f6..92cc0b37 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -61,6 +61,16 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet quicConfig.InitialConnectionReceiveWindow = tuic.DefaultConnectionReceiveWindow / 10 quicConfig.MaxConnectionReceiveWindow = tuic.DefaultConnectionReceiveWindow + if config.MaxUdpRelayPacketSize == 0 { + config.MaxUdpRelayPacketSize = 1500 + } + maxDatagramFrameSize := config.MaxUdpRelayPacketSize + tuic.PacketOverHead + if maxDatagramFrameSize > 1400 { + maxDatagramFrameSize = 1400 + } + config.MaxUdpRelayPacketSize = maxDatagramFrameSize - tuic.PacketOverHead + quicConfig.MaxDatagramFrameSize = int64(maxDatagramFrameSize) + tokens := make([][32]byte, len(config.Token)) for i, token := range config.Token { tokens[i] = tuic.GenTKN(token) diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index dfa43e1f..d5955e13 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -1,7 +1,6 @@ package tuic import ( - "fmt" "net" "net/netip" "sync" @@ -201,7 +200,7 @@ 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 q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize { - return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.maxUdpRelayPacketSize) + return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize) } if q.closed { return 0, net.ErrClosed diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index b14074a7..570b6e54 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -282,6 +282,8 @@ func (c Packet) BytesLen() int { return c.CommandHead.BytesLen() + 4 + 2 + c.ADDR.BytesLen() + len(c.DATA) } +var PacketOverHead = NewPacket(0, 0, NewAddressAddrPort(netip.AddrPortFrom(netip.IPv6Unspecified(), 0)), nil).BytesLen() + type Dissociate struct { CommandHead ASSOC_ID uint32