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