• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #ifndef NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_
11 #define NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_
12 
13 #include <deque>
14 #include <memory>
15 #include <optional>
16 #include <vector>
17 
18 #include "base/containers/linked_list.h"
19 #include "base/memory/raw_ptr.h"
20 #include "base/memory/safe_ref.h"
21 #include "base/memory/weak_ptr.h"
22 #include "base/time/time.h"
23 #include "net/base/address_family.h"
24 #include "net/base/network_anonymization_key.h"
25 #include "net/base/network_handle.h"
26 #include "net/base/prioritized_dispatcher.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/public/dns_query_type.h"
33 #include "net/dns/public/secure_dns_mode.h"
34 #include "net/log/net_log_with_source.h"
35 #include "third_party/abseil-cpp/absl/types/variant.h"
36 
37 namespace net {
38 
39 class ResolveContext;
40 class HostResolverMdnsTask;
41 class HostResolverNat64Task;
42 
43 // Key used to identify a HostResolverManager::Job.
44 struct HostResolverManager::JobKey {
45   JobKey(HostResolver::Host host, ResolveContext* resolve_context);
46   ~JobKey();
47 
48   JobKey(const JobKey& other);
49   JobKey& operator=(const JobKey& other);
50 
51   bool operator<(const JobKey& other) const;
52   bool operator==(const JobKey& other) const;
53 
54   HostResolver::Host host;
55   NetworkAnonymizationKey network_anonymization_key;
56   DnsQueryTypeSet query_types;
57   HostResolverFlags flags;
58   HostResolverSource source;
59   SecureDnsMode secure_dns_mode;
60   base::WeakPtr<ResolveContext> resolve_context;
61 
62   HostCache::Key ToCacheKey(bool secure) const;
63 
64   handles::NetworkHandle GetTargetNetwork() const;
65 };
66 
67 // Aggregates all Requests for the same Key. Dispatched via
68 // PrioritizedDispatcher.
69 class HostResolverManager::Job : public PrioritizedDispatcher::Job,
70                                  public HostResolverDnsTask::Delegate,
71                                  public DnsTaskResultsManager::Delegate {
72  public:
73   // Creates new job for |key| where |request_net_log| is bound to the
74   // request that spawned it.
75   Job(const base::WeakPtr<HostResolverManager>& resolver,
76       JobKey key,
77       ResolveHostParameters::CacheUsage cache_usage,
78       HostCache* host_cache,
79       std::deque<TaskType> tasks,
80       RequestPriority priority,
81       const NetLogWithSource& source_net_log,
82       const base::TickClock* tick_clock,
83       const HostResolver::HttpsSvcbOptions& https_svcb_options);
84   ~Job() override;
85 
86   // Add this job to the dispatcher.  If "at_head" is true, adds at the front
87   // of the queue.
88   void Schedule(bool at_head);
89 
90   void AddRequest(RequestImpl* request);
91 
92   void ChangeRequestPriority(RequestImpl* req, RequestPriority priority);
93 
94   // Detach cancelled request. If it was the last active Request, also finishes
95   // this Job.
96   void CancelRequest(RequestImpl* request);
97 
98   void AddServiceEndpointRequest(ServiceEndpointRequestImpl* request);
99 
100   // Similar to CancelRequest(), if `request` was the last active one, finishes
101   // this job.
102   void CancelServiceEndpointRequest(ServiceEndpointRequestImpl* request);
103 
104   // Similar to ChangeRequestPriority(), but for a ServiceEndpointRequest.
105   void ChangeServiceEndpointRequestPriority(ServiceEndpointRequestImpl* request,
106                                             RequestPriority priority);
107 
108   // Called from AbortJobsWithoutTargetNetwork(). Completes all requests and
109   // destroys the job. This currently assumes the abort is due to a network
110   // change.
111   // TODO This should not delete |this|.
112   void Abort();
113 
114   // Gets a closure that will abort an insecure DnsTask (see
115   // AbortInsecureDnsTask()) iff |this| is still valid. Useful if aborting a
116   // list of Jobs as some may be cancelled while aborting others.
117   base::OnceClosure GetAbortInsecureDnsTaskClosure(int error,
118                                                    bool fallback_only);
119 
120   // Aborts or removes any current/future insecure DnsTasks if a
121   // HostResolverSystemTask is available for fallback. If no fallback is
122   // available and |fallback_only| is false, a job that is currently running an
123   // insecure DnsTask will be completed with |error|.
124   void AbortInsecureDnsTask(int error, bool fallback_only);
125 
126   // Called by HostResolverManager when this job is evicted due to queue
127   // overflow. Completes all requests and destroys the job. The job could have
128   // waiting requests that will receive completion callbacks, so cleanup
129   // asynchronously to avoid reentrancy.
130   void OnEvicted();
131 
132   // Attempts to serve the job from HOSTS. Returns true if succeeded and
133   // this Job was destroyed.
134   bool ServeFromHosts();
135 
136   void OnAddedToJobMap(JobMap::iterator iterator);
137 
138   void OnRemovedFromJobMap();
139 
140   void RunNextTask();
141 
key()142   const JobKey& key() const { return key_; }
143 
is_queued()144   bool is_queued() const { return !handle_.is_null(); }
145 
is_running()146   bool is_running() const { return job_running_; }
147 
HasTargetNetwork()148   bool HasTargetNetwork() const {
149     return key_.GetTargetNetwork() != handles::kInvalidNetworkHandle;
150   }
151 
dns_task_results_manager()152   DnsTaskResultsManager* dns_task_results_manager() const {
153     return dns_task_results_manager_.get();
154   }
155 
156  private:
157   // Keeps track of the highest priority.
158   class PriorityTracker {
159    public:
PriorityTracker(RequestPriority initial_priority)160     explicit PriorityTracker(RequestPriority initial_priority)
161         : highest_priority_(initial_priority) {}
162 
highest_priority()163     RequestPriority highest_priority() const { return highest_priority_; }
164 
total_count()165     size_t total_count() const { return total_count_; }
166 
Add(RequestPriority req_priority)167     void Add(RequestPriority req_priority) {
168       ++total_count_;
169       ++counts_[req_priority];
170       if (highest_priority_ < req_priority) {
171         highest_priority_ = req_priority;
172       }
173     }
174 
Remove(RequestPriority req_priority)175     void Remove(RequestPriority req_priority) {
176       DCHECK_GT(total_count_, 0u);
177       DCHECK_GT(counts_[req_priority], 0u);
178       --total_count_;
179       --counts_[req_priority];
180       size_t i;
181       for (i = highest_priority_; i > MINIMUM_PRIORITY && !counts_[i]; --i) {
182       }
183       highest_priority_ = static_cast<RequestPriority>(i);
184 
185       // In absence of requests, default to MINIMUM_PRIORITY.
186       if (total_count_ == 0) {
187         DCHECK_EQ(MINIMUM_PRIORITY, highest_priority_);
188       }
189     }
190 
191    private:
192     RequestPriority highest_priority_;
193     size_t total_count_ = 0;
194     size_t counts_[NUM_PRIORITIES] = {};
195   };
196 
197   base::Value::Dict NetLogJobCreationParams(const NetLogSource& source);
198 
199   void Finish();
200 
201   void KillDnsTask();
202 
203   // Reduce the number of job slots occupied and queued in the dispatcher by
204   // one. If the next Job slot is queued in the dispatcher, cancels the queued
205   // job. Otherwise, the next Job has been started by the PrioritizedDispatcher,
206   // so signals it is complete.
207   void ReduceByOneJobSlot();
208 
209   // Common helper methods for adding and canceling a request.
210   void AddRequestCommon(RequestPriority request_priority,
211                         const NetLogWithSource& request_net_log,
212                         bool is_speculative);
213   void CancelRequestCommon(RequestPriority request_priority,
214                            const NetLogWithSource& request_net_log);
215 
216   void UpdatePriority();
217 
218   // PrioritizedDispatcher::Job:
219   void Start() override;
220 
221   // TODO(szym): Since DnsTransaction does not consume threads, we can increase
222   // the limits on |dispatcher_|. But in order to keep the number of
223   // ThreadPool threads low, we will need to use an "inner"
224   // PrioritizedDispatcher with tighter limits.
225   void StartSystemTask();
226   // Called by HostResolverSystemTask when it completes.
227   void OnSystemTaskComplete(base::TimeTicks start_time,
228                             const AddressList& addr_list,
229                             int /*os_error*/,
230                             int net_error);
231 
232   void InsecureCacheLookup();
233 
234   void StartDnsTask(bool secure);
235   void StartNextDnsTransaction();
236   // Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
237   // deleted before this callback. In this case dns_task is deleted as well,
238   // so we use it as indicator whether Job is still valid.
239   void OnDnsTaskFailure(const base::WeakPtr<HostResolverDnsTask>& dns_task,
240                         base::TimeDelta duration,
241                         bool allow_fallback,
242                         const HostCache::Entry& failure_results,
243                         bool secure);
244   // HostResolverDnsTask::Delegate implementation:
245   void OnDnsTaskComplete(base::TimeTicks start_time,
246                          bool allow_fallback,
247                          HostResolverDnsTask::Results results,
248                          bool secure) override;
249   void OnIntermediateTransactionsComplete(
250       std::optional<HostResolverDnsTask::SingleTransactionResults>
251           single_transaction_results) override;
252   void AddTransactionTimeQueued(base::TimeDelta time_queued) override;
253 
254   // DnsTaskResultsManager::Delegate implementation:
255   void OnServiceEndpointsUpdated() override;
256 
257   void StartMdnsTask();
258   void OnMdnsTaskComplete();
259   void OnMdnsImmediateFailure(int rv);
260 
261   void StartNat64Task();
262   void OnNat64TaskComplete();
263 
264   void RecordJobHistograms(const HostCache::Entry& results,
265                            std::optional<TaskType> task_type);
266 
267   void MaybeCacheResult(const HostCache::Entry& results,
268                         base::TimeDelta ttl,
269                         bool secure);
270 
271   // Performs Job's last rites. Completes all Requests. Deletes this.
272   //
273   // If not |allow_cache|, result will not be stored in the host cache, even if
274   // result would otherwise allow doing so. Update the key to reflect |secure|,
275   // which indicates whether or not the result was obtained securely.
276   void CompleteRequests(const HostCache::Entry& results,
277                         base::TimeDelta ttl,
278                         bool allow_cache,
279                         bool secure,
280                         std::optional<TaskType> task_type);
281 
282   void CompleteRequestsWithoutCache(
283       const HostCache::Entry& results,
284       std::optional<HostCache::EntryStaleness> stale_info,
285       TaskType task_type);
286 
287   // Convenience wrapper for CompleteRequests in case of failure.
288   void CompleteRequestsWithError(int net_error,
289                                  std::optional<TaskType> task_type);
290 
291   RequestPriority priority() const override;
292 
293   // Number of non-canceled requests in |requests_|.
num_active_requests()294   size_t num_active_requests() const { return priority_tracker_.total_count(); }
295 
296   base::WeakPtr<HostResolverManager> resolver_;
297 
298   const JobKey key_;
299   const ResolveHostParameters::CacheUsage cache_usage_;
300   // TODO(crbug.com/41462480): Consider allowing requests within a single Job to
301   // have different HostCaches.
302   const raw_ptr<HostCache> host_cache_;
303 
304   struct CompletionResult {
305     const HostCache::Entry entry;
306     base::TimeDelta ttl;
307     bool secure;
308   };
309 
310   // Results to use in last-ditch attempt to complete request.
311   std::vector<CompletionResult> completion_results_;
312 
313   // The sequence of tasks to run in this Job. Tasks may be aborted and removed
314   // from the sequence, but otherwise the tasks will run in order until a
315   // successful result is found.
316   std::deque<TaskType> tasks_;
317 
318   // Whether the job is running.
319   bool job_running_ = false;
320 
321   // Tracks the highest priority across |requests_|.
322   PriorityTracker priority_tracker_;
323 
324   bool had_non_speculative_request_ = false;
325 
326   // Number of slots occupied by this Job in |dispatcher_|. Should be 0 when
327   // the job is not registered with any dispatcher.
328   int num_occupied_job_slots_ = 0;
329 
330   // True once this Job has been sent to `resolver_->dispatcher_`.
331   bool dispatched_ = false;
332 
333   // Result of DnsTask.
334   int dns_task_error_ = OK;
335 
336   raw_ptr<const base::TickClock> tick_clock_;
337   base::TimeTicks start_time_;
338 
339   HostResolver::HttpsSvcbOptions https_svcb_options_;
340 
341   NetLogWithSource net_log_;
342 
343   // Resolves the host using the system DNS resolver, which can be overridden
344   // for tests.
345   std::unique_ptr<HostResolverSystemTask> system_task_;
346 
347   // Resolves the host using a DnsTransaction.
348   std::unique_ptr<HostResolverDnsTask> dns_task_;
349 
350   // Resolves the host using MDnsClient.
351   std::unique_ptr<HostResolverMdnsTask> mdns_task_;
352 
353   // Perform NAT64 address synthesis to a given IPv4 literal.
354   std::unique_ptr<HostResolverNat64Task> nat64_task_;
355 
356   // All Requests waiting for the result of this Job. Some can be canceled.
357   base::LinkedList<RequestImpl> requests_;
358 
359   // All ServiceEndpointRequests waiting for the result of this Job. Some can
360   // be canceled.
361   base::LinkedList<ServiceEndpointRequestImpl> service_endpoint_requests_;
362 
363   // Builds and updates intermediate service endpoints while executing
364   // a DnsTransaction.
365   std::unique_ptr<DnsTaskResultsManager> dns_task_results_manager_;
366 
367   // A handle used for |dispatcher_|.
368   PrioritizedDispatcher::Handle handle_;
369 
370   // Iterator to |this| in the JobMap. |nullopt| if not owned by the JobMap.
371   std::optional<JobMap::iterator> self_iterator_;
372 
373   base::TimeDelta total_transaction_time_queued_;
374 
375   base::WeakPtrFactory<Job> weak_ptr_factory_{this};
376 };
377 
378 }  // namespace net
379 
380 #endif  // NET_DNS_HOST_RESOLVER_MANAGER_JOB_H_
381