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_manager.h"
6
7 #include <cmath>
8 #include <cstdint>
9 #include <iterator>
10 #include <limits>
11 #include <memory>
12 #include <numeric>
13 #include <set>
14 #include <string>
15 #include <tuple>
16 #include <unordered_set>
17 #include <utility>
18 #include <vector>
19
20 #include "base/check_op.h"
21 #include "base/compiler_specific.h"
22 #include "base/containers/circular_deque.h"
23 #include "base/containers/contains.h"
24 #include "base/containers/cxx20_erase.h"
25 #include "base/containers/flat_set.h"
26 #include "base/containers/linked_list.h"
27 #include "base/debug/debugger.h"
28 #include "base/feature_list.h"
29 #include "base/functional/bind.h"
30 #include "base/functional/callback.h"
31 #include "base/functional/callback_helpers.h"
32 #include "base/functional/identity.h"
33 #include "base/logging.h"
34 #include "base/memory/ptr_util.h"
35 #include "base/memory/raw_ptr.h"
36 #include "base/memory/safe_ref.h"
37 #include "base/memory/weak_ptr.h"
38 #include "base/metrics/field_trial.h"
39 #include "base/metrics/field_trial_params.h"
40 #include "base/metrics/histogram_functions.h"
41 #include "base/metrics/histogram_macros.h"
42 #include "base/no_destructor.h"
43 #include "base/numerics/safe_conversions.h"
44 #include "base/observer_list.h"
45 #include "base/ranges/algorithm.h"
46 #include "base/sequence_checker.h"
47 #include "base/strings/strcat.h"
48 #include "base/strings/string_number_conversions.h"
49 #include "base/strings/string_piece.h"
50 #include "base/strings/string_split.h"
51 #include "base/strings/string_util.h"
52 #include "base/strings/stringprintf.h"
53 #include "base/strings/utf_string_conversions.h"
54 #include "base/task/sequenced_task_runner.h"
55 #include "base/task/single_thread_task_runner.h"
56 #include "base/task/thread_pool.h"
57 #include "base/threading/scoped_blocking_call.h"
58 #include "base/time/default_tick_clock.h"
59 #include "base/time/time.h"
60 #include "base/types/optional_util.h"
61 #include "base/values.h"
62 #include "build/build_config.h"
63 #include "net/base/address_family.h"
64 #include "net/base/address_list.h"
65 #include "net/base/completion_once_callback.h"
66 #include "net/base/features.h"
67 #include "net/base/host_port_pair.h"
68 #include "net/base/ip_address.h"
69 #include "net/base/ip_endpoint.h"
70 #include "net/base/net_errors.h"
71 #include "net/base/network_anonymization_key.h"
72 #include "net/base/network_interfaces.h"
73 #include "net/base/prioritized_dispatcher.h"
74 #include "net/base/request_priority.h"
75 #include "net/base/trace_constants.h"
76 #include "net/base/tracing.h"
77 #include "net/base/url_util.h"
78 #include "net/dns/address_sorter.h"
79 #include "net/dns/dns_alias_utility.h"
80 #include "net/dns/dns_client.h"
81 #include "net/dns/dns_names_util.h"
82 #include "net/dns/dns_response.h"
83 #include "net/dns/dns_response_result_extractor.h"
84 #include "net/dns/dns_transaction.h"
85 #include "net/dns/dns_util.h"
86 #include "net/dns/host_cache.h"
87 #include "net/dns/host_resolver_mdns_listener_impl.h"
88 #include "net/dns/host_resolver_mdns_task.h"
89 #include "net/dns/host_resolver_nat64_task.h"
90 #include "net/dns/host_resolver_proc.h"
91 #include "net/dns/host_resolver_system_task.h"
92 #include "net/dns/httpssvc_metrics.h"
93 #include "net/dns/mdns_client.h"
94 #include "net/dns/public/dns_protocol.h"
95 #include "net/dns/public/dns_query_type.h"
96 #include "net/dns/public/host_resolver_results.h"
97 #include "net/dns/public/resolve_error_info.h"
98 #include "net/dns/public/secure_dns_mode.h"
99 #include "net/dns/public/secure_dns_policy.h"
100 #include "net/dns/public/util.h"
101 #include "net/dns/record_parsed.h"
102 #include "net/dns/resolve_context.h"
103 #include "net/dns/test_dns_config_service.h"
104 #include "net/http/http_network_session.h"
105 #include "net/log/net_log.h"
106 #include "net/log/net_log_capture_mode.h"
107 #include "net/log/net_log_event_type.h"
108 #include "net/log/net_log_source.h"
109 #include "net/log/net_log_source_type.h"
110 #include "net/log/net_log_with_source.h"
111 #include "net/socket/client_socket_factory.h"
112 #include "net/url_request/url_request_context.h"
113 #include "third_party/abseil-cpp/absl/types/optional.h"
114 #include "third_party/abseil-cpp/absl/types/variant.h"
115 #include "url/scheme_host_port.h"
116 #include "url/url_constants.h"
117
118 #if BUILDFLAG(ENABLE_MDNS)
119 #include "net/dns/mdns_client_impl.h"
120 #endif
121
122 #if BUILDFLAG(IS_WIN)
123 #include <Winsock2.h>
124 #include "net/base/winsock_init.h"
125 #endif
126
127 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
128 #include <net/if.h>
129 #include "net/base/sys_addrinfo.h"
130 #if BUILDFLAG(IS_ANDROID)
131 #include "base/android/build_info.h"
132 #include "net/android/network_library.h"
133 #else // !BUILDFLAG(IS_ANDROID)
134 #include <ifaddrs.h>
135 #endif // BUILDFLAG(IS_ANDROID)
136 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
137
138 namespace net {
139
140 namespace {
141
142 // Limit the size of hostnames that will be resolved to combat issues in
143 // some platform's resolvers.
144 const size_t kMaxHostLength = 4096;
145
146 // Default TTL for successful resolutions with HostResolverSystemTask.
147 const unsigned kCacheEntryTTLSeconds = 60;
148
149 // Default TTL for unsuccessful resolutions with HostResolverSystemTask.
150 const unsigned kNegativeCacheEntryTTLSeconds = 0;
151
152 // Minimum TTL for successful resolutions with DnsTask.
153 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds;
154
155 // Time between IPv6 probes, i.e. for how long results of each IPv6 probe are
156 // cached.
157 const int kIPv6ProbePeriodMs = 1000;
158
159 // Google DNS address used for IPv6 probes.
160 const uint8_t kIPv6ProbeAddress[] = {0x20, 0x01, 0x48, 0x60, 0x48, 0x60,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x88, 0x88};
163
164 // ICANN uses this localhost address to indicate a name collision.
165 //
166 // The policy in Chromium is to fail host resolving if it resolves to
167 // this special address.
168 //
169 // Not however that IP literals are exempt from this policy, so it is still
170 // possible to navigate to http://127.0.53.53/ directly.
171 //
172 // For more details: https://www.icann.org/news/announcement-2-2014-08-01-en
173 const uint8_t kIcanNameCollisionIp[] = {127, 0, 53, 53};
174
ContainsIcannNameCollisionIp(const std::vector<IPEndPoint> & endpoints)175 bool ContainsIcannNameCollisionIp(const std::vector<IPEndPoint>& endpoints) {
176 for (const auto& endpoint : endpoints) {
177 const IPAddress& addr = endpoint.address();
178 if (addr.IsIPv4() && IPAddressStartsWith(addr, kIcanNameCollisionIp)) {
179 return true;
180 }
181 }
182 return false;
183 }
184
185 // True if |hostname| ends with either ".local" or ".local.".
ResemblesMulticastDNSName(base::StringPiece hostname)186 bool ResemblesMulticastDNSName(base::StringPiece hostname) {
187 return base::EndsWith(hostname, ".local") ||
188 base::EndsWith(hostname, ".local.");
189 }
190
ConfigureAsyncDnsNoFallbackFieldTrial()191 bool ConfigureAsyncDnsNoFallbackFieldTrial() {
192 const bool kDefault = false;
193
194 // Configure the AsyncDns field trial as follows:
195 // groups AsyncDnsNoFallbackA and AsyncDnsNoFallbackB: return true,
196 // groups AsyncDnsA and AsyncDnsB: return false,
197 // groups SystemDnsA and SystemDnsB: return false,
198 // otherwise (trial absent): return default.
199 std::string group_name = base::FieldTrialList::FindFullName("AsyncDns");
200 if (!group_name.empty()) {
201 return base::StartsWith(group_name, "AsyncDnsNoFallback",
202 base::CompareCase::INSENSITIVE_ASCII);
203 }
204 return kDefault;
205 }
206
207 // Returns true if NAT64 can be used in place of an IPv4 address during host
208 // resolution.
MayUseNAT64ForIPv4Literal(HostResolverFlags flags,HostResolverSource source,const IPAddress & ip_address)209 bool MayUseNAT64ForIPv4Literal(HostResolverFlags flags,
210 HostResolverSource source,
211 const IPAddress& ip_address) {
212 return !(flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6) &&
213 ip_address.IsValid() && ip_address.IsIPv4() &&
214 base::FeatureList::IsEnabled(features::kUseNAT64ForIPv4Literal) &&
215 (source != HostResolverSource::LOCAL_ONLY);
216 }
217
218 //-----------------------------------------------------------------------------
219
220 // Returns true if it can determine that only loopback addresses are configured.
221 // i.e. if only 127.0.0.1 and ::1 are routable.
222 // Also returns false if it cannot determine this.
HaveOnlyLoopbackAddresses()223 bool HaveOnlyLoopbackAddresses() {
224 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
225 base::BlockingType::WILL_BLOCK);
226 #if BUILDFLAG(IS_WIN)
227 // TODO(wtc): implement with the GetAdaptersAddresses function.
228 NOTIMPLEMENTED();
229 return false;
230 #elif BUILDFLAG(IS_ANDROID)
231 return android::HaveOnlyLoopbackAddresses();
232 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
233 struct ifaddrs* interface_addr = nullptr;
234 int rv = getifaddrs(&interface_addr);
235 if (rv != 0) {
236 DVPLOG(1) << "getifaddrs() failed";
237 return false;
238 }
239
240 bool result = true;
241 for (struct ifaddrs* interface = interface_addr; interface != nullptr;
242 interface = interface->ifa_next) {
243 if (!(IFF_UP & interface->ifa_flags))
244 continue;
245 if (IFF_LOOPBACK & interface->ifa_flags)
246 continue;
247 const struct sockaddr* addr = interface->ifa_addr;
248 if (!addr)
249 continue;
250 if (addr->sa_family == AF_INET6) {
251 // Safe cast since this is AF_INET6.
252 const struct sockaddr_in6* addr_in6 =
253 reinterpret_cast<const struct sockaddr_in6*>(addr);
254 const struct in6_addr* sin6_addr = &addr_in6->sin6_addr;
255 if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr))
256 continue;
257 }
258 if (addr->sa_family != AF_INET6 && addr->sa_family != AF_INET)
259 continue;
260
261 result = false;
262 break;
263 }
264 freeifaddrs(interface_addr);
265 return result;
266 #endif // defined(various platforms)
267 }
268
269 // Creates NetLog parameters when the DnsTask failed.
NetLogDnsTaskFailedParams(int net_error,absl::optional<DnsQueryType> failed_transaction_type,absl::optional<base::TimeDelta> ttl,const HostCache::Entry * saved_results)270 base::Value::Dict NetLogDnsTaskFailedParams(
271 int net_error,
272 absl::optional<DnsQueryType> failed_transaction_type,
273 absl::optional<base::TimeDelta> ttl,
274 const HostCache::Entry* saved_results) {
275 base::Value::Dict dict;
276 if (failed_transaction_type) {
277 dict.Set("dns_query_type", kDnsQueryTypes.at(*failed_transaction_type));
278 }
279 if (ttl)
280 dict.Set("error_ttl_sec",
281 base::saturated_cast<int>(ttl.value().InSeconds()));
282 dict.Set("net_error", net_error);
283 if (saved_results)
284 dict.Set("saved_results", saved_results->NetLogParams());
285 return dict;
286 }
287
NetLogDnsTaskExtractionFailureParams(DnsResponseResultExtractor::ExtractionError extraction_error,DnsQueryType dns_query_type,const HostCache::Entry & results)288 base::Value::Dict NetLogDnsTaskExtractionFailureParams(
289 DnsResponseResultExtractor::ExtractionError extraction_error,
290 DnsQueryType dns_query_type,
291 const HostCache::Entry& results) {
292 base::Value::Dict dict;
293 dict.Set("extraction_error", base::strict_cast<int>(extraction_error));
294 dict.Set("dns_query_type", kDnsQueryTypes.at(dns_query_type));
295 dict.Set("results", results.NetLogParams());
296 return dict;
297 }
298
299 // Creates NetLog parameters for HOST_RESOLVER_MANAGER_JOB_ATTACH/DETACH events.
NetLogJobAttachParams(const NetLogSource & source,RequestPriority priority)300 base::Value::Dict NetLogJobAttachParams(const NetLogSource& source,
301 RequestPriority priority) {
302 base::Value::Dict dict;
303 source.AddToEventParameters(dict);
304 dict.Set("priority", RequestPriorityToString(priority));
305 return dict;
306 }
307
NetLogIPv6AvailableParams(bool ipv6_available,bool cached)308 base::Value::Dict NetLogIPv6AvailableParams(bool ipv6_available, bool cached) {
309 base::Value::Dict dict;
310 dict.Set("ipv6_available", ipv6_available);
311 dict.Set("cached", cached);
312 return dict;
313 }
314
315 // The logging routines are defined here because some requests are resolved
316 // without a Request object.
317
318 //-----------------------------------------------------------------------------
319
320 // Maximum of 64 concurrent resolver calls (excluding retries).
321 // Between 2010 and 2020, the limit was set to 6 because of a report of a broken
322 // home router that would fail in the presence of more simultaneous queries.
323 // In 2020, we conducted an experiment to see if this kind of router was still
324 // present on the Internet, and found no evidence of any remaining issues, so
325 // we increased the limit to 64 at that time.
326 const size_t kDefaultMaxSystemTasks = 64u;
327
GetDispatcherLimits(const HostResolver::ManagerOptions & options)328 PrioritizedDispatcher::Limits GetDispatcherLimits(
329 const HostResolver::ManagerOptions& options) {
330 PrioritizedDispatcher::Limits limits(NUM_PRIORITIES,
331 options.max_concurrent_resolves);
332
333 // If not using default, do not use the field trial.
334 if (limits.total_jobs != HostResolver::ManagerOptions::kDefaultParallelism)
335 return limits;
336
337 // Default, without trial is no reserved slots.
338 limits.total_jobs = kDefaultMaxSystemTasks;
339
340 // Parallelism is determined by the field trial.
341 std::string group =
342 base::FieldTrialList::FindFullName("HostResolverDispatch");
343
344 if (group.empty())
345 return limits;
346
347 // The format of the group name is a list of non-negative integers separated
348 // by ':'. Each of the elements in the list corresponds to an element in
349 // |reserved_slots|, except the last one which is the |total_jobs|.
350 std::vector<base::StringPiece> group_parts = base::SplitStringPiece(
351 group, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
352 if (group_parts.size() != NUM_PRIORITIES + 1) {
353 NOTREACHED();
354 return limits;
355 }
356
357 std::vector<size_t> parsed(group_parts.size());
358 for (size_t i = 0; i < group_parts.size(); ++i) {
359 if (!base::StringToSizeT(group_parts[i], &parsed[i])) {
360 NOTREACHED();
361 return limits;
362 }
363 }
364
365 const size_t total_jobs = parsed.back();
366 parsed.pop_back();
367
368 const size_t total_reserved_slots =
369 std::accumulate(parsed.begin(), parsed.end(), 0u);
370
371 // There must be some unreserved slots available for the all priorities.
372 if (total_reserved_slots > total_jobs ||
373 (total_reserved_slots == total_jobs && parsed[MINIMUM_PRIORITY] == 0)) {
374 NOTREACHED();
375 return limits;
376 }
377
378 limits.total_jobs = total_jobs;
379 limits.reserved_slots = parsed;
380 return limits;
381 }
382
383 // Keeps track of the highest priority.
384 class PriorityTracker {
385 public:
PriorityTracker(RequestPriority initial_priority)386 explicit PriorityTracker(RequestPriority initial_priority)
387 : highest_priority_(initial_priority) {}
388
highest_priority() const389 RequestPriority highest_priority() const { return highest_priority_; }
390
total_count() const391 size_t total_count() const { return total_count_; }
392
Add(RequestPriority req_priority)393 void Add(RequestPriority req_priority) {
394 ++total_count_;
395 ++counts_[req_priority];
396 if (highest_priority_ < req_priority)
397 highest_priority_ = req_priority;
398 }
399
Remove(RequestPriority req_priority)400 void Remove(RequestPriority req_priority) {
401 DCHECK_GT(total_count_, 0u);
402 DCHECK_GT(counts_[req_priority], 0u);
403 --total_count_;
404 --counts_[req_priority];
405 size_t i;
406 for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i) {
407 }
408 highest_priority_ = static_cast<RequestPriority>(i);
409
410 // In absence of requests, default to MINIMUM_PRIORITY.
411 if (total_count_ == 0)
412 DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
413 }
414
415 private:
416 RequestPriority highest_priority_;
417 size_t total_count_ = 0;
418 size_t counts_[NUM_PRIORITIES] = {};
419 };
420
NetLogResults(const HostCache::Entry & results)421 base::Value::Dict NetLogResults(const HostCache::Entry& results) {
422 base::Value::Dict dict;
423 dict.Set("results", results.NetLogParams());
424 return dict;
425 }
426
ToLogStringValue(const absl::variant<url::SchemeHostPort,std::string> & host)427 base::Value ToLogStringValue(
428 const absl::variant<url::SchemeHostPort, std::string>& host) {
429 if (absl::holds_alternative<url::SchemeHostPort>(host)) {
430 return base::Value(absl::get<url::SchemeHostPort>(host).Serialize());
431 }
432
433 return base::Value(absl::get<std::string>(host));
434 }
435
436 // Returns empty string if `host` has no known scheme.
GetScheme(const absl::variant<url::SchemeHostPort,std::string> & host)437 base::StringPiece GetScheme(
438 const absl::variant<url::SchemeHostPort, std::string>& host) {
439 if (absl::holds_alternative<url::SchemeHostPort>(host))
440 return absl::get<url::SchemeHostPort>(host).scheme();
441
442 return base::StringPiece();
443 }
444
GetHostname(const absl::variant<url::SchemeHostPort,std::string> & host)445 base::StringPiece GetHostname(
446 const absl::variant<url::SchemeHostPort, std::string>& host) {
447 if (absl::holds_alternative<url::SchemeHostPort>(host)) {
448 base::StringPiece hostname = absl::get<url::SchemeHostPort>(host).host();
449 if (hostname.size() >= 2 && hostname.front() == '[' &&
450 hostname.back() == ']') {
451 hostname = hostname.substr(1, hostname.size() - 2);
452 }
453 return hostname;
454 }
455
456 return absl::get<std::string>(host);
457 }
458
459 // Only use scheme/port in JobKey if `https_svcb_options_enabled` is true
460 // (or the query is explicitly for HTTPS). Otherwise DNS will not give different
461 // results for the same hostname.
CreateHostForJobKey(const HostResolver::Host & input,DnsQueryType query_type,bool https_svcb_options_enabled)462 absl::variant<url::SchemeHostPort, std::string> CreateHostForJobKey(
463 const HostResolver::Host& input,
464 DnsQueryType query_type,
465 bool https_svcb_options_enabled) {
466 if ((https_svcb_options_enabled || query_type == DnsQueryType::HTTPS) &&
467 input.HasScheme()) {
468 return input.AsSchemeHostPort();
469 }
470
471 return std::string(input.GetHostnameWithoutBrackets());
472 }
473
CreateFakeEmptyResponse(base::StringPiece hostname,DnsQueryType query_type)474 DnsResponse CreateFakeEmptyResponse(base::StringPiece hostname,
475 DnsQueryType query_type) {
476 absl::optional<std::vector<uint8_t>> qname =
477 dns_names_util::DottedNameToNetwork(
478 hostname, /*require_valid_internet_hostname=*/true);
479 CHECK(qname.has_value());
480 return DnsResponse::CreateEmptyNoDataResponse(
481 /*id=*/0u, /*is_authoritative=*/true, qname.value(),
482 DnsQueryTypeToQtype(query_type));
483 }
484
FilterAddresses(std::vector<IPEndPoint> addresses,DnsQueryTypeSet query_types)485 std::vector<IPEndPoint> FilterAddresses(std::vector<IPEndPoint> addresses,
486 DnsQueryTypeSet query_types) {
487 DCHECK(!query_types.Has(DnsQueryType::UNSPECIFIED));
488 DCHECK(!query_types.Empty());
489
490 const AddressFamily want_family =
491 HostResolver::DnsQueryTypeSetToAddressFamily(query_types);
492
493 if (want_family == ADDRESS_FAMILY_UNSPECIFIED)
494 return addresses;
495
496 // Keep only the endpoints that match `want_family`.
497 addresses.erase(
498 base::ranges::remove_if(
499 addresses,
500 [want_family](AddressFamily family) { return family != want_family; },
501 &IPEndPoint::GetFamily),
502 addresses.end());
503 return addresses;
504 }
505
RecordResolveTimeDiffForBucket(const char * histogram_variant,const char * histogram_bucket,base::TimeDelta diff)506 void RecordResolveTimeDiffForBucket(const char* histogram_variant,
507 const char* histogram_bucket,
508 base::TimeDelta diff) {
509 base::UmaHistogramTimes(
510 base::StrCat({"Net.Dns.ResolveTimeDiff.", histogram_variant,
511 ".FirstRecord", histogram_bucket}),
512 diff);
513 }
514
RecordResolveTimeDiff(const char * histogram_variant,base::TimeTicks start_time,base::TimeTicks first_record_end_time,base::TimeTicks second_record_end_time)515 void RecordResolveTimeDiff(const char* histogram_variant,
516 base::TimeTicks start_time,
517 base::TimeTicks first_record_end_time,
518 base::TimeTicks second_record_end_time) {
519 CHECK_LE(start_time, first_record_end_time);
520 CHECK_LE(first_record_end_time, second_record_end_time);
521 base::TimeDelta first_elapsed = first_record_end_time - start_time;
522 base::TimeDelta diff = second_record_end_time - first_record_end_time;
523
524 if (first_elapsed < base::Milliseconds(10)) {
525 RecordResolveTimeDiffForBucket(histogram_variant, "FasterThan10ms", diff);
526 } else if (first_elapsed < base::Milliseconds(25)) {
527 RecordResolveTimeDiffForBucket(histogram_variant, "10msTo25ms", diff);
528 } else if (first_elapsed < base::Milliseconds(50)) {
529 RecordResolveTimeDiffForBucket(histogram_variant, "25msTo50ms", diff);
530 } else if (first_elapsed < base::Milliseconds(100)) {
531 RecordResolveTimeDiffForBucket(histogram_variant, "50msTo100ms", diff);
532 } else if (first_elapsed < base::Milliseconds(250)) {
533 RecordResolveTimeDiffForBucket(histogram_variant, "100msTo250ms", diff);
534 } else if (first_elapsed < base::Milliseconds(500)) {
535 RecordResolveTimeDiffForBucket(histogram_variant, "250msTo500ms", diff);
536 } else if (first_elapsed < base::Seconds(1)) {
537 RecordResolveTimeDiffForBucket(histogram_variant, "500msTo1s", diff);
538 } else {
539 RecordResolveTimeDiffForBucket(histogram_variant, "SlowerThan1s", diff);
540 }
541 }
542
543 } // namespace
544
545 //-----------------------------------------------------------------------------
546
ResolveLocalHostname(base::StringPiece host,std::vector<IPEndPoint> * address_list)547 bool ResolveLocalHostname(base::StringPiece host,
548 std::vector<IPEndPoint>* address_list) {
549 address_list->clear();
550 if (!IsLocalHostname(host))
551 return false;
552
553 address_list->emplace_back(IPAddress::IPv6Localhost(), 0);
554 address_list->emplace_back(IPAddress::IPv4Localhost(), 0);
555
556 return true;
557 }
558
559 struct HostResolverManager::JobKey {
JobKeynet::HostResolverManager::JobKey560 explicit JobKey(ResolveContext* resolve_context)
561 : resolve_context(resolve_context->AsSafeRef()) {}
562
operator <net::HostResolverManager::JobKey563 bool operator<(const JobKey& other) const {
564 return std::forward_as_tuple(query_types.ToEnumBitmask(), flags, source,
565 secure_dns_mode, &*resolve_context, host,
566 network_anonymization_key) <
567 std::forward_as_tuple(other.query_types.ToEnumBitmask(), other.flags,
568 other.source, other.secure_dns_mode,
569 &*other.resolve_context, other.host,
570 other.network_anonymization_key);
571 }
572
operator ==net::HostResolverManager::JobKey573 bool operator==(const JobKey& other) const {
574 return !(*this < other || other < *this);
575 }
576
577 absl::variant<url::SchemeHostPort, std::string> host;
578 NetworkAnonymizationKey network_anonymization_key;
579 DnsQueryTypeSet query_types;
580 HostResolverFlags flags;
581 HostResolverSource source;
582 SecureDnsMode secure_dns_mode;
583 base::SafeRef<ResolveContext> resolve_context;
584
ToCacheKeynet::HostResolverManager::JobKey585 HostCache::Key ToCacheKey(bool secure) const {
586 if (query_types.Size() != 1) {
587 // This function will produce identical cache keys for `JobKey` structs
588 // that differ only in their (non-singleton) `query_types` fields. When we
589 // enable new query types, this behavior could lead to subtle bugs. That
590 // is why the following DCHECK restricts the allowable query types.
591 DCHECK(Difference(query_types,
592 DnsQueryTypeSet(DnsQueryType::A, DnsQueryType::AAAA,
593 DnsQueryType::HTTPS))
594 .Empty());
595 }
596 const DnsQueryType query_type_for_key = query_types.Size() == 1
597 ? *query_types.begin()
598 : DnsQueryType::UNSPECIFIED;
599 HostCache::Key key(host, query_type_for_key, flags, source,
600 network_anonymization_key);
601 key.secure = secure;
602 return key;
603 }
604
GetTargetNetworknet::HostResolverManager::JobKey605 handles::NetworkHandle GetTargetNetwork() const {
606 return resolve_context->GetTargetNetwork();
607 }
608 };
609
610 // Holds the callback and request parameters for an outstanding request.
611 //
612 // The RequestImpl is owned by the end user of host resolution. Deletion prior
613 // to the request having completed means the request was cancelled by the
614 // caller.
615 //
616 // Both the RequestImpl and its associated Job hold non-owning pointers to each
617 // other. Care must be taken to clear the corresponding pointer when
618 // cancellation is initiated by the Job (OnJobCancelled) vs by the end user
619 // (~RequestImpl).
620 class HostResolverManager::RequestImpl
621 : public HostResolver::ResolveHostRequest,
622 public base::LinkNode<HostResolverManager::RequestImpl> {
623 public:
RequestImpl(NetLogWithSource source_net_log,HostResolver::Host request_host,NetworkAnonymizationKey network_anonymization_key,absl::optional<ResolveHostParameters> optional_parameters,base::WeakPtr<ResolveContext> resolve_context,HostCache * host_cache,base::WeakPtr<HostResolverManager> resolver,const base::TickClock * tick_clock)624 RequestImpl(NetLogWithSource source_net_log,
625 HostResolver::Host request_host,
626 NetworkAnonymizationKey network_anonymization_key,
627 absl::optional<ResolveHostParameters> optional_parameters,
628 base::WeakPtr<ResolveContext> resolve_context,
629 HostCache* host_cache,
630 base::WeakPtr<HostResolverManager> resolver,
631 const base::TickClock* tick_clock)
632 : source_net_log_(std::move(source_net_log)),
633 request_host_(std::move(request_host)),
634 network_anonymization_key_(
635 NetworkAnonymizationKey::IsPartitioningEnabled()
636 ? std::move(network_anonymization_key)
637 : NetworkAnonymizationKey()),
638 parameters_(optional_parameters ? std::move(optional_parameters).value()
639 : ResolveHostParameters()),
640 resolve_context_(std::move(resolve_context)),
641 host_cache_(host_cache),
642 host_resolver_flags_(
643 HostResolver::ParametersToHostResolverFlags(parameters_)),
644 priority_(parameters_.initial_priority),
645 job_key_(JobKey(resolve_context_.get())),
646 resolver_(std::move(resolver)),
647 tick_clock_(tick_clock) {}
648
649 RequestImpl(const RequestImpl&) = delete;
650 RequestImpl& operator=(const RequestImpl&) = delete;
651
652 ~RequestImpl() override;
653
Start(CompletionOnceCallback callback)654 int Start(CompletionOnceCallback callback) override {
655 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
656 DCHECK(callback);
657 // Start() may only be called once per request.
658 CHECK(!job_.has_value());
659 DCHECK(!complete_);
660 DCHECK(!callback_);
661 // Parent HostResolver must still be alive to call Start().
662 DCHECK(resolver_);
663
664 if (!resolve_context_) {
665 complete_ = true;
666 resolver_.reset();
667 set_error_info(ERR_CONTEXT_SHUT_DOWN, false);
668 return ERR_NAME_NOT_RESOLVED;
669 }
670
671 LogStartRequest();
672
673 next_state_ = STATE_IPV6_REACHABILITY;
674 callback_ = std::move(callback);
675
676 int rv = OK;
677 rv = DoLoop(rv);
678 return rv;
679 }
680
DoLoop(int rv)681 int DoLoop(int rv) {
682 do {
683 ResolveState state = next_state_;
684 next_state_ = STATE_NONE;
685 switch (state) {
686 case STATE_IPV6_REACHABILITY:
687 rv = DoIPv6Reachability();
688 break;
689 case STATE_GET_PARAMETERS:
690 DCHECK_EQ(OK, rv);
691 rv = DoGetParameters();
692 break;
693 case STATE_GET_PARAMETERS_COMPLETE:
694 rv = DoGetParametersComplete(rv);
695 break;
696 case STATE_RESOLVE_LOCALLY:
697 rv = DoResolveLocally();
698 break;
699 case STATE_START_JOB:
700 rv = DoStartJob();
701 break;
702 case STATE_FINISH_REQUEST:
703 rv = DoFinishRequest(rv);
704 break;
705 default:
706 NOTREACHED() << "next_state_: " << next_state_;
707 break;
708 }
709 } while (next_state_ != STATE_NONE && rv != ERR_IO_PENDING);
710
711 return rv;
712 }
713
OnIOComplete(int rv)714 void OnIOComplete(int rv) {
715 rv = DoLoop(rv);
716 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
717 std::move(callback_).Run(rv);
718 }
719 }
720
DoIPv6Reachability()721 int DoIPv6Reachability() {
722 next_state_ = STATE_GET_PARAMETERS;
723 // If a single reachability probe has not been completed, and the latest
724 // probe will return asynchronously, return ERR_NAME_NOT_RESOLVED when the
725 // request source is LOCAL_ONLY. This is due to LOCAL_ONLY requiring a
726 // synchronous response, so it cannot wait on an async probe result and
727 // cannot make assumptions about reachability.
728 if (parameters_.source == HostResolverSource::LOCAL_ONLY) {
729 int rv = resolver_->StartIPv6ReachabilityCheck(
730 source_net_log_, base::DoNothingAs<void(int)>());
731 if (rv == ERR_IO_PENDING) {
732 next_state_ = STATE_FINISH_REQUEST;
733 return ERR_NAME_NOT_RESOLVED;
734 }
735 return OK;
736 }
737 return resolver_->StartIPv6ReachabilityCheck(
738 source_net_log_, base::BindOnce(&RequestImpl::OnIOComplete,
739 weak_ptr_factory_.GetWeakPtr()));
740 }
741
DoGetParameters()742 int DoGetParameters() {
743 job_key_.host =
744 CreateHostForJobKey(request_host_, parameters_.dns_query_type,
745 resolver_->https_svcb_options_.enable);
746 job_key_.network_anonymization_key = network_anonymization_key_;
747 job_key_.source = parameters_.source;
748
749 bool is_ip = ip_address_.AssignFromIPLiteral(GetHostname(job_key_.host));
750
751 resolver_->GetEffectiveParametersForRequest(
752 job_key_.host, parameters_.dns_query_type, host_resolver_flags_,
753 parameters_.secure_dns_policy, is_ip, source_net_log_,
754 &job_key_.query_types, &job_key_.flags, &job_key_.secure_dns_mode);
755
756 // A reachability probe to determine if the network is only reachable on
757 // IPv6 will be scheduled if the parameters are met for using NAT64 in place
758 // of an IPv4 address.
759 if (MayUseNAT64ForIPv4Literal(job_key_.flags, parameters_.source,
760 ip_address_) &&
761 resolver_->last_ipv6_probe_result_) {
762 next_state_ = STATE_GET_PARAMETERS_COMPLETE;
763 return resolver_->StartGloballyReachableCheck(
764 ip_address_, source_net_log_,
765 base::BindOnce(&RequestImpl::OnIOComplete,
766 weak_ptr_factory_.GetWeakPtr()));
767 }
768 next_state_ = STATE_RESOLVE_LOCALLY;
769 return OK;
770 }
771
DoGetParametersComplete(int rv)772 int DoGetParametersComplete(int rv) {
773 next_state_ = STATE_RESOLVE_LOCALLY;
774 only_ipv6_reachable_ = (rv == ERR_FAILED) ? true : false;
775 return OK;
776 }
777
DoResolveLocally()778 int DoResolveLocally() {
779 absl::optional<HostCache::EntryStaleness> stale_info;
780 HostCache::Entry results = resolver_->ResolveLocally(
781 only_ipv6_reachable_, job_key_, ip_address_, parameters_.cache_usage,
782 parameters_.secure_dns_policy, parameters_.source, source_net_log_,
783 host_cache_, &tasks_, &stale_info);
784 if (results.error() != ERR_DNS_CACHE_MISS ||
785 parameters_.source == HostResolverSource::LOCAL_ONLY ||
786 tasks_.empty()) {
787 if (results.error() == OK && !parameters_.is_speculative) {
788 set_results(results.CopyWithDefaultPort(request_host_.GetPort()));
789 }
790 if (stale_info && !parameters_.is_speculative) {
791 set_stale_info(std::move(stale_info).value());
792 }
793 next_state_ = STATE_FINISH_REQUEST;
794 return results.error();
795 }
796 next_state_ = STATE_START_JOB;
797 return OK;
798 }
799
DoStartJob()800 int DoStartJob() {
801 resolver_->CreateAndStartJob(std::move(job_key_), std::move(tasks_), this);
802 DCHECK(!complete_);
803 resolver_.reset();
804 return ERR_IO_PENDING;
805 }
806
DoFinishRequest(int rv)807 int DoFinishRequest(int rv) {
808 CHECK(!job_.has_value());
809 complete_ = true;
810 set_error_info(rv, /*is_secure_network_error=*/false);
811 rv = HostResolver::SquashErrorCode(rv);
812 LogFinishRequest(rv, /*async_completion=*/false);
813 return rv;
814 }
815
GetAddressResults() const816 const AddressList* GetAddressResults() const override {
817 DCHECK(complete_);
818 return base::OptionalToPtr(legacy_address_results_);
819 }
820
GetEndpointResults() const821 const std::vector<HostResolverEndpointResult>* GetEndpointResults()
822 const override {
823 DCHECK(complete_);
824 return base::OptionalToPtr(endpoint_results_);
825 }
826
GetTextResults() const827 const absl::optional<std::vector<std::string>>& GetTextResults()
828 const override {
829 DCHECK(complete_);
830 static const base::NoDestructor<absl::optional<std::vector<std::string>>>
831 nullopt_result;
832 return results_ ? results_.value().text_records() : *nullopt_result;
833 }
834
GetHostnameResults() const835 const absl::optional<std::vector<HostPortPair>>& GetHostnameResults()
836 const override {
837 DCHECK(complete_);
838 static const base::NoDestructor<absl::optional<std::vector<HostPortPair>>>
839 nullopt_result;
840 return results_ ? results_.value().hostnames() : *nullopt_result;
841 }
842
GetDnsAliasResults() const843 const std::set<std::string>* GetDnsAliasResults() const override {
844 DCHECK(complete_);
845
846 // If `include_canonical_name` param was true, should only ever have at most
847 // a single alias, representing the expected "canonical name".
848 #if DCHECK_IS_ON()
849 if (parameters().include_canonical_name && fixed_up_dns_alias_results_) {
850 DCHECK_LE(fixed_up_dns_alias_results_->size(), 1u);
851 if (GetAddressResults()) {
852 std::set<std::string> address_list_aliases_set(
853 GetAddressResults()->dns_aliases().begin(),
854 GetAddressResults()->dns_aliases().end());
855 DCHECK(address_list_aliases_set == fixed_up_dns_alias_results_.value());
856 }
857 }
858 #endif // DCHECK_IS_ON()
859
860 return base::OptionalToPtr(fixed_up_dns_alias_results_);
861 }
862
GetExperimentalResultsForTesting() const863 const std::vector<bool>* GetExperimentalResultsForTesting() const override {
864 DCHECK(complete_);
865 return results_ ? results_.value().https_record_compatibility() : nullptr;
866 }
867
GetResolveErrorInfo() const868 net::ResolveErrorInfo GetResolveErrorInfo() const override {
869 DCHECK(complete_);
870 return error_info_;
871 }
872
GetStaleInfo() const873 const absl::optional<HostCache::EntryStaleness>& GetStaleInfo()
874 const override {
875 DCHECK(complete_);
876 return stale_info_;
877 }
878
879 void ChangeRequestPriority(RequestPriority priority) override;
880
set_results(HostCache::Entry results)881 void set_results(HostCache::Entry results) {
882 // Should only be called at most once and before request is marked
883 // completed.
884 DCHECK(!complete_);
885 DCHECK(!results_);
886 DCHECK(!parameters_.is_speculative);
887
888 results_ = std::move(results);
889 FixUpEndpointAndAliasResults();
890 }
891
set_error_info(int error,bool is_secure_network_error)892 void set_error_info(int error, bool is_secure_network_error) {
893 error_info_ = ResolveErrorInfo(error, is_secure_network_error);
894 }
895
set_stale_info(HostCache::EntryStaleness stale_info)896 void set_stale_info(HostCache::EntryStaleness stale_info) {
897 // Should only be called at most once and before request is marked
898 // completed.
899 DCHECK(!complete_);
900 DCHECK(!stale_info_);
901 DCHECK(!parameters_.is_speculative);
902
903 stale_info_ = std::move(stale_info);
904 }
905
AssignJob(base::SafeRef<Job> job)906 void AssignJob(base::SafeRef<Job> job) {
907 CHECK(!job_.has_value());
908 job_ = std::move(job);
909 }
910
HasJob() const911 bool HasJob() const { return job_.has_value(); }
912
913 // Gets the Job's key. Crashes if no Job has been assigned.
914 const JobKey& GetJobKey() const;
915
916 // Unassigns the Job without calling completion callback.
917 void OnJobCancelled(const JobKey& key);
918
919 // Cleans up Job assignment, marks request completed, and calls the completion
920 // callback. |is_secure_network_error| indicates whether |error| came from a
921 // secure DNS lookup.
922 void OnJobCompleted(const JobKey& job_key,
923 int error,
924 bool is_secure_network_error);
925
926 // NetLog for the source, passed in HostResolver::Resolve.
source_net_log()927 const NetLogWithSource& source_net_log() { return source_net_log_; }
928
request_host() const929 const HostResolver::Host& request_host() const { return request_host_; }
930
network_anonymization_key() const931 const NetworkAnonymizationKey& network_anonymization_key() const {
932 return network_anonymization_key_;
933 }
934
parameters() const935 const ResolveHostParameters& parameters() const { return parameters_; }
936
resolve_context() const937 ResolveContext* resolve_context() const { return resolve_context_.get(); }
938
host_cache() const939 HostCache* host_cache() const { return host_cache_; }
940
host_resolver_flags() const941 HostResolverFlags host_resolver_flags() const { return host_resolver_flags_; }
942
priority() const943 RequestPriority priority() const { return priority_; }
set_priority(RequestPriority priority)944 void set_priority(RequestPriority priority) { priority_ = priority; }
945
complete() const946 bool complete() const { return complete_; }
947
948 private:
949 enum ResolveState {
950 STATE_IPV6_REACHABILITY,
951 STATE_GET_PARAMETERS,
952 STATE_GET_PARAMETERS_COMPLETE,
953 STATE_RESOLVE_LOCALLY,
954 STATE_START_JOB,
955 STATE_FINISH_REQUEST,
956 STATE_NONE,
957 };
958
FixUpEndpointAndAliasResults()959 void FixUpEndpointAndAliasResults() {
960 DCHECK(results_.has_value());
961 DCHECK(!legacy_address_results_.has_value());
962 DCHECK(!endpoint_results_.has_value());
963 DCHECK(!fixed_up_dns_alias_results_.has_value());
964
965 endpoint_results_ = results_.value().GetEndpoints();
966 if (endpoint_results_.has_value()) {
967 DCHECK(results_.value().aliases());
968 fixed_up_dns_alias_results_ = *results_.value().aliases();
969
970 // Skip fixups for `include_canonical_name` requests. Just use the
971 // canonical name exactly as it was received from the system resolver.
972 if (parameters().include_canonical_name) {
973 DCHECK_LE(fixed_up_dns_alias_results_.value().size(), 1u);
974 } else {
975 fixed_up_dns_alias_results_ = dns_alias_utility::FixUpDnsAliases(
976 fixed_up_dns_alias_results_.value());
977 }
978
979 legacy_address_results_ = HostResolver::EndpointResultToAddressList(
980 endpoint_results_.value(), fixed_up_dns_alias_results_.value());
981 }
982 }
983
984 // Logging and metrics for when a request has just been started.
LogStartRequest()985 void LogStartRequest() {
986 DCHECK(request_time_.is_null());
987 request_time_ = tick_clock_->NowTicks();
988
989 source_net_log_.BeginEvent(
990 NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST, [this] {
991 base::Value::Dict dict;
992 dict.Set("host", request_host_.ToString());
993 dict.Set("dns_query_type",
994 kDnsQueryTypes.at(parameters_.dns_query_type));
995 dict.Set("allow_cached_response",
996 parameters_.cache_usage !=
997 ResolveHostParameters::CacheUsage::DISALLOWED);
998 dict.Set("is_speculative", parameters_.is_speculative);
999 dict.Set("network_anonymization_key",
1000 network_anonymization_key_.ToDebugString());
1001 dict.Set("secure_dns_policy",
1002 base::strict_cast<int>(parameters_.secure_dns_policy));
1003 return dict;
1004 });
1005 }
1006
1007 // Logging and metrics for when a request has just completed (before its
1008 // callback is run).
LogFinishRequest(int net_error,bool async_completion)1009 void LogFinishRequest(int net_error, bool async_completion) {
1010 source_net_log_.EndEventWithNetErrorCode(
1011 NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST, net_error);
1012
1013 if (!parameters_.is_speculative) {
1014 DCHECK(!request_time_.is_null());
1015 base::TimeDelta duration = tick_clock_->NowTicks() - request_time_;
1016
1017 UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTime", duration);
1018 if (async_completion)
1019 UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTimeAsync", duration);
1020 }
1021 }
1022
1023 // Logs when a request has been cancelled.
LogCancelRequest()1024 void LogCancelRequest() {
1025 source_net_log_.AddEvent(NetLogEventType::CANCELLED);
1026 source_net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST);
1027 }
1028
1029 const NetLogWithSource source_net_log_;
1030
1031 const HostResolver::Host request_host_;
1032 const NetworkAnonymizationKey network_anonymization_key_;
1033 ResolveHostParameters parameters_;
1034 base::WeakPtr<ResolveContext> resolve_context_;
1035 const raw_ptr<HostCache, DanglingUntriaged> host_cache_;
1036 const HostResolverFlags host_resolver_flags_;
1037
1038 RequestPriority priority_;
1039
1040 ResolveState next_state_;
1041 JobKey job_key_;
1042 IPAddress ip_address_;
1043
1044 std::deque<TaskType> tasks_;
1045 // The resolve job that this request is dependent on.
1046 absl::optional<base::SafeRef<Job>> job_;
1047 base::WeakPtr<HostResolverManager> resolver_ = nullptr;
1048
1049 // The user's callback to invoke when the request completes.
1050 CompletionOnceCallback callback_;
1051
1052 bool complete_ = false;
1053 bool only_ipv6_reachable_ = false;
1054 absl::optional<HostCache::Entry> results_;
1055 absl::optional<HostCache::EntryStaleness> stale_info_;
1056 absl::optional<AddressList> legacy_address_results_;
1057 absl::optional<std::vector<HostResolverEndpointResult>> endpoint_results_;
1058 absl::optional<std::set<std::string>> fixed_up_dns_alias_results_;
1059 ResolveErrorInfo error_info_;
1060
1061 const raw_ptr<const base::TickClock> tick_clock_;
1062 base::TimeTicks request_time_;
1063
1064 SEQUENCE_CHECKER(sequence_checker_);
1065
1066 base::WeakPtrFactory<RequestImpl> weak_ptr_factory_{this};
1067 };
1068
1069 class HostResolverManager::ProbeRequestImpl
1070 : public HostResolver::ProbeRequest,
1071 public ResolveContext::DohStatusObserver {
1072 public:
ProbeRequestImpl(base::WeakPtr<ResolveContext> context,base::WeakPtr<HostResolverManager> resolver)1073 ProbeRequestImpl(base::WeakPtr<ResolveContext> context,
1074 base::WeakPtr<HostResolverManager> resolver)
1075 : context_(std::move(context)), resolver_(std::move(resolver)) {}
1076
1077 ProbeRequestImpl(const ProbeRequestImpl&) = delete;
1078 ProbeRequestImpl& operator=(const ProbeRequestImpl&) = delete;
1079
~ProbeRequestImpl()1080 ~ProbeRequestImpl() override {
1081 // Ensure that observers are deregistered to avoid wasting memory.
1082 if (context_)
1083 context_->UnregisterDohStatusObserver(this);
1084 }
1085
Start()1086 int Start() override {
1087 DCHECK(resolver_);
1088 DCHECK(!runner_);
1089
1090 if (!context_)
1091 return ERR_CONTEXT_SHUT_DOWN;
1092
1093 context_->RegisterDohStatusObserver(this);
1094
1095 StartRunner(false /* network_change */);
1096 return ERR_IO_PENDING;
1097 }
1098
1099 // ResolveContext::DohStatusObserver
OnSessionChanged()1100 void OnSessionChanged() override { CancelRunner(); }
1101
OnDohServerUnavailable(bool network_change)1102 void OnDohServerUnavailable(bool network_change) override {
1103 // Start the runner asynchronously, as this may trigger reentrant calls into
1104 // HostResolverManager, which are not allowed during notification handling.
1105 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
1106 FROM_HERE,
1107 base::BindOnce(&ProbeRequestImpl::StartRunner,
1108 weak_ptr_factory_.GetWeakPtr(), network_change));
1109 }
1110
1111 private:
StartRunner(bool network_change)1112 void StartRunner(bool network_change) {
1113 DCHECK(resolver_);
1114 DCHECK(!resolver_->invalidation_in_progress_);
1115
1116 if (!context_)
1117 return; // Reachable if the context ends before a posted task runs.
1118
1119 if (!runner_)
1120 runner_ = resolver_->CreateDohProbeRunner(context_.get());
1121 if (runner_)
1122 runner_->Start(network_change);
1123 }
1124
CancelRunner()1125 void CancelRunner() {
1126 runner_.reset();
1127
1128 // Cancel any asynchronous StartRunner() calls.
1129 weak_ptr_factory_.InvalidateWeakPtrs();
1130 }
1131
1132 base::WeakPtr<ResolveContext> context_;
1133
1134 std::unique_ptr<DnsProbeRunner> runner_;
1135 base::WeakPtr<HostResolverManager> resolver_;
1136
1137 base::WeakPtrFactory<ProbeRequestImpl> weak_ptr_factory_{this};
1138 };
1139
1140 //-----------------------------------------------------------------------------
1141
1142 // Resolves the hostname using DnsTransaction, which is a full implementation of
1143 // a DNS stub resolver. One DnsTransaction is created for each resolution
1144 // needed, which for AF_UNSPEC resolutions includes both A and AAAA. The
1145 // transactions are scheduled separately and started separately.
1146 //
1147 // TODO(szym): This could be moved to separate source file as well.
1148 class HostResolverManager::DnsTask : public base::SupportsWeakPtr<DnsTask> {
1149 public:
1150 class Delegate {
1151 public:
1152 virtual void OnDnsTaskComplete(base::TimeTicks start_time,
1153 bool allow_fallback,
1154 HostCache::Entry results,
1155 bool secure) = 0;
1156
1157 // Called when one or more transactions complete or get cancelled, but only
1158 // if more transactions are needed. If no more transactions are needed,
1159 // expect `OnDnsTaskComplete()` to be called instead.
1160 virtual void OnIntermediateTransactionsComplete() = 0;
1161
1162 virtual RequestPriority priority() const = 0;
1163
1164 virtual void AddTransactionTimeQueued(base::TimeDelta time_queued) = 0;
1165
1166 protected:
1167 Delegate() = default;
1168 virtual ~Delegate() = default;
1169 };
1170
DnsTask(DnsClient * client,absl::variant<url::SchemeHostPort,std::string> host,DnsQueryTypeSet query_types,ResolveContext * resolve_context,bool secure,SecureDnsMode secure_dns_mode,Delegate * delegate,const NetLogWithSource & job_net_log,const base::TickClock * tick_clock,bool fallback_available,const HostResolver::HttpsSvcbOptions & https_svcb_options)1171 DnsTask(DnsClient* client,
1172 absl::variant<url::SchemeHostPort, std::string> host,
1173 DnsQueryTypeSet query_types,
1174 ResolveContext* resolve_context,
1175 bool secure,
1176 SecureDnsMode secure_dns_mode,
1177 Delegate* delegate,
1178 const NetLogWithSource& job_net_log,
1179 const base::TickClock* tick_clock,
1180 bool fallback_available,
1181 const HostResolver::HttpsSvcbOptions& https_svcb_options)
1182 : client_(client),
1183 host_(std::move(host)),
1184 resolve_context_(resolve_context->AsSafeRef()),
1185 secure_(secure),
1186 secure_dns_mode_(secure_dns_mode),
1187 delegate_(delegate),
1188 net_log_(job_net_log),
1189 tick_clock_(tick_clock),
1190 task_start_time_(tick_clock_->NowTicks()),
1191 fallback_available_(fallback_available),
1192 https_svcb_options_(https_svcb_options) {
1193 DCHECK(client_);
1194 DCHECK(delegate_);
1195
1196 if (!secure_) {
1197 DCHECK(client_->CanUseInsecureDnsTransactions());
1198 }
1199
1200 PushTransactionsNeeded(MaybeDisableAdditionalQueries(query_types));
1201 }
1202
1203 DnsTask(const DnsTask&) = delete;
1204 DnsTask& operator=(const DnsTask&) = delete;
1205
num_additional_transactions_needed() const1206 int num_additional_transactions_needed() const {
1207 return base::checked_cast<int>(transactions_needed_.size());
1208 }
1209
num_transactions_in_progress() const1210 int num_transactions_in_progress() const {
1211 return base::checked_cast<int>(transactions_in_progress_.size());
1212 }
1213
secure() const1214 bool secure() const { return secure_; }
1215
StartNextTransaction()1216 void StartNextTransaction() {
1217 DCHECK_GE(num_additional_transactions_needed(), 1);
1218
1219 if (!any_transaction_started_) {
1220 net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_MANAGER_DNS_TASK,
1221 [&] { return NetLogDnsTaskCreationParams(); });
1222 }
1223 any_transaction_started_ = true;
1224
1225 TransactionInfo transaction_info = std::move(transactions_needed_.front());
1226 transactions_needed_.pop_front();
1227
1228 DCHECK(IsAddressType(transaction_info.type) || secure_ ||
1229 client_->CanQueryAdditionalTypesViaInsecureDns());
1230
1231 // Record how long this transaction has been waiting to be created.
1232 base::TimeDelta time_queued = tick_clock_->NowTicks() - task_start_time_;
1233 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.PerTransaction",
1234 time_queued);
1235 delegate_->AddTransactionTimeQueued(time_queued);
1236
1237 CreateAndStartTransaction(std::move(transaction_info));
1238 }
1239
1240 private:
1241 enum class TransactionErrorBehavior {
1242 // Errors lead to task fallback (immediately unless another pending/started
1243 // transaction has the `kFatalOrEmpty` behavior).
1244 kFallback,
1245
1246 // Transaction errors are treated as if a NOERROR response were received,
1247 // allowing task success if other transactions complete successfully.
1248 kSynthesizeEmpty,
1249
1250 // Transaction errors are potentially fatal (determined by
1251 // `OnTransactionComplete` and often its helper
1252 // `IsFatalTransactionFailure()`) for the entire Job and may disallow
1253 // fallback. Otherwise, same as `kSynthesizeEmpty`.
1254 // TODO(crbug.com/1264933): Implement the fatality behavior.
1255 kFatalOrEmpty,
1256 };
1257
1258 struct TransactionInfo {
TransactionInfonet::HostResolverManager::DnsTask::TransactionInfo1259 explicit TransactionInfo(DnsQueryType type,
1260 TransactionErrorBehavior error_behavior =
1261 TransactionErrorBehavior::kFallback)
1262 : type(type), error_behavior(error_behavior) {}
1263 TransactionInfo(TransactionInfo&&) = default;
1264 TransactionInfo& operator=(TransactionInfo&&) = default;
1265
operator <net::HostResolverManager::DnsTask::TransactionInfo1266 bool operator<(const TransactionInfo& other) const {
1267 return std::tie(type, error_behavior, transaction) <
1268 std::tie(other.type, other.error_behavior, other.transaction);
1269 }
1270
1271 DnsQueryType type;
1272 TransactionErrorBehavior error_behavior;
1273 std::unique_ptr<DnsTransaction> transaction;
1274 };
1275
NetLogDnsTaskCreationParams()1276 base::Value::Dict NetLogDnsTaskCreationParams() {
1277 base::Value::Dict dict;
1278 dict.Set("secure", secure());
1279
1280 base::Value::List transactions_needed_value;
1281 for (const TransactionInfo& info : transactions_needed_) {
1282 base::Value::Dict transaction_dict;
1283 transaction_dict.Set("dns_query_type", kDnsQueryTypes.at(info.type));
1284 transactions_needed_value.Append(std::move(transaction_dict));
1285 }
1286 dict.Set("transactions_needed", std::move(transactions_needed_value));
1287
1288 return dict;
1289 }
1290
NetLogDnsTaskTimeoutParams()1291 base::Value::Dict NetLogDnsTaskTimeoutParams() {
1292 base::Value::Dict dict;
1293
1294 if (!transactions_in_progress_.empty()) {
1295 base::Value::List list;
1296 for (const TransactionInfo& info : transactions_in_progress_) {
1297 base::Value::Dict transaction_dict;
1298 transaction_dict.Set("dns_query_type", kDnsQueryTypes.at(info.type));
1299 list.Append(std::move(transaction_dict));
1300 }
1301 dict.Set("started_transactions", std::move(list));
1302 }
1303
1304 if (!transactions_needed_.empty()) {
1305 base::Value::List list;
1306 for (const TransactionInfo& info : transactions_needed_) {
1307 base::Value::Dict transaction_dict;
1308 transaction_dict.Set("dns_query_type", kDnsQueryTypes.at(info.type));
1309 list.Append(std::move(transaction_dict));
1310 }
1311 dict.Set("queued_transactions", std::move(list));
1312 }
1313
1314 return dict;
1315 }
1316
MaybeDisableAdditionalQueries(DnsQueryTypeSet types)1317 DnsQueryTypeSet MaybeDisableAdditionalQueries(DnsQueryTypeSet types) {
1318 DCHECK(!types.Empty());
1319 DCHECK(!types.Has(DnsQueryType::UNSPECIFIED));
1320
1321 // No-op if the caller explicitly requested this one query type.
1322 if (types.Size() == 1)
1323 return types;
1324
1325 if (types.Has(DnsQueryType::HTTPS)) {
1326 if (!secure_ && !client_->CanQueryAdditionalTypesViaInsecureDns()) {
1327 types.Remove(DnsQueryType::HTTPS);
1328 } else {
1329 DCHECK(!httpssvc_metrics_);
1330 httpssvc_metrics_.emplace(secure_);
1331 }
1332 }
1333 DCHECK(!types.Empty());
1334 return types;
1335 }
1336
PushTransactionsNeeded(DnsQueryTypeSet query_types)1337 void PushTransactionsNeeded(DnsQueryTypeSet query_types) {
1338 DCHECK(transactions_needed_.empty());
1339
1340 if (query_types.Has(DnsQueryType::HTTPS) &&
1341 features::kUseDnsHttpsSvcbEnforceSecureResponse.Get() && secure_) {
1342 query_types.Remove(DnsQueryType::HTTPS);
1343 transactions_needed_.emplace_back(
1344 DnsQueryType::HTTPS, TransactionErrorBehavior::kFatalOrEmpty);
1345 }
1346
1347 // Give AAAA/A queries a head start by pushing them to the queue first.
1348 constexpr DnsQueryType kHighPriorityQueries[] = {DnsQueryType::AAAA,
1349 DnsQueryType::A};
1350 for (DnsQueryType high_priority_query : kHighPriorityQueries) {
1351 if (query_types.Has(high_priority_query)) {
1352 query_types.Remove(high_priority_query);
1353 transactions_needed_.emplace_back(high_priority_query);
1354 }
1355 }
1356 for (DnsQueryType remaining_query : query_types) {
1357 if (remaining_query == DnsQueryType::HTTPS) {
1358 // Ignore errors for these types. In most cases treating them normally
1359 // would only result in fallback to resolution without querying the
1360 // type. Instead, synthesize empty results.
1361 transactions_needed_.emplace_back(
1362 remaining_query, TransactionErrorBehavior::kSynthesizeEmpty);
1363 } else {
1364 transactions_needed_.emplace_back(remaining_query);
1365 }
1366 }
1367 }
1368
CreateAndStartTransaction(TransactionInfo transaction_info)1369 void CreateAndStartTransaction(TransactionInfo transaction_info) {
1370 DCHECK(!transaction_info.transaction);
1371 DCHECK_NE(DnsQueryType::UNSPECIFIED, transaction_info.type);
1372
1373 std::string transaction_hostname(GetHostname(host_));
1374
1375 // For HTTPS, prepend "_<port>._https." for any non-default port.
1376 uint16_t request_port = 0;
1377 if (transaction_info.type == DnsQueryType::HTTPS &&
1378 absl::holds_alternative<url::SchemeHostPort>(host_)) {
1379 const auto& scheme_host_port = absl::get<url::SchemeHostPort>(host_);
1380 transaction_hostname =
1381 dns_util::GetNameForHttpsQuery(scheme_host_port, &request_port);
1382 }
1383
1384 transaction_info.transaction =
1385 client_->GetTransactionFactory()->CreateTransaction(
1386 std::move(transaction_hostname),
1387 DnsQueryTypeToQtype(transaction_info.type), net_log_, secure_,
1388 secure_dns_mode_, &*resolve_context_,
1389 fallback_available_ /* fast_timeout */);
1390 transaction_info.transaction->SetRequestPriority(delegate_->priority());
1391
1392 auto transaction_info_it =
1393 transactions_in_progress_.insert(std::move(transaction_info)).first;
1394
1395 // Safe to pass `transaction_info_it` because it is only modified/removed
1396 // after async completion of this call or by destruction (which cancels the
1397 // transaction and prevents callback because it owns the `DnsTransaction`
1398 // object).
1399 transaction_info_it->transaction->Start(base::BindOnce(
1400 &DnsTask::OnDnsTransactionComplete, base::Unretained(this),
1401 transaction_info_it, request_port));
1402 }
1403
OnTimeout()1404 void OnTimeout() {
1405 net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_DNS_TASK_TIMEOUT,
1406 [&] { return NetLogDnsTaskTimeoutParams(); });
1407
1408 for (const TransactionInfo& transaction : transactions_in_progress_) {
1409 base::TimeDelta elapsed_time = tick_clock_->NowTicks() - task_start_time_;
1410
1411 switch (transaction.type) {
1412 case DnsQueryType::HTTPS:
1413 DCHECK(!secure_ ||
1414 !features::kUseDnsHttpsSvcbEnforceSecureResponse.Get());
1415 if (httpssvc_metrics_) {
1416 // Don't record provider ID for timeouts. It is not precisely known
1417 // at this level which provider is actually to blame for the
1418 // timeout, and breaking metrics out by provider is no longer
1419 // important for current experimentation goals.
1420 httpssvc_metrics_->SaveForHttps(HttpssvcDnsRcode::kTimedOut,
1421 /*condensed_records=*/{},
1422 elapsed_time);
1423 }
1424 break;
1425 default:
1426 // The timeout timer is only started when all other transactions have
1427 // completed.
1428 NOTREACHED();
1429 }
1430 }
1431
1432 transactions_needed_.clear();
1433 transactions_in_progress_.clear();
1434
1435 OnTransactionsFinished();
1436 }
1437
1438 // Called on completion of a `DnsTransaction`, but not necessarily completion
1439 // of all work for the individual transaction in this task (see
1440 // `OnTransactionsFinished()`).
OnDnsTransactionComplete(std::set<TransactionInfo>::iterator transaction_info_it,uint16_t request_port,int net_error,const DnsResponse * response)1441 void OnDnsTransactionComplete(
1442 std::set<TransactionInfo>::iterator transaction_info_it,
1443 uint16_t request_port,
1444 int net_error,
1445 const DnsResponse* response) {
1446 DCHECK(transaction_info_it != transactions_in_progress_.end());
1447 DCHECK(transactions_in_progress_.find(*transaction_info_it) !=
1448 transactions_in_progress_.end());
1449
1450 // Pull the TransactionInfo out of `transactions_in_progress_` now, so it
1451 // and its underlying DnsTransaction will be deleted on completion of
1452 // OnTransactionComplete. Note: Once control leaves OnTransactionComplete,
1453 // there's no further need for the transaction object. On the other hand,
1454 // since it owns `*response`, it should stay around while
1455 // OnTransactionComplete executes.
1456 TransactionInfo transaction_info = std::move(
1457 transactions_in_progress_.extract(transaction_info_it).value());
1458
1459 const base::TimeTicks now = tick_clock_->NowTicks();
1460 base::TimeDelta elapsed_time = now - task_start_time_;
1461 enum HttpssvcDnsRcode rcode_for_httpssvc = HttpssvcDnsRcode::kNoError;
1462 if (httpssvc_metrics_) {
1463 if (net_error == ERR_DNS_TIMED_OUT) {
1464 rcode_for_httpssvc = HttpssvcDnsRcode::kTimedOut;
1465 } else if (net_error == ERR_NAME_NOT_RESOLVED) {
1466 rcode_for_httpssvc = HttpssvcDnsRcode::kNoError;
1467 } else if (response == nullptr) {
1468 rcode_for_httpssvc = HttpssvcDnsRcode::kMissingDnsResponse;
1469 } else {
1470 rcode_for_httpssvc =
1471 TranslateDnsRcodeForHttpssvcExperiment(response->rcode());
1472 }
1473 }
1474
1475 // Handle network errors. Note that for NXDOMAIN, DnsTransaction returns
1476 // ERR_NAME_NOT_RESOLVED, so that is not a network error if received with a
1477 // valid response.
1478 bool fatal_error =
1479 IsFatalTransactionFailure(net_error, transaction_info, response);
1480 absl::optional<DnsResponse> fake_response;
1481 if (net_error != OK && !(net_error == ERR_NAME_NOT_RESOLVED && response &&
1482 response->IsValid())) {
1483 if (transaction_info.error_behavior ==
1484 TransactionErrorBehavior::kFallback ||
1485 fatal_error) {
1486 // Fail task (or maybe Job) completely on network failure.
1487 OnFailure(net_error, /*allow_fallback=*/!fatal_error,
1488 /*ttl=*/absl::nullopt, transaction_info.type);
1489 return;
1490 } else {
1491 DCHECK((transaction_info.error_behavior ==
1492 TransactionErrorBehavior::kFatalOrEmpty &&
1493 !fatal_error) ||
1494 transaction_info.error_behavior ==
1495 TransactionErrorBehavior::kSynthesizeEmpty);
1496 // For non-fatal failures, synthesize an empty response.
1497 fake_response =
1498 CreateFakeEmptyResponse(GetHostname(host_), transaction_info.type);
1499 response = &fake_response.value();
1500 }
1501 }
1502
1503 HostCache::Entry results(ERR_FAILED, HostCache::Entry::SOURCE_UNKNOWN);
1504 DnsResponseResultExtractor extractor(response);
1505 DnsResponseResultExtractor::ExtractionError extraction_error =
1506 extractor.ExtractDnsResults(transaction_info.type,
1507 /*original_domain_name=*/GetHostname(host_),
1508 request_port, &results);
1509 DCHECK_NE(extraction_error,
1510 DnsResponseResultExtractor::ExtractionError::kUnexpected);
1511
1512 if (results.error() != OK && results.error() != ERR_NAME_NOT_RESOLVED) {
1513 net_log_.AddEvent(
1514 NetLogEventType::HOST_RESOLVER_MANAGER_DNS_TASK_EXTRACTION_FAILURE,
1515 [&] {
1516 return NetLogDnsTaskExtractionFailureParams(
1517 extraction_error, transaction_info.type, results);
1518 });
1519 if (transaction_info.error_behavior ==
1520 TransactionErrorBehavior::kFatalOrEmpty ||
1521 transaction_info.error_behavior ==
1522 TransactionErrorBehavior::kSynthesizeEmpty) {
1523 // No extraction errors are currently considered fatal, otherwise, there
1524 // would need to be a call to some sort of
1525 // IsFatalTransactionExtractionError() function.
1526 DCHECK(!fatal_error);
1527 results = DnsResponseResultExtractor::CreateEmptyResult(
1528 transaction_info.type);
1529 } else {
1530 OnFailure(results.error(), /*allow_fallback=*/true,
1531 results.GetOptionalTtl(), transaction_info.type);
1532 return;
1533 }
1534 }
1535
1536 if (httpssvc_metrics_) {
1537 if (transaction_info.type == DnsQueryType::HTTPS) {
1538 const std::vector<bool>* record_compatibility =
1539 results.https_record_compatibility();
1540 CHECK(record_compatibility);
1541 httpssvc_metrics_->SaveForHttps(rcode_for_httpssvc,
1542 *record_compatibility, elapsed_time);
1543 } else {
1544 httpssvc_metrics_->SaveForAddressQuery(elapsed_time,
1545 rcode_for_httpssvc);
1546 }
1547 }
1548
1549 // Trigger HTTP->HTTPS upgrade if an HTTPS record is received for an "http"
1550 // or "ws" request.
1551 if (transaction_info.type == DnsQueryType::HTTPS &&
1552 ShouldTriggerHttpToHttpsUpgrade(results)) {
1553 // Disallow fallback. Otherwise DNS could be reattempted without HTTPS
1554 // queries, and that would hide this error instead of triggering upgrade.
1555 OnFailure(ERR_DNS_NAME_HTTPS_ONLY, /*allow_fallback=*/false,
1556 results.GetOptionalTtl(), transaction_info.type);
1557 return;
1558 }
1559
1560 HideMetadataResultsIfNotDesired(results);
1561
1562 switch (transaction_info.type) {
1563 case DnsQueryType::A:
1564 a_record_end_time_ = now;
1565 if (!aaaa_record_end_time_.is_null()) {
1566 RecordResolveTimeDiff("AAAABeforeA", task_start_time_,
1567 aaaa_record_end_time_, a_record_end_time_);
1568 }
1569 break;
1570 case DnsQueryType::AAAA:
1571 aaaa_record_end_time_ = now;
1572 if (!a_record_end_time_.is_null()) {
1573 RecordResolveTimeDiff("ABeforeAAAA", task_start_time_,
1574 a_record_end_time_, aaaa_record_end_time_);
1575 }
1576 break;
1577 case DnsQueryType::HTTPS: {
1578 base::TimeTicks first_address_end_time =
1579 std::min(a_record_end_time_, aaaa_record_end_time_);
1580 if (!first_address_end_time.is_null()) {
1581 RecordResolveTimeDiff("AddressRecordBeforeHTTPS", task_start_time_,
1582 first_address_end_time, now);
1583 }
1584 break;
1585 }
1586 default:
1587 break;
1588 }
1589
1590 // Merge results with saved results from previous transactions.
1591 if (saved_results_) {
1592 // If saved result is a deferred failure, try again to complete with that
1593 // failure.
1594 if (saved_results_is_failure_) {
1595 OnFailure(saved_results_.value().error(), /*allow_fallback=*/true,
1596 saved_results_.value().GetOptionalTtl());
1597 return;
1598 }
1599
1600 switch (transaction_info.type) {
1601 case DnsQueryType::A:
1602 // Canonical names from A results have lower priority than those
1603 // from AAAA results, so merge to the back.
1604 results = HostCache::Entry::MergeEntries(
1605 std::move(saved_results_).value(), std::move(results));
1606 break;
1607 case DnsQueryType::AAAA:
1608 // Canonical names from AAAA results take priority over those
1609 // from A results, so merge to the front.
1610 results = HostCache::Entry::MergeEntries(
1611 std::move(results), std::move(saved_results_).value());
1612 break;
1613 case DnsQueryType::HTTPS:
1614 // No particular importance to order.
1615 results = HostCache::Entry::MergeEntries(
1616 std::move(results), std::move(saved_results_).value());
1617 break;
1618 default:
1619 // Only expect address query types with multiple transactions.
1620 NOTREACHED();
1621 }
1622 }
1623
1624 saved_results_ = std::move(results);
1625 OnTransactionsFinished();
1626 }
1627
IsFatalTransactionFailure(int transaction_error,const TransactionInfo & transaction_info,const DnsResponse * response)1628 bool IsFatalTransactionFailure(int transaction_error,
1629 const TransactionInfo& transaction_info,
1630 const DnsResponse* response) {
1631 if (transaction_info.type != DnsQueryType::HTTPS) {
1632 DCHECK(transaction_info.error_behavior !=
1633 TransactionErrorBehavior::kFatalOrEmpty);
1634 return false;
1635 }
1636
1637 // These values are logged to UMA. Entries should not be renumbered and
1638 // numeric values should never be reused. Please keep in sync with
1639 // "DNS.SvcbHttpsTransactionError" in
1640 // src/tools/metrics/histograms/enums.xml.
1641 enum class HttpsTransactionError {
1642 kNoError = 0,
1643 kInsecureError = 1,
1644 kNonFatalError = 2,
1645 kFatalErrorDisabled = 3,
1646 kFatalErrorEnabled = 4,
1647 kMaxValue = kFatalErrorEnabled
1648 } error;
1649
1650 if (transaction_error == OK ||
1651 (transaction_error == ERR_NAME_NOT_RESOLVED && response &&
1652 response->IsValid())) {
1653 error = HttpsTransactionError::kNoError;
1654 } else if (!secure_) {
1655 // HTTPS failures are never fatal via insecure DNS.
1656 DCHECK(transaction_info.error_behavior !=
1657 TransactionErrorBehavior::kFatalOrEmpty);
1658 error = HttpsTransactionError::kInsecureError;
1659 } else if (transaction_error == ERR_DNS_SERVER_FAILED && response &&
1660 response->rcode() != dns_protocol::kRcodeSERVFAIL) {
1661 // For server failures, only SERVFAIL is fatal.
1662 error = HttpsTransactionError::kNonFatalError;
1663 } else if (features::kUseDnsHttpsSvcbEnforceSecureResponse.Get()) {
1664 DCHECK(transaction_info.error_behavior ==
1665 TransactionErrorBehavior::kFatalOrEmpty);
1666 error = HttpsTransactionError::kFatalErrorEnabled;
1667 } else {
1668 DCHECK(transaction_info.error_behavior !=
1669 TransactionErrorBehavior::kFatalOrEmpty);
1670 error = HttpsTransactionError::kFatalErrorDisabled;
1671 }
1672
1673 UMA_HISTOGRAM_ENUMERATION("Net.DNS.DnsTask.SvcbHttpsTransactionError",
1674 error);
1675 return error == HttpsTransactionError::kFatalErrorEnabled;
1676 }
1677
1678 // Called on processing for one or more individual transaction being
1679 // completed/cancelled. Processes overall results if all transactions are
1680 // finished.
OnTransactionsFinished()1681 void OnTransactionsFinished() {
1682 if (!transactions_in_progress_.empty() || !transactions_needed_.empty()) {
1683 delegate_->OnIntermediateTransactionsComplete();
1684 MaybeStartTimeoutTimer();
1685 return;
1686 }
1687
1688 DCHECK(saved_results_.has_value());
1689 HostCache::Entry results = std::move(*saved_results_);
1690
1691 timeout_timer_.Stop();
1692
1693 absl::optional<std::vector<IPEndPoint>> ip_endpoints;
1694 ip_endpoints = base::OptionalFromPtr(results.ip_endpoints());
1695
1696 if (ip_endpoints.has_value()) {
1697 // If there are multiple addresses, and at least one is IPv6, need to
1698 // sort them.
1699 bool at_least_one_ipv6_address = base::ranges::any_of(
1700 ip_endpoints.value(),
1701 [](auto& e) { return e.GetFamily() == ADDRESS_FAMILY_IPV6; });
1702
1703 if (at_least_one_ipv6_address) {
1704 // Sort addresses if needed. Sort could complete synchronously.
1705 client_->GetAddressSorter()->Sort(
1706 ip_endpoints.value(),
1707 base::BindOnce(&DnsTask::OnSortComplete, AsWeakPtr(),
1708 tick_clock_->NowTicks(), std::move(results),
1709 secure_));
1710 return;
1711 }
1712 }
1713 OnSuccess(std::move(results));
1714 }
1715
OnSortComplete(base::TimeTicks sort_start_time,HostCache::Entry results,bool secure,bool success,std::vector<IPEndPoint> sorted)1716 void OnSortComplete(base::TimeTicks sort_start_time,
1717 HostCache::Entry results,
1718 bool secure,
1719 bool success,
1720 std::vector<IPEndPoint> sorted) {
1721 DCHECK(results.ip_endpoints());
1722 results.set_ip_endpoints(std::move(sorted));
1723
1724 if (!success) {
1725 OnFailure(ERR_DNS_SORT_ERROR, /*allow_fallback=*/true,
1726 results.GetOptionalTtl());
1727 return;
1728 }
1729
1730 // AddressSorter prunes unusable destinations.
1731 if ((!results.ip_endpoints() || results.ip_endpoints()->empty()) &&
1732 results.text_records().value_or(std::vector<std::string>()).empty() &&
1733 results.hostnames().value_or(std::vector<HostPortPair>()).empty()) {
1734 LOG(WARNING) << "Address list empty after RFC3484 sort";
1735 OnFailure(ERR_NAME_NOT_RESOLVED, /*allow_fallback=*/true,
1736 results.GetOptionalTtl());
1737 return;
1738 }
1739
1740 OnSuccess(std::move(results));
1741 }
1742
AnyPotentiallyFatalTransactionsRemain()1743 bool AnyPotentiallyFatalTransactionsRemain() {
1744 auto is_fatal_or_empty_error = [](TransactionErrorBehavior behavior) {
1745 return behavior == TransactionErrorBehavior::kFatalOrEmpty;
1746 };
1747
1748 return base::ranges::any_of(transactions_needed_, is_fatal_or_empty_error,
1749 &TransactionInfo::error_behavior) ||
1750 base::ranges::any_of(transactions_in_progress_,
1751 is_fatal_or_empty_error,
1752 &TransactionInfo::error_behavior);
1753 }
1754
CancelNonFatalTransactions()1755 void CancelNonFatalTransactions() {
1756 auto has_non_fatal_or_empty_error = [](const TransactionInfo& info) {
1757 return info.error_behavior != TransactionErrorBehavior::kFatalOrEmpty;
1758 };
1759
1760 base::EraseIf(transactions_needed_, has_non_fatal_or_empty_error);
1761 base::EraseIf(transactions_in_progress_, has_non_fatal_or_empty_error);
1762 }
1763
OnFailure(int net_error,bool allow_fallback,absl::optional<base::TimeDelta> ttl=absl::nullopt,absl::optional<DnsQueryType> failed_transaction_type=absl::nullopt)1764 void OnFailure(
1765 int net_error,
1766 bool allow_fallback,
1767 absl::optional<base::TimeDelta> ttl = absl::nullopt,
1768 absl::optional<DnsQueryType> failed_transaction_type = absl::nullopt) {
1769 if (httpssvc_metrics_ && failed_transaction_type.has_value() &&
1770 IsAddressType(failed_transaction_type.value())) {
1771 httpssvc_metrics_->SaveAddressQueryFailure();
1772 }
1773
1774 DCHECK_NE(OK, net_error);
1775 HostCache::Entry results(net_error, HostCache::Entry::SOURCE_UNKNOWN, ttl);
1776
1777 // On non-fatal errors, if any potentially fatal transactions remain, need
1778 // to defer ending the task in case any of those remaining transactions end
1779 // with a fatal failure.
1780 if (allow_fallback && AnyPotentiallyFatalTransactionsRemain()) {
1781 saved_results_ = std::move(results);
1782 saved_results_is_failure_ = true;
1783
1784 CancelNonFatalTransactions();
1785 OnTransactionsFinished();
1786 return;
1787 }
1788
1789 net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_DNS_TASK, [&] {
1790 return NetLogDnsTaskFailedParams(net_error, failed_transaction_type, ttl,
1791 base::OptionalToPtr(saved_results_));
1792 });
1793
1794 // Expect this to result in destroying `this` and thus cancelling any
1795 // remaining transactions.
1796 delegate_->OnDnsTaskComplete(task_start_time_, allow_fallback,
1797 std::move(results), secure_);
1798 }
1799
OnSuccess(HostCache::Entry results)1800 void OnSuccess(HostCache::Entry results) {
1801 net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_DNS_TASK,
1802 [&] { return NetLogResults(results); });
1803 delegate_->OnDnsTaskComplete(task_start_time_, /*allow_fallback=*/true,
1804 std::move(results), secure_);
1805 }
1806
1807 // Returns whether any transactions left to finish are of a transaction type
1808 // in `types`. Used for logging and starting the timeout timer (see
1809 // MaybeStartTimeoutTimer()).
AnyOfTypeTransactionsRemain(std::initializer_list<DnsQueryType> types) const1810 bool AnyOfTypeTransactionsRemain(
1811 std::initializer_list<DnsQueryType> types) const {
1812 // Should only be called if some transactions are still running or waiting
1813 // to run.
1814 DCHECK(!transactions_needed_.empty() || !transactions_in_progress_.empty());
1815
1816 // Check running transactions.
1817 if (base::ranges::find_first_of(transactions_in_progress_, types,
1818 /*pred=*/{},
1819 /*proj1=*/&TransactionInfo::type) !=
1820 transactions_in_progress_.end()) {
1821 return true;
1822 }
1823
1824 // Check queued transactions, in case it ever becomes possible to get here
1825 // without the transactions being started first.
1826 return base::ranges::find_first_of(transactions_needed_, types, /*pred=*/{},
1827 /*proj1=*/&TransactionInfo::type) !=
1828 transactions_needed_.end();
1829 }
1830
MaybeStartTimeoutTimer()1831 void MaybeStartTimeoutTimer() {
1832 // Should only be called if some transactions are still running or waiting
1833 // to run.
1834 DCHECK(!transactions_in_progress_.empty() || !transactions_needed_.empty());
1835
1836 // Timer already running.
1837 if (timeout_timer_.IsRunning())
1838 return;
1839
1840 // Always wait for address transactions.
1841 if (AnyOfTypeTransactionsRemain({DnsQueryType::A, DnsQueryType::AAAA}))
1842 return;
1843
1844 base::TimeDelta timeout_max;
1845 int extra_time_percent = 0;
1846 base::TimeDelta timeout_min;
1847
1848 if (AnyOfTypeTransactionsRemain({DnsQueryType::HTTPS})) {
1849 DCHECK(https_svcb_options_.enable);
1850
1851 if (secure_) {
1852 timeout_max = https_svcb_options_.secure_extra_time_max;
1853 extra_time_percent = https_svcb_options_.secure_extra_time_percent;
1854 timeout_min = https_svcb_options_.secure_extra_time_min;
1855 } else {
1856 timeout_max = https_svcb_options_.insecure_extra_time_max;
1857 extra_time_percent = https_svcb_options_.insecure_extra_time_percent;
1858 timeout_min = https_svcb_options_.insecure_extra_time_min;
1859 }
1860
1861 // Skip timeout for secure requests if the timeout would be a fatal
1862 // failure.
1863 if (secure_ && features::kUseDnsHttpsSvcbEnforceSecureResponse.Get()) {
1864 timeout_max = base::TimeDelta();
1865 extra_time_percent = 0;
1866 timeout_min = base::TimeDelta();
1867 }
1868 } else {
1869 // Unhandled supplemental type.
1870 NOTREACHED();
1871 }
1872
1873 base::TimeDelta timeout;
1874 if (extra_time_percent > 0) {
1875 base::TimeDelta total_time_for_other_transactions =
1876 tick_clock_->NowTicks() - task_start_time_;
1877 timeout = total_time_for_other_transactions * extra_time_percent / 100;
1878 // Use at least 1ms to ensure timeout doesn't occur immediately in tests.
1879 timeout = std::max(timeout, base::Milliseconds(1));
1880
1881 if (!timeout_max.is_zero())
1882 timeout = std::min(timeout, timeout_max);
1883 if (!timeout_min.is_zero())
1884 timeout = std::max(timeout, timeout_min);
1885 } else {
1886 // If no relative timeout, use a non-zero min/max as timeout. If both are
1887 // non-zero, that's not very sensible, but arbitrarily take the higher
1888 // timeout.
1889 timeout = std::max(timeout_min, timeout_max);
1890 }
1891
1892 if (!timeout.is_zero())
1893 timeout_timer_.Start(
1894 FROM_HERE, timeout,
1895 base::BindOnce(&DnsTask::OnTimeout, base::Unretained(this)));
1896 }
1897
ShouldTriggerHttpToHttpsUpgrade(const HostCache::Entry & results)1898 bool ShouldTriggerHttpToHttpsUpgrade(const HostCache::Entry& results) {
1899 // Upgrade if at least one HTTPS record was compatible, and the host uses an
1900 // upgradable scheme.
1901 return results.https_record_compatibility() &&
1902 base::ranges::any_of(*results.https_record_compatibility(),
1903 base::identity()) &&
1904 (GetScheme(host_) == url::kHttpScheme ||
1905 GetScheme(host_) == url::kWsScheme);
1906 }
1907
1908 // Only keep metadata results (from HTTPS records) for appropriate schemes.
1909 // This is needed to ensure metadata isn't included in results if the current
1910 // Feature setup allows querying HTTPS for http:// or ws:// but doesn't enable
1911 // scheme upgrade to error out on finding an HTTPS record.
1912 //
1913 // TODO(crbug.com/1206455): Remove once all requests that query HTTPS will
1914 // either allow metadata results or error out.
HideMetadataResultsIfNotDesired(HostCache::Entry & results)1915 void HideMetadataResultsIfNotDesired(HostCache::Entry& results) {
1916 if (GetScheme(host_) == url::kHttpsScheme ||
1917 GetScheme(host_) == url::kWssScheme) {
1918 return;
1919 }
1920
1921 results.ClearMetadatas();
1922 }
1923
1924 const raw_ptr<DnsClient> client_;
1925
1926 absl::variant<url::SchemeHostPort, std::string> host_;
1927
1928 base::SafeRef<ResolveContext> resolve_context_;
1929
1930 // Whether lookups in this DnsTask should occur using DoH or plaintext.
1931 const bool secure_;
1932 const SecureDnsMode secure_dns_mode_;
1933
1934 // The listener to the results of this DnsTask.
1935 const raw_ptr<Delegate> delegate_;
1936 const NetLogWithSource net_log_;
1937
1938 bool any_transaction_started_ = false;
1939 base::circular_deque<TransactionInfo> transactions_needed_;
1940 // Active transactions have iterators pointing to their entry in this set, so
1941 // individual entries should not be modified or removed until completion or
1942 // cancellation of the transaction.
1943 std::set<TransactionInfo> transactions_in_progress_;
1944
1945 // For histograms.
1946 base::TimeTicks a_record_end_time_;
1947 base::TimeTicks aaaa_record_end_time_;
1948
1949 absl::optional<HostCache::Entry> saved_results_;
1950 bool saved_results_is_failure_ = false;
1951
1952 const raw_ptr<const base::TickClock> tick_clock_;
1953 base::TimeTicks task_start_time_;
1954
1955 absl::optional<HttpssvcMetrics> httpssvc_metrics_;
1956
1957 // Timer for task timeout. Generally started after completion of address
1958 // transactions to allow aborting experimental or supplemental transactions.
1959 base::OneShotTimer timeout_timer_;
1960
1961 // If true, there are still significant fallback options available if this
1962 // task completes unsuccessfully. Used as a signal that underlying
1963 // transactions should timeout more quickly.
1964 bool fallback_available_;
1965
1966 const HostResolver::HttpsSvcbOptions https_svcb_options_;
1967 };
1968
1969 //-----------------------------------------------------------------------------
1970
1971 // Aggregates all Requests for the same Key. Dispatched via
1972 // PrioritizedDispatcher.
1973 class HostResolverManager::Job : public PrioritizedDispatcher::Job,
1974 public HostResolverManager::DnsTask::Delegate {
1975 public:
1976 // Creates new job for |key| where |request_net_log| is bound to the
1977 // request that spawned it.
Job(const base::WeakPtr<HostResolverManager> & resolver,JobKey key,ResolveHostParameters::CacheUsage cache_usage,HostCache * host_cache,std::deque<TaskType> tasks,RequestPriority priority,const NetLogWithSource & source_net_log,const base::TickClock * tick_clock,const HostResolver::HttpsSvcbOptions & https_svcb_options)1978 Job(const base::WeakPtr<HostResolverManager>& resolver,
1979 JobKey key,
1980 ResolveHostParameters::CacheUsage cache_usage,
1981 HostCache* host_cache,
1982 std::deque<TaskType> tasks,
1983 RequestPriority priority,
1984 const NetLogWithSource& source_net_log,
1985 const base::TickClock* tick_clock,
1986 const HostResolver::HttpsSvcbOptions& https_svcb_options)
1987 : resolver_(resolver),
1988 key_(std::move(key)),
1989 cache_usage_(cache_usage),
1990 host_cache_(host_cache),
1991 tasks_(tasks),
1992 priority_tracker_(priority),
1993 tick_clock_(tick_clock),
1994 https_svcb_options_(https_svcb_options),
1995 net_log_(
1996 NetLogWithSource::Make(source_net_log.net_log(),
1997 NetLogSourceType::HOST_RESOLVER_IMPL_JOB)) {
1998 source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_CREATE_JOB);
1999
2000 net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB, [&] {
2001 return NetLogJobCreationParams(source_net_log.source());
2002 });
2003 }
2004
~Job()2005 ~Job() override {
2006 bool was_queued = is_queued();
2007 bool was_running = is_running();
2008 // Clean up now for nice NetLog.
2009 Finish();
2010 if (was_running) {
2011 // This Job was destroyed while still in flight.
2012 net_log_.EndEventWithNetErrorCode(
2013 NetLogEventType::HOST_RESOLVER_MANAGER_JOB, ERR_ABORTED);
2014 } else if (was_queued) {
2015 // Job was cancelled before it could run.
2016 // TODO(szym): is there any benefit in having this distinction?
2017 net_log_.AddEvent(NetLogEventType::CANCELLED);
2018 net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB);
2019 }
2020 // else CompleteRequests logged EndEvent.
2021 while (!requests_.empty()) {
2022 // Log any remaining Requests as cancelled.
2023 RequestImpl* req = requests_.head()->value();
2024 req->RemoveFromList();
2025 CHECK(key_ == req->GetJobKey());
2026 req->OnJobCancelled(key_);
2027 }
2028 }
2029
2030 // Add this job to the dispatcher. If "at_head" is true, adds at the front
2031 // of the queue.
Schedule(bool at_head)2032 void Schedule(bool at_head) {
2033 DCHECK(!is_queued());
2034 PrioritizedDispatcher::Handle handle;
2035 DCHECK(dispatched_);
2036 if (!at_head) {
2037 handle = resolver_->dispatcher_->Add(this, priority());
2038 } else {
2039 handle = resolver_->dispatcher_->AddAtHead(this, priority());
2040 }
2041 // The dispatcher could have started |this| in the above call to Add, which
2042 // could have called Schedule again. In that case |handle| will be null,
2043 // but |handle_| may have been set by the other nested call to Schedule.
2044 if (!handle.is_null()) {
2045 DCHECK(handle_.is_null());
2046 handle_ = handle;
2047 }
2048 }
2049
AddRequest(RequestImpl * request)2050 void AddRequest(RequestImpl* request) {
2051 // Job currently assumes a 1:1 correspondence between ResolveContext and
2052 // HostCache. Since the ResolveContext is part of the JobKey, any request
2053 // added to any existing Job should share the same HostCache.
2054 DCHECK_EQ(host_cache_, request->host_cache());
2055 // TODO(crbug.com/1206799): Check equality of whole host once Jobs are
2056 // separated by scheme/port.
2057 DCHECK_EQ(GetHostname(key_.host),
2058 request->request_host().GetHostnameWithoutBrackets());
2059
2060 request->AssignJob(weak_ptr_factory_.GetSafeRef());
2061
2062 priority_tracker_.Add(request->priority());
2063
2064 request->source_net_log().AddEventReferencingSource(
2065 NetLogEventType::HOST_RESOLVER_MANAGER_JOB_ATTACH, net_log_.source());
2066
2067 net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_REQUEST_ATTACH,
2068 [&] {
2069 return NetLogJobAttachParams(
2070 request->source_net_log().source(), priority());
2071 });
2072
2073 if (!request->parameters().is_speculative)
2074 had_non_speculative_request_ = true;
2075
2076 requests_.Append(request);
2077
2078 UpdatePriority();
2079 }
2080
ChangeRequestPriority(RequestImpl * req,RequestPriority priority)2081 void ChangeRequestPriority(RequestImpl* req, RequestPriority priority) {
2082 // TODO(crbug.com/1206799): Check equality of whole host once Jobs are
2083 // separated by scheme/port.
2084 DCHECK_EQ(GetHostname(key_.host),
2085 req->request_host().GetHostnameWithoutBrackets());
2086
2087 priority_tracker_.Remove(req->priority());
2088 req->set_priority(priority);
2089 priority_tracker_.Add(req->priority());
2090 UpdatePriority();
2091 }
2092
2093 // Detach cancelled request. If it was the last active Request, also finishes
2094 // this Job.
CancelRequest(RequestImpl * request)2095 void CancelRequest(RequestImpl* request) {
2096 // TODO(crbug.com/1206799): Check equality of whole host once Jobs are
2097 // separated by scheme/port.
2098 DCHECK_EQ(GetHostname(key_.host),
2099 request->request_host().GetHostnameWithoutBrackets());
2100 DCHECK(!requests_.empty());
2101
2102 priority_tracker_.Remove(request->priority());
2103 net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_REQUEST_DETACH,
2104 [&] {
2105 return NetLogJobAttachParams(
2106 request->source_net_log().source(), priority());
2107 });
2108
2109 if (num_active_requests() > 0) {
2110 UpdatePriority();
2111 request->RemoveFromList();
2112 } else {
2113 // If we were called from a Request's callback within CompleteRequests,
2114 // that Request could not have been cancelled, so num_active_requests()
2115 // could not be 0. Therefore, we are not in CompleteRequests().
2116 CompleteRequestsWithError(ERR_DNS_REQUEST_CANCELLED,
2117 /*task_type=*/absl::nullopt);
2118 }
2119 }
2120
2121 // Called from AbortJobsWithoutTargetNetwork(). Completes all requests and
2122 // destroys the job. This currently assumes the abort is due to a network
2123 // change.
2124 // TODO This should not delete |this|.
Abort()2125 void Abort() {
2126 CompleteRequestsWithError(ERR_NETWORK_CHANGED, /*task_type=*/absl::nullopt);
2127 }
2128
2129 // Gets a closure that will abort an insecure DnsTask (see
2130 // AbortInsecureDnsTask()) iff |this| is still valid. Useful if aborting a
2131 // list of Jobs as some may be cancelled while aborting others.
GetAbortInsecureDnsTaskClosure(int error,bool fallback_only)2132 base::OnceClosure GetAbortInsecureDnsTaskClosure(int error,
2133 bool fallback_only) {
2134 return base::BindOnce(&Job::AbortInsecureDnsTask,
2135 weak_ptr_factory_.GetWeakPtr(), error, fallback_only);
2136 }
2137
2138 // Aborts or removes any current/future insecure DnsTasks if a
2139 // HostResolverSystemTask is available for fallback. If no fallback is
2140 // available and |fallback_only| is false, a job that is currently running an
2141 // insecure DnsTask will be completed with |error|.
AbortInsecureDnsTask(int error,bool fallback_only)2142 void AbortInsecureDnsTask(int error, bool fallback_only) {
2143 bool has_system_fallback = base::Contains(tasks_, TaskType::SYSTEM);
2144 if (has_system_fallback) {
2145 for (auto it = tasks_.begin(); it != tasks_.end();) {
2146 if (*it == TaskType::DNS)
2147 it = tasks_.erase(it);
2148 else
2149 ++it;
2150 }
2151 }
2152
2153 if (dns_task_ && !dns_task_->secure()) {
2154 if (has_system_fallback) {
2155 KillDnsTask();
2156 dns_task_error_ = OK;
2157 RunNextTask();
2158 } else if (!fallback_only) {
2159 CompleteRequestsWithError(error, /*task_type=*/absl::nullopt);
2160 }
2161 }
2162 }
2163
2164 // Called by HostResolverManager when this job is evicted due to queue
2165 // overflow. Completes all requests and destroys the job. The job could have
2166 // waiting requests that will receive completion callbacks, so cleanup
2167 // asynchronously to avoid reentrancy.
OnEvicted()2168 void OnEvicted() {
2169 DCHECK(!is_running());
2170 DCHECK(is_queued());
2171 handle_.Reset();
2172
2173 net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_EVICTED);
2174
2175 // This signals to CompleteRequests that parts of this job never ran.
2176 // Job must be saved in |resolver_| to be completed asynchronously.
2177 // Otherwise the job will be destroyed with requests silently cancelled
2178 // before completion runs.
2179 DCHECK(self_iterator_);
2180 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
2181 FROM_HERE, base::BindOnce(&Job::CompleteRequestsWithError,
2182 weak_ptr_factory_.GetWeakPtr(),
2183 ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
2184 /*task_type=*/absl::nullopt));
2185 }
2186
2187 // Attempts to serve the job from HOSTS. Returns true if succeeded and
2188 // this Job was destroyed.
ServeFromHosts()2189 bool ServeFromHosts() {
2190 DCHECK_GT(num_active_requests(), 0u);
2191 absl::optional<HostCache::Entry> results = resolver_->ServeFromHosts(
2192 GetHostname(key_.host), key_.query_types,
2193 key_.flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6, tasks_);
2194 if (results) {
2195 // This will destroy the Job.
2196 CompleteRequests(results.value(), base::TimeDelta(),
2197 true /* allow_cache */, true /* secure */,
2198 TaskType::HOSTS);
2199 return true;
2200 }
2201 return false;
2202 }
2203
OnAddedToJobMap(JobMap::iterator iterator)2204 void OnAddedToJobMap(JobMap::iterator iterator) {
2205 DCHECK(!self_iterator_);
2206 DCHECK(iterator != resolver_->jobs_.end());
2207 self_iterator_ = iterator;
2208 }
2209
OnRemovedFromJobMap()2210 void OnRemovedFromJobMap() {
2211 DCHECK(self_iterator_);
2212 self_iterator_ = absl::nullopt;
2213 }
2214
RunNextTask()2215 void RunNextTask() {
2216 // If there are no tasks left to try, cache any stored results and complete
2217 // the request with the last stored result. All stored results should be
2218 // errors.
2219 if (tasks_.empty()) {
2220 // If there are no stored results, complete with an error.
2221 if (completion_results_.size() == 0) {
2222 CompleteRequestsWithError(ERR_NAME_NOT_RESOLVED,
2223 /*task_type=*/absl::nullopt);
2224 return;
2225 }
2226
2227 // Cache all but the last result here. The last result will be cached
2228 // as part of CompleteRequests.
2229 for (size_t i = 0; i < completion_results_.size() - 1; ++i) {
2230 const auto& result = completion_results_[i];
2231 DCHECK_NE(OK, result.entry.error());
2232 MaybeCacheResult(result.entry, result.ttl, result.secure);
2233 }
2234 const auto& last_result = completion_results_.back();
2235 DCHECK_NE(OK, last_result.entry.error());
2236 CompleteRequests(
2237 last_result.entry, last_result.ttl, true /* allow_cache */,
2238 last_result.secure,
2239 last_result.secure ? TaskType::SECURE_DNS : TaskType::DNS);
2240 return;
2241 }
2242
2243 TaskType next_task = tasks_.front();
2244
2245 // Schedule insecure DnsTasks and HostResolverSystemTasks with the
2246 // dispatcher.
2247 if (!dispatched_ &&
2248 (next_task == TaskType::DNS || next_task == TaskType::SYSTEM ||
2249 next_task == TaskType::MDNS)) {
2250 dispatched_ = true;
2251 job_running_ = false;
2252 Schedule(false);
2253 DCHECK(is_running() || is_queued());
2254
2255 // Check for queue overflow.
2256 PrioritizedDispatcher& dispatcher = *resolver_->dispatcher_;
2257 if (dispatcher.num_queued_jobs() > resolver_->max_queued_jobs_) {
2258 Job* evicted = static_cast<Job*>(dispatcher.EvictOldestLowest());
2259 DCHECK(evicted);
2260 evicted->OnEvicted();
2261 }
2262 return;
2263 }
2264
2265 if (start_time_ == base::TimeTicks()) {
2266 net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_STARTED);
2267 start_time_ = tick_clock_->NowTicks();
2268 }
2269 tasks_.pop_front();
2270 job_running_ = true;
2271
2272 switch (next_task) {
2273 case TaskType::SYSTEM:
2274 StartSystemTask();
2275 break;
2276 case TaskType::DNS:
2277 StartDnsTask(false /* secure */);
2278 break;
2279 case TaskType::SECURE_DNS:
2280 StartDnsTask(true /* secure */);
2281 break;
2282 case TaskType::MDNS:
2283 StartMdnsTask();
2284 break;
2285 case TaskType::INSECURE_CACHE_LOOKUP:
2286 InsecureCacheLookup();
2287 break;
2288 case TaskType::NAT64:
2289 StartNat64Task();
2290 break;
2291 case TaskType::SECURE_CACHE_LOOKUP:
2292 case TaskType::CACHE_LOOKUP:
2293 case TaskType::CONFIG_PRESET:
2294 case TaskType::HOSTS:
2295 // These task types should have been handled synchronously in
2296 // ResolveLocally() prior to Job creation.
2297 NOTREACHED();
2298 break;
2299 }
2300 }
2301
key() const2302 const JobKey& key() const { return key_; }
2303
is_queued() const2304 bool is_queued() const { return !handle_.is_null(); }
2305
is_running() const2306 bool is_running() const { return job_running_; }
2307
HasTargetNetwork() const2308 bool HasTargetNetwork() const {
2309 return key_.GetTargetNetwork() != handles::kInvalidNetworkHandle;
2310 }
2311
2312 private:
NetLogJobCreationParams(const NetLogSource & source)2313 base::Value::Dict NetLogJobCreationParams(const NetLogSource& source) {
2314 base::Value::Dict dict;
2315 source.AddToEventParameters(dict);
2316 dict.Set("host", ToLogStringValue(key_.host));
2317 base::Value::List query_types_list;
2318 for (DnsQueryType query_type : key_.query_types)
2319 query_types_list.Append(kDnsQueryTypes.at(query_type));
2320 dict.Set("dns_query_types", std::move(query_types_list));
2321 dict.Set("secure_dns_mode", base::strict_cast<int>(key_.secure_dns_mode));
2322 dict.Set("network_anonymization_key",
2323 key_.network_anonymization_key.ToDebugString());
2324 return dict;
2325 }
2326
Finish()2327 void Finish() {
2328 if (is_running()) {
2329 // Clean up but don't run any callbacks.
2330 system_task_ = nullptr;
2331 KillDnsTask();
2332 mdns_task_ = nullptr;
2333 job_running_ = false;
2334
2335 if (dispatched_) {
2336 // Job should only ever occupy one slot after any tasks that may have
2337 // required additional slots, e.g. DnsTask, have been killed, and
2338 // additional slots are expected to be vacated as part of killing the
2339 // task.
2340 DCHECK_EQ(1, num_occupied_job_slots_);
2341 if (resolver_)
2342 resolver_->dispatcher_->OnJobFinished();
2343 num_occupied_job_slots_ = 0;
2344 }
2345 } else if (is_queued()) {
2346 DCHECK(dispatched_);
2347 if (resolver_)
2348 resolver_->dispatcher_->Cancel(handle_);
2349 handle_.Reset();
2350 }
2351 }
2352
KillDnsTask()2353 void KillDnsTask() {
2354 if (dns_task_) {
2355 if (dispatched_) {
2356 while (num_occupied_job_slots_ > 1 || is_queued()) {
2357 ReduceByOneJobSlot();
2358 }
2359 }
2360 dns_task_.reset();
2361 }
2362 }
2363
2364 // Reduce the number of job slots occupied and queued in the dispatcher by
2365 // one. If the next Job slot is queued in the dispatcher, cancels the queued
2366 // job. Otherwise, the next Job has been started by the PrioritizedDispatcher,
2367 // so signals it is complete.
ReduceByOneJobSlot()2368 void ReduceByOneJobSlot() {
2369 DCHECK_GE(num_occupied_job_slots_, 1);
2370 DCHECK(dispatched_);
2371 if (is_queued()) {
2372 if (resolver_)
2373 resolver_->dispatcher_->Cancel(handle_);
2374 handle_.Reset();
2375 } else if (num_occupied_job_slots_ > 1) {
2376 if (resolver_)
2377 resolver_->dispatcher_->OnJobFinished();
2378 --num_occupied_job_slots_;
2379 } else {
2380 NOTREACHED();
2381 }
2382 }
2383
UpdatePriority()2384 void UpdatePriority() {
2385 if (is_queued())
2386 handle_ = resolver_->dispatcher_->ChangePriority(handle_, priority());
2387 }
2388
2389 // PrioritizedDispatcher::Job:
Start()2390 void Start() override {
2391 handle_.Reset();
2392 ++num_occupied_job_slots_;
2393
2394 if (num_occupied_job_slots_ >= 2) {
2395 if (!dns_task_) {
2396 resolver_->dispatcher_->OnJobFinished();
2397 return;
2398 }
2399 StartNextDnsTransaction();
2400 DCHECK_EQ(num_occupied_job_slots_,
2401 dns_task_->num_transactions_in_progress());
2402 if (dns_task_->num_additional_transactions_needed() >= 1) {
2403 Schedule(true);
2404 }
2405 return;
2406 }
2407
2408 DCHECK(!is_running());
2409 DCHECK(!tasks_.empty());
2410 RunNextTask();
2411 // Caution: Job::Start must not complete synchronously.
2412 }
2413
2414 // TODO(szym): Since DnsTransaction does not consume threads, we can increase
2415 // the limits on |dispatcher_|. But in order to keep the number of
2416 // ThreadPool threads low, we will need to use an "inner"
2417 // PrioritizedDispatcher with tighter limits.
StartSystemTask()2418 void StartSystemTask() {
2419 DCHECK(dispatched_);
2420 DCHECK_EQ(1, num_occupied_job_slots_);
2421 DCHECK(HasAddressType(key_.query_types));
2422
2423 system_task_ = HostResolverSystemTask::Create(
2424 std::string(GetHostname(key_.host)),
2425 HostResolver::DnsQueryTypeSetToAddressFamily(key_.query_types),
2426 key_.flags, resolver_->host_resolver_system_params_, net_log_,
2427 key_.GetTargetNetwork());
2428
2429 // Start() could be called from within Resolve(), hence it must NOT directly
2430 // call OnSystemTaskComplete, for example, on synchronous failure.
2431 system_task_->Start(base::BindOnce(&Job::OnSystemTaskComplete,
2432 base::Unretained(this),
2433 tick_clock_->NowTicks()));
2434 }
2435
2436 // Called by HostResolverSystemTask when it completes.
OnSystemTaskComplete(base::TimeTicks start_time,const AddressList & addr_list,int,int net_error)2437 void OnSystemTaskComplete(base::TimeTicks start_time,
2438 const AddressList& addr_list,
2439 int /*os_error*/,
2440 int net_error) {
2441 DCHECK(system_task_);
2442
2443 base::TimeDelta duration = tick_clock_->NowTicks() - start_time;
2444 if (net_error == OK)
2445 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.SystemTask.SuccessTime", duration);
2446 else
2447 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.SystemTask.FailureTime", duration);
2448
2449 if (dns_task_error_ != OK && net_error == OK) {
2450 // This HostResolverSystemTask was a fallback resolution after a failed
2451 // insecure DnsTask.
2452 resolver_->OnFallbackResolve(dns_task_error_);
2453 }
2454
2455 if (ContainsIcannNameCollisionIp(addr_list.endpoints()))
2456 net_error = ERR_ICANN_NAME_COLLISION;
2457
2458 base::TimeDelta ttl = base::Seconds(kNegativeCacheEntryTTLSeconds);
2459 if (net_error == OK)
2460 ttl = base::Seconds(kCacheEntryTTLSeconds);
2461
2462 auto aliases = std::set<std::string>(addr_list.dns_aliases().begin(),
2463 addr_list.dns_aliases().end());
2464
2465 // Source unknown because the system resolver could have gotten it from a
2466 // hosts file, its own cache, a DNS lookup or somewhere else.
2467 // Don't store the |ttl| in cache since it's not obtained from the server.
2468 CompleteRequests(
2469 HostCache::Entry(
2470 net_error,
2471 net_error == OK ? addr_list.endpoints() : std::vector<IPEndPoint>(),
2472 std::move(aliases), HostCache::Entry::SOURCE_UNKNOWN),
2473 ttl, /*allow_cache=*/true, /*secure=*/false, TaskType::SYSTEM);
2474 }
2475
InsecureCacheLookup()2476 void InsecureCacheLookup() {
2477 // Insecure cache lookups for requests allowing stale results should have
2478 // occurred prior to Job creation.
2479 DCHECK(cache_usage_ != ResolveHostParameters::CacheUsage::STALE_ALLOWED);
2480 absl::optional<HostCache::EntryStaleness> stale_info;
2481 absl::optional<HostCache::Entry> resolved = resolver_->MaybeServeFromCache(
2482 host_cache_, key_.ToCacheKey(/*secure=*/false), cache_usage_,
2483 false /* ignore_secure */, net_log_, &stale_info);
2484
2485 if (resolved) {
2486 DCHECK(stale_info);
2487 DCHECK(!stale_info.value().is_stale());
2488 CompleteRequestsWithoutCache(resolved.value(), std::move(stale_info),
2489 TaskType::INSECURE_CACHE_LOOKUP);
2490 } else {
2491 RunNextTask();
2492 }
2493 }
2494
StartDnsTask(bool secure)2495 void StartDnsTask(bool secure) {
2496 DCHECK_EQ(secure, !dispatched_);
2497 DCHECK_EQ(dispatched_ ? 1 : 0, num_occupied_job_slots_);
2498 DCHECK(!resolver_->ShouldForceSystemResolverDueToTestOverride());
2499 // Need to create the task even if we're going to post a failure instead of
2500 // running it, as a "started" job needs a task to be properly cleaned up.
2501 dns_task_ = std::make_unique<DnsTask>(
2502 resolver_->dns_client_.get(), key_.host, key_.query_types,
2503 &*key_.resolve_context, secure, key_.secure_dns_mode, this, net_log_,
2504 tick_clock_, !tasks_.empty() /* fallback_available */,
2505 https_svcb_options_);
2506 dns_task_->StartNextTransaction();
2507 // Schedule a second transaction, if needed. DoH queries can bypass the
2508 // dispatcher and start all of their transactions immediately.
2509 if (secure) {
2510 while (dns_task_->num_additional_transactions_needed() >= 1)
2511 dns_task_->StartNextTransaction();
2512 DCHECK_EQ(dns_task_->num_additional_transactions_needed(), 0);
2513 } else if (dns_task_->num_additional_transactions_needed() >= 1) {
2514 Schedule(true);
2515 }
2516 }
2517
StartNextDnsTransaction()2518 void StartNextDnsTransaction() {
2519 DCHECK(dns_task_);
2520 DCHECK_EQ(dns_task_->secure(), !dispatched_);
2521 DCHECK(!dispatched_ || num_occupied_job_slots_ ==
2522 dns_task_->num_transactions_in_progress() + 1);
2523 DCHECK_GE(dns_task_->num_additional_transactions_needed(), 1);
2524 dns_task_->StartNextTransaction();
2525 }
2526
2527 // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
2528 // deleted before this callback. In this case dns_task is deleted as well,
2529 // so we use it as indicator whether Job is still valid.
OnDnsTaskFailure(const base::WeakPtr<DnsTask> & dns_task,base::TimeDelta duration,bool allow_fallback,const HostCache::Entry & failure_results,bool secure)2530 void OnDnsTaskFailure(const base::WeakPtr<DnsTask>& dns_task,
2531 base::TimeDelta duration,
2532 bool allow_fallback,
2533 const HostCache::Entry& failure_results,
2534 bool secure) {
2535 DCHECK_NE(OK, failure_results.error());
2536
2537 if (key_.secure_dns_mode == SecureDnsMode::kSecure) {
2538 DCHECK(secure);
2539 UMA_HISTOGRAM_LONG_TIMES_100(
2540 "Net.DNS.SecureDnsTask.DnsModeSecure.FailureTime", duration);
2541 } else if (key_.secure_dns_mode == SecureDnsMode::kAutomatic && secure) {
2542 UMA_HISTOGRAM_LONG_TIMES_100(
2543 "Net.DNS.SecureDnsTask.DnsModeAutomatic.FailureTime", duration);
2544 } else {
2545 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.InsecureDnsTask.FailureTime",
2546 duration);
2547 }
2548
2549 if (!dns_task)
2550 return;
2551
2552 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.Failure",
2553 total_transaction_time_queued_);
2554
2555 // If one of the fallback tasks doesn't complete the request, store a result
2556 // to use during request completion.
2557 base::TimeDelta ttl =
2558 failure_results.has_ttl() ? failure_results.ttl() : base::Seconds(0);
2559 completion_results_.push_back({failure_results, ttl, secure});
2560
2561 dns_task_error_ = failure_results.error();
2562 KillDnsTask();
2563
2564 if (!allow_fallback)
2565 tasks_.clear();
2566
2567 RunNextTask();
2568 }
2569
2570 // HostResolverManager::DnsTask::Delegate implementation:
2571
OnDnsTaskComplete(base::TimeTicks start_time,bool allow_fallback,HostCache::Entry results,bool secure)2572 void OnDnsTaskComplete(base::TimeTicks start_time,
2573 bool allow_fallback,
2574 HostCache::Entry results,
2575 bool secure) override {
2576 DCHECK(dns_task_);
2577
2578 // Tasks containing address queries are only considered successful overall
2579 // if they find address results. However, DnsTask may claim success if any
2580 // transaction, e.g. a supplemental HTTPS transaction, finds results.
2581 DCHECK(!key_.query_types.Has(DnsQueryType::UNSPECIFIED));
2582 if (HasAddressType(key_.query_types) && results.error() == OK &&
2583 (!results.ip_endpoints() || results.ip_endpoints()->empty())) {
2584 results.set_error(ERR_NAME_NOT_RESOLVED);
2585 }
2586
2587 base::TimeDelta duration = tick_clock_->NowTicks() - start_time;
2588 if (results.error() != OK) {
2589 OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, allow_fallback,
2590 results, secure);
2591 return;
2592 }
2593
2594 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.DnsTask.SuccessTime", duration);
2595
2596 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.Success",
2597 total_transaction_time_queued_);
2598
2599 // Reset the insecure DNS failure counter if an insecure DnsTask completed
2600 // successfully.
2601 if (!secure)
2602 resolver_->dns_client_->ClearInsecureFallbackFailures();
2603
2604 base::TimeDelta bounded_ttl =
2605 std::max(results.ttl(), base::Seconds(kMinimumTTLSeconds));
2606
2607 if ((results.ip_endpoints() &&
2608 ContainsIcannNameCollisionIp(*results.ip_endpoints()))) {
2609 CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION,
2610 secure ? TaskType::SECURE_DNS : TaskType::DNS);
2611 return;
2612 }
2613
2614 CompleteRequests(results, bounded_ttl, true /* allow_cache */, secure,
2615 secure ? TaskType::SECURE_DNS : TaskType::DNS);
2616 }
2617
OnIntermediateTransactionsComplete()2618 void OnIntermediateTransactionsComplete() override {
2619 if (dispatched_) {
2620 DCHECK_GE(num_occupied_job_slots_,
2621 dns_task_->num_transactions_in_progress());
2622 int unused_slots =
2623 num_occupied_job_slots_ - dns_task_->num_transactions_in_progress();
2624
2625 // Reuse vacated slots for any remaining transactions.
2626 while (unused_slots > 0 &&
2627 dns_task_->num_additional_transactions_needed() > 0) {
2628 dns_task_->StartNextTransaction();
2629 --unused_slots;
2630 }
2631
2632 // If all remaining transactions found a slot, no more needed from the
2633 // dispatcher.
2634 if (is_queued() && dns_task_->num_additional_transactions_needed() == 0) {
2635 resolver_->dispatcher_->Cancel(handle_);
2636 handle_.Reset();
2637 }
2638
2639 // Relinquish any remaining extra slots.
2640 while (unused_slots > 0) {
2641 ReduceByOneJobSlot();
2642 --unused_slots;
2643 }
2644 } else if (dns_task_->num_additional_transactions_needed() >= 1) {
2645 dns_task_->StartNextTransaction();
2646 }
2647 }
2648
AddTransactionTimeQueued(base::TimeDelta time_queued)2649 void AddTransactionTimeQueued(base::TimeDelta time_queued) override {
2650 total_transaction_time_queued_ += time_queued;
2651 }
2652
StartMdnsTask()2653 void StartMdnsTask() {
2654 // No flags are supported for MDNS except
2655 // HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 (which is not actually an
2656 // input flag).
2657 DCHECK_EQ(0, key_.flags & ~HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6);
2658
2659 MDnsClient* client = nullptr;
2660 int rv = resolver_->GetOrCreateMdnsClient(&client);
2661 mdns_task_ = std::make_unique<HostResolverMdnsTask>(
2662 client, std::string{GetHostname(key_.host)}, key_.query_types);
2663
2664 if (rv == OK) {
2665 mdns_task_->Start(
2666 base::BindOnce(&Job::OnMdnsTaskComplete, base::Unretained(this)));
2667 } else {
2668 // Could not create an mDNS client. Since we cannot complete synchronously
2669 // from here, post a failure without starting the task.
2670 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
2671 FROM_HERE, base::BindOnce(&Job::OnMdnsImmediateFailure,
2672 weak_ptr_factory_.GetWeakPtr(), rv));
2673 }
2674 }
2675
OnMdnsTaskComplete()2676 void OnMdnsTaskComplete() {
2677 DCHECK(mdns_task_);
2678 // TODO(crbug.com/846423): Consider adding MDNS-specific logging.
2679
2680 HostCache::Entry results = mdns_task_->GetResults();
2681
2682 if ((results.ip_endpoints() &&
2683 ContainsIcannNameCollisionIp(*results.ip_endpoints()))) {
2684 CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION, TaskType::MDNS);
2685 return;
2686 }
2687 // MDNS uses a separate cache, so skip saving result to cache.
2688 // TODO(crbug.com/926300): Consider merging caches.
2689 CompleteRequestsWithoutCache(results, absl::nullopt /* stale_info */,
2690 TaskType::MDNS);
2691 }
2692
OnMdnsImmediateFailure(int rv)2693 void OnMdnsImmediateFailure(int rv) {
2694 DCHECK(mdns_task_);
2695 DCHECK_NE(OK, rv);
2696
2697 CompleteRequestsWithError(rv, TaskType::MDNS);
2698 }
2699
StartNat64Task()2700 void StartNat64Task() {
2701 DCHECK(!nat64_task_);
2702 RequestImpl* req = requests_.head()->value();
2703 nat64_task_ = std::make_unique<HostResolverNat64Task>(
2704 std::string{GetHostname(key_.host)}, req->network_anonymization_key(),
2705 req->source_net_log(), req->resolve_context(), req->host_cache(),
2706 resolver_);
2707 nat64_task_->Start(base::BindOnce(&Job::OnNat64TaskComplete,
2708 weak_ptr_factory_.GetWeakPtr()));
2709 }
2710
OnNat64TaskComplete()2711 void OnNat64TaskComplete() {
2712 DCHECK(nat64_task_);
2713 HostCache::Entry results = nat64_task_->GetResults();
2714 CompleteRequestsWithoutCache(results, absl::nullopt /* stale_info */,
2715 TaskType::NAT64);
2716 }
2717
RecordJobHistograms(const HostCache::Entry & results,absl::optional<TaskType> task_type)2718 void RecordJobHistograms(const HostCache::Entry& results,
2719 absl::optional<TaskType> task_type) {
2720 int error = results.error();
2721 // Used in UMA_HISTOGRAM_ENUMERATION. Do not renumber entries or reuse
2722 // deprecated values.
2723 enum Category {
2724 RESOLVE_SUCCESS = 0,
2725 RESOLVE_FAIL = 1,
2726 RESOLVE_SPECULATIVE_SUCCESS = 2,
2727 RESOLVE_SPECULATIVE_FAIL = 3,
2728 RESOLVE_ABORT = 4,
2729 RESOLVE_SPECULATIVE_ABORT = 5,
2730 RESOLVE_MAX, // Bounding value.
2731 };
2732 Category category = RESOLVE_MAX; // Illegal value for later DCHECK only.
2733
2734 base::TimeDelta duration = tick_clock_->NowTicks() - start_time_;
2735 if (error == OK) {
2736 if (had_non_speculative_request_) {
2737 category = RESOLVE_SUCCESS;
2738 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime", duration);
2739 } else {
2740 category = RESOLVE_SPECULATIVE_SUCCESS;
2741 }
2742 } else if (error == ERR_NETWORK_CHANGED ||
2743 error == ERR_HOST_RESOLVER_QUEUE_TOO_LARGE) {
2744 category = had_non_speculative_request_ ? RESOLVE_ABORT
2745 : RESOLVE_SPECULATIVE_ABORT;
2746 } else {
2747 if (had_non_speculative_request_) {
2748 category = RESOLVE_FAIL;
2749 UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime", duration);
2750 } else {
2751 category = RESOLVE_SPECULATIVE_FAIL;
2752 }
2753 }
2754 DCHECK_LT(static_cast<int>(category),
2755 static_cast<int>(RESOLVE_MAX)); // Be sure it was set.
2756 UMA_HISTOGRAM_ENUMERATION("Net.DNS.ResolveCategory", category, RESOLVE_MAX);
2757
2758 if (category == RESOLVE_FAIL ||
2759 (start_time_ != base::TimeTicks() && category == RESOLVE_ABORT)) {
2760 if (duration < base::Milliseconds(10))
2761 base::UmaHistogramSparse("Net.DNS.ResolveError.Fast", std::abs(error));
2762 else
2763 base::UmaHistogramSparse("Net.DNS.ResolveError.Slow", std::abs(error));
2764 }
2765
2766 if (had_non_speculative_request_) {
2767 UmaHistogramMediumTimes(
2768 base::StringPrintf(
2769 "Net.DNS.SecureDnsMode.%s.ResolveTime",
2770 SecureDnsModeToString(key_.secure_dns_mode).c_str()),
2771 duration);
2772 }
2773
2774 if (error == OK) {
2775 DCHECK(task_type.has_value());
2776 // Record, for HTTPS-capable queries to a host known to serve HTTPS
2777 // records, whether the HTTPS record was successfully received.
2778 if (key_.query_types.Has(DnsQueryType::HTTPS) &&
2779 // Skip http- and ws-schemed hosts. Although they query HTTPS records,
2780 // successful queries are reported as errors, which would skew the
2781 // metrics.
2782 (GetScheme(key_.host) == url::kHttpsScheme ||
2783 GetScheme(key_.host) == url::kWssScheme) &&
2784 IsGoogleHostWithAlpnH3(GetHostname(key_.host))) {
2785 bool has_metadata =
2786 results.GetMetadatas() && !results.GetMetadatas()->empty();
2787 base::UmaHistogramExactLinear(
2788 "Net.DNS.H3SupportedGoogleHost.TaskTypeMetadataAvailability2",
2789 static_cast<int>(task_type.value()) * 2 + (has_metadata ? 1 : 0),
2790 (static_cast<int>(TaskType::kMaxValue) + 1) * 2);
2791 }
2792 }
2793 }
2794
MaybeCacheResult(const HostCache::Entry & results,base::TimeDelta ttl,bool secure)2795 void MaybeCacheResult(const HostCache::Entry& results,
2796 base::TimeDelta ttl,
2797 bool secure) {
2798 // If the request did not complete, don't cache it.
2799 if (!results.did_complete())
2800 return;
2801 resolver_->CacheResult(host_cache_, key_.ToCacheKey(secure), results, ttl);
2802 }
2803
2804 // Performs Job's last rites. Completes all Requests. Deletes this.
2805 //
2806 // If not |allow_cache|, result will not be stored in the host cache, even if
2807 // result would otherwise allow doing so. Update the key to reflect |secure|,
2808 // which indicates whether or not the result was obtained securely.
CompleteRequests(const HostCache::Entry & results,base::TimeDelta ttl,bool allow_cache,bool secure,absl::optional<TaskType> task_type)2809 void CompleteRequests(const HostCache::Entry& results,
2810 base::TimeDelta ttl,
2811 bool allow_cache,
2812 bool secure,
2813 absl::optional<TaskType> task_type) {
2814 CHECK(resolver_.get());
2815
2816 // This job must be removed from resolver's |jobs_| now to make room for a
2817 // new job with the same key in case one of the OnComplete callbacks decides
2818 // to spawn one. Consequently, if the job was owned by |jobs_|, the job
2819 // deletes itself when CompleteRequests is done.
2820 std::unique_ptr<Job> self_deleter;
2821 if (self_iterator_)
2822 self_deleter = resolver_->RemoveJob(self_iterator_.value());
2823
2824 Finish();
2825
2826 if (results.error() == ERR_DNS_REQUEST_CANCELLED) {
2827 net_log_.AddEvent(NetLogEventType::CANCELLED);
2828 net_log_.EndEventWithNetErrorCode(
2829 NetLogEventType::HOST_RESOLVER_MANAGER_JOB, OK);
2830 return;
2831 }
2832
2833 net_log_.EndEventWithNetErrorCode(
2834 NetLogEventType::HOST_RESOLVER_MANAGER_JOB, results.error());
2835
2836 // Handle all caching before completing requests as completing requests may
2837 // start new requests that rely on cached results.
2838 if (allow_cache)
2839 MaybeCacheResult(results, ttl, secure);
2840
2841 RecordJobHistograms(results, task_type);
2842
2843 // Complete all of the requests that were attached to the job and
2844 // detach them.
2845 while (!requests_.empty()) {
2846 RequestImpl* req = requests_.head()->value();
2847 req->RemoveFromList();
2848 CHECK(key_ == req->GetJobKey());
2849
2850 if (results.error() == OK && !req->parameters().is_speculative) {
2851 req->set_results(
2852 results.CopyWithDefaultPort(req->request_host().GetPort()));
2853 }
2854 req->OnJobCompleted(
2855 key_, results.error(),
2856 /*is_secure_network_error=*/secure && results.error() != OK);
2857
2858 // Check if the resolver was destroyed as a result of running the
2859 // callback. If it was, we could continue, but we choose to bail.
2860 if (!resolver_.get())
2861 return;
2862 }
2863
2864 // TODO(crbug.com/1200908): Call StartBootstrapFollowup() if any of the
2865 // requests have the Bootstrap policy. Note: A naive implementation could
2866 // cause an infinite loop if the bootstrap result has TTL=0.
2867 }
2868
CompleteRequestsWithoutCache(const HostCache::Entry & results,absl::optional<HostCache::EntryStaleness> stale_info,TaskType task_type)2869 void CompleteRequestsWithoutCache(
2870 const HostCache::Entry& results,
2871 absl::optional<HostCache::EntryStaleness> stale_info,
2872 TaskType task_type) {
2873 // Record the stale_info for all non-speculative requests, if it exists.
2874 if (stale_info) {
2875 for (auto* node = requests_.head(); node != requests_.end();
2876 node = node->next()) {
2877 if (!node->value()->parameters().is_speculative)
2878 node->value()->set_stale_info(stale_info.value());
2879 }
2880 }
2881 CompleteRequests(results, base::TimeDelta(), false /* allow_cache */,
2882 false /* secure */, task_type);
2883 }
2884
2885 // Convenience wrapper for CompleteRequests in case of failure.
CompleteRequestsWithError(int net_error,absl::optional<TaskType> task_type)2886 void CompleteRequestsWithError(int net_error,
2887 absl::optional<TaskType> task_type) {
2888 DCHECK_NE(OK, net_error);
2889 CompleteRequests(
2890 HostCache::Entry(net_error, HostCache::Entry::SOURCE_UNKNOWN),
2891 base::TimeDelta(), true /* allow_cache */, false /* secure */,
2892 task_type);
2893 }
2894
priority() const2895 RequestPriority priority() const override {
2896 return priority_tracker_.highest_priority();
2897 }
2898
2899 // Number of non-canceled requests in |requests_|.
num_active_requests() const2900 size_t num_active_requests() const { return priority_tracker_.total_count(); }
2901
2902 base::WeakPtr<HostResolverManager> resolver_;
2903
2904 const JobKey key_;
2905 const ResolveHostParameters::CacheUsage cache_usage_;
2906 // TODO(crbug.com/969847): Consider allowing requests within a single Job to
2907 // have different HostCaches.
2908 const raw_ptr<HostCache> host_cache_;
2909
2910 struct CompletionResult {
2911 const HostCache::Entry entry;
2912 base::TimeDelta ttl;
2913 bool secure;
2914 };
2915
2916 // Results to use in last-ditch attempt to complete request.
2917 std::vector<CompletionResult> completion_results_;
2918
2919 // The sequence of tasks to run in this Job. Tasks may be aborted and removed
2920 // from the sequence, but otherwise the tasks will run in order until a
2921 // successful result is found.
2922 std::deque<TaskType> tasks_;
2923
2924 // Whether the job is running.
2925 bool job_running_ = false;
2926
2927 // Tracks the highest priority across |requests_|.
2928 PriorityTracker priority_tracker_;
2929
2930 bool had_non_speculative_request_ = false;
2931
2932 // Number of slots occupied by this Job in |dispatcher_|. Should be 0 when
2933 // the job is not registered with any dispatcher.
2934 int num_occupied_job_slots_ = 0;
2935
2936 // True once this Job has been sent to `resolver_->dispatcher_`.
2937 bool dispatched_ = false;
2938
2939 // Result of DnsTask.
2940 int dns_task_error_ = OK;
2941
2942 raw_ptr<const base::TickClock> tick_clock_;
2943 base::TimeTicks start_time_;
2944
2945 HostResolver::HttpsSvcbOptions https_svcb_options_;
2946
2947 NetLogWithSource net_log_;
2948
2949 // Resolves the host using the system DNS resolver, which can be overridden
2950 // for tests.
2951 std::unique_ptr<HostResolverSystemTask> system_task_;
2952
2953 // Resolves the host using a DnsTransaction.
2954 std::unique_ptr<DnsTask> dns_task_;
2955
2956 // Resolves the host using MDnsClient.
2957 std::unique_ptr<HostResolverMdnsTask> mdns_task_;
2958
2959 // Perform NAT64 address synthesis to a given IPv4 literal.
2960 std::unique_ptr<HostResolverNat64Task> nat64_task_;
2961
2962 // All Requests waiting for the result of this Job. Some can be canceled.
2963 base::LinkedList<RequestImpl> requests_;
2964
2965 // A handle used for |dispatcher_|.
2966 PrioritizedDispatcher::Handle handle_;
2967
2968 // Iterator to |this| in the JobMap. |nullopt| if not owned by the JobMap.
2969 absl::optional<JobMap::iterator> self_iterator_;
2970
2971 base::TimeDelta total_transaction_time_queued_;
2972
2973 base::WeakPtrFactory<Job> weak_ptr_factory_{this};
2974 };
2975
2976 //-----------------------------------------------------------------------------
2977
HostResolverManager(const HostResolver::ManagerOptions & options,SystemDnsConfigChangeNotifier * system_dns_config_notifier,NetLog * net_log)2978 HostResolverManager::HostResolverManager(
2979 const HostResolver::ManagerOptions& options,
2980 SystemDnsConfigChangeNotifier* system_dns_config_notifier,
2981 NetLog* net_log)
2982 : HostResolverManager(PassKey(),
2983 options,
2984 system_dns_config_notifier,
2985 handles::kInvalidNetworkHandle,
2986 net_log) {}
2987
HostResolverManager(base::PassKey<HostResolverManager>,const HostResolver::ManagerOptions & options,SystemDnsConfigChangeNotifier * system_dns_config_notifier,handles::NetworkHandle target_network,NetLog * net_log)2988 HostResolverManager::HostResolverManager(
2989 base::PassKey<HostResolverManager>,
2990 const HostResolver::ManagerOptions& options,
2991 SystemDnsConfigChangeNotifier* system_dns_config_notifier,
2992 handles::NetworkHandle target_network,
2993 NetLog* net_log)
2994 : host_resolver_system_params_(nullptr, options.max_system_retry_attempts),
2995 net_log_(net_log),
2996 system_dns_config_notifier_(system_dns_config_notifier),
2997 target_network_(target_network),
2998 check_ipv6_on_wifi_(options.check_ipv6_on_wifi),
2999 tick_clock_(base::DefaultTickClock::GetInstance()),
3000 https_svcb_options_(
3001 options.https_svcb_options
3002 ? *options.https_svcb_options
3003 : HostResolver::HttpsSvcbOptions::FromFeatures()) {
3004 PrioritizedDispatcher::Limits job_limits = GetDispatcherLimits(options);
3005 dispatcher_ = std::make_unique<PrioritizedDispatcher>(job_limits);
3006 max_queued_jobs_ = job_limits.total_jobs * 100u;
3007
3008 DCHECK_GE(dispatcher_->num_priorities(), static_cast<size_t>(NUM_PRIORITIES));
3009
3010 #if BUILDFLAG(IS_WIN)
3011 EnsureWinsockInit();
3012 #endif
3013 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID)) || \
3014 BUILDFLAG(IS_FUCHSIA)
3015 RunLoopbackProbeJob();
3016 #endif
3017 // Network-bound HostResolverManagers don't need to act on network changes.
3018 if (!IsBoundToNetwork()) {
3019 NetworkChangeNotifier::AddIPAddressObserver(this);
3020 NetworkChangeNotifier::AddConnectionTypeObserver(this);
3021 }
3022 if (system_dns_config_notifier_)
3023 system_dns_config_notifier_->AddObserver(this);
3024 EnsureSystemHostResolverCallReady();
3025
3026 auto connection_type =
3027 IsBoundToNetwork()
3028 ? NetworkChangeNotifier::GetNetworkConnectionType(target_network)
3029 : NetworkChangeNotifier::GetConnectionType();
3030 UpdateConnectionType(connection_type);
3031
3032 #if defined(ENABLE_BUILT_IN_DNS)
3033 dns_client_ = DnsClient::CreateClient(net_log_);
3034 dns_client_->SetInsecureEnabled(
3035 options.insecure_dns_client_enabled,
3036 options.additional_types_via_insecure_dns_enabled);
3037 dns_client_->SetConfigOverrides(options.dns_config_overrides);
3038 #else
3039 DCHECK(options.dns_config_overrides == DnsConfigOverrides());
3040 #endif
3041
3042 allow_fallback_to_systemtask_ = !ConfigureAsyncDnsNoFallbackFieldTrial();
3043 }
3044
~HostResolverManager()3045 HostResolverManager::~HostResolverManager() {
3046 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3047 // Prevent the dispatcher from starting new jobs.
3048 dispatcher_->SetLimitsToZero();
3049 // It's now safe for Jobs to call KillDnsTask on destruction, because
3050 // OnJobComplete will not start any new jobs.
3051 jobs_.clear();
3052
3053 if (target_network_ == handles::kInvalidNetworkHandle) {
3054 NetworkChangeNotifier::RemoveIPAddressObserver(this);
3055 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
3056 }
3057 if (system_dns_config_notifier_)
3058 system_dns_config_notifier_->RemoveObserver(this);
3059 }
3060
3061 // static
3062 std::unique_ptr<HostResolverManager>
CreateNetworkBoundHostResolverManager(const HostResolver::ManagerOptions & options,handles::NetworkHandle target_network,NetLog * net_log)3063 HostResolverManager::CreateNetworkBoundHostResolverManager(
3064 const HostResolver::ManagerOptions& options,
3065 handles::NetworkHandle target_network,
3066 NetLog* net_log) {
3067 #if BUILDFLAG(IS_ANDROID)
3068 DCHECK(NetworkChangeNotifier::AreNetworkHandlesSupported());
3069 return std::make_unique<HostResolverManager>(
3070 PassKey(), options, nullptr /* system_dns_config_notifier */,
3071 target_network, net_log);
3072 #else // !BUILDFLAG(IS_ANDROID)
3073 NOTIMPLEMENTED();
3074 return nullptr;
3075 #endif // BUILDFLAG(IS_ANDROID)
3076 }
3077
3078 std::unique_ptr<HostResolver::ResolveHostRequest>
CreateRequest(absl::variant<url::SchemeHostPort,HostPortPair> host,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,absl::optional<ResolveHostParameters> optional_parameters,ResolveContext * resolve_context,HostCache * host_cache)3079 HostResolverManager::CreateRequest(
3080 absl::variant<url::SchemeHostPort, HostPortPair> host,
3081 NetworkAnonymizationKey network_anonymization_key,
3082 NetLogWithSource net_log,
3083 absl::optional<ResolveHostParameters> optional_parameters,
3084 ResolveContext* resolve_context,
3085 HostCache* host_cache) {
3086 return CreateRequest(HostResolver::Host(std::move(host)),
3087 std::move(network_anonymization_key), std::move(net_log),
3088 std::move(optional_parameters), resolve_context,
3089 host_cache);
3090 }
3091
3092 std::unique_ptr<HostResolver::ResolveHostRequest>
CreateRequest(HostResolver::Host host,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,absl::optional<ResolveHostParameters> optional_parameters,ResolveContext * resolve_context,HostCache * host_cache)3093 HostResolverManager::CreateRequest(
3094 HostResolver::Host host,
3095 NetworkAnonymizationKey network_anonymization_key,
3096 NetLogWithSource net_log,
3097 absl::optional<ResolveHostParameters> optional_parameters,
3098 ResolveContext* resolve_context,
3099 HostCache* host_cache) {
3100 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3101 DCHECK(!invalidation_in_progress_);
3102
3103 DCHECK_EQ(resolve_context->GetTargetNetwork(), target_network_);
3104 // ResolveContexts must register (via RegisterResolveContext()) before use to
3105 // ensure cached data is invalidated on network and configuration changes.
3106 DCHECK(registered_contexts_.HasObserver(resolve_context));
3107
3108 return std::make_unique<RequestImpl>(
3109 std::move(net_log), std::move(host), std::move(network_anonymization_key),
3110 std::move(optional_parameters), resolve_context->GetWeakPtr(), host_cache,
3111 weak_ptr_factory_.GetWeakPtr(), tick_clock_);
3112 }
3113
3114 std::unique_ptr<HostResolver::ProbeRequest>
CreateDohProbeRequest(ResolveContext * context)3115 HostResolverManager::CreateDohProbeRequest(ResolveContext* context) {
3116 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3117
3118 return std::make_unique<ProbeRequestImpl>(context->GetWeakPtr(),
3119 weak_ptr_factory_.GetWeakPtr());
3120 }
3121
3122 std::unique_ptr<HostResolver::MdnsListener>
CreateMdnsListener(const HostPortPair & host,DnsQueryType query_type)3123 HostResolverManager::CreateMdnsListener(const HostPortPair& host,
3124 DnsQueryType query_type) {
3125 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3126 DCHECK_NE(DnsQueryType::UNSPECIFIED, query_type);
3127
3128 auto listener =
3129 std::make_unique<HostResolverMdnsListenerImpl>(host, query_type);
3130
3131 MDnsClient* client;
3132 int rv = GetOrCreateMdnsClient(&client);
3133
3134 if (rv == OK) {
3135 std::unique_ptr<net::MDnsListener> inner_listener = client->CreateListener(
3136 DnsQueryTypeToQtype(query_type), host.host(), listener.get());
3137 listener->set_inner_listener(std::move(inner_listener));
3138 } else {
3139 listener->set_initialization_error(rv);
3140 }
3141 return listener;
3142 }
3143
SetInsecureDnsClientEnabled(bool enabled,bool additional_dns_types_enabled)3144 void HostResolverManager::SetInsecureDnsClientEnabled(
3145 bool enabled,
3146 bool additional_dns_types_enabled) {
3147 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3148
3149 if (!dns_client_)
3150 return;
3151
3152 bool enabled_before = dns_client_->CanUseInsecureDnsTransactions();
3153 bool additional_types_before =
3154 enabled_before && dns_client_->CanQueryAdditionalTypesViaInsecureDns();
3155 dns_client_->SetInsecureEnabled(enabled, additional_dns_types_enabled);
3156
3157 // Abort current tasks if `CanUseInsecureDnsTransactions()` changes or if
3158 // insecure transactions are enabled and
3159 // `CanQueryAdditionalTypesViaInsecureDns()` changes. Changes to allowing
3160 // additional types don't matter if insecure transactions are completely
3161 // disabled.
3162 if (dns_client_->CanUseInsecureDnsTransactions() != enabled_before ||
3163 (dns_client_->CanUseInsecureDnsTransactions() &&
3164 dns_client_->CanQueryAdditionalTypesViaInsecureDns() !=
3165 additional_types_before)) {
3166 AbortInsecureDnsTasks(ERR_NETWORK_CHANGED, false /* fallback_only */);
3167 }
3168 }
3169
GetDnsConfigAsValue() const3170 base::Value::Dict HostResolverManager::GetDnsConfigAsValue() const {
3171 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3172 return dns_client_ ? dns_client_->GetDnsConfigAsValueForNetLog()
3173 : base::Value::Dict();
3174 }
3175
SetDnsConfigOverrides(DnsConfigOverrides overrides)3176 void HostResolverManager::SetDnsConfigOverrides(DnsConfigOverrides overrides) {
3177 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
3178
3179 if (!dns_client_ && overrides == DnsConfigOverrides())
3180 return;
3181
3182 // Not allowed to set overrides if compiled without DnsClient.
3183 DCHECK(dns_client_);
3184
3185 bool transactions_allowed_before =
3186 dns_client_->CanUseSecureDnsTransactions() ||
3187 dns_client_->CanUseInsecureDnsTransactions();
3188 bool changed = dns_client_->SetConfigOverrides(std::move(overrides));
3189
3190 if (changed) {
3191 NetworkChangeNotifier::TriggerNonSystemDnsChange();
3192
3193 // Only invalidate cache if new overrides have resulted in a config change.
3194 InvalidateCaches();
3195
3196 // Need to update jobs iff transactions were previously allowed because
3197 // in-progress jobs may be running using a now-invalid configuration.
3198 if (transactions_allowed_before) {
3199 UpdateJobsForChangedConfig();
3200 }
3201 }
3202 }
3203
RegisterResolveContext(ResolveContext * context)3204 void HostResolverManager::RegisterResolveContext(ResolveContext* context) {
3205 registered_contexts_.AddObserver(context);
3206 context->InvalidateCachesAndPerSessionData(
3207 dns_client_ ? dns_client_->GetCurrentSession() : nullptr,
3208 false /* network_change */);
3209 }
3210
DeregisterResolveContext(const ResolveContext * context)3211 void HostResolverManager::DeregisterResolveContext(
3212 const ResolveContext* context) {
3213 registered_contexts_.RemoveObserver(context);
3214
3215 // Destroy Jobs when their context is closed.
3216 RemoveAllJobs(context);
3217 }
3218
SetTickClockForTesting(const base::TickClock * tick_clock)3219 void HostResolverManager::SetTickClockForTesting(
3220 const base::TickClock* tick_clock) {
3221 tick_clock_ = tick_clock;
3222 }
3223
SetMaxQueuedJobsForTesting(size_t value)3224 void HostResolverManager::SetMaxQueuedJobsForTesting(size_t value) {
3225 DCHECK_EQ(0u, dispatcher_->num_queued_jobs());
3226 DCHECK_GE(value, 0u);
3227 max_queued_jobs_ = value;
3228 }
3229
SetHaveOnlyLoopbackAddresses(bool result)3230 void HostResolverManager::SetHaveOnlyLoopbackAddresses(bool result) {
3231 if (result) {
3232 additional_resolver_flags_ |= HOST_RESOLVER_LOOPBACK_ONLY;
3233 } else {
3234 additional_resolver_flags_ &= ~HOST_RESOLVER_LOOPBACK_ONLY;
3235 }
3236 }
3237
SetMdnsSocketFactoryForTesting(std::unique_ptr<MDnsSocketFactory> socket_factory)3238 void HostResolverManager::SetMdnsSocketFactoryForTesting(
3239 std::unique_ptr<MDnsSocketFactory> socket_factory) {
3240 DCHECK(!mdns_client_);
3241 mdns_socket_factory_ = std::move(socket_factory);
3242 }
3243
SetMdnsClientForTesting(std::unique_ptr<MDnsClient> client)3244 void HostResolverManager::SetMdnsClientForTesting(
3245 std::unique_ptr<MDnsClient> client) {
3246 mdns_client_ = std::move(client);
3247 }
3248
SetDnsClientForTesting(std::unique_ptr<DnsClient> dns_client)3249 void HostResolverManager::SetDnsClientForTesting(
3250 std::unique_ptr<DnsClient> dns_client) {
3251 DCHECK(dns_client);
3252 if (dns_client_) {
3253 if (!dns_client->GetSystemConfigForTesting())
3254 dns_client->SetSystemConfig(dns_client_->GetSystemConfigForTesting());
3255 dns_client->SetConfigOverrides(dns_client_->GetConfigOverridesForTesting());
3256 }
3257 dns_client_ = std::move(dns_client);
3258 // Inform `registered_contexts_` of the new `DnsClient`.
3259 InvalidateCaches();
3260 }
3261
SetLastIPv6ProbeResultForTesting(bool last_ipv6_probe_result)3262 void HostResolverManager::SetLastIPv6ProbeResultForTesting(
3263 bool last_ipv6_probe_result) {
3264 SetLastIPv6ProbeResult(last_ipv6_probe_result);
3265 }
3266
3267 // static
IsLocalTask(TaskType task)3268 bool HostResolverManager::IsLocalTask(TaskType task) {
3269 switch (task) {
3270 case TaskType::SECURE_CACHE_LOOKUP:
3271 case TaskType::INSECURE_CACHE_LOOKUP:
3272 case TaskType::CACHE_LOOKUP:
3273 case TaskType::CONFIG_PRESET:
3274 case TaskType::HOSTS:
3275 return true;
3276 default:
3277 return false;
3278 }
3279 }
3280
ResolveLocally(bool only_ipv6_reachable,const JobKey & job_key,const IPAddress & ip_address,ResolveHostParameters::CacheUsage cache_usage,SecureDnsPolicy secure_dns_policy,HostResolverSource source,const NetLogWithSource & source_net_log,HostCache * cache,std::deque<TaskType> * out_tasks,absl::optional<HostCache::EntryStaleness> * out_stale_info)3281 HostCache::Entry HostResolverManager::ResolveLocally(
3282 bool only_ipv6_reachable,
3283 const JobKey& job_key,
3284 const IPAddress& ip_address,
3285 ResolveHostParameters::CacheUsage cache_usage,
3286 SecureDnsPolicy secure_dns_policy,
3287 HostResolverSource source,
3288 const NetLogWithSource& source_net_log,
3289 HostCache* cache,
3290 std::deque<TaskType>* out_tasks,
3291 absl::optional<HostCache::EntryStaleness>* out_stale_info) {
3292 DCHECK(out_stale_info);
3293 *out_stale_info = absl::nullopt;
3294
3295 CreateTaskSequence(job_key, cache_usage, secure_dns_policy, out_tasks);
3296
3297 if (!ip_address.IsValid()) {
3298 // Check that the caller supplied a valid hostname to resolve. For
3299 // MULTICAST_DNS, we are less restrictive.
3300 // TODO(ericorth): Control validation based on an explicit flag rather
3301 // than implicitly based on |source|.
3302 const bool is_valid_hostname =
3303 job_key.source == HostResolverSource::MULTICAST_DNS
3304 ? dns_names_util::IsValidDnsName(GetHostname(job_key.host))
3305 : IsCanonicalizedHostCompliant(GetHostname(job_key.host));
3306 if (!is_valid_hostname) {
3307 return HostCache::Entry(ERR_NAME_NOT_RESOLVED,
3308 HostCache::Entry::SOURCE_UNKNOWN);
3309 }
3310 }
3311
3312 bool resolve_canonname = job_key.flags & HOST_RESOLVER_CANONNAME;
3313 bool default_family_due_to_no_ipv6 =
3314 job_key.flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
3315
3316 // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
3317 // On Windows it gives the default interface's address, whereas on Linux it
3318 // gives an error. We will make it fail on all platforms for consistency.
3319 if (GetHostname(job_key.host).empty() ||
3320 GetHostname(job_key.host).size() > kMaxHostLength) {
3321 return HostCache::Entry(ERR_NAME_NOT_RESOLVED,
3322 HostCache::Entry::SOURCE_UNKNOWN);
3323 }
3324
3325 if (ip_address.IsValid()) {
3326 // Use NAT64Task for IPv4 literal when the network is IPv6 only.
3327 if (MayUseNAT64ForIPv4Literal(job_key.flags, source, ip_address) &&
3328 only_ipv6_reachable) {
3329 out_tasks->push_front(TaskType::NAT64);
3330 return HostCache::Entry(ERR_DNS_CACHE_MISS,
3331 HostCache::Entry::SOURCE_UNKNOWN);
3332 }
3333
3334 return ResolveAsIP(job_key.query_types, resolve_canonname, ip_address);
3335 }
3336
3337 // Special-case localhost names, as per the recommendations in
3338 // https://tools.ietf.org/html/draft-west-let-localhost-be-localhost.
3339 absl::optional<HostCache::Entry> resolved =
3340 ServeLocalhost(GetHostname(job_key.host), job_key.query_types,
3341 default_family_due_to_no_ipv6);
3342 if (resolved)
3343 return resolved.value();
3344
3345 // Do initial cache lookups.
3346 while (!out_tasks->empty() && IsLocalTask(out_tasks->front())) {
3347 TaskType task = out_tasks->front();
3348 out_tasks->pop_front();
3349 if (task == TaskType::SECURE_CACHE_LOOKUP ||
3350 task == TaskType::INSECURE_CACHE_LOOKUP ||
3351 task == TaskType::CACHE_LOOKUP) {
3352 bool secure = task == TaskType::SECURE_CACHE_LOOKUP;
3353 HostCache::Key key = job_key.ToCacheKey(secure);
3354
3355 bool ignore_secure = task == TaskType::CACHE_LOOKUP;
3356 resolved = MaybeServeFromCache(cache, key, cache_usage, ignore_secure,
3357 source_net_log, out_stale_info);
3358 if (resolved) {
3359 // |MaybeServeFromCache()| will update |*out_stale_info| as needed.
3360 DCHECK(out_stale_info->has_value());
3361 source_net_log.AddEvent(
3362 NetLogEventType::HOST_RESOLVER_MANAGER_CACHE_HIT,
3363 [&] { return NetLogResults(resolved.value()); });
3364
3365 // TODO(crbug.com/1200908): Call StartBootstrapFollowup() if the Secure
3366 // DNS Policy is kBootstrap and the result is not secure. Note: A naive
3367 // implementation could cause an infinite loop if |resolved| always
3368 // expires or is evicted before the followup runs.
3369 return resolved.value();
3370 }
3371 DCHECK(!out_stale_info->has_value());
3372 } else if (task == TaskType::CONFIG_PRESET) {
3373 resolved = MaybeReadFromConfig(job_key);
3374 if (resolved) {
3375 source_net_log.AddEvent(
3376 NetLogEventType::HOST_RESOLVER_MANAGER_CONFIG_PRESET_MATCH,
3377 [&] { return NetLogResults(resolved.value()); });
3378 StartBootstrapFollowup(job_key, cache, source_net_log);
3379 return resolved.value();
3380 }
3381 } else if (task == TaskType::HOSTS) {
3382 resolved = ServeFromHosts(GetHostname(job_key.host), job_key.query_types,
3383 default_family_due_to_no_ipv6, *out_tasks);
3384 if (resolved) {
3385 source_net_log.AddEvent(
3386 NetLogEventType::HOST_RESOLVER_MANAGER_HOSTS_HIT,
3387 [&] { return NetLogResults(resolved.value()); });
3388 return resolved.value();
3389 }
3390 } else {
3391 NOTREACHED();
3392 }
3393 }
3394
3395 return HostCache::Entry(ERR_DNS_CACHE_MISS, HostCache::Entry::SOURCE_UNKNOWN);
3396 }
3397
CreateAndStartJob(JobKey key,std::deque<TaskType> tasks,RequestImpl * request)3398 void HostResolverManager::CreateAndStartJob(JobKey key,
3399 std::deque<TaskType> tasks,
3400 RequestImpl* request) {
3401 DCHECK(!tasks.empty());
3402
3403 auto jobit = jobs_.find(key);
3404 Job* job;
3405 if (jobit == jobs_.end()) {
3406 job = AddJobWithoutRequest(key, request->parameters().cache_usage,
3407 request->host_cache(), std::move(tasks),
3408 request->priority(), request->source_net_log());
3409 job->AddRequest(request);
3410 job->RunNextTask();
3411 } else {
3412 job = jobit->second.get();
3413 job->AddRequest(request);
3414 }
3415 }
3416
AddJobWithoutRequest(JobKey key,ResolveHostParameters::CacheUsage cache_usage,HostCache * host_cache,std::deque<TaskType> tasks,RequestPriority priority,const NetLogWithSource & source_net_log)3417 HostResolverManager::Job* HostResolverManager::AddJobWithoutRequest(
3418 JobKey key,
3419 ResolveHostParameters::CacheUsage cache_usage,
3420 HostCache* host_cache,
3421 std::deque<TaskType> tasks,
3422 RequestPriority priority,
3423 const NetLogWithSource& source_net_log) {
3424 auto new_job =
3425 std::make_unique<Job>(weak_ptr_factory_.GetWeakPtr(), key, cache_usage,
3426 host_cache, std::move(tasks), priority,
3427 source_net_log, tick_clock_, https_svcb_options_);
3428 auto insert_result = jobs_.emplace(std::move(key), std::move(new_job));
3429 auto& iterator = insert_result.first;
3430 bool is_new = insert_result.second;
3431 DCHECK(is_new);
3432 auto& job = iterator->second;
3433 job->OnAddedToJobMap(iterator);
3434 return job.get();
3435 }
3436
ResolveAsIP(DnsQueryTypeSet query_types,bool resolve_canonname,const IPAddress & ip_address)3437 HostCache::Entry HostResolverManager::ResolveAsIP(DnsQueryTypeSet query_types,
3438 bool resolve_canonname,
3439 const IPAddress& ip_address) {
3440 DCHECK(ip_address.IsValid());
3441 DCHECK(!query_types.Has(DnsQueryType::UNSPECIFIED));
3442
3443 // IP literals cannot resolve unless the query type is an address query that
3444 // allows addresses with the same address family as the literal. E.g., don't
3445 // return IPv6 addresses for IPv4 queries or anything for a non-address query.
3446 AddressFamily family = GetAddressFamily(ip_address);
3447 if (!query_types.Has(AddressFamilyToDnsQueryType(family))) {
3448 return HostCache::Entry(ERR_NAME_NOT_RESOLVED,
3449 HostCache::Entry::SOURCE_UNKNOWN);
3450 }
3451
3452 std::set<std::string> aliases;
3453 if (resolve_canonname) {
3454 aliases = {ip_address.ToString()};
3455 }
3456 return HostCache::Entry(OK, {IPEndPoint(ip_address, 0)}, std::move(aliases),
3457 HostCache::Entry::SOURCE_UNKNOWN);
3458 }
3459
MaybeServeFromCache(HostCache * cache,const HostCache::Key & key,ResolveHostParameters::CacheUsage cache_usage,bool ignore_secure,const NetLogWithSource & source_net_log,absl::optional<HostCache::EntryStaleness> * out_stale_info)3460 absl::optional<HostCache::Entry> HostResolverManager::MaybeServeFromCache(
3461 HostCache* cache,
3462 const HostCache::Key& key,
3463 ResolveHostParameters::CacheUsage cache_usage,
3464 bool ignore_secure,
3465 const NetLogWithSource& source_net_log,
3466 absl::optional<HostCache::EntryStaleness>* out_stale_info) {
3467 DCHECK(out_stale_info);
3468 *out_stale_info = absl::nullopt;
3469
3470 if (!cache)
3471 return absl::nullopt;
3472
3473 if (cache_usage == ResolveHostParameters::CacheUsage::DISALLOWED)
3474 return absl::nullopt;
3475
3476 // Local-only requests search the cache for non-local-only results.
3477 HostCache::Key effective_key = key;
3478 if (effective_key.host_resolver_source == HostResolverSource::LOCAL_ONLY)
3479 effective_key.host_resolver_source = HostResolverSource::ANY;
3480
3481 const std::pair<const HostCache::Key, HostCache::Entry>* cache_result;
3482 HostCache::EntryStaleness staleness;
3483 if (cache_usage == ResolveHostParameters::CacheUsage::STALE_ALLOWED) {
3484 cache_result = cache->LookupStale(effective_key, tick_clock_->NowTicks(),
3485 &staleness, ignore_secure);
3486 } else {
3487 DCHECK(cache_usage == ResolveHostParameters::CacheUsage::ALLOWED);
3488 cache_result =
3489 cache->Lookup(effective_key, tick_clock_->NowTicks(), ignore_secure);
3490 staleness = HostCache::kNotStale;
3491 }
3492 if (cache_result) {
3493 *out_stale_info = std::move(staleness);
3494 source_net_log.AddEvent(
3495 NetLogEventType::HOST_RESOLVER_MANAGER_CACHE_HIT,
3496 [&] { return NetLogResults(cache_result->second); });
3497 return cache_result->second;
3498 }
3499 return absl::nullopt;
3500 }
3501
MaybeReadFromConfig(const JobKey & key)3502 absl::optional<HostCache::Entry> HostResolverManager::MaybeReadFromConfig(
3503 const JobKey& key) {
3504 DCHECK(HasAddressType(key.query_types));
3505 if (!absl::holds_alternative<url::SchemeHostPort>(key.host))
3506 return absl::nullopt;
3507 absl::optional<std::vector<IPEndPoint>> preset_addrs =
3508 dns_client_->GetPresetAddrs(absl::get<url::SchemeHostPort>(key.host));
3509 if (!preset_addrs)
3510 return absl::nullopt;
3511
3512 std::vector<IPEndPoint> filtered_addresses =
3513 FilterAddresses(std::move(*preset_addrs), key.query_types);
3514 if (filtered_addresses.empty())
3515 return absl::nullopt;
3516
3517 return HostCache::Entry(OK, std::move(filtered_addresses), /*aliases=*/{},
3518 HostCache::Entry::SOURCE_CONFIG);
3519 }
3520
StartBootstrapFollowup(JobKey key,HostCache * host_cache,const NetLogWithSource & source_net_log)3521 void HostResolverManager::StartBootstrapFollowup(
3522 JobKey key,
3523 HostCache* host_cache,
3524 const NetLogWithSource& source_net_log) {
3525 DCHECK_EQ(SecureDnsMode::kOff, key.secure_dns_mode);
3526 DCHECK(host_cache);
3527
3528 key.secure_dns_mode = SecureDnsMode::kSecure;
3529 if (jobs_.count(key) != 0)
3530 return;
3531
3532 Job* job = AddJobWithoutRequest(
3533 key, ResolveHostParameters::CacheUsage::ALLOWED, host_cache,
3534 {TaskType::SECURE_DNS}, RequestPriority::LOW, source_net_log);
3535 job->RunNextTask();
3536 }
3537
ServeFromHosts(base::StringPiece hostname,DnsQueryTypeSet query_types,bool default_family_due_to_no_ipv6,const std::deque<TaskType> & tasks)3538 absl::optional<HostCache::Entry> HostResolverManager::ServeFromHosts(
3539 base::StringPiece hostname,
3540 DnsQueryTypeSet query_types,
3541 bool default_family_due_to_no_ipv6,
3542 const std::deque<TaskType>& tasks) {
3543 DCHECK(!query_types.Has(DnsQueryType::UNSPECIFIED));
3544 // Don't attempt a HOSTS lookup if there is no DnsConfig or the HOSTS lookup
3545 // is going to be done next as part of a system lookup.
3546 if (!dns_client_ || !HasAddressType(query_types) ||
3547 (!tasks.empty() && tasks.front() == TaskType::SYSTEM))
3548 return absl::nullopt;
3549 const DnsHosts* hosts = dns_client_->GetHosts();
3550
3551 if (!hosts || hosts->empty())
3552 return absl::nullopt;
3553
3554 // HOSTS lookups are case-insensitive.
3555 std::string effective_hostname = base::ToLowerASCII(hostname);
3556
3557 // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations
3558 // (glibc and c-ares) return the first matching line. We have more
3559 // flexibility, but lose implicit ordering.
3560 // We prefer IPv6 because "happy eyeballs" will fall back to IPv4 if
3561 // necessary.
3562 std::vector<IPEndPoint> addresses;
3563 if (query_types.Has(DnsQueryType::AAAA)) {
3564 auto it = hosts->find(DnsHostsKey(effective_hostname, ADDRESS_FAMILY_IPV6));
3565 if (it != hosts->end()) {
3566 addresses.emplace_back(it->second, 0);
3567 }
3568 }
3569
3570 if (query_types.Has(DnsQueryType::A)) {
3571 auto it = hosts->find(DnsHostsKey(effective_hostname, ADDRESS_FAMILY_IPV4));
3572 if (it != hosts->end()) {
3573 addresses.emplace_back(it->second, 0);
3574 }
3575 }
3576
3577 // If got only loopback addresses and the family was restricted, resolve
3578 // again, without restrictions. See SystemHostResolverCall for rationale.
3579 if (default_family_due_to_no_ipv6 &&
3580 base::ranges::all_of(addresses, &IPAddress::IsIPv4,
3581 &IPEndPoint::address) &&
3582 base::ranges::all_of(addresses, &IPAddress::IsLoopback,
3583 &IPEndPoint::address)) {
3584 query_types.Put(DnsQueryType::AAAA);
3585 return ServeFromHosts(hostname, query_types, false, tasks);
3586 }
3587
3588 if (addresses.empty())
3589 return absl::nullopt;
3590
3591 return HostCache::Entry(OK, std::move(addresses),
3592 /*aliases=*/{}, HostCache::Entry::SOURCE_HOSTS);
3593 }
3594
ServeLocalhost(base::StringPiece hostname,DnsQueryTypeSet query_types,bool default_family_due_to_no_ipv6)3595 absl::optional<HostCache::Entry> HostResolverManager::ServeLocalhost(
3596 base::StringPiece hostname,
3597 DnsQueryTypeSet query_types,
3598 bool default_family_due_to_no_ipv6) {
3599 DCHECK(!query_types.Has(DnsQueryType::UNSPECIFIED));
3600
3601 std::vector<IPEndPoint> resolved_addresses;
3602 if (!HasAddressType(query_types) ||
3603 !ResolveLocalHostname(hostname, &resolved_addresses)) {
3604 return absl::nullopt;
3605 }
3606
3607 if (default_family_due_to_no_ipv6 && query_types.Has(DnsQueryType::A) &&
3608 !query_types.Has(DnsQueryType::AAAA)) {
3609 // The caller disabled the AAAA query due to lack of detected IPv6 support.
3610 // (See SystemHostResolverCall for rationale).
3611 query_types.Put(DnsQueryType::AAAA);
3612 }
3613 std::vector<IPEndPoint> filtered_addresses =
3614 FilterAddresses(std::move(resolved_addresses), query_types);
3615 return HostCache::Entry(OK, std::move(filtered_addresses), /*aliases=*/{},
3616 HostCache::Entry::SOURCE_UNKNOWN);
3617 }
3618
CacheResult(HostCache * cache,const HostCache::Key & key,const HostCache::Entry & entry,base::TimeDelta ttl)3619 void HostResolverManager::CacheResult(HostCache* cache,
3620 const HostCache::Key& key,
3621 const HostCache::Entry& entry,
3622 base::TimeDelta ttl) {
3623 // Don't cache an error unless it has a positive TTL.
3624 if (cache && (entry.error() == OK || ttl.is_positive()))
3625 cache->Set(key, entry, tick_clock_->NowTicks(), ttl);
3626 }
3627
RemoveJob(JobMap::iterator job_it)3628 std::unique_ptr<HostResolverManager::Job> HostResolverManager::RemoveJob(
3629 JobMap::iterator job_it) {
3630 DCHECK(job_it != jobs_.end());
3631 DCHECK(job_it->second);
3632 DCHECK_EQ(1u, jobs_.count(job_it->first));
3633
3634 std::unique_ptr<Job> job;
3635 job_it->second.swap(job);
3636 jobs_.erase(job_it);
3637 job->OnRemovedFromJobMap();
3638
3639 return job;
3640 }
3641
GetEffectiveSecureDnsMode(SecureDnsPolicy secure_dns_policy)3642 SecureDnsMode HostResolverManager::GetEffectiveSecureDnsMode(
3643 SecureDnsPolicy secure_dns_policy) {
3644 // Use switch() instead of if() to ensure that all policies are handled.
3645 switch (secure_dns_policy) {
3646 case SecureDnsPolicy::kDisable:
3647 case SecureDnsPolicy::kBootstrap:
3648 return SecureDnsMode::kOff;
3649 case SecureDnsPolicy::kAllow:
3650 break;
3651 }
3652
3653 const DnsConfig* config =
3654 dns_client_ ? dns_client_->GetEffectiveConfig() : nullptr;
3655
3656 SecureDnsMode secure_dns_mode = SecureDnsMode::kOff;
3657 if (config) {
3658 secure_dns_mode = config->secure_dns_mode;
3659 }
3660 return secure_dns_mode;
3661 }
3662
ShouldForceSystemResolverDueToTestOverride() const3663 bool HostResolverManager::ShouldForceSystemResolverDueToTestOverride() const {
3664 // If tests have provided a catch-all DNS block and then disabled it, check
3665 // that we are not at risk of sending queries beyond the local network.
3666 if (HostResolverProc::GetDefault() && system_resolver_disabled_for_testing_) {
3667 DCHECK(dns_client_);
3668 DCHECK(dns_client_->GetEffectiveConfig());
3669 DCHECK(base::ranges::none_of(dns_client_->GetEffectiveConfig()->nameservers,
3670 &IPAddress::IsPubliclyRoutable,
3671 &IPEndPoint::address))
3672 << "Test could query a publicly-routable address.";
3673 }
3674 return !host_resolver_system_params_.resolver_proc &&
3675 HostResolverProc::GetDefault() &&
3676 !system_resolver_disabled_for_testing_;
3677 }
3678
PushDnsTasks(bool system_task_allowed,SecureDnsMode secure_dns_mode,bool insecure_tasks_allowed,bool allow_cache,bool prioritize_local_lookups,ResolveContext * resolve_context,std::deque<TaskType> * out_tasks)3679 void HostResolverManager::PushDnsTasks(bool system_task_allowed,
3680 SecureDnsMode secure_dns_mode,
3681 bool insecure_tasks_allowed,
3682 bool allow_cache,
3683 bool prioritize_local_lookups,
3684 ResolveContext* resolve_context,
3685 std::deque<TaskType>* out_tasks) {
3686 DCHECK(dns_client_);
3687 DCHECK(dns_client_->GetEffectiveConfig());
3688
3689 // If a catch-all DNS block has been set for unit tests, we shouldn't send
3690 // DnsTasks. It is still necessary to call this method, however, so that the
3691 // correct cache tasks for the secure dns mode are added.
3692 const bool dns_tasks_allowed = !ShouldForceSystemResolverDueToTestOverride();
3693 // Upgrade the insecure DnsTask depending on the secure dns mode.
3694 switch (secure_dns_mode) {
3695 case SecureDnsMode::kSecure:
3696 DCHECK(!allow_cache ||
3697 out_tasks->front() == TaskType::SECURE_CACHE_LOOKUP);
3698 // Policy misconfiguration can put us in secure DNS mode without any DoH
3699 // servers to query. See https://crbug.com/1326526.
3700 if (dns_tasks_allowed && dns_client_->CanUseSecureDnsTransactions())
3701 out_tasks->push_back(TaskType::SECURE_DNS);
3702 break;
3703 case SecureDnsMode::kAutomatic:
3704 DCHECK(!allow_cache || out_tasks->front() == TaskType::CACHE_LOOKUP);
3705 if (dns_client_->FallbackFromSecureTransactionPreferred(
3706 resolve_context)) {
3707 // Don't run a secure DnsTask if there are no available DoH servers.
3708 if (dns_tasks_allowed && insecure_tasks_allowed)
3709 out_tasks->push_back(TaskType::DNS);
3710 } else if (prioritize_local_lookups) {
3711 // If local lookups are prioritized, the cache should be checked for
3712 // both secure and insecure results prior to running a secure DnsTask.
3713 // The task sequence should already contain the appropriate cache task.
3714 if (dns_tasks_allowed) {
3715 out_tasks->push_back(TaskType::SECURE_DNS);
3716 if (insecure_tasks_allowed)
3717 out_tasks->push_back(TaskType::DNS);
3718 }
3719 } else {
3720 if (allow_cache) {
3721 // Remove the initial cache lookup task so that the secure and
3722 // insecure lookups can be separated.
3723 out_tasks->pop_front();
3724 out_tasks->push_back(TaskType::SECURE_CACHE_LOOKUP);
3725 }
3726 if (dns_tasks_allowed)
3727 out_tasks->push_back(TaskType::SECURE_DNS);
3728 if (allow_cache)
3729 out_tasks->push_back(TaskType::INSECURE_CACHE_LOOKUP);
3730 if (dns_tasks_allowed && insecure_tasks_allowed)
3731 out_tasks->push_back(TaskType::DNS);
3732 }
3733 break;
3734 case SecureDnsMode::kOff:
3735 DCHECK(!allow_cache || IsLocalTask(out_tasks->front()));
3736 if (dns_tasks_allowed && insecure_tasks_allowed)
3737 out_tasks->push_back(TaskType::DNS);
3738 break;
3739 default:
3740 NOTREACHED();
3741 break;
3742 }
3743
3744 constexpr TaskType kWantTasks[] = {TaskType::DNS, TaskType::SECURE_DNS};
3745 const bool no_dns_or_secure_tasks =
3746 base::ranges::find_first_of(*out_tasks, kWantTasks) == out_tasks->end();
3747 // The system resolver can be used as a fallback for a non-existent or
3748 // failing DnsTask if allowed by the request parameters.
3749 if (system_task_allowed &&
3750 (no_dns_or_secure_tasks || allow_fallback_to_systemtask_))
3751 out_tasks->push_back(TaskType::SYSTEM);
3752 }
3753
CreateTaskSequence(const JobKey & job_key,ResolveHostParameters::CacheUsage cache_usage,SecureDnsPolicy secure_dns_policy,std::deque<TaskType> * out_tasks)3754 void HostResolverManager::CreateTaskSequence(
3755 const JobKey& job_key,
3756 ResolveHostParameters::CacheUsage cache_usage,
3757 SecureDnsPolicy secure_dns_policy,
3758 std::deque<TaskType>* out_tasks) {
3759 DCHECK(out_tasks->empty());
3760
3761 // A cache lookup should generally be performed first. For jobs involving a
3762 // DnsTask, this task may be replaced.
3763 bool allow_cache =
3764 cache_usage != ResolveHostParameters::CacheUsage::DISALLOWED;
3765 if (secure_dns_policy == SecureDnsPolicy::kBootstrap) {
3766 DCHECK_EQ(SecureDnsMode::kOff, job_key.secure_dns_mode);
3767 if (allow_cache)
3768 out_tasks->push_front(TaskType::INSECURE_CACHE_LOOKUP);
3769 out_tasks->push_front(TaskType::CONFIG_PRESET);
3770 if (allow_cache)
3771 out_tasks->push_front(TaskType::SECURE_CACHE_LOOKUP);
3772 } else if (allow_cache) {
3773 if (job_key.secure_dns_mode == SecureDnsMode::kSecure) {
3774 out_tasks->push_front(TaskType::SECURE_CACHE_LOOKUP);
3775 } else {
3776 out_tasks->push_front(TaskType::CACHE_LOOKUP);
3777 }
3778 }
3779 out_tasks->push_back(TaskType::HOSTS);
3780
3781 // Determine what type of task a future Job should start.
3782 bool prioritize_local_lookups =
3783 cache_usage ==
3784 HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
3785
3786 const bool has_address_type = HasAddressType(job_key.query_types);
3787
3788 switch (job_key.source) {
3789 case HostResolverSource::ANY:
3790 // Force address queries with canonname to use HostResolverSystemTask to
3791 // counter poor CNAME support in DnsTask. See https://crbug.com/872665
3792 //
3793 // Otherwise, default to DnsTask (with allowed fallback to
3794 // HostResolverSystemTask for address queries). But if hostname appears to
3795 // be an MDNS name (ends in *.local), go with HostResolverSystemTask for
3796 // address queries and MdnsTask for non- address queries.
3797 if ((job_key.flags & HOST_RESOLVER_CANONNAME) && has_address_type) {
3798 out_tasks->push_back(TaskType::SYSTEM);
3799 } else if (!ResemblesMulticastDNSName(GetHostname(job_key.host))) {
3800 bool system_task_allowed =
3801 has_address_type &&
3802 job_key.secure_dns_mode != SecureDnsMode::kSecure;
3803 if (dns_client_ && dns_client_->GetEffectiveConfig()) {
3804 bool insecure_allowed =
3805 dns_client_->CanUseInsecureDnsTransactions() &&
3806 !dns_client_->FallbackFromInsecureTransactionPreferred() &&
3807 (has_address_type ||
3808 dns_client_->CanQueryAdditionalTypesViaInsecureDns());
3809 PushDnsTasks(system_task_allowed, job_key.secure_dns_mode,
3810 insecure_allowed, allow_cache, prioritize_local_lookups,
3811 &*job_key.resolve_context, out_tasks);
3812 } else if (system_task_allowed) {
3813 out_tasks->push_back(TaskType::SYSTEM);
3814 }
3815 } else if (has_address_type) {
3816 // For *.local address queries, try the system resolver even if the
3817 // secure dns mode is SECURE. Public recursive resolvers aren't expected
3818 // to handle these queries.
3819 out_tasks->push_back(TaskType::SYSTEM);
3820 } else {
3821 out_tasks->push_back(TaskType::MDNS);
3822 }
3823 break;
3824 case HostResolverSource::SYSTEM:
3825 out_tasks->push_back(TaskType::SYSTEM);
3826 break;
3827 case HostResolverSource::DNS:
3828 if (dns_client_ && dns_client_->GetEffectiveConfig()) {
3829 bool insecure_allowed =
3830 dns_client_->CanUseInsecureDnsTransactions() &&
3831 (has_address_type ||
3832 dns_client_->CanQueryAdditionalTypesViaInsecureDns());
3833 PushDnsTasks(false /* system_task_allowed */, job_key.secure_dns_mode,
3834 insecure_allowed, allow_cache, prioritize_local_lookups,
3835 &*job_key.resolve_context, out_tasks);
3836 }
3837 break;
3838 case HostResolverSource::MULTICAST_DNS:
3839 out_tasks->push_back(TaskType::MDNS);
3840 break;
3841 case HostResolverSource::LOCAL_ONLY:
3842 // If no external source allowed, a job should not be created or started
3843 break;
3844 }
3845
3846 // `HOST_RESOLVER_CANONNAME` is only supported through system resolution.
3847 if (job_key.flags & HOST_RESOLVER_CANONNAME) {
3848 DCHECK(base::ranges::find(*out_tasks, TaskType::DNS) == out_tasks->end());
3849 DCHECK(base::ranges::find(*out_tasks, TaskType::MDNS) == out_tasks->end());
3850 }
3851 }
3852
GetEffectiveParametersForRequest(const absl::variant<url::SchemeHostPort,std::string> & host,DnsQueryType dns_query_type,HostResolverFlags flags,SecureDnsPolicy secure_dns_policy,bool is_ip,const NetLogWithSource & net_log,DnsQueryTypeSet * out_effective_types,HostResolverFlags * out_effective_flags,SecureDnsMode * out_effective_secure_dns_mode)3853 void HostResolverManager::GetEffectiveParametersForRequest(
3854 const absl::variant<url::SchemeHostPort, std::string>& host,
3855 DnsQueryType dns_query_type,
3856 HostResolverFlags flags,
3857 SecureDnsPolicy secure_dns_policy,
3858 bool is_ip,
3859 const NetLogWithSource& net_log,
3860 DnsQueryTypeSet* out_effective_types,
3861 HostResolverFlags* out_effective_flags,
3862 SecureDnsMode* out_effective_secure_dns_mode) {
3863 const SecureDnsMode secure_dns_mode =
3864 GetEffectiveSecureDnsMode(secure_dns_policy);
3865
3866 *out_effective_secure_dns_mode = secure_dns_mode;
3867 *out_effective_flags = flags | additional_resolver_flags_;
3868
3869 if (dns_query_type != DnsQueryType::UNSPECIFIED) {
3870 *out_effective_types = dns_query_type;
3871 return;
3872 }
3873
3874 DnsQueryTypeSet effective_types(DnsQueryType::A, DnsQueryType::AAAA);
3875
3876 // Disable AAAA queries when we cannot do anything with the results.
3877 bool use_local_ipv6 = true;
3878 if (dns_client_) {
3879 const DnsConfig* config = dns_client_->GetEffectiveConfig();
3880 if (config)
3881 use_local_ipv6 = config->use_local_ipv6;
3882 }
3883 // When resolving IPv4 literals, there's no need to probe for IPv6. When
3884 // resolving IPv6 literals, there's no benefit to artificially limiting our
3885 // resolution based on a probe. Prior logic ensures that this is an automatic
3886 // query, so the code requesting the resolution should be amenable to
3887 // receiving an IPv6 resolution.
3888 if (!use_local_ipv6 && !is_ip && !last_ipv6_probe_result_) {
3889 *out_effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
3890 effective_types.Remove(DnsQueryType::AAAA);
3891 }
3892
3893 // Optimistically enable feature-controlled queries. These queries may be
3894 // skipped at a later point.
3895
3896 // `https_svcb_options_.enable` has precedence, so if enabled, ignore any
3897 // other related features.
3898 if (https_svcb_options_.enable) {
3899 static const char* const kSchemesForHttpsQuery[] = {
3900 url::kHttpScheme, url::kHttpsScheme, url::kWsScheme, url::kWssScheme};
3901 if (base::Contains(kSchemesForHttpsQuery, GetScheme(host)))
3902 effective_types.Put(DnsQueryType::HTTPS);
3903 }
3904
3905 *out_effective_types = effective_types;
3906 }
3907
3908 namespace {
3909
RequestWillUseWiFi(handles::NetworkHandle network)3910 bool RequestWillUseWiFi(handles::NetworkHandle network) {
3911 NetworkChangeNotifier::ConnectionType connection_type;
3912 if (network == handles::kInvalidNetworkHandle)
3913 connection_type = NetworkChangeNotifier::GetConnectionType();
3914 else
3915 connection_type = NetworkChangeNotifier::GetNetworkConnectionType(network);
3916
3917 return connection_type == NetworkChangeNotifier::CONNECTION_WIFI;
3918 }
3919
3920 } // namespace
3921
FinishIPv6ReachabilityCheck(CompletionOnceCallback callback,int rv)3922 void HostResolverManager::FinishIPv6ReachabilityCheck(
3923 CompletionOnceCallback callback,
3924 int rv) {
3925 SetLastIPv6ProbeResult((rv == OK) ? true : false);
3926 std::move(callback).Run(OK);
3927 if (!ipv6_request_callbacks_.empty()) {
3928 std::vector<CompletionOnceCallback> tmp_request_callbacks;
3929 ipv6_request_callbacks_.swap(tmp_request_callbacks);
3930 for (auto& request_callback : tmp_request_callbacks) {
3931 std::move(request_callback).Run(OK);
3932 }
3933 }
3934 }
3935
StartIPv6ReachabilityCheck(const NetLogWithSource & net_log,CompletionOnceCallback callback)3936 int HostResolverManager::StartIPv6ReachabilityCheck(
3937 const NetLogWithSource& net_log,
3938 CompletionOnceCallback callback) {
3939 // Don't bother checking if the request will use WiFi and IPv6 is assumed to
3940 // not work on WiFi.
3941 if (!check_ipv6_on_wifi_ && RequestWillUseWiFi(target_network_)) {
3942 probing_ipv6_ = false;
3943 last_ipv6_probe_result_ = false;
3944 last_ipv6_probe_time_ = base::TimeTicks();
3945 return OK;
3946 }
3947
3948 if (probing_ipv6_) {
3949 ipv6_request_callbacks_.push_back(std::move(callback));
3950 return ERR_IO_PENDING;
3951 }
3952 // Cache the result for kIPv6ProbePeriodMs (measured from after
3953 // StartGloballyReachableCheck() completes).
3954 int rv = OK;
3955 bool cached = true;
3956 if (last_ipv6_probe_time_.is_null() ||
3957 (tick_clock_->NowTicks() - last_ipv6_probe_time_).InMilliseconds() >
3958 kIPv6ProbePeriodMs) {
3959 probing_ipv6_ = true;
3960 rv = StartGloballyReachableCheck(
3961 IPAddress(kIPv6ProbeAddress), net_log,
3962 base::BindOnce(&HostResolverManager::FinishIPv6ReachabilityCheck,
3963 weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
3964 if (rv != ERR_IO_PENDING) {
3965 SetLastIPv6ProbeResult((rv == OK) ? true : false);
3966 rv = OK;
3967 }
3968 cached = false;
3969 }
3970 net_log.AddEvent(
3971 NetLogEventType::HOST_RESOLVER_MANAGER_IPV6_REACHABILITY_CHECK, [&] {
3972 return NetLogIPv6AvailableParams(last_ipv6_probe_result_, cached);
3973 });
3974 return rv;
3975 }
3976
SetLastIPv6ProbeResult(bool last_ipv6_probe_result)3977 void HostResolverManager::SetLastIPv6ProbeResult(bool last_ipv6_probe_result) {
3978 probing_ipv6_ = false;
3979 last_ipv6_probe_result_ = last_ipv6_probe_result;
3980 last_ipv6_probe_time_ = tick_clock_->NowTicks();
3981 }
3982
StartGloballyReachableCheck(const IPAddress & dest,const NetLogWithSource & net_log,CompletionOnceCallback callback)3983 int HostResolverManager::StartGloballyReachableCheck(
3984 const IPAddress& dest,
3985 const NetLogWithSource& net_log,
3986 CompletionOnceCallback callback) {
3987 std::unique_ptr<DatagramClientSocket> probing_socket =
3988 ClientSocketFactory::GetDefaultFactory()->CreateDatagramClientSocket(
3989 DatagramSocket::DEFAULT_BIND, net_log.net_log(), net_log.source());
3990 DatagramClientSocket* probing_socket_ptr = probing_socket.get();
3991 auto refcounted_socket = base::MakeRefCounted<
3992 base::RefCountedData<std::unique_ptr<DatagramClientSocket>>>(
3993 std::move(probing_socket));
3994 int rv = probing_socket_ptr->ConnectAsync(
3995 IPEndPoint(dest, 53),
3996 base::BindOnce(&HostResolverManager::RunFinishGloballyReachableCheck,
3997 weak_ptr_factory_.GetWeakPtr(), refcounted_socket,
3998 std::move(callback)));
3999 if (rv != ERR_IO_PENDING) {
4000 rv = FinishGloballyReachableCheck(probing_socket_ptr, rv) ? OK : ERR_FAILED;
4001 }
4002 return rv;
4003 }
4004
FinishGloballyReachableCheck(DatagramClientSocket * socket,int rv)4005 bool HostResolverManager::FinishGloballyReachableCheck(
4006 DatagramClientSocket* socket,
4007 int rv) {
4008 if (rv != OK) {
4009 return false;
4010 }
4011 IPEndPoint endpoint;
4012 rv = socket->GetLocalAddress(&endpoint);
4013
4014 if (rv != OK) {
4015 return false;
4016 }
4017 const IPAddress& address = endpoint.address();
4018
4019 if (address.IsLinkLocal()) {
4020 return false;
4021 }
4022
4023 if (address.IsIPv6()) {
4024 const uint8_t kTeredoPrefix[] = {0x20, 0x01, 0, 0};
4025 if (IPAddressStartsWith(address, kTeredoPrefix)) {
4026 return false;
4027 }
4028 }
4029
4030 return true;
4031 }
4032
RunFinishGloballyReachableCheck(scoped_refptr<base::RefCountedData<std::unique_ptr<DatagramClientSocket>>> socket,CompletionOnceCallback callback,int rv)4033 void HostResolverManager::RunFinishGloballyReachableCheck(
4034 scoped_refptr<base::RefCountedData<std::unique_ptr<DatagramClientSocket>>>
4035 socket,
4036 CompletionOnceCallback callback,
4037 int rv) {
4038 bool is_reachable = FinishGloballyReachableCheck(socket->data.get(), rv);
4039 std::move(callback).Run(is_reachable ? OK : ERR_FAILED);
4040 }
4041
RunLoopbackProbeJob()4042 void HostResolverManager::RunLoopbackProbeJob() {
4043 // Run this asynchronously as it can take 40-100ms and should not block
4044 // initialization.
4045 base::ThreadPool::PostTaskAndReplyWithResult(
4046 FROM_HERE,
4047 {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
4048 base::BindOnce(&HaveOnlyLoopbackAddresses),
4049 base::BindOnce(&HostResolverManager::SetHaveOnlyLoopbackAddresses,
4050 weak_ptr_factory_.GetWeakPtr()));
4051 }
4052
RemoveAllJobs(const ResolveContext * context)4053 void HostResolverManager::RemoveAllJobs(const ResolveContext* context) {
4054 for (auto it = jobs_.begin(); it != jobs_.end();) {
4055 const JobKey& key = it->first;
4056 if (&*key.resolve_context == context) {
4057 RemoveJob(it++);
4058 } else {
4059 ++it;
4060 }
4061 }
4062 }
4063
AbortJobsWithoutTargetNetwork(bool in_progress_only)4064 void HostResolverManager::AbortJobsWithoutTargetNetwork(bool in_progress_only) {
4065 // In Abort, a Request callback could spawn new Jobs with matching keys, so
4066 // first collect and remove all running jobs from `jobs_`.
4067 std::vector<std::unique_ptr<Job>> jobs_to_abort;
4068 for (auto it = jobs_.begin(); it != jobs_.end();) {
4069 Job* job = it->second.get();
4070 if (!job->HasTargetNetwork() && (!in_progress_only || job->is_running())) {
4071 jobs_to_abort.push_back(RemoveJob(it++));
4072 } else {
4073 ++it;
4074 }
4075 }
4076
4077 // Pause the dispatcher so it won't start any new dispatcher jobs while
4078 // aborting the old ones. This is needed so that it won't start the second
4079 // DnsTransaction for a job in `jobs_to_abort` if the DnsConfig just became
4080 // invalid.
4081 PrioritizedDispatcher::Limits limits = dispatcher_->GetLimits();
4082 dispatcher_->SetLimits(
4083 PrioritizedDispatcher::Limits(limits.reserved_slots.size(), 0));
4084
4085 // Life check to bail once `this` is deleted.
4086 base::WeakPtr<HostResolverManager> self = weak_ptr_factory_.GetWeakPtr();
4087
4088 // Then Abort them.
4089 for (size_t i = 0; self.get() && i < jobs_to_abort.size(); ++i) {
4090 jobs_to_abort[i]->Abort();
4091 }
4092
4093 if (self)
4094 dispatcher_->SetLimits(limits);
4095 }
4096
AbortInsecureDnsTasks(int error,bool fallback_only)4097 void HostResolverManager::AbortInsecureDnsTasks(int error, bool fallback_only) {
4098 // Aborting jobs potentially modifies |jobs_| and may even delete some jobs.
4099 // Create safe closures of all current jobs.
4100 std::vector<base::OnceClosure> job_abort_closures;
4101 for (auto& job : jobs_) {
4102 job_abort_closures.push_back(
4103 job.second->GetAbortInsecureDnsTaskClosure(error, fallback_only));
4104 }
4105
4106 // Pause the dispatcher so it won't start any new dispatcher jobs while
4107 // aborting the old ones. This is needed so that it won't start the second
4108 // DnsTransaction for a job if the DnsConfig just changed.
4109 PrioritizedDispatcher::Limits limits = dispatcher_->GetLimits();
4110 dispatcher_->SetLimits(
4111 PrioritizedDispatcher::Limits(limits.reserved_slots.size(), 0));
4112
4113 for (base::OnceClosure& closure : job_abort_closures)
4114 std::move(closure).Run();
4115
4116 dispatcher_->SetLimits(limits);
4117 }
4118
4119 // TODO(crbug.com/995984): Consider removing this and its usage.
TryServingAllJobsFromHosts()4120 void HostResolverManager::TryServingAllJobsFromHosts() {
4121 if (!dns_client_ || !dns_client_->GetEffectiveConfig())
4122 return;
4123
4124 // TODO(szym): Do not do this if nsswitch.conf instructs not to.
4125 // http://crbug.com/117655
4126
4127 // Life check to bail once |this| is deleted.
4128 base::WeakPtr<HostResolverManager> self = weak_ptr_factory_.GetWeakPtr();
4129
4130 for (auto it = jobs_.begin(); self.get() && it != jobs_.end();) {
4131 Job* job = it->second.get();
4132 ++it;
4133 // This could remove |job| from |jobs_|, but iterator will remain valid.
4134 job->ServeFromHosts();
4135 }
4136 }
4137
OnIPAddressChanged()4138 void HostResolverManager::OnIPAddressChanged() {
4139 DCHECK(!IsBoundToNetwork());
4140 last_ipv6_probe_time_ = base::TimeTicks();
4141 // Abandon all ProbeJobs.
4142 probe_weak_ptr_factory_.InvalidateWeakPtrs();
4143 InvalidateCaches();
4144 #if (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID)) || \
4145 BUILDFLAG(IS_FUCHSIA)
4146 RunLoopbackProbeJob();
4147 #endif
4148 AbortJobsWithoutTargetNetwork(true /* in_progress_only */);
4149 // `this` may be deleted inside AbortJobsWithoutTargetNetwork().
4150 }
4151
OnConnectionTypeChanged(NetworkChangeNotifier::ConnectionType type)4152 void HostResolverManager::OnConnectionTypeChanged(
4153 NetworkChangeNotifier::ConnectionType type) {
4154 DCHECK(!IsBoundToNetwork());
4155 UpdateConnectionType(type);
4156 }
4157
OnSystemDnsConfigChanged(absl::optional<DnsConfig> config)4158 void HostResolverManager::OnSystemDnsConfigChanged(
4159 absl::optional<DnsConfig> config) {
4160 DCHECK(!IsBoundToNetwork());
4161 // If tests have provided a catch-all DNS block and then disabled it, check
4162 // that we are not at risk of sending queries beyond the local network.
4163 if (HostResolverProc::GetDefault() && system_resolver_disabled_for_testing_ &&
4164 config.has_value()) {
4165 DCHECK(base::ranges::none_of(config->nameservers,
4166 &IPAddress::IsPubliclyRoutable,
4167 &IPEndPoint::address))
4168 << "Test could query a publicly-routable address.";
4169 }
4170
4171 bool changed = false;
4172 bool transactions_allowed_before = false;
4173 if (dns_client_) {
4174 transactions_allowed_before = dns_client_->CanUseSecureDnsTransactions() ||
4175 dns_client_->CanUseInsecureDnsTransactions();
4176 changed = dns_client_->SetSystemConfig(std::move(config));
4177 }
4178
4179 // Always invalidate cache, even if no change is seen.
4180 InvalidateCaches();
4181
4182 if (changed) {
4183 // Need to update jobs iff transactions were previously allowed because
4184 // in-progress jobs may be running using a now-invalid configuration.
4185 if (transactions_allowed_before)
4186 UpdateJobsForChangedConfig();
4187 }
4188 }
4189
UpdateJobsForChangedConfig()4190 void HostResolverManager::UpdateJobsForChangedConfig() {
4191 // Life check to bail once `this` is deleted.
4192 base::WeakPtr<HostResolverManager> self = weak_ptr_factory_.GetWeakPtr();
4193
4194 // Existing jobs that were set up using the nameservers and secure dns mode
4195 // from the original config need to be aborted (does not apply to jobs
4196 // targeting a specific network).
4197 AbortJobsWithoutTargetNetwork(false /* in_progress_only */);
4198
4199 // `this` may be deleted inside AbortJobsWithoutTargetNetwork().
4200 if (self.get())
4201 TryServingAllJobsFromHosts();
4202 }
4203
OnFallbackResolve(int dns_task_error)4204 void HostResolverManager::OnFallbackResolve(int dns_task_error) {
4205 DCHECK(dns_client_);
4206 DCHECK_NE(OK, dns_task_error);
4207
4208 // Nothing to do if DnsTask is already not preferred.
4209 if (dns_client_->FallbackFromInsecureTransactionPreferred())
4210 return;
4211
4212 dns_client_->IncrementInsecureFallbackFailures();
4213
4214 // If DnsClient became not preferred, fallback all fallback-allowed insecure
4215 // DnsTasks to HostResolverSystemTasks.
4216 if (dns_client_->FallbackFromInsecureTransactionPreferred())
4217 AbortInsecureDnsTasks(ERR_FAILED, true /* fallback_only */);
4218 }
4219
GetOrCreateMdnsClient(MDnsClient ** out_client)4220 int HostResolverManager::GetOrCreateMdnsClient(MDnsClient** out_client) {
4221 #if BUILDFLAG(ENABLE_MDNS)
4222 if (!mdns_client_) {
4223 if (!mdns_socket_factory_)
4224 mdns_socket_factory_ = std::make_unique<MDnsSocketFactoryImpl>(net_log_);
4225 mdns_client_ = MDnsClient::CreateDefault();
4226 }
4227
4228 int rv = OK;
4229 if (!mdns_client_->IsListening())
4230 rv = mdns_client_->StartListening(mdns_socket_factory_.get());
4231
4232 DCHECK_NE(ERR_IO_PENDING, rv);
4233 DCHECK(rv != OK || mdns_client_->IsListening());
4234 if (rv == OK)
4235 *out_client = mdns_client_.get();
4236 return rv;
4237 #else
4238 // Should not request MDNS resoltuion unless MDNS is enabled.
4239 NOTREACHED();
4240 return ERR_UNEXPECTED;
4241 #endif
4242 }
4243
InvalidateCaches(bool network_change)4244 void HostResolverManager::InvalidateCaches(bool network_change) {
4245 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
4246 DCHECK(!invalidation_in_progress_);
4247
4248 #if DCHECK_IS_ON()
4249 base::WeakPtr<HostResolverManager> self_ptr = weak_ptr_factory_.GetWeakPtr();
4250 size_t num_jobs = jobs_.size();
4251 #endif
4252
4253 invalidation_in_progress_ = true;
4254 for (auto& context : registered_contexts_) {
4255 context.InvalidateCachesAndPerSessionData(
4256 dns_client_ ? dns_client_->GetCurrentSession() : nullptr,
4257 network_change);
4258 }
4259 invalidation_in_progress_ = false;
4260
4261 #if DCHECK_IS_ON()
4262 // Sanity checks that invalidation does not have reentrancy issues.
4263 DCHECK(self_ptr);
4264 DCHECK_EQ(num_jobs, jobs_.size());
4265 #endif
4266 }
4267
UpdateConnectionType(NetworkChangeNotifier::ConnectionType type)4268 void HostResolverManager::UpdateConnectionType(
4269 NetworkChangeNotifier::ConnectionType type) {
4270 host_resolver_system_params_.unresponsive_delay =
4271 GetTimeDeltaForConnectionTypeFromFieldTrialOrDefault(
4272 "DnsUnresponsiveDelayMsByConnectionType",
4273 HostResolverSystemTask::Params::kDnsDefaultUnresponsiveDelay, type);
4274
4275 // Note that NetworkChangeNotifier always sends a CONNECTION_NONE notification
4276 // before non-NONE notifications. This check therefore just ensures each
4277 // connection change notification is handled once and has nothing to do with
4278 // whether the change is to offline or online.
4279 if (type == NetworkChangeNotifier::CONNECTION_NONE && dns_client_) {
4280 dns_client_->ReplaceCurrentSession();
4281 InvalidateCaches(true /* network_change */);
4282 }
4283 }
4284
CreateDohProbeRunner(ResolveContext * resolve_context)4285 std::unique_ptr<DnsProbeRunner> HostResolverManager::CreateDohProbeRunner(
4286 ResolveContext* resolve_context) {
4287 DCHECK(resolve_context);
4288 DCHECK(registered_contexts_.HasObserver(resolve_context));
4289 if (!dns_client_ || !dns_client_->CanUseSecureDnsTransactions()) {
4290 return nullptr;
4291 }
4292
4293 return dns_client_->GetTransactionFactory()->CreateDohProbeRunner(
4294 resolve_context);
4295 }
4296
~RequestImpl()4297 HostResolverManager::RequestImpl::~RequestImpl() {
4298 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
4299 if (!job_.has_value())
4300 return;
4301
4302 job_.value()->CancelRequest(this);
4303 LogCancelRequest();
4304 }
4305
ChangeRequestPriority(RequestPriority priority)4306 void HostResolverManager::RequestImpl::ChangeRequestPriority(
4307 RequestPriority priority) {
4308 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
4309 if (!job_.has_value()) {
4310 priority_ = priority;
4311 return;
4312 }
4313 job_.value()->ChangeRequestPriority(this, priority);
4314 }
4315
GetJobKey() const4316 const HostResolverManager::JobKey& HostResolverManager::RequestImpl::GetJobKey()
4317 const {
4318 CHECK(job_.has_value());
4319 return job_.value()->key();
4320 }
4321
OnJobCancelled(const JobKey & job_key)4322 void HostResolverManager::RequestImpl::OnJobCancelled(const JobKey& job_key) {
4323 CHECK(job_.has_value());
4324 CHECK(job_key == job_.value()->key());
4325 job_.reset();
4326 DCHECK(!complete_);
4327 DCHECK(callback_);
4328 callback_.Reset();
4329
4330 // No results should be set.
4331 DCHECK(!results_);
4332
4333 LogCancelRequest();
4334 }
4335
OnJobCompleted(const JobKey & job_key,int error,bool is_secure_network_error)4336 void HostResolverManager::RequestImpl::OnJobCompleted(
4337 const JobKey& job_key,
4338 int error,
4339 bool is_secure_network_error) {
4340 set_error_info(error, is_secure_network_error);
4341
4342 CHECK(job_.has_value());
4343 CHECK(job_key == job_.value()->key());
4344 job_.reset();
4345
4346 DCHECK(!complete_);
4347 complete_ = true;
4348
4349 LogFinishRequest(error, true /* async_completion */);
4350
4351 DCHECK(callback_);
4352 std::move(callback_).Run(HostResolver::SquashErrorCode(error));
4353 }
4354
4355 } // namespace net
4356