tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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__