• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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_system_task.h"
6 
7 #include <memory>
8 #include <optional>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/check.h"
13 #include "base/dcheck_is_on.h"
14 #include "base/feature_list.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback.h"
17 #include "base/memory/raw_ref.h"
18 #include "base/metrics/field_trial_params.h"
19 #include "base/no_destructor.h"
20 #include "base/notreached.h"
21 #include "base/sequence_checker.h"
22 #include "base/sequence_checker_impl.h"
23 #include "base/task/sequenced_task_runner.h"
24 #include "base/task/task_traits.h"
25 #include "base/task/thread_pool.h"
26 #include "base/threading/scoped_blocking_call.h"
27 #include "base/time/time.h"
28 #include "base/types/pass_key.h"
29 #include "dns_reloader.h"
30 #include "net/base/address_family.h"
31 #include "net/base/address_list.h"
32 #include "net/base/features.h"
33 #include "net/base/ip_endpoint.h"
34 #include "net/base/net_errors.h"
35 #include "net/base/network_anonymization_key.h"
36 #include "net/base/network_interfaces.h"
37 #include "net/base/sys_addrinfo.h"
38 #include "net/base/trace_constants.h"
39 #include "net/base/tracing.h"
40 #include "net/dns/address_info.h"
41 #include "net/dns/dns_names_util.h"
42 #include "net/dns/host_resolver_cache.h"
43 #include "net/dns/host_resolver_internal_result.h"
44 #include "net/dns/public/host_resolver_source.h"
45 
46 #if BUILDFLAG(IS_WIN)
47 #include "net/base/winsock_init.h"
48 #endif
49 
50 namespace net {
51 
52 namespace {
53 
54 // System resolver results give no TTL, so a default caching time is needed.
55 // Pick 1 minute to match the minimum cache time for built-in resolver results
56 // because this is only serving as a secondary cache to the caching done by the
57 // system. Additionally, this matches the long-standing historical behavior from
58 // previous implementations of HostResolver caching.
59 constexpr base::TimeDelta kTtl = base::Minutes(1);
60 
61 // Returns nullptr in the common case, or a task runner if the default has
62 // been overridden.
GetSystemDnsResolutionTaskRunnerOverride()63 scoped_refptr<base::TaskRunner>& GetSystemDnsResolutionTaskRunnerOverride() {
64   static base::NoDestructor<scoped_refptr<base::TaskRunner>>
65       system_dns_resolution_task_runner(nullptr);
66   return *system_dns_resolution_task_runner;
67 }
68 
69 // Posts a synchronous callback to a thread pool task runner created with
70 // MayBlock, USER_BLOCKING, and CONTINUE_ON_SHUTDOWN. This task runner can be
71 // overridden by assigning to GetSystemDnsResolutionTaskRunnerOverride().
72 // `results_cb` will be called later on the current sequence with the results of
73 // the DNS resolution.
PostSystemDnsResolutionTaskAndReply(base::OnceCallback<int (AddressList * addrlist,int * os_error)> system_dns_resolution_callback,SystemDnsResultsCallback results_cb)74 void PostSystemDnsResolutionTaskAndReply(
75     base::OnceCallback<int(AddressList* addrlist, int* os_error)>
76         system_dns_resolution_callback,
77     SystemDnsResultsCallback results_cb) {
78   auto addr_list = std::make_unique<net::AddressList>();
79   net::AddressList* addr_list_ptr = addr_list.get();
80   auto os_error = std::make_unique<int>();
81   int* os_error_ptr = os_error.get();
82 
83   // This callback owns |addr_list| and |os_error| and just calls |results_cb|
84   // with the results.
85   auto call_with_results_cb = base::BindOnce(
86       [](SystemDnsResultsCallback results_cb,
87          std::unique_ptr<net::AddressList> addr_list,
88          std::unique_ptr<int> os_error, int net_error) {
89         std::move(results_cb).Run(std::move(*addr_list), *os_error, net_error);
90       },
91       std::move(results_cb), std::move(addr_list), std::move(os_error));
92 
93   scoped_refptr<base::TaskRunner> system_dns_resolution_task_runner =
94       GetSystemDnsResolutionTaskRunnerOverride();
95   if (!system_dns_resolution_task_runner) {
96     // In production this will run on every call, otherwise some tests will
97     // leave a stale task runner around after tearing down their task
98     // environment. This should not be less performant than the regular
99     // base::ThreadPool::PostTask().
100     system_dns_resolution_task_runner = base::ThreadPool::CreateTaskRunner(
101         {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
102          base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
103   }
104   system_dns_resolution_task_runner->PostTaskAndReplyWithResult(
105       FROM_HERE,
106       base::BindOnce(std::move(system_dns_resolution_callback), addr_list_ptr,
107                      os_error_ptr),
108       std::move(call_with_results_cb));
109 }
110 
ResolveOnWorkerThread(scoped_refptr<HostResolverProc> resolver_proc,std::optional<std::string> hostname,AddressFamily address_family,HostResolverFlags flags,handles::NetworkHandle network,AddressList * addrlist,int * os_error)111 int ResolveOnWorkerThread(scoped_refptr<HostResolverProc> resolver_proc,
112                           std::optional<std::string> hostname,
113                           AddressFamily address_family,
114                           HostResolverFlags flags,
115                           handles::NetworkHandle network,
116                           AddressList* addrlist,
117                           int* os_error) {
118   std::string hostname_str = hostname ? *std::move(hostname) : GetHostName();
119   if (resolver_proc) {
120     return resolver_proc->Resolve(hostname_str, address_family, flags, addrlist,
121                                   os_error, network);
122   } else {
123     return SystemHostResolverCall(hostname_str, address_family, flags, addrlist,
124                                   os_error, network);
125   }
126 }
127 
128 // Creates NetLog parameters when the resolve failed.
NetLogHostResolverSystemTaskFailedParams(uint32_t attempt_number,int net_error,int os_error)129 base::Value::Dict NetLogHostResolverSystemTaskFailedParams(
130     uint32_t attempt_number,
131     int net_error,
132     int os_error) {
133   base::Value::Dict dict;
134   if (attempt_number)
135     dict.Set("attempt_number", base::saturated_cast<int>(attempt_number));
136 
137   dict.Set("net_error", net_error);
138 
139   if (os_error) {
140     dict.Set("os_error", os_error);
141 #if BUILDFLAG(IS_WIN)
142     // Map the error code to a human-readable string.
143     LPWSTR error_string = nullptr;
144     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
145                   nullptr,  // Use the internal message table.
146                   os_error,
147                   0,  // Use default language.
148                   (LPWSTR)&error_string,
149                   0,         // Buffer size.
150                   nullptr);  // Arguments (unused).
151     dict.Set("os_error_string", base::WideToUTF8(error_string));
152     LocalFree(error_string);
153 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
154     dict.Set("os_error_string", gai_strerror(os_error));
155 #endif
156   }
157 
158   return dict;
159 }
160 
161 using SystemDnsResolverOverrideCallback =
162     base::RepeatingCallback<void(const std::optional<std::string>& host,
163                                  AddressFamily address_family,
164                                  HostResolverFlags host_resolver_flags,
165                                  SystemDnsResultsCallback results_cb,
166                                  handles::NetworkHandle network)>;
167 
GetSystemDnsResolverOverride()168 SystemDnsResolverOverrideCallback& GetSystemDnsResolverOverride() {
169   static base::NoDestructor<SystemDnsResolverOverrideCallback> dns_override;
170 
171 #if DCHECK_IS_ON()
172   if (*dns_override) {
173     // This should only be called on the main thread, so DCHECK that it is.
174     // However, in unittests this may be called on different task environments
175     // in the same process so only bother sequence checking if an override
176     // exists.
177     static base::NoDestructor<base::SequenceCheckerImpl> sequence_checker;
178     base::ScopedValidateSequenceChecker scoped_validated_sequence_checker(
179         *sequence_checker);
180   }
181 #endif
182 
183   return *dns_override;
184 }
185 
186 }  // namespace
187 
SetSystemDnsResolverOverride(SystemDnsResolverOverrideCallback dns_override)188 void SetSystemDnsResolverOverride(
189     SystemDnsResolverOverrideCallback dns_override) {
190   GetSystemDnsResolverOverride() = std::move(dns_override);
191 }
192 
Params(scoped_refptr<HostResolverProc> resolver_proc,size_t in_max_retry_attempts)193 HostResolverSystemTask::Params::Params(
194     scoped_refptr<HostResolverProc> resolver_proc,
195     size_t in_max_retry_attempts)
196     : resolver_proc(std::move(resolver_proc)),
197       max_retry_attempts(in_max_retry_attempts),
198       unresponsive_delay(kDnsDefaultUnresponsiveDelay) {
199   // Maximum of 4 retry attempts for host resolution.
200   static const size_t kDefaultMaxRetryAttempts = 4u;
201   if (max_retry_attempts == kDefaultRetryAttempts)
202     max_retry_attempts = kDefaultMaxRetryAttempts;
203 }
204 
205 HostResolverSystemTask::Params::Params(const Params& other) = default;
206 
207 HostResolverSystemTask::Params::~Params() = default;
208 
CacheParams(HostResolverCache & cache,NetworkAnonymizationKey network_anonymization_key)209 HostResolverSystemTask::CacheParams::CacheParams(
210     HostResolverCache& cache,
211     NetworkAnonymizationKey network_anonymization_key)
212     : cache(base::raw_ref(cache)),
213       network_anonymization_key(std::move(network_anonymization_key)) {}
214 
215 HostResolverSystemTask::CacheParams::CacheParams(const CacheParams&) = default;
216 
217 HostResolverSystemTask::CacheParams::CacheParams(CacheParams&&) = default;
218 
219 HostResolverSystemTask::CacheParams::~CacheParams() = default;
220 
221 // static
Create(std::string hostname,AddressFamily address_family,HostResolverFlags flags,const Params & params,const NetLogWithSource & job_net_log,handles::NetworkHandle network,std::optional<CacheParams> cache_params)222 std::unique_ptr<HostResolverSystemTask> HostResolverSystemTask::Create(
223     std::string hostname,
224     AddressFamily address_family,
225     HostResolverFlags flags,
226     const Params& params,
227     const NetLogWithSource& job_net_log,
228     handles::NetworkHandle network,
229     std::optional<CacheParams> cache_params) {
230   return std::make_unique<HostResolverSystemTask>(
231       std::move(hostname), address_family, flags, params, job_net_log, network,
232       std::move(cache_params));
233 }
234 
235 // static
236 std::unique_ptr<HostResolverSystemTask>
CreateForOwnHostname(AddressFamily address_family,HostResolverFlags flags,const Params & params,const NetLogWithSource & job_net_log,handles::NetworkHandle network)237 HostResolverSystemTask::CreateForOwnHostname(
238     AddressFamily address_family,
239     HostResolverFlags flags,
240     const Params& params,
241     const NetLogWithSource& job_net_log,
242     handles::NetworkHandle network) {
243   return std::make_unique<HostResolverSystemTask>(
244       std::nullopt, address_family, flags, params, job_net_log, network,
245       /*cache_params=*/std::nullopt);
246 }
247 
HostResolverSystemTask(std::optional<std::string> hostname,AddressFamily address_family,HostResolverFlags flags,const Params & params,const NetLogWithSource & job_net_log,handles::NetworkHandle network,std::optional<CacheParams> cache_params)248 HostResolverSystemTask::HostResolverSystemTask(
249     std::optional<std::string> hostname,
250     AddressFamily address_family,
251     HostResolverFlags flags,
252     const Params& params,
253     const NetLogWithSource& job_net_log,
254     handles::NetworkHandle network,
255     std::optional<CacheParams> cache_params)
256     : hostname_(std::move(hostname)),
257       address_family_(address_family),
258       flags_(flags),
259       params_(params),
260       net_log_(job_net_log),
261       network_(network),
262       cache_params_(std::move(cache_params)) {
263   // Must have hostname if results are to be cached.
264   CHECK(!cache_params_.has_value() || hostname_.has_value());
265 
266   if (hostname_) {
267     // `hostname` should be a valid domain name. HostResolverManager has checks
268     // to fail early if this is not the case.
269     DCHECK(dns_names_util::IsValidDnsName(*hostname_))
270         << "Invalid hostname: " << *hostname_;
271   }
272   // If a resolver_proc has not been specified, try to use a default if one is
273   // set, as it may be in tests.
274   if (!params_.resolver_proc.get())
275     params_.resolver_proc = HostResolverProc::GetDefault();
276 }
277 
278 // Cancels this HostResolverSystemTask. Any outstanding resolve attempts cannot
279 // be cancelled, but they will post back to the current thread before checking
280 // their WeakPtrs to find that this task is cancelled.
~HostResolverSystemTask()281 HostResolverSystemTask::~HostResolverSystemTask() {
282   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
283 
284   // If this is cancellation, log the EndEvent (otherwise this was logged in
285   // OnLookupComplete()).
286   if (!was_completed())
287     net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_SYSTEM_TASK);
288 }
289 
Start(SystemDnsResultsCallback results_cb)290 void HostResolverSystemTask::Start(SystemDnsResultsCallback results_cb) {
291   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
292   DCHECK(results_cb);
293   DCHECK(!results_cb_);
294   results_cb_ = std::move(results_cb);
295   net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_SYSTEM_TASK);
296   StartLookupAttempt();
297 }
298 
StartLookupAttempt()299 void HostResolverSystemTask::StartLookupAttempt() {
300   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
301   DCHECK(!was_completed());
302   ++attempt_number_;
303 
304   net_log_.AddEventWithIntParams(
305       NetLogEventType::HOST_RESOLVER_MANAGER_ATTEMPT_STARTED, "attempt_number",
306       attempt_number_);
307 
308   // If the results aren't received within a given time, RetryIfNotComplete
309   // will start a new attempt if none of the outstanding attempts have
310   // completed yet.
311   // Use a WeakPtr to avoid keeping the HostResolverSystemTask alive after
312   // completion or cancellation.
313   if (attempt_number_ <= params_.max_retry_attempts) {
314     base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
315         FROM_HERE,
316         base::BindOnce(&HostResolverSystemTask::StartLookupAttempt,
317                        weak_ptr_factory_.GetWeakPtr()),
318         params_.unresponsive_delay *
319             std::pow(params_.retry_factor, attempt_number_ - 1));
320   }
321 
322   auto lookup_complete_cb =
323       base::BindOnce(&HostResolverSystemTask::OnLookupComplete,
324                      weak_ptr_factory_.GetWeakPtr(), attempt_number_);
325 
326   // If a hook has been installed, call it instead of posting a resolution task
327   // to a worker thread.
328   if (GetSystemDnsResolverOverride()) {
329     GetSystemDnsResolverOverride().Run(hostname_, address_family_, flags_,
330                                        std::move(lookup_complete_cb), network_);
331     // Do not add code below. `lookup_complete_cb` may have already deleted
332     // `this`.
333   } else {
334     base::OnceCallback<int(AddressList * addrlist, int* os_error)> resolve_cb =
335         base::BindOnce(&ResolveOnWorkerThread, params_.resolver_proc, hostname_,
336                        address_family_, flags_, network_);
337     PostSystemDnsResolutionTaskAndReply(std::move(resolve_cb),
338                                         std::move(lookup_complete_cb));
339   }
340 }
341 
342 // Callback for when DoLookup() completes.
OnLookupComplete(const uint32_t attempt_number,const AddressList & results,const int os_error,int error)343 void HostResolverSystemTask::OnLookupComplete(const uint32_t attempt_number,
344                                               const AddressList& results,
345                                               const int os_error,
346                                               int error) {
347   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
348   DCHECK(!was_completed());
349 
350   TRACE_EVENT0(NetTracingCategory(),
351                "HostResolverSystemTask::OnLookupComplete");
352 
353   // Invalidate WeakPtrs to cancel handling of all outstanding lookup attempts
354   // and retries.
355   weak_ptr_factory_.InvalidateWeakPtrs();
356 
357   // If results are empty, we should return an error.
358   bool empty_list_on_ok = (error == OK && results.empty());
359   if (empty_list_on_ok)
360     error = ERR_NAME_NOT_RESOLVED;
361 
362   if (error != OK && NetworkChangeNotifier::IsOffline())
363     error = ERR_INTERNET_DISCONNECTED;
364 
365   if (error != OK) {
366     net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_SYSTEM_TASK, [&] {
367       return NetLogHostResolverSystemTaskFailedParams(0, error, os_error);
368     });
369     net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED,
370                       [&] {
371                         return NetLogHostResolverSystemTaskFailedParams(
372                             attempt_number, error, os_error);
373                       });
374   } else {
375     net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_SYSTEM_TASK,
376                       [&] { return results.NetLogParams(); });
377     net_log_.AddEventWithIntParams(
378         NetLogEventType::HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED,
379         "attempt_number", attempt_number);
380   }
381 
382   MaybeCacheResults(results);
383 
384   std::move(results_cb_).Run(results, os_error, error);
385   // Running |results_cb_| can delete |this|.
386 }
387 
MaybeCacheResults(const AddressList & address_list)388 void HostResolverSystemTask::MaybeCacheResults(
389     const AddressList& address_list) {
390   if (address_list.empty() || !cache_params_.has_value() ||
391       !base::FeatureList::IsEnabled(features::kUseHostResolverCache)) {
392     return;
393   }
394   CHECK(hostname_.has_value());
395 
396   // Split out IPv4 and IPv6 endpoints while keeping them in the received order.
397   std::vector<IPEndPoint> ipv4;
398   std::vector<IPEndPoint> ipv6;
399   for (const IPEndPoint& endpoint : address_list) {
400     switch (endpoint.GetFamily()) {
401       case ADDRESS_FAMILY_IPV4:
402         ipv4.push_back(endpoint);
403         break;
404       case ADDRESS_FAMILY_IPV6:
405         ipv6.push_back(endpoint);
406         break;
407       default:
408         // Expect only IPv4 and IPv6 endpoints from system resolver.
409         NOTREACHED();
410     }
411   }
412   CHECK(!ipv4.empty() || !ipv6.empty());
413 
414   std::string_view domain_name = hostname_.value();
415   if (!address_list.dns_aliases().empty()) {
416     // Expect at most one alias from system resolver.
417     CHECK_EQ(address_list.dns_aliases().size(), 1u);
418 
419     // Save one alias cache entry for each query type.
420     CacheAlias(std::string(domain_name), DnsQueryType::A,
421                address_list.dns_aliases().front());
422     CacheAlias(std::string(domain_name), DnsQueryType::AAAA,
423                address_list.dns_aliases().front());
424 
425     domain_name = address_list.dns_aliases().front();
426   }
427 
428   CacheEndpoints(std::string(domain_name), std::move(ipv4), DnsQueryType::A);
429   CacheEndpoints(std::string(domain_name), std::move(ipv6), DnsQueryType::AAAA);
430 }
431 
CacheEndpoints(std::string domain_name,std::vector<IPEndPoint> endpoints,DnsQueryType query_type)432 void HostResolverSystemTask::CacheEndpoints(std::string domain_name,
433                                             std::vector<IPEndPoint> endpoints,
434                                             DnsQueryType query_type) {
435   if (endpoints.empty()) {
436     cache_params_.value().cache->Set(
437         std::make_unique<HostResolverInternalErrorResult>(
438             std::move(domain_name), query_type, base::TimeTicks::Now() + kTtl,
439             base::Time::Now() + kTtl,
440             HostResolverInternalResult::Source::kUnknown,
441             ERR_NAME_NOT_RESOLVED),
442         cache_params_.value().network_anonymization_key,
443         HostResolverSource::SYSTEM, /*secure=*/false);
444   } else {
445     cache_params_.value().cache->Set(
446         std::make_unique<HostResolverInternalDataResult>(
447             std::move(domain_name), query_type, base::TimeTicks::Now() + kTtl,
448             base::Time::Now() + kTtl,
449             HostResolverInternalResult::Source::kUnknown, std::move(endpoints),
450             std::vector<std::string>{}, std::vector<HostPortPair>{}),
451         cache_params_.value().network_anonymization_key,
452         HostResolverSource::SYSTEM, /*secure=*/false);
453   }
454 }
455 
CacheAlias(std::string domain_name,DnsQueryType query_type,std::string target_name)456 void HostResolverSystemTask::CacheAlias(std::string domain_name,
457                                         DnsQueryType query_type,
458                                         std::string target_name) {
459   cache_params_.value().cache->Set(
460       std::make_unique<HostResolverInternalAliasResult>(
461           std::move(domain_name), query_type, base::TimeTicks::Now() + kTtl,
462           base::Time::Now() + kTtl,
463           HostResolverInternalResult::Source::kUnknown, std::move(target_name)),
464       cache_params_.value().network_anonymization_key,
465       HostResolverSource::SYSTEM, /*secure=*/false);
466 }
467 
EnsureSystemHostResolverCallReady()468 void EnsureSystemHostResolverCallReady() {
469   EnsureDnsReloaderInit();
470 #if BUILDFLAG(IS_WIN)
471   EnsureWinsockInit();
472 #endif
473 }
474 
475 namespace {
476 
AddressFamilyToAF(AddressFamily address_family)477 int AddressFamilyToAF(AddressFamily address_family) {
478   switch (address_family) {
479     case ADDRESS_FAMILY_IPV4:
480       return AF_INET;
481     case ADDRESS_FAMILY_IPV6:
482       return AF_INET6;
483     case ADDRESS_FAMILY_UNSPECIFIED:
484       return AF_UNSPEC;
485   }
486 }
487 
488 }  // namespace
489 
SystemHostResolverCall(const std::string & host,AddressFamily address_family,HostResolverFlags host_resolver_flags,AddressList * addrlist,int * os_error_opt,handles::NetworkHandle network)490 int SystemHostResolverCall(const std::string& host,
491                            AddressFamily address_family,
492                            HostResolverFlags host_resolver_flags,
493                            AddressList* addrlist,
494                            int* os_error_opt,
495                            handles::NetworkHandle network) {
496   struct addrinfo hints = {0};
497   hints.ai_family = AddressFamilyToAF(address_family);
498 
499 #if BUILDFLAG(IS_WIN)
500   // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
501   //
502   // The following comment in <winsock2.h> is the best documentation I found
503   // on AI_ADDRCONFIG for Windows:
504   //   Flags used in "hints" argument to getaddrinfo()
505   //       - AI_ADDRCONFIG is supported starting with Vista
506   //       - default is AI_ADDRCONFIG ON whether the flag is set or not
507   //         because the performance penalty in not having ADDRCONFIG in
508   //         the multi-protocol stack environment is severe;
509   //         this defaulting may be disabled by specifying the AI_ALL flag,
510   //         in that case AI_ADDRCONFIG must be EXPLICITLY specified to
511   //         enable ADDRCONFIG behavior
512   //
513   // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful.  If the
514   // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
515   // to fail with WSANO_DATA (11004) for "localhost", probably because of the
516   // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
517   //   The IPv4 or IPv6 loopback address is not considered a valid global
518   //   address.
519   // See http://crbug.com/5234.
520   //
521   // OpenBSD does not support it, either.
522   hints.ai_flags = 0;
523 #else
524   // On other operating systems, AI_ADDRCONFIG may reduce the amount of
525   // unnecessary DNS lookups, e.g. getaddrinfo() will not send a request for
526   // AAAA records if the current machine has no IPv6 addresses configured and
527   // therefore could not use the resulting AAAA record anyway. On some ancient
528   // routers, AAAA DNS queries won't be handled correctly and will cause
529   // multiple retransmitions and large latency spikes.
530   hints.ai_flags = AI_ADDRCONFIG;
531 #endif
532 
533   // On Linux AI_ADDRCONFIG doesn't consider loopback addresses, even if only
534   // loopback addresses are configured. So don't use it when there are only
535   // loopback addresses. See loopback_only.h and
536   // https://fedoraproject.org/wiki/QA/Networking/NameResolution/ADDRCONFIG for
537   // a description of some of the issues AI_ADDRCONFIG can cause.
538   if (host_resolver_flags & HOST_RESOLVER_LOOPBACK_ONLY) {
539     hints.ai_flags &= ~AI_ADDRCONFIG;
540   }
541 
542   if (host_resolver_flags & HOST_RESOLVER_CANONNAME)
543     hints.ai_flags |= AI_CANONNAME;
544 
545 #if BUILDFLAG(IS_WIN)
546   // See crbug.com/1176970. Flag not documented (other than the declaration
547   // comment in ws2def.h) but confirmed by Microsoft to work for this purpose
548   // and be safe.
549   if (host_resolver_flags & HOST_RESOLVER_AVOID_MULTICAST)
550     hints.ai_flags |= AI_DNS_ONLY;
551 #endif  // BUILDFLAG(IS_WIN)
552 
553   // Restrict result set to only this socket type to avoid duplicates.
554   hints.ai_socktype = SOCK_STREAM;
555 
556   // This function can block for a long time. Use ScopedBlockingCall to increase
557   // the current thread pool's capacity and thus avoid reducing CPU usage by the
558   // current process during that time.
559   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
560                                                 base::BlockingType::WILL_BLOCK);
561   DnsReloaderMaybeReload();
562 
563   auto [ai, err, os_error] = AddressInfo::Get(host, hints, nullptr, network);
564   bool should_retry = false;
565   // If the lookup was restricted (either by address family, or address
566   // detection), and the results where all localhost of a single family,
567   // maybe we should retry.  There were several bugs related to these
568   // issues, for example http://crbug.com/42058 and http://crbug.com/49024
569   if ((hints.ai_family != AF_UNSPEC || hints.ai_flags & AI_ADDRCONFIG) && ai &&
570       ai->IsAllLocalhostOfOneFamily()) {
571     if (host_resolver_flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) {
572       hints.ai_family = AF_UNSPEC;
573       should_retry = true;
574     }
575     if (hints.ai_flags & AI_ADDRCONFIG) {
576       hints.ai_flags &= ~AI_ADDRCONFIG;
577       should_retry = true;
578     }
579   }
580   if (should_retry) {
581     std::tie(ai, err, os_error) =
582         AddressInfo::Get(host, hints, nullptr, network);
583   }
584 
585   if (os_error_opt)
586     *os_error_opt = os_error;
587 
588   if (!ai)
589     return err;
590 
591   *addrlist = ai->CreateAddressList();
592   return OK;
593 }
594 
SetSystemDnsResolutionTaskRunnerForTesting(scoped_refptr<base::TaskRunner> task_runner)595 void SetSystemDnsResolutionTaskRunnerForTesting(  // IN-TEST
596     scoped_refptr<base::TaskRunner> task_runner) {
597   GetSystemDnsResolutionTaskRunnerOverride() = task_runner;
598 }
599 
600 }  // namespace net
601