1 // Copyright 2018 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/quic_connection_id.h"
6
7 #include <cstddef>
8 #include <cstdint>
9 #include <cstring>
10 #include <iomanip>
11 #include <string>
12
13 #include "absl/strings/escaping.h"
14 #include "openssl/siphash.h"
15 #include "quiche/quic/core/crypto/quic_random.h"
16 #include "quiche/quic/core/quic_types.h"
17 #include "quiche/quic/platform/api/quic_bug_tracker.h"
18 #include "quiche/quic/platform/api/quic_flag_utils.h"
19 #include "quiche/quic/platform/api/quic_flags.h"
20 #include "quiche/quic/platform/api/quic_logging.h"
21 #include "quiche/common/quiche_endian.h"
22
23 namespace quic {
24
25 namespace {
26
27 // QuicConnectionIdHasher can be used to generate a stable connection ID hash
28 // function that will return the same value for two equal connection IDs for
29 // the duration of process lifetime. It is meant to be used as input to data
30 // structures that do not outlast process lifetime. A new key is generated once
31 // per process to prevent attackers from crafting connection IDs in such a way
32 // that they always land in the same hash bucket.
33 class QuicConnectionIdHasher {
34 public:
QuicConnectionIdHasher()35 inline QuicConnectionIdHasher()
36 : QuicConnectionIdHasher(QuicRandom::GetInstance()) {}
37
QuicConnectionIdHasher(QuicRandom * random)38 explicit inline QuicConnectionIdHasher(QuicRandom* random) {
39 random->RandBytes(&sip_hash_key_, sizeof(sip_hash_key_));
40 }
41
Hash(const char * input,size_t input_len) const42 inline size_t Hash(const char* input, size_t input_len) const {
43 return static_cast<size_t>(SIPHASH_24(
44 sip_hash_key_, reinterpret_cast<const uint8_t*>(input), input_len));
45 }
46
47 private:
48 uint64_t sip_hash_key_[2];
49 };
50
51 } // namespace
52
QuicConnectionId()53 QuicConnectionId::QuicConnectionId() : QuicConnectionId(nullptr, 0) {
54 static_assert(offsetof(QuicConnectionId, padding_) ==
55 offsetof(QuicConnectionId, length_),
56 "bad offset");
57 static_assert(sizeof(QuicConnectionId) <= 16, "bad size");
58 }
59
QuicConnectionId(const char * data,uint8_t length)60 QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
61 length_ = length;
62 if (length_ == 0) {
63 return;
64 }
65 if (length_ <= sizeof(data_short_)) {
66 memcpy(data_short_, data, length_);
67 return;
68 }
69 data_long_ = reinterpret_cast<char*>(malloc(length_));
70 QUICHE_CHECK_NE(nullptr, data_long_);
71 memcpy(data_long_, data, length_);
72 }
73
QuicConnectionId(const absl::Span<const uint8_t> data)74 QuicConnectionId::QuicConnectionId(const absl::Span<const uint8_t> data)
75 : QuicConnectionId(reinterpret_cast<const char*>(data.data()),
76 data.length()) {}
77
~QuicConnectionId()78 QuicConnectionId::~QuicConnectionId() {
79 if (length_ > sizeof(data_short_)) {
80 free(data_long_);
81 data_long_ = nullptr;
82 }
83 }
84
QuicConnectionId(const QuicConnectionId & other)85 QuicConnectionId::QuicConnectionId(const QuicConnectionId& other)
86 : QuicConnectionId(other.data(), other.length()) {}
87
operator =(const QuicConnectionId & other)88 QuicConnectionId& QuicConnectionId::operator=(const QuicConnectionId& other) {
89 set_length(other.length());
90 memcpy(mutable_data(), other.data(), length_);
91 return *this;
92 }
93
data() const94 const char* QuicConnectionId::data() const {
95 if (length_ <= sizeof(data_short_)) {
96 return data_short_;
97 }
98 return data_long_;
99 }
100
mutable_data()101 char* QuicConnectionId::mutable_data() {
102 if (length_ <= sizeof(data_short_)) {
103 return data_short_;
104 }
105 return data_long_;
106 }
107
length() const108 uint8_t QuicConnectionId::length() const { return length_; }
109
set_length(uint8_t length)110 void QuicConnectionId::set_length(uint8_t length) {
111 char temporary_data[sizeof(data_short_)];
112 if (length > sizeof(data_short_)) {
113 if (length_ <= sizeof(data_short_)) {
114 // Copy data from data_short_ to data_long_.
115 memcpy(temporary_data, data_short_, length_);
116 data_long_ = reinterpret_cast<char*>(malloc(length));
117 QUICHE_CHECK_NE(nullptr, data_long_);
118 memcpy(data_long_, temporary_data, length_);
119 } else {
120 // Resize data_long_.
121 char* realloc_result =
122 reinterpret_cast<char*>(realloc(data_long_, length));
123 QUICHE_CHECK_NE(nullptr, realloc_result);
124 data_long_ = realloc_result;
125 }
126 } else if (length_ > sizeof(data_short_)) {
127 // Copy data from data_long_ to data_short_.
128 memcpy(temporary_data, data_long_, length);
129 free(data_long_);
130 data_long_ = nullptr;
131 memcpy(data_short_, temporary_data, length);
132 }
133 length_ = length;
134 }
135
IsEmpty() const136 bool QuicConnectionId::IsEmpty() const { return length_ == 0; }
137
Hash() const138 size_t QuicConnectionId::Hash() const {
139 static const QuicConnectionIdHasher hasher = QuicConnectionIdHasher();
140 return hasher.Hash(data(), length_);
141 }
142
ToString() const143 std::string QuicConnectionId::ToString() const {
144 if (IsEmpty()) {
145 return std::string("0");
146 }
147 return absl::BytesToHexString(absl::string_view(data(), length_));
148 }
149
operator <<(std::ostream & os,const QuicConnectionId & v)150 std::ostream& operator<<(std::ostream& os, const QuicConnectionId& v) {
151 os << v.ToString();
152 return os;
153 }
154
operator ==(const QuicConnectionId & v) const155 bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
156 return length_ == v.length_ && memcmp(data(), v.data(), length_) == 0;
157 }
158
operator !=(const QuicConnectionId & v) const159 bool QuicConnectionId::operator!=(const QuicConnectionId& v) const {
160 return !(v == *this);
161 }
162
operator <(const QuicConnectionId & v) const163 bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
164 if (length_ < v.length_) {
165 return true;
166 }
167 if (length_ > v.length_) {
168 return false;
169 }
170 return memcmp(data(), v.data(), length_) < 0;
171 }
172
EmptyQuicConnectionId()173 QuicConnectionId EmptyQuicConnectionId() { return QuicConnectionId(); }
174
175 static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
176 "kQuicDefaultConnectionIdLength changed");
177 static_assert(kQuicDefaultConnectionIdLength == 8,
178 "kQuicDefaultConnectionIdLength changed");
179
180 } // namespace quic
181