validate minimum packet size before sending a version negotiation packet

fixes #429
This commit is contained in:
Marten Seemann
2017-02-25 11:28:33 +07:00
parent e69ade8f24
commit c1c0fac0b4
2 changed files with 34 additions and 5 deletions

View File

@@ -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

View File

@@ -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() {