blob: 7e31f16adb26fefbfac7b09a436f7c2205ae6e79 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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 "net/third_party/quiche/src/quic/core/quic_connection_id.h"
6
dschinazi0fdff8e2019-07-18 09:07:39 -07007#include <cstddef>
QUICHE teama6ef0a62019-03-07 20:34:33 -05008#include <cstdint>
9#include <cstring>
10#include <iomanip>
vasilvv872e7a32019-03-12 16:42:44 -070011#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050012
dschinazi0fdff8e2019-07-18 09:07:39 -070013#include "third_party/boringssl/src/include/openssl/siphash.h"
14#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/core/quic_types.h"
16#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
18#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
19#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
QUICHE team173c48f2019-11-19 16:34:44 -080020#include "net/third_party/quiche/src/common/platform/api/quiche_endian.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080021#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050022
23namespace quic {
24
dschinazi0fdff8e2019-07-18 09:07:39 -070025namespace {
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.
33class QuicConnectionIdHasher {
34 public:
dschinazi2d014822019-07-18 15:28:13 -070035 inline QuicConnectionIdHasher()
dschinazi0fdff8e2019-07-18 09:07:39 -070036 : QuicConnectionIdHasher(QuicRandom::GetInstance()) {}
37
38 explicit inline QuicConnectionIdHasher(QuicRandom* random) {
39 random->RandBytes(&sip_hash_key_, sizeof(sip_hash_key_));
40 }
41
42 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
dschinazib3241162019-06-10 17:59:37 -070053QuicConnectionId::QuicConnectionId() : QuicConnectionId(nullptr, 0) {}
QUICHE teama6ef0a62019-03-07 20:34:33 -050054
55QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
QUICHE teama6ef0a62019-03-07 20:34:33 -050056 length_ = length;
dschinazib3241162019-06-10 17:59:37 -070057 if (length_ == 0) {
58 return;
59 }
dschinazib3241162019-06-10 17:59:37 -070060 if (length_ <= sizeof(data_short_)) {
61 memcpy(data_short_, data, length_);
62 return;
63 }
64 data_long_ = reinterpret_cast<char*>(malloc(length_));
65 CHECK_NE(nullptr, data_long_);
66 memcpy(data_long_, data, length_);
67}
68
69QuicConnectionId::~QuicConnectionId() {
dschinazib3241162019-06-10 17:59:37 -070070 if (length_ > sizeof(data_short_)) {
71 free(data_long_);
72 data_long_ = nullptr;
QUICHE teama6ef0a62019-03-07 20:34:33 -050073 }
74}
75
dschinazib3241162019-06-10 17:59:37 -070076QuicConnectionId::QuicConnectionId(const QuicConnectionId& other)
77 : QuicConnectionId(other.data(), other.length()) {}
78
79QuicConnectionId& QuicConnectionId::operator=(const QuicConnectionId& other) {
80 set_length(other.length());
81 memcpy(mutable_data(), other.data(), length_);
82 return *this;
83}
QUICHE teama6ef0a62019-03-07 20:34:33 -050084
85const char* QuicConnectionId::data() const {
dschinazib3241162019-06-10 17:59:37 -070086 if (length_ <= sizeof(data_short_)) {
87 return data_short_;
88 }
89 return data_long_;
QUICHE teama6ef0a62019-03-07 20:34:33 -050090}
91
92char* QuicConnectionId::mutable_data() {
dschinazib3241162019-06-10 17:59:37 -070093 if (length_ <= sizeof(data_short_)) {
94 return data_short_;
95 }
96 return data_long_;
QUICHE teama6ef0a62019-03-07 20:34:33 -050097}
98
99uint8_t QuicConnectionId::length() const {
100 return length_;
101}
102
103void QuicConnectionId::set_length(uint8_t length) {
dschinazi0d06d7b2019-08-19 14:33:07 -0700104 char temporary_data[sizeof(data_short_)];
105 if (length > sizeof(data_short_)) {
106 if (length_ <= sizeof(data_short_)) {
107 // Copy data from data_short_ to data_long_.
108 memcpy(temporary_data, data_short_, length_);
109 data_long_ = reinterpret_cast<char*>(malloc(length));
110 CHECK_NE(nullptr, data_long_);
111 memcpy(data_long_, temporary_data, length_);
112 } else {
113 // Resize data_long_.
114 char* realloc_result =
115 reinterpret_cast<char*>(realloc(data_long_, length));
116 CHECK_NE(nullptr, realloc_result);
117 data_long_ = realloc_result;
dschinazib3241162019-06-10 17:59:37 -0700118 }
dschinazi0d06d7b2019-08-19 14:33:07 -0700119 } else if (length_ > sizeof(data_short_)) {
120 // Copy data from data_long_ to data_short_.
121 memcpy(temporary_data, data_long_, length);
122 free(data_long_);
123 data_long_ = nullptr;
124 memcpy(data_short_, temporary_data, length);
dschinazib3241162019-06-10 17:59:37 -0700125 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500126 length_ = length;
127}
128
129bool QuicConnectionId::IsEmpty() const {
130 return length_ == 0;
131}
132
133size_t QuicConnectionId::Hash() const {
dschinazi0fdff8e2019-07-18 09:07:39 -0700134 static const QuicConnectionIdHasher hasher = QuicConnectionIdHasher();
135 return hasher.Hash(data(), length_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500136}
137
vasilvvc48c8712019-03-11 13:38:16 -0700138std::string QuicConnectionId::ToString() const {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500139 if (IsEmpty()) {
vasilvvc48c8712019-03-11 13:38:16 -0700140 return std::string("0");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500141 }
dmcardlecf0bfcf2019-12-13 08:08:21 -0800142 return quiche::QuicheTextUtils::HexEncode(data(), length_);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500143}
144
145std::ostream& operator<<(std::ostream& os, const QuicConnectionId& v) {
146 os << v.ToString();
147 return os;
148}
149
150bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
dschinazib3241162019-06-10 17:59:37 -0700151 return length_ == v.length_ && memcmp(data(), v.data(), length_) == 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500152}
153
154bool QuicConnectionId::operator!=(const QuicConnectionId& v) const {
155 return !(v == *this);
156}
157
158bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
159 if (length_ < v.length_) {
160 return true;
161 }
162 if (length_ > v.length_) {
163 return false;
164 }
dschinazib3241162019-06-10 17:59:37 -0700165 return memcmp(data(), v.data(), length_) < 0;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500166}
167
168QuicConnectionId EmptyQuicConnectionId() {
169 return QuicConnectionId();
170}
171
172static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
173 "kQuicDefaultConnectionIdLength changed");
174static_assert(kQuicDefaultConnectionIdLength == PACKET_8BYTE_CONNECTION_ID,
175 "kQuicDefaultConnectionIdLength changed");
176
177} // namespace quic