diff --git a/handshake/crypto_setup.go b/handshake/crypto_setup.go index efd265737..88ee5d3e4 100644 --- a/handshake/crypto_setup.go +++ b/handshake/crypto_setup.go @@ -323,3 +323,8 @@ func (h *CryptoSetup) LockForSealing() { func (h *CryptoSetup) UnlockForSealing() { h.mutex.RUnlock() } + +// HandshakeComplete returns true after the first forward secure packet was received form the client. +func (h *CryptoSetup) HandshakeComplete() bool { + return h.receivedForwardSecurePacket +} diff --git a/protocol/server_parameters.go b/protocol/server_parameters.go index 745465306..7be5976e9 100644 --- a/protocol/server_parameters.go +++ b/protocol/server_parameters.go @@ -49,7 +49,7 @@ const MaxNewStreamIDDelta = 4 * MaxStreamsPerConnection const MaxIdleConnectionStateLifetime = 60 * time.Second // MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed. -const MaxSessionUnprocessedPackets = 128 +const MaxSessionUnprocessedPackets = 2000 // RetransmissionThreshold + 1 is the number of times a packet has to be NACKed so that it gets retransmitted const RetransmissionThreshold = 3 diff --git a/session.go b/session.go index 471fe4177..d780bdef8 100644 --- a/session.go +++ b/session.go @@ -629,6 +629,9 @@ func (s *Session) scheduleSending() { } 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.Close(qerr.Error(qerr.DecryptionFailure, "too many undecryptable packets received")) diff --git a/session_test.go b/session_test.go index 9c56f9963..09edfbfd8 100644 --- a/session_test.go +++ b/session_test.go @@ -6,9 +6,11 @@ import ( "fmt" "io" "net" + "reflect" "runtime" "sync/atomic" "time" + "unsafe" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -739,6 +741,19 @@ var _ = Describe("Session", func() { Expect(conn.written[0]).To(ContainSubstring(string([]byte("PRST")))) }) + It("ignores undecryptable packets after the handshake is complete", func() { + *(*bool)(unsafe.Pointer(reflect.ValueOf(session.cryptoSetup).Elem().FieldByName("receivedForwardSecurePacket").UnsafeAddr())) = true + for i := 0; i < protocol.MaxUndecryptablePackets; i++ { + hdr := &PublicHeader{ + PacketNumber: protocol.PacketNumber(i + 1), + } + session.handlePacket(nil, hdr, []byte("foobar")) + } + go session.run() + Consistently(session.undecryptablePackets).Should(HaveLen(0)) + session.closeImpl(nil, true) + }) + It("unqueues undecryptable packets for later decryption", func() { session.undecryptablePackets = []receivedPacket{{ nil,