xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_manager_request_impl.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_request_impl.h"
6 
7 #include <deque>
8 #include <optional>
9 #include <set>
10 #include <string>
11 #include <vector>
12 
13 #include "base/containers/linked_list.h"
14 #include "base/memory/raw_ptr.h"
15 #include "base/memory/safe_ref.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/sequence_checker.h"
19 #include "base/time/tick_clock.h"
20 #include "net/base/address_list.h"
21 #include "net/base/completion_once_callback.h"
22 #include "net/base/network_anonymization_key.h"
23 #include "net/base/request_priority.h"
24 #include "net/dns/dns_alias_utility.h"
25 #include "net/dns/host_cache.h"
26 #include "net/dns/host_resolver.h"
27 #include "net/dns/host_resolver_manager.h"
28 #include "net/dns/host_resolver_manager_job.h"
29 #include "net/dns/public/host_resolver_results.h"
30 #include "net/dns/public/resolve_error_info.h"
31 #include "net/http/http_network_session.h"
32 #include "net/log/net_log_with_source.h"
33 #include "net/socket/client_socket_factory.h"
34 #include "net/url_request/url_request_context.h"
35 
36 namespace net {
37 
RequestImpl(NetLogWithSource source_net_log,HostResolver::Host request_host,NetworkAnonymizationKey network_anonymization_key,std::optional<ResolveHostParameters> optional_parameters,base::WeakPtr<ResolveContext> resolve_context,base::WeakPtr<HostResolverManager> resolver,const base::TickClock * tick_clock)38 HostResolverManager::RequestImpl::RequestImpl(
39     NetLogWithSource source_net_log,
40     HostResolver::Host request_host,
41     NetworkAnonymizationKey network_anonymization_key,
42     std::optional<ResolveHostParameters> optional_parameters,
43     base::WeakPtr<ResolveContext> resolve_context,
44     base::WeakPtr<HostResolverManager> resolver,
45     const base::TickClock* tick_clock)
46     : source_net_log_(std::move(source_net_log)),
47       request_host_(std::move(request_host)),
48       network_anonymization_key_(
49           NetworkAnonymizationKey::IsPartitioningEnabled()
50               ? std::move(network_anonymization_key)
51               : NetworkAnonymizationKey()),
52       parameters_(optional_parameters ? std::move(optional_parameters).value()
53                                       : ResolveHostParameters()),
54       resolve_context_(std::move(resolve_context)),
55       priority_(parameters_.initial_priority),
56       job_key_(request_host_, resolve_context_.get()),
57       resolver_(std::move(resolver)),
58       tick_clock_(tick_clock) {}
59 
~RequestImpl()60 HostResolverManager::RequestImpl::~RequestImpl() {
61   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
62   if (!job_.has_value()) {
63     return;
64   }
65 
66   job_.value()->CancelRequest(this);
67   LogCancelRequest();
68 }
69 
Start(CompletionOnceCallback callback)70 int HostResolverManager::RequestImpl::Start(CompletionOnceCallback callback) {
71   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
72   DCHECK(callback);
73   // Start() may only be called once per request.
74   CHECK(!job_.has_value());
75   DCHECK(!complete_);
76   DCHECK(!callback_);
77   // Parent HostResolver must still be alive to call Start().
78   DCHECK(resolver_);
79 
80   if (!resolve_context_) {
81     complete_ = true;
82     resolver_.reset();
83     set_error_info(ERR_CONTEXT_SHUT_DOWN, false);
84     return ERR_NAME_NOT_RESOLVED;
85   }
86 
87   LogStartRequest();
88 
89   next_state_ = STATE_IPV6_REACHABILITY;
90   callback_ = std::move(callback);
91 
92   int rv = OK;
93   rv = DoLoop(rv);
94   return rv;
95 }
96 
GetAddressResults() const97 const AddressList* HostResolverManager::RequestImpl::GetAddressResults() const {
98   DCHECK(complete_);
99   return base::OptionalToPtr(legacy_address_results_);
100 }
101 
102 const std::vector<HostResolverEndpointResult>*
GetEndpointResults() const103 HostResolverManager::RequestImpl::GetEndpointResults() const {
104   DCHECK(complete_);
105   return base::OptionalToPtr(endpoint_results_);
106 }
107 
108 const std::vector<std::string>*
GetTextResults() const109 HostResolverManager::RequestImpl::GetTextResults() const {
110   DCHECK(complete_);
111   return results_ ? &results_.value().text_records() : nullptr;
112 }
113 
114 const std::vector<HostPortPair>*
GetHostnameResults() const115 HostResolverManager::RequestImpl::GetHostnameResults() const {
116   DCHECK(complete_);
117   return results_ ? &results_.value().hostnames() : nullptr;
118 }
119 
120 const std::set<std::string>*
GetDnsAliasResults() const121 HostResolverManager::RequestImpl::GetDnsAliasResults() const {
122   DCHECK(complete_);
123 
124   // If `include_canonical_name` param was true, should only ever have at most
125   // a single alias, representing the expected "canonical name".
126 #if DCHECK_IS_ON()
127   if (parameters().include_canonical_name && fixed_up_dns_alias_results_) {
128     DCHECK_LE(fixed_up_dns_alias_results_->size(), 1u);
129     if (GetAddressResults()) {
130       std::set<std::string> address_list_aliases_set(
131           GetAddressResults()->dns_aliases().begin(),
132           GetAddressResults()->dns_aliases().end());
133       DCHECK(address_list_aliases_set == fixed_up_dns_alias_results_.value());
134     }
135   }
136 #endif  // DCHECK_IS_ON()
137 
138   return base::OptionalToPtr(fixed_up_dns_alias_results_);
139 }
140 
141 const std::vector<bool>*
GetExperimentalResultsForTesting() const142 HostResolverManager::RequestImpl::GetExperimentalResultsForTesting() const {
143   DCHECK(complete_);
144   return results_ ? &results_.value().https_record_compatibility() : nullptr;
145 }
146 
GetResolveErrorInfo() const147 net::ResolveErrorInfo HostResolverManager::RequestImpl::GetResolveErrorInfo()
148     const {
149   DCHECK(complete_);
150   return error_info_;
151 }
152 
153 const std::optional<HostCache::EntryStaleness>&
GetStaleInfo() const154 HostResolverManager::RequestImpl::GetStaleInfo() const {
155   DCHECK(complete_);
156   return stale_info_;
157 }
158 
ChangeRequestPriority(RequestPriority priority)159 void HostResolverManager::RequestImpl::ChangeRequestPriority(
160     RequestPriority priority) {
161   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
162   if (!job_.has_value()) {
163     priority_ = priority;
164     return;
165   }
166   job_.value()->ChangeRequestPriority(this, priority);
167 }
168 
set_results(HostCache::Entry results)169 void HostResolverManager::RequestImpl::set_results(HostCache::Entry results) {
170   // Should only be called at most once and before request is marked
171   // completed.
172   DCHECK(!complete_);
173   DCHECK(!results_);
174   DCHECK(!parameters_.is_speculative);
175 
176   results_ = std::move(results);
177   FixUpEndpointAndAliasResults();
178 }
179 
set_error_info(int error,bool is_secure_network_error)180 void HostResolverManager::RequestImpl::set_error_info(
181     int error,
182     bool is_secure_network_error) {
183   error_info_ = ResolveErrorInfo(error, is_secure_network_error);
184 }
185 
set_stale_info(HostCache::EntryStaleness stale_info)186 void HostResolverManager::RequestImpl::set_stale_info(
187     HostCache::EntryStaleness stale_info) {
188   // Should only be called at most once and before request is marked
189   // completed.
190   DCHECK(!complete_);
191   DCHECK(!stale_info_);
192   DCHECK(!parameters_.is_speculative);
193 
194   stale_info_ = std::move(stale_info);
195 }
196 
AssignJob(base::SafeRef<Job> job)197 void HostResolverManager::RequestImpl::AssignJob(base::SafeRef<Job> job) {
198   CHECK(!job_.has_value());
199   job_ = std::move(job);
200 }
201 
GetJobKey() const202 const HostResolverManager::JobKey& HostResolverManager::RequestImpl::GetJobKey()
203     const {
204   CHECK(job_.has_value());
205   return job_.value()->key();
206 }
207 
OnJobCancelled(const JobKey & job_key)208 void HostResolverManager::RequestImpl::OnJobCancelled(const JobKey& job_key) {
209   CHECK(job_.has_value());
210   CHECK(job_key == job_.value()->key());
211   job_.reset();
212   DCHECK(!complete_);
213   DCHECK(callback_);
214   callback_.Reset();
215 
216   // No results should be set.
217   DCHECK(!results_);
218 
219   LogCancelRequest();
220 }
221 
OnJobCompleted(const JobKey & job_key,int error,bool is_secure_network_error)222 void HostResolverManager::RequestImpl::OnJobCompleted(
223     const JobKey& job_key,
224     int error,
225     bool is_secure_network_error) {
226   set_error_info(error, is_secure_network_error);
227 
228   CHECK(job_.has_value());
229   CHECK(job_key == job_.value()->key());
230   job_.reset();
231 
232   DCHECK(!complete_);
233   complete_ = true;
234 
235   LogFinishRequest(error, true /* async_completion */);
236 
237   DCHECK(callback_);
238   std::move(callback_).Run(HostResolver::SquashErrorCode(error));
239 }
240 
DoLoop(int rv)241 int HostResolverManager::RequestImpl::DoLoop(int rv) {
242   do {
243     ResolveState state = next_state_;
244     next_state_ = STATE_NONE;
245     switch (state) {
246       case STATE_IPV6_REACHABILITY:
247         rv = DoIPv6Reachability();
248         break;
249       case STATE_GET_PARAMETERS:
250         DCHECK_EQ(OK, rv);
251         rv = DoGetParameters();
252         break;
253       case STATE_GET_PARAMETERS_COMPLETE:
254         rv = DoGetParametersComplete(rv);
255         break;
256       case STATE_RESOLVE_LOCALLY:
257         rv = DoResolveLocally();
258         break;
259       case STATE_START_JOB:
260         rv = DoStartJob();
261         break;
262       case STATE_FINISH_REQUEST:
263         rv = DoFinishRequest(rv);
264         break;
265       default:
266         NOTREACHED() << "next_state_: " << next_state_;
267         break;
268     }
269   } while (next_state_ != STATE_NONE && rv != ERR_IO_PENDING);
270 
271   return rv;
272 }
273 
OnIOComplete(int rv)274 void HostResolverManager::RequestImpl::OnIOComplete(int rv) {
275   rv = DoLoop(rv);
276   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
277     std::move(callback_).Run(rv);
278   }
279 }
280 
DoIPv6Reachability()281 int HostResolverManager::RequestImpl::DoIPv6Reachability() {
282   next_state_ = STATE_GET_PARAMETERS;
283   // If a single reachability probe has not been completed, and the latest
284   // probe will return asynchronously, return ERR_NAME_NOT_RESOLVED when the
285   // request source is LOCAL_ONLY. This is due to LOCAL_ONLY requiring a
286   // synchronous response, so it cannot wait on an async probe result and
287   // cannot make assumptions about reachability.
288   if (parameters_.source == HostResolverSource::LOCAL_ONLY) {
289     int rv = resolver_->StartIPv6ReachabilityCheck(
290         source_net_log_, GetClientSocketFactory(),
291         base::DoNothingAs<void(int)>());
292     if (rv == ERR_IO_PENDING) {
293       next_state_ = STATE_FINISH_REQUEST;
294       return ERR_NAME_NOT_RESOLVED;
295     }
296     return OK;
297   }
298   return resolver_->StartIPv6ReachabilityCheck(
299       source_net_log_, GetClientSocketFactory(),
300       base::BindOnce(&RequestImpl::OnIOComplete,
301                      weak_ptr_factory_.GetWeakPtr()));
302 }
303 
DoGetParameters()304 int HostResolverManager::RequestImpl::DoGetParameters() {
305   resolver_->InitializeJobKeyAndIPAddress(network_anonymization_key_,
306                                           parameters_, source_net_log_,
307                                           job_key_, ip_address_);
308 
309   // A reachability probe to determine if the network is only reachable on
310   // IPv6 will be scheduled if the parameters are met for using NAT64 in place
311   // of an IPv4 address.
312   if (HostResolver::MayUseNAT64ForIPv4Literal(
313           job_key_.flags, parameters_.source, ip_address_) &&
314       resolver_->last_ipv6_probe_result_) {
315     next_state_ = STATE_GET_PARAMETERS_COMPLETE;
316     return resolver_->StartGloballyReachableCheck(
317         ip_address_, source_net_log_, GetClientSocketFactory(),
318         base::BindOnce(&RequestImpl::OnIOComplete,
319                        weak_ptr_factory_.GetWeakPtr()));
320   }
321   next_state_ = STATE_RESOLVE_LOCALLY;
322   return OK;
323 }
324 
DoGetParametersComplete(int rv)325 int HostResolverManager::RequestImpl::DoGetParametersComplete(int rv) {
326   next_state_ = STATE_RESOLVE_LOCALLY;
327   only_ipv6_reachable_ = (rv == ERR_FAILED) ? true : false;
328   return OK;
329 }
330 
DoResolveLocally()331 int HostResolverManager::RequestImpl::DoResolveLocally() {
332   std::optional<HostCache::EntryStaleness> stale_info;
333   HostCache::Entry results = resolver_->ResolveLocally(
334       only_ipv6_reachable_, job_key_, ip_address_, parameters_.cache_usage,
335       parameters_.secure_dns_policy, parameters_.source, source_net_log_,
336       host_cache(), &tasks_, &stale_info);
337   if (results.error() != ERR_DNS_CACHE_MISS ||
338       parameters_.source == HostResolverSource::LOCAL_ONLY || tasks_.empty()) {
339     if (results.error() == OK && !parameters_.is_speculative) {
340       set_results(results.CopyWithDefaultPort(request_host_.GetPort()));
341     }
342     if (stale_info && !parameters_.is_speculative) {
343       set_stale_info(std::move(stale_info).value());
344     }
345     next_state_ = STATE_FINISH_REQUEST;
346     return results.error();
347   }
348   next_state_ = STATE_START_JOB;
349   return OK;
350 }
351 
DoStartJob()352 int HostResolverManager::RequestImpl::DoStartJob() {
353   resolver_->CreateAndStartJob(std::move(job_key_), std::move(tasks_), this);
354   DCHECK(!complete_);
355   resolver_.reset();
356   return ERR_IO_PENDING;
357 }
358 
DoFinishRequest(int rv)359 int HostResolverManager::RequestImpl::DoFinishRequest(int rv) {
360   CHECK(!job_.has_value());
361   complete_ = true;
362   set_error_info(rv, /*is_secure_network_error=*/false);
363   rv = HostResolver::SquashErrorCode(rv);
364   LogFinishRequest(rv, /*async_completion=*/false);
365   return rv;
366 }
367 
FixUpEndpointAndAliasResults()368 void HostResolverManager::RequestImpl::FixUpEndpointAndAliasResults() {
369   DCHECK(results_.has_value());
370   DCHECK(!legacy_address_results_.has_value());
371   DCHECK(!endpoint_results_.has_value());
372   DCHECK(!fixed_up_dns_alias_results_.has_value());
373 
374   endpoint_results_ = results_.value().GetEndpoints();
375   if (endpoint_results_.has_value()) {
376     fixed_up_dns_alias_results_ = results_.value().aliases();
377 
378     // Skip fixups for `include_canonical_name` requests. Just use the
379     // canonical name exactly as it was received from the system resolver.
380     if (parameters().include_canonical_name) {
381       DCHECK_LE(fixed_up_dns_alias_results_.value().size(), 1u);
382     } else {
383       fixed_up_dns_alias_results_ = dns_alias_utility::FixUpDnsAliases(
384           fixed_up_dns_alias_results_.value());
385     }
386 
387     legacy_address_results_ = HostResolver::EndpointResultToAddressList(
388         endpoint_results_.value(), fixed_up_dns_alias_results_.value());
389   }
390 }
391 
LogStartRequest()392 void HostResolverManager::RequestImpl::LogStartRequest() {
393   DCHECK(request_time_.is_null());
394   request_time_ = tick_clock_->NowTicks();
395 
396   source_net_log_.BeginEvent(
397       NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST, [this] {
398         base::Value::Dict dict;
399         dict.Set("host", request_host_.ToString());
400         dict.Set("dns_query_type",
401                  kDnsQueryTypes.at(parameters_.dns_query_type));
402         dict.Set("allow_cached_response",
403                  parameters_.cache_usage !=
404                      ResolveHostParameters::CacheUsage::DISALLOWED);
405         dict.Set("is_speculative", parameters_.is_speculative);
406         dict.Set("network_anonymization_key",
407                  network_anonymization_key_.ToDebugString());
408         dict.Set("secure_dns_policy",
409                  base::strict_cast<int>(parameters_.secure_dns_policy));
410         return dict;
411       });
412 }
413 
LogFinishRequest(int net_error,bool async_completion)414 void HostResolverManager::RequestImpl::LogFinishRequest(int net_error,
415                                                         bool async_completion) {
416   source_net_log_.EndEventWithNetErrorCode(
417       NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST, net_error);
418 
419   if (!parameters_.is_speculative) {
420     DCHECK(!request_time_.is_null());
421     base::TimeDelta duration = tick_clock_->NowTicks() - request_time_;
422 
423     UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTime", duration);
424     if (async_completion) {
425       UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTimeAsync", duration);
426     }
427   }
428 }
429 
LogCancelRequest()430 void HostResolverManager::RequestImpl::LogCancelRequest() {
431   source_net_log_.AddEvent(NetLogEventType::CANCELLED);
432   source_net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST);
433 }
434 
435 ClientSocketFactory*
GetClientSocketFactory()436 HostResolverManager::RequestImpl::GetClientSocketFactory() {
437   if (resolve_context_->url_request_context()) {
438     return resolve_context_->url_request_context()
439         ->GetNetworkSessionContext()
440         ->client_socket_factory;
441   } else {
442     return ClientSocketFactory::GetDefaultFactory();
443   }
444 }
445 
446 }  // namespace net
447