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