• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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/stale_host_resolver.h"
6 
7 #include <memory>
8 #include <optional>
9 #include <set>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/check_op.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/notreached.h"
18 #include "base/timer/timer.h"
19 #include "base/values.h"
20 #include "net/base/host_port_pair.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/network_anonymization_key.h"
23 #include "net/dns/context_host_resolver.h"
24 #include "net/dns/dns_util.h"
25 #include "net/dns/host_resolver.h"
26 #include "net/dns/public/host_resolver_results.h"
27 #include "net/dns/public/host_resolver_source.h"
28 #include "net/dns/public/resolve_error_info.h"
29 #include "net/log/net_log_with_source.h"
30 #include "url/scheme_host_port.h"
31 
32 namespace net {
33 
34 // A request made by the StaleHostResolver. May return fresh cached data,
35 // network data, or stale cached data.
36 class StaleHostResolver::RequestImpl : public HostResolver::ResolveHostRequest {
37  public:
38   // StaleOptions will be read directly from `resolver`.
39   RequestImpl(base::WeakPtr<StaleHostResolver> resolver,
40               const HostPortPair& host,
41               const NetworkAnonymizationKey& network_anonymization_key,
42               const NetLogWithSource& net_log,
43               const ResolveHostParameters& input_parameters,
44               const base::TickClock* tick_clock);
45   ~RequestImpl() override = default;
46 
47   // HostResolver::ResolveHostRequest implementation:
48   int Start(CompletionOnceCallback result_callback) override;
49   const AddressList* GetAddressResults() const override;
50   const HostResolverEndpointResults* GetEndpointResults() const override;
51   const std::vector<std::string>* GetTextResults() const override;
52   const std::vector<HostPortPair>* GetHostnameResults() const override;
53   const std::set<std::string>* GetDnsAliasResults() const override;
54   ResolveErrorInfo GetResolveErrorInfo() const override;
55   const std::optional<HostCache::EntryStaleness>& GetStaleInfo() const override;
56   void ChangeRequestPriority(RequestPriority priority) override;
57 
58   // Called on completion of an asynchronous (network) inner request. Expected
59   // to be called by StaleHostResolver::OnNetworkRequestComplete().
60   void OnNetworkRequestComplete(int error);
61 
62  private:
have_network_request() const63   bool have_network_request() const { return network_request_ != nullptr; }
have_cache_data() const64   bool have_cache_data() const { return cache_error_ != ERR_DNS_CACHE_MISS; }
have_returned() const65   bool have_returned() const { return result_callback_.is_null(); }
66 
67   // Determines if `cache_error_` and `cache_request_` represents a usable entry
68   // per the requirements of `resolver_->options_`.
69   bool CacheDataIsUsable() const;
70 
71   // Callback for `stale_timer_` that returns stale results.
72   void OnStaleDelayElapsed();
73 
74   base::WeakPtr<StaleHostResolver> resolver_;
75 
76   const HostPortPair host_;
77   const NetworkAnonymizationKey network_anonymization_key_;
78   const NetLogWithSource net_log_;
79   const ResolveHostParameters input_parameters_;
80 
81   // The callback passed into `Start()` to be called when the request returns.
82   CompletionOnceCallback result_callback_;
83 
84   // The error from the stale cache entry, if there was one.
85   // If not, ERR_DNS_CACHE_MISS.
86   int cache_error_;
87   // Inner local-only/stale-allowed request.
88   std::unique_ptr<ResolveHostRequest> cache_request_;
89   // A timer that fires when the `Request` should return stale results, if the
90   // underlying network request has not finished yet.
91   base::OneShotTimer stale_timer_;
92 
93   // An inner request for network results. Only set if `cache_request_` gave a
94   // stale or unusable result, and unset if the stale result is to be used as
95   // the overall result.
96   std::unique_ptr<ResolveHostRequest> network_request_;
97 
98   base::WeakPtrFactory<RequestImpl> weak_ptr_factory_{this};
99 };
100 
RequestImpl(base::WeakPtr<StaleHostResolver> resolver,const HostPortPair & host,const NetworkAnonymizationKey & network_anonymization_key,const NetLogWithSource & net_log,const ResolveHostParameters & input_parameters,const base::TickClock * tick_clock)101 StaleHostResolver::RequestImpl::RequestImpl(
102     base::WeakPtr<StaleHostResolver> resolver,
103     const HostPortPair& host,
104     const NetworkAnonymizationKey& network_anonymization_key,
105     const NetLogWithSource& net_log,
106     const ResolveHostParameters& input_parameters,
107     const base::TickClock* tick_clock)
108     : resolver_(std::move(resolver)),
109       host_(host),
110       network_anonymization_key_(network_anonymization_key),
111       net_log_(net_log),
112       input_parameters_(input_parameters),
113       cache_error_(ERR_DNS_CACHE_MISS),
114       stale_timer_(tick_clock) {
115   DCHECK(resolver_);
116 }
117 
Start(CompletionOnceCallback result_callback)118 int StaleHostResolver::RequestImpl::Start(
119     CompletionOnceCallback result_callback) {
120   DCHECK(resolver_);
121   DCHECK(!result_callback.is_null());
122 
123   HostResolver::ResolveHostParameters cache_parameters = input_parameters_;
124   cache_parameters.cache_usage =
125       HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED;
126   cache_parameters.source = HostResolverSource::LOCAL_ONLY;
127   cache_request_ = resolver_->inner_resolver_->CreateRequest(
128       host_, network_anonymization_key_, net_log_, cache_parameters);
129   int error =
130       cache_request_->Start(base::BindOnce([](int error) { NOTREACHED(); }));
131   DCHECK_NE(ERR_IO_PENDING, error);
132   cache_error_ = cache_request_->GetResolveErrorInfo().error;
133   DCHECK_NE(ERR_IO_PENDING, cache_error_);
134   // If it's a fresh cache hit (or literal), return it synchronously.
135   if (cache_error_ != ERR_DNS_CACHE_MISS &&
136       (!cache_request_->GetStaleInfo() ||
137        !cache_request_->GetStaleInfo().value().is_stale())) {
138     return cache_error_;
139   }
140 
141   if (cache_error_ != ERR_DNS_CACHE_MISS &&
142       input_parameters_.cache_usage ==
143           HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED) {
144     return cache_error_;
145   }
146 
147   result_callback_ = std::move(result_callback);
148 
149   if (CacheDataIsUsable()) {
150     // `stale_timer_` is deleted when the Request is deleted, so it's safe to
151     // use Unretained here.
152     stale_timer_.Start(
153         FROM_HERE, resolver_->options_.delay,
154         base::BindOnce(&StaleHostResolver::RequestImpl::OnStaleDelayElapsed,
155                        base::Unretained(this)));
156   } else {
157     cache_error_ = ERR_DNS_CACHE_MISS;
158     cache_request_.reset();
159   }
160 
161   // Don't check the cache again.
162   HostResolver::ResolveHostParameters no_cache_parameters = input_parameters_;
163   no_cache_parameters.cache_usage =
164       HostResolver::ResolveHostParameters::CacheUsage::DISALLOWED;
165   network_request_ = resolver_->inner_resolver_->CreateRequest(
166       host_, network_anonymization_key_, net_log_, no_cache_parameters);
167   int network_rv = network_request_->Start(
168       base::BindOnce(&StaleHostResolver::OnNetworkRequestComplete, resolver_,
169                      network_request_.get(), weak_ptr_factory_.GetWeakPtr()));
170 
171   // Network resolver has returned synchronously (for example by resolving from
172   // /etc/hosts).
173   if (network_rv != ERR_IO_PENDING) {
174     stale_timer_.Stop();
175   }
176   return network_rv;
177 }
178 
GetAddressResults() const179 const AddressList* StaleHostResolver::RequestImpl::GetAddressResults() const {
180   if (network_request_) {
181     return network_request_->GetAddressResults();
182   }
183 
184   DCHECK(cache_request_);
185   return cache_request_->GetAddressResults();
186 }
187 
188 const HostResolverEndpointResults*
GetEndpointResults() const189 StaleHostResolver::RequestImpl::GetEndpointResults() const {
190   if (network_request_) {
191     return network_request_->GetEndpointResults();
192   }
193 
194   DCHECK(cache_request_);
195   return cache_request_->GetEndpointResults();
196 }
197 
GetTextResults() const198 const std::vector<std::string>* StaleHostResolver::RequestImpl::GetTextResults()
199     const {
200   if (network_request_) {
201     return network_request_->GetTextResults();
202   }
203 
204   DCHECK(cache_request_);
205   return cache_request_->GetTextResults();
206 }
207 
208 const std::vector<HostPortPair>*
GetHostnameResults() const209 StaleHostResolver::RequestImpl::GetHostnameResults() const {
210   if (network_request_) {
211     return network_request_->GetHostnameResults();
212   }
213 
214   DCHECK(cache_request_);
215   return cache_request_->GetHostnameResults();
216 }
217 
218 const std::set<std::string>*
GetDnsAliasResults() const219 StaleHostResolver::RequestImpl::GetDnsAliasResults() const {
220   if (network_request_) {
221     return network_request_->GetDnsAliasResults();
222   }
223 
224   DCHECK(cache_request_);
225   return cache_request_->GetDnsAliasResults();
226 }
227 
GetResolveErrorInfo() const228 ResolveErrorInfo StaleHostResolver::RequestImpl::GetResolveErrorInfo() const {
229   if (network_request_) {
230     return network_request_->GetResolveErrorInfo();
231   }
232   DCHECK(cache_request_);
233   return cache_request_->GetResolveErrorInfo();
234 }
235 
236 const std::optional<HostCache::EntryStaleness>&
GetStaleInfo() const237 StaleHostResolver::RequestImpl::GetStaleInfo() const {
238   if (network_request_) {
239     return network_request_->GetStaleInfo();
240   }
241 
242   DCHECK(cache_request_);
243   return cache_request_->GetStaleInfo();
244 }
245 
ChangeRequestPriority(RequestPriority priority)246 void StaleHostResolver::RequestImpl::ChangeRequestPriority(
247     RequestPriority priority) {
248   if (network_request_) {
249     network_request_->ChangeRequestPriority(priority);
250   } else {
251     DCHECK(cache_request_);
252     cache_request_->ChangeRequestPriority(priority);
253   }
254 }
255 
OnNetworkRequestComplete(int error)256 void StaleHostResolver::RequestImpl::OnNetworkRequestComplete(int error) {
257   DCHECK(resolver_);
258   DCHECK(have_network_request());
259   DCHECK(!have_returned());
260 
261   bool return_stale_data_instead_of_network_name_not_resolved =
262       resolver_->options_.use_stale_on_name_not_resolved &&
263       error == ERR_NAME_NOT_RESOLVED && have_cache_data();
264 
265   stale_timer_.Stop();
266 
267   if (return_stale_data_instead_of_network_name_not_resolved) {
268     network_request_.reset();
269     std::move(result_callback_).Run(cache_error_);
270   } else {
271     cache_request_.reset();
272     std::move(result_callback_).Run(error);
273   }
274 }
275 
CacheDataIsUsable() const276 bool StaleHostResolver::RequestImpl::CacheDataIsUsable() const {
277   DCHECK(resolver_);
278   DCHECK(cache_request_);
279 
280   if (cache_error_ != OK) {
281     return false;
282   }
283 
284   DCHECK(cache_request_->GetStaleInfo());
285   const HostCache::EntryStaleness& staleness =
286       cache_request_->GetStaleInfo().value();
287 
288   if (resolver_->options_.max_expired_time != base::TimeDelta() &&
289       staleness.expired_by > resolver_->options_.max_expired_time) {
290     return false;
291   }
292   if (resolver_->options_.max_stale_uses > 0 &&
293       staleness.stale_hits > resolver_->options_.max_stale_uses) {
294     return false;
295   }
296   if (!resolver_->options_.allow_other_network &&
297       staleness.network_changes > 0) {
298     return false;
299   }
300   return true;
301 }
302 
OnStaleDelayElapsed()303 void StaleHostResolver::RequestImpl::OnStaleDelayElapsed() {
304   DCHECK(!have_returned());
305   DCHECK(have_cache_data());
306   DCHECK(have_network_request());
307 
308   // If resolver is destroyed after starting a request, the request is
309   // considered cancelled and callbacks must not be invoked. Logging the
310   // cancellation will happen on destruction of `this`.
311   if (!resolver_) {
312     network_request_.reset();
313     return;
314   }
315   DCHECK(CacheDataIsUsable());
316 
317   // Detach `network_request_` to allow it to complete and backfill the cache
318   // even if `this` is destroyed.
319   resolver_->DetachRequest(std::move(network_request_));
320 
321   std::move(result_callback_).Run(cache_error_);
322 }
323 
StaleOptions()324 StaleHostResolver::StaleOptions::StaleOptions()
325     : allow_other_network(false),
326       max_stale_uses(0),
327       use_stale_on_name_not_resolved(false) {}
328 
StaleHostResolver(std::unique_ptr<ContextHostResolver> inner_resolver,const StaleOptions & stale_options)329 StaleHostResolver::StaleHostResolver(
330     std::unique_ptr<ContextHostResolver> inner_resolver,
331     const StaleOptions& stale_options)
332     : inner_resolver_(std::move(inner_resolver)), options_(stale_options) {
333   DCHECK_LE(0, stale_options.max_expired_time.InMicroseconds());
334   DCHECK_LE(0, stale_options.max_stale_uses);
335 }
336 
337 StaleHostResolver::~StaleHostResolver() = default;
338 
OnShutdown()339 void StaleHostResolver::OnShutdown() {
340   inner_resolver_->OnShutdown();
341 }
342 
343 std::unique_ptr<HostResolver::ResolveHostRequest>
CreateRequest(url::SchemeHostPort host,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,std::optional<ResolveHostParameters> optional_parameters)344 StaleHostResolver::CreateRequest(
345     url::SchemeHostPort host,
346     NetworkAnonymizationKey network_anonymization_key,
347     NetLogWithSource net_log,
348     std::optional<ResolveHostParameters> optional_parameters) {
349   // TODO(crbug.com/40181080): Propagate scheme.
350   return CreateRequest(HostPortPair::FromSchemeHostPort(host),
351                        network_anonymization_key, net_log, optional_parameters);
352 }
353 
354 std::unique_ptr<HostResolver::ResolveHostRequest>
CreateRequest(const HostPortPair & host,const NetworkAnonymizationKey & network_anonymization_key,const NetLogWithSource & net_log,const std::optional<ResolveHostParameters> & optional_parameters)355 StaleHostResolver::CreateRequest(
356     const HostPortPair& host,
357     const NetworkAnonymizationKey& network_anonymization_key,
358     const NetLogWithSource& net_log,
359     const std::optional<ResolveHostParameters>& optional_parameters) {
360   DCHECK(tick_clock_);
361   return std::make_unique<RequestImpl>(
362       weak_ptr_factory_.GetWeakPtr(), host, network_anonymization_key, net_log,
363       optional_parameters.value_or(ResolveHostParameters()), tick_clock_);
364 }
365 
366 std::unique_ptr<HostResolver::ServiceEndpointRequest>
CreateServiceEndpointRequest(Host host,NetworkAnonymizationKey network_anonymization_key,NetLogWithSource net_log,ResolveHostParameters parameters)367 StaleHostResolver::CreateServiceEndpointRequest(
368     Host host,
369     NetworkAnonymizationKey network_anonymization_key,
370     NetLogWithSource net_log,
371     ResolveHostParameters parameters) {
372   // TODO(crbug.com/335119455): Figure out a plan to support the
373   // ServiceEndpointRequest API.
374   NOTIMPLEMENTED();
375   return nullptr;
376 }
377 
GetHostCache()378 HostCache* StaleHostResolver::GetHostCache() {
379   return inner_resolver_->GetHostCache();
380 }
381 
GetDnsConfigAsValue() const382 base::Value::Dict StaleHostResolver::GetDnsConfigAsValue() const {
383   return inner_resolver_->GetDnsConfigAsValue();
384 }
385 
SetRequestContext(URLRequestContext * request_context)386 void StaleHostResolver::SetRequestContext(URLRequestContext* request_context) {
387   inner_resolver_->SetRequestContext(request_context);
388 }
389 
SetTickClockForTesting(const base::TickClock * tick_clock)390 void StaleHostResolver::SetTickClockForTesting(
391     const base::TickClock* tick_clock) {
392   tick_clock_ = tick_clock;
393   inner_resolver_->SetTickClockForTesting(tick_clock);
394 }
395 
OnNetworkRequestComplete(ResolveHostRequest * network_request,base::WeakPtr<RequestImpl> stale_request,int error)396 void StaleHostResolver::OnNetworkRequestComplete(
397     ResolveHostRequest* network_request,
398     base::WeakPtr<RequestImpl> stale_request,
399     int error) {
400   if (detached_requests_.erase(network_request)) {
401     return;
402   }
403 
404   // If not a detached request, there should still be an owning RequestImpl.
405   // Otherwise the request should have been cancelled and this method never
406   // called.
407   DCHECK(stale_request);
408 
409   stale_request->OnNetworkRequestComplete(error);
410 }
411 
DetachRequest(std::unique_ptr<ResolveHostRequest> request)412 void StaleHostResolver::DetachRequest(
413     std::unique_ptr<ResolveHostRequest> request) {
414   DCHECK_EQ(0u, detached_requests_.count(request.get()));
415   detached_requests_[request.get()] = std::move(request);
416 }
417 
418 }  // namespace net
419