nsHostRecord.h (14320B)
1 /* vim:set ts=4 sw=2 sts=2 et cin: */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef nsHostRecord_h__ 7 #define nsHostRecord_h__ 8 9 #include "mozilla/AtomicBitfields.h" 10 #include "mozilla/DataMutex.h" 11 #include "mozilla/LinkedList.h" 12 #include "mozilla/net/HTTPSSVC.h" 13 #include "nsIDNSService.h" 14 #include "nsIDNSByTypeRecord.h" 15 #include "PLDHashTable.h" 16 #include "nsITRRSkipReason.h" 17 18 class nsHostRecord; 19 class nsHostResolver; 20 21 namespace mozilla { 22 namespace net { 23 class HostRecordQueue; 24 class TRR; 25 class TRRQuery; 26 } // namespace net 27 } // namespace mozilla 28 29 /** 30 * This class is used to notify listeners when a ResolveHost operation is 31 * complete. Classes that derive it must implement threadsafe nsISupports 32 * to be able to use RefPtr with this class. 33 */ 34 class nsResolveHostCallback 35 : public mozilla::LinkedListElement<RefPtr<nsResolveHostCallback>>, 36 public nsISupports { 37 public: 38 /** 39 * OnResolveHostComplete 40 * 41 * this function is called to complete a host lookup initiated by 42 * nsHostResolver::ResolveHost. it may be invoked recursively from 43 * ResolveHost or on an unspecified background thread. 44 * 45 * NOTE: it is the responsibility of the implementor of this method 46 * to handle the callback in a thread safe manner. 47 * 48 * @param resolver 49 * nsHostResolver object associated with this result 50 * @param record 51 * the host record containing the results of the lookup 52 * @param status 53 * if successful, |record| contains non-null results 54 */ 55 virtual void OnResolveHostComplete(nsHostResolver* resolver, 56 nsHostRecord* record, nsresult status) = 0; 57 /** 58 * EqualsAsyncListener 59 * 60 * Determines if the listener argument matches the listener member var. 61 * For subclasses not implementing a member listener, should return false. 62 * For subclasses having a member listener, the function should check if 63 * they are the same. Used for cases where a pointer to an object 64 * implementing nsResolveHostCallback is unknown, but a pointer to 65 * the original listener is known. 66 * 67 * @param aListener 68 * nsIDNSListener object associated with the original request 69 */ 70 virtual bool EqualsAsyncListener(nsIDNSListener* aListener) = 0; 71 72 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const = 0; 73 74 protected: 75 virtual ~nsResolveHostCallback() = default; 76 }; 77 78 struct nsHostKey { 79 const nsCString host; 80 const nsCString mTrrServer; 81 uint16_t type = 0; 82 mozilla::Atomic<nsIDNSService::DNSFlags> flags{ 83 nsIDNSService::RESOLVE_DEFAULT_FLAGS}; 84 uint16_t af = 0; 85 bool pb = false; 86 const nsCString originSuffix; 87 explicit nsHostKey(const nsACString& host, const nsACString& aTrrServer, 88 uint16_t type, nsIDNSService::DNSFlags flags, uint16_t af, 89 bool pb, const nsACString& originSuffix); 90 explicit nsHostKey(const nsHostKey& other); 91 bool operator==(const nsHostKey& other) const; 92 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 93 PLDHashNumber Hash() const; 94 }; 95 96 /** 97 * nsHostRecord - ref counted object type stored in host resolver cache. 98 */ 99 class nsHostRecord : public mozilla::LinkedListElement<RefPtr<nsHostRecord>>, 100 public nsHostKey, 101 public nsISupports { 102 using TRRSkippedReason = mozilla::net::TRRSkippedReason; 103 104 public: 105 NS_DECL_THREADSAFE_ISUPPORTS 106 107 virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { 108 return 0; 109 } 110 111 // Returns the TRR mode encoded by the flags 112 nsIRequest::TRRMode TRRMode(); 113 114 // Records the first reason that caused TRR to be skipped or to fail. 115 void RecordReason(TRRSkippedReason reason) { 116 if (mTRRSkippedReason == TRRSkippedReason::TRR_UNSET) { 117 mTRRSkippedReason = reason; 118 } 119 } 120 121 enum DnsPriority { 122 DNS_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW, 123 DNS_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM, 124 DNS_PRIORITY_HIGH, 125 }; 126 127 protected: 128 friend class nsHostResolver; 129 friend class mozilla::net::HostRecordQueue; 130 friend class mozilla::net::TRR; 131 friend class mozilla::net::TRRQuery; 132 133 using DNSResolverType = mozilla::net::DNSResolverType; 134 135 explicit nsHostRecord(const nsHostKey& key); 136 virtual ~nsHostRecord() = default; 137 138 // Mark hostrecord as not usable 139 void Invalidate(); 140 141 enum ExpirationStatus { 142 EXP_VALID, 143 EXP_GRACE, 144 EXP_EXPIRED, 145 }; 146 147 ExpirationStatus CheckExpiration(const mozilla::TimeStamp& now) const; 148 149 // Convenience function for setting the timestamps above (mValidStart, 150 // mValidEnd, and mGraceStart). valid and grace are durations in seconds. 151 void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid, 152 unsigned int grace); 153 void CopyExpirationTimesAndFlagsFrom(const nsHostRecord* aFromHostRecord); 154 155 // Checks if the record is usable (not expired and has a value) 156 bool HasUsableResult(const mozilla::TimeStamp& now, 157 nsIDNSService::DNSFlags queryFlags = 158 nsIDNSService::RESOLVE_DEFAULT_FLAGS) const; 159 160 static DnsPriority GetPriority(nsIDNSService::DNSFlags aFlags); 161 162 virtual void Cancel(); 163 virtual bool HasUsableResultInternal( 164 const mozilla::TimeStamp& now, 165 nsIDNSService::DNSFlags queryFlags) const = 0; 166 virtual bool RefreshForNegativeResponse() const { return true; } 167 168 mozilla::LinkedList<RefPtr<nsResolveHostCallback>> mCallbacks; 169 170 bool IsAddrRecord() const { 171 return type == nsIDNSService::RESOLVE_TYPE_DEFAULT; 172 } 173 174 virtual void Reset() { 175 mTRRSkippedReason = TRRSkippedReason::TRR_UNSET; 176 mFirstTRRSkippedReason = TRRSkippedReason::TRR_UNSET; 177 mTrrAttempts = 0; 178 mTRRSuccess = false; 179 mNativeSuccess = false; 180 mResolverType = DNSResolverType::Native; 181 } 182 183 virtual void OnCompleteLookup() {} 184 185 virtual void ResolveComplete() = 0; 186 187 // true if pending and on the queue (not yet given to getaddrinfo()) 188 bool onQueue() { return LoadNative() && isInList(); } 189 190 mozilla::TimeStamp mLastUpdate = mozilla::TimeStamp::NowLoRes(); 191 192 // When the record began being valid. Used mainly for bookkeeping. 193 mozilla::TimeStamp mValidStart; 194 195 // When the record is no longer valid (it's time of expiration) 196 mozilla::TimeStamp mValidEnd; 197 198 // When the record enters its grace period. This must be before mValidEnd. 199 // If a record is in its grace period (and not expired), it will be used 200 // but a request to refresh it will be made. 201 mozilla::TimeStamp mGraceStart; 202 203 mozilla::TimeDuration mTrrDuration; 204 205 mozilla::Atomic<uint32_t, mozilla::Relaxed> mTtl{0}; 206 207 // The computed TRR mode that is actually used by the request. 208 // It is set in nsHostResolver::NameLookup and is based on the mode of the 209 // default resolver and the TRRMode encoded in the flags. 210 // The mode into account if the TRR service is disabled, 211 // parental controls are on, domain matches exclusion list, etc. 212 mozilla::Atomic<nsIRequest::TRRMode> mEffectiveTRRMode{ 213 nsIRequest::TRR_DEFAULT_MODE}; 214 215 mozilla::Atomic<TRRSkippedReason> mTRRSkippedReason{ 216 TRRSkippedReason::TRR_UNSET}; 217 TRRSkippedReason mFirstTRRSkippedReason = TRRSkippedReason::TRR_UNSET; 218 219 mozilla::DataMutex<RefPtr<mozilla::net::TRRQuery>> mTRRQuery; 220 221 // counter of outstanding resolving calls 222 mozilla::Atomic<int32_t> mResolving{0}; 223 224 // Number of times we've attempted TRR. Reset when we refresh. 225 // TRR is attempted at most twice - first attempt and retry. 226 mozilla::Atomic<int32_t> mTrrAttempts{0}; 227 228 // TRR was used on this record 229 mozilla::Atomic<DNSResolverType> mResolverType{DNSResolverType::Native}; 230 231 // True if this record is a cache of a failed lookup. Negative cache 232 // entries are valid just like any other (though never for more than 60 233 // seconds), but a use of that negative entry forces an asynchronous refresh. 234 bool negative = false; 235 236 // Explicitly expired 237 bool mDoomed = false; 238 239 // Whether this is resolved by TRR successfully or not. 240 bool mTRRSuccess = false; 241 242 // Whether this is resolved by native resolver successfully or not. 243 bool mNativeSuccess = false; 244 245 // When the lookups of this record started and their durations 246 mozilla::TimeStamp mNativeStart; 247 mozilla::TimeDuration mNativeDuration; 248 249 // clang-format off 250 MOZ_ATOMIC_BITFIELDS(mAtomicBitfields, 8, ( 251 // true if this record is being resolved "natively", which means that 252 // it is either on the pending queue or owned by one of the worker threads. 253 (uint16_t, Native, 1), 254 (uint16_t, NativeUsed, 1), 255 // true if off queue and contributing to mActiveAnyThreadCount 256 (uint16_t, UsingAnyThread, 1), 257 (uint16_t, GetTtl, 1), 258 (uint16_t, ResolveAgain, 1) 259 )) 260 // clang-format on 261 }; 262 263 // b020e996-f6ab-45e5-9bf5-1da71dd0053a 264 #define ADDRHOSTRECORD_IID \ 265 {0xb020e996, 0xf6ab, 0x45e5, {0x9b, 0xf5, 0x1d, 0xa7, 0x1d, 0xd0, 0x05, 0x3a}} 266 267 class AddrHostRecord final : public nsHostRecord { 268 using Mutex = mozilla::Mutex; 269 270 public: 271 NS_INLINE_DECL_STATIC_IID(ADDRHOSTRECORD_IID) 272 NS_DECL_ISUPPORTS_INHERITED 273 274 /* a fully resolved host record has either a non-null |addr_info| or |addr| 275 * field. if |addr_info| is null, it implies that the |host| is an IP 276 * address literal. in which case, |addr| contains the parsed address. 277 * otherwise, if |addr_info| is non-null, then it contains one or many 278 * IP addresses corresponding to the given host name. if both |addr_info| 279 * and |addr| are null, then the given host has not yet been fully resolved. 280 * |af| is the address family of the record we are querying for. 281 */ 282 283 /* the lock protects |addr_info| and |addr_info_gencnt| because they 284 * are mutable and accessed by the resolver worker thread and the 285 * nsDNSService2 class. |addr| doesn't change after it has been 286 * assigned a value. only the resolver worker thread modifies 287 * nsHostRecord (and only in nsHostResolver::CompleteLookup); 288 * the other threads just read it. therefore the resolver worker 289 * thread doesn't need to lock when reading |addr_info|. 290 */ 291 Mutex addr_info_lock MOZ_UNANNOTATED{"AddrHostRecord.addr_info_lock"}; 292 // generation count of |addr_info| 293 int addr_info_gencnt = 0; 294 RefPtr<mozilla::net::AddrInfo> addr_info; 295 mozilla::UniquePtr<mozilla::net::NetAddr> addr; 296 297 // hold addr_info_lock when calling the blocklist functions 298 bool Blocklisted(const mozilla::net::NetAddr* query); 299 void ResetBlocklist(); 300 void ReportUnusable(const mozilla::net::NetAddr* aAddress); 301 302 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override; 303 304 nsIRequest::TRRMode EffectiveTRRMode() const { return mEffectiveTRRMode; } 305 nsITRRSkipReason::value TrrSkipReason() const { return mTRRSkippedReason; } 306 307 nsresult GetTtl(uint32_t* aResult); 308 nsresult GetLastUpdate(mozilla::TimeStamp* aLastUpdate); 309 310 private: 311 friend class nsHostResolver; 312 friend class mozilla::net::HostRecordQueue; 313 friend class mozilla::net::TRR; 314 friend class mozilla::net::TRRQuery; 315 316 explicit AddrHostRecord(const nsHostKey& key); 317 ~AddrHostRecord(); 318 319 // Checks if the record is usable (not expired and has a value) 320 bool HasUsableResultInternal( 321 const mozilla::TimeStamp& now, 322 nsIDNSService::DNSFlags queryFlags) const override; 323 324 bool RemoveOrRefresh(bool aTrrToo); // Mark records currently being resolved 325 // as needed to resolve again. 326 327 // Saves the skip reason of a first-attempt TRR lookup and clears 328 // it to prepare for a retry attempt. 329 void NotifyRetryingTrr(); 330 331 static DnsPriority GetPriority(nsIDNSService::DNSFlags aFlags); 332 333 virtual void Reset() override { 334 nsHostRecord::Reset(); 335 StoreNativeUsed(false); 336 } 337 338 virtual void OnCompleteLookup() override { 339 nsHostRecord::OnCompleteLookup(); 340 // This should always be cleared when a request is completed. 341 StoreNative(false); 342 } 343 344 void ResolveComplete() override; 345 346 // The number of times ReportUnusable() has been called in the record's 347 // lifetime. 348 uint32_t mUnusableCount = 0; 349 350 // a list of addresses associated with this record that have been reported 351 // as unusable. the list is kept as a set of strings to make it independent 352 // of gencnt. 353 nsTArray<nsCString> mUnusableItems; 354 }; 355 356 // 77b786a7-04be-44f2-987c-ab8aa96676e0 357 #define TYPEHOSTRECORD_IID \ 358 {0x77b786a7, 0x04be, 0x44f2, {0x98, 0x7c, 0xab, 0x8a, 0xa9, 0x66, 0x76, 0xe0}} 359 360 class TypeHostRecord final : public nsHostRecord, 361 public nsIDNSTXTRecord, 362 public nsIDNSHTTPSSVCRecord, 363 public mozilla::net::DNSHTTPSSVCRecordBase { 364 public: 365 NS_INLINE_DECL_STATIC_IID(TYPEHOSTRECORD_IID) 366 NS_DECL_ISUPPORTS_INHERITED 367 NS_DECL_NSIDNSTXTRECORD 368 NS_DECL_NSIDNSHTTPSSVCRECORD 369 370 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const override; 371 uint32_t GetType(); 372 mozilla::net::TypeRecordResultType GetResults(); 373 374 private: 375 friend class nsHostResolver; 376 friend class mozilla::net::TRR; 377 friend class mozilla::net::TRRQuery; 378 379 explicit TypeHostRecord(const nsHostKey& key); 380 ~TypeHostRecord(); 381 382 // Checks if the record is usable (not expired and has a value) 383 bool HasUsableResultInternal( 384 const mozilla::TimeStamp& now, 385 nsIDNSService::DNSFlags queryFlags) const override; 386 bool RefreshForNegativeResponse() const override; 387 388 void ResolveComplete() override; 389 390 mozilla::net::TypeRecordResultType mResults MOZ_GUARDED_BY(mResultsLock) = 391 AsVariant(mozilla::Nothing()); 392 mozilla::Mutex mResultsLock{"TypeHostRecord.mResultsLock"}; 393 394 mozilla::Maybe<nsCString> mOriginHost MOZ_GUARDED_BY(mResultsLock); 395 bool mAllRecordsExcluded = false; 396 }; 397 398 static inline bool IsHighPriority(nsIDNSService::DNSFlags flags) { 399 return !(flags & (nsHostRecord::DNS_PRIORITY_LOW | 400 nsHostRecord::DNS_PRIORITY_MEDIUM)); 401 } 402 403 static inline bool IsMediumPriority(nsIDNSService::DNSFlags flags) { 404 return flags & nsHostRecord::DNS_PRIORITY_MEDIUM; 405 } 406 407 static inline bool IsLowPriority(nsIDNSService::DNSFlags flags) { 408 return flags & nsHostRecord::DNS_PRIORITY_LOW; 409 } 410 411 #endif // nsHostRecord_h__