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