From 683b5823e4e38de37d82b7d51997b193decd6ddc Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 7 May 2018 13:24:43 +0900 Subject: [PATCH 1/3] handle gQUIC and IETF QUIC packets separately in the client --- client.go | 64 +++++++++++++++++++++++++----------- client_test.go | 1 + internal/wire/header.go | 11 +++---- internal/wire/header_test.go | 20 +++++------ 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/client.go b/client.go index e03f822b..7ffabd69 100644 --- a/client.go +++ b/client.go @@ -316,6 +316,35 @@ func (c *client) handlePacket(remoteAddr net.Addr, packet []byte) error { hdr.Raw = packet[:len(packet)-r.Len()] packetData := packet[len(packet)-r.Len():] + c.mutex.Lock() + defer c.mutex.Unlock() + + // handle Version Negotiation Packets + if hdr.IsVersionNegotiation { + // ignore delayed / duplicated version negotiation packets + if c.receivedVersionNegotiationPacket || c.versionNegotiated { + return errors.New("received a delayed Version Negotiation Packet") + } + + // version negotiation packets have no payload + if err := c.handleVersionNegotiationPacket(hdr); err != nil { + c.session.Close(err) + } + return nil + } + + if hdr.IsPublicHeader { + return c.handleGQUICPacket(hdr, r, packetData, remoteAddr, rcvTime) + } + return c.handleIETFQUICPacket(hdr, packetData, remoteAddr, rcvTime) +} + +func (c *client) handleIETFQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error { + // TODO(#1003): add support for server-chosen connection IDs + // reject packets with the wrong connection ID + if !hdr.DestConnectionID.Equal(c.srcConnID) { + return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", hdr.DestConnectionID, c.srcConnID) + } if hdr.IsLongHeader { c.logger.Debugf("len(packet data): %d, payloadLen: %d", len(packetData), hdr.PayloadLen) if protocol.ByteCount(len(packetData)) < hdr.PayloadLen { @@ -325,11 +354,24 @@ func (c *client) handlePacket(remoteAddr net.Addr, packet []byte) error { // TODO(#1312): implement parsing of compound packets } - c.mutex.Lock() - defer c.mutex.Unlock() + // 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 + close(c.versionNegotiationChan) + } + c.session.handlePacket(&receivedPacket{ + remoteAddr: remoteAddr, + header: hdr, + data: packetData, + rcvTime: rcvTime, + }) + return nil +} + +func (c *client) handleGQUICPacket(hdr *wire.Header, r *bytes.Reader, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error { // reject packets with the wrong connection ID - // TODO(#1003): add support for server-chosen connection IDs if !hdr.OmitConnectionID && !hdr.DestConnectionID.Equal(c.srcConnID) { return fmt.Errorf("received a packet with an unexpected connection ID (%s, expected %s)", hdr.DestConnectionID, c.srcConnID) } @@ -350,20 +392,6 @@ func (c *client) handlePacket(remoteAddr net.Addr, packet []byte) error { return nil } - // handle Version Negotiation Packets - if hdr.IsVersionNegotiation { - // ignore delayed / duplicated version negotiation packets - if c.receivedVersionNegotiationPacket || c.versionNegotiated { - return errors.New("received a delayed Version Negotiation Packet") - } - - // version negotiation packets have no payload - if err := c.handleVersionNegotiationPacket(hdr); err != nil { - c.session.Close(err) - } - 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 { @@ -371,8 +399,6 @@ func (c *client) handlePacket(remoteAddr net.Addr, packet []byte) error { close(c.versionNegotiationChan) } - // TODO: validate packet number and connection ID on Retry packets (for IETF QUIC) - c.session.handlePacket(&receivedPacket{ remoteAddr: remoteAddr, header: hdr, diff --git a/client_test.go b/client_test.go index 6b5ad873..c22e3b4a 100644 --- a/client_test.go +++ b/client_test.go @@ -580,6 +580,7 @@ var _ = Describe("Client", func() { SrcConnectionID: connID, PacketNumber: 1, PacketNumberLen: 1, + Version: versionIETFFrames, }).Write(buf, protocol.PerspectiveServer, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) err = cl.handlePacket(addr, buf.Bytes()) diff --git a/internal/wire/header.go b/internal/wire/header.go index 1bc1897e..ec0ae24d 100644 --- a/internal/wire/header.go +++ b/internal/wire/header.go @@ -10,6 +10,8 @@ import ( // Header is the header of a QUIC packet. // It contains fields that are only needed for the gQUIC Public Header and the IETF draft Header. type Header struct { + IsPublicHeader bool + Raw []byte Version protocol.VersionNumber @@ -34,9 +36,6 @@ type Header struct { IsLongHeader bool KeyPhase int PayloadLen protocol.ByteCount - - // only needed for logging - isPublicHeader bool } // ParseHeaderSentByServer parses the header for a packet that was sent by the server. @@ -85,7 +84,7 @@ func parsePacketHeader(b *bytes.Reader, sentBy protocol.Perspective, isPublicHea if err != nil { return nil, err } - hdr.isPublicHeader = true // save that this is a Public Header, so we can log it correctly later + hdr.IsPublicHeader = true // save that this is a Public Header, so we can log it correctly later return hdr, nil } return parseHeader(b, sentBy) @@ -94,7 +93,7 @@ func parsePacketHeader(b *bytes.Reader, sentBy protocol.Perspective, isPublicHea // Write writes the Header. func (h *Header) Write(b *bytes.Buffer, pers protocol.Perspective, version protocol.VersionNumber) error { if !version.UsesTLS() { - h.isPublicHeader = true // save that this is a Public Header, so we can log it correctly later + h.IsPublicHeader = true // save that this is a Public Header, so we can log it correctly later return h.writePublicHeader(b, pers, version) } return h.writeHeader(b) @@ -110,7 +109,7 @@ func (h *Header) GetLength(pers protocol.Perspective, version protocol.VersionNu // Log logs the Header func (h *Header) Log(logger utils.Logger) { - if h.isPublicHeader { + if h.IsPublicHeader { h.logPublicHeader(logger) } else { h.logHeader(logger) diff --git a/internal/wire/header_test.go b/internal/wire/header_test.go index 4a30de32..24ebb92a 100644 --- a/internal/wire/header_test.go +++ b/internal/wire/header_test.go @@ -35,7 +35,7 @@ var _ = Describe("Header", func() { Expect(err).ToNot(HaveOccurred()) Expect(hdr.KeyPhase).To(BeEquivalentTo(1)) Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42))) - Expect(hdr.isPublicHeader).To(BeFalse()) + Expect(hdr.IsPublicHeader).To(BeFalse()) }) It("parses an IETF draft header, when the version is not known, but it has Long Header format", func() { @@ -53,7 +53,7 @@ var _ = Describe("Header", func() { Expect(err).ToNot(HaveOccurred()) Expect(hdr.Type).To(Equal(protocol.PacketType0RTT)) Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42))) - Expect(hdr.isPublicHeader).To(BeFalse()) + Expect(hdr.IsPublicHeader).To(BeFalse()) Expect(hdr.Version).To(Equal(protocol.VersionNumber(0x1234))) }) @@ -70,7 +70,7 @@ var _ = Describe("Header", func() { Expect(err).ToNot(HaveOccurred()) hdr, err := ParseHeaderSentByServer(bytes.NewReader(buf.Bytes()), versionIETFHeader) Expect(err).ToNot(HaveOccurred()) - Expect(hdr.isPublicHeader).To(BeFalse()) + Expect(hdr.IsPublicHeader).To(BeFalse()) }) It("parses a gQUIC Public Header, when the version is not known", func() { @@ -91,7 +91,7 @@ var _ = Describe("Header", func() { Expect(hdr.SrcConnectionID).To(Equal(connID)) Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1337))) Expect(hdr.Version).To(Equal(versionPublicHeader)) - Expect(hdr.isPublicHeader).To(BeTrue()) + Expect(hdr.IsPublicHeader).To(BeTrue()) }) It("parses a gQUIC Public Header, when the version is known", func() { @@ -111,7 +111,7 @@ var _ = Describe("Header", func() { Expect(hdr.SrcConnectionID).To(Equal(connID)) Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1337))) Expect(hdr.DiversificationNonce).To(HaveLen(32)) - Expect(hdr.isPublicHeader).To(BeTrue()) + Expect(hdr.IsPublicHeader).To(BeTrue()) }) It("errors when parsing the gQUIC header fails", func() { @@ -142,7 +142,7 @@ var _ = Describe("Header", func() { data := ComposeGQUICVersionNegotiation(connID, versions) hdr, err := ParseHeaderSentByServer(bytes.NewReader(data), protocol.VersionUnknown) Expect(err).ToNot(HaveOccurred()) - Expect(hdr.isPublicHeader).To(BeTrue()) + Expect(hdr.IsPublicHeader).To(BeTrue()) Expect(hdr.DestConnectionID).To(Equal(connID)) Expect(hdr.SrcConnectionID).To(Equal(connID)) // in addition to the versions, the supported versions might contain a reserved version number @@ -159,7 +159,7 @@ var _ = Describe("Header", func() { Expect(err).ToNot(HaveOccurred()) hdr, err := ParseHeaderSentByServer(bytes.NewReader(data), protocol.VersionUnknown) Expect(err).ToNot(HaveOccurred()) - Expect(hdr.isPublicHeader).To(BeFalse()) + Expect(hdr.IsPublicHeader).To(BeFalse()) Expect(hdr.IsVersionNegotiation).To(BeTrue()) Expect(hdr.DestConnectionID).To(Equal(destConnID)) Expect(hdr.SrcConnectionID).To(Equal(srcConnID)) @@ -184,7 +184,7 @@ var _ = Describe("Header", func() { Expect(err).ToNot(HaveOccurred()) _, err = parsePublicHeader(bytes.NewReader(buf.Bytes()), protocol.PerspectiveServer) Expect(err).ToNot(HaveOccurred()) - Expect(hdr.isPublicHeader).To(BeTrue()) + Expect(hdr.IsPublicHeader).To(BeTrue()) }) It("writes a IETF draft header", func() { @@ -200,7 +200,7 @@ var _ = Describe("Header", func() { Expect(err).ToNot(HaveOccurred()) _, err = parseHeader(bytes.NewReader(buf.Bytes()), protocol.PerspectiveServer) Expect(err).ToNot(HaveOccurred()) - Expect(hdr.isPublicHeader).To(BeFalse()) + Expect(hdr.IsPublicHeader).To(BeFalse()) }) }) @@ -278,7 +278,7 @@ var _ = Describe("Header", func() { It("logs a Public Header", func() { (&Header{ - isPublicHeader: true, + IsPublicHeader: true, DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, }).Log(logger) From f0b412aeb86cd138c7a13013fe6c539e572c87d3 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 8 May 2018 20:17:38 +0900 Subject: [PATCH 2/3] simplify handling of Public Resets in the server The server shouldn't receive any Public Resets. There is no need to attempt parsing them, since they are ignored anyway. --- server.go | 12 +----------- server_test.go | 20 +------------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/server.go b/server.go index 23e06b6d..4a2459eb 100644 --- a/server.go +++ b/server.go @@ -334,17 +334,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet // ignore all Public Reset packets if hdr.ResetFlag { - if sessionKnown { - var pr *wire.PublicReset - pr, err = wire.ParsePublicReset(r) - if err != nil { - s.logger.Infof("Received a Public Reset for connection %s. An error occurred parsing the packet.", hdr.DestConnectionID) - } else { - s.logger.Infof("Received a Public Reset for connection %s, rejected packet number: 0x%x.", hdr.DestConnectionID, pr.RejectedPacketNumber) - } - } else { - s.logger.Infof("Received Public Reset for unknown connection %s.", hdr.DestConnectionID) - } + s.logger.Infof("Received unexpected Public Reset for connection %s.", hdr.DestConnectionID) return nil } diff --git a/server_test.go b/server_test.go index d2bae1c0..339d0be5 100644 --- a/server_test.go +++ b/server_test.go @@ -419,13 +419,7 @@ var _ = Describe("Server", func() { Expect(serv.sessions[string(connID)].(*mockSession).handledPackets[1].data).To(HaveLen(123)) }) - It("ignores public resets for unknown connections", func() { - err := serv.handlePacket(nil, nil, wire.WritePublicReset([]byte{9, 9, 9, 9, 9, 9, 9, 9}, 1, 1337)) - Expect(err).ToNot(HaveOccurred()) - Expect(serv.sessions).To(BeEmpty()) - }) - - It("ignores public resets for known connections", func() { + It("ignores Public Resets", func() { err := serv.handlePacket(nil, nil, firstPacket) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) @@ -436,18 +430,6 @@ var _ = Describe("Server", func() { Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1)) }) - It("ignores invalid public resets for known connections", func() { - err := serv.handlePacket(nil, nil, firstPacket) - Expect(err).ToNot(HaveOccurred()) - Expect(serv.sessions).To(HaveLen(1)) - Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1)) - data := wire.WritePublicReset(connID, 1, 1337) - err = serv.handlePacket(nil, nil, data[:len(data)-2]) - Expect(err).ToNot(HaveOccurred()) - Expect(serv.sessions).To(HaveLen(1)) - Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1)) - }) - It("doesn't try to process a packet after sending a gQUIC Version Negotiation Packet", func() { config.Versions = []protocol.VersionNumber{99} b := &bytes.Buffer{} From 518e212924263f43f6ce7df6bc22a40c162068e2 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 8 May 2018 20:51:29 +0900 Subject: [PATCH 3/3] handle gQUIC and IETF QUIC packets separately in the server --- server.go | 59 ++++++++++++++++++++++++++++++++++++++------------ server_test.go | 59 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 86 insertions(+), 32 deletions(-) diff --git a/server.go b/server.go index 4a2459eb..1db582f2 100644 --- a/server.go +++ b/server.go @@ -247,7 +247,7 @@ func (s *server) serve() { return } data = data[:n] - if err := s.handlePacket(s.conn, remoteAddr, data); err != nil { + if err := s.handlePacket(remoteAddr, data); err != nil { s.logger.Errorf("error handling packet: %s", err.Error()) } } @@ -297,7 +297,7 @@ func (s *server) Addr() net.Addr { return s.conn.LocalAddr() } -func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet []byte) error { +func (s *server) handlePacket(remoteAddr net.Addr, packet []byte) error { rcvTime := time.Now() r := bytes.NewReader(packet) @@ -308,6 +308,13 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet hdr.Raw = packet[:len(packet)-r.Len()] packetData := packet[len(packet)-r.Len():] + if hdr.IsPublicHeader { + return s.handleGQUICPacket(hdr, packetData, remoteAddr, rcvTime) + } + return s.handleIETFQUICPacket(hdr, packetData, remoteAddr, rcvTime) +} + +func (s *server) handleIETFQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error { if hdr.IsLongHeader { 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) @@ -327,6 +334,29 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet session, sessionKnown := s.sessions[string(hdr.DestConnectionID)] s.sessionsMutex.RUnlock() + if sessionKnown && session == nil { + // Late packet for closed session + return nil + } + if !sessionKnown { + s.logger.Debugf("Received %s packet for unknown connection %s.", hdr.Type, hdr.DestConnectionID) + return nil + } + + session.handlePacket(&receivedPacket{ + remoteAddr: remoteAddr, + header: hdr, + data: packetData, + rcvTime: rcvTime, + }) + return nil +} + +func (s *server) handleGQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error { + s.sessionsMutex.RLock() + session, sessionKnown := s.sessions[string(hdr.DestConnectionID)] + s.sessionsMutex.RUnlock() + if sessionKnown && session == nil { // Late packet for closed session return nil @@ -340,9 +370,8 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet // If we don't have a session for this connection, and this packet cannot open a new connection, send a Public Reset // This should only happen after a server restart, when we still receive packets for connections that we lost the state for. - // TODO(#943): implement sending of IETF draft style stateless resets - if !sessionKnown && (!hdr.VersionFlag && hdr.Type != protocol.PacketTypeInitial) { - _, err = pconn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), remoteAddr) + if !sessionKnown && !hdr.VersionFlag { + _, err := s.conn.WriteTo(wire.WritePublicReset(hdr.DestConnectionID, 0, 0), remoteAddr) return err } @@ -357,29 +386,30 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet // since the client send a Public Header (only gQUIC has a Version Flag), we need to send a gQUIC Version Negotiation Packet if hdr.VersionFlag && !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) { // drop packets that are too small to be valid first packets - if len(packet) < protocol.MinClientHelloSize+len(hdr.Raw) { + if len(packetData) < protocol.MinClientHelloSize { return errors.New("dropping small packet with unknown version") } s.logger.Infof("Client offered version %s, sending Version Negotiation Packet", hdr.Version) - _, err := pconn.WriteTo(wire.ComposeGQUICVersionNegotiation(hdr.SrcConnectionID, s.config.Versions), remoteAddr) + _, err := s.conn.WriteTo(wire.ComposeGQUICVersionNegotiation(hdr.SrcConnectionID, s.config.Versions), remoteAddr) return err } - // This is (potentially) a Client Hello. - // Make sure it has the minimum required size before spending any more ressources on it. - if !sessionKnown && len(packet) < protocol.MinClientHelloSize+len(hdr.Raw) { - return errors.New("dropping small packet for unknown connection") - } - if !sessionKnown { + // This is (potentially) a Client Hello. + // Make sure it has the minimum required size before spending any more ressources on it. + if len(packetData) < protocol.MinClientHelloSize { + return errors.New("dropping small packet for unknown connection") + } + version := hdr.Version if !protocol.IsSupportedVersion(s.config.Versions, version) { return errors.New("Server BUG: negotiated version not supported") } s.logger.Infof("Serving new connection: %s, version %s from %v", hdr.DestConnectionID, version, remoteAddr) + var err error session, err = s.newSession( - &conn{pconn: pconn, currentAddr: remoteAddr}, + &conn{pconn: s.conn, currentAddr: remoteAddr}, version, hdr.DestConnectionID, s.scfg, @@ -396,6 +426,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet s.runHandshakeAndSession(session, hdr.DestConnectionID) } + session.handlePacket(&receivedPacket{ remoteAddr: remoteAddr, header: hdr, diff --git a/server_test.go b/server_test.go index 339d0be5..46c09aa2 100644 --- a/server_test.go +++ b/server_test.go @@ -171,7 +171,7 @@ var _ = Describe("Server", func() { }) It("creates new sessions", func() { - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) sess := serv.sessions[string(connID)].(*mockSession) @@ -232,7 +232,7 @@ var _ = Describe("Server", func() { acceptedSess, err = serv.Accept() Expect(err).ToNot(HaveOccurred()) }() - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) sess := serv.sessions[string(connID)].(*mockSession) @@ -249,7 +249,7 @@ var _ = Describe("Server", func() { serv.Accept() accepted = true }() - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) sess := serv.sessions[string(connID)].(*mockSession) @@ -259,9 +259,9 @@ var _ = Describe("Server", func() { }) It("assigns packets to existing sessions", func() { - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) - err = serv.handlePacket(nil, nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01}) + err = serv.handlePacket(nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01}) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions[string(connID)].(*mockSession).connectionID).To(Equal(connID)) @@ -272,7 +272,7 @@ var _ = Describe("Server", func() { serv.deleteClosedSessionsAfter = time.Second // make sure that the nil value for the closed session doesn't get deleted in this test nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, connID, protocol.VersionWhatever) Expect(err).ToNot(HaveOccurred()) - err = serv.handlePacket(nil, nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...)) + err = serv.handlePacket(nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...)) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions[string(connID)]).ToNot(BeNil()) @@ -287,7 +287,7 @@ var _ = Describe("Server", func() { serv.deleteClosedSessionsAfter = 25 * time.Millisecond nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, connID, protocol.VersionWhatever) Expect(err).ToNot(HaveOccurred()) - err = serv.handlePacket(nil, nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...)) + err = serv.handlePacket(nil, append(firstPacket, nullAEAD.Seal(nil, nil, 0, firstPacket)...)) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions).To(HaveKey(string(connID))) @@ -313,7 +313,7 @@ var _ = Describe("Server", func() { It("ignores packets for closed sessions", func() { serv.sessions[string(connID)] = nil - err := serv.handlePacket(nil, nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01}) + err := serv.handlePacket(nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01}) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions[string(connID)]).To(BeNil()) @@ -364,7 +364,7 @@ var _ = Describe("Server", func() { }) It("ignores delayed packets with mismatching versions", func() { - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1)) b := &bytes.Buffer{} @@ -372,7 +372,7 @@ var _ = Describe("Server", func() { data := []byte{0x09, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6} utils.BigEndian.WriteUint32(b, uint32(protocol.SupportedVersions[0]+1)) data = append(append(data, b.Bytes()...), 0x01) - err = serv.handlePacket(nil, nil, data) + err = serv.handlePacket(nil, data) Expect(err).ToNot(HaveOccurred()) // if we didn't ignore the packet, the server would try to send a version negotiation packet, which would make the test panic because it doesn't have a udpConn Expect(conn.dataWritten.Bytes()).To(BeEmpty()) @@ -381,7 +381,7 @@ var _ = Describe("Server", func() { }) It("errors on invalid public header", func() { - err := serv.handlePacket(nil, nil, nil) + err := serv.handlePacket(nil, nil) Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidPacketHeader)) }) @@ -396,12 +396,12 @@ var _ = Describe("Server", func() { Version: versionIETFFrames, } Expect(hdr.Write(b, protocol.PerspectiveClient, versionIETFFrames)).To(Succeed()) - err := serv.handlePacket(nil, nil, append(b.Bytes(), make([]byte, 456)...)) + err := serv.handlePacket(nil, append(b.Bytes(), make([]byte, 456)...)) Expect(err).To(MatchError("packet payload (456 bytes) is smaller than the expected payload length (1000 bytes)")) }) It("cuts packets at the payload length", func() { - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) b := &bytes.Buffer{} hdr := &wire.Header{ @@ -413,18 +413,18 @@ var _ = Describe("Server", func() { Version: versionIETFFrames, } Expect(hdr.Write(b, protocol.PerspectiveClient, versionIETFFrames)).To(Succeed()) - err = serv.handlePacket(nil, nil, append(b.Bytes(), make([]byte, 456)...)) + err = serv.handlePacket(nil, append(b.Bytes(), make([]byte, 456)...)) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(2)) Expect(serv.sessions[string(connID)].(*mockSession).handledPackets[1].data).To(HaveLen(123)) }) It("ignores Public Resets", func() { - err := serv.handlePacket(nil, nil, firstPacket) + err := serv.handlePacket(nil, firstPacket) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1)) - err = serv.handlePacket(nil, nil, wire.WritePublicReset(connID, 1, 1337)) + err = serv.handlePacket(nil, wire.WritePublicReset(connID, 1, 1337)) Expect(err).ToNot(HaveOccurred()) Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions[string(connID)].(*mockSession).handledPackets).To(HaveLen(1)) @@ -442,7 +442,8 @@ var _ = Describe("Server", func() { } hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */) b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)) // add a fake CHLO - err := serv.handlePacket(conn, nil, b.Bytes()) + serv.conn = conn + err := serv.handlePacket(nil, b.Bytes()) Expect(conn.dataWritten.Bytes()).ToNot(BeEmpty()) Expect(err).ToNot(HaveOccurred()) }) @@ -458,7 +459,8 @@ var _ = Describe("Server", func() { } hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */) b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize-1)) // this packet is 1 byte too small - err := serv.handlePacket(conn, udpAddr, b.Bytes()) + serv.conn = conn + err := serv.handlePacket(udpAddr, b.Bytes()) Expect(err).To(MatchError("dropping small packet with unknown version")) Expect(conn.dataWritten.Len()).Should(BeZero()) }) @@ -628,6 +630,27 @@ var _ = Describe("Server", func() { Consistently(func() int { return conn.dataWritten.Len() }).Should(BeZero()) }) + It("ignores non-Initial Long Header packets for unknown connections", func() { + connID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1} + b := &bytes.Buffer{} + hdr := wire.Header{ + Type: protocol.PacketTypeHandshake, + IsLongHeader: true, + DestConnectionID: connID, + SrcConnectionID: connID, + PacketNumber: 0x55, + Version: protocol.VersionTLS, + } + err := hdr.Write(b, protocol.PerspectiveClient, protocol.VersionTLS) + Expect(err).ToNot(HaveOccurred()) + conn.dataToRead <- b.Bytes() + conn.dataReadFrom = udpAddr + ln, err := Listen(conn, testdata.GetTLSConfig(), config) + Expect(err).ToNot(HaveOccurred()) + defer ln.Close() + Consistently(func() int { return conn.dataWritten.Len() }).Should(BeZero()) + }) + It("sends a PublicReset for new connections that don't have the VersionFlag set", func() { conn.dataReadFrom = udpAddr conn.dataToRead <- []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01}