From c1c0fac0b46784125cdeca2059147750aadbd933 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 25 Feb 2017 11:28:33 +0700 Subject: [PATCH] validate minimum packet size before sending a version negotiation packet fixes #429 --- server.go | 4 ++++ server_test.go | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/server.go b/server.go index beac35a1..91c346e4 100644 --- a/server.go +++ b/server.go @@ -163,6 +163,10 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet // Send Version Negotiation Packet if the client is speaking a different protocol version if hdr.VersionFlag && !protocol.IsSupportedVersion(hdr.VersionNumber) { + // drop packets that are too small to be valid first packets + if len(packet) < protocol.ClientHelloMinimumSize+len(hdr.Raw) { + return errors.New("dropping small packet with unknown version") + } utils.Infof("Client offered version %d, sending VersionNegotiationPacket", hdr.VersionNumber) _, err = pconn.WriteTo(composeVersionNegotiation(hdr.ConnectionID), remoteAddr) return err diff --git a/server_test.go b/server_test.go index da2f114f..1622b324 100644 --- a/server_test.go +++ b/server_test.go @@ -260,6 +260,21 @@ var _ = Describe("Server", func() { Expect(serv.sessions).To(HaveLen(1)) Expect(serv.sessions[connID].(*mockSession).packetCount).To(Equal(1)) }) + + It("doesn't respond with a version negotiation packet if the first packet is too small", func() { + b := &bytes.Buffer{} + hdr := PublicHeader{ + VersionFlag: true, + ConnectionID: 0x1337, + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen2, + } + hdr.Write(b, 13 /* not a valid QUIC version */, protocol.PerspectiveClient) + b.Write(bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize-1)) // this packet is 1 byte too small + err := serv.handlePacket(conn, udpAddr, b.Bytes()) + Expect(err).To(MatchError("dropping small packet with unknown version")) + Expect(conn.dataWritten.Len()).Should(BeZero()) + }) }) It("setups with the right values", func() { @@ -284,24 +299,34 @@ var _ = Describe("Server", func() { }) It("setups and responds with version negotiation", func() { - conn.dataToRead = []byte{0x09, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x01, 'Q', '0', '0', '0', 0x01} + b := &bytes.Buffer{} + hdr := PublicHeader{ + VersionFlag: true, + ConnectionID: 0x1337, + PacketNumber: 1, + PacketNumberLen: protocol.PacketNumberLen2, + } + hdr.Write(b, 13 /* not a valid QUIC version */, protocol.PerspectiveClient) + b.Write(bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize)) // add a fake CHLO + conn.dataToRead = b.Bytes() conn.dataReadFrom = udpAddr ln, err := Listen(conn, config) Expect(err).ToNot(HaveOccurred()) + var returned bool go func() { - defer GinkgoRecover() - err := ln.Serve() - Expect(err).ToNot(HaveOccurred()) + ln.Serve() + returned = true }() Eventually(func() int { return conn.dataWritten.Len() }).ShouldNot(BeZero()) Expect(conn.dataWrittenTo).To(Equal(udpAddr)) expected := append( - []byte{0x9, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + []byte{0x9, 0x37, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, protocol.SupportedVersionsAsTags..., ) Expect(conn.dataWritten.Bytes()).To(Equal(expected)) + Expect(returned).To(BeFalse()) }) It("sends a PublicReset for new connections that don't have the VersionFlag set", func() {