• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 #ifndef NET_DNS_RESOLVE_CONTEXT_H_
6 #define NET_DNS_RESOLVE_CONTEXT_H_
7 
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 #include "base/memory/raw_ptr.h"
13 #include "base/memory/safe_ref.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/metrics/sample_vector.h"
16 #include "base/observer_list.h"
17 #include "base/observer_list_types.h"
18 #include "base/time/default_clock.h"
19 #include "base/time/default_tick_clock.h"
20 #include "base/time/time.h"
21 #include "base/timer/timer.h"
22 #include "net/base/isolation_info.h"
23 #include "net/base/net_export.h"
24 #include "net/base/network_handle.h"
25 #include "net/dns/dns_config.h"
26 #include "net/dns/public/secure_dns_mode.h"
27 
28 namespace net {
29 
30 class ClassicDnsServerIterator;
31 class DnsSession;
32 class DnsServerIterator;
33 class DohDnsServerIterator;
34 class HostCache;
35 class HostResolverCache;
36 class URLRequestContext;
37 
38 // Represents various states of the DoH auto-upgrade process.
39 // These values are persisted to logs. Entries should not be renumbered and
40 // numeric values should never be reused. Update the corresponding enums.xml
41 // entry when making changes here.
42 enum class DohServerAutoupgradeStatus {
43   kSuccessWithNoPriorFailures = 0,
44   kSuccessWithSomePriorFailures = 1,
45   kFailureWithSomePriorSuccesses = 2,
46   kFailureWithNoPriorSuccesses = 3,
47 
48   kMaxValue = kFailureWithNoPriorSuccesses
49 };
50 
51 // Per-URLRequestContext data used by HostResolver. Expected to be owned by the
52 // ContextHostResolver, and all usage/references are expected to be cleaned up
53 // or cancelled before the URLRequestContext goes out of service.
54 class NET_EXPORT_PRIVATE ResolveContext : public base::CheckedObserver {
55  public:
56   // Number of failures allowed before a DoH server is designated 'unavailable'.
57   // In AUTOMATIC mode, non-probe DoH queries should not be sent to DoH servers
58   // that have reached this limit.
59   //
60   // This limit is different from the failure limit that governs insecure async
61   // resolver bypass in multiple ways: NXDOMAIN responses are never counted as
62   // failures, and the outcome of fallback queries is not taken into account.
63   static const int kAutomaticModeFailureLimit = 10;
64 
65   // The amount of time to wait after `StartDohAutoupgradeSuccessTimer()` is
66   // called before `EmitDohAutoupgradeSuccessMetrics()` will be called to
67   // possibly record the state of the DoH auto-upgrade process.
68   static constexpr base::TimeDelta kDohAutoupgradeSuccessMetricTimeout =
69       base::Minutes(1);
70 
71   class DohStatusObserver : public base::CheckedObserver {
72    public:
73     // Notification indicating that the current session for which DoH servers
74     // are being tracked has changed.
75     virtual void OnSessionChanged() = 0;
76 
77     // Notification indicating that a DoH server has been marked unavailable,
78     // but is ready for usage such as availability probes.
79     //
80     // |network_change| true if the invalidation was triggered by a network
81     // connection change.
82     virtual void OnDohServerUnavailable(bool network_change) = 0;
83 
84    protected:
85     DohStatusObserver() = default;
86     ~DohStatusObserver() override = default;
87   };
88 
89   ResolveContext(URLRequestContext* url_request_context,
90                  bool enable_caching,
91                  const base::Clock& clock = *base::DefaultClock::GetInstance(),
92                  const base::TickClock& tick_clock =
93                      *base::DefaultTickClock::GetInstance());
94 
95   ResolveContext(const ResolveContext&) = delete;
96   ResolveContext& operator=(const ResolveContext&) = delete;
97 
98   ~ResolveContext() override;
99 
100   // Returns an iterator for DoH DNS servers.
101   std::unique_ptr<DnsServerIterator> GetDohIterator(const DnsConfig& config,
102                                                     const SecureDnsMode& mode,
103                                                     const DnsSession* session);
104 
105   // Returns an iterator for classic DNS servers.
106   std::unique_ptr<DnsServerIterator> GetClassicDnsIterator(
107       const DnsConfig& config,
108       const DnsSession* session);
109 
110   // Returns whether |doh_server_index| is eligible for use in AUTOMATIC mode,
111   // that is that consecutive failures are less than kAutomaticModeFailureLimit
112   // and the server has had at least one successful query or probe. Always
113   // |false| if |session| is not the current session.
114   bool GetDohServerAvailability(size_t doh_server_index,
115                                 const DnsSession* session) const;
116 
117   // Returns the number of DoH servers available for use in AUTOMATIC mode (see
118   // GetDohServerAvailability()). Always 0 if |session| is not the current
119   // session.
120   size_t NumAvailableDohServers(const DnsSession* session) const;
121 
122   // Record failure to get a response from the server (e.g. SERVFAIL, connection
123   // failures, or that the server failed to respond before the fallback period
124   // elapsed. If |is_doh_server| and the number of failures has surpassed a
125   // threshold, sets the DoH probe state to unavailable. Noop if |session| is
126   // not the current session. Should only be called with with server failure
127   // |rv|s, not e.g. OK, ERR_NAME_NOT_RESOLVED (which at the transaction level
128   // is expected to be nxdomain), or ERR_IO_PENDING.
129   void RecordServerFailure(size_t server_index,
130                            bool is_doh_server,
131                            int rv,
132                            const DnsSession* session);
133 
134   // Record that server responded successfully. Noop if |session| is not the
135   // current session.
136   void RecordServerSuccess(size_t server_index,
137                            bool is_doh_server,
138                            const DnsSession* session);
139 
140   // Record how long it took to receive a response from the server. Noop if
141   // |session| is not the current session.
142   void RecordRtt(size_t server_index,
143                  bool is_doh_server,
144                  base::TimeDelta rtt,
145                  int rv,
146                  const DnsSession* session);
147 
148   // Return the period the next query should run before fallback to next
149   // attempt. (Not actually a "timeout" because queries are not typically
150   // cancelled as additional attempts are made.) |attempt| counts from 0 and is
151   // used for exponential backoff.
152   base::TimeDelta NextClassicFallbackPeriod(size_t classic_server_index,
153                                             int attempt,
154                                             const DnsSession* session);
155 
156   // Return the period the next DoH query should run before fallback to next
157   // attempt.
158   base::TimeDelta NextDohFallbackPeriod(size_t doh_server_index,
159                                         const DnsSession* session);
160 
161   // Return a timeout for an insecure transaction (from Transaction::Start()).
162   // Expected that the transaction will skip waiting for this timeout if it is
163   // using fast timeouts, and also expected that transactions will always wait
164   // for all attempts to run for at least their fallback period before dying
165   // with timeout.
166   base::TimeDelta ClassicTransactionTimeout(const DnsSession* session);
167 
168   // Return a timeout for a secure transaction (from Transaction::Start()).
169   // Expected that the transaction will skip waiting for this timeout if it is
170   // using fast timeouts, and also expected that transactions will always wait
171   // for all attempts to run for at least their fallback period before dying
172   // with timeout.
173   base::TimeDelta SecureTransactionTimeout(SecureDnsMode secure_dns_mode,
174                                            const DnsSession* session);
175 
176   void RegisterDohStatusObserver(DohStatusObserver* observer);
177   void UnregisterDohStatusObserver(const DohStatusObserver* observer);
178 
url_request_context()179   URLRequestContext* url_request_context() { return url_request_context_; }
url_request_context()180   const URLRequestContext* url_request_context() const {
181     return url_request_context_;
182   }
set_url_request_context(URLRequestContext * url_request_context)183   void set_url_request_context(URLRequestContext* url_request_context) {
184     DCHECK(!url_request_context_);
185     DCHECK(url_request_context);
186     url_request_context_ = url_request_context;
187   }
188 
host_cache()189   HostCache* host_cache() { return host_cache_.get(); }
host_resolver_cache()190   HostResolverCache* host_resolver_cache() {
191     return host_resolver_cache_.get();
192   }
193 
194   // Invalidate or clear saved per-context cached data that is not expected to
195   // stay valid between connections or sessions (eg the HostCache and DNS server
196   // stats). |new_session|, if non-null, will be the new "current" session for
197   // which per-session data will be kept.
198   void InvalidateCachesAndPerSessionData(const DnsSession* new_session,
199                                          bool network_change);
200 
current_session_for_testing()201   const DnsSession* current_session_for_testing() const {
202     return current_session_.get();
203   }
204 
205   void StartDohAutoupgradeSuccessTimer(const DnsSession* session);
206 
doh_autoupgrade_metrics_timer_is_running_for_testing()207   bool doh_autoupgrade_metrics_timer_is_running_for_testing() {
208     return doh_autoupgrade_success_metric_timer_.IsRunning();
209   }
210 
211   // Returns IsolationInfo that should be used for DoH requests. Using a single
212   // transient IsolationInfo ensures that DNS requests aren't pooled with normal
213   // web requests, but still allows them to be pooled with each other, to allow
214   // reusing connections to the DoH server across different third party
215   // contexts. One downside of a transient IsolationInfo is that it means
216   // metadata about the DoH server itself will not be cached across restarts
217   // (alternative service info if it supports QUIC, for instance).
isolation_info()218   const IsolationInfo& isolation_info() const { return isolation_info_; }
219 
220   // Network to perform the DNS lookups for. When equal to
221   // handles::kInvalidNetworkHandle the decision of which one to target is left
222   // to the resolver. Virtual for testing.
223   virtual handles::NetworkHandle GetTargetNetwork() const;
224 
AsSafeRef()225   base::SafeRef<ResolveContext> AsSafeRef() {
226     return weak_ptr_factory_.GetSafeRef();
227   }
228 
GetWeakPtr()229   base::WeakPtr<ResolveContext> GetWeakPtr() {
230     return weak_ptr_factory_.GetWeakPtr();
231   }
232 
233  private:
234   friend DohDnsServerIterator;
235   friend ClassicDnsServerIterator;
236   // Runtime statistics of DNS server.
237   struct ServerStats {
238     explicit ServerStats(std::unique_ptr<base::SampleVector> rtt_histogram);
239 
240     ServerStats(ServerStats&&);
241 
242     ~ServerStats();
243 
244     // Count of consecutive failures after last success.
245     int last_failure_count = 0;
246 
247     // True if any success has ever been recorded for this server for the
248     // current connection.
249     bool current_connection_success = false;
250 
251     // Last time when server returned failure or exceeded fallback period. Reset
252     // each time that a server returned success.
253     base::TimeTicks last_failure;
254     // Last time when server returned success.
255     base::TimeTicks last_success;
256     // Whether the server has ever returned failure. Used for per-provider
257     // health metrics.
258     bool has_failed_previously = false;
259 
260     // A histogram of observed RTT .
261     std::unique_ptr<base::SampleVector> rtt_histogram;
262   };
263 
264   // Return the (potentially rotating) index of the first configured server (to
265   // be passed to [Doh]ServerIndexToUse()). Always returns 0 if |session| is not
266   // the current session.
267   size_t FirstServerIndex(bool doh_server, const DnsSession* session);
268 
269   bool IsCurrentSession(const DnsSession* session) const;
270 
271   // Returns the ServerStats for the designated server. Returns nullptr if no
272   // ServerStats found.
273   ServerStats* GetServerStats(size_t server_index, bool is_doh_server);
274 
275   // Return the fallback period for the next query.
276   base::TimeDelta NextFallbackPeriodHelper(const ServerStats* server_stats,
277                                            int attempt);
278 
279   template <typename Iterator>
280   base::TimeDelta TransactionTimeoutHelper(Iterator server_stats_begin,
281                                            Iterator server_stats_end);
282 
283   // Record the time to perform a query.
284   void RecordRttForUma(size_t server_index,
285                        bool is_doh_server,
286                        base::TimeDelta rtt,
287                        int rv,
288                        base::TimeDelta base_fallback_period,
289                        const DnsSession* session);
290   std::string GetQueryTypeForUma(size_t server_index,
291                                  bool is_doh_server,
292                                  const DnsSession* session);
293   std::string GetDohProviderIdForUma(size_t server_index,
294                                      bool is_doh_server,
295                                      const DnsSession* session);
296   bool GetProviderUseExtraLogging(size_t server_index,
297                                   bool is_doh_server,
298                                   const DnsSession* session);
299 
300   void NotifyDohStatusObserversOfSessionChanged();
301   void NotifyDohStatusObserversOfUnavailable(bool network_change);
302 
303   static bool ServerStatsToDohAvailability(const ServerStats& stats);
304 
305   // Emit histograms indicating the current state of all configured DoH
306   // providers (for use in determining whether DoH auto-upgrade was successful).
307   void EmitDohAutoupgradeSuccessMetrics();
308 
309   raw_ptr<URLRequestContext> url_request_context_;
310 
311   std::unique_ptr<HostCache> host_cache_;
312   std::unique_ptr<HostResolverCache> host_resolver_cache_;
313 
314   // Current maximum server fallback period. Updated on connection change.
315   base::TimeDelta max_fallback_period_;
316 
317   // All DohStatusObservers only hold a WeakPtr<ResolveContext>, so there's no
318   // need for check_empty to be true.
319   base::ObserverList<DohStatusObserver,
320                      false /* check_empty */,
321                      false /* allow_reentrancy */>
322       doh_status_observers_;
323 
324   // Per-session data is only stored and valid for the latest session. Before
325   // accessing, should check that |current_session_| is valid and matches a
326   // passed in DnsSession.
327   //
328   // Using a WeakPtr, so even if a new session has the same pointer as an old
329   // invalidated session, it can be recognized as a different session.
330   //
331   // TODO(crbug.com/40106440): Make const DnsSession once server stats have been
332   // moved and no longer need to be read from DnsSession for availability logic.
333   base::WeakPtr<const DnsSession> current_session_;
334   // Current index into |config_.nameservers| to begin resolution with.
335   int classic_server_index_ = 0;
336   base::TimeDelta initial_fallback_period_;
337   // Track runtime statistics of each classic (insecure) DNS server.
338   std::vector<ServerStats> classic_server_stats_;
339   // Track runtime statistics of each DoH server.
340   std::vector<ServerStats> doh_server_stats_;
341 
342   const IsolationInfo isolation_info_;
343 
344   base::OneShotTimer doh_autoupgrade_success_metric_timer_;
345 
346   base::WeakPtrFactory<ResolveContext> weak_ptr_factory_{this};
347 };
348 
349 }  // namespace net
350 
351 #endif  // NET_DNS_RESOLVE_CONTEXT_H_
352