1 // Copyright (c) 2022 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/deterministic_connection_id_generator.h"
6
7 #include "quiche/quic/core/quic_utils.h"
8 #include "quiche/quic/platform/api/quic_bug_tracker.h"
9 #include "quiche/quic/platform/api/quic_logging.h"
10
11 namespace quic {
12
DeterministicConnectionIdGenerator(uint8_t expected_connection_id_length)13 DeterministicConnectionIdGenerator::DeterministicConnectionIdGenerator(
14 uint8_t expected_connection_id_length)
15 : expected_connection_id_length_(expected_connection_id_length) {
16 if (expected_connection_id_length_ >
17 kQuicMaxConnectionIdWithLengthPrefixLength) {
18 QUIC_BUG(quic_bug_465151159_01)
19 << "Issuing connection IDs longer than allowed in RFC9000";
20 }
21 }
22
23 absl::optional<QuicConnectionId>
GenerateNextConnectionId(const QuicConnectionId & original)24 DeterministicConnectionIdGenerator::GenerateNextConnectionId(
25 const QuicConnectionId& original) {
26 if (expected_connection_id_length_ == 0) {
27 return EmptyQuicConnectionId();
28 }
29 const uint64_t connection_id_hash64 = QuicUtils::FNV1a_64_Hash(
30 absl::string_view(original.data(), original.length()));
31 if (expected_connection_id_length_ <= sizeof(uint64_t)) {
32 return QuicConnectionId(
33 reinterpret_cast<const char*>(&connection_id_hash64),
34 expected_connection_id_length_);
35 }
36 char new_connection_id_data[255] = {};
37 const absl::uint128 connection_id_hash128 = QuicUtils::FNV1a_128_Hash(
38 absl::string_view(original.data(), original.length()));
39 static_assert(sizeof(connection_id_hash64) + sizeof(connection_id_hash128) <=
40 sizeof(new_connection_id_data),
41 "bad size");
42 memcpy(new_connection_id_data, &connection_id_hash64,
43 sizeof(connection_id_hash64));
44 // TODO(martinduke): We don't have any test coverage of the line below. In
45 // particular, if the memcpy somehow misses a byte, a test could check if one
46 // byte position in generated connection IDs is always the same.
47 memcpy(new_connection_id_data + sizeof(connection_id_hash64),
48 &connection_id_hash128, sizeof(connection_id_hash128));
49 return QuicConnectionId(new_connection_id_data,
50 expected_connection_id_length_);
51 }
52
53 absl::optional<QuicConnectionId>
MaybeReplaceConnectionId(const QuicConnectionId & original,const ParsedQuicVersion & version)54 DeterministicConnectionIdGenerator::MaybeReplaceConnectionId(
55 const QuicConnectionId& original, const ParsedQuicVersion& version) {
56 if (original.length() == expected_connection_id_length_) {
57 return absl::optional<QuicConnectionId>();
58 }
59 QUICHE_DCHECK(version.AllowsVariableLengthConnectionIds());
60 absl::optional<QuicConnectionId> new_connection_id =
61 GenerateNextConnectionId(original);
62 // Verify that ReplaceShortServerConnectionId is deterministic.
63 QUICHE_DCHECK(new_connection_id.has_value());
64 QUICHE_DCHECK_EQ(
65 *new_connection_id,
66 static_cast<QuicConnectionId>(*GenerateNextConnectionId(original)));
67 QUICHE_DCHECK_EQ(expected_connection_id_length_, new_connection_id->length());
68 QUIC_DLOG(INFO) << "Replacing incoming connection ID " << original << " with "
69 << new_connection_id.value();
70 return new_connection_id;
71 }
72
73 } // namespace quic
74