From 8565fdf7226d92dfe2af32bac75cafd126165fc7 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 10 Apr 2017 17:51:18 +0700 Subject: [PATCH] fix limit of undecrytable packets queue length fixes #517 Also fixes an off-by-one error, such that the queue now holds exactly protocol.MaxUndecrytablePackets packets when enough undecryptable packets are received. --- session.go | 12 ++++++++---- session_test.go | 19 ++++++++++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/session.go b/session.go index 11c940d8..a8eaf39f 100644 --- a/session.go +++ b/session.go @@ -782,12 +782,16 @@ func (s *session) tryQueueingUndecryptablePacket(p *receivedPacket) { if s.cryptoSetup.HandshakeComplete() { return } - utils.Infof("Queueing packet 0x%x for later decryption", p.publicHeader.PacketNumber) - if len(s.undecryptablePackets)+1 >= protocol.MaxUndecryptablePackets && s.receivedTooManyUndecrytablePacketsTime.IsZero() { - s.receivedTooManyUndecrytablePacketsTime = time.Now() - s.maybeResetTimer() + if len(s.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets { + // if this is the first time the undecryptablePackets runs full, start the timer to send a Public Reset + if s.receivedTooManyUndecrytablePacketsTime.IsZero() { + s.receivedTooManyUndecrytablePacketsTime = time.Now() + s.maybeResetTimer() + } + utils.Infof("Dropping undecrytable packet 0x%x (undecryptable packet queue full)", p.publicHeader.PacketNumber) return } + utils.Infof("Queueing packet 0x%x for later decryption", p.publicHeader.PacketNumber) s.undecryptablePackets = append(s.undecryptablePackets, p) } diff --git a/session_test.go b/session_test.go index a996618a..009d3f39 100644 --- a/session_test.go +++ b/session_test.go @@ -1193,7 +1193,7 @@ var _ = Describe("Session", func() { Context("sending a Public Reset when receiving undecryptable packets during the handshake", func() { It("doesn't immediately send a Public Reset after receiving too many undecryptable packets", func() { go sess.run() - for i := 0; i < protocol.MaxUndecryptablePackets; i++ { + for i := 0; i < protocol.MaxUndecryptablePackets+1; i++ { hdr := &PublicHeader{ PacketNumber: protocol.PacketNumber(i + 1), } @@ -1205,7 +1205,7 @@ var _ = Describe("Session", func() { It("sets a deadline to send a Public Reset after receiving too many undecryptable packets", func() { go sess.run() - for i := 0; i < protocol.MaxUndecryptablePackets; i++ { + for i := 0; i < protocol.MaxUndecryptablePackets+1; i++ { hdr := &PublicHeader{ PacketNumber: protocol.PacketNumber(i + 1), } @@ -1214,6 +1214,19 @@ var _ = Describe("Session", func() { Eventually(func() time.Time { return sess.receivedTooManyUndecrytablePacketsTime }).Should(BeTemporally("~", time.Now(), 10*time.Millisecond)) }) + It("drops undecryptable packets when the undecrytable packet queue is full", func() { + go sess.run() + for i := 0; i < protocol.MaxUndecryptablePackets+10; i++ { + hdr := &PublicHeader{ + PacketNumber: protocol.PacketNumber(i + 1), + } + sess.handlePacket(&receivedPacket{publicHeader: hdr, data: []byte("foobar")}) + } + Eventually(func() []*receivedPacket { return sess.undecryptablePackets }).Should(HaveLen(protocol.MaxUndecryptablePackets)) + // check that old packets are kept, and the new packets are dropped + Expect(sess.undecryptablePackets[0].publicHeader.PacketNumber).To(Equal(protocol.PacketNumber(1))) + }) + It("sends a Public Reset after a timeout", func() { sess.receivedTooManyUndecrytablePacketsTime = time.Now().Add(-protocol.PublicResetTimeout) go sess.run() @@ -1226,7 +1239,7 @@ var _ = Describe("Session", func() { It("ignores undecryptable packets after the handshake is complete", func() { *(*bool)(unsafe.Pointer(reflect.ValueOf(sess.cryptoSetup).Elem().FieldByName("receivedForwardSecurePacket").UnsafeAddr())) = true - for i := 0; i < protocol.MaxUndecryptablePackets; i++ { + for i := 0; i < protocol.MaxUndecryptablePackets+1; i++ { hdr := &PublicHeader{ PacketNumber: protocol.PacketNumber(i + 1), }