xref: /aosp_15_r20/external/cronet/net/dns/https_record_rdata.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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, &param_key, &param_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, &param_key,
329                             &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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