forked from quic-go/quic-go
only accept 3 retries
While the server is allowed to perform multiple Retries, the client should impose a limit in order to avoid being caught in an endless loop.
This commit is contained in:
@@ -29,7 +29,8 @@ type client struct {
|
||||
|
||||
packetHandlers packetHandlerManager
|
||||
|
||||
token []byte
|
||||
token []byte
|
||||
numRetries int
|
||||
|
||||
versionNegotiated bool // has the server accepted our version
|
||||
receivedVersionNegotiationPacket bool
|
||||
@@ -495,6 +496,11 @@ func (c *client) handleRetryPacket(hdr *wire.Header) {
|
||||
c.logger.Debugf("Received spoofed Retry. Original Destination Connection ID: %s, expected: %s", hdr.OrigDestConnectionID, c.destConnID)
|
||||
return
|
||||
}
|
||||
c.numRetries++
|
||||
if c.numRetries > protocol.MaxRetries {
|
||||
c.session.destroy(qerr.CryptoTooManyRejects)
|
||||
return
|
||||
}
|
||||
c.destConnID = hdr.SrcConnectionID
|
||||
c.token = hdr.Token
|
||||
c.session.destroy(errCloseSessionForRetry)
|
||||
|
||||
@@ -534,6 +534,61 @@ var _ = Describe("Client", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(sessions).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("only accepts 3 retries", func() {
|
||||
manager := NewMockPacketHandlerManager(mockCtrl)
|
||||
manager.EXPECT().Add(gomock.Any(), gomock.Any()).Do(func(id protocol.ConnectionID, handler packetHandler) {
|
||||
go handler.handlePacket(&receivedPacket{
|
||||
header: &wire.Header{
|
||||
IsLongHeader: true,
|
||||
Type: protocol.PacketTypeRetry,
|
||||
Token: []byte("foobar"),
|
||||
SrcConnectionID: connID,
|
||||
DestConnectionID: id,
|
||||
OrigDestConnectionID: connID,
|
||||
Version: protocol.VersionTLS,
|
||||
},
|
||||
})
|
||||
}).AnyTimes()
|
||||
manager.EXPECT().Add(gomock.Any(), gomock.Any()).AnyTimes()
|
||||
mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
|
||||
|
||||
config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}}
|
||||
cl.config = config
|
||||
|
||||
sessions := make(chan quicSession, protocol.MaxRetries+1)
|
||||
for i := 0; i < protocol.MaxRetries+1; i++ {
|
||||
run := make(chan error)
|
||||
sess := NewMockQuicSession(mockCtrl)
|
||||
sess.EXPECT().run().DoAndReturn(func() error {
|
||||
return <-run
|
||||
})
|
||||
sess.EXPECT().destroy(gomock.Any()).Do(func(e error) {
|
||||
run <- e
|
||||
})
|
||||
sessions <- sess
|
||||
}
|
||||
|
||||
newTLSClientSession = func(
|
||||
_ connection,
|
||||
_ sessionRunner,
|
||||
_ []byte,
|
||||
_ protocol.ConnectionID,
|
||||
_ protocol.ConnectionID,
|
||||
_ *Config,
|
||||
_ *mint.Config,
|
||||
_ <-chan handshake.TransportParameters,
|
||||
_ protocol.PacketNumber,
|
||||
_ utils.Logger,
|
||||
_ protocol.VersionNumber,
|
||||
) (quicSession, error) {
|
||||
return <-sessions, nil
|
||||
}
|
||||
_, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.(qerr.ErrorCode)).To(Equal(qerr.CryptoTooManyRejects))
|
||||
Expect(sessions).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Context("version negotiation", func() {
|
||||
|
||||
@@ -149,3 +149,6 @@ const MinPacingDelay time.Duration = 100 * time.Microsecond
|
||||
// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections
|
||||
// if no other value is configured.
|
||||
const DefaultConnectionIDLength = 4
|
||||
|
||||
// MaxRetries is the maximum number of Retries a client will do before failing the connection.
|
||||
const MaxRetries = 3
|
||||
|
||||
Reference in New Issue
Block a user