diff --git a/app/dns/nameserver_quic.go b/app/dns/nameserver_quic.go index 2d56f43e69cb..f256ee957caf 100644 --- a/app/dns/nameserver_quic.go +++ b/app/dns/nameserver_quic.go @@ -9,7 +9,7 @@ import ( "sync/atomic" "time" - "github.com/quic-go/quic-go" + "github.com/refraction-networking/uquic" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/errors" @@ -400,7 +400,7 @@ func (s *QUICNameServer) openConnection() (quic.Connection, error) { HandshakeIdleTimeout: handshakeTimeout, } tlsConfig.ServerName = s.destination.Address.String() - conn, err := quic.DialAddr(context.Background(), s.destination.NetAddr(), tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ)), quicConfig) + conn, err := quic.DialAddr(context.Background(), s.destination.NetAddr(), tls.ToUTLSConfig(tlsConfig.GetTLSConfig(tls.WithNextProto("http/1.1", http2.NextProtoTLS, NextProtoDQ))), quicConfig) log.Record(&log.AccessMessage{ From: "DNS", To: s.destination, diff --git a/common/protocol/quic/sniff.go b/common/protocol/quic/sniff.go index bf4614648420..356f2de2c40b 100644 --- a/common/protocol/quic/sniff.go +++ b/common/protocol/quic/sniff.go @@ -7,7 +7,7 @@ import ( "encoding/binary" "io" - "github.com/quic-go/quic-go/quicvarint" + "github.com/refraction-networking/uquic/quicvarint" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/bytespool" diff --git a/go.mod b/go.mod index e60acb4ce548..33e69062628b 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/miekg/dns v1.1.61 github.com/pelletier/go-toml v1.9.5 github.com/pires/go-proxyproto v0.7.0 - github.com/quic-go/quic-go v0.45.1 + github.com/refraction-networking/uquic v0.0.6 github.com/refraction-networking/utls v1.6.7 github.com/sagernet/sing v0.4.1 github.com/sagernet/sing-shadowsocks v0.2.7 @@ -39,8 +39,11 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/francoispqt/gojay v1.2.13 // indirect + github.com/gaukas/clienthellod v0.4.2 // indirect + github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect github.com/klauspost/compress v1.17.8 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect diff --git a/go.sum b/go.sum index 15137ad3c8e7..ea10b46ce1dd 100644 --- a/go.sum +++ b/go.sum @@ -31,6 +31,10 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/gaukas/clienthellod v0.4.2 h1:LPJ+LSeqt99pqeCV4C0cllk+pyWmERisP7w6qWr7eqE= +github.com/gaukas/clienthellod v0.4.2/go.mod h1:M57+dsu0ZScvmdnNxaxsDPM46WhSEdPYAOdNgfL7IKA= +github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= +github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4= github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= @@ -57,6 +61,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= @@ -78,9 +84,11 @@ github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0N github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -112,8 +120,8 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7q github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA= -github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/refraction-networking/uquic v0.0.6 h1:9ol1oOaOpHDeeDlBY7u228jK+T5oic35QrFimHVaCMM= +github.com/refraction-networking/uquic v0.0.6/go.mod h1:TFgTmV/yqVCMEXVwP7z7PMAhzye02rFHLV6cRAg59jc= github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= @@ -187,6 +195,8 @@ golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +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.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= @@ -247,6 +257,7 @@ golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= @@ -279,8 +290,9 @@ google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/transport/internet/quic/conn.go b/transport/internet/quic/conn.go index 11bee7c543a9..1b3da91e29b0 100644 --- a/transport/internet/quic/conn.go +++ b/transport/internet/quic/conn.go @@ -7,7 +7,7 @@ import ( "syscall" "time" - "github.com/quic-go/quic-go" + "github.com/refraction-networking/uquic" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/net" diff --git a/transport/internet/quic/dialer.go b/transport/internet/quic/dialer.go index df73e169d4fc..516f03aaa8cd 100644 --- a/transport/internet/quic/dialer.go +++ b/transport/internet/quic/dialer.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/quic-go/quic-go" - "github.com/quic-go/quic-go/logging" - "github.com/quic-go/quic-go/qlog" + "github.com/refraction-networking/uquic" + "github.com/refraction-networking/uquic/logging" + "github.com/refraction-networking/uquic/qlog" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" @@ -169,7 +169,7 @@ func (s *clientConnections) openConnection(ctx context.Context, destAddr net.Add ConnectionIDLength: 12, Conn: sysConn, } - conn, err := tr.Dial(context.Background(), destAddr, tlsConfig.GetTLSConfig(tls.WithDestination(dest)), quicConfig) + conn, err := tr.Dial(context.Background(), destAddr, tls.ToUTLSConfig(tlsConfig.GetTLSConfig(tls.WithDestination(dest))), quicConfig) if err != nil { sysConn.Close() return nil, err diff --git a/transport/internet/quic/hub.go b/transport/internet/quic/hub.go index de8919fdb1e8..1c2b30c3cd42 100644 --- a/transport/internet/quic/hub.go +++ b/transport/internet/quic/hub.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/quic-go/quic-go" - "github.com/quic-go/quic-go/logging" - "github.com/quic-go/quic-go/qlog" + "github.com/refraction-networking/uquic" + "github.com/refraction-networking/uquic/logging" + "github.com/refraction-networking/uquic/qlog" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" @@ -123,7 +123,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti ConnectionIDLength: 12, Conn: conn, } - qListener, err := tr.Listen(tlsConfig.GetTLSConfig(), quicConfig) + qListener, err := tr.Listen(tls.ToUTLSConfig(tlsConfig.GetTLSConfig()), quicConfig) if err != nil { conn.Close() return nil, err diff --git a/transport/internet/quic/qlogWriter.go b/transport/internet/quic/qlogWriter.go index 54284d29cea6..20c9f811f243 100644 --- a/transport/internet/quic/qlogWriter.go +++ b/transport/internet/quic/qlogWriter.go @@ -1,6 +1,6 @@ package quic -import "github.com/quic-go/quic-go" +import "github.com/refraction-networking/uquic" type QlogWriter struct { connID quic.ConnectionID diff --git a/transport/internet/quic/quic_test.go b/transport/internet/quic/quic_test.go index ab07105895a0..402926ee8558 100644 --- a/transport/internet/quic/quic_test.go +++ b/transport/internet/quic/quic_test.go @@ -24,20 +24,18 @@ import ( func TestQuicConnection(t *testing.T) { port := udp.PickPort() - listener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{ + streamSettings := &internet.MemoryStreamConfig{ ProtocolName: "quic", ProtocolSettings: &quic.Config{}, SecurityType: "tls", SecuritySettings: &tls.Config{ - Certificate: []*tls.Certificate{ - tls.ParseCertificate( - cert.MustGenerate(nil, - cert.DNSNames("www.example.com"), - ), - ), - }, + AllowInsecure: true, + Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.CommonName("localhost")))}, + NextProtocol: []string{"h3"}, }, - }, func(conn stat.Connection) { + } + + listener, err := quic.Listen(context.Background(), net.LocalHostIP, port, streamSettings, func(conn stat.Connection) { go func() { defer conn.Close() @@ -54,21 +52,11 @@ func TestQuicConnection(t *testing.T) { }() }) common.Must(err) - defer listener.Close() time.Sleep(time.Second) - dctx := context.Background() - conn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{ - ProtocolName: "quic", - ProtocolSettings: &quic.Config{}, - SecurityType: "tls", - SecuritySettings: &tls.Config{ - ServerName: "www.example.com", - AllowInsecure: true, - }, - }) + conn, err := quic.Dial(context.Background(), net.UDPDestination(net.DomainAddress("localhost"), port), streamSettings) common.Must(err) defer conn.Close() diff --git a/transport/internet/splithttp/dialer.go b/transport/internet/splithttp/dialer.go index 5c22f8453005..b547fd32ed1b 100644 --- a/transport/internet/splithttp/dialer.go +++ b/transport/internet/splithttp/dialer.go @@ -7,11 +7,14 @@ import ( "net/http" "net/url" "strconv" + "strings" "sync" "time" - "github.com/quic-go/quic-go" - "github.com/quic-go/quic-go/http3" + "github.com/refraction-networking/uquic" + "github.com/refraction-networking/uquic/http3" + utls "github.com/refraction-networking/utls" + "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/errors" @@ -93,10 +96,17 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in KeepAlivePeriod: 3 * time.Second, Allow0RTT: true, } + utlsConfig := &utls.Config{ + RootCAs: gotlsConfig.RootCAs, + ServerName: gotlsConfig.ServerName, + InsecureSkipVerify: gotlsConfig.InsecureSkipVerify, + VerifyPeerCertificate: gotlsConfig.VerifyPeerCertificate, + KeyLogWriter: gotlsConfig.KeyLogWriter, + } roundTripper := &http3.RoundTripper{ - TLSClientConfig: gotlsConfig, - QUICConfig: quicConfig, - Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { + TLSClientConfig: utlsConfig, + QuicConfig: quicConfig, + Dial: func(ctx context.Context, addr string, tlsCfg *utls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) if err != nil { return nil, err @@ -129,8 +139,42 @@ func getHTTPClient(ctx context.Context, dest net.Destination, streamSettings *in return quic.DialEarly(ctx, udpConn, udpAddr, tlsCfg, cfg) }, } - downloadTransport = roundTripper - uploadTransport = roundTripper + + if gotlsConfig == nil { + downloadTransport = roundTripper + uploadTransport = roundTripper + } else if tlsConfig.GetFingerprint() == "" { + downloadTransport = roundTripper + uploadTransport = roundTripper + } else { + var quicSpec quic.QUICSpec + var err error + + // fingerprints available for QUIC are different from those of TCP TLS, so it has been implemented this way for now + // so that users who previously used http1.1 or h2 may not have to adjust their configurations as much. + // it should be changed in the future. (When you do this there will be many users crying that her client stopped working) + if strings.Contains(strings.ToLower(tlsConfig.GetFingerprint()), "chrome") { + quicSpec, err = quic.QUICID2Spec(quic.QUICChrome_115) + } else if strings.Contains(strings.ToLower(tlsConfig.GetFingerprint()), "firefox") { + quicSpec, err = quic.QUICID2Spec(quic.QUICFirefox_116) + } else { + errors.LogError(ctx, "unknown fingerprint: ", tlsConfig.GetFingerprint()) + return nil + } + + if err != nil { + errors.LogError(ctx, tlsConfig.GetFingerprint()) + return nil + } + + uRoundTripper := http3.GetURoundTripper( + roundTripper, + &quicSpec, + nil, + ) + downloadTransport = uRoundTripper + uploadTransport = uRoundTripper + } } else if isH2 { downloadTransport = &http2.Transport{ DialTLSContext: func(ctxInner context.Context, network string, addr string, cfg *gotls.Config) (net.Conn, error) { diff --git a/transport/internet/splithttp/hub.go b/transport/internet/splithttp/hub.go index 1ce8da6b0966..9fea6dae18dd 100644 --- a/transport/internet/splithttp/hub.go +++ b/transport/internet/splithttp/hub.go @@ -11,8 +11,8 @@ import ( "sync" "time" - "github.com/quic-go/quic-go" - "github.com/quic-go/quic-go/http3" + "github.com/refraction-networking/uquic" + "github.com/refraction-networking/uquic/http3" "github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/net" @@ -269,7 +269,6 @@ func ListenSH(ctx context.Context, address net.Address, port net.Port, streamSet tlsConfig := getTLSConfig(streamSettings) l.isH3 = len(tlsConfig.NextProtos) == 1 && tlsConfig.NextProtos[0] == "h3" - if port == net.Port(0) { // unix listener, err = internet.ListenSystem(ctx, &net.UnixAddr{ Name: address.Domain(), @@ -285,9 +284,9 @@ func ListenSH(ctx context.Context, address net.Address, port net.Port, streamSet Port: int(port), }, streamSettings.SocketSettings) if err != nil { - return nil, errors.New("failed to listen UDP(for SH3) on ", address, ":", port).Base(err) + return nil, errors.New("failed to listen UDP(for SH3) on ", address, ":", port).Base(err) } - h3listener, err := quic.ListenEarly(Conn,tlsConfig, nil) + h3listener, err := quic.ListenEarly(Conn, v2tls.ToUTLSConfig(tlsConfig), nil) if err != nil { return nil, errors.New("failed to listen QUIC(for SH3) on ", address, ":", port).Base(err) } diff --git a/transport/internet/splithttp/splithttp_test.go b/transport/internet/splithttp/splithttp_test.go index 5f59a738caa2..a571c6ff2cfc 100644 --- a/transport/internet/splithttp/splithttp_test.go +++ b/transport/internet/splithttp/splithttp_test.go @@ -2,6 +2,7 @@ package splithttp_test import ( "context" + "crypto/rand" gotls "crypto/tls" "fmt" gonet "net" @@ -10,7 +11,9 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" "github.com/xtls/xray-core/common" + "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/protocol/tls/cert" "github.com/xtls/xray-core/testing/servers/tcp" @@ -229,18 +232,52 @@ func Test_listenSHAndDial_QUIC(t *testing.T) { } listen, err := ListenSH(context.Background(), net.LocalHostIP, listenPort, streamSettings, func(conn stat.Connection) { go func() { - _ = conn.Close() + defer conn.Close() + + b := buf.New() + defer b.Release() + + for { + b.Clear() + if _, err := b.ReadFrom(conn); err != nil { + return + } + common.Must2(conn.Write(b.Bytes())) + } }() }) common.Must(err) defer listen.Close() + time.Sleep(time.Second) + conn, err := Dial(context.Background(), net.UDPDestination(net.DomainAddress("localhost"), listenPort), streamSettings) common.Must(err) - _ = conn.Close() + defer conn.Close() + + const N = 1024 + b1 := make([]byte, N) + common.Must2(rand.Read(b1)) + b2 := buf.New() + + common.Must2(conn.Write(b1)) + + b2.Clear() + common.Must2(b2.ReadFullFrom(conn, N)) + if r := cmp.Diff(b2.Bytes(), b1); r != "" { + t.Error(r) + } + + common.Must2(conn.Write(b1)) + + b2.Clear() + common.Must2(b2.ReadFullFrom(conn, N)) + if r := cmp.Diff(b2.Bytes(), b1); r != "" { + t.Error(r) + } end := time.Now() if !end.Before(start.Add(time.Second * 5)) { t.Error("end: ", end, " start: ", start) } -} \ No newline at end of file +} diff --git a/transport/internet/tls/tls.go b/transport/internet/tls/tls.go index 25889cb12adb..07b86343a6e9 100644 --- a/transport/internet/tls/tls.go +++ b/transport/internet/tls/tls.go @@ -131,17 +131,18 @@ func (c *UConn) NegotiatedProtocol() string { } func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn { - utlsConn := utls.UClient(c, copyConfig(config), *fingerprint) + utlsConn := utls.UClient(c, ToUTLSConfig(config), *fingerprint) return &UConn{UConn: utlsConn} } -func copyConfig(c *tls.Config) *utls.Config { +func ToUTLSConfig(c *tls.Config) *utls.Config { return &utls.Config{ RootCAs: c.RootCAs, ServerName: c.ServerName, InsecureSkipVerify: c.InsecureSkipVerify, VerifyPeerCertificate: c.VerifyPeerCertificate, KeyLogWriter: c.KeyLogWriter, + NextProtos: c.NextProtos, } }