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_