// Copyright (c) 2022 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "quiche/quic/core/deterministic_connection_id_generator.h" #include "quiche/quic/core/quic_utils.h" #include "quiche/quic/platform/api/quic_bug_tracker.h" #include "quiche/quic/platform/api/quic_logging.h" namespace quic { DeterministicConnectionIdGenerator::DeterministicConnectionIdGenerator( uint8_t expected_connection_id_length) : expected_connection_id_length_(expected_connection_id_length) { if (expected_connection_id_length_ > kQuicMaxConnectionIdWithLengthPrefixLength) { QUIC_BUG(quic_bug_465151159_01) << "Issuing connection IDs longer than allowed in RFC9000"; } } absl::optional DeterministicConnectionIdGenerator::GenerateNextConnectionId( const QuicConnectionId& original) { if (expected_connection_id_length_ == 0) { return EmptyQuicConnectionId(); } const uint64_t connection_id_hash64 = QuicUtils::FNV1a_64_Hash( absl::string_view(original.data(), original.length())); if (expected_connection_id_length_ <= sizeof(uint64_t)) { return QuicConnectionId( reinterpret_cast(&connection_id_hash64), expected_connection_id_length_); } char new_connection_id_data[255] = {}; const absl::uint128 connection_id_hash128 = QuicUtils::FNV1a_128_Hash( absl::string_view(original.data(), original.length())); static_assert(sizeof(connection_id_hash64) + sizeof(connection_id_hash128) <= sizeof(new_connection_id_data), "bad size"); memcpy(new_connection_id_data, &connection_id_hash64, sizeof(connection_id_hash64)); // TODO(martinduke): We don't have any test coverage of the line below. In // particular, if the memcpy somehow misses a byte, a test could check if one // byte position in generated connection IDs is always the same. memcpy(new_connection_id_data + sizeof(connection_id_hash64), &connection_id_hash128, sizeof(connection_id_hash128)); return QuicConnectionId(new_connection_id_data, expected_connection_id_length_); } absl::optional DeterministicConnectionIdGenerator::MaybeReplaceConnectionId( const QuicConnectionId& original, const ParsedQuicVersion& version) { if (original.length() == expected_connection_id_length_) { return absl::optional(); } QUICHE_DCHECK(version.AllowsVariableLengthConnectionIds()); absl::optional new_connection_id = GenerateNextConnectionId(original); // Verify that ReplaceShortServerConnectionId is deterministic. QUICHE_DCHECK(new_connection_id.has_value()); QUICHE_DCHECK_EQ( *new_connection_id, static_cast(*GenerateNextConnectionId(original))); QUICHE_DCHECK_EQ(expected_connection_id_length_, new_connection_id->length()); QUIC_DLOG(INFO) << "Replacing incoming connection ID " << original << " with " << new_connection_id.value(); return new_connection_id; } } // namespace quic