From f9f6b9df6ec6769ec6bb7d4fd0b29177cbc2bf55 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 3 Aug 2023 11:20:32 -0400 Subject: [PATCH 01/36] update qtls to restrict RSA keys in certificates to <= 8192 bits (#4012) --- go.mod | 2 +- go.sum | 4 ++-- integrationtests/gomodvendor/go.sum | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 53612c67..2f2a0ff0 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/onsi/ginkgo/v2 v2.9.5 github.com/onsi/gomega v1.27.6 github.com/quic-go/qpack v0.4.0 - github.com/quic-go/qtls-go1-20 v0.3.0 + github.com/quic-go/qtls-go1-20 v0.3.1 golang.org/x/crypto v0.4.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.10.0 diff --git a/go.sum b/go.sum index 4039bb07..c0ed9606 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,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/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= -github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= +github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= diff --git a/integrationtests/gomodvendor/go.sum b/integrationtests/gomodvendor/go.sum index 1336cd7c..ad9adb31 100644 --- a/integrationtests/gomodvendor/go.sum +++ b/integrationtests/gomodvendor/go.sum @@ -136,8 +136,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/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= -github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= +github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= From 18d3846d4f96f24f62bd8af2339fb860bb420be6 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 3 Aug 2023 20:33:19 -0400 Subject: [PATCH 02/36] set a net.Conn for tls.ClientHelloInfo.Conn used by GetCertificate (#4014) --- integrationtests/self/handshake_test.go | 26 ++++++++++++++++++++++++- internal/handshake/crypto_setup.go | 7 +++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/integrationtests/self/handshake_test.go b/integrationtests/self/handshake_test.go index 9652cb0d..f23ae77c 100644 --- a/integrationtests/self/handshake_test.go +++ b/integrationtests/self/handshake_test.go @@ -140,7 +140,7 @@ var _ = Describe("Handshake tests", func() { Expect(err).ToNot(HaveOccurred()) }) - It("has the right local and remote address on the ClientHelloInfo.Conn", func() { + It("has the right local and remote address on the tls.Config.GetConfigForClient ClientHelloInfo.Conn", func() { var local, remote net.Addr done := make(chan struct{}) tlsConf := &tls.Config{ @@ -164,6 +164,30 @@ var _ = Describe("Handshake tests", func() { Expect(conn.LocalAddr().(*net.UDPAddr).Port).To(Equal(remote.(*net.UDPAddr).Port)) }) + It("has the right local and remote address on the tls.Config.GetCertificate ClientHelloInfo.Conn", func() { + var local, remote net.Addr + done := make(chan struct{}) + tlsConf := getTLSConfig() + tlsConf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + defer close(done) + local = info.Conn.LocalAddr() + remote = info.Conn.RemoteAddr() + cert := tlsConf.Certificates[0] + return &cert, nil + } + runServer(tlsConf) + conn, err := quic.DialAddr( + context.Background(), + fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), + getTLSClientConfig(), + getQuicConfig(nil), + ) + Expect(err).ToNot(HaveOccurred()) + Eventually(done).Should(BeClosed()) + Expect(server.Addr()).To(Equal(local)) + Expect(conn.LocalAddr().(*net.UDPAddr).Port).To(Equal(remote.(*net.UDPAddr).Port)) + }) + It("works with a long certificate chain", func() { runServer(getTLSConfigWithLongCertChain()) _, err := quic.DialAddr( diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index b528f08e..7011a6fc 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -134,6 +134,13 @@ func NewCryptoSetupServer( return gcfc(info) } } + if quicConf.TLSConfig.GetCertificate != nil { + gc := quicConf.TLSConfig.GetCertificate + quicConf.TLSConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr} + return gc(info) + } + } cs.tlsConf = quicConf.TLSConfig cs.conn = qtls.QUICServer(quicConf) From 26c6fcc5495874f80ffebb04df9b318d748d4ebe Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 5 Aug 2023 10:02:24 -0400 Subject: [PATCH 03/36] add error handling when confirming handshake on HANDSHAKE_DONE frames (#4017) --- connection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/connection.go b/connection.go index fdf40d19..270bbbfe 100644 --- a/connection.go +++ b/connection.go @@ -1475,7 +1475,7 @@ func (s *connection) handleHandshakeDoneFrame() error { } } if !s.handshakeConfirmed { - s.handleHandshakeConfirmed() + return s.handleHandshakeConfirmed() } return nil } From 95ab7bdc9a392b0357598dd77caae66bd99a6b0b Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 5 Aug 2023 16:00:11 -0400 Subject: [PATCH 04/36] add tls.ClientHelloInfo.Conn for recursive GetConfigForClient calls (#4016) --- integrationtests/self/handshake_test.go | 37 +++------ internal/handshake/crypto_setup.go | 40 ++++++---- internal/handshake/crypto_setup_test.go | 100 +++++++++++++++++++----- 3 files changed, 118 insertions(+), 59 deletions(-) diff --git a/integrationtests/self/handshake_test.go b/integrationtests/self/handshake_test.go index f23ae77c..cccff8a6 100644 --- a/integrationtests/self/handshake_test.go +++ b/integrationtests/self/handshake_test.go @@ -142,13 +142,20 @@ var _ = Describe("Handshake tests", func() { It("has the right local and remote address on the tls.Config.GetConfigForClient ClientHelloInfo.Conn", func() { var local, remote net.Addr + var local2, remote2 net.Addr done := make(chan struct{}) tlsConf := &tls.Config{ GetConfigForClient: func(info *tls.ClientHelloInfo) (*tls.Config, error) { - defer close(done) local = info.Conn.LocalAddr() remote = info.Conn.RemoteAddr() - return getTLSConfig(), nil + conf := getTLSConfig() + conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + defer close(done) + local2 = info.Conn.LocalAddr() + remote2 = info.Conn.RemoteAddr() + return &(conf.Certificates[0]), nil + } + return conf, nil }, } runServer(tlsConf) @@ -162,30 +169,8 @@ var _ = Describe("Handshake tests", func() { Eventually(done).Should(BeClosed()) Expect(server.Addr()).To(Equal(local)) Expect(conn.LocalAddr().(*net.UDPAddr).Port).To(Equal(remote.(*net.UDPAddr).Port)) - }) - - It("has the right local and remote address on the tls.Config.GetCertificate ClientHelloInfo.Conn", func() { - var local, remote net.Addr - done := make(chan struct{}) - tlsConf := getTLSConfig() - tlsConf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - defer close(done) - local = info.Conn.LocalAddr() - remote = info.Conn.RemoteAddr() - cert := tlsConf.Certificates[0] - return &cert, nil - } - runServer(tlsConf) - conn, err := quic.DialAddr( - context.Background(), - fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), - getTLSClientConfig(), - getQuicConfig(nil), - ) - Expect(err).ToNot(HaveOccurred()) - Eventually(done).Should(BeClosed()) - Expect(server.Addr()).To(Equal(local)) - Expect(conn.LocalAddr().(*net.UDPAddr).Port).To(Equal(remote.(*net.UDPAddr).Port)) + Expect(local).To(Equal(local2)) + Expect(remote).To(Equal(remote2)) }) It("works with a long certificate chain", func() { diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index 7011a6fc..543e70e0 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -127,20 +127,7 @@ func NewCryptoSetupServer( quicConf := &qtls.QUICConfig{TLSConfig: tlsConf} qtls.SetupConfigForServer(quicConf, cs.allow0RTT, cs.getDataForSessionTicket, cs.accept0RTT) - if quicConf.TLSConfig.GetConfigForClient != nil { - gcfc := quicConf.TLSConfig.GetConfigForClient - quicConf.TLSConfig.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) { - info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr} - return gcfc(info) - } - } - if quicConf.TLSConfig.GetCertificate != nil { - gc := quicConf.TLSConfig.GetCertificate - quicConf.TLSConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr} - return gc(info) - } - } + addConnToClientHelloInfo(quicConf.TLSConfig, localAddr, remoteAddr) cs.tlsConf = quicConf.TLSConfig cs.conn = qtls.QUICServer(quicConf) @@ -148,6 +135,31 @@ func NewCryptoSetupServer( return cs } +// The tls.Config contains two callbacks that pass in a tls.ClientHelloInfo. +// Since crypto/tls doesn't do it, we need to make sure to set the Conn field with a fake net.Conn +// that allows the caller to get the local and the remote address. +func addConnToClientHelloInfo(conf *tls.Config, localAddr, remoteAddr net.Addr) { + if conf.GetConfigForClient != nil { + gcfc := conf.GetConfigForClient + conf.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) { + info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr} + c, err := gcfc(info) + if c != nil { + // We're returning a tls.Config here, so we need to apply this recursively. + addConnToClientHelloInfo(c, localAddr, remoteAddr) + } + return c, err + } + } + if conf.GetCertificate != nil { + gc := conf.GetCertificate + conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr} + return gc(info) + } + } +} + func newCryptoSetup( connID protocol.ConnectionID, tp *wire.TransportParameters, diff --git a/internal/handshake/crypto_setup_test.go b/internal/handshake/crypto_setup_test.go index 4b210d20..8b2c5efe 100644 --- a/internal/handshake/crypto_setup_test.go +++ b/internal/handshake/crypto_setup_test.go @@ -29,6 +29,25 @@ const ( ) var _ = Describe("Crypto Setup TLS", func() { + generateCert := func() tls.Certificate { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + Expect(err).ToNot(HaveOccurred()) + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{}, + SignatureAlgorithm: x509.SHA256WithRSA, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour), // valid for an hour + BasicConstraintsValid: true, + } + certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, priv.Public(), priv) + Expect(err).ToNot(HaveOccurred()) + return tls.Certificate{ + PrivateKey: priv, + Certificate: [][]byte{certDER}, + } + } + var clientConf, serverConf *tls.Config BeforeEach(func() { @@ -86,26 +105,69 @@ var _ = Describe("Crypto Setup TLS", func() { Expect(err.Error()).To(ContainSubstring("tls: handshake data received at wrong level")) }) - Context("doing the handshake", func() { - generateCert := func() tls.Certificate { - priv, err := rsa.GenerateKey(rand.Reader, 2048) - Expect(err).ToNot(HaveOccurred()) - tmpl := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{}, - SignatureAlgorithm: x509.SHA256WithRSA, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour), // valid for an hour - BasicConstraintsValid: true, - } - certDER, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, priv.Public(), priv) - Expect(err).ToNot(HaveOccurred()) - return tls.Certificate{ - PrivateKey: priv, - Certificate: [][]byte{certDER}, - } - } + Context("filling in a net.Conn in tls.ClientHelloInfo", func() { + var ( + local = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 42} + remote = &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1337} + ) + It("wraps GetCertificate", func() { + var localAddr, remoteAddr net.Addr + tlsConf := &tls.Config{ + GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + localAddr = info.Conn.LocalAddr() + remoteAddr = info.Conn.RemoteAddr() + cert := generateCert() + return &cert, nil + }, + } + addConnToClientHelloInfo(tlsConf, local, remote) + _, err := tlsConf.GetCertificate(&tls.ClientHelloInfo{}) + Expect(err).ToNot(HaveOccurred()) + Expect(localAddr).To(Equal(local)) + Expect(remoteAddr).To(Equal(remote)) + }) + + It("wraps GetConfigForClient", func() { + var localAddr, remoteAddr net.Addr + tlsConf := &tls.Config{ + GetConfigForClient: func(info *tls.ClientHelloInfo) (*tls.Config, error) { + localAddr = info.Conn.LocalAddr() + remoteAddr = info.Conn.RemoteAddr() + return &tls.Config{}, nil + }, + } + addConnToClientHelloInfo(tlsConf, local, remote) + _, err := tlsConf.GetConfigForClient(&tls.ClientHelloInfo{}) + Expect(err).ToNot(HaveOccurred()) + Expect(localAddr).To(Equal(local)) + Expect(remoteAddr).To(Equal(remote)) + }) + + It("wraps GetConfigForClient, recursively", func() { + var localAddr, remoteAddr net.Addr + tlsConf := &tls.Config{} + tlsConf.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) { + conf := tlsConf.Clone() + conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + localAddr = info.Conn.LocalAddr() + remoteAddr = info.Conn.RemoteAddr() + cert := generateCert() + return &cert, nil + } + return conf, nil + } + addConnToClientHelloInfo(tlsConf, local, remote) + conf, err := tlsConf.GetConfigForClient(&tls.ClientHelloInfo{}) + Expect(err).ToNot(HaveOccurred()) + _, err = conf.GetCertificate(&tls.ClientHelloInfo{}) + Expect(err).ToNot(HaveOccurred()) + Expect(localAddr).To(Equal(local)) + Expect(remoteAddr).To(Equal(remote)) + }) + }) + + Context("doing the handshake", func() { newRTTStatsWithRTT := func(rtt time.Duration) *utils.RTTStats { rttStats := &utils.RTTStats{} rttStats.UpdateRTT(rtt, 0, time.Now()) From aab4d4e4108459e70711f4785a4ab10b3d4d918e Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 5 Aug 2023 18:25:04 -0400 Subject: [PATCH 05/36] fix handling of ACK frames serialized after CRYPTO frames (#4018) --- connection.go | 31 ++++++++++++++++++++----- connection_test.go | 57 ++++++++++------------------------------------ 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/connection.go b/connection.go index 270bbbfe..b17f3ce8 100644 --- a/connection.go +++ b/connection.go @@ -718,20 +718,22 @@ func (s *connection) idleTimeoutStartTime() time.Time { } func (s *connection) handleHandshakeComplete() error { - s.handshakeComplete = true defer s.handshakeCtxCancel() // Once the handshake completes, we have derived 1-RTT keys. - // There's no point in queueing undecryptable packets for later decryption any more. + // There's no point in queueing undecryptable packets for later decryption anymore. s.undecryptablePackets = nil s.connIDManager.SetHandshakeComplete() s.connIDGenerator.SetHandshakeComplete() + // The server applies transport parameters right away, but the client side has to wait for handshake completion. + // During a 0-RTT connection, the client is only allowed to use the new transport parameters for 1-RTT packets. if s.perspective == protocol.PerspectiveClient { s.applyTransportParameters() return nil } + // All these only apply to the server side. if err := s.handleHandshakeConfirmed(); err != nil { return err } @@ -1229,6 +1231,7 @@ func (s *connection) handleFrames( if log != nil { frames = make([]logging.Frame, 0, 4) } + handshakeWasComplete := s.handshakeComplete var handleErr error for len(data) > 0 { l, frame, err := s.frameParser.ParseNext(data, encLevel, s.version) @@ -1265,6 +1268,17 @@ func (s *connection) handleFrames( return false, handleErr } } + + // Handle completion of the handshake after processing all the frames. + // This ensures that we correctly handle the following case on the server side: + // We receive a Handshake packet that contains the CRYPTO frame that allows us to complete the handshake, + // and an ACK serialized after that CRYPTO frame. In this case, we still want to process the ACK frame. + if !handshakeWasComplete && s.handshakeComplete { + if err := s.handleHandshakeComplete(); err != nil { + return false, err + } + } + return } @@ -1360,7 +1374,9 @@ func (s *connection) handleHandshakeEvents() error { case handshake.EventNoEvent: return nil case handshake.EventHandshakeComplete: - err = s.handleHandshakeComplete() + // Don't call handleHandshakeComplete yet. + // It's advantageous to process ACK frames that might be serialized after the CRYPTO frame first. + s.handshakeComplete = true case handshake.EventReceivedTransportParameters: err = s.handleTransportParameters(ev.TransportParameters) case handshake.EventRestoredTransportParameters: @@ -1488,6 +1504,9 @@ func (s *connection) handleAckFrame(frame *wire.AckFrame, encLevel protocol.Encr if !acked1RTTPacket { return nil } + // On the client side: If the packet acknowledged a 1-RTT packet, this confirms the handshake. + // This is only possible if the ACK was sent in a 1-RTT packet. + // This is an optimization over simply waiting for a HANDSHAKE_DONE frame, see section 4.1.2 of RFC 9001. if s.perspective == protocol.PerspectiveClient && !s.handshakeConfirmed { if err := s.handleHandshakeConfirmed(); err != nil { return err @@ -1659,6 +1678,9 @@ func (s *connection) restoreTransportParameters(params *wire.TransportParameters } func (s *connection) handleTransportParameters(params *wire.TransportParameters) error { + if s.tracer != nil { + s.tracer.ReceivedTransportParameters(params) + } if err := s.checkTransportParameters(params); err != nil { return &qerr.TransportError{ ErrorCode: qerr.TransportParameterError, @@ -1693,9 +1715,6 @@ func (s *connection) checkTransportParameters(params *wire.TransportParameters) if s.logger.Debug() { s.logger.Debugf("Processed Transport Parameters: %s", params) } - if s.tracer != nil { - s.tracer.ReceivedTransportParameters(params) - } // check the initial_source_connection_id if params.InitialSourceConnectionID != s.handshakeDestConnID { diff --git a/connection_test.go b/connection_test.go index c3c5d2c5..5c972733 100644 --- a/connection_test.go +++ b/connection_test.go @@ -1891,7 +1891,6 @@ var _ = Describe("Connection", func() { It("cancels the HandshakeComplete context when the handshake completes", func() { packer.EXPECT().PackCoalescedPacket(false, gomock.Any(), conn.version).AnyTimes() - finishHandshake := make(chan struct{}) sph := mockackhandler.NewMockSentPacketHandler(mockCtrl) conn.sentPacketHandler = sph tracer.EXPECT().DroppedEncryptionLevel(protocol.EncryptionHandshake) @@ -1901,53 +1900,26 @@ var _ = Describe("Connection", func() { sph.EXPECT().DropPackets(protocol.EncryptionHandshake) sph.EXPECT().SetHandshakeConfirmed() connRunner.EXPECT().Retire(clientDestConnID) - go func() { - defer GinkgoRecover() - <-finishHandshake - cryptoSetup.EXPECT().StartHandshake() - cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventHandshakeComplete}) - cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventNoEvent}) - cryptoSetup.EXPECT().SetHandshakeConfirmed() - cryptoSetup.EXPECT().GetSessionTicket() - conn.run() - }() + cryptoSetup.EXPECT().SetHandshakeConfirmed() + cryptoSetup.EXPECT().GetSessionTicket() handshakeCtx := conn.HandshakeComplete() Consistently(handshakeCtx).ShouldNot(BeClosed()) - close(finishHandshake) + Expect(conn.handleHandshakeComplete()).To(Succeed()) Eventually(handshakeCtx).Should(BeClosed()) - // make sure the go routine returns - streamManager.EXPECT().CloseWithError(gomock.Any()) - expectReplaceWithClosed() - packer.EXPECT().PackApplicationClose(gomock.Any(), gomock.Any(), conn.version).Return(&coalescedPacket{buffer: getPacketBuffer()}, nil) - cryptoSetup.EXPECT().Close() - mconn.EXPECT().Write(gomock.Any(), gomock.Any()) - tracer.EXPECT().ClosedConnection(gomock.Any()) - tracer.EXPECT().Close() - conn.shutdown() - Eventually(conn.Context().Done()).Should(BeClosed()) }) It("sends a session ticket when the handshake completes", func() { const size = protocol.MaxPostHandshakeCryptoFrameSize * 3 / 2 packer.EXPECT().PackCoalescedPacket(false, gomock.Any(), conn.version).AnyTimes() - finishHandshake := make(chan struct{}) connRunner.EXPECT().Retire(clientDestConnID) conn.sentPacketHandler.DropPackets(protocol.EncryptionInitial) tracer.EXPECT().DroppedEncryptionLevel(protocol.EncryptionHandshake) - go func() { - defer GinkgoRecover() - <-finishHandshake - cryptoSetup.EXPECT().StartHandshake() - cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventHandshakeComplete}) - cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventNoEvent}) - cryptoSetup.EXPECT().SetHandshakeConfirmed() - cryptoSetup.EXPECT().GetSessionTicket().Return(make([]byte, size), nil) - conn.run() - }() + cryptoSetup.EXPECT().SetHandshakeConfirmed() + cryptoSetup.EXPECT().GetSessionTicket().Return(make([]byte, size), nil) handshakeCtx := conn.HandshakeComplete() Consistently(handshakeCtx).ShouldNot(BeClosed()) - close(finishHandshake) + Expect(conn.handleHandshakeComplete()).To(Succeed()) var frames []ackhandler.Frame Eventually(func() []ackhandler.Frame { frames, _ = conn.framer.AppendControlFrames(nil, protocol.MaxByteCount, protocol.Version1) @@ -1963,16 +1935,6 @@ var _ = Describe("Connection", func() { } } Expect(size).To(BeEquivalentTo(s)) - // make sure the go routine returns - streamManager.EXPECT().CloseWithError(gomock.Any()) - expectReplaceWithClosed() - packer.EXPECT().PackApplicationClose(gomock.Any(), gomock.Any(), conn.version).Return(&coalescedPacket{buffer: getPacketBuffer()}, nil) - cryptoSetup.EXPECT().Close() - mconn.EXPECT().Write(gomock.Any(), gomock.Any()) - tracer.EXPECT().ClosedConnection(gomock.Any()) - tracer.EXPECT().Close() - conn.shutdown() - Eventually(conn.Context().Done()).Should(BeClosed()) }) It("doesn't cancel the HandshakeComplete context when the handshake fails", func() { @@ -2027,6 +1989,7 @@ var _ = Describe("Connection", func() { cryptoSetup.EXPECT().SetHandshakeConfirmed() cryptoSetup.EXPECT().GetSessionTicket() mconn.EXPECT().Write(gomock.Any(), gomock.Any()) + Expect(conn.handleHandshakeComplete()).To(Succeed()) conn.run() }() Eventually(done).Should(BeClosed()) @@ -2350,6 +2313,7 @@ var _ = Describe("Connection", func() { cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventNoEvent}) cryptoSetup.EXPECT().GetSessionTicket().MaxTimes(1) cryptoSetup.EXPECT().SetHandshakeConfirmed().MaxTimes(1) + Expect(conn.handleHandshakeComplete()).To(Succeed()) err := conn.run() nerr, ok := err.(net.Error) Expect(ok).To(BeTrue()) @@ -2867,7 +2831,10 @@ var _ = Describe("Client Connection", func() { TransportParameters: params, }) cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventHandshakeComplete}).MaxTimes(1) - cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventNoEvent}).MaxTimes(1) + cryptoSetup.EXPECT().NextEvent().Return(handshake.Event{Kind: handshake.EventNoEvent}).MaxTimes(1).Do(func() { + defer GinkgoRecover() + Expect(conn.handleHandshakeComplete()).To(Succeed()) + }) errChan <- conn.run() close(errChan) }() From 571d3adef4266a7c08f8e10dda32d07444716f00 Mon Sep 17 00:00:00 2001 From: elagergren-spideroak <36516532+elagergren-spideroak@users.noreply.github.com> Date: Wed, 9 Aug 2023 05:22:30 -0700 Subject: [PATCH 06/36] fix compatibility with API breaking change in Go 1.21 (#4020) * add Go 1.21 compatibility Signed-off-by: Eric Lagergren * refactor for Go 1.20 Signed-off-by: Eric Lagergren --------- Signed-off-by: Eric Lagergren --- .github/workflows/cross-compile.yml | 2 +- .github/workflows/integration.yml | 2 +- .github/workflows/unit.yml | 2 +- internal/handshake/crypto_setup.go | 2 +- internal/qtls/go120.go | 4 ++++ internal/qtls/go121.go | 19 +++++++++++++------ 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cross-compile.yml b/.github/workflows/cross-compile.yml index 042953f8..46309b0a 100644 --- a/.github/workflows/cross-compile.yml +++ b/.github/workflows/cross-compile.yml @@ -4,7 +4,7 @@ jobs: strategy: fail-fast: false matrix: - go: [ "1.20.x", "1.21.0-rc.3" ] + go: [ "1.20.x", "1.21.x" ] runs-on: ${{ fromJSON(vars['CROSS_COMPILE_RUNNER_UBUNTU'] || '"ubuntu-latest"') }} name: "Cross Compilation (Go ${{matrix.go}})" steps: diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 362a24ec..7ad8f5ba 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -5,7 +5,7 @@ jobs: strategy: fail-fast: false matrix: - go: [ "1.20.x", "1.21.0-rc.3" ] + go: [ "1.20.x", "1.21.x" ] runs-on: ${{ fromJSON(vars['INTEGRATION_RUNNER_UBUNTU'] || '"ubuntu-latest"') }} env: DEBUG: false # set this to true to export qlogs and save them as artifacts diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index fb21749f..c9eff032 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -7,7 +7,7 @@ jobs: fail-fast: false matrix: os: [ "ubuntu", "windows", "macos" ] - go: [ "1.20.x", "1.21.0-rc.3" ] + go: [ "1.20.x", "1.21.x" ] runs-on: ${{ fromJSON(vars[format('UNIT_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }} name: Unit tests (${{ matrix.os}}, Go ${{ matrix.go }}) steps: diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index 543e70e0..35d65b5e 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -359,7 +359,7 @@ func (h *cryptoSetup) GetSessionTicket() ([]byte, error) { if h.tlsConf.SessionTicketsDisabled { return nil, nil } - if err := h.conn.SendSessionTicket(h.allow0RTT); err != nil { + if err := qtls.SendSessionTicket(h.conn, h.allow0RTT); err != nil { return nil, err } ev := h.conn.NextEvent() diff --git a/internal/qtls/go120.go b/internal/qtls/go120.go index 595e6e66..3b50441c 100644 --- a/internal/qtls/go120.go +++ b/internal/qtls/go120.go @@ -139,3 +139,7 @@ func SetCipherSuite(id uint16) (reset func()) { cipherSuitesModified = false } } + +func SendSessionTicket(c *QUICConn, allow0RTT bool) error { + return c.SendSessionTicket(allow0RTT) +} diff --git a/internal/qtls/go121.go b/internal/qtls/go121.go index 1137556e..4aebc4a1 100644 --- a/internal/qtls/go121.go +++ b/internal/qtls/go121.go @@ -11,12 +11,13 @@ import ( ) type ( - QUICConn = tls.QUICConn - QUICConfig = tls.QUICConfig - QUICEvent = tls.QUICEvent - QUICEventKind = tls.QUICEventKind - QUICEncryptionLevel = tls.QUICEncryptionLevel - AlertError = tls.AlertError + QUICConn = tls.QUICConn + QUICConfig = tls.QUICConfig + QUICEvent = tls.QUICEvent + QUICEventKind = tls.QUICEventKind + QUICEncryptionLevel = tls.QUICEncryptionLevel + QUICSessionTicketOptions = tls.QUICSessionTicketOptions + AlertError = tls.AlertError ) const ( @@ -152,3 +153,9 @@ func findExtraData(extras [][]byte) []byte { } return nil } + +func SendSessionTicket(c *QUICConn, allow0RTT bool) error { + return c.SendSessionTicket(tls.QUICSessionTicketOptions{ + EarlyData: allow0RTT, + }) +} From 10d11149625ab20c87ee6e4ef64f0c44b08e9205 Mon Sep 17 00:00:00 2001 From: Gokul PM Date: Wed, 9 Aug 2023 17:56:39 +0530 Subject: [PATCH 07/36] README: fix invocation of Go routine in example (#4019) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3eaf0583..a19249b4 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ go func() { // ... error handling // handle the connection, usually in a new Go routine } -} +}() ``` The listener `ln` can now be used to accept incoming QUIC connections by (repeatedly) calling the `Accept` method (see below for more information on the `quic.Connection`). From 05db808f72b9183653cfce97d6c235108bb18ee6 Mon Sep 17 00:00:00 2001 From: Ondrej Kokes Date: Wed, 9 Aug 2023 15:30:46 +0200 Subject: [PATCH 08/36] http3: change code point for HTTP datagrams to RFC 9297 (#3588) * HTTP/3 Datagrams are now RFC 9297 * Use datatracker htmlized docs rather than rfc-editor (to be consistent) --- http3/error_codes.go | 2 +- http3/frames.go | 2 +- http3/roundtrip.go | 2 +- http3/server.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/http3/error_codes.go b/http3/error_codes.go index 67b215d8..e8428d0a 100644 --- a/http3/error_codes.go +++ b/http3/error_codes.go @@ -26,7 +26,7 @@ const ( ErrCodeMessageError ErrCode = 0x10e ErrCodeConnectError ErrCode = 0x10f ErrCodeVersionFallback ErrCode = 0x110 - ErrCodeDatagramError ErrCode = 0x4a1268 + ErrCodeDatagramError ErrCode = 0x33 ) func (e ErrCode) String() string { diff --git a/http3/frames.go b/http3/frames.go index cdd97bc5..454e5f94 100644 --- a/http3/frames.go +++ b/http3/frames.go @@ -88,7 +88,7 @@ func (f *headersFrame) Append(b []byte) []byte { return quicvarint.Append(b, f.Length) } -const settingDatagram = 0xffd277 +const settingDatagram = 0x33 type settingsFrame struct { Datagram bool diff --git a/http3/roundtrip.go b/http3/roundtrip.go index 066b762b..bed42103 100644 --- a/http3/roundtrip.go +++ b/http3/roundtrip.go @@ -52,7 +52,7 @@ type RoundTripper struct { // Enable support for HTTP/3 datagrams. // If set to true, QuicConfig.EnableDatagram will be set. - // See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html. + // See https://datatracker.ietf.org/doc/html/rfc9297. EnableDatagrams bool // Additional HTTP/3 settings. diff --git a/http3/server.go b/http3/server.go index b90c850c..728811c0 100644 --- a/http3/server.go +++ b/http3/server.go @@ -176,7 +176,7 @@ type Server struct { // EnableDatagrams enables support for HTTP/3 datagrams. // If set to true, QuicConfig.EnableDatagram will be set. - // See https://datatracker.ietf.org/doc/html/draft-ietf-masque-h3-datagram-07. + // See https://datatracker.ietf.org/doc/html/rfc9297. EnableDatagrams bool // MaxHeaderBytes controls the maximum number of bytes the server will From b65ed61feac22f479eada7d54884ff8a7dadbe6d Mon Sep 17 00:00:00 2001 From: Egon Elbre Date: Sun, 13 Aug 2023 11:43:28 +0300 Subject: [PATCH 09/36] integrationtests: fix proxy test on Windows (#4023) --- integrationtests/tools/proxy/proxy_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/integrationtests/tools/proxy/proxy_test.go b/integrationtests/tools/proxy/proxy_test.go index 81e13b23..c9b80be5 100644 --- a/integrationtests/tools/proxy/proxy_test.go +++ b/integrationtests/tools/proxy/proxy_test.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "net" + "runtime" "runtime/pprof" "strconv" "strings" @@ -68,7 +69,11 @@ var _ = Describe("QUIC Proxy", func() { addr, err := net.ResolveUDPAddr("udp", "localhost:"+strconv.Itoa(proxy.LocalPort())) Expect(err).ToNot(HaveOccurred()) _, err = net.ListenUDP("udp", addr) - Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: address already in use", proxy.LocalPort()))) + if runtime.GOOS == "windows" { + Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.", proxy.LocalPort()))) + } else { + Expect(err).To(MatchError(fmt.Sprintf("listen udp 127.0.0.1:%d: bind: address already in use", proxy.LocalPort()))) + } Expect(proxy.Close()).To(Succeed()) // stopping is tested in the next test }) From 70f3f44a0975ad84c96f6efa08f7ad47a39796eb Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 14 Aug 2023 09:36:01 +0700 Subject: [PATCH 10/36] http3: remove leftover ALPN constant for draft-29 (#4027) --- http3/server.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/http3/server.go b/http3/server.go index 728811c0..8d39f374 100644 --- a/http3/server.go +++ b/http3/server.go @@ -31,12 +31,8 @@ var ( } ) -const ( - // NextProtoH3Draft29 is the ALPN protocol negotiated during the TLS handshake, for QUIC draft 29. - NextProtoH3Draft29 = "h3-29" - // NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2. - NextProtoH3 = "h3" -) +// NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2. +const NextProtoH3 = "h3" // StreamType is the stream type of a unidirectional stream. type StreamType uint64 From 1d848392bcf0b9611709c8018ad66bb88ddd8ccc Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 09:53:41 +0700 Subject: [PATCH 11/36] ignore QUICConn.SendSessionTicket error if session tickets are disabled (#4030) --- integrationtests/self/resumption_test.go | 58 ++++++++++++++++++++++-- internal/handshake/crypto_setup.go | 12 +++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/integrationtests/self/resumption_test.go b/integrationtests/self/resumption_test.go index 264f832e..bedf0470 100644 --- a/integrationtests/self/resumption_test.go +++ b/integrationtests/self/resumption_test.go @@ -56,7 +56,7 @@ var _ = Describe("TLS session resumption", func() { context.Background(), fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), tlsConf, - nil, + getQuicConfig(nil), ) Expect(err).ToNot(HaveOccurred()) var sessionKey string @@ -71,7 +71,7 @@ var _ = Describe("TLS session resumption", func() { context.Background(), fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), tlsConf, - nil, + getQuicConfig(nil), ) Expect(err).ToNot(HaveOccurred()) Expect(gets).To(Receive(Equal(sessionKey))) @@ -85,7 +85,7 @@ var _ = Describe("TLS session resumption", func() { It("doesn't use session resumption, if the config disables it", func() { sConf := getTLSConfig() sConf.SessionTicketsDisabled = true - server, err := quic.ListenAddr("localhost:0", sConf, nil) + server, err := quic.ListenAddr("localhost:0", sConf, getQuicConfig(nil)) Expect(err).ToNot(HaveOccurred()) defer server.Close() @@ -98,7 +98,7 @@ var _ = Describe("TLS session resumption", func() { context.Background(), fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), tlsConf, - nil, + getQuicConfig(nil), ) Expect(err).ToNot(HaveOccurred()) Consistently(puts).ShouldNot(Receive()) @@ -114,7 +114,55 @@ var _ = Describe("TLS session resumption", func() { context.Background(), fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), tlsConf, - nil, + getQuicConfig(nil), + ) + Expect(err).ToNot(HaveOccurred()) + Expect(conn.ConnectionState().TLS.DidResume).To(BeFalse()) + + serverConn, err = server.Accept(context.Background()) + Expect(err).ToNot(HaveOccurred()) + Expect(serverConn.ConnectionState().TLS.DidResume).To(BeFalse()) + }) + + It("doesn't use session resumption, if the config returned by GetConfigForClient disables it", func() { + sConf := &tls.Config{ + GetConfigForClient: func(*tls.ClientHelloInfo) (*tls.Config, error) { + conf := getTLSConfig() + conf.SessionTicketsDisabled = true + return conf, nil + }, + } + + server, err := quic.ListenAddr("localhost:0", sConf, getQuicConfig(nil)) + Expect(err).ToNot(HaveOccurred()) + defer server.Close() + + gets := make(chan string, 100) + puts := make(chan string, 100) + cache := newClientSessionCache(tls.NewLRUClientSessionCache(10), gets, puts) + tlsConf := getTLSClientConfig() + tlsConf.ClientSessionCache = cache + conn, err := quic.DialAddr( + context.Background(), + fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), + tlsConf, + getQuicConfig(nil), + ) + Expect(err).ToNot(HaveOccurred()) + Consistently(puts).ShouldNot(Receive()) + Expect(conn.ConnectionState().TLS.DidResume).To(BeFalse()) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + serverConn, err := server.Accept(ctx) + Expect(err).ToNot(HaveOccurred()) + Expect(serverConn.ConnectionState().TLS.DidResume).To(BeFalse()) + + conn, err = quic.DialAddr( + context.Background(), + fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), + tlsConf, + getQuicConfig(nil), ) Expect(err).ToNot(HaveOccurred()) Expect(conn.ConnectionState().TLS.DidResume).To(BeFalse()) diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index 35d65b5e..a1179257 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "net" + "strings" "sync" "sync/atomic" "time" @@ -356,10 +357,15 @@ func (h *cryptoSetup) getDataForSessionTicket() []byte { // Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection. // It is only valid for the server. func (h *cryptoSetup) GetSessionTicket() ([]byte, error) { - if h.tlsConf.SessionTicketsDisabled { - return nil, nil - } if err := qtls.SendSessionTicket(h.conn, h.allow0RTT); err != nil { + // Session tickets might be disabled by tls.Config.SessionTicketsDisabled. + // We can't check h.tlsConfig here, since the actual config might have been obtained from + // the GetConfigForClient callback. + // See https://github.com/golang/go/issues/62032. + // Once that issue is resolved, this error assertion can be removed. + if strings.Contains(err.Error(), "session ticket keys unavailable") { + return nil, nil + } return nil, err } ev := h.conn.NextEvent() From bda01bc4894568fbd80175676580b9b523a51c63 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 10:09:01 +0700 Subject: [PATCH 12/36] handshake: use the correct hash function for TLS_AES_256_GCM_SHA384 (#4031) --- internal/handshake/cipher_suite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/handshake/cipher_suite.go b/internal/handshake/cipher_suite.go index 608d5ea0..265231f0 100644 --- a/internal/handshake/cipher_suite.go +++ b/internal/handshake/cipher_suite.go @@ -30,7 +30,7 @@ func getCipherSuite(id uint16) *cipherSuite { case tls.TLS_CHACHA20_POLY1305_SHA256: return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305} case tls.TLS_AES_256_GCM_SHA384: - return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadAESGCMTLS13} + return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13} default: panic(fmt.Sprintf("unknown cypher suite: %d", id)) } From 2e7ea9119c84904a881bd31eed130edcf200b98e Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 18:58:07 +0700 Subject: [PATCH 13/36] add OSS-Fuzz badge to README (#3942) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a19249b4..a793f984 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![PkgGoDev](https://pkg.go.dev/badge/github.com/quic-go/quic-go)](https://pkg.go.dev/github.com/quic-go/quic-go) [![Code Coverage](https://img.shields.io/codecov/c/github/quic-go/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/quic-go/quic-go/) +[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/quic-go.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:quic-go) quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go. It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)). From 4f696569a22f88d9bd913b354848f8460c6faed9 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 18:59:11 +0700 Subject: [PATCH 14/36] store the server port as an int, not a string, in HTTP tests (#3959) --- integrationtests/self/http_test.go | 44 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/integrationtests/self/http_test.go b/integrationtests/self/http_test.go index e41dc85e..b647d4d9 100644 --- a/integrationtests/self/http_test.go +++ b/integrationtests/self/http_test.go @@ -42,7 +42,7 @@ var _ = Describe("HTTP tests", func() { rt *http3.RoundTripper server *http3.Server stoppedServing chan struct{} - port string + port int ) BeforeEach(func() { @@ -93,7 +93,7 @@ var _ = Describe("HTTP tests", func() { Expect(err).NotTo(HaveOccurred()) conn, err := net.ListenUDP("udp", addr) Expect(err).NotTo(HaveOccurred()) - port = strconv.Itoa(conn.LocalAddr().(*net.UDPAddr).Port) + port = conn.LocalAddr().(*net.UDPAddr).Port stoppedServing = make(chan struct{}) @@ -120,7 +120,7 @@ var _ = Describe("HTTP tests", func() { }) It("downloads a hello", func() { - resp, err := client.Get("https://localhost:" + port + "/hello") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/hello", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 3*time.Second)) @@ -129,12 +129,12 @@ var _ = Describe("HTTP tests", func() { }) It("requests to different servers with the same udpconn", func() { - resp, err := client.Get("https://localhost:" + port + "/remoteAddr") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/remoteAddr", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) addr1 := resp.Header.Get("X-RemoteAddr") Expect(addr1).ToNot(Equal("")) - resp, err = client.Get("https://127.0.0.1:" + port + "/remoteAddr") + resp, err = client.Get(fmt.Sprintf("https://127.0.0.1:%d/remoteAddr", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) addr2 := resp.Header.Get("X-RemoteAddr") @@ -146,7 +146,7 @@ var _ = Describe("HTTP tests", func() { group, ctx := errgroup.WithContext(context.Background()) for i := 0; i < 2; i++ { group.Go(func() error { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://localhost:"+port+"/hello", nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://localhost:%d/hello", port), nil) Expect(err).ToNot(HaveOccurred()) resp, err := client.Do(req) Expect(err).ToNot(HaveOccurred()) @@ -172,7 +172,7 @@ var _ = Describe("HTTP tests", func() { close(handlerCalled) }) - req, err := http.NewRequest(http.MethodGet, "https://localhost:"+port+"/headers/request", nil) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://localhost:%d/headers/request", port), nil) Expect(err).ToNot(HaveOccurred()) req.Header.Set("foo", "bar") req.Header.Set("lorem", "ipsum") @@ -189,7 +189,7 @@ var _ = Describe("HTTP tests", func() { w.Header().Set("lorem", "ipsum") }) - resp, err := client.Get("https://localhost:" + port + "/headers/response") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/headers/response", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) Expect(resp.Header.Get("foo")).To(Equal("bar")) @@ -197,7 +197,7 @@ var _ = Describe("HTTP tests", func() { }) It("downloads a small file", func() { - resp, err := client.Get("https://localhost:" + port + "/prdata") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/prdata", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 5*time.Second)) @@ -206,7 +206,7 @@ var _ = Describe("HTTP tests", func() { }) It("downloads a large file", func() { - resp, err := client.Get("https://localhost:" + port + "/prdatalong") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/prdatalong", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 20*time.Second)) @@ -218,7 +218,7 @@ var _ = Describe("HTTP tests", func() { const num = 150 for i := 0; i < num; i++ { - resp, err := client.Get("https://localhost:" + port + "/hello") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/hello", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 3*time.Second)) @@ -231,7 +231,7 @@ var _ = Describe("HTTP tests", func() { const num = 150 for i := 0; i < num; i++ { - resp, err := client.Get("https://localhost:" + port + "/prdata") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/prdata", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) Expect(resp.Body.Close()).To(Succeed()) @@ -240,7 +240,7 @@ var _ = Describe("HTTP tests", func() { It("posts a small message", func() { resp, err := client.Post( - "https://localhost:"+port+"/echo", + fmt.Sprintf("https://localhost:%d/echo", port), "text/plain", bytes.NewReader([]byte("Hello, world!")), ) @@ -253,7 +253,7 @@ var _ = Describe("HTTP tests", func() { It("uploads a file", func() { resp, err := client.Post( - "https://localhost:"+port+"/echo", + fmt.Sprintf("https://localhost:%d/echo", port), "text/plain", bytes.NewReader(PRData), ) @@ -277,7 +277,7 @@ var _ = Describe("HTTP tests", func() { }) client.Transport.(*http3.RoundTripper).DisableCompression = false - resp, err := client.Get("https://localhost:" + port + "/gzipped/hello") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/gzipped/hello", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) Expect(resp.Uncompressed).To(BeTrue()) @@ -303,7 +303,7 @@ var _ = Describe("HTTP tests", func() { } }) - req, err := http.NewRequest(http.MethodGet, "https://localhost:"+port+"/cancel", nil) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://localhost:%d/cancel", port), nil) Expect(err).ToNot(HaveOccurred()) ctx, cancel := context.WithCancel(context.Background()) req = req.WithContext(ctx) @@ -336,7 +336,7 @@ var _ = Describe("HTTP tests", func() { }) r, w := io.Pipe() - req, err := http.NewRequest("PUT", "https://localhost:"+port+"/echoline", r) + req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("https://localhost:%d/echoline", port), r) Expect(err).ToNot(HaveOccurred()) rsp, err := client.Do(req) Expect(err).ToNot(HaveOccurred()) @@ -373,7 +373,7 @@ var _ = Describe("HTTP tests", func() { }() }) - req, err := http.NewRequest(http.MethodGet, "https://localhost:"+port+"/httpstreamer", nil) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("https://localhost:%d/httpstreamer", port), nil) Expect(err).ToNot(HaveOccurred()) rsp, err := client.Transport.(*http3.RoundTripper).RoundTripOpt(req, http3.RoundTripOpt{DontCloseRequestStream: true}) Expect(err).ToNot(HaveOccurred()) @@ -431,7 +431,11 @@ var _ = Describe("HTTP tests", func() { }) expectedEnd := time.Now().Add(deadlineDelay) - resp, err := client.Post("https://localhost:"+port+"/read-deadline", "text/plain", neverEnding('a')) + resp, err := client.Post( + fmt.Sprintf("https://localhost:%d/read-deadline", port), + "text/plain", + neverEnding('a'), + ) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) @@ -453,7 +457,7 @@ var _ = Describe("HTTP tests", func() { expectedEnd := time.Now().Add(deadlineDelay) - resp, err := client.Get("https://localhost:" + port + "/write-deadline") + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/write-deadline", port)) Expect(err).ToNot(HaveOccurred()) Expect(resp.StatusCode).To(Equal(200)) From ca3842d6c8409514a63d98a4ff8b5d493a90e7bf Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 20:54:42 +0700 Subject: [PATCH 15/36] automatically set the tls.Config.ServerName if unset (#4032) --- client.go | 16 +++++----------- transport.go | 30 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/client.go b/client.go index 4dfacb50..61cd7526 100644 --- a/client.go +++ b/client.go @@ -55,11 +55,11 @@ func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Confi if err != nil { return nil, err } - dl, err := setupTransport(udpConn, tlsConf, true) + tr, err := setupTransport(udpConn, tlsConf, true) if err != nil { return nil, err } - return dl.Dial(ctx, udpAddr, tlsConf, conf) + return tr.dial(ctx, udpAddr, addr, tlsConf, conf, false) } // DialAddrEarly establishes a new 0-RTT QUIC connection to a server. @@ -73,13 +73,13 @@ func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf * if err != nil { return nil, err } - dl, err := setupTransport(udpConn, tlsConf, true) + tr, err := setupTransport(udpConn, tlsConf, true) if err != nil { return nil, err } - conn, err := dl.DialEarly(ctx, udpAddr, tlsConf, conf) + conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, true) if err != nil { - dl.Close() + tr.Close() return nil, err } return conn, nil @@ -163,12 +163,6 @@ func dial( } func newClient(sendConn sendConn, connIDGenerator ConnectionIDGenerator, config *Config, tlsConf *tls.Config, onClose func(), use0RTT bool) (*client, error) { - if tlsConf == nil { - tlsConf = &tls.Config{} - } else { - tlsConf = tlsConf.Clone() - } - srcConnID, err := connIDGenerator.GenerateConnectionID() if err != nil { return nil, err diff --git a/transport.go b/transport.go index 290b647f..42fafd49 100644 --- a/transport.go +++ b/transport.go @@ -148,24 +148,15 @@ func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListen // Dial dials a new connection to a remote host (not using 0-RTT). func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) { - if err := validateConfig(conf); err != nil { - return nil, err - } - conf = populateConfig(conf) - if err := t.init(t.isSingleUse); err != nil { - return nil, err - } - var onClose func() - if t.isSingleUse { - onClose = func() { t.Close() } - } - tlsConf = tlsConf.Clone() - tlsConf.MinVersion = tls.VersionTLS13 - return dial(ctx, newSendConn(t.conn, addr), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, false) + return t.dial(ctx, addr, "", tlsConf, conf, false) } // DialEarly dials a new connection, attempting to use 0-RTT if possible. func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { + return t.dial(ctx, addr, "", tlsConf, conf, true) +} + +func (t *Transport) dial(ctx context.Context, addr net.Addr, hostname string, tlsConf *tls.Config, conf *Config, use0RTT bool) (EarlyConnection, error) { if err := validateConfig(conf); err != nil { return nil, err } @@ -179,7 +170,16 @@ func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.C } tlsConf = tlsConf.Clone() tlsConf.MinVersion = tls.VersionTLS13 - return dial(ctx, newSendConn(t.conn, addr), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, true) + // If no ServerName is set, infer the ServerName from the hostname we're connecting to. + if tlsConf.ServerName == "" { + if hostname == "" { + if udpAddr, ok := addr.(*net.UDPAddr); ok { + hostname = udpAddr.IP.String() + } + } + tlsConf.ServerName = hostname + } + return dial(ctx, newSendConn(t.conn, addr), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, use0RTT) } func (t *Transport) init(allowZeroLengthConnIDs bool) error { From 51d257d6082b531778855c76a2c3521cdafd7581 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 20:55:44 +0700 Subject: [PATCH 16/36] handshake fuzzer: fix TLS handshake sequence (#4033) There were two problems with the existing code: 1. The transport parameters were rejected due to an invalid value for ActiveConnectionIDLimit, causing the handshake to fail. 2. Handshake messages were passed in at the wrong encryption level, leading to consistent handshake failures. --- fuzzing/handshake/fuzz.go | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/fuzzing/handshake/fuzz.go b/fuzzing/handshake/fuzz.go index 2c5c1259..93cec975 100644 --- a/fuzzing/handshake/fuzz.go +++ b/fuzzing/handshake/fuzz.go @@ -147,6 +147,7 @@ func getTransportParameters(seed uint8) *wire.TransportParameters { const maxVarInt = math.MaxUint64 / 4 r := mrand.New(mrand.NewSource(int64(seed))) return &wire.TransportParameters{ + ActiveConnectionIDLimit: 2, InitialMaxData: protocol.ByteCount(r.Int63n(maxVarInt)), InitialMaxStreamDataBidiLocal: protocol.ByteCount(r.Int63n(maxVarInt)), InitialMaxStreamDataBidiRemote: protocol.ByteCount(r.Int63n(maxVarInt)), @@ -302,6 +303,7 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. if err := client.StartHandshake(); err != nil { log.Fatal(err) } + defer client.Close() server := handshake.NewCryptoSetupServer( protocol.ConnectionID{}, @@ -318,12 +320,13 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. if err := server.StartHandshake(); err != nil { log.Fatal(err) } + defer server.Close() var clientHandshakeComplete, serverHandshakeComplete bool for { + var processedEvent bool clientLoop: for { - var processedEvent bool ev := client.NextEvent() //nolint:exhaustive // only need to process a few events switch ev.Kind { @@ -334,11 +337,16 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. break clientLoop case handshake.EventWriteInitialData, handshake.EventWriteHandshakeData: msg := ev.Data + encLevel := protocol.EncryptionInitial + if ev.Kind == handshake.EventWriteHandshakeData { + encLevel = protocol.EncryptionHandshake + } if msg[0] == messageToReplace { fmt.Printf("replacing %s message to the server with %s at %s\n", messageType(msg[0]), messageType(data[0]), messageToReplaceEncLevel) msg = data + encLevel = messageToReplaceEncLevel } - if err := server.HandleMessage(msg, messageToReplaceEncLevel); err != nil { + if err := server.HandleMessage(msg, encLevel); err != nil { return 1 } case handshake.EventHandshakeComplete: @@ -347,9 +355,9 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. processedEvent = true } + processedEvent = false serverLoop: for { - var processedEvent bool ev := server.NextEvent() //nolint:exhaustive // only need to process a few events switch ev.Kind { @@ -359,12 +367,17 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. } break serverLoop case handshake.EventWriteInitialData, handshake.EventWriteHandshakeData: + encLevel := protocol.EncryptionInitial + if ev.Kind == handshake.EventWriteHandshakeData { + encLevel = protocol.EncryptionHandshake + } msg := ev.Data if msg[0] == messageToReplace { fmt.Printf("replacing %s message to the client with %s at %s\n", messageType(msg[0]), messageType(data[0]), messageToReplaceEncLevel) msg = data + encLevel = messageToReplaceEncLevel } - if err := client.HandleMessage(msg, messageToReplaceEncLevel); err != nil { + if err := client.HandleMessage(msg, encLevel); err != nil { return 1 } case handshake.EventHandshakeComplete: @@ -410,9 +423,11 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. client.HandleMessage(ticket, protocol.Encryption1RTT) } if sendPostHandshakeMessageToClient { + fmt.Println("sending post handshake message to the client at", messageToReplaceEncLevel) client.HandleMessage(data, messageToReplaceEncLevel) } if sendPostHandshakeMessageToServer { + fmt.Println("sending post handshake message to the server at", messageToReplaceEncLevel) server.HandleMessage(data, messageToReplaceEncLevel) } From 83c00a574dbaed179d969c918ae5855ac3c634ab Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 16 Aug 2023 21:21:48 +0700 Subject: [PATCH 17/36] ci: also run integration tests on Windows and macOS (#3987) --- .github/workflows/integration.yml | 12 +++++++++--- integrationtests/self/handshake_test.go | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 7ad8f5ba..0b8fa904 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -5,12 +5,18 @@ jobs: strategy: fail-fast: false matrix: + os: [ "ubuntu" ] go: [ "1.20.x", "1.21.x" ] - runs-on: ${{ fromJSON(vars['INTEGRATION_RUNNER_UBUNTU'] || '"ubuntu-latest"') }} + include: + - os: "windows" + go: "1.21.x" + - os: "macos" + go: "1.21.x" + runs-on: ${{ fromJSON(vars[format('INTEGRATION_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }} env: DEBUG: false # set this to true to export qlogs and save them as artifacts TIMESCALE_FACTOR: 3 - name: Integration Tests (Go ${{ matrix.go }}) + name: Integration Tests (${{ matrix.os }}, Go ${{ matrix.go }}) steps: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 @@ -37,7 +43,7 @@ jobs: QUIC_GO_ENABLE_GSO: true run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=1 ${{ env.QLOGFLAG }} - name: Run tests (32 bit) - if: success() || failure() # run this step even if the previous one failed + if: ${{ matrix.os != 'macos' && (success() || failure()) }} # run this step even if the previous one failed env: GOARCH: 386 run: | diff --git a/integrationtests/self/handshake_test.go b/integrationtests/self/handshake_test.go index cccff8a6..951c4c7a 100644 --- a/integrationtests/self/handshake_test.go +++ b/integrationtests/self/handshake_test.go @@ -453,7 +453,7 @@ var _ = Describe("Handshake tests", func() { It("rejects invalid Retry token with the INVALID_TOKEN error", func() { serverConfig.RequireAddressValidation = func(net.Addr) bool { return true } - serverConfig.MaxRetryTokenAge = time.Nanosecond + serverConfig.MaxRetryTokenAge = -time.Second server, err := quic.ListenAddr("localhost:0", getTLSConfig(), serverConfig) Expect(err).ToNot(HaveOccurred()) From 4122eb7a7d59ecbb47398a24124206e14a196f36 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 29 Jul 2023 15:58:32 -0700 Subject: [PATCH 18/36] disable GSO if sending fails for a particular remote address --- mock_raw_conn_test.go | 122 +++++++++++++++++++++++++++++++ mockgen.go | 3 + packet_handler_map.go | 6 +- send_conn.go | 91 ++++++++++++++--------- send_conn_test.go | 95 ++++++++++++++++-------- server.go | 8 +- sys_conn.go | 6 +- sys_conn_df_linux.go | 40 +--------- sys_conn_helper_linux.go | 30 ++++++++ sys_conn_helper_linux_test.go | 20 +++-- sys_conn_helper_nonlinux.go | 3 + sys_conn_helper_nonlinux_test.go | 7 ++ sys_conn_no_gso.go | 8 -- sys_conn_oob.go | 20 +---- transport.go | 9 +-- 15 files changed, 318 insertions(+), 150 deletions(-) create mode 100644 mock_raw_conn_test.go create mode 100644 sys_conn_helper_nonlinux_test.go delete mode 100644 sys_conn_no_gso.go diff --git a/mock_raw_conn_test.go b/mock_raw_conn_test.go new file mode 100644 index 00000000..66b9c611 --- /dev/null +++ b/mock_raw_conn_test.go @@ -0,0 +1,122 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/quic-go/quic-go (interfaces: RawConn) + +// Package quic is a generated GoMock package. +package quic + +import ( + net "net" + reflect "reflect" + time "time" + + gomock "github.com/golang/mock/gomock" +) + +// MockRawConn is a mock of RawConn interface. +type MockRawConn struct { + ctrl *gomock.Controller + recorder *MockRawConnMockRecorder +} + +// MockRawConnMockRecorder is the mock recorder for MockRawConn. +type MockRawConnMockRecorder struct { + mock *MockRawConn +} + +// NewMockRawConn creates a new mock instance. +func NewMockRawConn(ctrl *gomock.Controller) *MockRawConn { + mock := &MockRawConn{ctrl: ctrl} + mock.recorder = &MockRawConnMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRawConn) EXPECT() *MockRawConnMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockRawConn) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockRawConnMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockRawConn)(nil).Close)) +} + +// LocalAddr mocks base method. +func (m *MockRawConn) LocalAddr() net.Addr { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LocalAddr") + ret0, _ := ret[0].(net.Addr) + return ret0 +} + +// LocalAddr indicates an expected call of LocalAddr. +func (mr *MockRawConnMockRecorder) LocalAddr() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LocalAddr", reflect.TypeOf((*MockRawConn)(nil).LocalAddr)) +} + +// ReadPacket mocks base method. +func (m *MockRawConn) ReadPacket() (receivedPacket, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadPacket") + ret0, _ := ret[0].(receivedPacket) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadPacket indicates an expected call of ReadPacket. +func (mr *MockRawConnMockRecorder) ReadPacket() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadPacket", reflect.TypeOf((*MockRawConn)(nil).ReadPacket)) +} + +// SetReadDeadline mocks base method. +func (m *MockRawConn) SetReadDeadline(arg0 time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetReadDeadline", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetReadDeadline indicates an expected call of SetReadDeadline. +func (mr *MockRawConnMockRecorder) SetReadDeadline(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetReadDeadline", reflect.TypeOf((*MockRawConn)(nil).SetReadDeadline), arg0) +} + +// WritePacket mocks base method. +func (m *MockRawConn) WritePacket(arg0 []byte, arg1 net.Addr, arg2 []byte) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WritePacket", arg0, arg1, arg2) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WritePacket indicates an expected call of WritePacket. +func (mr *MockRawConnMockRecorder) WritePacket(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WritePacket", reflect.TypeOf((*MockRawConn)(nil).WritePacket), arg0, arg1, arg2) +} + +// capabilities mocks base method. +func (m *MockRawConn) capabilities() connCapabilities { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "capabilities") + ret0, _ := ret[0].(connCapabilities) + return ret0 +} + +// capabilities indicates an expected call of capabilities. +func (mr *MockRawConnMockRecorder) capabilities() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "capabilities", reflect.TypeOf((*MockRawConn)(nil).capabilities)) +} diff --git a/mockgen.go b/mockgen.go index eb700864..221c1367 100644 --- a/mockgen.go +++ b/mockgen.go @@ -5,6 +5,9 @@ package quic //go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn" type SendConn = sendConn +//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn" +type RawConn = rawConn + //go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender" type Sender = sender diff --git a/packet_handler_map.go b/packet_handler_map.go index 2a16773c..e0f0567d 100644 --- a/packet_handler_map.go +++ b/packet_handler_map.go @@ -26,9 +26,9 @@ type connCapabilities struct { // rawConn is a connection that allow reading of a receivedPackeh. type rawConn interface { ReadPacket() (receivedPacket, error) - // The size parameter is used for GSO. - // If GSO is not support, len(b) must be equal to size. - WritePacket(b []byte, size uint16, addr net.Addr, oob []byte) (int, error) + // WritePacket writes a packet on the wire. + // If GSO is enabled, it's the caller's responsibility to set the correct control message. + WritePacket(b []byte, addr net.Addr, oob []byte) (int, error) LocalAddr() net.Addr SetReadDeadline(time.Time) error io.Closer diff --git a/send_conn.go b/send_conn.go index 4e7007fa..34cbfd6e 100644 --- a/send_conn.go +++ b/send_conn.go @@ -1,10 +1,12 @@ package quic import ( + "fmt" "math" "net" "github.com/quic-go/quic-go/internal/protocol" + "github.com/quic-go/quic-go/internal/utils" ) // A sendConn allows sending using a simple Write() on a non-connected packet conn. @@ -20,61 +22,84 @@ type sendConn interface { type sconn struct { rawConn + localAddr net.Addr remoteAddr net.Addr - info packetInfo - oob []byte + + logger utils.Logger + + info packetInfo + oob []byte + // If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled. + gotGSOError bool } var _ sendConn = &sconn{} -func newSendConn(c rawConn, remote net.Addr) *sconn { - sc := &sconn{ - rawConn: c, - remoteAddr: remote, +func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logger) *sconn { + localAddr := c.LocalAddr() + if info.addr.IsValid() { + if udpAddr, ok := localAddr.(*net.UDPAddr); ok { + addrCopy := *udpAddr + addrCopy.IP = info.addr.AsSlice() + localAddr = &addrCopy + } } - if c.capabilities().GSO { - // add 32 bytes, so we can add the UDP_SEGMENT msg - sc.oob = make([]byte, 0, 32) - } - return sc -} -func newSendConnWithPacketInfo(c rawConn, remote net.Addr, info packetInfo) *sconn { oob := info.OOB() - if c.capabilities().GSO { - // add 32 bytes, so we can add the UDP_SEGMENT msg - l := len(oob) - oob = append(oob, make([]byte, 32)...) - oob = oob[:l] - } + // add 32 bytes, so we can add the UDP_SEGMENT msg + l := len(oob) + oob = append(oob, make([]byte, 32)...) + oob = oob[:l] return &sconn{ rawConn: c, + localAddr: localAddr, remoteAddr: remote, info: info, oob: oob, + logger: logger, } } func (c *sconn) Write(p []byte, size protocol.ByteCount) error { + if !c.capabilities().GSO { + if protocol.ByteCount(len(p)) != size { + panic(fmt.Sprintf("inconsistent packet size (%d vs %d)", len(p), size)) + } + _, err := c.WritePacket(p, c.remoteAddr, c.oob) + return err + } + // GSO is supported. Append the control message and send. if size > math.MaxUint16 { panic("size overflow") } - _, err := c.WritePacket(p, uint16(size), c.remoteAddr, c.oob) + _, err := c.WritePacket(p, c.remoteAddr, appendUDPSegmentSizeMsg(c.oob, uint16(size))) + if err != nil && isGSOError(err) { + // disable GSO for future calls + c.gotGSOError = true + if c.logger.Debug() { + c.logger.Debugf("GSO failed when sending to %s", c.remoteAddr) + } + // send out the packets one by one + for len(p) > 0 { + l := len(p) + if l > int(size) { + l = int(size) + } + if _, err := c.WritePacket(p[:l], c.remoteAddr, c.oob); err != nil { + return err + } + p = p[l:] + } + return nil + } return err } -func (c *sconn) RemoteAddr() net.Addr { - return c.remoteAddr +func (c *sconn) capabilities() connCapabilities { + capabilities := c.rawConn.capabilities() + capabilities.GSO = !c.gotGSOError + return capabilities } -func (c *sconn) LocalAddr() net.Addr { - addr := c.rawConn.LocalAddr() - if c.info.addr.IsValid() { - if udpAddr, ok := addr.(*net.UDPAddr); ok { - addrCopy := *udpAddr - addrCopy.IP = c.info.addr.AsSlice() - addr = &addrCopy - } - } - return addr -} +func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddr } +func (c *sconn) LocalAddr() net.Addr { return c.localAddr } diff --git a/send_conn_test.go b/send_conn_test.go index 56fe9236..8676d409 100644 --- a/send_conn_test.go +++ b/send_conn_test.go @@ -2,46 +2,81 @@ package quic import ( "net" + "net/netip" + "github.com/quic-go/quic-go/internal/utils" + + "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) +// Only if appendUDPSegmentSizeMsg actually appends a message (and isn't only a stub implementation), +// GSO is actually supported on this platform. +var platformSupportsGSO = len(appendUDPSegmentSizeMsg([]byte{}, 1337)) > 0 + var _ = Describe("Connection (for sending packets)", func() { - var ( - c sendConn - packetConn *MockPacketConn - addr net.Addr - ) + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337} - BeforeEach(func() { - addr = &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337} - packetConn = NewMockPacketConn(mockCtrl) - rawConn, err := wrapConn(packetConn) - Expect(err).ToNot(HaveOccurred()) - c = newSendConnWithPacketInfo(rawConn, addr, packetInfo{}) - }) - - It("writes", func() { - packetConn.EXPECT().WriteTo([]byte("foobar"), addr) - Expect(c.Write([]byte("foobar"), 6)).To(Succeed()) - }) - - It("gets the remote address", func() { + It("gets the local and remote addresses", func() { + localAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1234} + rawConn := NewMockRawConn(mockCtrl) + rawConn.EXPECT().LocalAddr().Return(localAddr) + c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger) + Expect(c.LocalAddr().String()).To(Equal("192.168.0.1:1234")) Expect(c.RemoteAddr().String()).To(Equal("192.168.100.200:1337")) }) - It("gets the local address", func() { - addr := &net.UDPAddr{ - IP: net.IPv4(192, 168, 0, 1), - Port: 1234, - } - packetConn.EXPECT().LocalAddr().Return(addr) - Expect(c.LocalAddr()).To(Equal(addr)) + It("uses the local address from the packet info", func() { + localAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 0, 1), Port: 1234} + rawConn := NewMockRawConn(mockCtrl) + rawConn.EXPECT().LocalAddr().Return(localAddr) + c := newSendConn(rawConn, remoteAddr, packetInfo{addr: netip.AddrFrom4([4]byte{127, 0, 0, 42})}, utils.DefaultLogger) + Expect(c.LocalAddr().String()).To(Equal("127.0.0.42:1234")) }) - It("closes", func() { - packetConn.EXPECT().Close() - Expect(c.Close()).To(Succeed()) - }) + if platformSupportsGSO { + It("writes with GSO", func() { + rawConn := NewMockRawConn(mockCtrl) + rawConn.EXPECT().LocalAddr() + rawConn.EXPECT().capabilities().Return(connCapabilities{GSO: true}).AnyTimes() + c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger) + rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any()).Do(func(_ []byte, _ net.Addr, oob []byte) { + msg := appendUDPSegmentSizeMsg([]byte{}, 3) + Expect(oob).To(Equal(msg)) + }) + Expect(c.Write([]byte("foobar"), 3)).To(Succeed()) + }) + + It("disables GSO if writing fails", func() { + rawConn := NewMockRawConn(mockCtrl) + rawConn.EXPECT().LocalAddr() + rawConn.EXPECT().capabilities().Return(connCapabilities{GSO: true}).AnyTimes() + c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger) + Expect(c.capabilities().GSO).To(BeTrue()) + gomock.InOrder( + rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Any()).DoAndReturn(func(_ []byte, _ net.Addr, oob []byte) (int, error) { + msg := appendUDPSegmentSizeMsg([]byte{}, 3) + Expect(oob).To(Equal(msg)) + return 0, errGSO + }), + rawConn.EXPECT().WritePacket([]byte("foo"), remoteAddr, []byte{}).Return(3, nil), + rawConn.EXPECT().WritePacket([]byte("bar"), remoteAddr, []byte{}).Return(3, nil), + ) + Expect(c.Write([]byte("foobar"), 3)).To(Succeed()) + Expect(c.capabilities().GSO).To(BeFalse()) // GSO support is now disabled + // make sure we actually enforce that + Expect(func() { c.Write([]byte("foobar"), 3) }).To(PanicWith("inconsistent packet size (6 vs 3)")) + }) + } else { + It("writes without GSO", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337} + rawConn := NewMockRawConn(mockCtrl) + rawConn.EXPECT().LocalAddr() + rawConn.EXPECT().capabilities() + c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger) + rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, nil) + Expect(c.Write([]byte("foobar"), 6)).To(Succeed()) + }) + } }) diff --git a/server.go b/server.go index 0f8219e3..c06228c9 100644 --- a/server.go +++ b/server.go @@ -632,7 +632,7 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error tracer = config.Tracer(context.WithValue(context.Background(), ConnectionTracingKey, tracingID), protocol.PerspectiveServer, connID) } conn = s.newConn( - newSendConnWithPacketInfo(s.conn, p.remoteAddr, p.info), + newSendConn(s.conn, p.remoteAddr, p.info, s.logger), s.connHandler, origDestConnID, retrySrcConnID, @@ -742,7 +742,7 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info packe if s.tracer != nil { s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil) } - _, err = s.conn.WritePacket(buf.Data, uint16(len(buf.Data)), remoteAddr, info.OOB()) + _, err = s.conn.WritePacket(buf.Data, remoteAddr, info.OOB()) return err } @@ -841,7 +841,7 @@ func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer han if s.tracer != nil { s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(b.Data)), []logging.Frame{ccf}) } - _, err = s.conn.WritePacket(b.Data, uint16(len(b.Data)), remoteAddr, info.OOB()) + _, err = s.conn.WritePacket(b.Data, remoteAddr, info.OOB()) return err } @@ -879,7 +879,7 @@ func (s *baseServer) maybeSendVersionNegotiationPacket(p receivedPacket) { if s.tracer != nil { s.tracer.SentVersionNegotiationPacket(p.remoteAddr, src, dest, s.config.Versions) } - if _, err := s.conn.WritePacket(data, uint16(len(data)), p.remoteAddr, p.info.OOB()); err != nil { + if _, err := s.conn.WritePacket(data, p.remoteAddr, p.info.OOB()); err != nil { s.logger.Debugf("Error sending Version Negotiation: %s", err) } } diff --git a/sys_conn.go b/sys_conn.go index 414472e7..f2224e4c 100644 --- a/sys_conn.go +++ b/sys_conn.go @@ -1,7 +1,6 @@ package quic import ( - "fmt" "log" "net" "os" @@ -105,10 +104,7 @@ func (c *basicConn) ReadPacket() (receivedPacket, error) { }, nil } -func (c *basicConn) WritePacket(b []byte, packetSize uint16, addr net.Addr, _ []byte) (n int, err error) { - if uint16(len(b)) != packetSize { - panic(fmt.Sprintf("inconsistent length. got: %d. expected %d", packetSize, len(b))) - } +func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte) (n int, err error) { return c.PacketConn.WriteTo(b, addr) } diff --git a/sys_conn_df_linux.go b/sys_conn_df_linux.go index 199f6347..f09eaa5d 100644 --- a/sys_conn_df_linux.go +++ b/sys_conn_df_linux.go @@ -4,11 +4,7 @@ package quic import ( "errors" - "log" - "os" - "strconv" "syscall" - "unsafe" "golang.org/x/sys/unix" @@ -38,43 +34,9 @@ func setDF(rawConn syscall.RawConn) (bool, error) { return true, nil } -func maybeSetGSO(rawConn syscall.RawConn) bool { - enable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_ENABLE_GSO")) - if !enable { - return false - } - - var setErr error - if err := rawConn.Control(func(fd uintptr) { - setErr = unix.SetsockoptInt(int(fd), syscall.IPPROTO_UDP, unix.UDP_SEGMENT, 1) - }); err != nil { - setErr = err - } - if setErr != nil { - log.Println("failed to enable GSO") - return false - } - return true -} - func isSendMsgSizeErr(err error) bool { // https://man7.org/linux/man-pages/man7/udp.7.html return errors.Is(err, unix.EMSGSIZE) } -func isRecvMsgSizeErr(err error) bool { return false } - -func appendUDPSegmentSizeMsg(b []byte, size uint16) []byte { - startLen := len(b) - const dataLen = 2 // payload is a uint16 - b = append(b, make([]byte, unix.CmsgSpace(dataLen))...) - h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen])) - h.Level = syscall.IPPROTO_UDP - h.Type = unix.UDP_SEGMENT - h.SetLen(unix.CmsgLen(dataLen)) - - // UnixRights uses the private `data` method, but I *think* this achieves the same goal. - offset := startLen + unix.CmsgSpace(0) - *(*uint16)(unsafe.Pointer(&b[offset])) = size - return b -} +func isRecvMsgSizeErr(error) bool { return false } diff --git a/sys_conn_helper_linux.go b/sys_conn_helper_linux.go index 61224eaa..4e87bba0 100644 --- a/sys_conn_helper_linux.go +++ b/sys_conn_helper_linux.go @@ -4,8 +4,11 @@ package quic import ( "encoding/binary" + "errors" "net/netip" + "os" "syscall" + "unsafe" "golang.org/x/sys/unix" ) @@ -48,3 +51,30 @@ func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) { } return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.LittleEndian.Uint32(body), true } + +func appendUDPSegmentSizeMsg(b []byte, size uint16) []byte { + startLen := len(b) + const dataLen = 2 // payload is a uint16 + b = append(b, make([]byte, unix.CmsgSpace(dataLen))...) + h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen])) + h.Level = syscall.IPPROTO_UDP + h.Type = unix.UDP_SEGMENT + h.SetLen(unix.CmsgLen(dataLen)) + + // UnixRights uses the private `data` method, but I *think* this achieves the same goal. + offset := startLen + unix.CmsgSpace(0) + *(*uint16)(unsafe.Pointer(&b[offset])) = size + return b +} + +func isGSOError(err error) bool { + var serr *os.SyscallError + if errors.As(err, &serr) { + // EIO is returned by udp_send_skb() if the device driver does not have tx checksums enabled, + // which is a hard requirement of UDP_SEGMENT. See: + // https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/tree/man7/udp.7?id=806eabd74910447f21005160e90957bde4db0183#n228 + // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv4/udp.c?h=v6.2&id=c9c3395d5e3dcc6daee66c6908354d47bf98cb0c#n942 + return serr.Err == unix.EIO + } + return false +} diff --git a/sys_conn_helper_linux_test.go b/sys_conn_helper_linux_test.go index fa39c523..4cf59abe 100644 --- a/sys_conn_helper_linux_test.go +++ b/sys_conn_helper_linux_test.go @@ -1,22 +1,24 @@ -// We need root permissions to use RCVBUFFORCE. -// This test is therefore only compiled when the root build flag is set. -// It can only succeed if the tests are then also run with root permissions. -//go:build linux && root +//go:build linux package quic import ( + "errors" "net" "os" + "golang.org/x/sys/unix" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) +var errGSO = &os.SyscallError{Err: unix.EIO} + var _ = Describe("forcing a change of send and receive buffer sizes", func() { It("forces a change of the receive buffer size", func() { if os.Getuid() != 0 { - Fail("Must be root to force change the receive buffer size") + Skip("Must be root to force change the receive buffer size") } c, err := net.ListenPacket("udp", "127.0.0.1:0") @@ -43,7 +45,7 @@ var _ = Describe("forcing a change of send and receive buffer sizes", func() { It("forces a change of the send buffer size", func() { if os.Getuid() != 0 { - Fail("Must be root to force change the send buffer size") + Skip("Must be root to force change the send buffer size") } c, err := net.ListenPacket("udp", "127.0.0.1:0") @@ -67,4 +69,10 @@ var _ = Describe("forcing a change of send and receive buffer sizes", func() { // The kernel doubles this value (to allow space for bookkeeping overhead) Expect(size).To(Equal(2 * large)) }) + + It("detects GSO errors", func() { + Expect(isGSOError(errGSO)).To(BeTrue()) + Expect(isGSOError(nil)).To(BeFalse()) + Expect(isGSOError(errors.New("test"))).To(BeFalse()) + }) }) diff --git a/sys_conn_helper_nonlinux.go b/sys_conn_helper_nonlinux.go index 80b795c3..48ab10aa 100644 --- a/sys_conn_helper_nonlinux.go +++ b/sys_conn_helper_nonlinux.go @@ -4,3 +4,6 @@ package quic func forceSetReceiveBuffer(c any, bytes int) error { return nil } func forceSetSendBuffer(c any, bytes int) error { return nil } + +func appendUDPSegmentSizeMsg(_ []byte, _ uint16) []byte { return nil } +func isGSOError(error) bool { return false } diff --git a/sys_conn_helper_nonlinux_test.go b/sys_conn_helper_nonlinux_test.go new file mode 100644 index 00000000..29d42ad3 --- /dev/null +++ b/sys_conn_helper_nonlinux_test.go @@ -0,0 +1,7 @@ +//go:build !linux + +package quic + +import "errors" + +var errGSO = errors.New("fake GSO error") diff --git a/sys_conn_no_gso.go b/sys_conn_no_gso.go deleted file mode 100644 index 6f6a8c91..00000000 --- a/sys_conn_no_gso.go +++ /dev/null @@ -1,8 +0,0 @@ -//go:build darwin || freebsd - -package quic - -import "syscall" - -func maybeSetGSO(_ syscall.RawConn) bool { return false } -func appendUDPSegmentSizeMsg(_ []byte, _ uint16) []byte { return nil } diff --git a/sys_conn_oob.go b/sys_conn_oob.go index 84d5e7e6..aa69262b 100644 --- a/sys_conn_oob.go +++ b/sys_conn_oob.go @@ -5,7 +5,6 @@ package quic import ( "encoding/binary" "errors" - "fmt" "log" "net" "net/netip" @@ -128,10 +127,6 @@ func newConn(c OOBCapablePacketConn, supportsDF bool) (*oobConn, error) { bc = ipv4.NewPacketConn(c) } - // Try enabling GSO. - // This will only succeed on Linux, and only for kernels > 4.18. - supportsGSO := maybeSetGSO(rawConn) - msgs := make([]ipv4.Message, batchSize) for i := range msgs { // preallocate the [][]byte @@ -144,7 +139,6 @@ func newConn(c OOBCapablePacketConn, supportsDF bool) (*oobConn, error) { readPos: batchSize, } oobConn.cap.DF = supportsDF - oobConn.cap.GSO = supportsGSO for i := 0; i < batchSize; i++ { oobConn.messages[i].OOB = make([]byte, oobBufferSize) } @@ -231,17 +225,9 @@ func (c *oobConn) ReadPacket() (receivedPacket, error) { } // WritePacket writes a new packet. -// If the connection supports GSO (and we activated GSO support before), -// it appends the UDP_SEGMENT size message to oob. -// Callers are advised to make sure that oob has a sufficient capacity, -// such that appending the UDP_SEGMENT size message doesn't cause an allocation. -func (c *oobConn) WritePacket(b []byte, packetSize uint16, addr net.Addr, oob []byte) (n int, err error) { - if c.cap.GSO { - oob = appendUDPSegmentSizeMsg(oob, packetSize) - } else if uint16(len(b)) != packetSize { - panic(fmt.Sprintf("inconsistent length. got: %d. expected %d", packetSize, len(b))) - } - n, _, err = c.OOBCapablePacketConn.WriteMsgUDP(b, oob, addr.(*net.UDPAddr)) +// If the connection supports GSO, it's the caller's responsibility to append the right control mesage. +func (c *oobConn) WritePacket(b []byte, addr net.Addr, oob []byte) (int, error) { + n, _, err := c.OOBCapablePacketConn.WriteMsgUDP(b, oob, addr.(*net.UDPAddr)) return n, err } diff --git a/transport.go b/transport.go index 42fafd49..ae44e3da 100644 --- a/transport.go +++ b/transport.go @@ -179,7 +179,7 @@ func (t *Transport) dial(ctx context.Context, addr net.Addr, hostname string, tl } tlsConf.ServerName = hostname } - return dial(ctx, newSendConn(t.conn, addr), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, use0RTT) + return dial(ctx, newSendConn(t.conn, addr, packetInfo{}, utils.DefaultLogger), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, use0RTT) } func (t *Transport) init(allowZeroLengthConnIDs bool) error { @@ -195,7 +195,6 @@ func (t *Transport) init(allowZeroLengthConnIDs bool) error { return } } - t.conn = conn t.logger = utils.DefaultLogger // TODO: make this configurable t.conn = conn @@ -229,7 +228,7 @@ func (t *Transport) WriteTo(b []byte, addr net.Addr) (int, error) { if err := t.init(false); err != nil { return 0, err } - return t.conn.WritePacket(b, uint16(len(b)), addr, nil) + return t.conn.WritePacket(b, addr, nil) } func (t *Transport) enqueueClosePacket(p closePacket) { @@ -247,7 +246,7 @@ func (t *Transport) runSendQueue() { case <-t.listening: return case p := <-t.closeQueue: - t.conn.WritePacket(p.payload, uint16(len(p.payload)), p.addr, p.info.OOB()) + t.conn.WritePacket(p.payload, p.addr, p.info.OOB()) case p := <-t.statelessResetQueue: t.sendStatelessReset(p) } @@ -408,7 +407,7 @@ func (t *Transport) sendStatelessReset(p receivedPacket) { rand.Read(data) data[0] = (data[0] & 0x7f) | 0x40 data = append(data, token[:]...) - if _, err := t.conn.WritePacket(data, uint16(len(data)), p.remoteAddr, p.info.OOB()); err != nil { + if _, err := t.conn.WritePacket(data, p.remoteAddr, p.info.OOB()); err != nil { t.logger.Debugf("Error sending Stateless Reset to %s: %s", p.remoteAddr, err) } } From 3a3169551bf6b579fd8e5044479abf6bbfc3bbea Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 30 Jul 2023 16:31:30 -0400 Subject: [PATCH 19/36] detect kernel GSO support --- send_conn.go | 4 +++- send_conn_test.go | 6 +++--- sys_conn_helper_darwin.go | 3 +++ sys_conn_helper_freebsd.go | 3 +++ sys_conn_helper_linux.go | 12 ++++++++++++ sys_conn_helper_nonlinux.go | 4 ++-- sys_conn_oob.go | 5 ++++- 7 files changed, 30 insertions(+), 7 deletions(-) diff --git a/send_conn.go b/send_conn.go index 34cbfd6e..d8ddbc87 100644 --- a/send_conn.go +++ b/send_conn.go @@ -97,7 +97,9 @@ func (c *sconn) Write(p []byte, size protocol.ByteCount) error { func (c *sconn) capabilities() connCapabilities { capabilities := c.rawConn.capabilities() - capabilities.GSO = !c.gotGSOError + if capabilities.GSO { + capabilities.GSO = !c.gotGSOError + } return capabilities } diff --git a/send_conn_test.go b/send_conn_test.go index 8676d409..024a8eba 100644 --- a/send_conn_test.go +++ b/send_conn_test.go @@ -60,8 +60,8 @@ var _ = Describe("Connection (for sending packets)", func() { Expect(oob).To(Equal(msg)) return 0, errGSO }), - rawConn.EXPECT().WritePacket([]byte("foo"), remoteAddr, []byte{}).Return(3, nil), - rawConn.EXPECT().WritePacket([]byte("bar"), remoteAddr, []byte{}).Return(3, nil), + rawConn.EXPECT().WritePacket([]byte("foo"), remoteAddr, gomock.Len(0)).Return(3, nil), + rawConn.EXPECT().WritePacket([]byte("bar"), remoteAddr, gomock.Len(0)).Return(3, nil), ) Expect(c.Write([]byte("foobar"), 3)).To(Succeed()) Expect(c.capabilities().GSO).To(BeFalse()) // GSO support is now disabled @@ -75,7 +75,7 @@ var _ = Describe("Connection (for sending packets)", func() { rawConn.EXPECT().LocalAddr() rawConn.EXPECT().capabilities() c := newSendConn(rawConn, remoteAddr, packetInfo{}, utils.DefaultLogger) - rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, nil) + rawConn.EXPECT().WritePacket([]byte("foobar"), remoteAddr, gomock.Len(0)) Expect(c.Write([]byte("foobar"), 6)).To(Succeed()) }) } diff --git a/sys_conn_helper_darwin.go b/sys_conn_helper_darwin.go index bf735f0f..758cf778 100644 --- a/sys_conn_helper_darwin.go +++ b/sys_conn_helper_darwin.go @@ -5,6 +5,7 @@ package quic import ( "encoding/binary" "net/netip" + "syscall" "golang.org/x/sys/unix" ) @@ -29,3 +30,5 @@ func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) { } return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.LittleEndian.Uint32(body), true } + +func isGSOSupported(syscall.RawConn) bool { return false } diff --git a/sys_conn_helper_freebsd.go b/sys_conn_helper_freebsd.go index fe5a7c20..a2baae3b 100644 --- a/sys_conn_helper_freebsd.go +++ b/sys_conn_helper_freebsd.go @@ -4,6 +4,7 @@ package quic import ( "net/netip" + "syscall" "golang.org/x/sys/unix" ) @@ -24,3 +25,5 @@ func parseIPv4PktInfo(body []byte) (ip netip.Addr, _ uint32, ok bool) { } return netip.AddrFrom4(*(*[4]byte)(body)), 0, true } + +func isGSOSupported(syscall.RawConn) bool { return false } diff --git a/sys_conn_helper_linux.go b/sys_conn_helper_linux.go index 4e87bba0..5a177c29 100644 --- a/sys_conn_helper_linux.go +++ b/sys_conn_helper_linux.go @@ -52,6 +52,18 @@ func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) { return netip.AddrFrom4(*(*[4]byte)(body[8:12])), binary.LittleEndian.Uint32(body), true } +// isGSOSupported tests if the kernel supports GSO. +// Sending with GSO might still fail later on, if the interface doesn't support it (see isGSOError). +func isGSOSupported(conn syscall.RawConn) bool { + var serr error + if err := conn.Control(func(fd uintptr) { + _, serr = unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_SEGMENT) + }); err != nil { + return false + } + return serr == nil +} + func appendUDPSegmentSizeMsg(b []byte, size uint16) []byte { startLen := len(b) const dataLen = 2 // payload is a uint16 diff --git a/sys_conn_helper_nonlinux.go b/sys_conn_helper_nonlinux.go index 48ab10aa..cace82d5 100644 --- a/sys_conn_helper_nonlinux.go +++ b/sys_conn_helper_nonlinux.go @@ -5,5 +5,5 @@ package quic func forceSetReceiveBuffer(c any, bytes int) error { return nil } func forceSetSendBuffer(c any, bytes int) error { return nil } -func appendUDPSegmentSizeMsg(_ []byte, _ uint16) []byte { return nil } -func isGSOError(error) bool { return false } +func appendUDPSegmentSizeMsg([]byte, uint16) []byte { return nil } +func isGSOError(error) bool { return false } diff --git a/sys_conn_oob.go b/sys_conn_oob.go index aa69262b..4026a7b3 100644 --- a/sys_conn_oob.go +++ b/sys_conn_oob.go @@ -137,8 +137,11 @@ func newConn(c OOBCapablePacketConn, supportsDF bool) (*oobConn, error) { batchConn: bc, messages: msgs, readPos: batchSize, + cap: connCapabilities{ + DF: supportsDF, + GSO: isGSOSupported(rawConn), + }, } - oobConn.cap.DF = supportsDF for i := 0; i < batchSize; i++ { oobConn.messages[i].OOB = make([]byte, oobBufferSize) } From 5200f27dcfa7146b6585d292befbbe23cfa55777 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 6 Aug 2023 18:22:47 -0400 Subject: [PATCH 20/36] add QUIC_GO_DISABLE_GSO env to disable GSO --- sys_conn_helper_linux.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sys_conn_helper_linux.go b/sys_conn_helper_linux.go index 5a177c29..5bda2286 100644 --- a/sys_conn_helper_linux.go +++ b/sys_conn_helper_linux.go @@ -7,12 +7,22 @@ import ( "errors" "net/netip" "os" + "strconv" "syscall" "unsafe" "golang.org/x/sys/unix" ) +var gsoDisabled bool + +func init() { + disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_GSO")) + if err == nil { + gsoDisabled = disabled + } +} + const ( msgTypeIPTOS = unix.IP_TOS ipv4PKTINFO = unix.IP_PKTINFO @@ -55,6 +65,9 @@ func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) { // isGSOSupported tests if the kernel supports GSO. // Sending with GSO might still fail later on, if the interface doesn't support it (see isGSOError). func isGSOSupported(conn syscall.RawConn) bool { + if gsoDisabled { + return false + } var serr error if err := conn.Control(func(fd uintptr) { _, serr = unix.GetsockoptInt(int(fd), unix.IPPROTO_UDP, unix.UDP_SEGMENT) From 3822dae9bbb1baee54b71e3a5a5a585c62680a0d Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 17 Aug 2023 12:26:36 +0700 Subject: [PATCH 21/36] handshake fuzzer: fix setting of cipher suites (#4037) --- fuzzing/handshake/fuzz.go | 44 +++++++++++++-------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/fuzzing/handshake/fuzz.go b/fuzzing/handshake/fuzz.go index 93cec975..a3f549ee 100644 --- a/fuzzing/handshake/fuzz.go +++ b/fuzzing/handshake/fuzz.go @@ -17,6 +17,7 @@ import ( "github.com/quic-go/quic-go/fuzzing/internal/helper" "github.com/quic-go/quic-go/internal/handshake" "github.com/quic-go/quic-go/internal/protocol" + "github.com/quic-go/quic-go/internal/qtls" "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/internal/wire" ) @@ -84,33 +85,6 @@ func (m messageType) String() string { } } -func appendSuites(suites []uint16, rand uint8) []uint16 { - const ( - s1 = tls.TLS_AES_128_GCM_SHA256 - s2 = tls.TLS_AES_256_GCM_SHA384 - s3 = tls.TLS_CHACHA20_POLY1305_SHA256 - ) - switch rand % 4 { - default: - return suites - case 1: - return append(suites, s1) - case 2: - return append(suites, s2) - case 3: - return append(suites, s3) - } -} - -// consumes 2 bits -func getSuites(rand uint8) []uint16 { - suites := make([]uint16, 0, 3) - for i := 1; i <= 3; i++ { - suites = appendSuites(suites, rand>>i%4) - } - return suites -} - // consumes 3 bits func getClientAuth(rand uint8) tls.ClientAuthType { switch rand { @@ -207,14 +181,26 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. SessionTicketKey: sessionTicketKey, } + // This sets the cipher suite for both client and server. + // The way crypto/tls is designed doesn't allow us to set different cipher suites for client and server. + resetCipherSuite := func() {} + switch (runConfig[0] >> 6) % 4 { + case 0: + resetCipherSuite = qtls.SetCipherSuite(tls.TLS_AES_128_GCM_SHA256) + case 1: + resetCipherSuite = qtls.SetCipherSuite(tls.TLS_AES_256_GCM_SHA384) + case 3: + resetCipherSuite = qtls.SetCipherSuite(tls.TLS_CHACHA20_POLY1305_SHA256) + default: + } + defer resetCipherSuite() + enable0RTTClient := helper.NthBit(runConfig[0], 0) enable0RTTServer := helper.NthBit(runConfig[0], 1) sendPostHandshakeMessageToClient := helper.NthBit(runConfig[0], 3) sendPostHandshakeMessageToServer := helper.NthBit(runConfig[0], 4) sendSessionTicket := helper.NthBit(runConfig[0], 5) - clientConf.CipherSuites = getSuites(runConfig[0] >> 6) serverConf.ClientAuth = getClientAuth(runConfig[1] & 0b00000111) - serverConf.CipherSuites = getSuites(runConfig[1] >> 6) serverConf.SessionTicketsDisabled = helper.NthBit(runConfig[1], 3) if helper.NthBit(runConfig[2], 0) { clientConf.RootCAs = x509.NewCertPool() From 501cc21c4b7ff3bf3b37a20b4f78fabb741aa046 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 18 Aug 2023 17:01:49 +0700 Subject: [PATCH 22/36] expose crypto/tls errors on the TransportError (#4015) --- go.mod | 2 +- go.sum | 4 ++-- integrationtests/gomodvendor/go.sum | 4 ++-- integrationtests/self/handshake_test.go | 2 ++ internal/handshake/crypto_setup.go | 3 ++- internal/qerr/errors.go | 14 +++++++++++--- internal/qerr/errors_test.go | 21 ++++++++++++++++++--- packet_packer_test.go | 3 ++- 8 files changed, 40 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 2f2a0ff0..106c90fd 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/onsi/ginkgo/v2 v2.9.5 github.com/onsi/gomega v1.27.6 github.com/quic-go/qpack v0.4.0 - github.com/quic-go/qtls-go1-20 v0.3.1 + github.com/quic-go/qtls-go1-20 v0.3.2 golang.org/x/crypto v0.4.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.10.0 diff --git a/go.sum b/go.sum index c0ed9606..f28b844c 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,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/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= -github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= +github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= diff --git a/integrationtests/gomodvendor/go.sum b/integrationtests/gomodvendor/go.sum index ad9adb31..ab32e138 100644 --- a/integrationtests/gomodvendor/go.sum +++ b/integrationtests/gomodvendor/go.sum @@ -136,8 +136,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/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= -github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= +github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= diff --git a/integrationtests/self/handshake_test.go b/integrationtests/self/handshake_test.go index 951c4c7a..8123c8fe 100644 --- a/integrationtests/self/handshake_test.go +++ b/integrationtests/self/handshake_test.go @@ -202,6 +202,8 @@ var _ = Describe("Handshake tests", func() { Expect(errors.As(err, &transportErr)).To(BeTrue()) Expect(transportErr.ErrorCode.IsCryptoError()).To(BeTrue()) Expect(transportErr.Error()).To(ContainSubstring("x509: certificate is valid for localhost, not foo.bar")) + var certErr *tls.CertificateVerificationError + Expect(errors.As(transportErr, &certErr)).To(BeTrue()) }) It("fails the handshake if the client fails to provide the requested client cert", func() { diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index a1179257..332dbd7e 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -664,8 +664,9 @@ func (h *cryptoSetup) ConnectionState() ConnectionState { } func wrapError(err error) error { + // alert 80 is an internal error if alertErr := qtls.AlertError(0); errors.As(err, &alertErr) && alertErr != 80 { - return qerr.NewLocalCryptoError(uint8(alertErr), err.Error()) + return qerr.NewLocalCryptoError(uint8(alertErr), err) } return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()} } diff --git a/internal/qerr/errors.go b/internal/qerr/errors.go index 26ea3445..2d8511f7 100644 --- a/internal/qerr/errors.go +++ b/internal/qerr/errors.go @@ -17,15 +17,16 @@ type TransportError struct { FrameType uint64 ErrorCode TransportErrorCode ErrorMessage string + error error // only set for local errors, sometimes } var _ error = &TransportError{} // NewLocalCryptoError create a new TransportError instance for a crypto error -func NewLocalCryptoError(tlsAlert uint8, errorMessage string) *TransportError { +func NewLocalCryptoError(tlsAlert uint8, err error) *TransportError { return &TransportError{ - ErrorCode: 0x100 + TransportErrorCode(tlsAlert), - ErrorMessage: errorMessage, + ErrorCode: 0x100 + TransportErrorCode(tlsAlert), + error: err, } } @@ -35,6 +36,9 @@ func (e *TransportError) Error() string { str += fmt.Sprintf(" (frame type: %#x)", e.FrameType) } msg := e.ErrorMessage + if len(msg) == 0 && e.error != nil { + msg = e.error.Error() + } if len(msg) == 0 { msg = e.ErrorCode.Message() } @@ -48,6 +52,10 @@ func (e *TransportError) Is(target error) bool { return target == net.ErrClosed } +func (e *TransportError) Unwrap() error { + return e.error +} + // An ApplicationErrorCode is an application-defined error code. type ApplicationErrorCode uint64 diff --git a/internal/qerr/errors_test.go b/internal/qerr/errors_test.go index 52d5c9e9..770ebd68 100644 --- a/internal/qerr/errors_test.go +++ b/internal/qerr/errors_test.go @@ -2,6 +2,7 @@ package qerr import ( "errors" + "fmt" "net" "github.com/quic-go/quic-go/internal/protocol" @@ -10,6 +11,12 @@ import ( . "github.com/onsi/gomega" ) +type myError int + +var _ error = myError(0) + +func (e myError) Error() string { return fmt.Sprintf("my error %d", e) } + var _ = Describe("QUIC Errors", func() { Context("Transport Errors", func() { It("has a string representation", func() { @@ -41,12 +48,20 @@ var _ = Describe("QUIC Errors", func() { Context("crypto errors", func() { It("has a string representation for errors with a message", func() { - err := NewLocalCryptoError(0x42, "foobar") - Expect(err.Error()).To(Equal("CRYPTO_ERROR 0x142 (local): foobar")) + myErr := myError(1337) + err := NewLocalCryptoError(0x42, myErr) + Expect(err.Error()).To(Equal("CRYPTO_ERROR 0x142 (local): my error 1337")) + }) + + It("unwraps errors", func() { + var myErr myError + err := NewLocalCryptoError(0x42, myError(1337)) + Expect(errors.As(err, &myErr)).To(BeTrue()) + Expect(myErr).To(BeEquivalentTo(1337)) }) It("has a string representation for errors without a message", func() { - err := NewLocalCryptoError(0x2a, "") + err := NewLocalCryptoError(0x2a, nil) Expect(err.Error()).To(Equal("CRYPTO_ERROR 0x12a (local): tls: bad certificate")) }) }) diff --git a/packet_packer_test.go b/packet_packer_test.go index 3ff15eaf..38ced47a 100644 --- a/packet_packer_test.go +++ b/packet_packer_test.go @@ -2,6 +2,7 @@ package quic import ( "bytes" + "errors" "fmt" "net" "time" @@ -334,7 +335,7 @@ var _ = Describe("Packet packer", func() { sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped) sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil) sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable) - quicErr := qerr.NewLocalCryptoError(0x42, "crypto error") + quicErr := qerr.NewLocalCryptoError(0x42, errors.New("crypto error")) quicErr.FrameType = 0x1234 p, err := packer.PackConnectionClose(quicErr, maxPacketSize, protocol.Version1) Expect(err).ToNot(HaveOccurred()) From 5c5db8cc599b11c9cef913f5a816f42b9ebd9dc6 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 19 Aug 2023 07:16:57 +0700 Subject: [PATCH 23/36] reassemble post-handshake TLS messages before passing them to crypto/tls (#4038) --- connection.go | 8 ++++---- crypto_stream.go | 25 +++++++++++++++++++++++-- crypto_stream_test.go | 22 +++++++++++++++++++++- fuzzing/handshake/fuzz.go | 1 + 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/connection.go b/connection.go index b17f3ce8..877f2d03 100644 --- a/connection.go +++ b/connection.go @@ -243,7 +243,7 @@ var newConnection = func( handshakeDestConnID: destConnID, srcConnIDLen: srcConnID.Len(), tokenGenerator: tokenGenerator, - oneRTTStream: newCryptoStream(), + oneRTTStream: newCryptoStream(true), perspective: protocol.PerspectiveServer, tracer: tracer, logger: logger, @@ -391,7 +391,7 @@ var newClientConnection = func( s.logger, ) s.mtuDiscoverer = newMTUDiscoverer(s.rttStats, getMaxPacketSize(s.conn.RemoteAddr()), s.sentPacketHandler.SetMaxDatagramSize) - oneRTTStream := newCryptoStream() + oneRTTStream := newCryptoStream(true) params := &wire.TransportParameters{ InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow), InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow), @@ -447,8 +447,8 @@ var newClientConnection = func( } func (s *connection) preSetup() { - s.initialStream = newCryptoStream() - s.handshakeStream = newCryptoStream() + s.initialStream = newCryptoStream(false) + s.handshakeStream = newCryptoStream(false) s.sendQueue = newSendQueue(s.conn) s.retransmissionQueue = newRetransmissionQueue() s.frameParser = wire.NewFrameParser(s.config.EnableDatagrams) diff --git a/crypto_stream.go b/crypto_stream.go index 4be2a07a..5ce2125d 100644 --- a/crypto_stream.go +++ b/crypto_stream.go @@ -30,10 +30,17 @@ type cryptoStreamImpl struct { writeOffset protocol.ByteCount writeBuf []byte + + // Reassemble TLS handshake messages before returning them from GetCryptoData. + // This is only needed because crypto/tls doesn't correctly handle post-handshake messages. + onlyCompleteMsg bool } -func newCryptoStream() cryptoStream { - return &cryptoStreamImpl{queue: newFrameSorter()} +func newCryptoStream(onlyCompleteMsg bool) cryptoStream { + return &cryptoStreamImpl{ + queue: newFrameSorter(), + onlyCompleteMsg: onlyCompleteMsg, + } } func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error { @@ -71,6 +78,20 @@ func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error { // GetCryptoData retrieves data that was received in CRYPTO frames func (s *cryptoStreamImpl) GetCryptoData() []byte { + if s.onlyCompleteMsg { + if len(s.msgBuf) < 4 { + return nil + } + msgLen := 4 + int(s.msgBuf[1])<<16 + int(s.msgBuf[2])<<8 + int(s.msgBuf[3]) + if len(s.msgBuf) < msgLen { + return nil + } + msg := make([]byte, msgLen) + copy(msg, s.msgBuf[:msgLen]) + s.msgBuf = s.msgBuf[msgLen:] + return msg + } + b := s.msgBuf s.msgBuf = nil return b diff --git a/crypto_stream_test.go b/crypto_stream_test.go index 9a4a2ee5..67de9149 100644 --- a/crypto_stream_test.go +++ b/crypto_stream_test.go @@ -1,6 +1,7 @@ package quic import ( + "crypto/rand" "fmt" "github.com/quic-go/quic-go/internal/protocol" @@ -15,7 +16,7 @@ var _ = Describe("Crypto Stream", func() { var str cryptoStream BeforeEach(func() { - str = newCryptoStream() + str = newCryptoStream(false) }) Context("handling incoming data", func() { @@ -137,4 +138,23 @@ var _ = Describe("Crypto Stream", func() { Expect(f.Data).To(Equal([]byte("bar"))) }) }) + + It("reassembles data", func() { + str = newCryptoStream(true) + data := make([]byte, 1337) + l := len(data) - 4 + data[1] = uint8(l >> 16) + data[2] = uint8(l >> 8) + data[3] = uint8(l) + rand.Read(data[4:]) + + for i, b := range data { + Expect(str.GetCryptoData()).To(BeEmpty()) + Expect(str.HandleCryptoFrame(&wire.CryptoFrame{ + Offset: protocol.ByteCount(i), + Data: []byte{b}, + })).To(Succeed()) + } + Expect(str.GetCryptoData()).To(Equal(data)) + }) }) diff --git a/fuzzing/handshake/fuzz.go b/fuzzing/handshake/fuzz.go index a3f549ee..be34c22d 100644 --- a/fuzzing/handshake/fuzz.go +++ b/fuzzing/handshake/fuzz.go @@ -408,6 +408,7 @@ func runHandshake(runConfig [confLen]byte, messageConfig uint8, clientConf *tls. } client.HandleMessage(ticket, protocol.Encryption1RTT) } + if sendPostHandshakeMessageToClient { fmt.Println("sending post handshake message to the client at", messageToReplaceEncLevel) client.HandleMessage(data, messageToReplaceEncLevel) From 443c6148b6f6a48a421f1a07c9ef9c593aec535a Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 19 Aug 2023 07:17:37 +0700 Subject: [PATCH 24/36] protocol: add string representation for ECN values (#4008) --- internal/protocol/protocol.go | 15 +++++++++++++++ internal/protocol/protocol_test.go | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/internal/protocol/protocol.go b/internal/protocol/protocol.go index 98bc9ffb..b8104882 100644 --- a/internal/protocol/protocol.go +++ b/internal/protocol/protocol.go @@ -43,6 +43,21 @@ const ( ECNCE // 11 ) +func (e ECN) String() string { + switch e { + case ECNNon: + return "Not-ECT" + case ECT1: + return "ECT(1)" + case ECT0: + return "ECT(0)" + case ECNCE: + return "CE" + default: + return fmt.Sprintf("invalid ECN value: %d", e) + } +} + // A ByteCount in QUIC type ByteCount int64 diff --git a/internal/protocol/protocol_test.go b/internal/protocol/protocol_test.go index d9048f01..e672d31e 100644 --- a/internal/protocol/protocol_test.go +++ b/internal/protocol/protocol_test.go @@ -22,4 +22,12 @@ var _ = Describe("Protocol", func() { Expect(ECN(0b00000001)).To(Equal(ECT1)) Expect(ECN(0b00000011)).To(Equal(ECNCE)) }) + + It("has a string representation for ECN", func() { + Expect(ECNNon.String()).To(Equal("Not-ECT")) + Expect(ECT0.String()).To(Equal("ECT(0)")) + Expect(ECT1.String()).To(Equal("ECT(1)")) + Expect(ECNCE.String()).To(Equal("CE")) + Expect(ECN(42).String()).To(Equal("invalid ECN value: 42")) + }) }) From 6880f88089d442d6eb739bcbb84875588896dc82 Mon Sep 17 00:00:00 2001 From: Ameagari <47713057+tanghaowillow@users.noreply.github.com> Date: Sat, 19 Aug 2023 10:16:16 +0800 Subject: [PATCH 25/36] save the max_datagram_frame_size transport parameter in the session ticket (#4013) * Add MaxDatagramFrameSize parameter in session ticket * fix gofumpt issues * Update integrationtests/self/zero_rtt_test.go Co-authored-by: Marten Seemann * fix: correct comparsion of max_datagram_frame_size * test: use constant MaxDatagramFrameSize for session ticket test * fix grammar --------- Co-authored-by: Marten Seemann --- integrationtests/self/zero_rtt_oldgo_test.go | 112 ++++++++++++++++++ integrationtests/self/zero_rtt_test.go | 115 +++++++++++++++++++ internal/handshake/session_ticket_test.go | 2 + internal/wire/transport_parameter_test.go | 24 ++++ internal/wire/transport_parameters.go | 10 ++ 5 files changed, 263 insertions(+) diff --git a/integrationtests/self/zero_rtt_oldgo_test.go b/integrationtests/self/zero_rtt_oldgo_test.go index beaf351e..e5809286 100644 --- a/integrationtests/self/zero_rtt_oldgo_test.go +++ b/integrationtests/self/zero_rtt_oldgo_test.go @@ -801,4 +801,116 @@ var _ = Describe("0-RTT", func() { Expect(len(zeroRTTPackets)).To(BeNumerically(">", 10)) Expect(zeroRTTPackets[0]).To(Equal(protocol.PacketNumber(0))) }) + + It("sends 0-RTT datagrams", func() { + tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ + EnableDatagrams: true, + })) + + tracer := newPacketTracer() + ln, err := quic.ListenAddrEarly( + "localhost:0", + tlsConf, + getQuicConfig(&quic.Config{ + Allow0RTT: true, + EnableDatagrams: true, + Tracer: newTracer(tracer), + }), + ) + Expect(err).ToNot(HaveOccurred()) + defer ln.Close() + + proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) + defer proxy.Close() + + // second connection + sentMessage := GeneratePRData(100) + var receivedMessage []byte + received := make(chan struct{}) + go func() { + defer GinkgoRecover() + defer close(received) + conn, err := ln.Accept(context.Background()) + Expect(err).ToNot(HaveOccurred()) + receivedMessage, err = conn.ReceiveMessage(context.Background()) + Expect(err).ToNot(HaveOccurred()) + Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) + }() + conn, err := quic.DialAddrEarly( + context.Background(), + fmt.Sprintf("localhost:%d", proxy.LocalPort()), + clientTLSConf, + getQuicConfig(&quic.Config{ + EnableDatagrams: true, + }), + ) + Expect(err).ToNot(HaveOccurred()) + Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue()) + Expect(conn.SendMessage(sentMessage)).To(Succeed()) + <-conn.HandshakeComplete() + <-received + + Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) + Expect(receivedMessage).To(Equal(sentMessage)) + num0RTT := atomic.LoadUint32(num0RTTPackets) + fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) + Expect(num0RTT).ToNot(BeZero()) + zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets()) + Expect(zeroRTTPackets).To(HaveLen(1)) + Expect(conn.CloseWithError(0, "")).To(Succeed()) + }) + + It("rejects 0-RTT datagrams when the server doesn't support datagrams anymore", func() { + tlsConf, clientTLSConf := dialAndReceiveSessionTicket(getQuicConfig(&quic.Config{ + EnableDatagrams: true, + })) + + tracer := newPacketTracer() + ln, err := quic.ListenAddrEarly( + "localhost:0", + tlsConf, + getQuicConfig(&quic.Config{ + Allow0RTT: true, + EnableDatagrams: false, + Tracer: newTracer(tracer), + }), + ) + Expect(err).ToNot(HaveOccurred()) + defer ln.Close() + + proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) + defer proxy.Close() + + // second connection + go func() { + defer GinkgoRecover() + conn, err := ln.Accept(context.Background()) + Expect(err).ToNot(HaveOccurred()) + _, err = conn.ReceiveMessage(context.Background()) + Expect(err.Error()).To(Equal("datagram support disabled")) + <-conn.HandshakeComplete() + Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) + }() + conn, err := quic.DialAddrEarly( + context.Background(), + fmt.Sprintf("localhost:%d", proxy.LocalPort()), + clientTLSConf, + getQuicConfig(&quic.Config{ + EnableDatagrams: true, + }), + ) + Expect(err).ToNot(HaveOccurred()) + // the client can temporarily send datagrams but the server doesn't process them. + Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue()) + Expect(conn.SendMessage(make([]byte, 100))).To(Succeed()) + <-conn.HandshakeComplete() + + Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse()) + Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) + num0RTT := atomic.LoadUint32(num0RTTPackets) + fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) + Expect(num0RTT).ToNot(BeZero()) + Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty()) + Expect(conn.CloseWithError(0, "")).To(Succeed()) + }) }) diff --git a/integrationtests/self/zero_rtt_test.go b/integrationtests/self/zero_rtt_test.go index 2de283ac..011687ae 100644 --- a/integrationtests/self/zero_rtt_test.go +++ b/integrationtests/self/zero_rtt_test.go @@ -938,4 +938,119 @@ var _ = Describe("0-RTT", func() { ) Expect(restored).To(BeTrue()) }) + + It("sends 0-RTT datagrams", func() { + tlsConf := getTLSConfig() + clientTLSConf := getTLSClientConfig() + dialAndReceiveSessionTicket(tlsConf, getQuicConfig(&quic.Config{ + EnableDatagrams: true, + }), clientTLSConf) + + tracer := newPacketTracer() + ln, err := quic.ListenAddrEarly( + "localhost:0", + tlsConf, + getQuicConfig(&quic.Config{ + Allow0RTT: true, + EnableDatagrams: true, + Tracer: newTracer(tracer), + }), + ) + Expect(err).ToNot(HaveOccurred()) + defer ln.Close() + proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) + defer proxy.Close() + + // second connection + sentMessage := GeneratePRData(100) + var receivedMessage []byte + received := make(chan struct{}) + go func() { + defer GinkgoRecover() + defer close(received) + conn, err := ln.Accept(context.Background()) + Expect(err).ToNot(HaveOccurred()) + receivedMessage, err = conn.ReceiveMessage(context.Background()) + Expect(err).ToNot(HaveOccurred()) + Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) + }() + conn, err := quic.DialAddrEarly( + context.Background(), + fmt.Sprintf("localhost:%d", proxy.LocalPort()), + clientTLSConf, + getQuicConfig(&quic.Config{ + EnableDatagrams: true, + }), + ) + Expect(err).ToNot(HaveOccurred()) + Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue()) + Expect(conn.SendMessage(sentMessage)).To(Succeed()) + <-conn.HandshakeComplete() + <-received + + Expect(conn.ConnectionState().Used0RTT).To(BeTrue()) + Expect(receivedMessage).To(Equal(sentMessage)) + num0RTT := atomic.LoadUint32(num0RTTPackets) + fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) + Expect(num0RTT).ToNot(BeZero()) + zeroRTTPackets := get0RTTPackets(tracer.getRcvdLongHeaderPackets()) + Expect(zeroRTTPackets).To(HaveLen(1)) + Expect(conn.CloseWithError(0, "")).To(Succeed()) + }) + + It("rejects 0-RTT datagrams when the server doesn't support datagrams anymore", func() { + tlsConf := getTLSConfig() + clientTLSConf := getTLSClientConfig() + dialAndReceiveSessionTicket(tlsConf, getQuicConfig(&quic.Config{ + EnableDatagrams: true, + }), clientTLSConf) + + tracer := newPacketTracer() + ln, err := quic.ListenAddrEarly( + "localhost:0", + tlsConf, + getQuicConfig(&quic.Config{ + Allow0RTT: true, + EnableDatagrams: false, + Tracer: newTracer(tracer), + }), + ) + Expect(err).ToNot(HaveOccurred()) + defer ln.Close() + + proxy, num0RTTPackets := runCountingProxy(ln.Addr().(*net.UDPAddr).Port) + defer proxy.Close() + + // second connection + go func() { + defer GinkgoRecover() + conn, err := ln.Accept(context.Background()) + Expect(err).ToNot(HaveOccurred()) + _, err = conn.ReceiveMessage(context.Background()) + Expect(err.Error()).To(Equal("datagram support disabled")) + <-conn.HandshakeComplete() + Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) + }() + conn, err := quic.DialAddrEarly( + context.Background(), + fmt.Sprintf("localhost:%d", proxy.LocalPort()), + clientTLSConf, + getQuicConfig(&quic.Config{ + EnableDatagrams: true, + }), + ) + Expect(err).ToNot(HaveOccurred()) + // the client can temporarily send datagrams but the server doesn't process them. + Expect(conn.ConnectionState().SupportsDatagrams).To(BeTrue()) + Expect(conn.SendMessage(make([]byte, 100))).To(Succeed()) + <-conn.HandshakeComplete() + + Expect(conn.ConnectionState().SupportsDatagrams).To(BeFalse()) + Expect(conn.ConnectionState().Used0RTT).To(BeFalse()) + num0RTT := atomic.LoadUint32(num0RTTPackets) + fmt.Fprintf(GinkgoWriter, "Sent %d 0-RTT packets.", num0RTT) + Expect(num0RTT).ToNot(BeZero()) + Expect(get0RTTPackets(tracer.getRcvdLongHeaderPackets())).To(BeEmpty()) + Expect(conn.CloseWithError(0, "")).To(Succeed()) + }) }) diff --git a/internal/handshake/session_ticket_test.go b/internal/handshake/session_ticket_test.go index 67e33b22..6f004de9 100644 --- a/internal/handshake/session_ticket_test.go +++ b/internal/handshake/session_ticket_test.go @@ -17,6 +17,7 @@ var _ = Describe("Session Ticket", func() { InitialMaxStreamDataBidiLocal: 1, InitialMaxStreamDataBidiRemote: 2, ActiveConnectionIDLimit: 10, + MaxDatagramFrameSize: 20, }, RTT: 1337 * time.Microsecond, } @@ -25,6 +26,7 @@ var _ = Describe("Session Ticket", func() { Expect(t.Parameters.InitialMaxStreamDataBidiLocal).To(BeEquivalentTo(1)) Expect(t.Parameters.InitialMaxStreamDataBidiRemote).To(BeEquivalentTo(2)) Expect(t.Parameters.ActiveConnectionIDLimit).To(BeEquivalentTo(10)) + Expect(t.Parameters.MaxDatagramFrameSize).To(BeEquivalentTo(20)) Expect(t.RTT).To(Equal(1337 * time.Microsecond)) }) diff --git a/internal/wire/transport_parameter_test.go b/internal/wire/transport_parameter_test.go index 9dd306b7..2fb79539 100644 --- a/internal/wire/transport_parameter_test.go +++ b/internal/wire/transport_parameter_test.go @@ -503,6 +503,7 @@ var _ = Describe("Transport Parameters", func() { MaxBidiStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), MaxUniStreamNum: protocol.StreamNum(getRandomValueUpTo(int64(protocol.MaxStreamCount))), ActiveConnectionIDLimit: 2 + getRandomValueUpTo(math.MaxInt64-2), + MaxDatagramFrameSize: protocol.ByteCount(getRandomValueUpTo(int64(protocol.MaxDatagramFrameSize))), } Expect(params.ValidFor0RTT(params)).To(BeTrue()) b := params.MarshalForSessionTicket(nil) @@ -515,6 +516,7 @@ var _ = Describe("Transport Parameters", func() { Expect(tp.MaxBidiStreamNum).To(Equal(params.MaxBidiStreamNum)) Expect(tp.MaxUniStreamNum).To(Equal(params.MaxUniStreamNum)) Expect(tp.ActiveConnectionIDLimit).To(Equal(params.ActiveConnectionIDLimit)) + Expect(tp.MaxDatagramFrameSize).To(Equal(params.MaxDatagramFrameSize)) }) It("rejects the parameters if it can't parse them", func() { @@ -540,6 +542,7 @@ var _ = Describe("Transport Parameters", func() { MaxBidiStreamNum: 5, MaxUniStreamNum: 6, ActiveConnectionIDLimit: 7, + MaxDatagramFrameSize: 1000, } BeforeEach(func() { @@ -611,6 +614,16 @@ var _ = Describe("Transport Parameters", func() { p.ActiveConnectionIDLimit = 0 Expect(p.ValidFor0RTT(saved)).To(BeFalse()) }) + + It("accepts the parameters if the MaxDatagramFrameSize was increased", func() { + p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1 + Expect(p.ValidFor0RTT(saved)).To(BeTrue()) + }) + + It("rejects the parameters if the MaxDatagramFrameSize reduced", func() { + p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1 + Expect(p.ValidFor0RTT(saved)).To(BeFalse()) + }) }) Context("client checks the parameters after successfully sending 0-RTT data", func() { @@ -623,6 +636,7 @@ var _ = Describe("Transport Parameters", func() { MaxBidiStreamNum: 5, MaxUniStreamNum: 6, ActiveConnectionIDLimit: 7, + MaxDatagramFrameSize: 1000, } BeforeEach(func() { @@ -699,6 +713,16 @@ var _ = Describe("Transport Parameters", func() { p.ActiveConnectionIDLimit = saved.ActiveConnectionIDLimit + 1 Expect(p.ValidForUpdate(saved)).To(BeTrue()) }) + + It("rejects the parameters if the MaxDatagramFrameSize reduced", func() { + p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize - 1 + Expect(p.ValidForUpdate(saved)).To(BeFalse()) + }) + + It("doesn't reject the parameters if the MaxDatagramFrameSize increased", func() { + p.MaxDatagramFrameSize = saved.MaxDatagramFrameSize + 1 + Expect(p.ValidForUpdate(saved)).To(BeTrue()) + }) }) }) }) diff --git a/internal/wire/transport_parameters.go b/internal/wire/transport_parameters.go index dc0aa22f..7226521b 100644 --- a/internal/wire/transport_parameters.go +++ b/internal/wire/transport_parameters.go @@ -454,6 +454,10 @@ func (p *TransportParameters) MarshalForSessionTicket(b []byte) []byte { b = p.marshalVarintParam(b, initialMaxStreamsBidiParameterID, uint64(p.MaxBidiStreamNum)) // initial_max_uni_streams b = p.marshalVarintParam(b, initialMaxStreamsUniParameterID, uint64(p.MaxUniStreamNum)) + // max_datagram_frame_size + if p.MaxDatagramFrameSize != protocol.InvalidByteCount { + b = p.marshalVarintParam(b, maxDatagramFrameSizeParameterID, uint64(p.MaxDatagramFrameSize)) + } // active_connection_id_limit return p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit) } @@ -472,6 +476,9 @@ func (p *TransportParameters) UnmarshalFromSessionTicket(r *bytes.Reader) error // ValidFor0RTT checks if the transport parameters match those saved in the session ticket. func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool { + if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) { + return false + } return p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal && p.InitialMaxStreamDataBidiRemote >= saved.InitialMaxStreamDataBidiRemote && p.InitialMaxStreamDataUni >= saved.InitialMaxStreamDataUni && @@ -484,6 +491,9 @@ func (p *TransportParameters) ValidFor0RTT(saved *TransportParameters) bool { // ValidForUpdate checks that the new transport parameters don't reduce limits after resuming a 0-RTT connection. // It is only used on the client side. func (p *TransportParameters) ValidForUpdate(saved *TransportParameters) bool { + if saved.MaxDatagramFrameSize != protocol.InvalidByteCount && (p.MaxDatagramFrameSize == protocol.InvalidByteCount || p.MaxDatagramFrameSize < saved.MaxDatagramFrameSize) { + return false + } return p.ActiveConnectionIDLimit >= saved.ActiveConnectionIDLimit && p.InitialMaxData >= saved.InitialMaxData && p.InitialMaxStreamDataBidiLocal >= saved.InitialMaxStreamDataBidiLocal && From fe3c4f271df1a713a2e98bff2c35f0804b63e801 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 19 Aug 2023 15:19:17 +0700 Subject: [PATCH 26/36] add a method to retrieve non-QUIC packets from the Transport (#3992) --- integrationtests/self/multiplex_test.go | 65 +++++++++++++++++++++ internal/wire/header.go | 4 ++ transport.go | 53 ++++++++++++++++- transport_test.go | 77 ++++++++++++++++++++++++- 4 files changed, 195 insertions(+), 4 deletions(-) diff --git a/integrationtests/self/multiplex_test.go b/integrationtests/self/multiplex_test.go index 9b00bc34..72c858a1 100644 --- a/integrationtests/self/multiplex_test.go +++ b/integrationtests/self/multiplex_test.go @@ -2,9 +2,11 @@ package self_test import ( "context" + "crypto/rand" "io" "net" "runtime" + "sync/atomic" "time" "github.com/quic-go/quic-go" @@ -210,4 +212,67 @@ var _ = Describe("Multiplexing", func() { }) } }) + + It("sends and receives non-QUIC packets", func() { + addr1, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn1, err := net.ListenUDP("udp", addr1) + Expect(err).ToNot(HaveOccurred()) + defer conn1.Close() + tr1 := &quic.Transport{Conn: conn1} + + addr2, err := net.ResolveUDPAddr("udp", "localhost:0") + Expect(err).ToNot(HaveOccurred()) + conn2, err := net.ListenUDP("udp", addr2) + Expect(err).ToNot(HaveOccurred()) + defer conn2.Close() + tr2 := &quic.Transport{Conn: conn2} + + server, err := tr1.Listen(getTLSConfig(), getQuicConfig(nil)) + Expect(err).ToNot(HaveOccurred()) + runServer(server) + defer server.Close() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + var sentPackets, rcvdPackets atomic.Int64 + const packetLen = 128 + // send a non-QUIC packet every 100µs + go func() { + defer GinkgoRecover() + ticker := time.NewTicker(time.Millisecond / 10) + defer ticker.Stop() + for { + select { + case <-ticker.C: + case <-ctx.Done(): + return + } + b := make([]byte, packetLen) + rand.Read(b[1:]) // keep the first byte set to 0, so it's not classified as a QUIC packet + _, err := tr1.WriteTo(b, tr2.Conn.LocalAddr()) + Expect(err).ToNot(HaveOccurred()) + sentPackets.Add(1) + } + }() + + // receive and count non-QUIC packets + go func() { + defer GinkgoRecover() + for { + b := make([]byte, 1024) + n, addr, err := tr2.ReadNonQUICPacket(ctx, b) + if err != nil { + Expect(err).To(MatchError(context.Canceled)) + return + } + Expect(addr).To(Equal(tr1.Conn.LocalAddr())) + Expect(n).To(Equal(packetLen)) + rcvdPackets.Add(1) + } + }() + dial(tr2, server.Addr()) + Eventually(func() int64 { return sentPackets.Load() }).Should(BeNumerically(">", 10)) + Eventually(func() int64 { return rcvdPackets.Load() }).Should(BeNumerically(">=", sentPackets.Load()*4/5)) + }) }) diff --git a/internal/wire/header.go b/internal/wire/header.go index e2dc72e4..0c60f4dd 100644 --- a/internal/wire/header.go +++ b/internal/wire/header.go @@ -74,6 +74,10 @@ func parseArbitraryLenConnectionIDs(r *bytes.Reader) (dest, src protocol.Arbitra return destConnID, srcConnID, nil } +func IsPotentialQUICPacket(firstByte byte) bool { + return firstByte&0x40 > 0 +} + // IsLongHeaderPacket says if this is a Long Header packet func IsLongHeaderPacket(firstByte byte) bool { return firstByte&0x80 > 0 diff --git a/transport.go b/transport.go index ae44e3da..fe6dc1fc 100644 --- a/transport.go +++ b/transport.go @@ -7,12 +7,12 @@ import ( "errors" "net" "sync" + "sync/atomic" "time" - "github.com/quic-go/quic-go/internal/wire" - "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/utils" + "github.com/quic-go/quic-go/internal/wire" "github.com/quic-go/quic-go/logging" ) @@ -85,6 +85,9 @@ type Transport struct { createdConn bool isSingleUse bool // was created for a single server or client, i.e. by calling quic.Listen or quic.Dial + readingNonQUICPackets atomic.Bool + nonQUICPackets chan receivedPacket + logger utils.Logger } @@ -341,6 +344,13 @@ func (t *Transport) listen(conn rawConn) { } func (t *Transport) handlePacket(p receivedPacket) { + if len(p.data) == 0 { + return + } + if !wire.IsPotentialQUICPacket(p.data[0]) && !wire.IsLongHeaderPacket(p.data[0]) { + t.handleNonQUICPacket(p) + return + } connID, err := wire.ParseConnectionID(p.data, t.connIDLen) if err != nil { t.logger.Debugf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err) @@ -429,3 +439,42 @@ func (t *Transport) maybeHandleStatelessReset(data []byte) bool { } return false } + +func (t *Transport) handleNonQUICPacket(p receivedPacket) { + // Strictly speaking, this is racy, + // but we only care about receiving packets at some point after ReadNonQUICPacket has been called. + if !t.readingNonQUICPackets.Load() { + return + } + select { + case t.nonQUICPackets <- p: + default: + if t.Tracer != nil { + t.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropDOSPrevention) + } + } +} + +const maxQueuedNonQUICPackets = 32 + +// ReadNonQUICPacket reads non-QUIC packets received on the underlying connection. +// The detection logic is very simple: Any packet that has the first and second bit of the packet set to 0. +// Note that this is stricter than the detection logic defined in RFC 9443. +func (t *Transport) ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.Addr, error) { + if err := t.init(false); err != nil { + return 0, nil, err + } + if !t.readingNonQUICPackets.Load() { + t.nonQUICPackets = make(chan receivedPacket, maxQueuedNonQUICPackets) + t.readingNonQUICPackets.Store(true) + } + select { + case <-ctx.Done(): + return 0, nil, ctx.Err() + case p := <-t.nonQUICPackets: + n := copy(b, p.data) + return n, p.remoteAddr, nil + case <-t.listening: + return 0, nil, errors.New("closed") + } +} diff --git a/transport_test.go b/transport_test.go index f46affb3..93e1d32a 100644 --- a/transport_test.go +++ b/transport_test.go @@ -2,6 +2,7 @@ package quic import ( "bytes" + "context" "crypto/rand" "crypto/tls" "errors" @@ -122,7 +123,7 @@ var _ = Describe("Transport", func() { tr.Close() }) - It("drops unparseable packets", func() { + It("drops unparseable QUIC packets", func() { addr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} packetChan := make(chan packetToRead) tracer := mocklogging.NewMockTracer(mockCtrl) @@ -136,7 +137,7 @@ var _ = Describe("Transport", func() { tracer.EXPECT().DroppedPacket(addr, logging.PacketTypeNotDetermined, protocol.ByteCount(4), logging.PacketDropHeaderParseError).Do(func(net.Addr, logging.PacketType, protocol.ByteCount, logging.PacketDropReason) { close(dropped) }) packetChan <- packetToRead{ addr: addr, - data: []byte{0, 1, 2, 3}, + data: []byte{0x40 /* set the QUIC bit */, 1, 2, 3}, } Eventually(dropped).Should(BeClosed()) @@ -323,6 +324,78 @@ var _ = Describe("Transport", func() { conns := getMultiplexer().(*connMultiplexer).conns Expect(len(conns)).To(BeZero()) }) + + It("allows receiving non-QUIC packets", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} + packetChan := make(chan packetToRead) + tracer := mocklogging.NewMockTracer(mockCtrl) + tr := &Transport{ + Conn: newMockPacketConn(packetChan), + ConnectionIDLength: 10, + Tracer: tracer, + } + tr.init(true) + receivedPacketChan := make(chan []byte) + go func() { + defer GinkgoRecover() + b := make([]byte, 100) + n, addr, err := tr.ReadNonQUICPacket(context.Background(), b) + Expect(err).ToNot(HaveOccurred()) + Expect(addr).To(Equal(remoteAddr)) + receivedPacketChan <- b[:n] + }() + // Receiving of non-QUIC packets is enabled when ReadNonQUICPacket is called. + // Give the Go routine some time to spin up. + time.Sleep(scaleDuration(50 * time.Millisecond)) + packetChan <- packetToRead{ + addr: remoteAddr, + data: []byte{0 /* don't set the QUIC bit */, 1, 2, 3}, + } + + Eventually(receivedPacketChan).Should(Receive(Equal([]byte{0, 1, 2, 3}))) + + // shutdown + close(packetChan) + tr.Close() + }) + + It("drops non-QUIC packet if the application doesn't process them quickly enough", func() { + remoteAddr := &net.UDPAddr{IP: net.IPv4(9, 8, 7, 6), Port: 1234} + packetChan := make(chan packetToRead) + tracer := mocklogging.NewMockTracer(mockCtrl) + tr := &Transport{ + Conn: newMockPacketConn(packetChan), + ConnectionIDLength: 10, + Tracer: tracer, + } + tr.init(true) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + _, _, err := tr.ReadNonQUICPacket(ctx, make([]byte, 10)) + Expect(err).To(MatchError(context.Canceled)) + + for i := 0; i < maxQueuedNonQUICPackets; i++ { + packetChan <- packetToRead{ + addr: remoteAddr, + data: []byte{0 /* don't set the QUIC bit */, 1, 2, 3}, + } + } + + done := make(chan struct{}) + tracer.EXPECT().DroppedPacket(remoteAddr, logging.PacketTypeNotDetermined, protocol.ByteCount(4), logging.PacketDropDOSPrevention).Do(func(net.Addr, logging.PacketType, protocol.ByteCount, logging.PacketDropReason) { + close(done) + }) + packetChan <- packetToRead{ + addr: remoteAddr, + data: []byte{0 /* don't set the QUIC bit */, 1, 2, 3}, + } + Eventually(done).Should(BeClosed()) + + // shutdown + close(packetChan) + tr.Close() + }) }) type mockSyscallConn struct { From f689a5d023ba58cf0acea9bbacc2a94b6bee9549 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 21 Aug 2023 09:48:03 +0700 Subject: [PATCH 27/36] ci: build interop Docker image for pushes to master, and for releases (#4035) * ci: build interop Docker image for pushes to master, and tag releases * use self-hosted runner to build Docker image * Apply suggestions from code review Co-authored-by: Piotr Galar * Update .github/workflows/build-interop-docker.yml Co-authored-by: Piotr Galar * build the correct commit * Update .github/workflows/build-interop-docker.yml --------- Co-authored-by: Piotr Galar --- .github/workflows/build-interop-docker.yml | 23 +++++++++++++++++++--- interop/Dockerfile | 13 ++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-interop-docker.yml b/.github/workflows/build-interop-docker.yml index e16663c7..bef6f205 100644 --- a/.github/workflows/build-interop-docker.yml +++ b/.github/workflows/build-interop-docker.yml @@ -1,11 +1,14 @@ name: Build interop Docker image on: push: - branches: [ interop ] + branches: + - master + tags: + - 'v*' jobs: interop: - runs-on: ubuntu-latest + runs-on: ${{ fromJSON(vars['DOCKER_RUNNER_UBUNTU'] || '"ubuntu-latest"') }} steps: - uses: actions/checkout@v3 - name: Set up QEMU @@ -19,9 +22,23 @@ jobs: with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} + - name: set tag name + id: tag + # Tagged releases won't be picked up by the interop runner automatically, + # but they can be useful when debugging regressions. + run: | + if [[ $GITHUB_REF == refs/tags/* ]]; then + echo "tag=${GITHUB_REF#refs/tags/}" | tee -a $GITHUB_OUTPUT; + echo "gitref=${GITHUB_REF#refs/tags/}" | tee -a $GITHUB_OUTPUT; + else + echo 'tag=latest' | tee -a $GITHUB_OUTPUT; + echo 'gitref=${{ github.sha }}' | tee -a $GITHUB_OUTPUT; + fi - uses: docker/build-push-action@v4 with: context: "{{defaultContext}}:interop" platforms: linux/amd64,linux/arm64 push: true - tags: martenseemann/quic-go-interop:latest + build-args: | + GITREF=${{ steps.tag.outputs.gitref }} + tags: martenseemann/quic-go-interop:${{ steps.tag.outputs.tag }} diff --git a/interop/Dockerfile b/interop/Dockerfile index 48d4f096..afff1276 100644 --- a/interop/Dockerfile +++ b/interop/Dockerfile @@ -5,7 +5,7 @@ RUN echo "TARGETPLATFORM: ${TARGETPLATFORM}" RUN apt-get update && apt-get install -y wget tar git -ENV GOVERSION=1.20.2 +ENV GOVERSION=1.20.7 RUN platform=$(echo ${TARGETPLATFORM} | tr '/' '-') && \ filename="go${GOVERSION}.${platform}.tar.gz" && \ @@ -18,14 +18,15 @@ ENV PATH="/go/bin:${PATH}" # build with --build-arg CACHEBUST=$(date +%s) ARG CACHEBUST=1 -RUN git clone https://github.com/quic-go/quic-go && \ - cd quic-go && \ - git fetch origin interop && git checkout -t origin/interop && \ - go get ./... +# build other branches / commits / tags using --build-arg GITREF="" +ARG GITREF="master" +RUN git clone https://github.com/quic-go/quic-go WORKDIR /quic-go +RUN git checkout ${GITREF} +RUN go get ./... -RUN git rev-parse HEAD > commit.txt +RUN git rev-parse HEAD | tee commit.txt RUN go build -o server -ldflags="-X github.com/quic-go/quic-go/qlog.quicGoVersion=$(git describe --always --long --dirty)" interop/server/main.go RUN go build -o client -ldflags="-X github.com/quic-go/quic-go/qlog.quicGoVersion=$(git describe --always --long --dirty)" interop/client/main.go From ced65c0ddcf5b24b0e1f04b07bb18e968a77b05a Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 21 Aug 2023 09:55:57 +0700 Subject: [PATCH 28/36] wire: always set the QUIC bit for Version Negotiation packets (#3991) * wire: always set the QUIC bit for Version Negotiation packets * Update internal/wire/version_negotiation_test.go --- internal/wire/version_negotiation.go | 5 ++++- internal/wire/version_negotiation_test.go | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/wire/version_negotiation.go b/internal/wire/version_negotiation.go index 3dc62113..afde70fa 100644 --- a/internal/wire/version_negotiation.go +++ b/internal/wire/version_negotiation.go @@ -40,7 +40,10 @@ func ComposeVersionNegotiation(destConnID, srcConnID protocol.ArbitraryLenConnec buf := bytes.NewBuffer(make([]byte, 0, expectedLen)) r := make([]byte, 1) _, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here. - buf.WriteByte(r[0] | 0x80) + // Setting the "QUIC bit" (0x40) is not required by the RFC, + // but it allows clients to demultiplex QUIC with a long list of other protocols. + // See RFC 9443 and https://mailarchive.ietf.org/arch/msg/quic/oR4kxGKY6mjtPC1CZegY1ED4beg/ for details. + buf.WriteByte(r[0] | 0xc0) utils.BigEndian.WriteUint32(buf, 0) // version 0 buf.WriteByte(uint8(destConnID.Len())) buf.Write(destConnID.Bytes()) diff --git a/internal/wire/version_negotiation_test.go b/internal/wire/version_negotiation_test.go index 65d0ba91..acd6d7ce 100644 --- a/internal/wire/version_negotiation_test.go +++ b/internal/wire/version_negotiation_test.go @@ -64,6 +64,7 @@ var _ = Describe("Version Negotiation Packets", func() { versions := []protocol.VersionNumber{1001, 1003} data := ComposeVersionNegotiation(destConnID, srcConnID, versions) Expect(IsLongHeaderPacket(data[0])).To(BeTrue()) + Expect(data[0] & 0x40).ToNot(BeZero()) v, err := ParseVersion(data) Expect(err).ToNot(HaveOccurred()) Expect(v).To(BeZero()) From 824fd8a2f2eb8a08fe6cef7a693fee6be3819e01 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Mon, 21 Aug 2023 11:31:22 +0800 Subject: [PATCH 29/36] http3: automatically add content-length for small responses (#3989) * response writer: add content-length automatically when response is small enough and doesn't call Flush * fix comment * add integration test * Update http3/response_writer.go * Update integrationtests/self/http_test.go --------- Co-authored-by: Marten Seemann --- http3/response_writer.go | 97 ++++++++++++++++++++---------- http3/server.go | 8 ++- http3/server_test.go | 41 +++++++++++++ integrationtests/self/http_test.go | 12 ++++ 4 files changed, 126 insertions(+), 32 deletions(-) diff --git a/http3/response_writer.go b/http3/response_writer.go index 3d927185..90a30497 100644 --- a/http3/response_writer.go +++ b/http3/response_writer.go @@ -15,19 +15,61 @@ import ( "github.com/quic-go/qpack" ) +// The maximum length of an encoded HTTP/3 frame header is 16: +// The frame has a type and length field, both QUIC varints (maximum 8 bytes in length) +const frameHeaderLen = 16 + +// headerWriter wraps the stream, so that the first Write call flushes the header to the stream +type headerWriter struct { + str quic.Stream + header http.Header + status int // status code passed to WriteHeader + written bool + + logger utils.Logger +} + +// writeHeader encodes and flush header to the stream +func (hw *headerWriter) writeHeader() error { + var headers bytes.Buffer + enc := qpack.NewEncoder(&headers) + enc.WriteField(qpack.HeaderField{Name: ":status", Value: strconv.Itoa(hw.status)}) + + for k, v := range hw.header { + for index := range v { + enc.WriteField(qpack.HeaderField{Name: strings.ToLower(k), Value: v[index]}) + } + } + + buf := make([]byte, 0, frameHeaderLen+headers.Len()) + buf = (&headersFrame{Length: uint64(headers.Len())}).Append(buf) + hw.logger.Infof("Responding with %d", hw.status) + buf = append(buf, headers.Bytes()...) + + _, err := hw.str.Write(buf) + return err +} + +// first Write will trigger flushing header +func (hw *headerWriter) Write(p []byte) (int, error) { + if !hw.written { + if err := hw.writeHeader(); err != nil { + return 0, err + } + hw.written = true + } + return hw.str.Write(p) +} + type responseWriter struct { + *headerWriter conn quic.Connection - str quic.Stream bufferedStr *bufio.Writer buf []byte - header http.Header - status int // status code passed to WriteHeader headerWritten bool contentLen int64 // if handler set valid Content-Length header numWritten int64 // bytes written - - logger utils.Logger } var ( @@ -37,13 +79,16 @@ var ( ) func newResponseWriter(str quic.Stream, conn quic.Connection, logger utils.Logger) *responseWriter { + hw := &headerWriter{ + str: str, + header: http.Header{}, + logger: logger, + } return &responseWriter{ - header: http.Header{}, - buf: make([]byte, 16), - conn: conn, - str: str, - bufferedStr: bufio.NewWriter(str), - logger: logger, + headerWriter: hw, + buf: make([]byte, frameHeaderLen), + conn: conn, + bufferedStr: bufio.NewWriter(hw), } } @@ -83,27 +128,8 @@ func (w *responseWriter) WriteHeader(status int) { } w.status = status - var headers bytes.Buffer - enc := qpack.NewEncoder(&headers) - enc.WriteField(qpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)}) - - for k, v := range w.header { - for index := range v { - enc.WriteField(qpack.HeaderField{Name: strings.ToLower(k), Value: v[index]}) - } - } - - w.buf = w.buf[:0] - w.buf = (&headersFrame{Length: uint64(headers.Len())}).Append(w.buf) - w.logger.Infof("Responding with %d", status) - if _, err := w.bufferedStr.Write(w.buf); err != nil { - w.logger.Errorf("could not write headers frame: %s", err.Error()) - } - if _, err := w.bufferedStr.Write(headers.Bytes()); err != nil { - w.logger.Errorf("could not write header frame payload: %s", err.Error()) - } if !w.headerWritten { - w.Flush() + w.writeHeader() } } @@ -146,6 +172,15 @@ func (w *responseWriter) Write(p []byte) (int, error) { } func (w *responseWriter) FlushError() error { + if !w.headerWritten { + w.WriteHeader(http.StatusOK) + } + if !w.written { + if err := w.writeHeader(); err != nil { + return err + } + w.written = true + } return w.bufferedStr.Flush() } diff --git a/http3/server.go b/http3/server.go index 8d39f374..4587a1fc 100644 --- a/http3/server.go +++ b/http3/server.go @@ -9,6 +9,7 @@ import ( "net" "net/http" "runtime" + "strconv" "strings" "sync" "time" @@ -627,7 +628,12 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q // only write response when there is no panic if !panicked { - r.WriteHeader(http.StatusOK) + // response not written to the client yet, set Content-Length + if !r.written { + if _, haveCL := r.header["Content-Length"]; !haveCL { + r.header.Set("Content-Length", strconv.FormatInt(r.numWritten, 10)) + } + } r.Flush() } // If the EOF was read by the handler, CancelRead() is a no-op. diff --git a/http3/server_test.go b/http3/server_test.go index f180ef0d..67713b92 100644 --- a/http3/server_test.go +++ b/http3/server_test.go @@ -180,6 +180,47 @@ var _ = Describe("Server", func() { Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"})) }) + It("sets Content-Length when the handler doesn't flush to the client", func() { + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("foobar")) + }) + + responseBuf := &bytes.Buffer{} + setRequest(encodeRequest(exampleGetRequest)) + str.EXPECT().Context().Return(reqContext) + str.EXPECT().Write(gomock.Any()).DoAndReturn(responseBuf.Write).AnyTimes() + str.EXPECT().CancelRead(gomock.Any()) + + serr := s.handleRequest(conn, str, qpackDecoder, nil) + Expect(serr.err).ToNot(HaveOccurred()) + hfs := decodeHeader(responseBuf) + Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"})) + Expect(hfs).To(HaveKeyWithValue("content-length", []string{"6"})) + // status, content-length, date, content-type + Expect(hfs).To(HaveLen(4)) + }) + + It("not sets Content-Length when the handler flushes to the client", func() { + s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("foobar")) + // force flush + w.(http.Flusher).Flush() + }) + + responseBuf := &bytes.Buffer{} + setRequest(encodeRequest(exampleGetRequest)) + str.EXPECT().Context().Return(reqContext) + str.EXPECT().Write(gomock.Any()).DoAndReturn(responseBuf.Write).AnyTimes() + str.EXPECT().CancelRead(gomock.Any()) + + serr := s.handleRequest(conn, str, qpackDecoder, nil) + Expect(serr.err).ToNot(HaveOccurred()) + hfs := decodeHeader(responseBuf) + Expect(hfs).To(HaveKeyWithValue(":status", []string{"200"})) + // status, date, content-type + Expect(hfs).To(HaveLen(3)) + }) + It("handles a aborting handler", func() { s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { panic(http.ErrAbortHandler) diff --git a/integrationtests/self/http_test.go b/integrationtests/self/http_test.go index b647d4d9..a1067070 100644 --- a/integrationtests/self/http_test.go +++ b/integrationtests/self/http_test.go @@ -128,6 +128,18 @@ var _ = Describe("HTTP tests", func() { Expect(string(body)).To(Equal("Hello, World!\n")) }) + It("sets content-length for small response", func() { + mux.HandleFunc("/small", func(w http.ResponseWriter, r *http.Request) { + defer GinkgoRecover() + w.Write([]byte("foobar")) + }) + + resp, err := client.Get(fmt.Sprintf("https://localhost:%d/small", port)) + Expect(err).ToNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(200)) + Expect(resp.Header.Get("Content-Length")).To(Equal(strconv.Itoa(len("foobar")))) + }) + It("requests to different servers with the same udpconn", func() { resp, err := client.Get(fmt.Sprintf("https://localhost:%d/remoteAddr", port)) Expect(err).ToNot(HaveOccurred()) From 8d91ad9fcd02d818424401bcc21a78d4e151c7d5 Mon Sep 17 00:00:00 2001 From: Jean-Francois Giorgi Date: Wed, 23 Aug 2023 05:12:08 +0200 Subject: [PATCH 30/36] move QUIC_GO_DISABLE_GSO check out of init (#4041) * move QUIC_GO_DISABLE_GSO test out of init(). * Update sys_conn_helper_linux.go --------- Co-authored-by: Marten Seemann --- sys_conn_helper_linux.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/sys_conn_helper_linux.go b/sys_conn_helper_linux.go index 5bda2286..6a049241 100644 --- a/sys_conn_helper_linux.go +++ b/sys_conn_helper_linux.go @@ -14,15 +14,6 @@ import ( "golang.org/x/sys/unix" ) -var gsoDisabled bool - -func init() { - disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_GSO")) - if err == nil { - gsoDisabled = disabled - } -} - const ( msgTypeIPTOS = unix.IP_TOS ipv4PKTINFO = unix.IP_PKTINFO @@ -65,7 +56,8 @@ func parseIPv4PktInfo(body []byte) (ip netip.Addr, ifIndex uint32, ok bool) { // isGSOSupported tests if the kernel supports GSO. // Sending with GSO might still fail later on, if the interface doesn't support it (see isGSOError). func isGSOSupported(conn syscall.RawConn) bool { - if gsoDisabled { + disabled, err := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_GSO")) + if err == nil && disabled { return false } var serr error From f633dca488b0858088afae0ba4709b3bfdf798f9 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 23 Aug 2023 10:36:33 +0700 Subject: [PATCH 31/36] update qtls to v0.3.3 (#4044) --- go.mod | 2 +- go.sum | 4 ++-- integrationtests/gomodvendor/go.sum | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 106c90fd..32092eb6 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/onsi/ginkgo/v2 v2.9.5 github.com/onsi/gomega v1.27.6 github.com/quic-go/qpack v0.4.0 - github.com/quic-go/qtls-go1-20 v0.3.2 + github.com/quic-go/qtls-go1-20 v0.3.3 golang.org/x/crypto v0.4.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.10.0 diff --git a/go.sum b/go.sum index f28b844c..59ef763c 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,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/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= -github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= +github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= diff --git a/integrationtests/gomodvendor/go.sum b/integrationtests/gomodvendor/go.sum index ab32e138..ae9f9517 100644 --- a/integrationtests/gomodvendor/go.sum +++ b/integrationtests/gomodvendor/go.sum @@ -136,8 +136,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/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= -github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= +github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= From d22854641ace1792ca27d7d911a6d62c0075e2c2 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 25 Aug 2023 07:53:02 +0700 Subject: [PATCH 32/36] remove the port from the hostname used for tls.Config.ServerName (#4046) --- transport.go | 31 +++++++++++++++++++++---------- transport_test.go | 12 ++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/transport.go b/transport.go index fe6dc1fc..d8da9b1a 100644 --- a/transport.go +++ b/transport.go @@ -159,7 +159,7 @@ func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.C return t.dial(ctx, addr, "", tlsConf, conf, true) } -func (t *Transport) dial(ctx context.Context, addr net.Addr, hostname string, tlsConf *tls.Config, conf *Config, use0RTT bool) (EarlyConnection, error) { +func (t *Transport) dial(ctx context.Context, addr net.Addr, host string, tlsConf *tls.Config, conf *Config, use0RTT bool) (EarlyConnection, error) { if err := validateConfig(conf); err != nil { return nil, err } @@ -173,15 +173,7 @@ func (t *Transport) dial(ctx context.Context, addr net.Addr, hostname string, tl } tlsConf = tlsConf.Clone() tlsConf.MinVersion = tls.VersionTLS13 - // If no ServerName is set, infer the ServerName from the hostname we're connecting to. - if tlsConf.ServerName == "" { - if hostname == "" { - if udpAddr, ok := addr.(*net.UDPAddr); ok { - hostname = udpAddr.IP.String() - } - } - tlsConf.ServerName = hostname - } + setTLSConfigServerName(tlsConf, addr, host) return dial(ctx, newSendConn(t.conn, addr, packetInfo{}, utils.DefaultLogger), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, use0RTT) } @@ -478,3 +470,22 @@ func (t *Transport) ReadNonQUICPacket(ctx context.Context, b []byte) (int, net.A return 0, nil, errors.New("closed") } } + +func setTLSConfigServerName(tlsConf *tls.Config, addr net.Addr, host string) { + // If no ServerName is set, infer the ServerName from the host we're connecting to. + if tlsConf.ServerName != "" { + return + } + if host == "" { + if udpAddr, ok := addr.(*net.UDPAddr); ok { + tlsConf.ServerName = udpAddr.IP.String() + return + } + } + h, _, err := net.SplitHostPort(host) + if err != nil { // This happens if the host doesn't contain a port number. + tlsConf.ServerName = host + return + } + tlsConf.ServerName = h +} diff --git a/transport_test.go b/transport_test.go index 93e1d32a..cf38e325 100644 --- a/transport_test.go +++ b/transport_test.go @@ -396,6 +396,18 @@ var _ = Describe("Transport", func() { close(packetChan) tr.Close() }) + + remoteAddr := &net.UDPAddr{IP: net.IPv4(1, 3, 5, 7), Port: 1234} + DescribeTable("setting the tls.Config.ServerName", + func(expected string, conf *tls.Config, addr net.Addr, host string) { + setTLSConfigServerName(conf, addr, host) + Expect(conf.ServerName).To(Equal(expected)) + }, + Entry("uses the value from the config", "foo.bar", &tls.Config{ServerName: "foo.bar"}, remoteAddr, "baz.foo"), + Entry("uses the hostname", "golang.org", &tls.Config{}, remoteAddr, "golang.org"), + Entry("removes the port from the hostname", "golang.org", &tls.Config{}, remoteAddr, "golang.org:1234"), + Entry("uses the IP", "1.3.5.7", &tls.Config{}, remoteAddr, ""), + ) }) type mockSyscallConn struct { From e058f56643f5e1f56208ccb859c2256f419c12cd Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 25 Aug 2023 08:23:44 +0700 Subject: [PATCH 33/36] ci: fix integration test running with and without GSO (#4043) --- .github/workflows/integration.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 0b8fa904..be5efa59 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -37,10 +37,10 @@ jobs: - name: Run self tests, using QUIC v2 if: success() || failure() # run this step even if the previous one failed run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=2 ${{ env.QLOGFLAG }} - - name: Run set tests, with GSO enabled - if: success() || failure() # run this step even if the previous one failed + - name: Run self tests, with GSO disabled + if: ${{ matrix.os == 'ubuntu' && (success() || failure()) # run this step even if the previous one failed env: - QUIC_GO_ENABLE_GSO: true + QUIC_GO_DISABLE_GSO: true run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=1 ${{ env.QLOGFLAG }} - name: Run tests (32 bit) if: ${{ matrix.os != 'macos' && (success() || failure()) }} # run this step even if the previous one failed From 89633069878628392edef3a5fd285eeb11e87889 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 26 Aug 2023 18:23:26 +0700 Subject: [PATCH 34/36] ci: fix syntax error in integration test workflow (#4048) --- .github/workflows/integration.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index be5efa59..0e76cba8 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -21,7 +21,6 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - stable: '!contains(${{ matrix.go }}, "beta") && !contains(${{ matrix.go }}, "rc")' go-version: ${{ matrix.go }} - run: go version - name: set qlogger @@ -38,7 +37,7 @@ jobs: if: success() || failure() # run this step even if the previous one failed run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=2 ${{ env.QLOGFLAG }} - name: Run self tests, with GSO disabled - if: ${{ matrix.os == 'ubuntu' && (success() || failure()) # run this step even if the previous one failed + if: ${{ matrix.os == 'ubuntu' && (success() || failure()) }} # run this step even if the previous one failed env: QUIC_GO_DISABLE_GSO: true run: go run github.com/onsi/ginkgo/v2/ginkgo -r -v -randomize-all -randomize-suites -trace integrationtests/self -- -version=1 ${{ env.QLOGFLAG }} From 8f34488c7620bfcedc88c64bf70e678c2db5d534 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 27 Aug 2023 11:53:07 +0700 Subject: [PATCH 35/36] fix flaky version negotiation connection unit test (#4052) --- connection_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connection_test.go b/connection_test.go index 5c972733..70864190 100644 --- a/connection_test.go +++ b/connection_test.go @@ -2702,8 +2702,9 @@ var _ = Describe("Client Connection", func() { Expect(recreateErr.nextPacketNumber).To(Equal(protocol.PacketNumber(128))) }) - It("it closes when no matching version is found", func() { + It("closes when no matching version is found", func() { errChan := make(chan error, 1) + packer.EXPECT().PackCoalescedPacket(gomock.Any(), gomock.Any(), gomock.Any()).MaxTimes(1) go func() { defer GinkgoRecover() cryptoSetup.EXPECT().StartHandshake().MaxTimes(1) @@ -2711,7 +2712,6 @@ var _ = Describe("Client Connection", func() { errChan <- conn.run() }() connRunner.EXPECT().Remove(srcConnID).MaxTimes(1) - packer.EXPECT().PackCoalescedPacket(gomock.Any(), gomock.Any(), gomock.Any()).MaxTimes(1) gomock.InOrder( tracer.EXPECT().ReceivedVersionNegotiationPacket(gomock.Any(), gomock.Any(), gomock.Any()), tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) { From 2797f85fc0fbea493a3d3ae95cac2be666d7288b Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 28 Aug 2023 16:23:55 +0700 Subject: [PATCH 36/36] switch from unmaintained golang/mock to go.uber.org/mock (#4050) --- client_test.go | 3 +- connection_test.go | 3 +- framer_test.go | 3 +- go.mod | 2 +- go.sum | 24 +-------- http3/body_test.go | 2 +- http3/client_test.go | 2 +- http3/http3_suite_test.go | 3 +- http3/http_stream_test.go | 2 +- http3/mock_quic_early_listener_test.go | 2 +- http3/mock_roundtripcloser_test.go | 2 +- http3/mockgen.go | 4 +- http3/request_writer_test.go | 2 +- http3/response_writer_test.go | 2 +- http3/roundtrip_test.go | 2 +- http3/server_test.go | 2 +- integrationtests/gomodvendor/go.sum | 12 ++--- internal/ackhandler/ackhandler_suite_test.go | 2 +- .../mock_sent_packet_tracker_test.go | 2 +- internal/ackhandler/mockgen.go | 2 +- .../received_packet_handler_test.go | 3 +- .../ackhandler/sent_packet_handler_test.go | 3 +- .../flowcontrol/flowcontrol_suite_test.go | 2 +- internal/handshake/crypto_setup_test.go | 3 +- internal/handshake/handshake_suite_test.go | 3 +- internal/handshake/updatable_aead_test.go | 2 +- .../ackhandler/received_packet_handler.go | 2 +- .../mocks/ackhandler/sent_packet_handler.go | 2 +- internal/mocks/congestion.go | 2 +- internal/mocks/connection_flow_controller.go | 2 +- internal/mocks/crypto_setup.go | 2 +- internal/mocks/logging/connection_tracer.go | 2 +- internal/mocks/logging/tracer.go | 2 +- internal/mocks/long_header_opener.go | 2 +- internal/mocks/mockgen.go | 28 +++++------ internal/mocks/quic/early_conn.go | 2 +- internal/mocks/quic/stream.go | 2 +- internal/mocks/short_header_opener.go | 2 +- internal/mocks/short_header_sealer.go | 2 +- internal/mocks/stream_flow_controller.go | 2 +- internal/mocks/tls/client_session_cache.go | 2 +- internal/qtls/qtls_suite_test.go | 3 +- logging/logging_suite_test.go | 3 +- logging/mock_connection_tracer_test.go | 2 +- logging/mock_tracer_test.go | 2 +- logging/mockgen.go | 4 +- mock_ack_frame_source_test.go | 2 +- mock_batch_conn_test.go | 2 +- mock_conn_runner_test.go | 2 +- mock_crypto_data_handler_test.go | 2 +- mock_crypto_stream_test.go | 2 +- mock_frame_source_test.go | 2 +- mock_mtu_discoverer_test.go | 2 +- mock_packer_test.go | 2 +- mock_packet_handler_manager_test.go | 2 +- mock_packet_handler_test.go | 2 +- mock_packetconn_test.go | 2 +- mock_quic_conn_test.go | 2 +- mock_raw_conn_test.go | 2 +- mock_receive_stream_internal_test.go | 2 +- mock_sealing_manager_test.go | 2 +- mock_send_conn_test.go | 2 +- mock_send_stream_internal_test.go | 2 +- mock_sender_test.go | 2 +- mock_stream_getter_test.go | 2 +- mock_stream_internal_test.go | 2 +- mock_stream_manager_test.go | 2 +- mock_stream_sender_test.go | 2 +- mock_token_store_test.go | 2 +- mock_unknown_packet_handler_test.go | 2 +- mock_unpacker_test.go | 2 +- mockgen.go | 50 +++++++++---------- packet_packer_test.go | 3 +- packet_unpacker_test.go | 2 +- quic_suite_test.go | 2 +- receive_stream_test.go | 2 +- send_conn_test.go | 2 +- send_queue_test.go | 2 +- send_stream_test.go | 2 +- server_test.go | 2 +- streams_map_incoming_test.go | 2 +- streams_map_outgoing_test.go | 2 +- streams_map_test.go | 3 +- sys_conn_oob_test.go | 2 +- sys_conn_test.go | 3 +- tools.go | 2 +- transport_test.go | 2 +- 87 files changed, 130 insertions(+), 167 deletions(-) diff --git a/client_test.go b/client_test.go index 50346891..e908b82f 100644 --- a/client_test.go +++ b/client_test.go @@ -12,10 +12,9 @@ import ( "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/logging" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) type nullMultiplexer struct{} diff --git a/connection_test.go b/connection_test.go index 70864190..05a0f20d 100644 --- a/connection_test.go +++ b/connection_test.go @@ -25,10 +25,9 @@ import ( "github.com/quic-go/quic-go/internal/wire" "github.com/quic-go/quic-go/logging" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func areConnsRunning() bool { diff --git a/framer_test.go b/framer_test.go index 9615e78e..add9da71 100644 --- a/framer_test.go +++ b/framer_test.go @@ -8,10 +8,9 @@ import ( "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Framer", func() { diff --git a/go.mod b/go.mod index 32092eb6..fac9c9fb 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,11 @@ go 1.20 require ( github.com/francoispqt/gojay v1.2.13 - github.com/golang/mock v1.6.0 github.com/onsi/ginkgo/v2 v2.9.5 github.com/onsi/gomega v1.27.6 github.com/quic-go/qpack v0.4.0 github.com/quic-go/qtls-go1-20 v0.3.3 + go.uber.org/mock v0.2.0 golang.org/x/crypto v0.4.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.10.0 diff --git a/go.sum b/go.sum index 59ef763c..28cab718 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -125,14 +123,14 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= +go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -141,7 +139,6 @@ golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZ 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/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -152,9 +149,6 @@ golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -166,8 +160,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -175,33 +167,21 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= diff --git a/http3/body_test.go b/http3/body_test.go index 5bcca2e9..7b96345d 100644 --- a/http3/body_test.go +++ b/http3/body_test.go @@ -6,9 +6,9 @@ import ( "github.com/quic-go/quic-go" mockquic "github.com/quic-go/quic-go/internal/mocks/quic" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Response Body", func() { diff --git a/http3/client_test.go b/http3/client_test.go index babcb064..66e290e2 100644 --- a/http3/client_test.go +++ b/http3/client_test.go @@ -18,11 +18,11 @@ import ( "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/quicvarint" - "github.com/golang/mock/gomock" "github.com/quic-go/qpack" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Client", func() { diff --git a/http3/http3_suite_test.go b/http3/http3_suite_test.go index 56b2108f..b34003b9 100644 --- a/http3/http3_suite_test.go +++ b/http3/http3_suite_test.go @@ -6,10 +6,9 @@ import ( "testing" "time" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestHttp3(t *testing.T) { diff --git a/http3/http_stream_test.go b/http3/http_stream_test.go index cff5476b..2d2dc3f3 100644 --- a/http3/http_stream_test.go +++ b/http3/http_stream_test.go @@ -7,9 +7,9 @@ import ( "github.com/quic-go/quic-go" mockquic "github.com/quic-go/quic-go/internal/mocks/quic" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func getDataFrame(data []byte) []byte { diff --git a/http3/mock_quic_early_listener_test.go b/http3/mock_quic_early_listener_test.go index ab40f060..b79e9858 100644 --- a/http3/mock_quic_early_listener_test.go +++ b/http3/mock_quic_early_listener_test.go @@ -9,8 +9,8 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" quic "github.com/quic-go/quic-go" + gomock "go.uber.org/mock/gomock" ) // MockQUICEarlyListener is a mock of QUICEarlyListener interface. diff --git a/http3/mock_roundtripcloser_test.go b/http3/mock_roundtripcloser_test.go index 7aa19ee3..ce7f0d19 100644 --- a/http3/mock_roundtripcloser_test.go +++ b/http3/mock_roundtripcloser_test.go @@ -8,7 +8,7 @@ import ( http "net/http" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockRoundTripCloser is a mock of RoundTripCloser interface. diff --git a/http3/mockgen.go b/http3/mockgen.go index 38939e60..ad0a8a26 100644 --- a/http3/mockgen.go +++ b/http3/mockgen.go @@ -2,7 +2,7 @@ package http3 -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/quic-go/quic-go/http3 RoundTripCloser" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/quic-go/quic-go/http3 RoundTripCloser" type RoundTripCloser = roundTripCloser -//go:generate sh -c "go run github.com/golang/mock/mockgen -package http3 -destination mock_quic_early_listener_test.go github.com/quic-go/quic-go/http3 QUICEarlyListener" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package http3 -destination mock_quic_early_listener_test.go github.com/quic-go/quic-go/http3 QUICEarlyListener" diff --git a/http3/request_writer_test.go b/http3/request_writer_test.go index 74fd2398..beabb378 100644 --- a/http3/request_writer_test.go +++ b/http3/request_writer_test.go @@ -8,8 +8,8 @@ import ( mockquic "github.com/quic-go/quic-go/internal/mocks/quic" "github.com/quic-go/quic-go/internal/utils" - "github.com/golang/mock/gomock" "github.com/quic-go/qpack" + "go.uber.org/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" diff --git a/http3/response_writer_test.go b/http3/response_writer_test.go index c803adb7..ed6c1d28 100644 --- a/http3/response_writer_test.go +++ b/http3/response_writer_test.go @@ -9,11 +9,11 @@ import ( mockquic "github.com/quic-go/quic-go/internal/mocks/quic" "github.com/quic-go/quic-go/internal/utils" - "github.com/golang/mock/gomock" "github.com/quic-go/qpack" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Response Writer", func() { diff --git a/http3/roundtrip_test.go b/http3/roundtrip_test.go index 0c219db7..30672384 100644 --- a/http3/roundtrip_test.go +++ b/http3/roundtrip_test.go @@ -13,9 +13,9 @@ import ( "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/internal/qerr" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) type mockBody struct { diff --git a/http3/server_test.go b/http3/server_test.go index 67713b92..486d3135 100644 --- a/http3/server_test.go +++ b/http3/server_test.go @@ -20,8 +20,8 @@ import ( "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/quicvarint" - "github.com/golang/mock/gomock" "github.com/quic-go/qpack" + "go.uber.org/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" diff --git a/integrationtests/gomodvendor/go.sum b/integrationtests/gomodvendor/go.sum index ae9f9517..e24232c0 100644 --- a/integrationtests/gomodvendor/go.sum +++ b/integrationtests/gomodvendor/go.sum @@ -39,8 +39,6 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -173,10 +171,11 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= +go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -195,7 +194,7 @@ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTk 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/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= @@ -217,7 +216,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -261,9 +259,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -309,7 +305,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm 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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= diff --git a/internal/ackhandler/ackhandler_suite_test.go b/internal/ackhandler/ackhandler_suite_test.go index 069aaa79..a0cf3ee1 100644 --- a/internal/ackhandler/ackhandler_suite_test.go +++ b/internal/ackhandler/ackhandler_suite_test.go @@ -3,9 +3,9 @@ package ackhandler import ( "testing" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestCrypto(t *testing.T) { diff --git a/internal/ackhandler/mock_sent_packet_tracker_test.go b/internal/ackhandler/mock_sent_packet_tracker_test.go index 83c28fd5..63a9a163 100644 --- a/internal/ackhandler/mock_sent_packet_tracker_test.go +++ b/internal/ackhandler/mock_sent_packet_tracker_test.go @@ -7,8 +7,8 @@ package ackhandler import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockSentPacketTracker is a mock of SentPacketTracker interface. diff --git a/internal/ackhandler/mockgen.go b/internal/ackhandler/mockgen.go index d6178367..b9eb8a88 100644 --- a/internal/ackhandler/mockgen.go +++ b/internal/ackhandler/mockgen.go @@ -2,5 +2,5 @@ package ackhandler -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker" type SentPacketTracker = sentPacketTracker diff --git a/internal/ackhandler/received_packet_handler_test.go b/internal/ackhandler/received_packet_handler_test.go index b07d6178..387ab7bc 100644 --- a/internal/ackhandler/received_packet_handler_test.go +++ b/internal/ackhandler/received_packet_handler_test.go @@ -3,14 +3,13 @@ package ackhandler import ( "time" - "github.com/golang/mock/gomock" - "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/internal/wire" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Received Packet Handler", func() { diff --git a/internal/ackhandler/sent_packet_handler_test.go b/internal/ackhandler/sent_packet_handler_test.go index 6c603c87..fc120171 100644 --- a/internal/ackhandler/sent_packet_handler_test.go +++ b/internal/ackhandler/sent_packet_handler_test.go @@ -4,8 +4,6 @@ import ( "fmt" "time" - "github.com/golang/mock/gomock" - "github.com/quic-go/quic-go/internal/mocks" "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/qerr" @@ -14,6 +12,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) type customFrameHandler struct { diff --git a/internal/flowcontrol/flowcontrol_suite_test.go b/internal/flowcontrol/flowcontrol_suite_test.go index 8831296d..6cfe981d 100644 --- a/internal/flowcontrol/flowcontrol_suite_test.go +++ b/internal/flowcontrol/flowcontrol_suite_test.go @@ -3,9 +3,9 @@ package flowcontrol import ( "testing" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestFlowControl(t *testing.T) { diff --git a/internal/handshake/crypto_setup_test.go b/internal/handshake/crypto_setup_test.go index 8b2c5efe..e40db500 100644 --- a/internal/handshake/crypto_setup_test.go +++ b/internal/handshake/crypto_setup_test.go @@ -17,10 +17,9 @@ import ( "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) const ( diff --git a/internal/handshake/handshake_suite_test.go b/internal/handshake/handshake_suite_test.go index 3289928e..80e48a30 100644 --- a/internal/handshake/handshake_suite_test.go +++ b/internal/handshake/handshake_suite_test.go @@ -6,10 +6,9 @@ import ( "strings" "testing" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestHandshake(t *testing.T) { diff --git a/internal/handshake/updatable_aead_test.go b/internal/handshake/updatable_aead_test.go index db3cf56e..a4a91f01 100644 --- a/internal/handshake/updatable_aead_test.go +++ b/internal/handshake/updatable_aead_test.go @@ -12,9 +12,9 @@ import ( "github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/internal/utils" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Updatable AEAD", func() { diff --git a/internal/mocks/ackhandler/received_packet_handler.go b/internal/mocks/ackhandler/received_packet_handler.go index c73727e0..b068586e 100644 --- a/internal/mocks/ackhandler/received_packet_handler.go +++ b/internal/mocks/ackhandler/received_packet_handler.go @@ -8,9 +8,9 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockReceivedPacketHandler is a mock of ReceivedPacketHandler interface. diff --git a/internal/mocks/ackhandler/sent_packet_handler.go b/internal/mocks/ackhandler/sent_packet_handler.go index 0904d5cb..80aaae0f 100644 --- a/internal/mocks/ackhandler/sent_packet_handler.go +++ b/internal/mocks/ackhandler/sent_packet_handler.go @@ -8,10 +8,10 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" ackhandler "github.com/quic-go/quic-go/internal/ackhandler" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockSentPacketHandler is a mock of SentPacketHandler interface. diff --git a/internal/mocks/congestion.go b/internal/mocks/congestion.go index 6a5e46ad..d27113a7 100644 --- a/internal/mocks/congestion.go +++ b/internal/mocks/congestion.go @@ -8,8 +8,8 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockSendAlgorithmWithDebugInfos is a mock of SendAlgorithmWithDebugInfos interface. diff --git a/internal/mocks/connection_flow_controller.go b/internal/mocks/connection_flow_controller.go index a0c252f3..1ec76f9e 100644 --- a/internal/mocks/connection_flow_controller.go +++ b/internal/mocks/connection_flow_controller.go @@ -7,8 +7,8 @@ package mocks import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockConnectionFlowController is a mock of ConnectionFlowController interface. diff --git a/internal/mocks/crypto_setup.go b/internal/mocks/crypto_setup.go index 1c707b9c..bf496c22 100644 --- a/internal/mocks/crypto_setup.go +++ b/internal/mocks/crypto_setup.go @@ -7,9 +7,9 @@ package mocks import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" handshake "github.com/quic-go/quic-go/internal/handshake" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockCryptoSetup is a mock of CryptoSetup interface. diff --git a/internal/mocks/logging/connection_tracer.go b/internal/mocks/logging/connection_tracer.go index 2a7d2f13..1ca0895d 100644 --- a/internal/mocks/logging/connection_tracer.go +++ b/internal/mocks/logging/connection_tracer.go @@ -9,11 +9,11 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" utils "github.com/quic-go/quic-go/internal/utils" wire "github.com/quic-go/quic-go/internal/wire" logging "github.com/quic-go/quic-go/logging" + gomock "go.uber.org/mock/gomock" ) // MockConnectionTracer is a mock of ConnectionTracer interface. diff --git a/internal/mocks/logging/tracer.go b/internal/mocks/logging/tracer.go index 56741ef2..2cdd2335 100644 --- a/internal/mocks/logging/tracer.go +++ b/internal/mocks/logging/tracer.go @@ -8,10 +8,10 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" logging "github.com/quic-go/quic-go/logging" + gomock "go.uber.org/mock/gomock" ) // MockTracer is a mock of Tracer interface. diff --git a/internal/mocks/long_header_opener.go b/internal/mocks/long_header_opener.go index cb4970d1..fc284dd8 100644 --- a/internal/mocks/long_header_opener.go +++ b/internal/mocks/long_header_opener.go @@ -7,8 +7,8 @@ package mocks import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockLongHeaderOpener is a mock of LongHeaderOpener interface. diff --git a/internal/mocks/mockgen.go b/internal/mocks/mockgen.go index 8717fce0..9bee4270 100644 --- a/internal/mocks/mockgen.go +++ b/internal/mocks/mockgen.go @@ -1,19 +1,19 @@ package mocks -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockquic -destination quic/stream.go github.com/quic-go/quic-go Stream" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockquic -destination quic/early_conn_tmp.go github.com/quic-go/quic-go EarlyConnection && sed 's/qtls.ConnectionState/quic.ConnectionState/g' quic/early_conn_tmp.go > quic/early_conn.go && rm quic/early_conn_tmp.go && go run golang.org/x/tools/cmd/goimports -w quic/early_conn.go" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocklogging -destination logging/tracer.go github.com/quic-go/quic-go/logging Tracer" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocklogging -destination logging/connection_tracer.go github.com/quic-go/quic-go/logging ConnectionTracer" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination short_header_sealer.go github.com/quic-go/quic-go/internal/handshake ShortHeaderSealer" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination short_header_opener.go github.com/quic-go/quic-go/internal/handshake ShortHeaderOpener" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination long_header_opener.go github.com/quic-go/quic-go/internal/handshake LongHeaderOpener" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination crypto_setup_tmp.go github.com/quic-go/quic-go/internal/handshake CryptoSetup && sed -E 's~github.com/quic-go/qtls[[:alnum:]_-]*~github.com/quic-go/quic-go/internal/qtls~g; s~qtls.ConnectionStateWith0RTT~qtls.ConnectionState~g' crypto_setup_tmp.go > crypto_setup.go && rm crypto_setup_tmp.go && go run golang.org/x/tools/cmd/goimports -w crypto_setup.go" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination stream_flow_controller.go github.com/quic-go/quic-go/internal/flowcontrol StreamFlowController" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination congestion.go github.com/quic-go/quic-go/internal/congestion SendAlgorithmWithDebugInfos" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocks -destination connection_flow_controller.go github.com/quic-go/quic-go/internal/flowcontrol ConnectionFlowController" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockackhandler -destination ackhandler/sent_packet_handler.go github.com/quic-go/quic-go/internal/ackhandler SentPacketHandler" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mockackhandler -destination ackhandler/received_packet_handler.go github.com/quic-go/quic-go/internal/ackhandler ReceivedPacketHandler" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockquic -destination quic/stream.go github.com/quic-go/quic-go Stream" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockquic -destination quic/early_conn_tmp.go github.com/quic-go/quic-go EarlyConnection && sed 's/qtls.ConnectionState/quic.ConnectionState/g' quic/early_conn_tmp.go > quic/early_conn.go && rm quic/early_conn_tmp.go && go run golang.org/x/tools/cmd/goimports -w quic/early_conn.go" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocklogging -destination logging/tracer.go github.com/quic-go/quic-go/logging Tracer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocklogging -destination logging/connection_tracer.go github.com/quic-go/quic-go/logging ConnectionTracer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination short_header_sealer.go github.com/quic-go/quic-go/internal/handshake ShortHeaderSealer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination short_header_opener.go github.com/quic-go/quic-go/internal/handshake ShortHeaderOpener" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination long_header_opener.go github.com/quic-go/quic-go/internal/handshake LongHeaderOpener" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination crypto_setup_tmp.go github.com/quic-go/quic-go/internal/handshake CryptoSetup && sed -E 's~github.com/quic-go/qtls[[:alnum:]_-]*~github.com/quic-go/quic-go/internal/qtls~g; s~qtls.ConnectionStateWith0RTT~qtls.ConnectionState~g' crypto_setup_tmp.go > crypto_setup.go && rm crypto_setup_tmp.go && go run golang.org/x/tools/cmd/goimports -w crypto_setup.go" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination stream_flow_controller.go github.com/quic-go/quic-go/internal/flowcontrol StreamFlowController" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination congestion.go github.com/quic-go/quic-go/internal/congestion SendAlgorithmWithDebugInfos" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocks -destination connection_flow_controller.go github.com/quic-go/quic-go/internal/flowcontrol ConnectionFlowController" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockackhandler -destination ackhandler/sent_packet_handler.go github.com/quic-go/quic-go/internal/ackhandler SentPacketHandler" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mockackhandler -destination ackhandler/received_packet_handler.go github.com/quic-go/quic-go/internal/ackhandler ReceivedPacketHandler" // The following command produces a warning message on OSX, however, it still generates the correct mock file. // See https://github.com/golang/mock/issues/339 for details. -//go:generate sh -c "go run github.com/golang/mock/mockgen -package mocktls -destination tls/client_session_cache.go crypto/tls ClientSessionCache" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package mocktls -destination tls/client_session_cache.go crypto/tls ClientSessionCache" diff --git a/internal/mocks/quic/early_conn.go b/internal/mocks/quic/early_conn.go index a573e06f..c4db88d2 100644 --- a/internal/mocks/quic/early_conn.go +++ b/internal/mocks/quic/early_conn.go @@ -9,9 +9,9 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" quic "github.com/quic-go/quic-go" qerr "github.com/quic-go/quic-go/internal/qerr" + gomock "go.uber.org/mock/gomock" ) // MockEarlyConnection is a mock of EarlyConnection interface. diff --git a/internal/mocks/quic/stream.go b/internal/mocks/quic/stream.go index 1221ac3b..7fc65600 100644 --- a/internal/mocks/quic/stream.go +++ b/internal/mocks/quic/stream.go @@ -9,9 +9,9 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" qerr "github.com/quic-go/quic-go/internal/qerr" + gomock "go.uber.org/mock/gomock" ) // MockStream is a mock of Stream interface. diff --git a/internal/mocks/short_header_opener.go b/internal/mocks/short_header_opener.go index 47e858cb..ffc8bd48 100644 --- a/internal/mocks/short_header_opener.go +++ b/internal/mocks/short_header_opener.go @@ -8,8 +8,8 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockShortHeaderOpener is a mock of ShortHeaderOpener interface. diff --git a/internal/mocks/short_header_sealer.go b/internal/mocks/short_header_sealer.go index 666fd8fb..d0109b5e 100644 --- a/internal/mocks/short_header_sealer.go +++ b/internal/mocks/short_header_sealer.go @@ -7,8 +7,8 @@ package mocks import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockShortHeaderSealer is a mock of ShortHeaderSealer interface. diff --git a/internal/mocks/stream_flow_controller.go b/internal/mocks/stream_flow_controller.go index 9d730eba..05eaf8b9 100644 --- a/internal/mocks/stream_flow_controller.go +++ b/internal/mocks/stream_flow_controller.go @@ -7,8 +7,8 @@ package mocks import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockStreamFlowController is a mock of StreamFlowController interface. diff --git a/internal/mocks/tls/client_session_cache.go b/internal/mocks/tls/client_session_cache.go index e3ae2c8e..6877f9bb 100644 --- a/internal/mocks/tls/client_session_cache.go +++ b/internal/mocks/tls/client_session_cache.go @@ -8,7 +8,7 @@ import ( tls "crypto/tls" reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockClientSessionCache is a mock of ClientSessionCache interface. diff --git a/internal/qtls/qtls_suite_test.go b/internal/qtls/qtls_suite_test.go index e8ce652a..bde81e6c 100644 --- a/internal/qtls/qtls_suite_test.go +++ b/internal/qtls/qtls_suite_test.go @@ -3,10 +3,9 @@ package qtls import ( "testing" - gomock "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestQTLS(t *testing.T) { diff --git a/logging/logging_suite_test.go b/logging/logging_suite_test.go index d37ada48..d808adfe 100644 --- a/logging/logging_suite_test.go +++ b/logging/logging_suite_test.go @@ -3,10 +3,9 @@ package logging import ( "testing" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestLogging(t *testing.T) { diff --git a/logging/mock_connection_tracer_test.go b/logging/mock_connection_tracer_test.go index ac6d5fd7..f4f7648a 100644 --- a/logging/mock_connection_tracer_test.go +++ b/logging/mock_connection_tracer_test.go @@ -9,10 +9,10 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" utils "github.com/quic-go/quic-go/internal/utils" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockConnectionTracer is a mock of ConnectionTracer interface. diff --git a/logging/mock_tracer_test.go b/logging/mock_tracer_test.go index 8526cd3a..61eb47ea 100644 --- a/logging/mock_tracer_test.go +++ b/logging/mock_tracer_test.go @@ -8,9 +8,9 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockTracer is a mock of Tracer interface. diff --git a/logging/mockgen.go b/logging/mockgen.go index d5091679..e44c15e1 100644 --- a/logging/mockgen.go +++ b/logging/mockgen.go @@ -1,4 +1,4 @@ package logging -//go:generate sh -c "go run github.com/golang/mock/mockgen -package logging -self_package github.com/quic-go/quic-go/logging -destination mock_connection_tracer_test.go github.com/quic-go/quic-go/logging ConnectionTracer" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package logging -self_package github.com/quic-go/quic-go/logging -destination mock_tracer_test.go github.com/quic-go/quic-go/logging Tracer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package logging -self_package github.com/quic-go/quic-go/logging -destination mock_connection_tracer_test.go github.com/quic-go/quic-go/logging ConnectionTracer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package logging -self_package github.com/quic-go/quic-go/logging -destination mock_tracer_test.go github.com/quic-go/quic-go/logging Tracer" diff --git a/mock_ack_frame_source_test.go b/mock_ack_frame_source_test.go index 1284752b..54105f9d 100644 --- a/mock_ack_frame_source_test.go +++ b/mock_ack_frame_source_test.go @@ -7,9 +7,9 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockAckFrameSource is a mock of AckFrameSource interface. diff --git a/mock_batch_conn_test.go b/mock_batch_conn_test.go index fcb23e34..9621e7b4 100644 --- a/mock_batch_conn_test.go +++ b/mock_batch_conn_test.go @@ -7,7 +7,7 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ipv4 "golang.org/x/net/ipv4" ) diff --git a/mock_conn_runner_test.go b/mock_conn_runner_test.go index ec587323..e404c283 100644 --- a/mock_conn_runner_test.go +++ b/mock_conn_runner_test.go @@ -7,8 +7,8 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockConnRunner is a mock of ConnRunner interface. diff --git a/mock_crypto_data_handler_test.go b/mock_crypto_data_handler_test.go index d077886c..22e6eaa2 100644 --- a/mock_crypto_data_handler_test.go +++ b/mock_crypto_data_handler_test.go @@ -7,9 +7,9 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" handshake "github.com/quic-go/quic-go/internal/handshake" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockCryptoDataHandler is a mock of CryptoDataHandler interface. diff --git a/mock_crypto_stream_test.go b/mock_crypto_stream_test.go index c2048fa8..253e95e8 100644 --- a/mock_crypto_stream_test.go +++ b/mock_crypto_stream_test.go @@ -7,9 +7,9 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockCryptoStream is a mock of CryptoStream interface. diff --git a/mock_frame_source_test.go b/mock_frame_source_test.go index e23aa39d..040c7581 100644 --- a/mock_frame_source_test.go +++ b/mock_frame_source_test.go @@ -7,9 +7,9 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" ackhandler "github.com/quic-go/quic-go/internal/ackhandler" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockFrameSource is a mock of FrameSource interface. diff --git a/mock_mtu_discoverer_test.go b/mock_mtu_discoverer_test.go index 406943c5..1f5432cd 100644 --- a/mock_mtu_discoverer_test.go +++ b/mock_mtu_discoverer_test.go @@ -8,9 +8,9 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" ackhandler "github.com/quic-go/quic-go/internal/ackhandler" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockMTUDiscoverer is a mock of MTUDiscoverer interface. diff --git a/mock_packer_test.go b/mock_packer_test.go index d54fe58b..4eedab98 100644 --- a/mock_packer_test.go +++ b/mock_packer_test.go @@ -7,10 +7,10 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" ackhandler "github.com/quic-go/quic-go/internal/ackhandler" protocol "github.com/quic-go/quic-go/internal/protocol" qerr "github.com/quic-go/quic-go/internal/qerr" + gomock "go.uber.org/mock/gomock" ) // MockPacker is a mock of Packer interface. diff --git a/mock_packet_handler_manager_test.go b/mock_packet_handler_manager_test.go index 7b70a8db..c948d9d5 100644 --- a/mock_packet_handler_manager_test.go +++ b/mock_packet_handler_manager_test.go @@ -7,8 +7,8 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockPacketHandlerManager is a mock of PacketHandlerManager interface. diff --git a/mock_packet_handler_test.go b/mock_packet_handler_test.go index 529d1b84..e8490589 100644 --- a/mock_packet_handler_test.go +++ b/mock_packet_handler_test.go @@ -7,8 +7,8 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockPacketHandler is a mock of PacketHandler interface. diff --git a/mock_packetconn_test.go b/mock_packetconn_test.go index d6731e4a..c8e20bf2 100644 --- a/mock_packetconn_test.go +++ b/mock_packetconn_test.go @@ -9,7 +9,7 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockPacketConn is a mock of PacketConn interface. diff --git a/mock_quic_conn_test.go b/mock_quic_conn_test.go index 18932051..20015c66 100644 --- a/mock_quic_conn_test.go +++ b/mock_quic_conn_test.go @@ -9,9 +9,9 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" qerr "github.com/quic-go/quic-go/internal/qerr" + gomock "go.uber.org/mock/gomock" ) // MockQUICConn is a mock of QUICConn interface. diff --git a/mock_raw_conn_test.go b/mock_raw_conn_test.go index 66b9c611..0a1a0f3a 100644 --- a/mock_raw_conn_test.go +++ b/mock_raw_conn_test.go @@ -9,7 +9,7 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockRawConn is a mock of RawConn interface. diff --git a/mock_receive_stream_internal_test.go b/mock_receive_stream_internal_test.go index a4cbb276..518e275b 100644 --- a/mock_receive_stream_internal_test.go +++ b/mock_receive_stream_internal_test.go @@ -8,10 +8,10 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" qerr "github.com/quic-go/quic-go/internal/qerr" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockReceiveStreamI is a mock of ReceiveStreamI interface. diff --git a/mock_sealing_manager_test.go b/mock_sealing_manager_test.go index 26e442e5..b77c747a 100644 --- a/mock_sealing_manager_test.go +++ b/mock_sealing_manager_test.go @@ -7,8 +7,8 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" handshake "github.com/quic-go/quic-go/internal/handshake" + gomock "go.uber.org/mock/gomock" ) // MockSealingManager is a mock of SealingManager interface. diff --git a/mock_send_conn_test.go b/mock_send_conn_test.go index 62c01a23..04df8763 100644 --- a/mock_send_conn_test.go +++ b/mock_send_conn_test.go @@ -8,8 +8,8 @@ import ( net "net" reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockSendConn is a mock of SendConn interface. diff --git a/mock_send_stream_internal_test.go b/mock_send_stream_internal_test.go index c0581bc2..4fb89a35 100644 --- a/mock_send_stream_internal_test.go +++ b/mock_send_stream_internal_test.go @@ -9,11 +9,11 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" ackhandler "github.com/quic-go/quic-go/internal/ackhandler" protocol "github.com/quic-go/quic-go/internal/protocol" qerr "github.com/quic-go/quic-go/internal/qerr" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockSendStreamI is a mock of SendStreamI interface. diff --git a/mock_sender_test.go b/mock_sender_test.go index feafdf4e..c2a0fa8f 100644 --- a/mock_sender_test.go +++ b/mock_sender_test.go @@ -7,8 +7,8 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockSender is a mock of Sender interface. diff --git a/mock_stream_getter_test.go b/mock_stream_getter_test.go index d0238750..0ff7f13f 100644 --- a/mock_stream_getter_test.go +++ b/mock_stream_getter_test.go @@ -7,8 +7,8 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" + gomock "go.uber.org/mock/gomock" ) // MockStreamGetter is a mock of StreamGetter interface. diff --git a/mock_stream_internal_test.go b/mock_stream_internal_test.go index 512b4b1d..447438c1 100644 --- a/mock_stream_internal_test.go +++ b/mock_stream_internal_test.go @@ -9,11 +9,11 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" ackhandler "github.com/quic-go/quic-go/internal/ackhandler" protocol "github.com/quic-go/quic-go/internal/protocol" qerr "github.com/quic-go/quic-go/internal/qerr" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockStreamI is a mock of StreamI interface. diff --git a/mock_stream_manager_test.go b/mock_stream_manager_test.go index 2159372d..dc4a39eb 100644 --- a/mock_stream_manager_test.go +++ b/mock_stream_manager_test.go @@ -8,9 +8,9 @@ import ( context "context" reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockStreamManager is a mock of StreamManager interface. diff --git a/mock_stream_sender_test.go b/mock_stream_sender_test.go index b4898c67..94606942 100644 --- a/mock_stream_sender_test.go +++ b/mock_stream_sender_test.go @@ -7,9 +7,9 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockStreamSender is a mock of StreamSender interface. diff --git a/mock_token_store_test.go b/mock_token_store_test.go index 0fb461a6..8576a3e2 100644 --- a/mock_token_store_test.go +++ b/mock_token_store_test.go @@ -7,7 +7,7 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockTokenStore is a mock of TokenStore interface. diff --git a/mock_unknown_packet_handler_test.go b/mock_unknown_packet_handler_test.go index f7489782..6f29101a 100644 --- a/mock_unknown_packet_handler_test.go +++ b/mock_unknown_packet_handler_test.go @@ -7,7 +7,7 @@ package quic import ( reflect "reflect" - gomock "github.com/golang/mock/gomock" + gomock "go.uber.org/mock/gomock" ) // MockUnknownPacketHandler is a mock of UnknownPacketHandler interface. diff --git a/mock_unpacker_test.go b/mock_unpacker_test.go index a144fb4c..272585c0 100644 --- a/mock_unpacker_test.go +++ b/mock_unpacker_test.go @@ -8,9 +8,9 @@ import ( reflect "reflect" time "time" - gomock "github.com/golang/mock/gomock" protocol "github.com/quic-go/quic-go/internal/protocol" wire "github.com/quic-go/quic-go/internal/wire" + gomock "go.uber.org/mock/gomock" ) // MockUnpacker is a mock of Unpacker interface. diff --git a/mockgen.go b/mockgen.go index 221c1367..ea0aa58b 100644 --- a/mockgen.go +++ b/mockgen.go @@ -2,76 +2,76 @@ package quic -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn" type SendConn = sendConn -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn" type RawConn = rawConn -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender" type Sender = sender -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI" type StreamI = streamI -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_stream_test.go github.com/quic-go/quic-go CryptoStream" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_stream_test.go github.com/quic-go/quic-go CryptoStream" type CryptoStream = cryptoStream -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI" type ReceiveStreamI = receiveStreamI -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI" type SendStreamI = sendStreamI -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_getter_test.go github.com/quic-go/quic-go StreamGetter" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_getter_test.go github.com/quic-go/quic-go StreamGetter" type StreamGetter = streamGetter -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender" type StreamSender = streamSender -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_data_handler_test.go github.com/quic-go/quic-go CryptoDataHandler" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_data_handler_test.go github.com/quic-go/quic-go CryptoDataHandler" type CryptoDataHandler = cryptoDataHandler -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource" type FrameSource = frameSource -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource" type AckFrameSource = ackFrameSource -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager" type StreamManager = streamManager -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager" type SealingManager = sealingManager -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker" type Unpacker = unpacker -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer" type Packer = packer -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer" type MTUDiscoverer = mtuDiscoverer -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner" type ConnRunner = connRunner -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn" type QUICConn = quicConn -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler" type PacketHandler = packetHandler -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unknown_packet_handler_test.go github.com/quic-go/quic-go UnknownPacketHandler" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unknown_packet_handler_test.go github.com/quic-go/quic-go UnknownPacketHandler" type UnknownPacketHandler = unknownPacketHandler -//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_manager_test.go github.com/quic-go/quic-go PacketHandlerManager" +//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_manager_test.go github.com/quic-go/quic-go PacketHandlerManager" type PacketHandlerManager = packetHandlerManager // Need to use source mode for the batchConn, since reflect mode follows type aliases. // See https://github.com/golang/mock/issues/244 for details. // -//go:generate sh -c "go run github.com/golang/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -source sys_conn_oob.go -destination mock_batch_conn_test.go -mock_names batchConn=MockBatchConn" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -source sys_conn_oob.go -destination mock_batch_conn_test.go -mock_names batchConn=MockBatchConn" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore" -//go:generate sh -c "go run github.com/golang/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore" +//go:generate sh -c "go run go.uber.org/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn" diff --git a/packet_packer_test.go b/packet_packer_test.go index 38ced47a..6dba31f9 100644 --- a/packet_packer_test.go +++ b/packet_packer_test.go @@ -18,10 +18,9 @@ import ( "github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Packet packer", func() { diff --git a/packet_unpacker_test.go b/packet_unpacker_test.go index 927635cb..035a431d 100644 --- a/packet_unpacker_test.go +++ b/packet_unpacker_test.go @@ -10,9 +10,9 @@ import ( "github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Packet Unpacker", func() { diff --git a/quic_suite_test.go b/quic_suite_test.go index d979d81b..954ca60b 100644 --- a/quic_suite_test.go +++ b/quic_suite_test.go @@ -9,9 +9,9 @@ import ( "sync" "testing" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func TestQuicGo(t *testing.T) { diff --git a/receive_stream_test.go b/receive_stream_test.go index f3c515e6..f688433d 100644 --- a/receive_stream_test.go +++ b/receive_stream_test.go @@ -12,10 +12,10 @@ import ( "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" + "go.uber.org/mock/gomock" ) var _ = Describe("Receive Stream", func() { diff --git a/send_conn_test.go b/send_conn_test.go index 024a8eba..7f072430 100644 --- a/send_conn_test.go +++ b/send_conn_test.go @@ -6,9 +6,9 @@ import ( "github.com/quic-go/quic-go/internal/utils" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) // Only if appendUDPSegmentSizeMsg actually appends a message (and isn't only a stub implementation), diff --git a/send_queue_test.go b/send_queue_test.go index 5a9e6598..69562c58 100644 --- a/send_queue_test.go +++ b/send_queue_test.go @@ -5,9 +5,9 @@ import ( "github.com/quic-go/quic-go/internal/protocol" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Send Queue", func() { diff --git a/send_stream_test.go b/send_stream_test.go index 3356b420..ad1d0469 100644 --- a/send_stream_test.go +++ b/send_stream_test.go @@ -11,7 +11,6 @@ import ( "golang.org/x/exp/rand" - "github.com/golang/mock/gomock" "github.com/quic-go/quic-go/internal/ackhandler" "github.com/quic-go/quic-go/internal/mocks" "github.com/quic-go/quic-go/internal/protocol" @@ -20,6 +19,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" + "go.uber.org/mock/gomock" ) var _ = Describe("Send Stream", func() { diff --git a/server_test.go b/server_test.go index 2ba39cf5..4705225a 100644 --- a/server_test.go +++ b/server_test.go @@ -20,9 +20,9 @@ import ( "github.com/quic-go/quic-go/internal/wire" "github.com/quic-go/quic-go/logging" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Server", func() { diff --git a/streams_map_incoming_test.go b/streams_map_incoming_test.go index c3366542..b5abba51 100644 --- a/streams_map_incoming_test.go +++ b/streams_map_incoming_test.go @@ -10,9 +10,9 @@ import ( "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) type mockGenericStream struct { diff --git a/streams_map_outgoing_test.go b/streams_map_outgoing_test.go index 7b4b28c3..b4b2e25b 100644 --- a/streams_map_outgoing_test.go +++ b/streams_map_outgoing_test.go @@ -13,9 +13,9 @@ import ( "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/wire" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Streams Map (outgoing)", func() { diff --git a/streams_map_test.go b/streams_map_test.go index 6300ea8d..77ee4aa8 100644 --- a/streams_map_test.go +++ b/streams_map_test.go @@ -6,8 +6,6 @@ import ( "fmt" "net" - "github.com/golang/mock/gomock" - "github.com/quic-go/quic-go/internal/flowcontrol" "github.com/quic-go/quic-go/internal/mocks" "github.com/quic-go/quic-go/internal/protocol" @@ -16,6 +14,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) func (e streamError) TestError() error { diff --git a/sys_conn_oob_test.go b/sys_conn_oob_test.go index 30b333b9..3ae97ed9 100644 --- a/sys_conn_oob_test.go +++ b/sys_conn_oob_test.go @@ -13,9 +13,9 @@ import ( "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/utils" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("OOB Conn Test", func() { diff --git a/sys_conn_test.go b/sys_conn_test.go index 418e2c31..5eb0417a 100644 --- a/sys_conn_test.go +++ b/sys_conn_test.go @@ -6,10 +6,9 @@ import ( "github.com/quic-go/quic-go/internal/protocol" - "github.com/golang/mock/gomock" - . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Basic Conn Test", func() { diff --git a/tools.go b/tools.go index e848317f..d00ce748 100644 --- a/tools.go +++ b/tools.go @@ -3,6 +3,6 @@ package quic import ( - _ "github.com/golang/mock/mockgen" _ "github.com/onsi/ginkgo/v2/ginkgo" + _ "go.uber.org/mock/mockgen" ) diff --git a/transport_test.go b/transport_test.go index cf38e325..14c6fdbb 100644 --- a/transport_test.go +++ b/transport_test.go @@ -15,9 +15,9 @@ import ( "github.com/quic-go/quic-go/internal/wire" "github.com/quic-go/quic-go/logging" - "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" ) var _ = Describe("Transport", func() {