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