xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_manager_job.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2024 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_job.h"
6 
7 #include <deque>
8 #include <memory>
9 #include <optional>
10 #include <vector>
11 
12 #include "base/containers/linked_list.h"
13 #include "base/memory/raw_ptr.h"
14 #include "base/memory/safe_ref.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/metrics/histogram_functions.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/task/sequenced_task_runner.h"
19 #include "base/time/time.h"
20 #include "net/base/address_family.h"
21 #include "net/base/features.h"
22 #include "net/base/network_anonymization_key.h"
23 #include "net/base/network_handle.h"
24 #include "net/base/prioritized_dispatcher.h"
25 #include "net/base/url_util.h"
26 #include "net/dns/dns_client.h"
27 #include "net/dns/dns_task_results_manager.h"
28 #include "net/dns/host_cache.h"
29 #include "net/dns/host_resolver.h"
30 #include "net/dns/host_resolver_dns_task.h"
31 #include "net/dns/host_resolver_manager.h"
32 #include "net/dns/host_resolver_manager_request_impl.h"
33 #include "net/dns/host_resolver_manager_service_endpoint_request_impl.h"
34 #include "net/dns/host_resolver_mdns_task.h"
35 #include "net/dns/host_resolver_nat64_task.h"
36 #include "net/dns/public/dns_query_type.h"
37 #include "net/dns/public/secure_dns_mode.h"
38 #include "net/log/net_log_with_source.h"
39 #include "third_party/abseil-cpp/absl/types/variant.h"
40 #include "url/url_constants.h"
41 
42 namespace net {
43 
44 namespace {
45 
46 // Default TTL for successful resolutions with HostResolverSystemTask.
47 const unsigned kCacheEntryTTLSeconds = 60;
48 
49 // Default TTL for unsuccessful resolutions with HostResolverSystemTask.
50 const unsigned kNegativeCacheEntryTTLSeconds = 0;
51 
52 // Minimum TTL for successful resolutions with HostResolverDnsTask.
53 const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds;
54 
55 // ICANN uses this localhost address to indicate a name collision.
56 //
57 // The policy in Chromium is to fail host resolving if it resolves to
58 // this special address.
59 //
60 // Not however that IP literals are exempt from this policy, so it is still
61 // possible to navigate to http://127.0.53.53/ directly.
62 //
63 // For more details: https://www.icann.org/news/announcement-2-2014-08-01-en
64 const uint8_t kIcanNameCollisionIp[] = {127, 0, 53, 53};
65 
ContainsIcannNameCollisionIp(const std::vector<IPEndPoint> & endpoints)66 bool ContainsIcannNameCollisionIp(const std::vector<IPEndPoint>& endpoints) {
67   for (const auto& endpoint : endpoints) {
68     const IPAddress& addr = endpoint.address();
69     if (addr.IsIPv4() && IPAddressStartsWith(addr, kIcanNameCollisionIp)) {
70       return true;
71     }
72   }
73   return false;
74 }
75 
76 // Creates NetLog parameters for HOST_RESOLVER_MANAGER_JOB_ATTACH/DETACH events.
NetLogJobAttachParams(const NetLogSource & source,RequestPriority priority)77 base::Value::Dict NetLogJobAttachParams(const NetLogSource& source,
78                                         RequestPriority priority) {
79   base::Value::Dict dict;
80   source.AddToEventParameters(dict);
81   dict.Set("priority", RequestPriorityToString(priority));
82   return dict;
83 }
84 
IsSchemeHttpsOrWss(const HostResolver::Host & host)85 bool IsSchemeHttpsOrWss(const HostResolver::Host& host) {
86   if (!host.HasScheme()) {
87     return false;
88   }
89   const std::string& scheme = host.GetScheme();
90   return scheme == url::kHttpsScheme || scheme == url::kWssScheme;
91 }
92 
93 }  // namespace
94 
JobKey(HostResolver::Host host,ResolveContext * resolve_context)95 HostResolverManager::JobKey::JobKey(HostResolver::Host host,
96                                     ResolveContext* resolve_context)
97     : host(std::move(host)), resolve_context(resolve_context->GetWeakPtr()) {}
98 
99 HostResolverManager::JobKey::~JobKey() = default;
100 
101 HostResolverManager::JobKey::JobKey(const JobKey& other) = default;
102 HostResolverManager::JobKey& HostResolverManager::JobKey::operator=(
103     const JobKey& other) = default;
104 
operator <(const JobKey & other) const105 bool HostResolverManager::JobKey::operator<(const JobKey& other) const {
106   return std::forward_as_tuple(query_types.ToEnumBitmask(), flags, source,
107                                secure_dns_mode, &*resolve_context, host,
108                                network_anonymization_key) <
109          std::forward_as_tuple(other.query_types.ToEnumBitmask(), other.flags,
110                                other.source, other.secure_dns_mode,
111                                &*other.resolve_context, other.host,
112                                other.network_anonymization_key);
113 }
114 
operator ==(const JobKey & other) const115 bool HostResolverManager::JobKey::operator==(const JobKey& other) const {
116   return !(*this < other || other < *this);
117 }
118 
ToCacheKey(bool secure) const119 HostCache::Key HostResolverManager::JobKey::ToCacheKey(bool secure) const {
120   if (query_types.size() != 1) {
121     // This function will produce identical cache keys for `JobKey` structs
122     // that differ only in their (non-singleton) `query_types` fields. When we
123     // enable new query types, this behavior could lead to subtle bugs. That
124     // is why the following DCHECK restricts the allowable query types.
125     DCHECK(Difference(query_types, {DnsQueryType::A, DnsQueryType::AAAA,
126                                     DnsQueryType::HTTPS})
127                .empty());
128   }
129   const DnsQueryType query_type_for_key = query_types.size() == 1
130                                               ? *query_types.begin()
131                                               : DnsQueryType::UNSPECIFIED;
132   absl::variant<url::SchemeHostPort, std::string> host_for_cache;
133   if (host.HasScheme()) {
134     host_for_cache = host.AsSchemeHostPort();
135   } else {
136     host_for_cache = std::string(host.GetHostnameWithoutBrackets());
137   }
138   HostCache::Key key(std::move(host_for_cache), query_type_for_key, flags,
139                      source, network_anonymization_key);
140   key.secure = secure;
141   return key;
142 }
143 
GetTargetNetwork() const144 handles::NetworkHandle HostResolverManager::JobKey::GetTargetNetwork() const {
145   return resolve_context ? resolve_context->GetTargetNetwork()
146                          : handles::kInvalidNetworkHandle;
147 }
148 
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)149 HostResolverManager::Job::Job(
150     const base::WeakPtr<HostResolverManager>& resolver,
151     JobKey key,
152     ResolveHostParameters::CacheUsage cache_usage,
153     HostCache* host_cache,
154     std::deque<TaskType> tasks,
155     RequestPriority priority,
156     const NetLogWithSource& source_net_log,
157     const base::TickClock* tick_clock,
158     const HostResolver::HttpsSvcbOptions& https_svcb_options)
159     : resolver_(resolver),
160       key_(std::move(key)),
161       cache_usage_(cache_usage),
162       host_cache_(host_cache),
163       tasks_(tasks),
164       priority_tracker_(priority),
165       tick_clock_(tick_clock),
166       https_svcb_options_(https_svcb_options),
167       net_log_(
168           NetLogWithSource::Make(source_net_log.net_log(),
169                                  NetLogSourceType::HOST_RESOLVER_IMPL_JOB)) {
170   source_net_log.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_CREATE_JOB);
171 
172   net_log_.BeginEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB, [&] {
173     return NetLogJobCreationParams(source_net_log.source());
174   });
175 }
176 
~Job()177 HostResolverManager::Job::~Job() {
178   bool was_queued = is_queued();
179   bool was_running = is_running();
180   // Clean up now for nice NetLog.
181   Finish();
182   if (was_running) {
183     // This Job was destroyed while still in flight.
184     net_log_.EndEventWithNetErrorCode(
185         NetLogEventType::HOST_RESOLVER_MANAGER_JOB, ERR_ABORTED);
186   } else if (was_queued) {
187     // Job was cancelled before it could run.
188     // TODO(szym): is there any benefit in having this distinction?
189     net_log_.AddEvent(NetLogEventType::CANCELLED);
190     net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB);
191   }
192   // else CompleteRequests logged EndEvent.
193   while (!requests_.empty()) {
194     // Log any remaining Requests as cancelled.
195     RequestImpl* req = requests_.head()->value();
196     req->RemoveFromList();
197     CHECK(key_ == req->GetJobKey());
198     req->OnJobCancelled(key_);
199   }
200 
201   while (!service_endpoint_requests_.empty()) {
202     ServiceEndpointRequestImpl* request =
203         service_endpoint_requests_.head()->value();
204     request->RemoveFromList();
205     request->OnJobCancelled();
206   }
207 }
208 
Schedule(bool at_head)209 void HostResolverManager::Job::Schedule(bool at_head) {
210   DCHECK(!is_queued());
211   PrioritizedDispatcher::Handle handle;
212   DCHECK(dispatched_);
213   if (!at_head) {
214     handle = resolver_->dispatcher_->Add(this, priority());
215   } else {
216     handle = resolver_->dispatcher_->AddAtHead(this, priority());
217   }
218   // The dispatcher could have started |this| in the above call to Add, which
219   // could have called Schedule again. In that case |handle| will be null,
220   // but |handle_| may have been set by the other nested call to Schedule.
221   if (!handle.is_null()) {
222     DCHECK(handle_.is_null());
223     handle_ = handle;
224   }
225 }
226 
AddRequest(RequestImpl * request)227 void HostResolverManager::Job::AddRequest(RequestImpl* request) {
228   // Job currently assumes a 1:1 correspondence between ResolveContext and
229   // HostCache. Since the ResolveContext is part of the JobKey, any request
230   // added to any existing Job should share the same HostCache.
231   DCHECK_EQ(host_cache_, request->host_cache());
232   // TODO(crbug.com/1206799): Check equality of whole host once Jobs are
233   // separated by scheme/port.
234   DCHECK_EQ(key_.host.GetHostnameWithoutBrackets(),
235             request->request_host().GetHostnameWithoutBrackets());
236 
237   request->AssignJob(weak_ptr_factory_.GetSafeRef());
238 
239   AddRequestCommon(request->priority(), request->source_net_log(),
240                    request->parameters().is_speculative);
241 
242   requests_.Append(request);
243 
244   UpdatePriority();
245 }
246 
ChangeRequestPriority(RequestImpl * req,RequestPriority priority)247 void HostResolverManager::Job::ChangeRequestPriority(RequestImpl* req,
248                                                      RequestPriority priority) {
249   DCHECK_EQ(key_.host, req->request_host());
250 
251   priority_tracker_.Remove(req->priority());
252   req->set_priority(priority);
253   priority_tracker_.Add(req->priority());
254   UpdatePriority();
255 }
256 
CancelRequest(RequestImpl * request)257 void HostResolverManager::Job::CancelRequest(RequestImpl* request) {
258   DCHECK_EQ(key_.host, request->request_host());
259   DCHECK(!requests_.empty());
260 
261   CancelRequestCommon(request->priority(), request->source_net_log());
262 
263   if (num_active_requests() > 0) {
264     UpdatePriority();
265     request->RemoveFromList();
266   } else {
267     // If we were called from a Request's callback within CompleteRequests,
268     // that Request could not have been cancelled, so num_active_requests()
269     // could not be 0. Therefore, we are not in CompleteRequests().
270     CompleteRequestsWithError(ERR_DNS_REQUEST_CANCELLED,
271                               /*task_type=*/std::nullopt);
272   }
273 }
274 
AddServiceEndpointRequest(ServiceEndpointRequestImpl * request)275 void HostResolverManager::Job::AddServiceEndpointRequest(
276     ServiceEndpointRequestImpl* request) {
277   CHECK_EQ(host_cache_, request->host_cache());
278 
279   request->AssignJob(weak_ptr_factory_.GetSafeRef());
280 
281   AddRequestCommon(request->priority(), request->net_log(),
282                    request->parameters().is_speculative);
283 
284   service_endpoint_requests_.Append(request);
285 
286   UpdatePriority();
287 }
288 
CancelServiceEndpointRequest(ServiceEndpointRequestImpl * request)289 void HostResolverManager::Job::CancelServiceEndpointRequest(
290     ServiceEndpointRequestImpl* request) {
291   CancelRequestCommon(request->priority(), request->net_log());
292 
293   if (num_active_requests() > 0) {
294     UpdatePriority();
295     request->RemoveFromList();
296   } else {
297     // See comments in CancelRequest().
298     CompleteRequestsWithError(ERR_DNS_REQUEST_CANCELLED,
299                               /*task_type=*/std::nullopt);
300   }
301 }
302 
Abort()303 void HostResolverManager::Job::Abort() {
304   CompleteRequestsWithError(ERR_NETWORK_CHANGED, /*task_type=*/std::nullopt);
305 }
306 
GetAbortInsecureDnsTaskClosure(int error,bool fallback_only)307 base::OnceClosure HostResolverManager::Job::GetAbortInsecureDnsTaskClosure(
308     int error,
309     bool fallback_only) {
310   return base::BindOnce(&Job::AbortInsecureDnsTask,
311                         weak_ptr_factory_.GetWeakPtr(), error, fallback_only);
312 }
313 
AbortInsecureDnsTask(int error,bool fallback_only)314 void HostResolverManager::Job::AbortInsecureDnsTask(int error,
315                                                     bool fallback_only) {
316   bool has_system_fallback = base::Contains(tasks_, TaskType::SYSTEM);
317   if (has_system_fallback) {
318     for (auto it = tasks_.begin(); it != tasks_.end();) {
319       if (*it == TaskType::DNS) {
320         it = tasks_.erase(it);
321       } else {
322         ++it;
323       }
324     }
325   }
326 
327   if (dns_task_ && !dns_task_->secure()) {
328     if (has_system_fallback) {
329       KillDnsTask();
330       dns_task_error_ = OK;
331       RunNextTask();
332     } else if (!fallback_only) {
333       CompleteRequestsWithError(error, /*task_type=*/std::nullopt);
334     }
335   }
336 }
337 
OnEvicted()338 void HostResolverManager::Job::OnEvicted() {
339   DCHECK(!is_running());
340   DCHECK(is_queued());
341   handle_.Reset();
342 
343   net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_EVICTED);
344 
345   // This signals to CompleteRequests that parts of this job never ran.
346   // Job must be saved in |resolver_| to be completed asynchronously.
347   // Otherwise the job will be destroyed with requests silently cancelled
348   // before completion runs.
349   DCHECK(self_iterator_);
350   base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
351       FROM_HERE, base::BindOnce(&Job::CompleteRequestsWithError,
352                                 weak_ptr_factory_.GetWeakPtr(),
353                                 ERR_HOST_RESOLVER_QUEUE_TOO_LARGE,
354                                 /*task_type=*/std::nullopt));
355 }
356 
ServeFromHosts()357 bool HostResolverManager::Job::ServeFromHosts() {
358   DCHECK_GT(num_active_requests(), 0u);
359   std::optional<HostCache::Entry> results = resolver_->ServeFromHosts(
360       key_.host.GetHostnameWithoutBrackets(), key_.query_types,
361       key_.flags & HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6, tasks_);
362   if (results) {
363     // This will destroy the Job.
364     CompleteRequests(results.value(), base::TimeDelta(), true /* allow_cache */,
365                      true /* secure */, TaskType::HOSTS);
366     return true;
367   }
368   return false;
369 }
370 
OnAddedToJobMap(JobMap::iterator iterator)371 void HostResolverManager::Job::OnAddedToJobMap(JobMap::iterator iterator) {
372   DCHECK(!self_iterator_);
373   DCHECK(iterator != resolver_->jobs_.end());
374   self_iterator_ = iterator;
375 }
376 
OnRemovedFromJobMap()377 void HostResolverManager::Job::OnRemovedFromJobMap() {
378   DCHECK(self_iterator_);
379   self_iterator_ = std::nullopt;
380 }
381 
RunNextTask()382 void HostResolverManager::Job::RunNextTask() {
383   // If there are no tasks left to try, cache any stored results and complete
384   // the request with the last stored result. All stored results should be
385   // errors.
386   if (tasks_.empty()) {
387     // If there are no stored results, complete with an error.
388     if (completion_results_.size() == 0) {
389       CompleteRequestsWithError(ERR_NAME_NOT_RESOLVED,
390                                 /*task_type=*/std::nullopt);
391       return;
392     }
393 
394     // Cache all but the last result here. The last result will be cached
395     // as part of CompleteRequests.
396     for (size_t i = 0; i < completion_results_.size() - 1; ++i) {
397       const auto& result = completion_results_[i];
398       DCHECK_NE(OK, result.entry.error());
399       MaybeCacheResult(result.entry, result.ttl, result.secure);
400     }
401     const auto& last_result = completion_results_.back();
402     DCHECK_NE(OK, last_result.entry.error());
403     CompleteRequests(last_result.entry, last_result.ttl, true /* allow_cache */,
404                      last_result.secure,
405                      last_result.secure ? TaskType::SECURE_DNS : TaskType::DNS);
406     return;
407   }
408 
409   TaskType next_task = tasks_.front();
410 
411   // Schedule insecure DnsTasks and HostResolverSystemTasks with the
412   // dispatcher.
413   if (!dispatched_ &&
414       (next_task == TaskType::DNS || next_task == TaskType::SYSTEM ||
415        next_task == TaskType::MDNS)) {
416     dispatched_ = true;
417     job_running_ = false;
418     Schedule(false);
419     DCHECK(is_running() || is_queued());
420 
421     // Check for queue overflow.
422     PrioritizedDispatcher& dispatcher = *resolver_->dispatcher_;
423     if (dispatcher.num_queued_jobs() > resolver_->max_queued_jobs_) {
424       Job* evicted = static_cast<Job*>(dispatcher.EvictOldestLowest());
425       DCHECK(evicted);
426       evicted->OnEvicted();
427     }
428     return;
429   }
430 
431   if (start_time_ == base::TimeTicks()) {
432     net_log_.AddEvent(NetLogEventType::HOST_RESOLVER_MANAGER_JOB_STARTED);
433     start_time_ = tick_clock_->NowTicks();
434   }
435   tasks_.pop_front();
436   job_running_ = true;
437 
438   switch (next_task) {
439     case TaskType::SYSTEM:
440       StartSystemTask();
441       break;
442     case TaskType::DNS:
443       StartDnsTask(false /* secure */);
444       break;
445     case TaskType::SECURE_DNS:
446       StartDnsTask(true /* secure */);
447       break;
448     case TaskType::MDNS:
449       StartMdnsTask();
450       break;
451     case TaskType::INSECURE_CACHE_LOOKUP:
452       InsecureCacheLookup();
453       break;
454     case TaskType::NAT64:
455       StartNat64Task();
456       break;
457     case TaskType::SECURE_CACHE_LOOKUP:
458     case TaskType::CACHE_LOOKUP:
459     case TaskType::CONFIG_PRESET:
460     case TaskType::HOSTS:
461       // These task types should have been handled synchronously in
462       // ResolveLocally() prior to Job creation.
463       NOTREACHED();
464       break;
465   }
466 }
467 
NetLogJobCreationParams(const NetLogSource & source)468 base::Value::Dict HostResolverManager::Job::NetLogJobCreationParams(
469     const NetLogSource& source) {
470   base::Value::Dict dict;
471   source.AddToEventParameters(dict);
472   dict.Set("host", key_.host.ToString());
473   base::Value::List query_types_list;
474   for (DnsQueryType query_type : key_.query_types) {
475     query_types_list.Append(kDnsQueryTypes.at(query_type));
476   }
477   dict.Set("dns_query_types", std::move(query_types_list));
478   dict.Set("secure_dns_mode", base::strict_cast<int>(key_.secure_dns_mode));
479   dict.Set("network_anonymization_key",
480            key_.network_anonymization_key.ToDebugString());
481   return dict;
482 }
483 
Finish()484 void HostResolverManager::Job::Finish() {
485   if (is_running()) {
486     // Clean up but don't run any callbacks.
487     system_task_ = nullptr;
488     KillDnsTask();
489     mdns_task_ = nullptr;
490     job_running_ = false;
491 
492     if (dispatched_) {
493       // Job should only ever occupy one slot after any tasks that may have
494       // required additional slots, e.g. DnsTask, have been killed, and
495       // additional slots are expected to be vacated as part of killing the
496       // task.
497       DCHECK_EQ(1, num_occupied_job_slots_);
498       if (resolver_) {
499         resolver_->dispatcher_->OnJobFinished();
500       }
501       num_occupied_job_slots_ = 0;
502     }
503   } else if (is_queued()) {
504     DCHECK(dispatched_);
505     if (resolver_) {
506       resolver_->dispatcher_->Cancel(handle_);
507     }
508     handle_.Reset();
509   }
510 }
511 
KillDnsTask()512 void HostResolverManager::Job::KillDnsTask() {
513   if (dns_task_) {
514     if (dispatched_) {
515       while (num_occupied_job_slots_ > 1 || is_queued()) {
516         ReduceByOneJobSlot();
517       }
518     }
519     dns_task_.reset();
520   }
521   dns_task_results_manager_.reset();
522 }
523 
ReduceByOneJobSlot()524 void HostResolverManager::Job::ReduceByOneJobSlot() {
525   DCHECK_GE(num_occupied_job_slots_, 1);
526   DCHECK(dispatched_);
527   if (is_queued()) {
528     if (resolver_) {
529       resolver_->dispatcher_->Cancel(handle_);
530     }
531     handle_.Reset();
532   } else if (num_occupied_job_slots_ > 1) {
533     if (resolver_) {
534       resolver_->dispatcher_->OnJobFinished();
535     }
536     --num_occupied_job_slots_;
537   } else {
538     NOTREACHED();
539   }
540 }
541 
AddRequestCommon(RequestPriority request_priority,const NetLogWithSource & request_net_log,bool is_speculative)542 void HostResolverManager::Job::AddRequestCommon(
543     RequestPriority request_priority,
544     const NetLogWithSource& request_net_log,
545     bool is_speculative) {
546   priority_tracker_.Add(request_priority);
547   request_net_log.AddEventReferencingSource(
548       NetLogEventType::HOST_RESOLVER_MANAGER_JOB_ATTACH, net_log_.source());
549   net_log_.AddEvent(
550       NetLogEventType::HOST_RESOLVER_MANAGER_JOB_REQUEST_ATTACH, [&] {
551         return NetLogJobAttachParams(request_net_log.source(), priority());
552       });
553   if (!is_speculative) {
554     had_non_speculative_request_ = true;
555   }
556 }
557 
CancelRequestCommon(RequestPriority request_priority,const NetLogWithSource & request_net_log)558 void HostResolverManager::Job::CancelRequestCommon(
559     RequestPriority request_priority,
560     const NetLogWithSource& request_net_log) {
561   priority_tracker_.Remove(request_priority);
562   net_log_.AddEvent(
563       NetLogEventType::HOST_RESOLVER_MANAGER_JOB_REQUEST_DETACH, [&] {
564         return NetLogJobAttachParams(request_net_log.source(), priority());
565       });
566 }
567 
UpdatePriority()568 void HostResolverManager::Job::UpdatePriority() {
569   if (is_queued()) {
570     handle_ = resolver_->dispatcher_->ChangePriority(handle_, priority());
571   }
572 }
573 
Start()574 void HostResolverManager::Job::Start() {
575   handle_.Reset();
576   ++num_occupied_job_slots_;
577 
578   if (num_occupied_job_slots_ >= 2) {
579     if (!dns_task_) {
580       resolver_->dispatcher_->OnJobFinished();
581       return;
582     }
583     StartNextDnsTransaction();
584     DCHECK_EQ(num_occupied_job_slots_,
585               dns_task_->num_transactions_in_progress());
586     if (dns_task_->num_additional_transactions_needed() >= 1) {
587       Schedule(true);
588     }
589     return;
590   }
591 
592   DCHECK(!is_running());
593   DCHECK(!tasks_.empty());
594   RunNextTask();
595   // Caution: Job::Start must not complete synchronously.
596 }
597 
StartSystemTask()598 void HostResolverManager::Job::StartSystemTask() {
599   DCHECK(dispatched_);
600   DCHECK_EQ(1, num_occupied_job_slots_);
601   DCHECK(HasAddressType(key_.query_types));
602 
603   system_task_ = HostResolverSystemTask::Create(
604       std::string(key_.host.GetHostnameWithoutBrackets()),
605       HostResolver::DnsQueryTypeSetToAddressFamily(key_.query_types),
606       key_.flags, resolver_->host_resolver_system_params_, net_log_,
607       key_.GetTargetNetwork());
608 
609   // Start() could be called from within Resolve(), hence it must NOT directly
610   // call OnSystemTaskComplete, for example, on synchronous failure.
611   system_task_->Start(base::BindOnce(&Job::OnSystemTaskComplete,
612                                      base::Unretained(this),
613                                      tick_clock_->NowTicks()));
614 }
615 
OnSystemTaskComplete(base::TimeTicks start_time,const AddressList & addr_list,int,int net_error)616 void HostResolverManager::Job::OnSystemTaskComplete(
617     base::TimeTicks start_time,
618     const AddressList& addr_list,
619     int /*os_error*/,
620     int net_error) {
621   DCHECK(system_task_);
622 
623   base::TimeDelta duration = tick_clock_->NowTicks() - start_time;
624   if (net_error == OK) {
625     UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.SystemTask.SuccessTime", duration);
626   } else {
627     UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.SystemTask.FailureTime", duration);
628   }
629 
630   if (dns_task_error_ != OK && net_error == OK) {
631     // This HostResolverSystemTask was a fallback resolution after a failed
632     // insecure DnsTask.
633     resolver_->OnFallbackResolve(dns_task_error_);
634   }
635 
636   if (ContainsIcannNameCollisionIp(addr_list.endpoints())) {
637     net_error = ERR_ICANN_NAME_COLLISION;
638   }
639 
640   base::TimeDelta ttl = base::Seconds(kNegativeCacheEntryTTLSeconds);
641   if (net_error == OK) {
642     ttl = base::Seconds(kCacheEntryTTLSeconds);
643   }
644 
645   auto aliases = std::set<std::string>(addr_list.dns_aliases().begin(),
646                                        addr_list.dns_aliases().end());
647 
648   // Source unknown because the system resolver could have gotten it from a
649   // hosts file, its own cache, a DNS lookup or somewhere else.
650   // Don't store the |ttl| in cache since it's not obtained from the server.
651   CompleteRequests(
652       HostCache::Entry(
653           net_error,
654           net_error == OK ? addr_list.endpoints() : std::vector<IPEndPoint>(),
655           std::move(aliases), HostCache::Entry::SOURCE_UNKNOWN),
656       ttl, /*allow_cache=*/true, /*secure=*/false, TaskType::SYSTEM);
657 }
658 
InsecureCacheLookup()659 void HostResolverManager::Job::InsecureCacheLookup() {
660   // Insecure cache lookups for requests allowing stale results should have
661   // occurred prior to Job creation.
662   DCHECK(cache_usage_ != ResolveHostParameters::CacheUsage::STALE_ALLOWED);
663   std::optional<HostCache::EntryStaleness> stale_info;
664   std::optional<HostCache::Entry> resolved = resolver_->MaybeServeFromCache(
665       host_cache_, key_.ToCacheKey(/*secure=*/false), cache_usage_,
666       false /* ignore_secure */, net_log_, &stale_info);
667 
668   if (resolved) {
669     DCHECK(stale_info);
670     DCHECK(!stale_info.value().is_stale());
671     CompleteRequestsWithoutCache(resolved.value(), std::move(stale_info),
672                                  TaskType::INSECURE_CACHE_LOOKUP);
673   } else {
674     RunNextTask();
675   }
676 }
677 
StartDnsTask(bool secure)678 void HostResolverManager::Job::StartDnsTask(bool secure) {
679   DCHECK_EQ(secure, !dispatched_);
680   DCHECK_EQ(dispatched_ ? 1 : 0, num_occupied_job_slots_);
681   DCHECK(!resolver_->ShouldForceSystemResolverDueToTestOverride());
682 
683   CHECK(!dns_task_results_manager_);
684   if (base::FeatureList::IsEnabled(features::kUseServiceEndpointRequest)) {
685     dns_task_results_manager_ = std::make_unique<DnsTaskResultsManager>(
686         this, key_.host, key_.query_types, net_log_);
687   }
688 
689   // Need to create the task even if we're going to post a failure instead of
690   // running it, as a "started" job needs a task to be properly cleaned up.
691   dns_task_ = std::make_unique<HostResolverDnsTask>(
692       resolver_->dns_client_.get(), key_.host, key_.network_anonymization_key,
693       key_.query_types, &*key_.resolve_context, secure, key_.secure_dns_mode,
694       this, net_log_, tick_clock_, !tasks_.empty() /* fallback_available */,
695       https_svcb_options_);
696   dns_task_->StartNextTransaction();
697   // Schedule a second transaction, if needed. DoH queries can bypass the
698   // dispatcher and start all of their transactions immediately.
699   if (secure) {
700     while (dns_task_->num_additional_transactions_needed() >= 1) {
701       dns_task_->StartNextTransaction();
702     }
703     DCHECK_EQ(dns_task_->num_additional_transactions_needed(), 0);
704   } else if (dns_task_->num_additional_transactions_needed() >= 1) {
705     Schedule(true);
706   }
707 }
708 
StartNextDnsTransaction()709 void HostResolverManager::Job::StartNextDnsTransaction() {
710   DCHECK(dns_task_);
711   DCHECK_EQ(dns_task_->secure(), !dispatched_);
712   DCHECK(!dispatched_ || num_occupied_job_slots_ ==
713                              dns_task_->num_transactions_in_progress() + 1);
714   DCHECK_GE(dns_task_->num_additional_transactions_needed(), 1);
715   dns_task_->StartNextTransaction();
716 }
717 
OnDnsTaskFailure(const base::WeakPtr<HostResolverDnsTask> & dns_task,base::TimeDelta duration,bool allow_fallback,const HostCache::Entry & failure_results,bool secure)718 void HostResolverManager::Job::OnDnsTaskFailure(
719     const base::WeakPtr<HostResolverDnsTask>& dns_task,
720     base::TimeDelta duration,
721     bool allow_fallback,
722     const HostCache::Entry& failure_results,
723     bool secure) {
724   DCHECK_NE(OK, failure_results.error());
725 
726   if (!secure) {
727     DCHECK_NE(key_.secure_dns_mode, SecureDnsMode::kSecure);
728     UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.InsecureDnsTask.FailureTime",
729                                  duration);
730   }
731 
732   if (!dns_task) {
733     return;
734   }
735 
736   UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.Failure",
737                                total_transaction_time_queued_);
738 
739   // If one of the fallback tasks doesn't complete the request, store a result
740   // to use during request completion.
741   base::TimeDelta ttl =
742       failure_results.has_ttl() ? failure_results.ttl() : base::Seconds(0);
743   completion_results_.push_back({failure_results, ttl, secure});
744 
745   dns_task_error_ = failure_results.error();
746   KillDnsTask();
747 
748   if (!allow_fallback) {
749     tasks_.clear();
750   }
751 
752   RunNextTask();
753 }
754 
OnDnsTaskComplete(base::TimeTicks start_time,bool allow_fallback,HostCache::Entry results,bool secure)755 void HostResolverManager::Job::OnDnsTaskComplete(base::TimeTicks start_time,
756                                                  bool allow_fallback,
757                                                  HostCache::Entry results,
758                                                  bool secure) {
759   DCHECK(dns_task_);
760 
761   // Tasks containing address queries are only considered successful overall
762   // if they find address results. However, DnsTask may claim success if any
763   // transaction, e.g. a supplemental HTTPS transaction, finds results.
764   DCHECK(!key_.query_types.Has(DnsQueryType::UNSPECIFIED));
765   if (HasAddressType(key_.query_types) && results.error() == OK &&
766       results.ip_endpoints().empty()) {
767     results.set_error(ERR_NAME_NOT_RESOLVED);
768   }
769 
770   base::TimeDelta duration = tick_clock_->NowTicks() - start_time;
771   if (results.error() != OK) {
772     OnDnsTaskFailure(dns_task_->AsWeakPtr(), duration, allow_fallback, results,
773                      secure);
774     return;
775   }
776 
777   UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.DnsTask.SuccessTime", duration);
778 
779   UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.JobQueueTime.Success",
780                                total_transaction_time_queued_);
781 
782   // Reset the insecure DNS failure counter if an insecure DnsTask completed
783   // successfully.
784   if (!secure) {
785     resolver_->dns_client_->ClearInsecureFallbackFailures();
786   }
787 
788   base::TimeDelta bounded_ttl =
789       std::max(results.ttl(), base::Seconds(kMinimumTTLSeconds));
790 
791   if (ContainsIcannNameCollisionIp(results.ip_endpoints())) {
792     CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION,
793                               secure ? TaskType::SECURE_DNS : TaskType::DNS);
794     return;
795   }
796 
797   CompleteRequests(results, bounded_ttl, true /* allow_cache */, secure,
798                    secure ? TaskType::SECURE_DNS : TaskType::DNS);
799 }
800 
OnIntermediateTransactionsComplete(std::optional<HostResolverDnsTask::SingleTransactionResults> single_transaction_results)801 void HostResolverManager::Job::OnIntermediateTransactionsComplete(
802     std::optional<HostResolverDnsTask::SingleTransactionResults>
803         single_transaction_results) {
804   if (dispatched_) {
805     DCHECK_GE(num_occupied_job_slots_,
806               dns_task_->num_transactions_in_progress());
807     int unused_slots =
808         num_occupied_job_slots_ - dns_task_->num_transactions_in_progress();
809 
810     // Reuse vacated slots for any remaining transactions.
811     while (unused_slots > 0 &&
812            dns_task_->num_additional_transactions_needed() > 0) {
813       dns_task_->StartNextTransaction();
814       --unused_slots;
815     }
816 
817     // If all remaining transactions found a slot, no more needed from the
818     // dispatcher.
819     if (is_queued() && dns_task_->num_additional_transactions_needed() == 0) {
820       resolver_->dispatcher_->Cancel(handle_);
821       handle_.Reset();
822     }
823 
824     // Relinquish any remaining extra slots.
825     while (unused_slots > 0) {
826       ReduceByOneJobSlot();
827       --unused_slots;
828     }
829   } else if (dns_task_->num_additional_transactions_needed() >= 1) {
830     dns_task_->StartNextTransaction();
831   }
832 
833   if (dns_task_results_manager_ && single_transaction_results.has_value()) {
834     dns_task_results_manager_->ProcessDnsTransactionResults(
835         single_transaction_results->query_type,
836         single_transaction_results->results);
837     // `this` may be deleted. Do not add code below.
838   }
839 }
840 
AddTransactionTimeQueued(base::TimeDelta time_queued)841 void HostResolverManager::Job::AddTransactionTimeQueued(
842     base::TimeDelta time_queued) {
843   total_transaction_time_queued_ += time_queued;
844 }
845 
OnServiceEndpointsUpdated()846 void HostResolverManager::Job::OnServiceEndpointsUpdated() {
847   // Requests could be destroyed while executing callbacks. Post tasks
848   // instead of calling callbacks synchronously to prevent requests from being
849   // destroyed in the following for loop.
850   for (auto* request = service_endpoint_requests_.head();
851        request != service_endpoint_requests_.end(); request = request->next()) {
852     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
853         FROM_HERE,
854         base::BindOnce(&ServiceEndpointRequestImpl::OnServiceEndpointsChanged,
855                        request->value()->GetWeakPtr()));
856   }
857 }
858 
StartMdnsTask()859 void HostResolverManager::Job::StartMdnsTask() {
860   // No flags are supported for MDNS except
861   // HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 (which is not actually an
862   // input flag).
863   DCHECK_EQ(0, key_.flags & ~HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6);
864 
865   MDnsClient* client = nullptr;
866   int rv = resolver_->GetOrCreateMdnsClient(&client);
867   mdns_task_ = std::make_unique<HostResolverMdnsTask>(
868       client, std::string(key_.host.GetHostnameWithoutBrackets()),
869       key_.query_types);
870 
871   if (rv == OK) {
872     mdns_task_->Start(
873         base::BindOnce(&Job::OnMdnsTaskComplete, base::Unretained(this)));
874   } else {
875     // Could not create an mDNS client. Since we cannot complete synchronously
876     // from here, post a failure without starting the task.
877     base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
878         FROM_HERE, base::BindOnce(&Job::OnMdnsImmediateFailure,
879                                   weak_ptr_factory_.GetWeakPtr(), rv));
880   }
881 }
882 
OnMdnsTaskComplete()883 void HostResolverManager::Job::OnMdnsTaskComplete() {
884   DCHECK(mdns_task_);
885   // TODO(crbug.com/846423): Consider adding MDNS-specific logging.
886 
887   HostCache::Entry results = mdns_task_->GetResults();
888 
889   if (ContainsIcannNameCollisionIp(results.ip_endpoints())) {
890     CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION, TaskType::MDNS);
891     return;
892   }
893   // MDNS uses a separate cache, so skip saving result to cache.
894   // TODO(crbug.com/926300): Consider merging caches.
895   CompleteRequestsWithoutCache(results, std::nullopt /* stale_info */,
896                                TaskType::MDNS);
897 }
898 
OnMdnsImmediateFailure(int rv)899 void HostResolverManager::Job::OnMdnsImmediateFailure(int rv) {
900   DCHECK(mdns_task_);
901   DCHECK_NE(OK, rv);
902 
903   CompleteRequestsWithError(rv, TaskType::MDNS);
904 }
905 
StartNat64Task()906 void HostResolverManager::Job::StartNat64Task() {
907   DCHECK(!nat64_task_);
908   nat64_task_ = std::make_unique<HostResolverNat64Task>(
909       key_.host.GetHostnameWithoutBrackets(), key_.network_anonymization_key,
910       net_log_, &*key_.resolve_context, resolver_);
911   nat64_task_->Start(base::BindOnce(&Job::OnNat64TaskComplete,
912                                     weak_ptr_factory_.GetWeakPtr()));
913 }
914 
OnNat64TaskComplete()915 void HostResolverManager::Job::OnNat64TaskComplete() {
916   DCHECK(nat64_task_);
917   HostCache::Entry results = nat64_task_->GetResults();
918   CompleteRequestsWithoutCache(results, std::nullopt /* stale_info */,
919                                TaskType::NAT64);
920 }
921 
RecordJobHistograms(const HostCache::Entry & results,std::optional<TaskType> task_type)922 void HostResolverManager::Job::RecordJobHistograms(
923     const HostCache::Entry& results,
924     std::optional<TaskType> task_type) {
925   int error = results.error();
926   // Used in UMA_HISTOGRAM_ENUMERATION. Do not renumber entries or reuse
927   // deprecated values.
928   enum Category {
929     RESOLVE_SUCCESS = 0,
930     RESOLVE_FAIL = 1,
931     RESOLVE_SPECULATIVE_SUCCESS = 2,
932     RESOLVE_SPECULATIVE_FAIL = 3,
933     RESOLVE_ABORT = 4,
934     RESOLVE_SPECULATIVE_ABORT = 5,
935     RESOLVE_MAX,  // Bounding value.
936   };
937   Category category = RESOLVE_MAX;  // Illegal value for later DCHECK only.
938 
939   base::TimeDelta duration = tick_clock_->NowTicks() - start_time_;
940   if (error == OK) {
941     if (had_non_speculative_request_) {
942       category = RESOLVE_SUCCESS;
943       UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveSuccessTime", duration);
944     } else {
945       category = RESOLVE_SPECULATIVE_SUCCESS;
946     }
947   } else if (error == ERR_NETWORK_CHANGED ||
948              error == ERR_HOST_RESOLVER_QUEUE_TOO_LARGE) {
949     category = had_non_speculative_request_ ? RESOLVE_ABORT
950                                             : RESOLVE_SPECULATIVE_ABORT;
951   } else {
952     if (had_non_speculative_request_) {
953       category = RESOLVE_FAIL;
954       UMA_HISTOGRAM_LONG_TIMES_100("Net.DNS.ResolveFailureTime", duration);
955     } else {
956       category = RESOLVE_SPECULATIVE_FAIL;
957     }
958   }
959   DCHECK_LT(static_cast<int>(category),
960             static_cast<int>(RESOLVE_MAX));  // Be sure it was set.
961   UMA_HISTOGRAM_ENUMERATION("Net.DNS.ResolveCategory", category, RESOLVE_MAX);
962 
963   if (category == RESOLVE_FAIL ||
964       (start_time_ != base::TimeTicks() && category == RESOLVE_ABORT)) {
965     if (duration < base::Milliseconds(10)) {
966       base::UmaHistogramSparse("Net.DNS.ResolveError.Fast", std::abs(error));
967     } else {
968       base::UmaHistogramSparse("Net.DNS.ResolveError.Slow", std::abs(error));
969     }
970   }
971 
972   if (error == OK) {
973     DCHECK(task_type.has_value());
974     // Record, for HTTPS-capable queries to a host known to serve HTTPS
975     // records, whether the HTTPS record was successfully received.
976     if (key_.query_types.Has(DnsQueryType::HTTPS) &&
977         // Skip http- and ws-schemed hosts. Although they query HTTPS records,
978         // successful queries are reported as errors, which would skew the
979         // metrics.
980         IsSchemeHttpsOrWss(key_.host) &&
981         IsGoogleHostWithAlpnH3(key_.host.GetHostnameWithoutBrackets())) {
982       bool has_metadata = !results.GetMetadatas().empty();
983       base::UmaHistogramExactLinear(
984           "Net.DNS.H3SupportedGoogleHost.TaskTypeMetadataAvailability2",
985           static_cast<int>(task_type.value()) * 2 + (has_metadata ? 1 : 0),
986           (static_cast<int>(TaskType::kMaxValue) + 1) * 2);
987     }
988   }
989 }
990 
MaybeCacheResult(const HostCache::Entry & results,base::TimeDelta ttl,bool secure)991 void HostResolverManager::Job::MaybeCacheResult(const HostCache::Entry& results,
992                                                 base::TimeDelta ttl,
993                                                 bool secure) {
994   // If the request did not complete, don't cache it.
995   if (!results.did_complete()) {
996     return;
997   }
998   resolver_->CacheResult(host_cache_, key_.ToCacheKey(secure), results, ttl);
999 }
1000 
CompleteRequests(const HostCache::Entry & results,base::TimeDelta ttl,bool allow_cache,bool secure,std::optional<TaskType> task_type)1001 void HostResolverManager::Job::CompleteRequests(
1002     const HostCache::Entry& results,
1003     base::TimeDelta ttl,
1004     bool allow_cache,
1005     bool secure,
1006     std::optional<TaskType> task_type) {
1007   CHECK(resolver_.get());
1008 
1009   // This job must be removed from resolver's |jobs_| now to make room for a
1010   // new job with the same key in case one of the OnComplete callbacks decides
1011   // to spawn one. Consequently, if the job was owned by |jobs_|, the job
1012   // deletes itself when CompleteRequests is done.
1013   std::unique_ptr<Job> self_deleter;
1014   if (self_iterator_) {
1015     self_deleter = resolver_->RemoveJob(self_iterator_.value());
1016   }
1017 
1018   Finish();
1019 
1020   if (results.error() == ERR_DNS_REQUEST_CANCELLED) {
1021     net_log_.AddEvent(NetLogEventType::CANCELLED);
1022     net_log_.EndEventWithNetErrorCode(
1023         NetLogEventType::HOST_RESOLVER_MANAGER_JOB, OK);
1024     return;
1025   }
1026 
1027   net_log_.EndEventWithNetErrorCode(NetLogEventType::HOST_RESOLVER_MANAGER_JOB,
1028                                     results.error());
1029 
1030   // Handle all caching before completing requests as completing requests may
1031   // start new requests that rely on cached results.
1032   if (allow_cache) {
1033     MaybeCacheResult(results, ttl, secure);
1034   }
1035 
1036   RecordJobHistograms(results, task_type);
1037 
1038   // Complete all of the requests that were attached to the job and
1039   // detach them.
1040   while (!requests_.empty()) {
1041     RequestImpl* req = requests_.head()->value();
1042     req->RemoveFromList();
1043     CHECK(key_ == req->GetJobKey());
1044 
1045     if (results.error() == OK && !req->parameters().is_speculative) {
1046       req->set_results(
1047           results.CopyWithDefaultPort(req->request_host().GetPort()));
1048     }
1049     req->OnJobCompleted(
1050         key_, results.error(),
1051         /*is_secure_network_error=*/secure && results.error() != OK);
1052 
1053     // Check if the resolver was destroyed as a result of running the
1054     // callback. If it was, we could continue, but we choose to bail.
1055     if (!resolver_.get()) {
1056       return;
1057     }
1058   }
1059 
1060   while (!service_endpoint_requests_.empty()) {
1061     ServiceEndpointRequestImpl* request =
1062         service_endpoint_requests_.head()->value();
1063     request->RemoveFromList();
1064     request->OnJobCompleted(results, secure);
1065     if (!resolver_.get()) {
1066       return;
1067     }
1068   }
1069 
1070   // TODO(crbug.com/1200908): Call StartBootstrapFollowup() if any of the
1071   // requests have the Bootstrap policy.  Note: A naive implementation could
1072   // cause an infinite loop if the bootstrap result has TTL=0.
1073 }
1074 
CompleteRequestsWithoutCache(const HostCache::Entry & results,std::optional<HostCache::EntryStaleness> stale_info,TaskType task_type)1075 void HostResolverManager::Job::CompleteRequestsWithoutCache(
1076     const HostCache::Entry& results,
1077     std::optional<HostCache::EntryStaleness> stale_info,
1078     TaskType task_type) {
1079   // Record the stale_info for all non-speculative requests, if it exists.
1080   if (stale_info) {
1081     for (auto* node = requests_.head(); node != requests_.end();
1082          node = node->next()) {
1083       if (!node->value()->parameters().is_speculative) {
1084         node->value()->set_stale_info(stale_info.value());
1085       }
1086     }
1087   }
1088   CompleteRequests(results, base::TimeDelta(), false /* allow_cache */,
1089                    false /* secure */, task_type);
1090 }
1091 
CompleteRequestsWithError(int net_error,std::optional<TaskType> task_type)1092 void HostResolverManager::Job::CompleteRequestsWithError(
1093     int net_error,
1094     std::optional<TaskType> task_type) {
1095   DCHECK_NE(OK, net_error);
1096   CompleteRequests(
1097       HostCache::Entry(net_error, HostCache::Entry::SOURCE_UNKNOWN),
1098       base::TimeDelta(), true /* allow_cache */, false /* secure */, task_type);
1099 }
1100 
priority() const1101 RequestPriority HostResolverManager::Job::priority() const {
1102   return priority_tracker_.highest_priority();
1103 }
1104 
1105 }  // namespace net
1106