1 // Copyright 2020 The Chromium Authors
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/dns/https_record_rdata.h"
6
7 #include <stdint.h>
8
9 #include <map>
10 #include <memory>
11 #include <optional>
12 #include <set>
13 #include <string>
14 #include <string_view>
15 #include <utility>
16 #include <vector>
17
18 #include "base/big_endian.h"
19 #include "base/check.h"
20 #include "base/containers/contains.h"
21 #include "base/dcheck_is_on.h"
22 #include "base/immediate_crash.h"
23 #include "base/memory/ptr_util.h"
24 #include "base/numerics/byte_conversions.h"
25 #include "net/base/ip_address.h"
26 #include "net/dns/dns_names_util.h"
27 #include "net/dns/public/dns_protocol.h"
28
29 namespace net {
30
31 namespace {
32
ReadNextServiceParam(std::optional<uint16_t> last_key,base::SpanReader<const uint8_t> & reader,uint16_t * out_param_key,std::string_view * out_param_value)33 bool ReadNextServiceParam(std::optional<uint16_t> last_key,
34 base::SpanReader<const uint8_t>& reader,
35 uint16_t* out_param_key,
36 std::string_view* out_param_value) {
37 DCHECK(out_param_key);
38 DCHECK(out_param_value);
39
40 uint16_t key;
41 if (!reader.ReadU16BigEndian(key)) {
42 return false;
43 }
44 if (last_key.has_value() && last_key.value() >= key)
45 return false;
46
47 base::span<const uint8_t> value;
48 if (!dns_names_util::ReadU16LengthPrefixed(reader, &value)) {
49 return false;
50 }
51
52 *out_param_key = key;
53 *out_param_value = base::as_string_view(value);
54 return true;
55 }
56
ParseMandatoryKeys(std::string_view param_value,std::set<uint16_t> * out_parsed)57 bool ParseMandatoryKeys(std::string_view param_value,
58 std::set<uint16_t>* out_parsed) {
59 DCHECK(out_parsed);
60
61 auto reader = base::SpanReader(base::as_byte_span(param_value));
62
63 std::set<uint16_t> mandatory_keys;
64 // Do/while to require at least one key.
65 do {
66 uint16_t key;
67 if (!reader.ReadU16BigEndian(key)) {
68 return false;
69 }
70
71 // Mandatory key itself is disallowed from its list.
72 if (key == dns_protocol::kHttpsServiceParamKeyMandatory)
73 return false;
74 // Keys required to be listed in ascending order.
75 if (!mandatory_keys.empty() && key <= *mandatory_keys.rbegin())
76 return false;
77
78 CHECK(mandatory_keys.insert(key).second);
79 } while (reader.remaining() > 0u);
80
81 *out_parsed = std::move(mandatory_keys);
82 return true;
83 }
84
ParseAlpnIds(std::string_view param_value,std::vector<std::string> * out_parsed)85 bool ParseAlpnIds(std::string_view param_value,
86 std::vector<std::string>* out_parsed) {
87 DCHECK(out_parsed);
88
89 auto reader = base::SpanReader(base::as_byte_span(param_value));
90
91 std::vector<std::string> alpn_ids;
92 // Do/while to require at least one ID.
93 do {
94 base::span<const uint8_t> alpn_id;
95 if (!dns_names_util::ReadU8LengthPrefixed(reader, &alpn_id)) {
96 return false;
97 }
98 if (alpn_id.size() < 1u) {
99 return false;
100 }
101 DCHECK_LE(alpn_id.size(), 255u);
102
103 alpn_ids.emplace_back(base::as_string_view(alpn_id));
104 } while (reader.remaining() > 0u);
105
106 *out_parsed = std::move(alpn_ids);
107 return true;
108 }
109
110 template <size_t ADDRESS_SIZE>
ParseIpAddresses(std::string_view param_value,std::vector<IPAddress> * out_addresses)111 bool ParseIpAddresses(std::string_view param_value,
112 std::vector<IPAddress>* out_addresses) {
113 DCHECK(out_addresses);
114
115 auto reader = base::SpanReader(base::as_byte_span(param_value));
116
117 std::vector<IPAddress> addresses;
118 do {
119 if (auto addr_bytes = reader.template Read<ADDRESS_SIZE>();
120 !addr_bytes.has_value()) {
121 return false;
122 } else {
123 addresses.emplace_back(*addr_bytes);
124 }
125 DCHECK(addresses.back().IsValid());
126 } while (reader.remaining() > 0u);
127
128 *out_addresses = std::move(addresses);
129 return true;
130 }
131
132 } // namespace
133
134 // static
Parse(std::string_view data)135 std::unique_ptr<HttpsRecordRdata> HttpsRecordRdata::Parse(
136 std::string_view data) {
137 if (!HasValidSize(data, kType))
138 return nullptr;
139
140 auto reader = base::SpanReader(base::as_byte_span(data));
141 uint16_t priority;
142 CHECK(reader.ReadU16BigEndian(priority));
143
144 if (priority == 0) {
145 return AliasFormHttpsRecordRdata::Parse(data);
146 }
147 return ServiceFormHttpsRecordRdata::Parse(data);
148 }
149
150 HttpsRecordRdata::~HttpsRecordRdata() = default;
151
IsEqual(const RecordRdata * other) const152 bool HttpsRecordRdata::IsEqual(const RecordRdata* other) const {
153 DCHECK(other);
154
155 if (other->Type() != kType)
156 return false;
157
158 const HttpsRecordRdata* https = static_cast<const HttpsRecordRdata*>(other);
159 return IsEqual(https);
160 }
161
Type() const162 uint16_t HttpsRecordRdata::Type() const {
163 return kType;
164 }
165
AsAliasForm()166 AliasFormHttpsRecordRdata* HttpsRecordRdata::AsAliasForm() {
167 CHECK(IsAlias());
168 return static_cast<AliasFormHttpsRecordRdata*>(this);
169 }
170
AsAliasForm() const171 const AliasFormHttpsRecordRdata* HttpsRecordRdata::AsAliasForm() const {
172 return const_cast<HttpsRecordRdata*>(this)->AsAliasForm();
173 }
174
AsServiceForm()175 ServiceFormHttpsRecordRdata* HttpsRecordRdata::AsServiceForm() {
176 CHECK(!IsAlias());
177 return static_cast<ServiceFormHttpsRecordRdata*>(this);
178 }
179
AsServiceForm() const180 const ServiceFormHttpsRecordRdata* HttpsRecordRdata::AsServiceForm() const {
181 return const_cast<HttpsRecordRdata*>(this)->AsServiceForm();
182 }
183
AliasFormHttpsRecordRdata(std::string alias_name)184 AliasFormHttpsRecordRdata::AliasFormHttpsRecordRdata(std::string alias_name)
185 : alias_name_(std::move(alias_name)) {}
186
187 // static
Parse(std::string_view data)188 std::unique_ptr<AliasFormHttpsRecordRdata> AliasFormHttpsRecordRdata::Parse(
189 std::string_view data) {
190 auto reader = base::SpanReader(base::as_byte_span(data));
191
192 uint16_t priority;
193 if (!reader.ReadU16BigEndian(priority)) {
194 return nullptr;
195 }
196 if (priority != 0u) {
197 return nullptr;
198 }
199
200 std::optional<std::string> alias_name =
201 dns_names_util::NetworkToDottedName(reader, true /* require_complete */);
202 if (!alias_name.has_value())
203 return nullptr;
204
205 // Ignore any params.
206 std::optional<uint16_t> last_param_key;
207 while (reader.remaining() > 0u) {
208 uint16_t param_key;
209 std::string_view param_value;
210 if (!ReadNextServiceParam(last_param_key, reader, ¶m_key, ¶m_value))
211 return nullptr;
212 last_param_key = param_key;
213 }
214
215 return std::make_unique<AliasFormHttpsRecordRdata>(
216 std::move(alias_name).value());
217 }
218
IsEqual(const HttpsRecordRdata * other) const219 bool AliasFormHttpsRecordRdata::IsEqual(const HttpsRecordRdata* other) const {
220 DCHECK(other);
221
222 if (!other->IsAlias())
223 return false;
224
225 const AliasFormHttpsRecordRdata* alias = other->AsAliasForm();
226 return alias_name_ == alias->alias_name_;
227 }
228
IsAlias() const229 bool AliasFormHttpsRecordRdata::IsAlias() const {
230 return true;
231 }
232
233 // static
234 constexpr uint16_t ServiceFormHttpsRecordRdata::kSupportedKeys[];
235
ServiceFormHttpsRecordRdata(HttpsRecordPriority priority,std::string service_name,std::set<uint16_t> mandatory_keys,std::vector<std::string> alpn_ids,bool default_alpn,std::optional<uint16_t> port,std::vector<IPAddress> ipv4_hint,std::string ech_config,std::vector<IPAddress> ipv6_hint,std::map<uint16_t,std::string> unparsed_params)236 ServiceFormHttpsRecordRdata::ServiceFormHttpsRecordRdata(
237 HttpsRecordPriority priority,
238 std::string service_name,
239 std::set<uint16_t> mandatory_keys,
240 std::vector<std::string> alpn_ids,
241 bool default_alpn,
242 std::optional<uint16_t> port,
243 std::vector<IPAddress> ipv4_hint,
244 std::string ech_config,
245 std::vector<IPAddress> ipv6_hint,
246 std::map<uint16_t, std::string> unparsed_params)
247 : priority_(priority),
248 service_name_(std::move(service_name)),
249 mandatory_keys_(std::move(mandatory_keys)),
250 alpn_ids_(std::move(alpn_ids)),
251 default_alpn_(default_alpn),
252 port_(port),
253 ipv4_hint_(std::move(ipv4_hint)),
254 ech_config_(std::move(ech_config)),
255 ipv6_hint_(std::move(ipv6_hint)),
256 unparsed_params_(std::move(unparsed_params)) {
257 DCHECK_NE(priority_, 0);
258 DCHECK(!base::Contains(mandatory_keys_,
259 dns_protocol::kHttpsServiceParamKeyMandatory));
260
261 #if DCHECK_IS_ON()
262 for (const IPAddress& address : ipv4_hint_) {
263 DCHECK(address.IsIPv4());
264 }
265 for (const IPAddress& address : ipv6_hint_) {
266 DCHECK(address.IsIPv6());
267 }
268 for (const auto& unparsed_param : unparsed_params_) {
269 DCHECK(!IsSupportedKey(unparsed_param.first));
270 }
271 #endif // DCHECK_IS_ON()
272 }
273
274 ServiceFormHttpsRecordRdata::~ServiceFormHttpsRecordRdata() = default;
275
IsEqual(const HttpsRecordRdata * other) const276 bool ServiceFormHttpsRecordRdata::IsEqual(const HttpsRecordRdata* other) const {
277 DCHECK(other);
278
279 if (other->IsAlias())
280 return false;
281
282 const ServiceFormHttpsRecordRdata* service = other->AsServiceForm();
283 return priority_ == service->priority_ &&
284 service_name_ == service->service_name_ &&
285 mandatory_keys_ == service->mandatory_keys_ &&
286 alpn_ids_ == service->alpn_ids_ &&
287 default_alpn_ == service->default_alpn_ && port_ == service->port_ &&
288 ipv4_hint_ == service->ipv4_hint_ &&
289 ech_config_ == service->ech_config_ &&
290 ipv6_hint_ == service->ipv6_hint_;
291 }
292
IsAlias() const293 bool ServiceFormHttpsRecordRdata::IsAlias() const {
294 return false;
295 }
296
297 // static
Parse(std::string_view data)298 std::unique_ptr<ServiceFormHttpsRecordRdata> ServiceFormHttpsRecordRdata::Parse(
299 std::string_view data) {
300 auto reader = base::SpanReader(base::as_byte_span(data));
301
302 uint16_t priority;
303 if (!reader.ReadU16BigEndian(priority)) {
304 return nullptr;
305 }
306 if (priority == 0u) {
307 return nullptr;
308 }
309
310 std::optional<std::string> service_name =
311 dns_names_util::NetworkToDottedName(reader, true /* require_complete */);
312 if (!service_name.has_value())
313 return nullptr;
314
315 if (reader.remaining() == 0u) {
316 return std::make_unique<ServiceFormHttpsRecordRdata>(
317 HttpsRecordPriority{priority}, std::move(service_name).value(),
318 std::set<uint16_t>() /* mandatory_keys */,
319 std::vector<std::string>() /* alpn_ids */, true /* default_alpn */,
320 std::nullopt /* port */, std::vector<IPAddress>() /* ipv4_hint */,
321 std::string() /* ech_config */,
322 std::vector<IPAddress>() /* ipv6_hint */,
323 std::map<uint16_t, std::string>() /* unparsed_params */);
324 }
325
326 uint16_t param_key = 0;
327 std::string_view param_value;
328 if (!ReadNextServiceParam(std::nullopt /* last_key */, reader, ¶m_key,
329 ¶m_value)) {
330 return nullptr;
331 }
332
333 // Assume keys less than Mandatory are not possible.
334 DCHECK_GE(param_key, dns_protocol::kHttpsServiceParamKeyMandatory);
335
336 std::set<uint16_t> mandatory_keys;
337 if (param_key == dns_protocol::kHttpsServiceParamKeyMandatory) {
338 DCHECK(IsSupportedKey(param_key));
339 if (!ParseMandatoryKeys(param_value, &mandatory_keys))
340 return nullptr;
341 if (reader.remaining() > 0 &&
342 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
343 return nullptr;
344 }
345 }
346
347 std::vector<std::string> alpn_ids;
348 if (param_key == dns_protocol::kHttpsServiceParamKeyAlpn) {
349 DCHECK(IsSupportedKey(param_key));
350 if (!ParseAlpnIds(param_value, &alpn_ids))
351 return nullptr;
352 if (reader.remaining() > 0 &&
353 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
354 return nullptr;
355 }
356 }
357
358 bool default_alpn = true;
359 if (param_key == dns_protocol::kHttpsServiceParamKeyNoDefaultAlpn) {
360 DCHECK(IsSupportedKey(param_key));
361 if (!param_value.empty())
362 return nullptr;
363 default_alpn = false;
364 if (reader.remaining() > 0 &&
365 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
366 return nullptr;
367 }
368 }
369
370 std::optional<uint16_t> port;
371 if (param_key == dns_protocol::kHttpsServiceParamKeyPort) {
372 DCHECK(IsSupportedKey(param_key));
373 if (param_value.size() != 2)
374 return nullptr;
375 uint16_t port_val =
376 base::U16FromBigEndian(base::as_byte_span(param_value).first<2>());
377 port = port_val;
378 if (reader.remaining() > 0 &&
379 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
380 return nullptr;
381 }
382 }
383
384 std::vector<IPAddress> ipv4_hint;
385 if (param_key == dns_protocol::kHttpsServiceParamKeyIpv4Hint) {
386 DCHECK(IsSupportedKey(param_key));
387 if (!ParseIpAddresses<IPAddress::kIPv4AddressSize>(param_value, &ipv4_hint))
388 return nullptr;
389 if (reader.remaining() > 0 &&
390 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
391 return nullptr;
392 }
393 }
394
395 std::string ech_config;
396 if (param_key == dns_protocol::kHttpsServiceParamKeyEchConfig) {
397 DCHECK(IsSupportedKey(param_key));
398 ech_config = std::string(param_value.data(), param_value.size());
399 if (reader.remaining() > 0 &&
400 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
401 return nullptr;
402 }
403 }
404
405 std::vector<IPAddress> ipv6_hint;
406 if (param_key == dns_protocol::kHttpsServiceParamKeyIpv6Hint) {
407 DCHECK(IsSupportedKey(param_key));
408 if (!ParseIpAddresses<IPAddress::kIPv6AddressSize>(param_value, &ipv6_hint))
409 return nullptr;
410 if (reader.remaining() > 0 &&
411 !ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value)) {
412 return nullptr;
413 }
414 }
415
416 // Note that if parsing has already reached the end of the rdata, `param_key`
417 // is still set for whatever param was read last.
418 std::map<uint16_t, std::string> unparsed_params;
419 if (param_key > dns_protocol::kHttpsServiceParamKeyIpv6Hint) {
420 for (;;) {
421 DCHECK(!IsSupportedKey(param_key));
422 CHECK(unparsed_params
423 .emplace(param_key, static_cast<std::string>(param_value))
424 .second);
425 if (reader.remaining() == 0)
426 break;
427 if (!ReadNextServiceParam(param_key, reader, ¶m_key, ¶m_value))
428 return nullptr;
429 }
430 }
431
432 return std::make_unique<ServiceFormHttpsRecordRdata>(
433 HttpsRecordPriority{priority}, std::move(service_name).value(),
434 std::move(mandatory_keys), std::move(alpn_ids), default_alpn, port,
435 std::move(ipv4_hint), std::move(ech_config), std::move(ipv6_hint),
436 std::move(unparsed_params));
437 }
438
IsCompatible() const439 bool ServiceFormHttpsRecordRdata::IsCompatible() const {
440 std::set<uint16_t> supported_keys(std::begin(kSupportedKeys),
441 std::end(kSupportedKeys));
442
443 for (uint16_t mandatory_key : mandatory_keys_) {
444 DCHECK_NE(mandatory_key, dns_protocol::kHttpsServiceParamKeyMandatory);
445
446 if (!base::Contains(supported_keys, mandatory_key)) {
447 return false;
448 }
449 }
450
451 #if DCHECK_IS_ON()
452 for (const auto& unparsed_param : unparsed_params_) {
453 DCHECK(!base::Contains(mandatory_keys_, unparsed_param.first));
454 }
455 #endif // DCHECK_IS_ON()
456
457 return true;
458 }
459
460 // static
IsSupportedKey(uint16_t key)461 bool ServiceFormHttpsRecordRdata::IsSupportedKey(uint16_t key) {
462 #if DCHECK_IS_ON()
463 return base::Contains(kSupportedKeys, key);
464 #else
465 // Only intended for DCHECKs.
466 base::ImmediateCrash();
467 #endif // DCHECK_IS_ON()
468 }
469
470 } // namespace net
471