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_service_endpoint_request_impl.h"
6
7 #include "base/memory/safe_ref.h"
8 #include "base/no_destructor.h"
9 #include "base/notreached.h"
10 #include "base/types/optional_util.h"
11 #include "net/base/net_errors.h"
12 #include "net/dns/dns_alias_utility.h"
13 #include "net/dns/dns_task_results_manager.h"
14 #include "net/dns/host_resolver.h"
15 #include "net/dns/host_resolver_manager.h"
16 #include "url/scheme_host_port.h"
17
18 namespace net {
19
20 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::
FinalizedResult(std::vector<ServiceEndpoint> endpoints,std::set<std::string> dns_aliases)21 FinalizedResult(std::vector<ServiceEndpoint> endpoints,
22 std::set<std::string> dns_aliases)
23 : endpoints(std::move(endpoints)), dns_aliases(std::move(dns_aliases)) {}
24
25 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::
26 ~FinalizedResult() = default;
27
28 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::
29 FinalizedResult(FinalizedResult&&) = default;
30 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult&
31 HostResolverManager::ServiceEndpointRequestImpl::FinalizedResult::operator=(
32 FinalizedResult&&) = default;
33
ServiceEndpointRequestImpl(url::SchemeHostPort scheme_host_port,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,ResolveHostParameters parameters,base::WeakPtr<ResolveContext> resolve_context,base::WeakPtr<HostResolverManager> manager,const base::TickClock * tick_clock)34 HostResolverManager::ServiceEndpointRequestImpl::ServiceEndpointRequestImpl(
35 url::SchemeHostPort scheme_host_port,
36 NetworkAnonymizationKey network_anonymization_key,
37 NetLogWithSource net_log,
38 ResolveHostParameters parameters,
39 base::WeakPtr<ResolveContext> resolve_context,
40 base::WeakPtr<HostResolverManager> manager,
41 const base::TickClock* tick_clock)
42 : host_(std::move(scheme_host_port)),
43 network_anonymization_key_(
44 NetworkAnonymizationKey::IsPartitioningEnabled()
45 ? std::move(network_anonymization_key)
46 : NetworkAnonymizationKey()),
47 net_log_(std::move(net_log)),
48 parameters_(std::move(parameters)),
49 resolve_context_(std::move(resolve_context)),
50 manager_(std::move(manager)),
51 tick_clock_(tick_clock),
52 priority_(parameters_.initial_priority) {}
53
~ServiceEndpointRequestImpl()54 HostResolverManager::ServiceEndpointRequestImpl::~ServiceEndpointRequestImpl() {
55 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56 if (!job_.has_value()) {
57 return;
58 }
59
60 LogCancelRequest();
61
62 // Clear the delegate to avoid calling delegate's callback after destruction.
63 // The following CancelServiceEndpointRequest() could result in calling
64 // OnJobCancelled() synchronously.
65 delegate_ = nullptr;
66
67 job_.value()->CancelServiceEndpointRequest(this);
68 }
69
Start(Delegate * delegate)70 int HostResolverManager::ServiceEndpointRequestImpl::Start(Delegate* delegate) {
71 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
72 CHECK(!delegate_);
73 CHECK(manager_);
74
75 if (!resolve_context_) {
76 return ERR_CONTEXT_SHUT_DOWN;
77 }
78
79 delegate_ = delegate;
80
81 JobKey job_key(host_, resolve_context_.get());
82 IPAddress ip_address;
83 manager_->InitializeJobKeyAndIPAddress(
84 network_anonymization_key_, parameters_, net_log_, job_key, ip_address);
85
86 // Try to resolve locally first.
87 std::optional<HostCache::EntryStaleness> stale_info;
88 std::deque<TaskType> tasks;
89 HostCache::Entry results = manager_->ResolveLocally(
90 /*only_ipv6_reachable=*/false, job_key, ip_address,
91 parameters_.cache_usage, parameters_.secure_dns_policy,
92 parameters_.source, net_log_, host_cache(), &tasks, &stale_info);
93 if (results.error() != ERR_DNS_CACHE_MISS ||
94 parameters_.source == HostResolverSource::LOCAL_ONLY || tasks.empty()) {
95 SetFinalizedResultFromLegacyResults(results);
96 return results.error();
97 }
98
99 manager_->CreateAndStartJobForServiceEndpointRequest(std::move(job_key),
100 std::move(tasks), this);
101 return ERR_IO_PENDING;
102 }
103
104 const std::vector<ServiceEndpoint>&
GetEndpointResults()105 HostResolverManager::ServiceEndpointRequestImpl::GetEndpointResults() {
106 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107
108 if (finalized_result_.has_value()) {
109 return finalized_result_->endpoints;
110 }
111
112 if (job_) {
113 CHECK(job_.value()->dns_task_results_manager());
114 return job_.value()->dns_task_results_manager()->GetCurrentEndpoints();
115 }
116
117 NOTREACHED_NORETURN();
118 }
119
120 const std::set<std::string>&
GetDnsAliasResults()121 HostResolverManager::ServiceEndpointRequestImpl::GetDnsAliasResults() {
122 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
123
124 if (finalized_result_.has_value()) {
125 return finalized_result_->dns_aliases;
126 }
127
128 if (job_) {
129 CHECK(job_.value()->dns_task_results_manager());
130 // TODO(crbug.com/41493696): Call dns_alias_utility::FixUpDnsAliases().
131 return job_.value()->dns_task_results_manager()->GetAliases();
132 }
133
134 NOTREACHED_NORETURN();
135 }
136
EndpointsCryptoReady()137 bool HostResolverManager::ServiceEndpointRequestImpl::EndpointsCryptoReady() {
138 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
139
140 if (finalized_result_.has_value()) {
141 return true;
142 }
143
144 if (job_) {
145 CHECK(job_.value()->dns_task_results_manager());
146 return job_.value()->dns_task_results_manager()->IsMetadataReady();
147 }
148
149 NOTREACHED_NORETURN();
150 }
151
AssignJob(base::SafeRef<Job> job)152 void HostResolverManager::ServiceEndpointRequestImpl::AssignJob(
153 base::SafeRef<Job> job) {
154 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
155 CHECK(!job_.has_value());
156 job_ = job;
157 }
158
OnJobCompleted(const HostCache::Entry & results,bool obtained_securely)159 void HostResolverManager::ServiceEndpointRequestImpl::OnJobCompleted(
160 const HostCache::Entry& results,
161 bool obtained_securely) {
162 CHECK(job_);
163 CHECK(delegate_);
164 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
165
166 job_.reset();
167 SetFinalizedResultFromLegacyResults(results);
168
169 const bool is_secure_network_error =
170 obtained_securely && results.error() != OK;
171 error_info_ = ResolveErrorInfo(results.error(), is_secure_network_error);
172 delegate_->OnServiceEndpointRequestFinished(results.error());
173 // Do not add code below. `this` may be deleted at this point.
174 }
175
OnJobCancelled()176 void HostResolverManager::ServiceEndpointRequestImpl::OnJobCancelled() {
177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 CHECK(job_);
179
180 job_.reset();
181
182 // The owner of `this` has already destroyed `this`.
183 if (!delegate_) {
184 return;
185 }
186
187 LogCancelRequest();
188
189 finalized_result_ = FinalizedResult(/*endpoints=*/{}, /*dns_aliases=*/{});
190 error_info_ = ResolveErrorInfo(ERR_DNS_REQUEST_CANCELLED,
191 /*is_secure_network_error=*/false);
192 delegate_->OnServiceEndpointRequestFinished(ERR_DNS_REQUEST_CANCELLED);
193 // Do not add code below. `this` may be deleted at this point.
194 }
195
196 void HostResolverManager::ServiceEndpointRequestImpl::
OnServiceEndpointsChanged()197 OnServiceEndpointsChanged() {
198 // This method is called asynchronously via a posted task. `job_` could
199 // be completed or cancelled before executing the task.
200 if (finalized_result_.has_value()) {
201 return;
202 }
203
204 CHECK(job_);
205 CHECK(job_.value()->dns_task_results_manager());
206 CHECK(delegate_);
207 delegate_->OnServiceEndpointsUpdated();
208 // Do not add code below. `this` may be deleted at this point.
209 }
210
211 base::WeakPtr<HostResolverManager::ServiceEndpointRequestImpl>
GetWeakPtr()212 HostResolverManager::ServiceEndpointRequestImpl::GetWeakPtr() {
213 return weak_ptr_factory_.GetWeakPtr();
214 }
215
216 void HostResolverManager::ServiceEndpointRequestImpl::
SetFinalizedResultFromLegacyResults(const HostCache::Entry & results)217 SetFinalizedResultFromLegacyResults(const HostCache::Entry& results) {
218 CHECK(!finalized_result_);
219 if (results.error() == OK && !parameters_.is_speculative) {
220 std::vector<IPEndPoint> ipv4_endpoints;
221 std::vector<IPEndPoint> ipv6_endpoints;
222 for (const auto& ip_endpoint : results.ip_endpoints()) {
223 std::vector<IPEndPoint>& ip_endpoints =
224 ip_endpoint.address().IsIPv6() ? ipv6_endpoints : ipv4_endpoints;
225 if (ip_endpoint.port() == 0) {
226 ip_endpoints.emplace_back(ip_endpoint.address(), host_.GetPort());
227 } else {
228 ip_endpoints.emplace_back(ip_endpoint);
229 }
230 }
231
232 // See HostCache::Entry::GetEndpoints.
233 std::vector<ServiceEndpoint> endpoints;
234 if (!ipv4_endpoints.empty() || !ipv6_endpoints.empty()) {
235 for (const auto& metadata : results.GetMetadatas()) {
236 if (!base::Contains(results.canonical_names(), metadata.target_name)) {
237 continue;
238 }
239
240 ServiceEndpoint endpoint;
241 endpoint.ipv4_endpoints = ipv4_endpoints;
242 endpoint.ipv6_endpoints = ipv6_endpoints;
243 endpoint.metadata = metadata;
244 endpoints.emplace_back(std::move(endpoint));
245 }
246
247 // Append Non-SVCB endpoints at the end for fallback.
248 // TODO(crbug.com/41493696): Revisit how to handle non-SVCB endpoints once
249 // the connection layer starts using this API. Adding non-SVCB endpoints
250 // here might be inconsistent with intermediate results generated by
251 // DnsTaskResultsManager, which doesn't append non-SVCB endpoints.
252 ServiceEndpoint non_alternative_endpoint;
253 non_alternative_endpoint.ipv4_endpoints = ipv4_endpoints;
254 non_alternative_endpoint.ipv6_endpoints = ipv6_endpoints;
255 endpoints.emplace_back(std::move(non_alternative_endpoint));
256 }
257
258 finalized_result_ =
259 FinalizedResult(std::move(endpoints),
260 dns_alias_utility::FixUpDnsAliases(results.aliases()));
261 } else {
262 finalized_result_ = FinalizedResult(/*endpoints=*/{}, /*dns_aliases=*/{});
263 }
264 }
265
LogCancelRequest()266 void HostResolverManager::ServiceEndpointRequestImpl::LogCancelRequest() {
267 net_log_.AddEvent(NetLogEventType::CANCELLED);
268 net_log_.EndEvent(NetLogEventType::HOST_RESOLVER_MANAGER_REQUEST);
269 }
270
271 } // namespace net
272