From 3b66d2f35ddda0043878a907e33f9eb300ac4ac4 Mon Sep 17 00:00:00 2001 From: Lucas Clemente Date: Thu, 8 Sep 2016 13:37:44 +0200 Subject: [PATCH] add a timeout before crypto handshake completes --- session.go | 40 +++++++++++++++++++++++++++------------- session_test.go | 22 ++++++++++++++-------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/session.go b/session.go index 36ffc64a..47044b21 100644 --- a/session.go +++ b/session.go @@ -81,6 +81,7 @@ type Session struct { // representation, and sent back in public reset packets largestRcvdPacketNumber protocol.PacketNumber + sessionCreationTime time.Time lastNetworkActivityTime time.Time timer *time.Timer @@ -99,23 +100,29 @@ func newSession(conn connection, v protocol.VersionNumber, connectionID protocol sentPacketHandler = ackhandler.NewSentPacketHandler() receivedPacketHandler = ackhandler.NewReceivedPacketHandler() + now := time.Now() session := &Session{ - connectionID: connectionID, - version: v, - conn: conn, - streamCallback: streamCallback, - closeCallback: closeCallback, + conn: conn, + connectionID: connectionID, + version: v, + + streamCallback: streamCallback, + closeCallback: closeCallback, + + connectionParametersManager: connectionParametersManager, sentPacketHandler: sentPacketHandler, receivedPacketHandler: receivedPacketHandler, flowControlManager: flowControlManager, - receivedPackets: make(chan *receivedPacket, protocol.MaxSessionUnprocessedPackets), - closeChan: make(chan *qerr.QuicError, 1), - sendingScheduled: make(chan struct{}, 1), - connectionParametersManager: connectionParametersManager, - undecryptablePackets: make([]*receivedPacket, 0, protocol.MaxUndecryptablePackets), - aeadChanged: make(chan struct{}, 1), - timer: time.NewTimer(0), - lastNetworkActivityTime: time.Now(), + + receivedPackets: make(chan *receivedPacket, protocol.MaxSessionUnprocessedPackets), + closeChan: make(chan *qerr.QuicError, 1), + sendingScheduled: make(chan struct{}, 1), + undecryptablePackets: make([]*receivedPacket, 0, protocol.MaxUndecryptablePackets), + aeadChanged: make(chan struct{}, 1), + + timer: time.NewTimer(0), + lastNetworkActivityTime: now, + sessionCreationTime: now, } session.streamsMap = newStreamsMap(session.newStream) @@ -196,6 +203,9 @@ func (s *Session) run() { if time.Now().Sub(s.lastNetworkActivityTime) >= s.connectionParametersManager.GetIdleConnectionStateLifetime() { s.Close(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity.")) } + if !s.cryptoSetup.HandshakeComplete() && time.Now().Sub(s.sessionCreationTime) >= protocol.MaxTimeForCryptoHandshake { + s.Close(qerr.Error(qerr.NetworkIdleTimeout, "Crypto handshake did not complete in time.")) + } s.garbageCollectStreams() } } @@ -209,6 +219,10 @@ func (s *Session) maybeResetTimer() { if rtoTime := s.sentPacketHandler.TimeOfFirstRTO(); !rtoTime.IsZero() { nextDeadline = utils.MinTime(nextDeadline, rtoTime) } + if !s.cryptoSetup.HandshakeComplete() { + handshakeDeadline := s.sessionCreationTime.Add(protocol.MaxTimeForCryptoHandshake) + nextDeadline = utils.MinTime(nextDeadline, handshakeDeadline) + } if nextDeadline.Equal(s.currentDeadline) { // No need to reset the timer diff --git a/session_test.go b/session_test.go index 632f1a5b..58a78b74 100644 --- a/session_test.go +++ b/session_test.go @@ -748,15 +748,21 @@ var _ = Describe("Session", func() { Expect(session.receivedPackets).To(Receive()) }) - It("times out", func(done Done) { - session.connectionParametersManager.SetFromMap(map[handshake.Tag][]byte{ - handshake.TagICSL: {0, 0, 0, 0}, + Context("timeouts", func() { + It("times out due to no network activity", func(done Done) { + session.lastNetworkActivityTime = time.Now().Add(-time.Hour) + session.run() // Would normally not return + Expect(conn.written[0]).To(ContainSubstring("No recent network activity.")) + close(done) }) - session.packer.connectionParametersManager = session.connectionParametersManager - session.run() // Would normally not return - Expect(conn.written[0]).To(ContainSubstring("No recent network activity.")) - close(done) - }, 3) + + It("times out due to non-completed crypto handshake", func(done Done) { + session.sessionCreationTime = time.Now().Add(-time.Hour) + session.run() // Would normally not return + Expect(conn.written[0]).To(ContainSubstring("Crypto handshake did not complete in time.")) + close(done) + }) + }) It("errors when the SentPacketHandler has too many packets tracked", func() { streamFrame := frames.StreamFrame{StreamID: 5, Data: []byte("foobar")}