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 }
268 } while (next_state_ != STATE_NONE && rv != ERR_IO_PENDING);
269
270 return rv;
271 }
272
OnIOComplete(int rv)273 void HostResolverManager::RequestImpl::OnIOComplete(int rv) {
274 rv = DoLoop(rv);
275 if (rv != ERR_IO_PENDING && !callback_.is_null()) {
276 std::move(callback_).Run(rv);
277 }
278 }
279
DoIPv6Reachability()280 int HostResolverManager::RequestImpl::DoIPv6Reachability() {
281 next_state_ = STATE_GET_PARAMETERS;
282 // If a single reachability probe has not been completed, and the latest
283 // probe will return asynchronously, return ERR_NAME_NOT_RESOLVED when the
284 // request source is LOCAL_ONLY. This is due to LOCAL_ONLY requiring a
285 // synchronous response, so it cannot wait on an async probe result and
286 // cannot make assumptions about reachability.
287 if (parameters_.source == HostResolverSource::LOCAL_ONLY) {
288 int rv = resolver_->StartIPv6ReachabilityCheck(
289 source_net_log_, GetClientSocketFactory(),
290 base::DoNothingAs<void(int)>());
291 if (rv == ERR_IO_PENDING) {
292 next_state_ = STATE_FINISH_REQUEST;
293 return ERR_NAME_NOT_RESOLVED;
294 }
295 return OK;
296 }
297 return resolver_->StartIPv6ReachabilityCheck(
298 source_net_log_, GetClientSocketFactory(),
299 base::BindOnce(&RequestImpl::OnIOComplete,
300 weak_ptr_factory_.GetWeakPtr()));
301 }
302
DoGetParameters()303 int HostResolverManager::RequestImpl::DoGetParameters() {
304 resolver_->InitializeJobKeyAndIPAddress(network_anonymization_key_,
305 parameters_, source_net_log_,
306 job_key_, ip_address_);
307
308 // A reachability probe to determine if the network is only reachable on
309 // IPv6 will be scheduled if the parameters are met for using NAT64 in place
310 // of an IPv4 address.
311 if (HostResolver::MayUseNAT64ForIPv4Literal(
312 job_key_.flags, parameters_.source, ip_address_) &&
313 resolver_->last_ipv6_probe_result_) {
314 next_state_ = STATE_GET_PARAMETERS_COMPLETE;
315 return resolver_->StartGloballyReachableCheck(
316 ip_address_, source_net_log_, GetClientSocketFactory(),
317 base::BindOnce(&RequestImpl::OnIOComplete,
318 weak_ptr_factory_.GetWeakPtr()));
319 }
320 next_state_ = STATE_RESOLVE_LOCALLY;
321 return OK;
322 }
323
DoGetParametersComplete(int rv)324 int HostResolverManager::RequestImpl::DoGetParametersComplete(int rv) {
325 next_state_ = STATE_RESOLVE_LOCALLY;
326 only_ipv6_reachable_ = (rv == ERR_FAILED) ? true : false;
327 return OK;
328 }
329
DoResolveLocally()330 int HostResolverManager::RequestImpl::DoResolveLocally() {
331 std::optional<HostCache::EntryStaleness> stale_info;
332 HostCache::Entry results = resolver_->ResolveLocally(
333 only_ipv6_reachable_, job_key_, ip_address_, parameters_.cache_usage,
334 parameters_.secure_dns_policy, parameters_.source, source_net_log_,
335 host_cache(), &tasks_, &stale_info);
336 if (results.error() != ERR_DNS_CACHE_MISS ||
337 parameters_.source == HostResolverSource::LOCAL_ONLY || tasks_.empty()) {
338 if (results.error() == OK && !parameters_.is_speculative) {
339 set_results(results.CopyWithDefaultPort(request_host_.GetPort()));
340 }
341 if (stale_info && !parameters_.is_speculative) {
342 set_stale_info(std::move(stale_info).value());
343 }
344 next_state_ = STATE_FINISH_REQUEST;
345 return results.error();
346 }
347 next_state_ = STATE_START_JOB;
348 return OK;
349 }
350
DoStartJob()351 int HostResolverManager::RequestImpl::DoStartJob() {
352 resolver_->CreateAndStartJob(std::move(job_key_), std::move(tasks_), this);
353 DCHECK(!complete_);
354 resolver_.reset();
355 return ERR_IO_PENDING;
356 }
357
DoFinishRequest(int rv)358 int HostResolverManager::RequestImpl::DoFinishRequest(int rv) {
359 CHECK(!job_.has_value());
360 complete_ = true;
361 set_error_info(rv, /*is_secure_network_error=*/false);
362 rv = HostResolver::SquashErrorCode(rv);
363 LogFinishRequest(rv, /*async_completion=*/false);
364 return rv;
365 }
366
FixUpEndpointAndAliasResults()367 void HostResolverManager::RequestImpl::FixUpEndpointAndAliasResults() {
368 DCHECK(results_.has_value());
369 DCHECK(!legacy_address_results_.has_value());
370 DCHECK(!endpoint_results_.has_value());
371 DCHECK(!fixed_up_dns_alias_results_.has_value());
372
373 endpoint_results_ = results_.value().GetEndpoints();
374 if (endpoint_results_.has_value()) {
375 fixed_up_dns_alias_results_ = results_.value().aliases();
376
377 // Skip fixups for `include_canonical_name` requests. Just use the
378 // canonical name exactly as it was received from the system resolver.
379 if (parameters().include_canonical_name) {
380 DCHECK_LE(fixed_up_dns_alias_results_.value().size(), 1u);
381 } else {
382 fixed_up_dns_alias_results_ = dns_alias_utility::FixUpDnsAliases(
383 fixed_up_dns_alias_results_.value());
384 }
385
386 legacy_address_results_ = HostResolver::EndpointResultToAddressList(
387 endpoint_results_.value(), fixed_up_dns_alias_results_.value());
388 }
389 }
390
LogStartRequest()391 void HostResolverManager::RequestImpl::LogStartRequest() {
392 DCHECK(request_time_.is_null());
393 request_time_ = tick_clock_->NowTicks();
394
395 source_net_log_.BeginEvent(
396 NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST, [this] {
397 base::Value::Dict dict;
398 dict.Set("host", request_host_.ToString());
399 dict.Set("dns_query_type",
400 kDnsQueryTypes.at(parameters_.dns_query_type));
401 dict.Set("allow_cached_response",
402 parameters_.cache_usage !=
403 ResolveHostParameters::CacheUsage::DISALLOWED);
404 dict.Set("is_speculative", parameters_.is_speculative);
405 dict.Set("network_anonymization_key",
406 network_anonymization_key_.ToDebugString());
407 dict.Set("secure_dns_policy",
408 base::strict_cast<int>(parameters_.secure_dns_policy));
409 return dict;
410 });
411 }
412
LogFinishRequest(int net_error,bool async_completion)413 void HostResolverManager::RequestImpl::LogFinishRequest(int net_error,
414 bool async_completion) {
415 source_net_log_.EndEventWithNetErrorCode(
416 NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST, net_error);
417
418 if (!parameters_.is_speculative) {
419 DCHECK(!request_time_.is_null());
420 base::TimeDelta duration = tick_clock_->NowTicks() - request_time_;
421
422 DEPRECATED_UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTime",
423 duration);
424 if (async_completion) {
425 DEPRECATED_UMA_HISTOGRAM_MEDIUM_TIMES("Net.DNS.Request.TotalTimeAsync",
426 duration);
427 }
428 }
429 }
430
LogCancelRequest()431 void HostResolverManager::RequestImpl::LogCancelRequest() {
432 source_net_log_.AddEvent(NetLogEventType::CANCELLED);
433 source_net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST);
434 }
435
436 ClientSocketFactory*
GetClientSocketFactory()437 HostResolverManager::RequestImpl::GetClientSocketFactory() {
438 if (resolve_context_->url_request_context()) {
439 return resolve_context_->url_request_context()
440 ->GetNetworkSessionContext()
441 ->client_socket_factory;
442 } else {
443 return ClientSocketFactory::GetDefaultFactory();
444 }
445 }
446
447 } // namespace net
448