From 2762cc1597fbf20aa45be7f6f66fdc545182b080 Mon Sep 17 00:00:00 2001 From: Bonnie Xu Date: Thu, 13 Jun 2019 08:41:29 -0700 Subject: [PATCH] Setup stateless reset token Summary: Replace hard coded stateless reset token with a token from the stateless reset token generator. Reviewed By: yangchi Differential Revision: D15481858 fbshipit-source-id: 30c96843c38c616600466b2fabb6defd5fcc5799 --- quic/QuicConstants.h | 5 +- .../handshake/test/ClientHandshakeTest.cpp | 3 +- quic/client/test/QuicClientTransportTest.cpp | 64 +++++++++++++++++-- quic/codec/Types.h | 1 - quic/common/test/TestUtils.cpp | 16 +++++ quic/common/test/TestUtils.h | 4 ++ quic/server/QuicServer.cpp | 11 +++- quic/server/QuicServerTransport.cpp | 3 +- quic/server/QuicServerWorker.cpp | 33 +++++++--- quic/server/QuicServerWorker.h | 3 +- .../ServerTransportParametersExtension.h | 11 ++-- .../handshake/StatelessResetGenerator.h | 13 ++-- .../handshake/test/ServerHandshakeTest.cpp | 4 +- .../test/ServerTransportParametersTest.cpp | 21 ++++-- quic/server/state/ServerStateMachine.cpp | 23 +++++-- quic/server/state/ServerStateMachine.h | 3 + quic/server/test/QuicServerTest.cpp | 22 +++++-- quic/server/test/QuicServerTransportTest.cpp | 4 ++ quic/state/TransportSettings.h | 3 + quic/state/test/QuicStateFunctionsTest.cpp | 2 - quic/state/test/StateMachineTest.cpp | 5 +- 21 files changed, 198 insertions(+), 56 deletions(-) diff --git a/quic/QuicConstants.h b/quic/QuicConstants.h index d851bd4fa..52035e52b 100644 --- a/quic/QuicConstants.h +++ b/quic/QuicConstants.h @@ -332,9 +332,6 @@ constexpr uint32_t kRequiredMaxEarlyDataSize = 0xffffffff; // and 16 bytes of the token and 16 bytes of randomness constexpr uint16_t kMinStatelessPacketSize = 13 + 16 + 16; -// TODO: remove this when we have a stateless reset generator. -constexpr folly::StringPiece kTestStatelessResetToken = "aaaabbbbccccdddd"; - constexpr std::chrono::milliseconds kHappyEyeballsV4Delay = 150ms; constexpr std::chrono::milliseconds kHappyEyeballsConnAttemptDelayWithCache = @@ -356,6 +353,8 @@ constexpr uint32_t kMaxNumMigrationsAllowed = 6; constexpr auto kExpectedNumOfParamsInTheTicket = 8; +constexpr auto kStatelessResetTokenSecretLength = 32; + // default capability of QUIC partial reliability constexpr TransportPartialReliabilitySetting kDefaultPartialReliability = false; diff --git a/quic/client/handshake/test/ClientHandshakeTest.cpp b/quic/client/handshake/test/ClientHandshakeTest.cpp index da97f5e61..0db1ace56 100644 --- a/quic/client/handshake/test/ClientHandshakeTest.cpp +++ b/quic/client/handshake/test/ClientHandshakeTest.cpp @@ -97,7 +97,8 @@ class ClientHandshakeTest : public Test, public boost::static_visitor<> { kDefaultIdleTimeout, kDefaultAckDelayExponent, kDefaultUDPSendPacketLen, - kDefaultPartialReliability); + kDefaultPartialReliability, + generateStatelessResetToken()); fizzServer.reset( new fizz::server:: FizzServer( diff --git a/quic/client/test/QuicClientTransportTest.cpp b/quic/client/test/QuicClientTransportTest.cpp index 375788fca..77bacf7da 100644 --- a/quic/client/test/QuicClientTransportTest.cpp +++ b/quic/client/test/QuicClientTransportTest.cpp @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. * */ - #include #include @@ -29,7 +28,6 @@ #include #include #include -#include using namespace testing; using namespace folly; @@ -732,6 +730,55 @@ TEST_P(QuicClientTransportIntegrationTest, ResetClient) { EXPECT_TRUE(resetRecvd); } +TEST_P(QuicClientTransportIntegrationTest, TestStatelessResetToken) { + folly::Optional token1, token2; + + expectTransportCallbacks(); + auto server2 = createServer(ProcessId::ONE); + SCOPE_EXIT { + server2->shutdown(); + server2 = nullptr; + }; + + client->start(&clientConnCallback); + + EXPECT_CALL(clientConnCallback, onTransportReady()).WillOnce(Invoke([&] { + token1 = client->getConn().statelessResetToken; + eventbase_.terminateLoopSoon(); + })); + eventbase_.loopForever(); + + auto streamId = client->createBidirectionalStream().value(); + auto data = IOBuf::copyBuffer("hello"); + auto expected = std::shared_ptr(IOBuf::copyBuffer("echo ")); + expected->prependChain(data->clone()); + sendRequestAndResponseAndWait(*expected, data->clone(), streamId, &readCb); + + // change the address to a new server which does not have the connection. + auto server2Addr = server2->getAddress(); + client->getNonConstConn().peerAddress = server2Addr; + + MockReadCallback readCb2; + bool resetRecvd = false; + auto streamId2 = client->createBidirectionalStream().value(); + sendRequestAndResponse(data->clone(), streamId2, &readCb2) + .thenValue([&](StreamPair) { resetRecvd = false; }) + .thenError( + folly::tag_t{}, + [&](const std::runtime_error& e) { + LOG(INFO) << e.what(); + resetRecvd = true; + token2 = client->getConn().statelessResetToken; + }) + .ensure([&] { eventbase_.terminateLoopSoon(); }); + eventbase_.loopForever(); + + EXPECT_TRUE(resetRecvd); + EXPECT_TRUE(token1.hasValue()); + EXPECT_TRUE(token2.hasValue()); + EXPECT_EQ(token1.value(), token2.value()); +} + TEST_P(QuicClientTransportIntegrationTest, PartialReliabilityDisabledTest) { expectTransportCallbacks(); TransportSettings settings; @@ -741,6 +788,7 @@ TEST_P(QuicClientTransportIntegrationTest, PartialReliabilityDisabledTest) { TransportSettings serverSettings; serverSettings.partialReliabilityEnabled = false; + serverSettings.statelessResetTokenSecret = getRandSecret(); server_->setTransportSettings(serverSettings); client->start(&clientConnCallback); @@ -768,6 +816,7 @@ TEST_P(QuicClientTransportIntegrationTest, PartialReliabilityDisabledTest2) { TransportSettings serverSettings; serverSettings.partialReliabilityEnabled = false; + serverSettings.statelessResetTokenSecret = getRandSecret(); server_->setTransportSettings(serverSettings); client->start(&clientConnCallback); @@ -795,6 +844,7 @@ TEST_P(QuicClientTransportIntegrationTest, PartialReliabilityDisabledTest3) { TransportSettings serverSettings; serverSettings.partialReliabilityEnabled = true; + serverSettings.statelessResetTokenSecret = getRandSecret(); server_->setTransportSettings(serverSettings); client->start(&clientConnCallback); @@ -822,6 +872,7 @@ TEST_P(QuicClientTransportIntegrationTest, PartialReliabilityEnabledTest) { TransportSettings serverSettings; serverSettings.partialReliabilityEnabled = true; + serverSettings.statelessResetTokenSecret = getRandSecret(); server_->setTransportSettings(serverSettings); client->start(&clientConnCallback); @@ -897,14 +948,13 @@ class FakeOneRttHandshakeLayer : public ClientHandshake { params.negotiated_version = negotiatedVersion; params.supported_versions = {QuicVersion::MVFST, QuicVersion::QUIC_DRAFT}; - // TODO: replace this with a real stateless reset token. + StatelessResetToken testStatelessResetToken = generateStatelessResetToken(); TransportParameter statelessReset; statelessReset.parameter = TransportParameterId::stateless_reset_token; - statelessReset.value = folly::IOBuf::copyBuffer(kTestStatelessResetToken); + statelessReset.value = folly::IOBuf::copyBuffer(testStatelessResetToken); parameters.push_back(std::move(statelessReset)); params.parameters = std::move(parameters); - // TODO: stateless reset token. params_ = std::move(params); } @@ -1015,6 +1065,7 @@ class QuicClientTransportTest : public Test { connIdAlgo_ = std::make_unique(); ON_CALL(*sock, resumeRead(_)) .WillByDefault(SaveArg<0>(&networkReadCallback)); + ON_CALL(*sock, address()).WillByDefault(ReturnRef(serverAddr)); } virtual void setupCryptoLayer() { @@ -1450,6 +1501,7 @@ TEST_F(QuicClientTransportTest, SocketClosedDuringOnTransportReady) { socketWrites.push_back(buf->clone()); return buf->computeChainDataLength(); })); + ON_CALL(*sock, address()).WillByDefault(ReturnRef(serverAddr)); client->addNewPeerAddress(serverAddr); setupCryptoLayer(); @@ -2211,6 +2263,8 @@ class QuicClientTransportAfterStartTest : public QuicClientTransportTest { socketWrites.push_back(buf->clone()); return buf->computeChainDataLength(); })); + ON_CALL(*sock, address()).WillByDefault(ReturnRef(serverAddr)); + setupCryptoLayer(); start(); client->getNonConstConn().streamManager->setMaxLocalBidirectionalStreams( diff --git a/quic/codec/Types.h b/quic/codec/Types.h index cc048cb98..2112b7743 100644 --- a/quic/codec/Types.h +++ b/quic/codec/Types.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/quic/common/test/TestUtils.cpp b/quic/common/test/TestUtils.cpp index f8ac6962f..32d6cc1d4 100644 --- a/quic/common/test/TestUtils.cpp +++ b/quic/common/test/TestUtils.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace { std::deque::reverse_iterator @@ -591,5 +592,20 @@ folly::IOBufQueue bufToQueue(Buf buf) { return queue; } +StatelessResetToken generateStatelessResetToken() { + StatelessResetSecret secret; + folly::Random::secureRandom(secret.data(), secret.size()); + folly::SocketAddress address("1.2.3.4", 8080); + StatelessResetGenerator generator(secret, address.getFullyQualified()); + + return generator.generateToken(ConnectionId({0x14, 0x35, 0x22, 0x11})); +} + +std::array getRandSecret() { + std::array secret; + folly::Random::secureRandom(secret.data(), secret.size()); + return secret; +} + } // namespace test } // namespace quic diff --git a/quic/common/test/TestUtils.h b/quic/common/test/TestUtils.h index aa0e68212..c617a7d0d 100644 --- a/quic/common/test/TestUtils.h +++ b/quic/common/test/TestUtils.h @@ -249,5 +249,9 @@ CongestionController::AckEvent makeAck( folly::IOBufQueue bufToQueue(Buf buf); +StatelessResetToken generateStatelessResetToken(); + +std::array getRandSecret(); + } // namespace test } // namespace quic diff --git a/quic/server/QuicServer.cpp b/quic/server/QuicServer.cpp index d684eef9f..91c4b71b2 100644 --- a/quic/server/QuicServer.cpp +++ b/quic/server/QuicServer.cpp @@ -6,8 +6,9 @@ * */ -#include +#include +#include #include #include #include @@ -109,6 +110,14 @@ void QuicServer::initialize( << std::numeric_limits::max() << " workers"; CHECK(shutdown_); shutdown_ = false; + + // setting default stateless reset token if not set + if (!transportSettings_.statelessResetTokenSecret) { + std::array secret; + folly::Random::secureRandom(secret.data(), secret.size()); + transportSettings_.statelessResetTokenSecret = secret; + } + // it the connid algo factory is not set, use default impl if (!connIdAlgoFactory_) { connIdAlgoFactory_ = std::make_unique(); diff --git a/quic/server/QuicServerTransport.cpp b/quic/server/QuicServerTransport.cpp index 4ad0eb369..aaa0ce297 100644 --- a/quic/server/QuicServerTransport.cpp +++ b/quic/server/QuicServerTransport.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include namespace quic { @@ -21,6 +21,7 @@ QuicServerTransport::QuicServerTransport( std::shared_ptr ctx) : QuicTransportBase(evb, std::move(sock)), ctx_(std::move(ctx)) { auto tempConn = std::make_unique(); + tempConn->serverAddr = socket_->address(); serverConn_ = tempConn.get(); conn_ = std::move(tempConn); // TODO: generate this when we can encode the packet sequence number diff --git a/quic/server/QuicServerWorker.cpp b/quic/server/QuicServerWorker.cpp index 28f8d3ea4..4e2e7a42d 100644 --- a/quic/server/QuicServerWorker.cpp +++ b/quic/server/QuicServerWorker.cpp @@ -12,6 +12,7 @@ #include #include +#include namespace quic { @@ -406,13 +407,21 @@ void QuicServerWorker::dispatchPacketData( infoCallback_, onPacketDropped, PacketDropReason::ROUTING_ERROR_WRONG_HOST); - return sendResetPacket(routingData.headerForm, client, networkData); + return sendResetPacket( + routingData.headerForm, + client, + networkData, + routingData.destinationConnId); } if (!packetForwardingEnabled_) { QUIC_STATS( infoCallback_, onPacketDropped, PacketDropReason::CONNECTION_NOT_FOUND); - return sendResetPacket(routingData.headerForm, client, networkData); + return sendResetPacket( + routingData.headerForm, + client, + networkData, + routingData.destinationConnId); } // There's no existing connection for the packet's CID or the client's @@ -420,7 +429,11 @@ void QuicServerWorker::dispatchPacketData( if (connIdParam.processId == static_cast(processId_)) { QUIC_STATS( infoCallback_, onPacketDropped, PacketDropReason::CONNECTION_NOT_FOUND); - return sendResetPacket(routingData.headerForm, client, networkData); + return sendResetPacket( + routingData.headerForm, + client, + networkData, + routingData.destinationConnId); } // Optimistically route to another server @@ -437,7 +450,8 @@ void QuicServerWorker::dispatchPacketData( void QuicServerWorker::sendResetPacket( const HeaderForm& headerForm, const folly::SocketAddress& client, - const NetworkData& networkData) { + const NetworkData& networkData, + const ConnectionId& connId) { if (headerForm != HeaderForm::Short) { // Only send resets in response to short header packets. return; @@ -446,12 +460,11 @@ void QuicServerWorker::sendResetPacket( uint16_t maxResetPacketSize = std::min( std::max(kMinStatelessPacketSize, packetSize), kDefaultUDPSendPacketLen); - // TODO: replace with real token. - StatelessResetToken token; - static_assert( - kTestStatelessResetToken.size() == sizeof(StatelessResetToken), - "Token size does not match"); - memcpy(&token, kTestStatelessResetToken.data(), token.size()); + CHECK(transportSettings_.statelessResetTokenSecret.hasValue()); + StatelessResetGenerator generator( + *transportSettings_.statelessResetTokenSecret, + getAddress().getFullyQualified()); + StatelessResetToken token = generator.generateToken(connId); StatelessResetPacketBuilder builder(maxResetPacketSize, token); auto resetData = std::move(builder).buildPacket(); socket_->write(client, std::move(resetData)); diff --git a/quic/server/QuicServerWorker.h b/quic/server/QuicServerWorker.h index 07cd1f5cc..5adf267b2 100644 --- a/quic/server/QuicServerWorker.h +++ b/quic/server/QuicServerWorker.h @@ -301,7 +301,8 @@ class QuicServerWorker : public folly::AsyncUDPSocket::ReadCallback, void sendResetPacket( const HeaderForm& headerForm, const folly::SocketAddress& client, - const NetworkData& networkData); + const NetworkData& networkData, + const ConnectionId& connId); std::unique_ptr socket_; std::shared_ptr callback_; diff --git a/quic/server/handshake/ServerTransportParametersExtension.h b/quic/server/handshake/ServerTransportParametersExtension.h index 9290ce512..868f07f29 100644 --- a/quic/server/handshake/ServerTransportParametersExtension.h +++ b/quic/server/handshake/ServerTransportParametersExtension.h @@ -10,6 +10,7 @@ #include #include +#include namespace quic { @@ -27,7 +28,8 @@ class ServerTransportParametersExtension : public fizz::ServerExtensions { std::chrono::milliseconds idleTimeout, uint64_t ackDelayExponent, uint64_t maxRecvPacketSize, - TransportPartialReliabilitySetting partialReliability) + TransportPartialReliabilitySetting partialReliability, + const StatelessResetToken& token) : negotiatedVersion_(negotiatedVersion), supportedVersions_(supportedVersions), initialMaxData_(initialMaxData), @@ -39,7 +41,8 @@ class ServerTransportParametersExtension : public fizz::ServerExtensions { idleTimeout_(idleTimeout), ackDelayExponent_(ackDelayExponent), maxRecvPacketSize_(maxRecvPacketSize), - partialReliability_(partialReliability) {} + partialReliability_(partialReliability), + token_(token) {} ~ServerTransportParametersExtension() override = default; @@ -87,8 +90,7 @@ class ServerTransportParametersExtension : public fizz::ServerExtensions { TransportParameterId::max_packet_size, maxRecvPacketSize_)); TransportParameter statelessReset; statelessReset.parameter = TransportParameterId::stateless_reset_token; - // TODO: replace this with a real stateless reset token. - statelessReset.value = folly::IOBuf::copyBuffer(kTestStatelessResetToken); + statelessReset.value = folly::IOBuf::copyBuffer(token_); params.parameters.push_back(std::move(statelessReset)); uint64_t partialReliabilitySetting = 0; @@ -121,5 +123,6 @@ class ServerTransportParametersExtension : public fizz::ServerExtensions { uint64_t maxRecvPacketSize_; TransportPartialReliabilitySetting partialReliability_; folly::Optional clientTransportParameters_; + StatelessResetToken token_; }; } // namespace quic diff --git a/quic/server/handshake/StatelessResetGenerator.h b/quic/server/handshake/StatelessResetGenerator.h index 013c80259..f2ba8db43 100644 --- a/quic/server/handshake/StatelessResetGenerator.h +++ b/quic/server/handshake/StatelessResetGenerator.h @@ -14,17 +14,18 @@ namespace quic { -using StatelessResetSecret = std::array; +using StatelessResetSecret = + std::array; /** * A StatelessResetToken generator. * - * This generator takes in a StatelessResetSecret, a string that represent - * address. It generates different StatelessResetToken given different - * ConnectionId. + * This generator takes in a StatelessResetSecret, and a string that represents + * the server address. It generates a different StatelessResetToken given a + * different ConnectionId. * * The StatelessResetSecret is provided to HKDF to generate a pesudorandom key. - * Address string and ConnectionId are concated together to as app specific + * Address string and ConnectionId are concated together, as app specific * input in HKDF-Expand. The output of HKDF will be the StatelessResetToken. * * PRK = HKDF-Extract(Salt, secret) @@ -33,7 +34,7 @@ using StatelessResetSecret = std::array; */ class StatelessResetGenerator { public: - StatelessResetGenerator( + explicit StatelessResetGenerator( StatelessResetSecret secret, const std::string& addressStr); diff --git a/quic/server/handshake/test/ServerHandshakeTest.cpp b/quic/server/handshake/test/ServerHandshakeTest.cpp index 995d09f31..4c4de75fd 100644 --- a/quic/server/handshake/test/ServerHandshakeTest.cpp +++ b/quic/server/handshake/test/ServerHandshakeTest.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -116,7 +117,8 @@ class ServerHandshakeTest : public Test { kDefaultIdleTimeout, kDefaultAckDelayExponent, kDefaultUDPSendPacketLen, - kDefaultPartialReliability); + kDefaultPartialReliability, + generateStatelessResetToken()); initialize(); handshake->accept(params); diff --git a/quic/server/handshake/test/ServerTransportParametersTest.cpp b/quic/server/handshake/test/ServerTransportParametersTest.cpp index 0dc03ff08..061c12a08 100644 --- a/quic/server/handshake/test/ServerTransportParametersTest.cpp +++ b/quic/server/handshake/test/ServerTransportParametersTest.cpp @@ -48,7 +48,8 @@ TEST(ServerTransportParametersTest, TestGetExtensions) { kDefaultIdleTimeout, kDefaultAckDelayExponent, kDefaultUDPSendPacketLen, - kDefaultPartialReliability); + kDefaultPartialReliability, + generateStatelessResetToken()); auto extensions = ext.getExtensions(getClientHello(folly::none)); EXPECT_EQ(extensions.size(), 1); @@ -58,6 +59,7 @@ TEST(ServerTransportParametersTest, TestGetExtensions) { } TEST(ServerTransportParametersTest, TestGetExtensionsD18) { + StatelessResetToken token = generateStatelessResetToken(); ServerTransportParametersExtension ext( QuicVersion::MVFST, {MVFST1, QuicVersion::MVFST}, @@ -70,13 +72,21 @@ TEST(ServerTransportParametersTest, TestGetExtensionsD18) { kDefaultIdleTimeout, kDefaultAckDelayExponent, kDefaultUDPSendPacketLen, - kDefaultPartialReliability); + kDefaultPartialReliability, + token); auto extensions = ext.getExtensions(getClientHello(QuicVersion::MVFST)); EXPECT_EQ(extensions.size(), 1); auto serverParams = getExtension(extensions); EXPECT_TRUE(serverParams.hasValue()); EXPECT_TRUE(serverParams->negotiated_version.hasValue()); + + folly::Optional tokWrapper = + getStatelessResetTokenParameter(serverParams->parameters); + + StatelessResetToken expectedToken; + EXPECT_NO_THROW(expectedToken = *tokWrapper); + EXPECT_EQ(token, expectedToken); } TEST(ServerTransportParametersTest, TestGetExtensionsMissingClientParams) { @@ -92,8 +102,9 @@ TEST(ServerTransportParametersTest, TestGetExtensionsMissingClientParams) { kDefaultIdleTimeout, kDefaultAckDelayExponent, kDefaultUDPSendPacketLen, - kDefaultPartialReliability); + kDefaultPartialReliability, + generateStatelessResetToken()); EXPECT_THROW(ext.getExtensions(TestMessages::clientHello()), FizzException); } -} -} +} // namespace test +} // namespace quic diff --git a/quic/server/state/ServerStateMachine.cpp b/quic/server/state/ServerStateMachine.cpp index b6da1e552..bb03cc608 100644 --- a/quic/server/state/ServerStateMachine.cpp +++ b/quic/server/state/ServerStateMachine.cpp @@ -431,6 +431,19 @@ void onServerReadDataFromOpen( return; } + CHECK(conn.connIdAlgo) << "ConnectionIdAlgo is not set."; + CHECK(!conn.serverConnectionId.hasValue()); + // serverConnIdParams must be set by the QuicServerTransport + CHECK(conn.serverConnIdParams); + + conn.serverConnectionId = + conn.connIdAlgo->encodeConnectionId(*conn.serverConnIdParams); + StatelessResetGenerator generator( + conn.transportSettings.statelessResetTokenSecret.value(), + conn.serverAddr.getFullyQualified()); + StatelessResetToken token = + generator.generateToken(*conn.serverConnectionId); + conn.serverHandshakeLayer->accept( std::make_shared( version, @@ -444,7 +457,8 @@ void onServerReadDataFromOpen( conn.transportSettings.idleTimeout, conn.transportSettings.ackDelayExponent, conn.transportSettings.maxRecvPacketSize, - conn.transportSettings.partialReliabilityEnabled)); + conn.transportSettings.partialReliabilityEnabled, + token)); QuicFizzFactory fizzFactory; conn.readCodec = std::make_unique(QuicNodeType::Server); conn.readCodec->setInitialReadCipher( @@ -593,8 +607,6 @@ void onServerReadDataFromOpen( // TODO: remove this when we actually negotiate connid and version if (!conn.clientConnectionId) { - // serverConnIdParams must be set by the QuicServerTransport - CHECK(conn.serverConnIdParams); conn.clientConnectionId = folly::variant_match( regularPacket.header, [](const LongHeader& longHeader) { @@ -607,10 +619,9 @@ void onServerReadDataFromOpen( CHECK(conn.clientConnectionId); // TODO: if conn.serverConnIdParams->clientConnId != conn.clientConnId, // we need to update sourceAddressMap_. + // TODO: need to remove ServerConnectionIdParams::clientConnId, it is no + // longer needed. conn.serverConnIdParams->clientConnId = *conn.clientConnectionId; - CHECK(conn.connIdAlgo) << "ConnectionIdAlgo is not set."; - conn.serverConnectionId = - conn.connIdAlgo->encodeConnectionId(*conn.serverConnIdParams); conn.readCodec->setServerConnectionId(*conn.serverConnectionId); } QUIC_TRACE(packet_recvd, conn, packetNum, packetSize); diff --git a/quic/server/state/ServerStateMachine.h b/quic/server/state/ServerStateMachine.h index 636aa5fad..a92cdfd84 100644 --- a/quic/server/state/ServerStateMachine.h +++ b/quic/server/state/ServerStateMachine.h @@ -110,6 +110,9 @@ struct QuicServerConnectionState : public QuicConnectionStateBase { // limited until CFIN depending on matching policy. folly::Optional sourceTokenMatching; + // Server address of VIP. Currently used as input for stateless reset token. + folly::SocketAddress serverAddr; + QuicServerConnectionState() : QuicConnectionStateBase(QuicNodeType::Server) { state = ServerState::Open; // Create the crypto stream. diff --git a/quic/server/test/QuicServerTest.cpp b/quic/server/test/QuicServerTest.cpp index 59013ebf5..400e7d38e 100644 --- a/quic/server/test/QuicServerTest.cpp +++ b/quic/server/test/QuicServerTest.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include using namespace testing; @@ -92,14 +93,16 @@ std::unique_ptr createData(size_t size) { class QuicServerWorkerTest : public Test { public: void SetUp() override { + fakeAddress_ = folly::SocketAddress("111.111.111.111", 44444); auto sock = std::make_unique(&eventbase_); DCHECK(sock->getEventBase()); - EXPECT_CALL(*sock, getNetworkSocket()) - .WillRepeatedly(Return(folly::NetworkSocket())); socketPtr_ = sock.get(); workerCb_ = std::make_shared(); worker_ = std::make_unique(workerCb_); auto transportInfoCb = std::make_unique(); + TransportSettings settings; + settings.statelessResetTokenSecret = getRandSecret(); + worker_->setTransportSettings(settings); worker_->setSocket(std::move(sock)); worker_->setWorkerId(42); worker_->setProcessId(ProcessId::ONE); @@ -126,6 +129,7 @@ class QuicServerWorkerTest : public Test { MockConnectionCallback connCb; auto mockSock = std::make_unique(&eventbase_); + EXPECT_CALL(*mockSock, address()).WillRepeatedly(ReturnRef(fakeAddress_)); transport_.reset(new MockQuicTransport( worker_->getEventBase(), std::move(mockSock), connCb, nullptr)); factory_ = std::make_unique(); @@ -155,6 +159,7 @@ class QuicServerWorkerTest : public Test { QuicTransportStatsCallback::PacketDropReason dropReason); protected: + folly::SocketAddress fakeAddress_; std::unique_ptr worker_; folly::EventBase eventbase_; MockQuicTransport::Ptr transport_; @@ -238,8 +243,7 @@ void QuicServerWorkerTest::testSendReset( Invoke([&](auto&, auto, auto) { return folly::none; })); codec.setOneRttReadCipher(std::move(aead)); codec.setOneRttHeaderCipher(test::createNoOpHeaderCipher()); - StatelessResetToken token; - memcpy(token.data(), kTestStatelessResetToken.data(), token.size()); + StatelessResetToken token = generateStatelessResetToken(); codec.setStatelessResetToken(token); AckStates ackStates; auto packetQueue = bufToQueue(buf->clone()); @@ -267,6 +271,7 @@ void QuicServerWorkerTest::testSendReset( TEST_F(QuicServerWorkerTest, HostIdMismatchTestReset) { auto data = folly::IOBuf::copyBuffer("data"); + EXPECT_CALL(*socketPtr_, address()).WillRepeatedly(ReturnRef(fakeAddress_)); PacketNum num = 2; // create packet with connId with different hostId encoded ShortHeader shortHeaderConnId( @@ -279,6 +284,7 @@ TEST_F(QuicServerWorkerTest, HostIdMismatchTestReset) { } TEST_F(QuicServerWorkerTest, NoConnFoundTestReset) { + EXPECT_CALL(*socketPtr_, address()).WillRepeatedly(ReturnRef(fakeAddress_)); auto data = folly::IOBuf::copyBuffer("data"); PacketNum num = 2; // create packet with connId with different hostId encoded @@ -293,6 +299,7 @@ TEST_F(QuicServerWorkerTest, NoConnFoundTestReset) { } TEST_F(QuicServerWorkerTest, QuicServerNewConnection) { + EXPECT_CALL(*socketPtr_, address()).WillRepeatedly(ReturnRef(fakeAddress_)); auto connId = getTestConnectionId(hostId_); createQuicConnection(kClientAddr, connId); @@ -351,6 +358,8 @@ TEST_F(QuicServerWorkerTest, QuicServerNewConnection) { MockConnectionCallback connCb; auto mockSock = std::make_unique(&eventbase_); + + EXPECT_CALL(*mockSock, address()).WillRepeatedly(ReturnRef(fakeAddress_)); MockQuicTransport::Ptr transport2 = std::make_shared( worker_->getEventBase(), std::move(mockSock), connCb, nullptr); EXPECT_CALL(*transport2, getEventBase()).WillRepeatedly(Return(&eventbase_)); @@ -933,6 +942,7 @@ class QuicServerTest : public Test { kDefaultStreamWindowSize * 2; transportSettings_.advertisedInitialUniStreamWindowSize = kDefaultStreamWindowSize * 2; + transportSettings_.statelessResetTokenSecret = getRandSecret(); server_->setTransportSettings(transportSettings_); server_->setConnectionIdAlgoFactory( std::make_unique()); @@ -1006,6 +1016,7 @@ class QuicServerTest : public Test { MockConnectionCallback cb; auto mockSock = std::make_unique(eventBase); + EXPECT_CALL(*mockSock, address()).WillRepeatedly(ReturnRef(serverAddr)); transport = std::make_shared( eventBase, std::move(mockSock), cb, quic::test::createServerCtx()); }); @@ -1634,8 +1645,7 @@ void QuicServerTest::testReset(Buf packet) { .WillRepeatedly(Invoke([&](auto&, auto, auto) { return folly::none; })); codec.setOneRttReadCipher(std::move(aead)); codec.setOneRttHeaderCipher(test::createNoOpHeaderCipher()); - StatelessResetToken token; - memcpy(token.data(), kTestStatelessResetToken.data(), token.size()); + StatelessResetToken token = generateStatelessResetToken(); codec.setStatelessResetToken(token); AckStates ackStates; auto packetQueue = bufToQueue(serverData->clone()); diff --git a/quic/server/test/QuicServerTransportTest.cpp b/quic/server/test/QuicServerTransportTest.cpp index 8a55300bc..5ef036928 100644 --- a/quic/server/test/QuicServerTransportTest.cpp +++ b/quic/server/test/QuicServerTransportTest.cpp @@ -265,6 +265,7 @@ class QuicServerTransportTest : public Test { void SetUp() override { QuicFizzFactory fizzFactory; clientAddr = folly::SocketAddress("127.0.0.1", 1000); + auto fakeServerAddr = folly::SocketAddress("1.2.3.4", 8080); clientConnectionId = getTestConnectionId(); initialDestinationConnectionId = clientConnectionId; // change the initialDestinationConnectionId to be different @@ -281,6 +282,7 @@ class QuicServerTransportTest : public Test { serverWrites.push_back(buf->clone()); return buf->computeChainDataLength(); })); + EXPECT_CALL(*sock, address()).WillRepeatedly(ReturnRef(fakeServerAddr)); supportedVersions = {QuicVersion::MVFST, QuicVersion::QUIC_DRAFT}; serverCtx = createServerCtx(); connIdAlgo_ = std::make_unique(); @@ -292,6 +294,8 @@ class QuicServerTransportTest : public Test { server->setSupportedVersions(supportedVersions); server->setOriginalPeerAddress(clientAddr); server->setServerConnectionIdParams(params); + server->getNonConstConn().transportSettings.statelessResetTokenSecret = + getRandSecret(); transportInfoCb_ = std::make_unique(); server->setTransportInfoCallback(transportInfoCb_.get()); initializeServerHandshake(); diff --git a/quic/state/TransportSettings.h b/quic/state/TransportSettings.h index 51f1e6cb3..b287a63bc 100644 --- a/quic/state/TransportSettings.h +++ b/quic/state/TransportSettings.h @@ -107,6 +107,9 @@ struct TransportSettings { bool partialReliabilityEnabled{false}; // Whether the endpoint allows peer to migrate to new address bool disableMigration{true}; + // default stateless reset secret for stateless reset token + folly::Optional> + statelessResetTokenSecret; }; } // namespace quic diff --git a/quic/state/test/QuicStateFunctionsTest.cpp b/quic/state/test/QuicStateFunctionsTest.cpp index 5bf488a6b..7321c9168 100644 --- a/quic/state/test/QuicStateFunctionsTest.cpp +++ b/quic/state/test/QuicStateFunctionsTest.cpp @@ -14,8 +14,6 @@ #include #include -#include - using namespace folly; using namespace testing; diff --git a/quic/state/test/StateMachineTest.cpp b/quic/state/test/StateMachineTest.cpp index b1d79d59d..bb250c083 100644 --- a/quic/state/test/StateMachineTest.cpp +++ b/quic/state/test/StateMachineTest.cpp @@ -8,7 +8,6 @@ #include #include -#include #include @@ -182,5 +181,5 @@ TEST_F(StateMachineTest, TestTemplateInvalid) { invokeHandler>(stateT, Event1(), stateT), InvalidHandlerException); } -} -} +} // namespace test +} // namespace quic