• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &param_key, &param_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, &param_key,
317                             &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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, &param_key, &param_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