resolve_context.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef NET_DNS_RESOLVE_CONTEXT_H_
  5. #define NET_DNS_RESOLVE_CONTEXT_H_
  6. #include <memory>
  7. #include <string>
  8. #include <vector>
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/memory/safe_ref.h"
  11. #include "base/memory/weak_ptr.h"
  12. #include "base/metrics/sample_vector.h"
  13. #include "base/observer_list.h"
  14. #include "base/observer_list_types.h"
  15. #include "base/time/time.h"
  16. #include "net/base/isolation_info.h"
  17. #include "net/base/net_export.h"
  18. #include "net/base/network_handle.h"
  19. #include "net/dns/dns_config.h"
  20. #include "net/dns/public/secure_dns_mode.h"
  21. namespace net {
  22. class ClassicDnsServerIterator;
  23. class DnsSession;
  24. class DnsServerIterator;
  25. class DohDnsServerIterator;
  26. class HostCache;
  27. class URLRequestContext;
  28. // Per-URLRequestContext data used by HostResolver. Expected to be owned by the
  29. // ContextHostResolver, and all usage/references are expected to be cleaned up
  30. // or cancelled before the URLRequestContext goes out of service.
  31. class NET_EXPORT_PRIVATE ResolveContext : public base::CheckedObserver {
  32. public:
  33. // Number of failures allowed before a DoH server is designated 'unavailable'.
  34. // In AUTOMATIC mode, non-probe DoH queries should not be sent to DoH servers
  35. // that have reached this limit.
  36. //
  37. // This limit is different from the failure limit that governs insecure async
  38. // resolver bypass in multiple ways: NXDOMAIN responses are never counted as
  39. // failures, and the outcome of fallback queries is not taken into account.
  40. static const int kAutomaticModeFailureLimit = 10;
  41. class DohStatusObserver : public base::CheckedObserver {
  42. public:
  43. // Notification indicating that the current session for which DoH servers
  44. // are being tracked has changed.
  45. virtual void OnSessionChanged() = 0;
  46. // Notification indicating that a DoH server has been marked unavailable,
  47. // but is ready for usage such as availability probes.
  48. //
  49. // |network_change| true if the invalidation was triggered by a network
  50. // connection change.
  51. virtual void OnDohServerUnavailable(bool network_change) = 0;
  52. protected:
  53. DohStatusObserver() = default;
  54. ~DohStatusObserver() override = default;
  55. };
  56. ResolveContext(URLRequestContext* url_request_context, bool enable_caching);
  57. ResolveContext(const ResolveContext&) = delete;
  58. ResolveContext& operator=(const ResolveContext&) = delete;
  59. ~ResolveContext() override;
  60. // Returns an iterator for DoH DNS servers.
  61. std::unique_ptr<DnsServerIterator> GetDohIterator(const DnsConfig& config,
  62. const SecureDnsMode& mode,
  63. const DnsSession* session);
  64. // Returns an iterator for classic DNS servers.
  65. std::unique_ptr<DnsServerIterator> GetClassicDnsIterator(
  66. const DnsConfig& config,
  67. const DnsSession* session);
  68. // Returns whether |doh_server_index| is eligible for use in AUTOMATIC mode,
  69. // that is that consecutive failures are less than kAutomaticModeFailureLimit
  70. // and the server has had at least one successful query or probe. Always
  71. // |false| if |session| is not the current session.
  72. bool GetDohServerAvailability(size_t doh_server_index,
  73. const DnsSession* session) const;
  74. // Returns the number of DoH servers available for use in AUTOMATIC mode (see
  75. // GetDohServerAvailability()). Always 0 if |session| is not the current
  76. // session.
  77. size_t NumAvailableDohServers(const DnsSession* session) const;
  78. // Record failure to get a response from the server (e.g. SERVFAIL, connection
  79. // failures, or that the server failed to respond before the fallback period
  80. // elapsed. If |is_doh_server| and the number of failures has surpassed a
  81. // threshold, sets the DoH probe state to unavailable. Noop if |session| is
  82. // not the current session. Should only be called with with server failure
  83. // |rv|s, not e.g. OK, ERR_NAME_NOT_RESOLVED (which at the transaction level
  84. // is expected to be nxdomain), or ERR_IO_PENDING.
  85. void RecordServerFailure(size_t server_index,
  86. bool is_doh_server,
  87. int rv,
  88. const DnsSession* session);
  89. // Record that server responded successfully. Noop if |session| is not the
  90. // current session.
  91. void RecordServerSuccess(size_t server_index,
  92. bool is_doh_server,
  93. const DnsSession* session);
  94. // Record how long it took to receive a response from the server. Noop if
  95. // |session| is not the current session.
  96. void RecordRtt(size_t server_index,
  97. bool is_doh_server,
  98. base::TimeDelta rtt,
  99. int rv,
  100. const DnsSession* session);
  101. // Return the period the next query should run before fallback to next
  102. // attempt. (Not actually a "timeout" because queries are not typically
  103. // cancelled as additional attempts are made.) |attempt| counts from 0 and is
  104. // used for exponential backoff.
  105. base::TimeDelta NextClassicFallbackPeriod(size_t classic_server_index,
  106. int attempt,
  107. const DnsSession* session);
  108. // Return the period the next DoH query should run before fallback to next
  109. // attempt.
  110. base::TimeDelta NextDohFallbackPeriod(size_t doh_server_index,
  111. const DnsSession* session);
  112. // Return a timeout for an insecure transaction (from Transaction::Start()).
  113. // Expected that the transaction will skip waiting for this timeout if it is
  114. // using fast timeouts, and also expected that transactions will always wait
  115. // for all attempts to run for at least their fallback period before dying
  116. // with timeout.
  117. base::TimeDelta ClassicTransactionTimeout(const DnsSession* session);
  118. // Return a timeout for a secure transaction (from Transaction::Start()).
  119. // Expected that the transaction will skip waiting for this timeout if it is
  120. // using fast timeouts, and also expected that transactions will always wait
  121. // for all attempts to run for at least their fallback period before dying
  122. // with timeout.
  123. base::TimeDelta SecureTransactionTimeout(SecureDnsMode secure_dns_mode,
  124. const DnsSession* session);
  125. void RegisterDohStatusObserver(DohStatusObserver* observer);
  126. void UnregisterDohStatusObserver(const DohStatusObserver* observer);
  127. URLRequestContext* url_request_context() { return url_request_context_; }
  128. const URLRequestContext* url_request_context() const {
  129. return url_request_context_;
  130. }
  131. void set_url_request_context(URLRequestContext* url_request_context) {
  132. DCHECK(!url_request_context_);
  133. DCHECK(url_request_context);
  134. url_request_context_ = url_request_context;
  135. }
  136. HostCache* host_cache() { return host_cache_.get(); }
  137. // Invalidate or clear saved per-context cached data that is not expected to
  138. // stay valid between connections or sessions (eg the HostCache and DNS server
  139. // stats). |new_session|, if non-null, will be the new "current" session for
  140. // which per-session data will be kept.
  141. void InvalidateCachesAndPerSessionData(const DnsSession* new_session,
  142. bool network_change);
  143. const DnsSession* current_session_for_testing() const {
  144. return current_session_.get();
  145. }
  146. // Returns IsolationInfo that should be used for DoH requests. Using a single
  147. // transient IsolationInfo ensures that DNS requests aren't pooled with normal
  148. // web requests, but still allows them to be pooled with each other, to allow
  149. // reusing connections to the DoH server across different third party
  150. // contexts. One downside of a transient IsolationInfo is that it means
  151. // metadata about the DoH server itself will not be cached across restarts
  152. // (alternative service info if it supports QUIC, for instance).
  153. const IsolationInfo& isolation_info() const { return isolation_info_; }
  154. // Network to perform the DNS lookups for. When equal to
  155. // handles::kInvalidNetworkHandle the decision of which one to target is left
  156. // to the resolver. Virtual for testing.
  157. virtual handles::NetworkHandle GetTargetNetwork() const;
  158. base::SafeRef<ResolveContext> AsSafeRef() {
  159. return weak_ptr_factory_.GetSafeRef();
  160. }
  161. base::WeakPtr<ResolveContext> GetWeakPtr() {
  162. return weak_ptr_factory_.GetWeakPtr();
  163. }
  164. private:
  165. friend DohDnsServerIterator;
  166. friend ClassicDnsServerIterator;
  167. // Runtime statistics of DNS server.
  168. struct ServerStats {
  169. explicit ServerStats(std::unique_ptr<base::SampleVector> rtt_histogram);
  170. ServerStats(ServerStats&&);
  171. ~ServerStats();
  172. // Count of consecutive failures after last success.
  173. int last_failure_count = 0;
  174. // True if any success has ever been recorded for this server for the
  175. // current connection.
  176. bool current_connection_success = false;
  177. // Last time when server returned failure or exceeded fallback period.
  178. base::TimeTicks last_failure;
  179. // Last time when server returned success.
  180. base::TimeTicks last_success;
  181. // A histogram of observed RTT .
  182. std::unique_ptr<base::SampleVector> rtt_histogram;
  183. };
  184. // Return the (potentially rotating) index of the first configured server (to
  185. // be passed to [Doh]ServerIndexToUse()). Always returns 0 if |session| is not
  186. // the current session.
  187. size_t FirstServerIndex(bool doh_server, const DnsSession* session);
  188. bool IsCurrentSession(const DnsSession* session) const;
  189. // Returns the ServerStats for the designated server. Returns nullptr if no
  190. // ServerStats found.
  191. ServerStats* GetServerStats(size_t server_index, bool is_doh_server);
  192. // Return the fallback period for the next query.
  193. base::TimeDelta NextFallbackPeriodHelper(const ServerStats* server_stats,
  194. int attempt);
  195. template <typename Iterator>
  196. base::TimeDelta TransactionTimeoutHelper(Iterator server_stats_begin,
  197. Iterator server_stats_end);
  198. // Record the time to perform a query.
  199. void RecordRttForUma(size_t server_index,
  200. bool is_doh_server,
  201. base::TimeDelta rtt,
  202. int rv,
  203. base::TimeDelta base_fallback_period,
  204. const DnsSession* session);
  205. std::string GetQueryTypeForUma(size_t server_index,
  206. bool is_doh_server,
  207. const DnsSession* session);
  208. std::string GetDohProviderIdForUma(size_t server_index,
  209. bool is_doh_server,
  210. const DnsSession* session);
  211. bool GetProviderUseExtraLogging(size_t server_index,
  212. bool is_doh_server,
  213. const DnsSession* session);
  214. void NotifyDohStatusObserversOfSessionChanged();
  215. void NotifyDohStatusObserversOfUnavailable(bool network_change);
  216. static bool ServerStatsToDohAvailability(const ServerStats& stats);
  217. raw_ptr<URLRequestContext> url_request_context_;
  218. std::unique_ptr<HostCache> host_cache_;
  219. // Current maximum server fallback period. Updated on connection change.
  220. base::TimeDelta max_fallback_period_;
  221. // All DohStatusObservers only hold a WeakPtr<ResolveContext>, so there's no
  222. // need for check_empty to be true.
  223. base::ObserverList<DohStatusObserver,
  224. false /* check_empty */,
  225. false /* allow_reentrancy */>
  226. doh_status_observers_;
  227. // Per-session data is only stored and valid for the latest session. Before
  228. // accessing, should check that |current_session_| is valid and matches a
  229. // passed in DnsSession.
  230. //
  231. // Using a WeakPtr, so even if a new session has the same pointer as an old
  232. // invalidated session, it can be recognized as a different session.
  233. //
  234. // TODO(crbug.com/1022059): Make const DnsSession once server stats have been
  235. // moved and no longer need to be read from DnsSession for availability logic.
  236. base::WeakPtr<const DnsSession> current_session_;
  237. // Current index into |config_.nameservers| to begin resolution with.
  238. int classic_server_index_ = 0;
  239. base::TimeDelta initial_fallback_period_;
  240. // Track runtime statistics of each classic (insecure) DNS server.
  241. std::vector<ServerStats> classic_server_stats_;
  242. // Track runtime statistics of each DoH server.
  243. std::vector<ServerStats> doh_server_stats_;
  244. const IsolationInfo isolation_info_;
  245. base::WeakPtrFactory<ResolveContext> weak_ptr_factory_{this};
  246. };
  247. } // namespace net
  248. #endif // NET_DNS_RESOLVE_CONTEXT_H_