• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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/host_resolver.h"
6 
7 #include <set>
8 #include <string>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/check.h"
13 #include "base/functional/bind.h"
14 #include "base/no_destructor.h"
15 #include "base/notreached.h"
16 #include "base/ranges/algorithm.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/string_piece.h"
19 #include "base/time/time_delta_from_string.h"
20 #include "base/values.h"
21 #include "net/base/address_list.h"
22 #include "net/base/features.h"
23 #include "net/base/host_port_pair.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/network_change_notifier.h"
26 #include "net/dns/context_host_resolver.h"
27 #include "net/dns/dns_client.h"
28 #include "net/dns/dns_util.h"
29 #include "net/dns/host_cache.h"
30 #include "net/dns/host_resolver_manager.h"
31 #include "net/dns/mapped_host_resolver.h"
32 #include "net/dns/public/host_resolver_results.h"
33 #include "net/dns/resolve_context.h"
34 #include "third_party/abseil-cpp/absl/types/optional.h"
35 #include "third_party/abseil-cpp/absl/types/variant.h"
36 #include "url/scheme_host_port.h"
37 
38 #if BUILDFLAG(IS_ANDROID)
39 #include "base/android/build_info.h"
40 #include "net/android/network_library.h"
41 #endif  // BUILDFLAG(IS_ANDROID)
42 
43 namespace net {
44 
45 namespace {
46 
47 // The experiment settings of features::kUseDnsHttpsSvcb. See the comments in
48 // net/base/features.h for more details.
49 const char kUseDnsHttpsSvcbEnable[] = "enable";
50 const char kUseDnsHttpsSvcbInsecureExtraTimeMax[] = "insecure_extra_time_max";
51 const char kUseDnsHttpsSvcbInsecureExtraTimePercent[] =
52     "insecure_extra_time_percent";
53 const char kUseDnsHttpsSvcbInsecureExtraTimeMin[] = "insecure_extra_time_min";
54 const char kUseDnsHttpsSvcbSecureExtraTimeMax[] = "secure_extra_time_max";
55 const char kUseDnsHttpsSvcbSecureExtraTimePercent[] =
56     "secure_extra_time_percent";
57 const char kUseDnsHttpsSvcbSecureExtraTimeMin[] = "secure_extra_time_min";
58 
59 class FailingRequestImpl : public HostResolver::ResolveHostRequest,
60                            public HostResolver::ProbeRequest {
61  public:
FailingRequestImpl(int error)62   explicit FailingRequestImpl(int error) : error_(error) {}
63 
64   FailingRequestImpl(const FailingRequestImpl&) = delete;
65   FailingRequestImpl& operator=(const FailingRequestImpl&) = delete;
66 
67   ~FailingRequestImpl() override = default;
68 
Start(CompletionOnceCallback callback)69   int Start(CompletionOnceCallback callback) override { return error_; }
Start()70   int Start() override { return error_; }
71 
GetAddressResults() const72   AddressList* GetAddressResults() const override { return nullptr; }
73 
GetEndpointResults() const74   std::vector<HostResolverEndpointResult>* GetEndpointResults() const override {
75     return nullptr;
76   }
77 
GetTextResults() const78   const absl::optional<std::vector<std::string>>& GetTextResults()
79       const override {
80     static const base::NoDestructor<absl::optional<std::vector<std::string>>>
81         nullopt_result;
82     return *nullopt_result;
83   }
84 
GetHostnameResults() const85   const absl::optional<std::vector<HostPortPair>>& GetHostnameResults()
86       const override {
87     static const base::NoDestructor<absl::optional<std::vector<HostPortPair>>>
88         nullopt_result;
89     return *nullopt_result;
90   }
91 
GetDnsAliasResults() const92   const std::set<std::string>* GetDnsAliasResults() const override {
93     return nullptr;
94   }
95 
GetResolveErrorInfo() const96   ResolveErrorInfo GetResolveErrorInfo() const override {
97     return ResolveErrorInfo(error_);
98   }
99 
GetStaleInfo() const100   const absl::optional<HostCache::EntryStaleness>& GetStaleInfo()
101       const override {
102     static const absl::optional<HostCache::EntryStaleness> nullopt_result;
103     return nullopt_result;
104   }
105 
106  private:
107   const int error_;
108 };
109 
EndpointResultIsNonProtocol(const HostResolverEndpointResult & result)110 bool EndpointResultIsNonProtocol(const HostResolverEndpointResult& result) {
111   return result.metadata.supported_protocol_alpns.empty();
112 }
113 
GetTimeDeltaFromDictString(const base::Value::Dict & args,base::StringPiece key,base::TimeDelta * out)114 void GetTimeDeltaFromDictString(const base::Value::Dict& args,
115                                 base::StringPiece key,
116                                 base::TimeDelta* out) {
117   const std::string* value_string = args.FindString(key);
118   if (!value_string)
119     return;
120   *out = base::TimeDeltaFromString(*value_string).value_or(*out);
121 }
122 
123 }  // namespace
124 
Host(absl::variant<url::SchemeHostPort,HostPortPair> host)125 HostResolver::Host::Host(absl::variant<url::SchemeHostPort, HostPortPair> host)
126     : host_(std::move(host)) {
127 #if DCHECK_IS_ON()
128   if (absl::holds_alternative<url::SchemeHostPort>(host_)) {
129     DCHECK(absl::get<url::SchemeHostPort>(host_).IsValid());
130   } else {
131     DCHECK(absl::holds_alternative<HostPortPair>(host_));
132     DCHECK(!absl::get<HostPortPair>(host_).IsEmpty());
133   }
134 #endif  // DCHECK_IS_ON()
135 }
136 
137 HostResolver::Host::~Host() = default;
138 
139 HostResolver::Host::Host(const Host&) = default;
140 
141 HostResolver::Host& HostResolver::Host::operator=(const Host&) = default;
142 
143 HostResolver::Host::Host(Host&&) = default;
144 
145 HostResolver::Host& HostResolver::Host::operator=(Host&&) = default;
146 
HasScheme() const147 bool HostResolver::Host::HasScheme() const {
148   return absl::holds_alternative<url::SchemeHostPort>(host_);
149 }
150 
GetScheme() const151 const std::string& HostResolver::Host::GetScheme() const {
152   DCHECK(absl::holds_alternative<url::SchemeHostPort>(host_));
153   return absl::get<url::SchemeHostPort>(host_).scheme();
154 }
155 
GetHostname() const156 std::string HostResolver::Host::GetHostname() const {
157   if (absl::holds_alternative<url::SchemeHostPort>(host_)) {
158     return absl::get<url::SchemeHostPort>(host_).host();
159   } else {
160     DCHECK(absl::holds_alternative<HostPortPair>(host_));
161     return absl::get<HostPortPair>(host_).HostForURL();
162   }
163 }
164 
GetHostnameWithoutBrackets() const165 base::StringPiece HostResolver::Host::GetHostnameWithoutBrackets() const {
166   if (absl::holds_alternative<url::SchemeHostPort>(host_)) {
167     base::StringPiece hostname = absl::get<url::SchemeHostPort>(host_).host();
168     if (hostname.size() > 2 && hostname.front() == '[' &&
169         hostname.back() == ']') {
170       return hostname.substr(1, hostname.size() - 2);
171     } else {
172       return hostname;
173     }
174   } else {
175     DCHECK(absl::holds_alternative<HostPortPair>(host_));
176     return absl::get<HostPortPair>(host_).host();
177   }
178 }
179 
GetPort() const180 uint16_t HostResolver::Host::GetPort() const {
181   if (absl::holds_alternative<url::SchemeHostPort>(host_)) {
182     return absl::get<url::SchemeHostPort>(host_).port();
183   } else {
184     DCHECK(absl::holds_alternative<HostPortPair>(host_));
185     return absl::get<HostPortPair>(host_).port();
186   }
187 }
188 
ToString() const189 std::string HostResolver::Host::ToString() const {
190   if (absl::holds_alternative<url::SchemeHostPort>(host_)) {
191     return absl::get<url::SchemeHostPort>(host_).Serialize();
192   } else {
193     DCHECK(absl::holds_alternative<HostPortPair>(host_));
194     return absl::get<HostPortPair>(host_).ToString();
195   }
196 }
197 
AsSchemeHostPort() const198 const url::SchemeHostPort& HostResolver::Host::AsSchemeHostPort() const {
199   const url::SchemeHostPort* scheme_host_port =
200       absl::get_if<url::SchemeHostPort>(&host_);
201   DCHECK(scheme_host_port);
202   return *scheme_host_port;
203 }
204 
205 HostResolver::HttpsSvcbOptions::HttpsSvcbOptions() = default;
206 
207 HostResolver::HttpsSvcbOptions::HttpsSvcbOptions(
208     const HttpsSvcbOptions& other) = default;
209 HostResolver::HttpsSvcbOptions::HttpsSvcbOptions(HttpsSvcbOptions&& other) =
210     default;
211 
212 HostResolver::HttpsSvcbOptions::~HttpsSvcbOptions() = default;
213 
214 // static
FromDict(const base::Value::Dict & dict)215 HostResolver::HttpsSvcbOptions HostResolver::HttpsSvcbOptions::FromDict(
216     const base::Value::Dict& dict) {
217   net::HostResolver::HttpsSvcbOptions options;
218   options.enable =
219       dict.FindBool(kUseDnsHttpsSvcbEnable).value_or(options.enable);
220   GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbInsecureExtraTimeMax,
221                              &options.insecure_extra_time_max);
222 
223   options.insecure_extra_time_percent =
224       dict.FindInt(kUseDnsHttpsSvcbInsecureExtraTimePercent)
225           .value_or(options.insecure_extra_time_percent);
226   GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbInsecureExtraTimeMin,
227                              &options.insecure_extra_time_min);
228 
229   GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbSecureExtraTimeMax,
230                              &options.secure_extra_time_max);
231 
232   options.secure_extra_time_percent =
233       dict.FindInt(kUseDnsHttpsSvcbSecureExtraTimePercent)
234           .value_or(options.secure_extra_time_percent);
235   GetTimeDeltaFromDictString(dict, kUseDnsHttpsSvcbSecureExtraTimeMin,
236                              &options.secure_extra_time_min);
237 
238   return options;
239 }
240 
241 // static
FromFeatures()242 HostResolver::HttpsSvcbOptions HostResolver::HttpsSvcbOptions::FromFeatures() {
243   net::HostResolver::HttpsSvcbOptions options;
244   options.enable = base::FeatureList::IsEnabled(features::kUseDnsHttpsSvcb);
245   options.insecure_extra_time_max =
246       features::kUseDnsHttpsSvcbInsecureExtraTimeMax.Get();
247   options.insecure_extra_time_percent =
248       features::kUseDnsHttpsSvcbInsecureExtraTimePercent.Get();
249   options.insecure_extra_time_min =
250       features::kUseDnsHttpsSvcbInsecureExtraTimeMin.Get();
251   options.secure_extra_time_max =
252       features::kUseDnsHttpsSvcbSecureExtraTimeMax.Get();
253   options.secure_extra_time_percent =
254       features::kUseDnsHttpsSvcbSecureExtraTimePercent.Get();
255   options.secure_extra_time_min =
256       features::kUseDnsHttpsSvcbSecureExtraTimeMin.Get();
257   return options;
258 }
259 
260 HostResolver::ManagerOptions::ManagerOptions() = default;
261 
262 HostResolver::ManagerOptions::ManagerOptions(const ManagerOptions& other) =
263     default;
264 HostResolver::ManagerOptions::ManagerOptions(ManagerOptions&& other) = default;
265 
266 HostResolver::ManagerOptions::~ManagerOptions() = default;
267 
268 const std::vector<bool>*
GetExperimentalResultsForTesting() const269 HostResolver::ResolveHostRequest::GetExperimentalResultsForTesting() const {
270   NOTREACHED();
271   return nullptr;
272 }
273 
CreateResolver(HostResolverManager * manager,base::StringPiece host_mapping_rules,bool enable_caching)274 std::unique_ptr<HostResolver> HostResolver::Factory::CreateResolver(
275     HostResolverManager* manager,
276     base::StringPiece host_mapping_rules,
277     bool enable_caching) {
278   return HostResolver::CreateResolver(manager, host_mapping_rules,
279                                       enable_caching);
280 }
281 
CreateStandaloneResolver(NetLog * net_log,const ManagerOptions & options,base::StringPiece host_mapping_rules,bool enable_caching)282 std::unique_ptr<HostResolver> HostResolver::Factory::CreateStandaloneResolver(
283     NetLog* net_log,
284     const ManagerOptions& options,
285     base::StringPiece host_mapping_rules,
286     bool enable_caching) {
287   return HostResolver::CreateStandaloneResolver(
288       net_log, options, host_mapping_rules, enable_caching);
289 }
290 
291 HostResolver::ResolveHostParameters::ResolveHostParameters() = default;
292 
293 HostResolver::ResolveHostParameters::ResolveHostParameters(
294     const ResolveHostParameters& other) = default;
295 
296 HostResolver::~HostResolver() = default;
297 
298 std::unique_ptr<HostResolver::ProbeRequest>
CreateDohProbeRequest()299 HostResolver::CreateDohProbeRequest() {
300   // Should be overridden in any HostResolver implementation where this method
301   // may be called.
302   NOTREACHED();
303   return nullptr;
304 }
305 
CreateMdnsListener(const HostPortPair & host,DnsQueryType query_type)306 std::unique_ptr<HostResolver::MdnsListener> HostResolver::CreateMdnsListener(
307     const HostPortPair& host,
308     DnsQueryType query_type) {
309   // Should be overridden in any HostResolver implementation where this method
310   // may be called.
311   NOTREACHED();
312   return nullptr;
313 }
314 
GetHostCache()315 HostCache* HostResolver::GetHostCache() {
316   return nullptr;
317 }
318 
GetDnsConfigAsValue() const319 base::Value::Dict HostResolver::GetDnsConfigAsValue() const {
320   return base::Value::Dict();
321 }
322 
SetRequestContext(URLRequestContext * request_context)323 void HostResolver::SetRequestContext(URLRequestContext* request_context) {
324   // Should be overridden in any HostResolver implementation where this method
325   // may be called.
326   NOTREACHED();
327 }
328 
GetManagerForTesting()329 HostResolverManager* HostResolver::GetManagerForTesting() {
330   // Should be overridden in any HostResolver implementation where this method
331   // may be called.
332   NOTREACHED();
333   return nullptr;
334 }
335 
GetContextForTesting() const336 const URLRequestContext* HostResolver::GetContextForTesting() const {
337   // Should be overridden in any HostResolver implementation where this method
338   // may be called.
339   NOTREACHED();
340   return nullptr;
341 }
342 
GetTargetNetworkForTesting() const343 handles::NetworkHandle HostResolver::GetTargetNetworkForTesting() const {
344   return handles::kInvalidNetworkHandle;
345 }
346 
347 // static
CreateResolver(HostResolverManager * manager,base::StringPiece host_mapping_rules,bool enable_caching)348 std::unique_ptr<HostResolver> HostResolver::CreateResolver(
349     HostResolverManager* manager,
350     base::StringPiece host_mapping_rules,
351     bool enable_caching) {
352   DCHECK(manager);
353 
354   auto resolve_context = std::make_unique<ResolveContext>(
355       nullptr /* url_request_context */, enable_caching);
356 
357   auto resolver = std::make_unique<ContextHostResolver>(
358       manager, std::move(resolve_context));
359 
360   if (host_mapping_rules.empty())
361     return resolver;
362   auto remapped_resolver =
363       std::make_unique<MappedHostResolver>(std::move(resolver));
364   remapped_resolver->SetRulesFromString(host_mapping_rules);
365   return remapped_resolver;
366 }
367 
368 // static
CreateStandaloneResolver(NetLog * net_log,absl::optional<ManagerOptions> options,base::StringPiece host_mapping_rules,bool enable_caching)369 std::unique_ptr<HostResolver> HostResolver::CreateStandaloneResolver(
370     NetLog* net_log,
371     absl::optional<ManagerOptions> options,
372     base::StringPiece host_mapping_rules,
373     bool enable_caching) {
374   std::unique_ptr<ContextHostResolver> resolver =
375       CreateStandaloneContextResolver(net_log, std::move(options),
376                                       enable_caching);
377 
378   if (host_mapping_rules.empty())
379     return resolver;
380   auto remapped_resolver =
381       std::make_unique<MappedHostResolver>(std::move(resolver));
382   remapped_resolver->SetRulesFromString(host_mapping_rules);
383   return remapped_resolver;
384 }
385 
386 // static
387 std::unique_ptr<ContextHostResolver>
CreateStandaloneContextResolver(NetLog * net_log,absl::optional<ManagerOptions> options,bool enable_caching)388 HostResolver::CreateStandaloneContextResolver(
389     NetLog* net_log,
390     absl::optional<ManagerOptions> options,
391     bool enable_caching) {
392   auto resolve_context = std::make_unique<ResolveContext>(
393       nullptr /* url_request_context */, enable_caching);
394 
395   return std::make_unique<ContextHostResolver>(
396       std::make_unique<HostResolverManager>(
397           std::move(options).value_or(ManagerOptions()),
398           NetworkChangeNotifier::GetSystemDnsConfigNotifier(), net_log),
399       std::move(resolve_context));
400 }
401 
402 // static
403 std::unique_ptr<HostResolver>
CreateStandaloneNetworkBoundResolver(NetLog * net_log,handles::NetworkHandle target_network,absl::optional<ManagerOptions> options,base::StringPiece host_mapping_rules,bool enable_caching)404 HostResolver::CreateStandaloneNetworkBoundResolver(
405     NetLog* net_log,
406     handles::NetworkHandle target_network,
407     absl::optional<ManagerOptions> options,
408     base::StringPiece host_mapping_rules,
409     bool enable_caching) {
410 #if BUILDFLAG(IS_ANDROID)
411   // Note that the logic below uses Android APIs that don't work on a sandboxed
412   // process: This is not problematic because this function is used only by
413   // Cronet which doesn't enable sandboxing.
414 
415   auto resolve_context = std::make_unique<ResolveContext>(
416       nullptr /*url_request_context */, enable_caching);
417   auto manager_options = std::move(options).value_or(ManagerOptions());
418   // Support the use of the built-in resolver when possible.
419   bool is_builtin_resolver_supported =
420       manager_options.insecure_dns_client_enabled &&
421       base::android::BuildInfo::GetInstance()->sdk_int() >=
422           base::android::SDK_VERSION_P;
423   if (is_builtin_resolver_supported) {
424     // Pre-existing DnsConfigOverrides is currently ignored, consider extending
425     // if a use case arises.
426     DCHECK(manager_options.dns_config_overrides == DnsConfigOverrides());
427 
428     std::vector<IPEndPoint> dns_servers;
429     bool dns_over_tls_active;
430     std::string dns_over_tls_hostname;
431     std::vector<std::string> search_suffixes;
432     if (android::GetDnsServersForNetwork(&dns_servers, &dns_over_tls_active,
433                                          &dns_over_tls_hostname,
434                                          &search_suffixes, target_network)) {
435       DnsConfigOverrides dns_config_overrides =
436           DnsConfigOverrides::CreateOverridingEverythingWithDefaults();
437       dns_config_overrides.nameservers = dns_servers;
438       // Android APIs don't specify whether to use DoT or DoH. So, leave the
439       // decision to `DnsConfig::allow_dns_over_https_upgrade` default value.
440       dns_config_overrides.dns_over_tls_active = dns_over_tls_active;
441       dns_config_overrides.dns_over_tls_hostname = dns_over_tls_hostname;
442       dns_config_overrides.search = search_suffixes;
443 
444       manager_options.dns_config_overrides = dns_config_overrides;
445       // Regardless of DoH vs DoT, the important contract to respect is not to
446       // perform insecure DNS lookups if `dns_over_tls_active` == true.
447       manager_options.additional_types_via_insecure_dns_enabled =
448           !dns_over_tls_active;
449     } else {
450       // Disable when android::GetDnsServersForNetwork fails.
451       is_builtin_resolver_supported = false;
452     }
453   }
454 
455   manager_options.insecure_dns_client_enabled = is_builtin_resolver_supported;
456   return std::make_unique<ContextHostResolver>(
457       HostResolverManager::CreateNetworkBoundHostResolverManager(
458           manager_options, target_network, net_log),
459       std::move(resolve_context));
460 #else   // !BUILDFLAG(IS_ANDROID)
461   NOTIMPLEMENTED();
462   return nullptr;
463 #endif  // BUILDFLAG(IS_ANDROID)
464 }
465 
466 // static
DnsQueryTypeSetToAddressFamily(DnsQueryTypeSet dns_query_types)467 AddressFamily HostResolver::DnsQueryTypeSetToAddressFamily(
468     DnsQueryTypeSet dns_query_types) {
469   DCHECK(HasAddressType(dns_query_types));
470   // If the set of query types contains A and AAAA, defer the choice of address
471   // family. Otherwise, pick the corresponding address family.
472   if (dns_query_types.HasAll({DnsQueryType::A, DnsQueryType::AAAA}))
473     return ADDRESS_FAMILY_UNSPECIFIED;
474   if (dns_query_types.Has(DnsQueryType::AAAA))
475     return ADDRESS_FAMILY_IPV6;
476   DCHECK(dns_query_types.Has(DnsQueryType::A));
477   return ADDRESS_FAMILY_IPV4;
478 }
479 
480 // static
ParametersToHostResolverFlags(const ResolveHostParameters & parameters)481 HostResolverFlags HostResolver::ParametersToHostResolverFlags(
482     const ResolveHostParameters& parameters) {
483   HostResolverFlags flags = 0;
484   if (parameters.include_canonical_name)
485     flags |= HOST_RESOLVER_CANONNAME;
486   if (parameters.loopback_only)
487     flags |= HOST_RESOLVER_LOOPBACK_ONLY;
488   if (parameters.avoid_multicast_resolution)
489     flags |= HOST_RESOLVER_AVOID_MULTICAST;
490   return flags;
491 }
492 
493 // static
SquashErrorCode(int error)494 int HostResolver::SquashErrorCode(int error) {
495   // TODO(crbug.com/1043281): Consider squashing ERR_INTERNET_DISCONNECTED.
496   if (error == OK || error == ERR_IO_PENDING ||
497       error == ERR_INTERNET_DISCONNECTED || error == ERR_NAME_NOT_RESOLVED ||
498       error == ERR_DNS_NAME_HTTPS_ONLY) {
499     return error;
500   } else {
501     return ERR_NAME_NOT_RESOLVED;
502   }
503 }
504 
505 // static
506 std::vector<HostResolverEndpointResult>
AddressListToEndpointResults(const AddressList & address_list)507 HostResolver::AddressListToEndpointResults(const AddressList& address_list) {
508   HostResolverEndpointResult connection_endpoint;
509   connection_endpoint.ip_endpoints = address_list.endpoints();
510 
511   std::vector<HostResolverEndpointResult> list;
512   list.push_back(std::move(connection_endpoint));
513   return list;
514 }
515 
516 // static
EndpointResultToAddressList(base::span<const HostResolverEndpointResult> endpoints,const std::set<std::string> & aliases)517 AddressList HostResolver::EndpointResultToAddressList(
518     base::span<const HostResolverEndpointResult> endpoints,
519     const std::set<std::string>& aliases) {
520   AddressList list;
521 
522   auto non_protocol_endpoint =
523       base::ranges::find_if(endpoints, &EndpointResultIsNonProtocol);
524   if (non_protocol_endpoint == endpoints.end())
525     return list;
526 
527   list.endpoints() = non_protocol_endpoint->ip_endpoints;
528 
529   std::vector<std::string> aliases_vector(aliases.begin(), aliases.end());
530   list.SetDnsAliases(std::move(aliases_vector));
531 
532   return list;
533 }
534 
535 // static
GetNonProtocolEndpoints(base::span<const HostResolverEndpointResult> endpoints)536 std::vector<IPEndPoint> HostResolver::GetNonProtocolEndpoints(
537     base::span<const HostResolverEndpointResult> endpoints) {
538   auto non_protocol_endpoint =
539       base::ranges::find_if(endpoints, &EndpointResultIsNonProtocol);
540   if (non_protocol_endpoint == endpoints.end())
541     return std::vector<IPEndPoint>();
542   return non_protocol_endpoint->ip_endpoints;
543 }
544 
545 // static
AllProtocolEndpointsHaveEch(base::span<const HostResolverEndpointResult> endpoints)546 bool HostResolver::AllProtocolEndpointsHaveEch(
547     base::span<const HostResolverEndpointResult> endpoints) {
548   bool has_svcb = false;
549   for (const auto& endpoint : endpoints) {
550     if (!endpoint.metadata.supported_protocol_alpns.empty()) {
551       has_svcb = true;
552       if (endpoint.metadata.ech_config_list.empty()) {
553         return false;  // There is a non-ECH SVCB/HTTPS route.
554       }
555     }
556   }
557   // Either there were no SVCB/HTTPS records (should be SVCB-optional), or there
558   // were and all supported ECH (should be SVCB-reliant).
559   return has_svcb;
560 }
561 
562 HostResolver::HostResolver() = default;
563 
564 // static
565 std::unique_ptr<HostResolver::ResolveHostRequest>
CreateFailingRequest(int error)566 HostResolver::CreateFailingRequest(int error) {
567   return std::make_unique<FailingRequestImpl>(error);
568 }
569 
570 // static
571 std::unique_ptr<HostResolver::ProbeRequest>
CreateFailingProbeRequest(int error)572 HostResolver::CreateFailingProbeRequest(int error) {
573   return std::make_unique<FailingRequestImpl>(error);
574 }
575 
576 }  // namespace net
577