From c0d4f00b2089e10975d6928384ed493bce473912 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 27 Aug 2018 15:51:44 +0700 Subject: [PATCH] implement gQUIC 44 --- client.go | 88 +++++++++++++------------ client_test.go | 141 ++++++++++++++++++++++++++++++++++------- packet_handler_map.go | 2 +- server.go | 21 ++++-- server_session.go | 2 +- server_session_test.go | 4 +- server_test.go | 28 ++++++-- session.go | 28 ++++---- session_test.go | 3 + 9 files changed, 225 insertions(+), 92 deletions(-) diff --git a/client.go b/client.go index 31db6a74..71e72dce 100644 --- a/client.go +++ b/client.go @@ -128,6 +128,13 @@ func dialContext( createdPacketConn bool, ) (Session, error) { config = populateClientConfig(config, createdPacketConn) + if !createdPacketConn { + for _, v := range config.Versions { + if v == protocol.Version44 { + return nil, errors.New("Cannot multiplex connections using gQUIC 44, see https://groups.google.com/a/chromium.org/forum/#!topic/proto-quic/pE9NlLLjizE. Please disable gQUIC 44 in the quic.Config, or use DialAddr") + } + } + } packetHandlers, err := getMultiplexer().AddConn(pconn, config.ConnectionIDLength) if err != nil { return nil, err @@ -234,6 +241,11 @@ func populateClientConfig(config *Config, createdPacketConn bool) *Config { if connIDLen == 0 && !createdPacketConn { connIDLen = protocol.DefaultConnectionIDLength } + for _, v := range versions { + if v == protocol.Version44 { + connIDLen = 0 + } + } return &Config{ Versions: versions, @@ -267,6 +279,9 @@ func (c *client) generateConnectionIDs() error { } c.srcConnID = srcConnID c.destConnID = destConnID + if c.version == protocol.Version44 { + c.srcConnID = nil + } return nil } @@ -372,23 +387,32 @@ func (c *client) handlePacketImpl(p *receivedPacket) error { return err } - if p.header.IsPublicHeader { - return c.handleGQUICPacket(p) + if !c.version.UsesIETFHeaderFormat() { + connID := p.header.DestConnectionID + // reject packets with truncated connection id if we didn't request truncation + if !c.config.RequestConnectionIDOmission && connID.Len() == 0 { + return errors.New("received packet with truncated connection ID, but didn't request truncation") + } + // reject packets with the wrong connection ID + if connID.Len() > 0 && !connID.Equal(c.srcConnID) { + return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", connID, c.srcConnID) + } + if p.header.ResetFlag { + return c.handlePublicReset(p) + } + } else { + // reject packets with the wrong connection ID + if !p.header.DestConnectionID.Equal(c.srcConnID) { + return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", p.header.DestConnectionID, c.srcConnID) + } } - return c.handleIETFQUICPacket(p) -} -func (c *client) handleIETFQUICPacket(p *receivedPacket) error { - // reject packets with the wrong connection ID - if !p.header.DestConnectionID.Equal(c.srcConnID) { - return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", p.header.DestConnectionID, c.srcConnID) - } if p.header.IsLongHeader { switch p.header.Type { case protocol.PacketTypeRetry: c.handleRetryPacket(p.header) return nil - case protocol.PacketTypeHandshake: + case protocol.PacketTypeHandshake, protocol.PacketType0RTT: default: return fmt.Errorf("Received unsupported packet type: %s", p.header.Type) } @@ -404,40 +428,19 @@ func (c *client) handleIETFQUICPacket(p *receivedPacket) error { return nil } -func (c *client) handleGQUICPacket(p *receivedPacket) error { - connID := p.header.DestConnectionID - // reject packets with truncated connection id if we didn't request truncation - if !c.config.RequestConnectionIDOmission && connID.Len() == 0 { - return errors.New("received packet with truncated connection ID, but didn't request truncation") +func (c *client) handlePublicReset(p *receivedPacket) error { + cr := c.conn.RemoteAddr() + // check if the remote address and the connection ID match + // otherwise this might be an attacker trying to inject a PUBLIC_RESET to kill the connection + if cr.Network() != p.remoteAddr.Network() || cr.String() != p.remoteAddr.String() || !p.header.DestConnectionID.Equal(c.srcConnID) { + return errors.New("Received a spoofed Public Reset") } - // reject packets with the wrong connection ID - if connID.Len() > 0 && !connID.Equal(c.srcConnID) { - return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", connID, c.srcConnID) + pr, err := wire.ParsePublicReset(bytes.NewReader(p.data)) + if err != nil { + return fmt.Errorf("Received a Public Reset. An error occurred parsing the packet: %s", err) } - - if p.header.ResetFlag { - cr := c.conn.RemoteAddr() - // check if the remote address and the connection ID match - // otherwise this might be an attacker trying to inject a PUBLIC_RESET to kill the connection - if cr.Network() != p.remoteAddr.Network() || cr.String() != p.remoteAddr.String() || !connID.Equal(c.srcConnID) { - return errors.New("Received a spoofed Public Reset") - } - pr, err := wire.ParsePublicReset(bytes.NewReader(p.data)) - if err != nil { - return fmt.Errorf("Received a Public Reset. An error occurred parsing the packet: %s", err) - } - c.session.closeRemote(qerr.Error(qerr.PublicReset, fmt.Sprintf("Received a Public Reset for packet number %#x", pr.RejectedPacketNumber))) - c.logger.Infof("Received Public Reset, rejected packet number: %#x", pr.RejectedPacketNumber) - return nil - } - - // this is the first packet we are receiving - // since it is not a Version Negotiation Packet, this means the server supports the suggested version - if !c.versionNegotiated { - c.versionNegotiated = true - } - - c.session.handlePacket(p) + c.session.closeRemote(qerr.Error(qerr.PublicReset, fmt.Sprintf("Received a Public Reset for packet number %#x", pr.RejectedPacketNumber))) + c.logger.Infof("Received Public Reset, rejected packet number: %#x", pr.RejectedPacketNumber) return nil } @@ -513,6 +516,7 @@ func (c *client) createNewGQUICSession() error { c.hostname, c.version, c.destConnID, + c.srcConnID, c.tlsConf, c.config, c.initialVersion, diff --git a/client_test.go b/client_test.go index 8a7067ce..ef39eec2 100644 --- a/client_test.go +++ b/client_test.go @@ -31,7 +31,9 @@ var _ = Describe("Client", func() { mockMultiplexer *MockMultiplexer origMultiplexer multiplexer - originalClientSessConstructor func(connection, sessionRunner, string, protocol.VersionNumber, protocol.ConnectionID, *tls.Config, *Config, protocol.VersionNumber, []protocol.VersionNumber, utils.Logger) (quicSession, error) + supportedVersionsWithoutGQUIC44 []protocol.VersionNumber + + originalClientSessConstructor func(connection, sessionRunner, string, protocol.VersionNumber, protocol.ConnectionID, protocol.ConnectionID, *tls.Config, *Config, protocol.VersionNumber, []protocol.VersionNumber, utils.Logger) (quicSession, error) ) // generate a packet sent by the server that accepts the QUIC version suggested by the client @@ -78,6 +80,12 @@ var _ = Describe("Client", func() { mockMultiplexer = NewMockMultiplexer(mockCtrl) origMultiplexer = connMuxer connMuxer = mockMultiplexer + for _, v := range protocol.SupportedVersions { + if v != protocol.Version44 { + supportedVersionsWithoutGQUIC44 = append(supportedVersionsWithoutGQUIC44, v) + } + } + Expect(supportedVersionsWithoutGQUIC44).ToNot(BeEmpty()) }) AfterEach(func() { @@ -114,7 +122,7 @@ var _ = Describe("Client", func() { It("resolves the address", func() { manager := NewMockPacketHandlerManager(mockCtrl) - manager.EXPECT().Add(connID, gomock.Any()) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil) if os.Getenv("APPVEYOR") == "True" { @@ -127,6 +135,7 @@ var _ = Describe("Client", func() { _ string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -145,7 +154,7 @@ var _ = Describe("Client", func() { It("uses the tls.Config.ServerName as the hostname, if present", func() { manager := NewMockPacketHandlerManager(mockCtrl) - manager.EXPECT().Add(connID, gomock.Any()) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil) hostnameChan := make(chan string, 1) @@ -155,6 +164,7 @@ var _ = Describe("Client", func() { h string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -173,7 +183,7 @@ var _ = Describe("Client", func() { It("returns after the handshake is complete", func() { manager := NewMockPacketHandlerManager(mockCtrl) - manager.EXPECT().Add(connID, gomock.Any()) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) run := make(chan struct{}) @@ -183,6 +193,7 @@ var _ = Describe("Client", func() { _ string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -194,15 +205,33 @@ var _ = Describe("Client", func() { runner.onHandshakeComplete(sess) return sess, nil } - s, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, nil) + s, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) Expect(err).ToNot(HaveOccurred()) Expect(s).ToNot(BeNil()) Eventually(run).Should(BeClosed()) }) + It("refuses to multiplex gQUIC 44", func() { + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: []protocol.VersionNumber{protocol.Version44}}, + ) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Cannot multiplex connections using gQUIC 44")) + }) + It("returns an error that occurs while waiting for the connection to become secure", func() { manager := NewMockPacketHandlerManager(mockCtrl) - manager.EXPECT().Add(connID, gomock.Any()) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) testErr := errors.New("early handshake error") @@ -212,6 +241,7 @@ var _ = Describe("Client", func() { _ string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -223,13 +253,19 @@ var _ = Describe("Client", func() { return sess, nil } packetConn.dataToRead <- acceptClientVersionPacket(cl.srcConnID) - _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, nil) + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) Expect(err).To(MatchError(testErr)) }) It("closes the session when the context is canceled", func() { manager := NewMockPacketHandlerManager(mockCtrl) - manager.EXPECT().Add(connID, gomock.Any()) + manager.EXPECT().Add(gomock.Any(), gomock.Any()) mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) sessionRunning := make(chan struct{}) @@ -244,6 +280,7 @@ var _ = Describe("Client", func() { _ string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -256,7 +293,14 @@ var _ = Describe("Client", func() { dialed := make(chan struct{}) go func() { defer GinkgoRecover() - _, err := DialContext(ctx, packetConn, addr, "quic.clemnte.io:1337", nil, nil) + _, err := DialContext( + ctx, + packetConn, + addr, + "quic.clemnte.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) Expect(err).To(MatchError(context.Canceled)) close(dialed) }() @@ -279,7 +323,8 @@ var _ = Describe("Client", func() { runnerP sessionRunner, _ string, _ protocol.VersionNumber, - connID protocol.ConnectionID, + _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -293,7 +338,14 @@ var _ = Describe("Client", func() { runner.removeConnectionID(connID) }) - _, err := DialContext(context.Background(), packetConn, addr, "quic.clemnte.io:1337", nil, nil) + _, err := DialContext( + context.Background(), + packetConn, + addr, + "quic.clemnte.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) Expect(err).ToNot(HaveOccurred()) }) @@ -311,7 +363,8 @@ var _ = Describe("Client", func() { _ sessionRunner, _ string, _ protocol.VersionNumber, - connID protocol.ConnectionID, + _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -358,6 +411,7 @@ var _ = Describe("Client", func() { MaxIncomingStreams: 1234, MaxIncomingUniStreams: 4321, ConnectionIDLength: 13, + Versions: supportedVersionsWithoutGQUIC44, } c := populateClientConfig(config, false) Expect(c.HandshakeTimeout).To(Equal(1337 * time.Minute)) @@ -368,6 +422,22 @@ var _ = Describe("Client", func() { Expect(c.ConnectionIDLength).To(Equal(13)) }) + It("uses a 0 byte connection IDs if gQUIC 44 is supported", func() { + config := &Config{ + Versions: []protocol.VersionNumber{protocol.Version43, protocol.Version44}, + ConnectionIDLength: 13, + } + c := populateClientConfig(config, false) + Expect(c.Versions).To(Equal([]protocol.VersionNumber{protocol.Version43, protocol.Version44})) + Expect(c.ConnectionIDLength).To(BeZero()) + }) + + It("doesn't use 0-byte connection IDs when dialing an address", func() { + config := &Config{Versions: supportedVersionsWithoutGQUIC44} + c := populateClientConfig(config, false) + Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength)) + }) + It("errors when the Config contains an invalid version", func() { manager := NewMockPacketHandlerManager(mockCtrl) mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) @@ -403,12 +473,6 @@ var _ = Describe("Client", func() { Expect(c.ConnectionIDLength).To(BeZero()) }) - It("doesn't use 0-byte connection IDs when dialing an address", func() { - config := &Config{} - c := populateClientConfig(config, false) - Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength)) - }) - It("fills in default values if options are not set in the Config", func() { c := populateClientConfig(&Config{}, false) Expect(c.Versions).To(Equal(protocol.SupportedVersions)) @@ -430,6 +494,7 @@ var _ = Describe("Client", func() { _ string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -438,7 +503,13 @@ var _ = Describe("Client", func() { ) (quicSession, error) { return nil, testErr } - _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, nil) + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) Expect(err).To(MatchError(testErr)) }) }) @@ -615,6 +686,7 @@ var _ = Describe("Client", func() { _ string, _ protocol.VersionNumber, _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -626,7 +698,13 @@ var _ = Describe("Client", func() { sess.EXPECT().run().Return(testErr) return sess, nil } - _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, nil) + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + &Config{Versions: supportedVersionsWithoutGQUIC44}, + ) Expect(err).To(MatchError(testErr)) }) @@ -634,6 +712,7 @@ var _ = Describe("Client", func() { sess := NewMockQuicSession(mockCtrl) sess.EXPECT().handlePacket(gomock.Any()) cl.session = sess + cl.config = &Config{} ph := &wire.Header{ PacketNumber: 1, PacketNumberLen: protocol.PacketNumberLen2, @@ -667,7 +746,8 @@ var _ = Describe("Client", func() { _ sessionRunner, _ string, _ protocol.VersionNumber, - connectionID protocol.ConnectionID, + _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -713,7 +793,8 @@ var _ = Describe("Client", func() { _ sessionRunner, _ string, _ protocol.VersionNumber, - connectionID protocol.ConnectionID, + _ protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, _ *Config, _ protocol.VersionNumber, @@ -786,6 +867,7 @@ var _ = Describe("Client", func() { }) It("ignores packets with the wrong Long Header Type", func() { + cl.config = &Config{} hdr := &wire.Header{ IsLongHeader: true, Type: protocol.PacketTypeInitial, @@ -804,6 +886,7 @@ var _ = Describe("Client", func() { }) It("ignores packets without connection id, if it didn't request connection id trunctation", func() { + cl.version = versionGQUICFrames cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls cl.config = &Config{RequestConnectionIDOmission: false} hdr := &wire.Header{ @@ -843,7 +926,6 @@ var _ = Describe("Client", func() { manager.EXPECT().Add(gomock.Any(), gomock.Any()) mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil) - config := &Config{Versions: protocol.SupportedVersions} c := make(chan struct{}) var cconn connection var hostname string @@ -855,6 +937,7 @@ var _ = Describe("Client", func() { hostnameP string, versionP protocol.VersionNumber, connIDP protocol.ConnectionID, + _ protocol.ConnectionID, _ *tls.Config, configP *Config, _ protocol.VersionNumber, @@ -872,7 +955,14 @@ var _ = Describe("Client", func() { return sess, nil } - _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config) + config := &Config{Versions: supportedVersionsWithoutGQUIC44} + _, err := Dial( + packetConn, + addr, + "quic.clemente.io:1337", + nil, + config, + ) Expect(err).ToNot(HaveOccurred()) Eventually(c).Should(BeClosed()) Expect(cconn.(*conn).pconn).To(Equal(packetConn)) @@ -901,6 +991,7 @@ var _ = Describe("Client", func() { }) It("closes the session when receiving a Public Reset", func() { + cl.version = versionGQUICFrames sess := NewMockQuicSession(mockCtrl) sess.EXPECT().closeRemote(gomock.Any()).Do(func(err error) { Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.PublicReset)) @@ -914,6 +1005,7 @@ var _ = Describe("Client", func() { }) It("ignores Public Resets from the wrong remote address", func() { + cl.version = versionGQUICFrames cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls spoofedAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 5678} err := cl.handlePacketImpl(&receivedPacket{ @@ -925,6 +1017,7 @@ var _ = Describe("Client", func() { }) It("ignores unparseable Public Resets", func() { + cl.version = versionGQUICFrames cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls err := cl.handlePacketImpl(&receivedPacket{ remoteAddr: addr, diff --git a/packet_handler_map.go b/packet_handler_map.go index fef9468e..35f9bdfa 100644 --- a/packet_handler_map.go +++ b/packet_handler_map.go @@ -180,7 +180,7 @@ func (h *packetHandlerMap) handlePacket(addr net.Addr, data []byte) error { hdr.Raw = data[:len(data)-r.Len()] packetData := data[len(data)-r.Len():] - if hdr.IsLongHeader { + if hdr.IsLongHeader && hdr.Version.UsesLengthInHeader() { if protocol.ByteCount(len(packetData)) < hdr.PayloadLen { return fmt.Errorf("packet payload (%d bytes) is smaller than the expected payload length (%d bytes)", len(packetData), hdr.PayloadLen) } diff --git a/server.go b/server.go index 9b72078d..d9af6a43 100644 --- a/server.go +++ b/server.go @@ -89,7 +89,7 @@ type server struct { sessionRunner sessionRunner // set as a member, so they can be set in the tests - newSession func(connection, sessionRunner, protocol.VersionNumber, protocol.ConnectionID, *handshake.ServerConfig, *tls.Config, *Config, utils.Logger) (quicSession, error) + newSession func(connection, sessionRunner, protocol.VersionNumber, protocol.ConnectionID, protocol.ConnectionID, *handshake.ServerConfig, *tls.Config, *Config, utils.Logger) (quicSession, error) logger utils.Logger } @@ -269,6 +269,11 @@ func populateServerConfig(config *Config) *Config { if connIDLen == 0 { connIDLen = protocol.DefaultConnectionIDLength } + for _, v := range versions { + if v == protocol.Version44 { + connIDLen = protocol.ConnectionIDLenGQUIC + } + } return &Config{ Versions: versions, @@ -351,13 +356,13 @@ func (s *server) handlePacketImpl(p *receivedPacket) error { return s.sendVersionNegotiationPacket(p) } } - if hdr.Type == protocol.PacketTypeInitial { + if hdr.Type == protocol.PacketTypeInitial && hdr.Version.UsesTLS() { go s.serverTLS.HandleInitial(p) return nil } // TODO(#943): send Stateless Reset, if this an IETF QUIC packet - if !hdr.VersionFlag { + if !hdr.VersionFlag && !hdr.Version.UsesIETFHeaderFormat() { _, err := s.conn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), p.remoteAddr) return err } @@ -368,12 +373,20 @@ func (s *server) handlePacketImpl(p *receivedPacket) error { return errors.New("dropping small packet for unknown connection") } + var destConnID, srcConnID protocol.ConnectionID + if hdr.Version.UsesIETFHeaderFormat() { + srcConnID = hdr.DestConnectionID + } else { + destConnID = hdr.DestConnectionID + srcConnID = hdr.DestConnectionID + } s.logger.Infof("Serving new connection: %s, version %s from %v", hdr.DestConnectionID, hdr.Version, p.remoteAddr) sess, err := s.newSession( &conn{pconn: s.conn, currentAddr: p.remoteAddr}, s.sessionRunner, hdr.Version, - hdr.DestConnectionID, + destConnID, + srcConnID, s.scfg, s.tlsConf, s.config, diff --git a/server_session.go b/server_session.go index 6c7dd81c..51743b3a 100644 --- a/server_session.go +++ b/server_session.go @@ -46,7 +46,7 @@ func (s *serverSession) handlePacketImpl(p *receivedPacket) error { if hdr.IsLongHeader { switch hdr.Type { - case protocol.PacketTypeHandshake: + case protocol.PacketTypeHandshake, protocol.PacketType0RTT: // 0-RTT accepted for gQUIC 44 // nothing to do here. Packet will be passed to the session. default: // Note that this also drops 0-RTT packets. diff --git a/server_session_test.go b/server_session_test.go index 426ca9ad..4486d7e4 100644 --- a/server_session_test.go +++ b/server_session_test.go @@ -72,13 +72,13 @@ var _ = Describe("Server Session", func() { p := &receivedPacket{ header: &wire.Header{ IsLongHeader: true, - Type: protocol.PacketType0RTT, + Type: protocol.PacketTypeRetry, Version: protocol.VersionNumber(100), DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}, }, } err := sess.handlePacketImpl(p) - Expect(err).To(MatchError("Received unsupported packet type: 0-RTT Protected")) + Expect(err).To(MatchError("Received unsupported packet type: Retry")) }) It("passes on Handshake packets", func() { diff --git a/server_test.go b/server_test.go index d1f5d231..387ec665 100644 --- a/server_test.go +++ b/server_test.go @@ -50,6 +50,7 @@ var _ = Describe("Server", func() { MaxIncomingStreams: 1234, MaxIncomingUniStreams: 4321, ConnectionIDLength: 12, + Versions: []protocol.VersionNumber{VersionGQUIC43}, } c := populateServerConfig(config) Expect(c.HandshakeTimeout).To(Equal(1337 * time.Minute)) @@ -58,6 +59,25 @@ var _ = Describe("Server", func() { Expect(c.MaxIncomingStreams).To(Equal(1234)) Expect(c.MaxIncomingUniStreams).To(Equal(4321)) Expect(c.ConnectionIDLength).To(Equal(12)) + Expect(c.Versions).To(Equal([]protocol.VersionNumber{VersionGQUIC43})) + }) + + It("uses 8 byte connection IDs if gQUIC 44 is supported", func() { + config := &Config{ + Versions: []protocol.VersionNumber{protocol.Version43, protocol.Version44}, + ConnectionIDLength: 13, + } + c := populateServerConfig(config) + Expect(c.Versions).To(Equal([]protocol.VersionNumber{protocol.Version43, protocol.Version44})) + Expect(c.ConnectionIDLength).To(Equal(8)) + }) + + It("uses 4 byte connection IDs by default, if gQUIC 44 is not supported", func() { + config := &Config{ + Versions: []protocol.VersionNumber{protocol.Version39}, + } + c := populateServerConfig(config) + Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength)) }) It("disables bidirectional streams", func() { @@ -79,12 +99,6 @@ var _ = Describe("Server", func() { Expect(c.MaxIncomingStreams).To(Equal(1234)) Expect(c.MaxIncomingUniStreams).To(BeZero()) }) - - It("doesn't use 0-byte connection IDs", func() { - config := &Config{} - c := populateServerConfig(config) - Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength)) - }) }) Context("with mock session", func() { @@ -103,6 +117,7 @@ var _ = Describe("Server", func() { runner sessionRunner, _ protocol.VersionNumber, connID protocol.ConnectionID, + _ protocol.ConnectionID, _ *handshake.ServerConfig, _ *tls.Config, _ *Config, @@ -322,6 +337,7 @@ var _ = Describe("Server", func() { remoteAddr: udpAddr, header: &wire.Header{ IsPublicHeader: true, + Version: versionGQUICFrames, }, }) Expect(err).ToNot(HaveOccurred()) diff --git a/session.go b/session.go index 0c2c5a80..81422d1f 100644 --- a/session.go +++ b/session.go @@ -152,19 +152,21 @@ func newSession( conn connection, sessionRunner sessionRunner, v protocol.VersionNumber, - connectionID protocol.ConnectionID, + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, scfg *handshake.ServerConfig, tlsConf *tls.Config, config *Config, logger utils.Logger, ) (quicSession, error) { + logger.Debugf("Creating new session. Destination Connection ID: %s, Source Connection ID: %s", destConnID, srcConnID) paramsChan := make(chan handshake.TransportParameters) handshakeEvent := make(chan struct{}, 1) s := &session{ conn: conn, sessionRunner: sessionRunner, - srcConnID: connectionID, - destConnID: connectionID, + srcConnID: srcConnID, + destConnID: destConnID, perspective: protocol.PerspectiveServer, version: v, config: config, @@ -185,7 +187,7 @@ func newSession( } cs, err := newCryptoSetup( s.cryptoStream, - connectionID, + srcConnID, s.conn.RemoteAddr(), s.version, divNonce, @@ -205,8 +207,8 @@ func newSession( s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective) s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) s.packer = newPacketPacker( - connectionID, - nil, // no src connection ID + destConnID, + srcConnID, 1, s.sentPacketHandler.GetPacketNumberLen, s.RemoteAddr(), @@ -226,20 +228,22 @@ var newClientSession = func( sessionRunner sessionRunner, hostname string, v protocol.VersionNumber, - connectionID protocol.ConnectionID, + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, tlsConf *tls.Config, config *Config, initialVersion protocol.VersionNumber, negotiatedVersions []protocol.VersionNumber, // needed for validation of the GQUIC version negotiation logger utils.Logger, ) (quicSession, error) { + logger.Debugf("Creating new session. Destination Connection ID: %s, Source Connection ID: %s", destConnID, srcConnID) paramsChan := make(chan handshake.TransportParameters) handshakeEvent := make(chan struct{}, 1) s := &session{ conn: conn, sessionRunner: sessionRunner, - srcConnID: connectionID, - destConnID: connectionID, + srcConnID: srcConnID, + destConnID: destConnID, perspective: protocol.PerspectiveClient, version: v, config: config, @@ -258,7 +262,7 @@ var newClientSession = func( cs, err := newCryptoSetupClient( s.cryptoStream, hostname, - connectionID, + destConnID, s.version, tlsConf, transportParams, @@ -276,8 +280,8 @@ var newClientSession = func( s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective) s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) s.packer = newPacketPacker( - connectionID, - nil, // no src connection ID + destConnID, + srcConnID, 1, s.sentPacketHandler.GetPacketNumberLen, s.RemoteAddr(), diff --git a/session_test.go b/session_test.go index bef8ad6f..a2906046 100644 --- a/session_test.go +++ b/session_test.go @@ -111,6 +111,7 @@ var _ = Describe("Session", func() { sessionRunner, protocol.Version39, protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, scfg, nil, populateServerConfig(&Config{}), @@ -165,6 +166,7 @@ var _ = Describe("Session", func() { sessionRunner, protocol.Version39, protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, scfg, nil, conf, @@ -1746,6 +1748,7 @@ var _ = Describe("Client Session", func() { "hostname", protocol.Version39, protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, nil, populateClientConfig(&Config{}, false), protocol.VersionWhatever,