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