tor-browser

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

TRRService.h (14138B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      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 TRRService_h_
      7 #define TRRService_h_
      8 
      9 #include "mozilla/DataMutex.h"
     10 #include "nsHostResolver.h"
     11 #include "nsIObserver.h"
     12 #include "nsITimer.h"
     13 #include "nsWeakReference.h"
     14 #include "TRRServiceBase.h"
     15 #include "nsICaptivePortalService.h"
     16 #include "nsTHashSet.h"
     17 #include "TRR.h"
     18 
     19 class nsDNSService;
     20 class nsIPrefBranch;
     21 class nsINetworkLinkService;
     22 class nsIObserverService;
     23 
     24 namespace mozilla {
     25 namespace net {
     26 
     27 class TRRServiceChild;
     28 class TRRServiceParent;
     29 
     30 const nsCString& TRRProviderKey();
     31 
     32 class TRRService : public TRRServiceBase,
     33                   public nsIObserver,
     34                   public nsSupportsWeakReference,
     35                   public AHostResolver {
     36 public:
     37  NS_DECL_ISUPPORTS_INHERITED
     38  NS_DECL_NSIOBSERVER
     39  NS_DECL_NSIPROXYCONFIGCHANGEDCALLBACK
     40 
     41  TRRService();
     42  static TRRService* Get();
     43 
     44  nsresult Init(bool aNativeHTTPSQueryEnabled);
     45  nsresult Start();
     46  bool Enabled(nsIRequest::TRRMode aRequestMode = nsIRequest::TRR_DEFAULT_MODE);
     47  bool IsConfirmed() { return mConfirmation.State() == CONFIRM_OK; }
     48  uint32_t ConfirmationState() { return mConfirmation.State(); }
     49 
     50  void GetURI(nsACString& result) override;
     51  nsresult GetCredentials(nsCString& result);
     52  uint32_t GetRequestTimeout();
     53  void RetryTRRConfirm();
     54 
     55  LookupStatus CompleteLookup(nsHostRecord*, nsresult, mozilla::net::AddrInfo*,
     56                              bool pb, const nsACString& aOriginSuffix,
     57                              TRRSkippedReason aReason,
     58                              TRR* aTrrRequest) override;
     59  LookupStatus CompleteLookupByType(nsHostRecord*, nsresult,
     60                                    mozilla::net::TypeRecordResultType&,
     61                                    TRRSkippedReason, uint32_t,
     62                                    bool pb) override;
     63  void AddToBlocklist(const nsACString& host, const nsACString& originSuffix,
     64                      bool privateBrowsing, bool aParentsToo);
     65  bool IsTemporarilyBlocked(const nsACString& aHost,
     66                            const nsACString& aOriginSuffix,
     67                            bool aPrivateBrowsing, bool aParentsToo);
     68  bool IsExcludedFromTRR(const nsACString& aHost);
     69 
     70  bool MaybeBootstrap(const nsACString& possible, nsACString& result);
     71  void RecordTRRStatus(TRR* aTrrRequest);
     72  bool ParentalControlEnabled() const { return mParentalControlEnabled; }
     73 
     74  nsresult DispatchTRRRequest(TRR* aTrrRequest);
     75  already_AddRefed<nsIThread> TRRThread();
     76  bool IsOnTRRThread();
     77 
     78  bool IsUsingAutoDetectedURL() { return mURISetByDetection; }
     79 
     80  void SetHeuristicDetectionResult(TRRSkippedReason aValue) {
     81    mHeuristicDetectionValue = aValue;
     82  }
     83  TRRSkippedReason GetHeuristicDetectionResult() {
     84    return mHeuristicDetectionValue;
     85  }
     86 
     87  nsresult LastConfirmationStatus() {
     88    return mConfirmation.LastConfirmationStatus();
     89  }
     90  TRRSkippedReason LastConfirmationSkipReason() {
     91    return mConfirmation.LastConfirmationSkipReason();
     92  }
     93 
     94  // Returns a reference to a static string identifying the current DoH server
     95  // If the DoH server is not one of the built-in ones it will return "(other)"
     96  static const nsCString& ProviderKey();
     97  static void SetProviderDomain(const nsACString& aTRRDomain);
     98  // Only called when TRR mode changed.
     99  static void SetCurrentTRRMode(nsIDNSService::ResolverMode aMode);
    100 
    101  void InitTRRConnectionInfo(bool aForceReinit = false) override;
    102 
    103  void DontUseTRRThread() { mDontUseTRRThread = true; }
    104 
    105 private:
    106  virtual ~TRRService();
    107 
    108  friend class TRR;
    109  friend class TRRServiceChild;
    110  friend class TRRServiceParent;
    111  static void AddObserver(nsIObserver* aObserver,
    112                          nsIObserverService* aObserverService = nullptr);
    113  static bool CheckCaptivePortalIsPassed();
    114  static bool GetParentalControlsEnabledInternal();
    115  // Exposed for testing purposes only
    116  static bool ReloadParentalControlsEnabled();
    117 
    118  static bool CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService);
    119 
    120  nsresult ReadPrefs(const char* name);
    121  void GetPrefBranch(nsIPrefBranch** result);
    122  friend class ::nsDNSService;
    123  void SetDetectedTrrURI(const nsACString& aURI);
    124 
    125  bool IsDomainBlocked(const nsACString& aHost, const nsACString& aOriginSuffix,
    126                       bool aPrivateBrowsing);
    127  bool IsExcludedFromTRR_unlocked(const nsACString& aHost) MOZ_REQUIRES(mLock);
    128 
    129  void RebuildSuffixList(nsTArray<nsCString>&& aSuffixList);
    130 
    131  nsresult DispatchTRRRequestInternal(TRR* aTrrRequest, bool aWithLock);
    132  already_AddRefed<nsIThread> TRRThread_locked();
    133  already_AddRefed<nsIThread> MainThreadOrTRRThread(bool aWithLock = true);
    134 
    135  // This method will process the URI and try to set mPrivateURI to that value.
    136  // Will return true if performed the change (if the value was different)
    137  // or false if mPrivateURI already had that value.
    138  bool MaybeSetPrivateURI(const nsACString& aURI) override;
    139  void ClearEntireCache();
    140 
    141  virtual void ReadEtcHostsFile() override;
    142  void AddEtcHosts(const nsTArray<nsCString>&);
    143 
    144  bool mInitialized{false};
    145  Mutex mLock;
    146 
    147  nsCString mPrivateCred;  // main thread only
    148  nsCString mConfirmationNS MOZ_GUARDED_BY(mLock){"example.com"_ns};
    149  nsCString mBootstrapAddr MOZ_GUARDED_BY(mLock);
    150 
    151  Atomic<bool, Relaxed> mCaptiveIsPassed{
    152      false};  // set when captive portal check is passed
    153  Atomic<bool, Relaxed> mShutdown{false};
    154  Atomic<bool, Relaxed> mDontUseTRRThread{false};
    155 
    156  // TRR Blocklist storage
    157  // mTRRBLStorage is only modified on the main thread, but we query whether it
    158  // is initialized or not off the main thread as well. Therefore we need to
    159  // lock while creating it and while accessing it off the main thread.
    160  DataMutex<nsTHashMap<nsCStringHashKey, int32_t>> mTRRBLStorage{
    161      "DataMutex::TRRBlocklist"};
    162 
    163  // A set of domains that we should not use TRR for.
    164  nsTHashSet<nsCString> mExcludedDomains MOZ_GUARDED_BY(mLock);
    165  nsTHashSet<nsCString> mDNSSuffixDomains MOZ_GUARDED_BY(mLock);
    166  nsTHashSet<nsCString> mEtcHostsDomains MOZ_GUARDED_BY(mLock);
    167 
    168  // The result of the TRR heuristic detection
    169  TRRSkippedReason mHeuristicDetectionValue = nsITRRSkipReason::TRR_UNSET;
    170 
    171  enum class ConfirmationEvent {
    172    Init,
    173    PrefChange,
    174    ConfirmationRetry,
    175    FailedLookups,
    176    RetryTRR,
    177    URIChange,
    178    CaptivePortalConnectivity,
    179    NetworkUp,
    180    ConfirmOK,
    181    ConfirmFail,
    182  };
    183 
    184  //                            (FailedLookups/RetryTRR/URIChange/NetworkUp)
    185  //                                    +---------------------------+
    186  // +-----------+                      |                           |
    187  // |   (Init)  |               +------v---------+               +-+--+
    188  // |           | TRR turned on |                | (ConfirmOK)   |    |
    189  // |    OFF    +--------------->     TRY-OK     +---------------> OK |
    190  // |           |  (PrefChange) |                |               |    |
    191  // +-----^-----+               +^-^----+--------+               +-^--+
    192  //       |    (PrefChange/CP)   | |    |                          |
    193  //   TRR +   +------------------+ |    |                          |
    194  //   off |   |               +----+    |(ConfirmFail)             |(ConfirmOK)
    195  // (Pref)|   |               |         |                          |
    196  // +---------+-+             |         |                          |
    197  // |           |    (CPConn) | +-------v--------+               +-+---------+
    198  // | ANY-STATE |  (NetworkUp)| |                |  timer        |           |
    199  // |           |  (URIChange)+-+      FAIL      +--------------->  TRY-FAIL |
    200  // +-----+-----+               |                | (Confirmation |           |
    201  //       |                     +------^---------+  Retry)       +------+----+
    202  //       | (PrefChange)               |                                |
    203  //       | TRR_ONLY mode or           +--------------------------------+
    204  //       | confirmationNS = skip                (ConfirmFail)
    205  // +-----v-----+
    206  // |           |
    207  // |  DISABLED |
    208  // |           |
    209  // +-----------+
    210  //
    211  enum ConfirmationState {
    212    CONFIRM_OFF = 0,
    213    CONFIRM_TRYING_OK = 1,
    214    CONFIRM_OK = 2,
    215    CONFIRM_FAILED = 3,
    216    CONFIRM_TRYING_FAILED = 4,
    217    CONFIRM_DISABLED = 5,
    218  };
    219 
    220  class ConfirmationContext final : public nsITimerCallback, public nsINamed {
    221    NS_DECL_ISUPPORTS_INHERITED
    222    NS_DECL_NSITIMERCALLBACK
    223    NS_DECL_NSINAMED
    224 
    225   private:
    226    static const size_t RESULTS_SIZE = 32;
    227 
    228    RefPtr<TRR> mTask;
    229    nsCOMPtr<nsITimer> mTimer;
    230    uint32_t mRetryInterval = 125;  // milliseconds until retry
    231    // The number of TRR requests that failed in a row.
    232    Atomic<uint32_t, Relaxed> mTRRFailures{0};
    233 
    234    // This buffer holds consecutive TRR failures reported by calling
    235    // RecordTRRStatus(). It is only meant for reporting event telemetry.
    236    char mFailureReasons[RESULTS_SIZE] = {0};
    237 
    238    // The number of confirmation retries.
    239    uint32_t mAttemptCount = 0;
    240 
    241    // The results of past confirmation attempts.
    242    // This is circular buffer ending at mAttemptCount.
    243    char mResults[RESULTS_SIZE] = {0};
    244 
    245    // Time when first confirmation started. Needed so we can
    246    // record the time from start to confirmed.
    247    TimeStamp mFirstRequestTime;
    248    // The network ID at the start of the last confirmation attempt
    249    nsCString mNetworkId;
    250    // Captive portal status at the time of recording.
    251    int32_t mCaptivePortalStatus = nsICaptivePortalService::UNKNOWN;
    252 
    253    // The reason the confirmation context changed.
    254    nsCString mContextChangeReason;
    255 
    256    // What triggered the confirmation
    257    nsCString mTrigger;
    258 
    259    // String representation of consecutive failed lookups that triggered
    260    // confirmation.
    261    nsCString mFailedLookups;
    262 
    263    Atomic<TRRSkippedReason, Relaxed> mLastConfirmationSkipReason{
    264        nsITRRSkipReason::TRR_UNSET};
    265    Atomic<nsresult, Relaxed> mLastConfirmationStatus{NS_OK};
    266 
    267    void SetState(enum ConfirmationState aNewState);
    268 
    269   public:
    270    // Called when a confirmation completes successfully or when the
    271    // confirmation context changes.
    272    void RecordEvent(const char* aReason, const MutexAutoLock&);
    273 
    274    // Called when a confirmation request is completed. The status is recorded
    275    // in the results.
    276    void RequestCompleted(nsresult aLookupStatus, nsresult aChannelStatus);
    277 
    278    enum ConfirmationState State() { return mState; }
    279 
    280    void CompleteConfirmation(nsresult aStatus, TRR* aTrrRequest);
    281 
    282    void RecordTRRStatus(TRR* aTrrRequest);
    283 
    284    // Returns true when handling the event caused a new confirmation task to be
    285    // dispatched.
    286    bool HandleEvent(ConfirmationEvent aEvent);
    287    bool HandleEvent(ConfirmationEvent aEvent, const MutexAutoLock&);
    288 
    289    void SetCaptivePortalStatus(int32_t aStatus) {
    290      mCaptivePortalStatus = aStatus;
    291    }
    292 
    293    TRRSkippedReason LastConfirmationSkipReason() {
    294      return mLastConfirmationSkipReason;
    295    }
    296    nsresult LastConfirmationStatus() { return mLastConfirmationStatus; }
    297 
    298    uintptr_t TaskAddr() { return uintptr_t(mTask.get()); }
    299 
    300   private:
    301    // Since the ConfirmationContext is embedded in the TRRService object
    302    // we can easily get a pointer to the TRRService. ConfirmationContext
    303    // delegates AddRef/Release calls to the owning object since they are
    304    // guaranteed to have the same lifetime.
    305    TRRService* OwningObject() {
    306      return reinterpret_cast<TRRService*>(
    307          reinterpret_cast<uint8_t*>(this) -
    308          offsetof(TRRService, mConfirmation) -
    309          offsetof(ConfirmationWrapper, mConfirmation));
    310    }
    311 
    312    Atomic<enum ConfirmationState, Relaxed> mState{CONFIRM_OFF};
    313 
    314    // TRRService needs to be a friend class because it needs to access the
    315    // destructor.
    316    friend class TRRService;
    317    ~ConfirmationContext() = default;
    318  };
    319 
    320  // Because TRRService needs to be a friend class to ConfirmationContext that
    321  // means it can access member variables. In order to properly separate logic
    322  // and prevent direct access to its member variables we embed it in a wrapper
    323  // class.
    324  class ConfirmationWrapper {
    325   public:
    326    // Called when a confirmation completes successfully or when the
    327    // confirmation context changes.
    328    void RecordEvent(const char* aReason, const MutexAutoLock& aLock) {
    329      mConfirmation.RecordEvent(aReason, aLock);
    330    }
    331 
    332    // Called when a confirmation request is completed. The status is recorded
    333    // in the results.
    334    void RequestCompleted(nsresult aLookupStatus, nsresult aChannelStatus) {
    335      mConfirmation.RequestCompleted(aLookupStatus, aChannelStatus);
    336    }
    337 
    338    enum ConfirmationState State() { return mConfirmation.State(); }
    339 
    340    void CompleteConfirmation(nsresult aStatus, TRR* aTrrRequest) {
    341      mConfirmation.CompleteConfirmation(aStatus, aTrrRequest);
    342    }
    343 
    344    void RecordTRRStatus(TRR* aTrrRequest) {
    345      mConfirmation.RecordTRRStatus(aTrrRequest);
    346    }
    347 
    348    bool HandleEvent(ConfirmationEvent aEvent) {
    349      return mConfirmation.HandleEvent(aEvent);
    350    }
    351 
    352    bool HandleEvent(ConfirmationEvent aEvent, const MutexAutoLock& lock) {
    353      return mConfirmation.HandleEvent(aEvent, lock);
    354    }
    355 
    356    void SetCaptivePortalStatus(int32_t aStatus) {
    357      mConfirmation.SetCaptivePortalStatus(aStatus);
    358    }
    359 
    360    TRRSkippedReason LastConfirmationSkipReason() {
    361      return mConfirmation.LastConfirmationSkipReason();
    362    }
    363    nsresult LastConfirmationStatus() {
    364      return mConfirmation.LastConfirmationStatus();
    365    }
    366 
    367   private:
    368    friend TRRService* ConfirmationContext::OwningObject();
    369    ConfirmationContext mConfirmation;
    370  };
    371 
    372  ConfirmationWrapper mConfirmation;
    373 
    374  bool mParentalControlEnabled{false};
    375  // This is used to track whether a confirmation was triggered by a URI change,
    376  // so we don't trigger another one just because other prefs have changed.
    377  bool mConfirmationTriggered{false};
    378  nsCOMPtr<nsINetworkLinkService> mLinkService;
    379 };
    380 
    381 }  // namespace net
    382 }  // namespace mozilla
    383 
    384 #endif  // TRRService_h_