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