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