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