xref: /aosp_15_r20/external/cronet/net/dns/host_resolver_cache.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 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_HOST_RESOLVER_CACHE_H_
6 #define NET_DNS_HOST_RESOLVER_CACHE_H_
7 
8 #include <cstddef>
9 #include <map>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <string_view>
14 #include <tuple>
15 #include <utility>
16 #include <vector>
17 
18 #include "base/memory/raw_ref.h"
19 #include "base/time/clock.h"
20 #include "base/time/default_clock.h"
21 #include "base/time/default_tick_clock.h"
22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "net/base/net_export.h"
25 #include "net/base/network_anonymization_key.h"
26 #include "net/dns/public/dns_query_type.h"
27 #include "net/dns/public/host_resolver_source.h"
28 
29 namespace net {
30 
31 class HostResolverInternalResult;
32 
33 // Cache used by HostResolverManager to save previously resolved information.
34 class NET_EXPORT HostResolverCache final {
35  public:
36   struct StaleLookupResult {
37     StaleLookupResult(const HostResolverInternalResult& result,
38                       std::optional<base::TimeDelta> expired_by,
39                       bool stale_by_generation);
40     ~StaleLookupResult() = default;
41 
42     const raw_ref<const HostResolverInternalResult> result;
43 
44     // Time since the result's TTL has expired. nullopt if not expired.
45     const std::optional<base::TimeDelta> expired_by;
46 
47     // True if result is stale due to a call to
48     // HostResolverCache::MakeAllResultsStale().
49     const bool stale_by_generation;
50 
IsStaleStaleLookupResult51     bool IsStale() const {
52       return stale_by_generation || expired_by.has_value();
53     }
54   };
55 
56   explicit HostResolverCache(
57       size_t max_results,
58       const base::Clock& clock = *base::DefaultClock::GetInstance(),
59       const base::TickClock& tick_clock =
60           *base::DefaultTickClock::GetInstance());
61   ~HostResolverCache();
62 
63   // Move-only.
64   HostResolverCache(HostResolverCache&&);
65   HostResolverCache& operator=(HostResolverCache&&);
66 
67   // Lookup an active (non-stale) cached result matching the given criteria. If
68   // `query_type` is `DnsQueryType::UNSPECIFIED`, `source` is
69   // `HostResolverSource::ANY`, or `secure` is `std::nullopt`, it is a wildcard
70   // that can match for any cached parameter of that type. In cases where a
71   // wildcard lookup leads to multiple matching results, only one result will be
72   // returned, preferring first the most secure result and then the most
73   // recently set one. Additionally, if a cached result has
74   // `DnsQueryType::UNSPECIFIED`, it will match for any argument of
75   // `query_type`.
76   //
77   // Returns nullptr on cache miss (no active result matches the given
78   // criteria).
79   const HostResolverInternalResult* Lookup(
80       std::string_view domain_name,
81       const NetworkAnonymizationKey& network_anonymization_key,
82       DnsQueryType query_type = DnsQueryType::UNSPECIFIED,
83       HostResolverSource source = HostResolverSource::ANY,
84       std::optional<bool> secure = std::nullopt) const;
85 
86   // Lookup a cached result matching the given criteria. Unlike Lookup(), may
87   // return stale results. In cases where a wildcard lookup leads to multiple
88   // matching results, only one result will be returned, preferring active
89   // (non-stale) results, then the least stale by generation, then the least
90   // stale by time expiration, then the most secure, then the most recently set.
91   //
92   // Used to implement
93   // `HostResolver::ResolveHostParameters::CacheUsage::STALE_ALLOWED` behavior,
94   // which is itself primarily for usage by cronet::StaleHostResolver, but no
95   // assumptions are made here that this is Cronet-only behavior.
96   //
97   // Returns nullopt on cache miss (no active or stale result matches the given
98   // criteria).
99   std::optional<StaleLookupResult> LookupStale(
100       std::string_view domain_name,
101       const NetworkAnonymizationKey& network_anonymization_key,
102       DnsQueryType query_type = DnsQueryType::UNSPECIFIED,
103       HostResolverSource source = HostResolverSource::ANY,
104       std::optional<bool> secure = std::nullopt) const;
105 
106   // Sets the result into the cache, replacing any previous result entries that
107   // would match the same criteria, even if a previous entry would have matched
108   // more criteria than the new one, e.g. if the previous entry used a wildcard
109   // `DnsQueryType::UNSPECIFIED`.
110   void Set(std::unique_ptr<HostResolverInternalResult> result,
111            const NetworkAnonymizationKey& network_anonymization_key,
112            HostResolverSource source,
113            bool secure);
114 
115   // Makes all cached results considered stale. Typically used for network
116   // change to ensure cached results are only considered active for the current
117   // network.
118   void MakeAllResultsStale();
119 
120   // Serialization to later be deserialized. Only serializes the results likely
121   // to still be of value after serialization and deserialization, that is that
122   // results with a transient anonymization key are not included.
123   //
124   // Used to implement cronet::HostCachePersistenceManager, but no assumptions
125   // are made here that this is Cronet-only functionality.
126   base::Value Serialize() const;
127 
128   // Deserialize value received from Serialize(). Results already contained in
129   // the cache are preferred, thus deserialized results are ignored if any
130   // previous result entries would match the same criteria, and deserialization
131   // stops on reaching max size, rather than evicting anything. Deserialized
132   // results are also always considered stale by generation.
133   //
134   // Returns false if `value` is malformed to be deserialized.
135   //
136   // Used to implement cronet::HostCachePersistenceManager, but no assumptions
137   // are made here that this is Cronet-only functionality.
138   bool RestoreFromValue(const base::Value& value);
139 
140   // Serialize for output to debug logs, e.g. netlog. Serializes all results,
141   // including those with transient anonymization keys, and also serializes
142   // cache-wide data. Incompatible with base::Values returned from Serialize(),
143   // and cannot be used in RestoreFromValue().
144   base::Value SerializeForLogging() const;
145 
AtMaxSizeForTesting()146   bool AtMaxSizeForTesting() const { return entries_.size() >= max_entries_; }
147 
148  private:
149   struct Key {
150     ~Key();
151 
152     std::string domain_name;
153     NetworkAnonymizationKey network_anonymization_key;
154   };
155 
156   struct KeyRef {
157     ~KeyRef() = default;
158 
159     std::string_view domain_name;
160     const raw_ref<const NetworkAnonymizationKey> network_anonymization_key;
161   };
162 
163   // Allow comparing Key to KeyRef to allow refs for entry lookup.
164   struct KeyComparator {
165     using is_transparent = void;
166 
167     ~KeyComparator() = default;
168 
operatorKeyComparator169     bool operator()(const Key& lhs, const Key& rhs) const {
170       return std::tie(lhs.domain_name, lhs.network_anonymization_key) <
171              std::tie(rhs.domain_name, rhs.network_anonymization_key);
172     }
173 
operatorKeyComparator174     bool operator()(const Key& lhs, const KeyRef& rhs) const {
175       return std::tie(lhs.domain_name, lhs.network_anonymization_key) <
176              std::tie(rhs.domain_name, *rhs.network_anonymization_key);
177     }
178 
operatorKeyComparator179     bool operator()(const KeyRef& lhs, const Key& rhs) const {
180       return std::tie(lhs.domain_name, *lhs.network_anonymization_key) <
181              std::tie(rhs.domain_name, rhs.network_anonymization_key);
182     }
183   };
184 
185   struct Entry {
186     Entry(std::unique_ptr<HostResolverInternalResult> result,
187           HostResolverSource source,
188           bool secure,
189           int staleness_generation);
190     ~Entry();
191 
192     Entry(Entry&&);
193     Entry& operator=(Entry&&);
194 
195     bool IsStale(base::Time now,
196                  base::TimeTicks now_ticks,
197                  int current_staleness_generation) const;
198     base::TimeDelta TimeUntilExpiration(base::Time now,
199                                         base::TimeTicks now_ticks) const;
200 
201     std::unique_ptr<HostResolverInternalResult> result;
202     HostResolverSource source;
203     bool secure;
204 
205     // The `HostResolverCache::staleness_generation_` value at the time this
206     // entry was created. Entry is stale if this does not match the current
207     // value.
208     int staleness_generation;
209   };
210 
211   using EntryMap = std::multimap<Key, Entry, KeyComparator>;
212 
213   // Get all matching results, from most to least recently added.
214   std::vector<EntryMap::const_iterator> LookupInternal(
215       std::string_view domain_name,
216       const NetworkAnonymizationKey& network_anonymization_key,
217       DnsQueryType query_type,
218       HostResolverSource source,
219       std::optional<bool> secure) const;
220 
221   void Set(std::unique_ptr<HostResolverInternalResult> result,
222            const NetworkAnonymizationKey& network_anonymization_key,
223            HostResolverSource source,
224            bool secure,
225            bool replace_existing,
226            int staleness_generation);
227 
228   void EvictEntries();
229 
230   // If `require_persistable_anonymization_key` is true, will not serialize
231   // any entries that do not have an anonymization key that supports
232   // serialization and restoration. If false, will serialize all entries, but
233   // the result may contain anonymization keys that are malformed for
234   // restoration.
235   base::Value SerializeEntries(
236       bool serialize_staleness_generation,
237       bool require_persistable_anonymization_key) const;
238 
239   EntryMap entries_;
240   size_t max_entries_;
241 
242   // Number of times MakeAllEntriesStale() has been called.
243   int staleness_generation_ = 0;
244 
245   raw_ref<const base::Clock> clock_;
246   raw_ref<const base::TickClock> tick_clock_;
247 };
248 
249 }  // namespace net
250 
251 #endif  // NET_DNS_HOST_RESOLVER_CACHE_H_
252