Bug 1838739 - Initialize result of SetAsGPUOutOfMemoryError. r=webgpu-reviewers,nical
[gecko.git] / netwerk / dns / TRRService.cpp
blob5cb42f43082d1cada783439099ac5432c496e5b2
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/. */
6 #include "nsCharSeparatedTokenizer.h"
7 #include "nsComponentManagerUtils.h"
8 #include "nsDirectoryServiceUtils.h"
9 #include "nsHttpConnectionInfo.h"
10 #include "nsICaptivePortalService.h"
11 #include "nsIFile.h"
12 #include "nsIParentalControlsService.h"
13 #include "nsINetworkLinkService.h"
14 #include "nsIObserverService.h"
15 #include "nsIOService.h"
16 #include "nsNetUtil.h"
17 #include "nsStandardURL.h"
18 #include "TRR.h"
19 #include "TRRService.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/StaticPrefs_network.h"
23 #include "mozilla/Telemetry.h"
24 #include "mozilla/TelemetryComms.h"
25 #include "mozilla/Tokenizer.h"
26 #include "mozilla/dom/ContentParent.h"
27 #include "mozilla/net/NeckoParent.h"
28 #include "mozilla/net/TRRServiceChild.h"
29 // Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
30 #include "DNSLogging.h"
32 static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
33 static const char kClearPrivateData[] = "clear-private-data";
34 static const char kPurge[] = "browser:purge-session-history";
35 static const char kDisableIpv6Pref[] = "network.dns.disableIPv6";
37 #define TRR_PREF_PREFIX "network.trr."
38 #define TRR_PREF(x) TRR_PREF_PREFIX x
40 namespace mozilla::net {
42 StaticRefPtr<nsIThread> sTRRBackgroundThread;
43 static Atomic<TRRService*> sTRRServicePtr;
45 static Atomic<size_t, Relaxed> sDomainIndex(0);
46 static Atomic<size_t, Relaxed> sCurrentTRRModeIndex(0);
48 constexpr nsLiteralCString kTRRDomains[3][7] = {
49 // clang-format off
51 // When mode is 0, the provider key has no postfix.
52 "(other)"_ns,
53 "mozilla.cloudflare-dns.com"_ns,
54 "firefox.dns.nextdns.io"_ns,
55 "private.canadianshield.cira.ca"_ns,
56 "doh.xfinity.com"_ns, // Steered clients
57 "dns.shaw.ca"_ns, // Steered clients
58 "dooh.cloudflare-dns.com"_ns, // DNS over Oblivious HTTP
61 "(other)_2"_ns,
62 "mozilla.cloudflare-dns.com_2"_ns,
63 "firefox.dns.nextdns.io_2"_ns,
64 "private.canadianshield.cira.ca_2"_ns,
65 "doh.xfinity.com_2"_ns, // Steered clients
66 "dns.shaw.ca_2"_ns, // Steered clients
67 "dooh.cloudflare-dns.com_2"_ns, // DNS over Oblivious HTTP
70 "(other)_3"_ns,
71 "mozilla.cloudflare-dns.com_3"_ns,
72 "firefox.dns.nextdns.io_3"_ns,
73 "private.canadianshield.cira.ca_3"_ns,
74 "doh.xfinity.com_3"_ns, // Steered clients
75 "dns.shaw.ca_3"_ns, // Steered clients
76 "dooh.cloudflare-dns.com_3"_ns, // DNS over Oblivious HTTP
78 // clang-format on
81 // static
82 void TRRService::SetCurrentTRRMode(nsIDNSService::ResolverMode aMode) {
83 // A table to map ResolverMode to the row of kTRRDomains.
84 // When the aMode is 2, we use kTRRDomains[1] as provider keys. When aMode is
85 // 3, we use kTRRDomains[2]. Otherwise, we kTRRDomains[0] is used.
86 static const uint32_t index[] = {0, 0, 1, 2, 0, 0};
87 if (aMode > nsIDNSService::MODE_TRROFF) {
88 aMode = nsIDNSService::MODE_TRROFF;
90 sCurrentTRRModeIndex = index[static_cast<size_t>(aMode)];
93 // static
94 void TRRService::SetProviderDomain(const nsACString& aTRRDomain) {
95 sDomainIndex = 0;
96 for (size_t i = 1; i < std::size(kTRRDomains[0]); i++) {
97 if (aTRRDomain.Equals(kTRRDomains[0][i])) {
98 sDomainIndex = i;
99 break;
104 // static
105 const nsCString& TRRService::ProviderKey() {
106 return kTRRDomains[sCurrentTRRModeIndex][sDomainIndex];
109 NS_IMPL_ISUPPORTS_INHERITED(TRRService, TRRServiceBase, nsIObserver,
110 nsISupportsWeakReference)
112 NS_IMPL_ADDREF_USING_AGGREGATOR(TRRService::ConfirmationContext, OwningObject())
113 NS_IMPL_RELEASE_USING_AGGREGATOR(TRRService::ConfirmationContext,
114 OwningObject())
115 NS_IMPL_QUERY_INTERFACE(TRRService::ConfirmationContext, nsITimerCallback,
116 nsINamed)
118 TRRService::TRRService() : mLock("TRRService", this) {
119 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
122 // static
123 TRRService* TRRService::Get() { return sTRRServicePtr; }
125 // static
126 void TRRService::AddObserver(nsIObserver* aObserver,
127 nsIObserverService* aObserverService) {
128 nsCOMPtr<nsIObserverService> observerService;
129 if (aObserverService) {
130 observerService = aObserverService;
131 } else {
132 observerService = mozilla::services::GetObserverService();
135 if (observerService) {
136 observerService->AddObserver(aObserver, NS_CAPTIVE_PORTAL_CONNECTIVITY,
137 true);
138 observerService->AddObserver(aObserver, kOpenCaptivePortalLoginEvent, true);
139 observerService->AddObserver(aObserver, kClearPrivateData, true);
140 observerService->AddObserver(aObserver, kPurge, true);
141 observerService->AddObserver(aObserver, NS_NETWORK_LINK_TOPIC, true);
142 observerService->AddObserver(aObserver, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC,
143 true);
144 observerService->AddObserver(aObserver, "xpcom-shutdown-threads", true);
148 // static
149 bool TRRService::CheckCaptivePortalIsPassed() {
150 bool result = false;
151 nsCOMPtr<nsICaptivePortalService> captivePortalService =
152 do_GetService(NS_CAPTIVEPORTAL_CID);
153 if (captivePortalService) {
154 int32_t captiveState;
155 MOZ_ALWAYS_SUCCEEDS(captivePortalService->GetState(&captiveState));
157 if ((captiveState == nsICaptivePortalService::UNLOCKED_PORTAL) ||
158 (captiveState == nsICaptivePortalService::NOT_CAPTIVE)) {
159 result = true;
161 LOG(("TRRService::Init mCaptiveState=%d mCaptiveIsPassed=%d\n",
162 captiveState, (int)result));
165 return result;
168 static void EventTelemetryPrefChanged(const char* aPref, void* aData) {
169 Telemetry::SetEventRecordingEnabled(
170 "network.dns"_ns,
171 StaticPrefs::network_trr_confirmation_telemetry_enabled());
174 nsresult TRRService::Init() {
175 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
176 if (mInitialized) {
177 return NS_OK;
179 mInitialized = true;
181 AddObserver(this);
183 nsCOMPtr<nsIPrefBranch> prefBranch;
184 GetPrefBranch(getter_AddRefs(prefBranch));
185 if (prefBranch) {
186 prefBranch->AddObserver(TRR_PREF_PREFIX, this, true);
187 prefBranch->AddObserver(kDisableIpv6Pref, this, true);
188 prefBranch->AddObserver(kRolloutURIPref, this, true);
189 prefBranch->AddObserver(kRolloutModePref, this, true);
192 sTRRServicePtr = this;
194 ReadPrefs(nullptr);
195 mConfirmation.HandleEvent(ConfirmationEvent::Init);
197 if (XRE_IsParentProcess()) {
198 mCaptiveIsPassed = CheckCaptivePortalIsPassed();
200 mParentalControlEnabled = GetParentalControlEnabledInternal();
202 mLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
203 if (mLinkService) {
204 nsTArray<nsCString> suffixList;
205 mLinkService->GetDnsSuffixList(suffixList);
206 RebuildSuffixList(std::move(suffixList));
209 nsCOMPtr<nsIThread> thread;
210 if (NS_FAILED(
211 NS_NewNamedThread("TRR Background", getter_AddRefs(thread)))) {
212 NS_WARNING("NS_NewNamedThread failed!");
213 return NS_ERROR_FAILURE;
216 sTRRBackgroundThread = thread;
219 Preferences::RegisterCallbackAndCall(
220 EventTelemetryPrefChanged,
221 "network.trr.confirmation_telemetry_enabled"_ns);
223 LOG(("Initialized TRRService\n"));
224 return NS_OK;
227 // static
228 bool TRRService::GetParentalControlEnabledInternal() {
229 nsCOMPtr<nsIParentalControlsService> pc =
230 do_CreateInstance("@mozilla.org/parental-controls-service;1");
231 if (pc) {
232 bool result = false;
233 pc->GetParentalControlsEnabled(&result);
234 LOG(("TRRService::GetParentalControlEnabledInternal=%d\n", result));
235 return result;
238 return false;
241 void TRRService::SetDetectedTrrURI(const nsACString& aURI) {
242 LOG(("SetDetectedTrrURI(%s", nsPromiseFlatCString(aURI).get()));
243 // If the user has set a custom URI then we don't want to override that.
244 // If the URI is set via doh-rollout.uri, mURIPref will be empty
245 // (see TRRServiceBase::OnTRRURIChange)
246 if (!mURIPref.IsEmpty()) {
247 LOG(("Already has user value. Not setting URI"));
248 return;
251 if (StaticPrefs::network_trr_use_ohttp()) {
252 LOG(("No autodetection when using OHTTP"));
253 return;
256 mURISetByDetection = MaybeSetPrivateURI(aURI);
259 bool TRRService::Enabled(nsIRequest::TRRMode aRequestMode) {
260 if (mMode == nsIDNSService::MODE_TRROFF ||
261 aRequestMode == nsIRequest::TRR_DISABLED_MODE) {
262 LOG(("TRR service not enabled - off or disabled"));
263 return false;
266 // If already confirmed, service is enabled.
267 if (mConfirmation.State() == CONFIRM_OK ||
268 aRequestMode == nsIRequest::TRR_ONLY_MODE) {
269 LOG(("TRR service enabled - confirmed or trr_only request"));
270 return true;
273 // If this is a TRR_FIRST request but the resolver has a different mode,
274 // just go ahead and let it try to use TRR.
275 if (aRequestMode == nsIRequest::TRR_FIRST_MODE &&
276 mMode != nsIDNSService::MODE_TRRFIRST) {
277 LOG(("TRR service enabled - trr_first request"));
278 return true;
281 // In TRR_ONLY_MODE / confirmationNS == "skip" we don't try to confirm.
282 if (mConfirmation.State() == CONFIRM_DISABLED) {
283 LOG(("TRRService service enabled - confirmation is disabled"));
284 return true;
287 LOG(("TRRService::Enabled mConfirmation.mState=%d mCaptiveIsPassed=%d\n",
288 mConfirmation.State(), (int)mCaptiveIsPassed));
290 if (StaticPrefs::network_trr_wait_for_confirmation()) {
291 return mConfirmation.State() == CONFIRM_OK;
294 if (StaticPrefs::network_trr_attempt_when_retrying_confirmation()) {
295 return mConfirmation.State() == CONFIRM_OK ||
296 mConfirmation.State() == CONFIRM_TRYING_OK ||
297 mConfirmation.State() == CONFIRM_TRYING_FAILED;
300 return mConfirmation.State() == CONFIRM_OK ||
301 mConfirmation.State() == CONFIRM_TRYING_OK;
304 void TRRService::GetPrefBranch(nsIPrefBranch** result) {
305 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
306 *result = nullptr;
307 CallGetService(NS_PREFSERVICE_CONTRACTID, result);
310 bool TRRService::MaybeSetPrivateURI(const nsACString& aURI) {
311 bool clearCache = false;
312 nsAutoCString newURI(aURI);
313 LOG(("MaybeSetPrivateURI(%s)", newURI.get()));
315 ProcessURITemplate(newURI);
317 MutexSingleWriterAutoLock lock(mLock);
318 if (mPrivateURI.Equals(newURI)) {
319 return false;
322 if (!mPrivateURI.IsEmpty()) {
323 LOG(("TRRService clearing blocklist because of change in uri service\n"));
324 auto bl = mTRRBLStorage.Lock();
325 bl->Clear();
326 clearCache = true;
329 nsAutoCString host;
331 nsCOMPtr<nsIURI> url;
332 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(url), newURI))) {
333 url->GetHost(host);
336 SetProviderDomain(host);
338 mPrivateURI = newURI;
340 // Notify the content processes of the new TRR
341 for (auto* cp :
342 dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
343 PNeckoParent* neckoParent =
344 SingleManagedOrNull(cp->ManagedPNeckoParent());
345 if (!neckoParent) {
346 continue;
348 Unused << neckoParent->SendSetTRRDomain(host);
351 AsyncCreateTRRConnectionInfo(mPrivateURI);
353 // The URI has changed. We should trigger a new confirmation immediately.
354 // We must do this here because the URI could also change because of
355 // steering.
356 mConfirmationTriggered =
357 mConfirmation.HandleEvent(ConfirmationEvent::URIChange, lock);
360 // Clear the cache because we changed the URI
361 if (clearCache) {
362 ClearEntireCache();
365 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
366 if (obs) {
367 obs->NotifyObservers(nullptr, NS_NETWORK_TRR_URI_CHANGED_TOPIC, nullptr);
369 return true;
372 nsresult TRRService::ReadPrefs(const char* name) {
373 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
375 // Whenever a pref change occurs that would cause us to clear the cache
376 // we set this to true then do it at the end of the method.
377 bool clearEntireCache = false;
379 if (!name || !strcmp(name, TRR_PREF("mode")) ||
380 !strcmp(name, kRolloutModePref)) {
381 nsIDNSService::ResolverMode prevMode = Mode();
383 OnTRRModeChange();
384 // When the TRR service gets disabled we should purge the TRR cache to
385 // make sure we don't use any of the cached entries on a network where
386 // they are invalid - for example after turning on a VPN.
387 if (TRR_DISABLED(Mode()) && !TRR_DISABLED(prevMode)) {
388 clearEntireCache = true;
391 if (!name || !strcmp(name, TRR_PREF("uri")) ||
392 !strcmp(name, TRR_PREF("default_provider_uri")) ||
393 !strcmp(name, kRolloutURIPref) || !strcmp(name, TRR_PREF("ohttp.uri")) ||
394 !strcmp(name, TRR_PREF("use_ohttp"))) {
395 OnTRRURIChange();
397 if (!name || !strcmp(name, TRR_PREF("credentials"))) {
398 MutexSingleWriterAutoLock lock(mLock);
399 Preferences::GetCString(TRR_PREF("credentials"), mPrivateCred);
401 if (!name || !strcmp(name, TRR_PREF("confirmationNS"))) {
402 MutexSingleWriterAutoLock lock(mLock);
403 Preferences::GetCString(TRR_PREF("confirmationNS"), mConfirmationNS);
404 LOG(("confirmationNS = %s", mConfirmationNS.get()));
406 if (!name || !strcmp(name, TRR_PREF("bootstrapAddr"))) {
407 MutexSingleWriterAutoLock lock(mLock);
408 Preferences::GetCString(TRR_PREF("bootstrapAddr"), mBootstrapAddr);
409 clearEntireCache = true;
411 if (!name || !strcmp(name, kDisableIpv6Pref)) {
412 bool tmp;
413 if (NS_SUCCEEDED(Preferences::GetBool(kDisableIpv6Pref, &tmp))) {
414 mDisableIPv6 = tmp;
417 if (!name || !strcmp(name, TRR_PREF("excluded-domains")) ||
418 !strcmp(name, TRR_PREF("builtin-excluded-domains"))) {
419 MutexSingleWriterAutoLock lock(mLock);
420 mExcludedDomains.Clear();
422 auto parseExcludedDomains = [this](const char* aPrefName) {
423 nsAutoCString excludedDomains;
424 mLock.AssertCurrentThreadOwns();
425 Preferences::GetCString(aPrefName, excludedDomains);
426 if (excludedDomains.IsEmpty()) {
427 return;
430 for (const nsACString& tokenSubstring :
431 nsCCharSeparatedTokenizerTemplate<
432 NS_IsAsciiWhitespace, nsTokenizerFlags::SeparatorOptional>(
433 excludedDomains, ',')
434 .ToRange()) {
435 nsCString token{tokenSubstring};
436 LOG(("TRRService::ReadPrefs %s host:[%s]\n", aPrefName, token.get()));
437 mExcludedDomains.Insert(token);
441 parseExcludedDomains(TRR_PREF("excluded-domains"));
442 parseExcludedDomains(TRR_PREF("builtin-excluded-domains"));
443 clearEntireCache = true;
446 // if name is null, then we're just now initializing. In that case we don't
447 // need to clear the cache.
448 if (name && clearEntireCache) {
449 ClearEntireCache();
452 return NS_OK;
455 void TRRService::ClearEntireCache() {
456 if (!StaticPrefs::network_trr_clear_cache_on_pref_change()) {
457 return;
459 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
460 if (!dns) {
461 return;
463 dns->ClearCache(true);
466 void TRRService::AddEtcHosts(const nsTArray<nsCString>& aArray) {
467 MutexSingleWriterAutoLock lock(mLock);
468 for (const auto& item : aArray) {
469 LOG(("Adding %s from /etc/hosts to excluded domains", item.get()));
470 mEtcHostsDomains.Insert(item);
474 void TRRService::ReadEtcHostsFile() {
475 if (!XRE_IsParentProcess()) {
476 return;
479 DoReadEtcHostsFile([](const nsTArray<nsCString>* aArray) -> bool {
480 RefPtr<TRRService> service(sTRRServicePtr);
481 if (service && aArray) {
482 service->AddEtcHosts(*aArray);
484 return !!service;
488 void TRRService::GetURI(nsACString& result) {
489 MutexSingleWriterAutoLock lock(mLock);
490 result = mPrivateURI;
493 nsresult TRRService::GetCredentials(nsCString& result) {
494 MutexSingleWriterAutoLock lock(mLock);
495 result = mPrivateCred;
496 return NS_OK;
499 uint32_t TRRService::GetRequestTimeout() {
500 if (mMode == nsIDNSService::MODE_TRRONLY) {
501 return StaticPrefs::network_trr_request_timeout_mode_trronly_ms();
504 if (StaticPrefs::network_trr_strict_native_fallback()) {
505 return StaticPrefs::network_trr_strict_fallback_request_timeout_ms();
508 return StaticPrefs::network_trr_request_timeout_ms();
511 nsresult TRRService::Start() {
512 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
513 if (!mInitialized) {
514 return NS_ERROR_NOT_INITIALIZED;
516 return NS_OK;
519 TRRService::~TRRService() {
520 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
521 LOG(("Exiting TRRService\n"));
524 nsresult TRRService::DispatchTRRRequest(TRR* aTrrRequest) {
525 return DispatchTRRRequestInternal(aTrrRequest, true);
528 nsresult TRRService::DispatchTRRRequestInternal(TRR* aTrrRequest,
529 bool aWithLock) {
530 NS_ENSURE_ARG_POINTER(aTrrRequest);
532 nsCOMPtr<nsIThread> thread = MainThreadOrTRRThread(aWithLock);
533 if (!thread) {
534 return NS_ERROR_FAILURE;
537 RefPtr<TRR> trr = aTrrRequest;
538 return thread->Dispatch(trr.forget());
541 already_AddRefed<nsIThread> TRRService::MainThreadOrTRRThread(bool aWithLock) {
542 if (!StaticPrefs::network_trr_fetch_off_main_thread() ||
543 XRE_IsSocketProcess() || mDontUseTRRThread) {
544 return do_GetMainThread();
547 nsCOMPtr<nsIThread> thread = aWithLock ? TRRThread() : TRRThread_locked();
548 return thread.forget();
551 already_AddRefed<nsIThread> TRRService::TRRThread() {
552 MutexSingleWriterAutoLock lock(mLock);
553 return TRRThread_locked();
556 already_AddRefed<nsIThread> TRRService::TRRThread_locked() {
557 RefPtr<nsIThread> thread = sTRRBackgroundThread;
558 return thread.forget();
561 bool TRRService::IsOnTRRThread() {
562 nsCOMPtr<nsIThread> thread;
564 MutexSingleWriterAutoLock lock(mLock);
565 thread = sTRRBackgroundThread;
567 if (!thread) {
568 return false;
571 return thread->IsOnCurrentThread();
574 NS_IMETHODIMP
575 TRRService::Observe(nsISupports* aSubject, const char* aTopic,
576 const char16_t* aData) {
577 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
578 LOG(("TRR::Observe() topic=%s\n", aTopic));
579 if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
580 // Reset the state of whether a confirmation is triggered, so we can check
581 // if we create a new one after ReadPrefs().
582 mConfirmationTriggered = false;
583 ReadPrefs(NS_ConvertUTF16toUTF8(aData).get());
585 MutexSingleWriterAutoLock lock(mLock);
586 mConfirmation.RecordEvent("pref-change", lock);
589 // We should only trigger a new confirmation if reading the prefs didn't
590 // already trigger one.
591 if (!mConfirmationTriggered) {
592 mConfirmation.HandleEvent(ConfirmationEvent::PrefChange);
594 } else if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
595 // We are in a captive portal
596 LOG(("TRRservice in captive portal\n"));
597 mCaptiveIsPassed = false;
598 mConfirmation.SetCaptivePortalStatus(
599 nsICaptivePortalService::LOCKED_PORTAL);
600 } else if (!strcmp(aTopic, NS_CAPTIVE_PORTAL_CONNECTIVITY)) {
601 nsAutoCString data = NS_ConvertUTF16toUTF8(aData);
602 LOG(("TRRservice captive portal was %s\n", data.get()));
603 nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
604 if (cps) {
605 mConfirmation.SetCaptivePortalStatus(cps->State());
608 // If we were previously in a captive portal, this event means we will
609 // need to trigger confirmation again. Otherwise it's just a periodical
610 // captive-portal check that completed and we don't need to react to it.
611 if (!mCaptiveIsPassed) {
612 mConfirmation.HandleEvent(ConfirmationEvent::CaptivePortalConnectivity);
615 mCaptiveIsPassed = true;
616 } else if (!strcmp(aTopic, kClearPrivateData) || !strcmp(aTopic, kPurge)) {
617 // flush the TRR blocklist
618 auto bl = mTRRBLStorage.Lock();
619 bl->Clear();
620 } else if (!strcmp(aTopic, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC) ||
621 !strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
622 // nsINetworkLinkService is only available on parent process.
623 if (XRE_IsParentProcess()) {
624 nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
625 // The network link service notification normally passes itself as the
626 // subject, but some unit tests will sometimes pass a null subject.
627 if (link) {
628 nsTArray<nsCString> suffixList;
629 link->GetDnsSuffixList(suffixList);
630 RebuildSuffixList(std::move(suffixList));
634 if (!strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
635 if (NS_ConvertUTF16toUTF8(aData).EqualsLiteral(
636 NS_NETWORK_LINK_DATA_DOWN)) {
637 MutexSingleWriterAutoLock lock(mLock);
638 mConfirmation.RecordEvent("network-change", lock);
641 if (mURISetByDetection) {
642 // If the URI was set via SetDetectedTrrURI we need to restore it to the
643 // default pref when a network link change occurs.
644 CheckURIPrefs();
647 if (NS_ConvertUTF16toUTF8(aData).EqualsLiteral(NS_NETWORK_LINK_DATA_UP)) {
648 mConfirmation.HandleEvent(ConfirmationEvent::NetworkUp);
651 } else if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
652 mShutdown = true;
653 // If a confirmation is still in progress we record the event.
654 // Since there should be no more confirmations after this, the shutdown
655 // reason would not really be recorded in telemetry.
657 MutexSingleWriterAutoLock lock(mLock);
658 mConfirmation.RecordEvent("shutdown", lock);
661 if (sTRRBackgroundThread) {
662 nsCOMPtr<nsIThread> thread;
663 thread = sTRRBackgroundThread.get();
664 sTRRBackgroundThread = nullptr;
665 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
666 sTRRServicePtr = nullptr;
669 return NS_OK;
672 void TRRService::RebuildSuffixList(nsTArray<nsCString>&& aSuffixList) {
673 if (!StaticPrefs::network_trr_split_horizon_mitigations() || mShutdown) {
674 return;
677 MutexSingleWriterAutoLock lock(mLock);
678 mDNSSuffixDomains.Clear();
679 for (const auto& item : aSuffixList) {
680 LOG(("TRRService adding %s to suffix list", item.get()));
681 mDNSSuffixDomains.Insert(item);
685 void TRRService::ConfirmationContext::SetState(
686 enum ConfirmationState aNewState) {
687 mState = aNewState;
689 enum ConfirmationState state = mState;
690 if (XRE_IsParentProcess()) {
691 NS_DispatchToMainThread(NS_NewRunnableFunction(
692 "TRRService::ConfirmationContextNotify", [state] {
693 if (nsCOMPtr<nsIObserverService> obs =
694 mozilla::services::GetObserverService()) {
695 auto stateString =
696 [](enum ConfirmationState aState) -> const char16_t* {
697 switch (aState) {
698 case CONFIRM_OFF:
699 return u"CONFIRM_OFF";
700 case CONFIRM_TRYING_OK:
701 return u"CONFIRM_TRYING_OK";
702 case CONFIRM_OK:
703 return u"CONFIRM_OK";
704 case CONFIRM_FAILED:
705 return u"CONFIRM_FAILED";
706 case CONFIRM_TRYING_FAILED:
707 return u"CONFIRM_TRYING_FAILED";
708 case CONFIRM_DISABLED:
709 return u"CONFIRM_DISABLED";
711 MOZ_ASSERT_UNREACHABLE();
712 return u"";
715 obs->NotifyObservers(nullptr, "network:trr-confirmation",
716 stateString(state));
718 }));
721 if (XRE_IsParentProcess()) {
722 return;
725 MOZ_ASSERT(XRE_IsSocketProcess());
726 MOZ_ASSERT(NS_IsMainThread());
728 TRRServiceChild* child = TRRServiceChild::GetSingleton();
729 if (child && child->CanSend()) {
730 LOG(("TRRService::SendSetConfirmationState"));
731 Unused << child->SendSetConfirmationState(mState);
735 bool TRRService::ConfirmationContext::HandleEvent(ConfirmationEvent aEvent) {
736 MutexSingleWriterAutoLock lock(OwningObject()->mLock);
737 return HandleEvent(aEvent, lock);
740 // We're protected by service->mLock
741 bool TRRService::ConfirmationContext::HandleEvent(
742 ConfirmationEvent aEvent, const MutexSingleWriterAutoLock&) {
743 auto prevAddr = TaskAddr();
744 TRRService* service = OwningObject();
745 service->mLock.AssertCurrentThreadOwns();
746 nsIDNSService::ResolverMode mode = service->Mode();
748 auto resetConfirmation = [&]() {
749 service->mLock.AssertCurrentThreadOwns();
750 mTask = nullptr;
751 nsCOMPtr<nsITimer> timer = std::move(mTimer);
752 if (timer) {
753 timer->Cancel();
756 mRetryInterval = StaticPrefs::network_trr_retry_timeout_ms();
757 mTRRFailures = 0;
759 if (TRR_DISABLED(mode)) {
760 LOG(("TRR is disabled. mConfirmation.mState -> CONFIRM_OFF"));
761 SetState(CONFIRM_OFF);
762 return;
765 if (mode == nsIDNSService::MODE_TRRONLY) {
766 LOG(("TRR_ONLY_MODE. mConfirmation.mState -> CONFIRM_DISABLED"));
767 SetState(CONFIRM_DISABLED);
768 return;
771 if (service->mConfirmationNS.Equals("skip"_ns)) {
772 LOG((
773 "mConfirmationNS == skip. mConfirmation.mState -> CONFIRM_DISABLED"));
774 SetState(CONFIRM_DISABLED);
775 return;
778 // The next call to maybeConfirm will transition to CONFIRM_TRYING_OK
779 LOG(("mConfirmation.mState -> CONFIRM_OK"));
780 SetState(CONFIRM_OK);
783 auto maybeConfirm = [&](const char* aReason) {
784 service->mLock.AssertCurrentThreadOwns();
785 if (TRR_DISABLED(mode) || mState == CONFIRM_DISABLED || mTask) {
786 LOG(
787 ("TRRService:MaybeConfirm(%s) mode=%d, mTask=%p "
788 "mState=%d\n",
789 aReason, (int)mode, (void*)mTask, (int)mState));
790 return;
793 MOZ_ASSERT(mode != nsIDNSService::MODE_TRRONLY,
794 "Confirmation should be disabled");
795 MOZ_ASSERT(!service->mConfirmationNS.Equals("skip"),
796 "Confirmation should be disabled");
798 LOG(("maybeConfirm(%s) starting confirmation test %s %s\n", aReason,
799 service->mPrivateURI.get(), service->mConfirmationNS.get()));
801 MOZ_ASSERT(mState == CONFIRM_OK || mState == CONFIRM_FAILED);
803 if (mState == CONFIRM_FAILED) {
804 LOG(("mConfirmation.mState -> CONFIRM_TRYING_FAILED"));
805 SetState(CONFIRM_TRYING_FAILED);
806 } else {
807 LOG(("mConfirmation.mState -> CONFIRM_TRYING_OK"));
808 SetState(CONFIRM_TRYING_OK);
811 nsCOMPtr<nsITimer> timer = std::move(mTimer);
812 if (timer) {
813 timer->Cancel();
816 MOZ_ASSERT(mode == nsIDNSService::MODE_TRRFIRST,
817 "Should only confirm in TRR first mode");
818 // Set aUseFreshConnection if TRR lookups are retried.
819 mTask = new TRR(service, service->mConfirmationNS, TRRTYPE_NS, ""_ns, false,
820 StaticPrefs::network_trr_retry_on_recoverable_errors());
821 mTask->SetTimeout(StaticPrefs::network_trr_confirmation_timeout_ms());
822 mTask->SetPurpose(TRR::Confirmation);
824 if (service->mLinkService) {
825 service->mLinkService->GetNetworkID(mNetworkId);
828 if (mFirstRequestTime.IsNull()) {
829 mFirstRequestTime = TimeStamp::Now();
831 if (mTrigger.IsEmpty()) {
832 mTrigger.Assign(aReason);
835 LOG(("Dispatching confirmation task: %p", mTask.get()));
836 service->DispatchTRRRequestInternal(mTask, false);
839 switch (aEvent) {
840 case ConfirmationEvent::Init:
841 resetConfirmation();
842 maybeConfirm("context-init");
843 break;
844 case ConfirmationEvent::PrefChange:
845 resetConfirmation();
846 maybeConfirm("pref-change");
847 break;
848 case ConfirmationEvent::ConfirmationRetry:
849 MOZ_ASSERT(mState == CONFIRM_FAILED);
850 if (mState == CONFIRM_FAILED) {
851 maybeConfirm("confirmation-retry");
853 break;
854 case ConfirmationEvent::FailedLookups:
855 MOZ_ASSERT(mState == CONFIRM_OK);
856 mTrigger.Assign("failed-lookups");
857 mFailedLookups = nsDependentCSubstring(
858 mFailureReasons, mTRRFailures % ConfirmationContext::RESULTS_SIZE);
859 maybeConfirm("failed-lookups");
860 break;
861 case ConfirmationEvent::RetryTRR:
862 MOZ_ASSERT(mState == CONFIRM_OK);
863 maybeConfirm("retry-trr");
864 break;
865 case ConfirmationEvent::URIChange:
866 resetConfirmation();
867 maybeConfirm("uri-change");
868 break;
869 case ConfirmationEvent::CaptivePortalConnectivity:
870 // If we area already confirmed then we're fine.
871 // If there is a confirmation in progress, likely it started before
872 // we had full connectivity, so it may be hanging. We reset and try again.
873 if (mState == CONFIRM_FAILED || mState == CONFIRM_TRYING_FAILED ||
874 mState == CONFIRM_TRYING_OK) {
875 resetConfirmation();
876 maybeConfirm("cp-connectivity");
878 break;
879 case ConfirmationEvent::NetworkUp:
880 if (mState != CONFIRM_OK) {
881 resetConfirmation();
882 maybeConfirm("network-up");
884 break;
885 case ConfirmationEvent::ConfirmOK:
886 SetState(CONFIRM_OK);
887 mTask = nullptr;
888 break;
889 case ConfirmationEvent::ConfirmFail:
890 MOZ_ASSERT(mState == CONFIRM_TRYING_OK ||
891 mState == CONFIRM_TRYING_FAILED);
892 SetState(CONFIRM_FAILED);
893 mTask = nullptr;
894 // retry failed NS confirmation
896 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, mRetryInterval,
897 nsITimer::TYPE_ONE_SHOT);
898 if (mRetryInterval < 64000) {
899 // double the interval up to this point
900 mRetryInterval *= 2;
902 break;
903 default:
904 MOZ_ASSERT_UNREACHABLE("Unexpected ConfirmationEvent");
907 return prevAddr != TaskAddr();
910 bool TRRService::MaybeBootstrap(const nsACString& aPossible,
911 nsACString& aResult) {
912 MutexSingleWriterAutoLock lock(mLock);
913 if (mMode == nsIDNSService::MODE_TRROFF || mBootstrapAddr.IsEmpty()) {
914 return false;
917 nsCOMPtr<nsIURI> url;
918 nsresult rv =
919 NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
920 .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_STANDARD,
921 443, mPrivateURI, nullptr, nullptr, nullptr)
922 .Finalize(url);
923 if (NS_FAILED(rv)) {
924 LOG(("TRRService::MaybeBootstrap failed to create URI!\n"));
925 return false;
928 nsAutoCString host;
929 url->GetHost(host);
930 if (!aPossible.Equals(host)) {
931 return false;
933 LOG(("TRRService::MaybeBootstrap: use %s instead of %s\n",
934 mBootstrapAddr.get(), host.get()));
935 aResult = mBootstrapAddr;
936 return true;
939 bool TRRService::IsDomainBlocked(const nsACString& aHost,
940 const nsACString& aOriginSuffix,
941 bool aPrivateBrowsing) {
942 auto bl = mTRRBLStorage.Lock();
943 if (bl->IsEmpty()) {
944 return false;
947 // use a unified casing for the hashkey
948 nsAutoCString hashkey(aHost + aOriginSuffix);
949 if (auto val = bl->Lookup(hashkey)) {
950 int32_t until =
951 *val + int32_t(StaticPrefs::network_trr_temp_blocklist_duration_sec());
952 int32_t expire = NowInSeconds();
953 if (until > expire) {
954 LOG(("Host [%s] is TRR blocklisted\n", nsCString(aHost).get()));
955 return true;
958 // the blocklisted entry has expired
959 val.Remove();
961 return false;
964 // When running in TRR-only mode, the blocklist is not used and it will also
965 // try resolving the localhost / .local names.
966 bool TRRService::IsTemporarilyBlocked(const nsACString& aHost,
967 const nsACString& aOriginSuffix,
968 bool aPrivateBrowsing,
969 bool aParentsToo) // false if domain
971 if (!StaticPrefs::network_trr_temp_blocklist()) {
972 LOG(("TRRService::IsTemporarilyBlocked temp blocklist disabled by pref"));
973 return false;
976 if (mMode == nsIDNSService::MODE_TRRONLY) {
977 return false; // might as well try
980 LOG(("Checking if host [%s] is blocklisted", aHost.BeginReading()));
982 int32_t dot = aHost.FindChar('.');
983 if ((dot == kNotFound) && aParentsToo) {
984 // Only if a full host name. Domains can be dotless to be able to
985 // blocklist entire TLDs
986 return true;
989 if (IsDomainBlocked(aHost, aOriginSuffix, aPrivateBrowsing)) {
990 return true;
993 nsDependentCSubstring domain = Substring(aHost, 0);
994 while (dot != kNotFound) {
995 dot++;
996 domain.Rebind(domain, dot, domain.Length() - dot);
998 if (IsDomainBlocked(domain, aOriginSuffix, aPrivateBrowsing)) {
999 return true;
1002 dot = domain.FindChar('.');
1005 return false;
1008 bool TRRService::IsExcludedFromTRR(const nsACString& aHost) {
1009 // This method may be called off the main thread. We need to lock so
1010 // mExcludedDomains and mDNSSuffixDomains don't change while this code
1011 // is running.
1012 MutexSingleWriterAutoLock lock(mLock);
1014 return IsExcludedFromTRR_unlocked(aHost);
1017 bool TRRService::IsExcludedFromTRR_unlocked(const nsACString& aHost) {
1018 mLock.AssertOnWritingThreadOrHeld();
1020 int32_t dot = 0;
1021 // iteratively check the sub-domain of |aHost|
1022 while (dot < static_cast<int32_t>(aHost.Length())) {
1023 nsDependentCSubstring subdomain =
1024 Substring(aHost, dot, aHost.Length() - dot);
1026 if (mExcludedDomains.Contains(subdomain)) {
1027 LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR via pref\n",
1028 subdomain.BeginReading(), aHost.BeginReading()));
1029 return true;
1031 if (mDNSSuffixDomains.Contains(subdomain)) {
1032 LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR via pref\n",
1033 subdomain.BeginReading(), aHost.BeginReading()));
1034 return true;
1036 if (mEtcHostsDomains.Contains(subdomain)) {
1037 LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR by /etc/hosts\n",
1038 subdomain.BeginReading(), aHost.BeginReading()));
1039 return true;
1042 dot = aHost.FindChar('.', dot + 1);
1043 if (dot == kNotFound) {
1044 break;
1046 dot++;
1049 return false;
1052 void TRRService::AddToBlocklist(const nsACString& aHost,
1053 const nsACString& aOriginSuffix,
1054 bool privateBrowsing, bool aParentsToo) {
1055 if (!StaticPrefs::network_trr_temp_blocklist()) {
1056 LOG(("TRRService::AddToBlocklist temp blocklist disabled by pref"));
1057 return;
1060 LOG(("TRR blocklist %s\n", nsCString(aHost).get()));
1061 nsAutoCString hashkey(aHost + aOriginSuffix);
1063 // this overwrites any existing entry
1065 auto bl = mTRRBLStorage.Lock();
1066 bl->InsertOrUpdate(hashkey, NowInSeconds());
1069 // See bug 1700405. Some test expects 15 trr consecutive failures, but the NS
1070 // check against the base domain is successful. So, we skip this NS check when
1071 // the pref said so in order to pass the test reliably.
1072 if (aParentsToo && !StaticPrefs::network_trr_skip_check_for_blocked_host()) {
1073 // when given a full host name, verify its domain as well
1074 int32_t dot = aHost.FindChar('.');
1075 if (dot != kNotFound) {
1076 // this has a domain to be checked
1077 dot++;
1078 nsDependentCSubstring domain =
1079 Substring(aHost, dot, aHost.Length() - dot);
1080 nsAutoCString check(domain);
1081 if (IsTemporarilyBlocked(check, aOriginSuffix, privateBrowsing, false)) {
1082 // the domain part is already blocklisted, no need to add this entry
1083 return;
1085 // verify 'check' over TRR
1086 LOG(("TRR: verify if '%s' resolves as NS\n", check.get()));
1088 // check if there's an NS entry for this name
1089 RefPtr<TRR> trr = new TRR(this, check, TRRTYPE_NS, aOriginSuffix,
1090 privateBrowsing, false);
1091 trr->SetPurpose(TRR::Blocklist);
1092 DispatchTRRRequest(trr);
1097 NS_IMETHODIMP
1098 TRRService::ConfirmationContext::Notify(nsITimer* aTimer) {
1099 MutexSingleWriterAutoLock lock(OwningObject()->mLock);
1100 if (aTimer == mTimer) {
1101 HandleEvent(ConfirmationEvent::ConfirmationRetry, lock);
1104 return NS_OK;
1107 NS_IMETHODIMP
1108 TRRService::ConfirmationContext::GetName(nsACString& aName) {
1109 aName.AssignLiteral("TRRService::ConfirmationContext");
1110 return NS_OK;
1113 static char StatusToChar(nsresult aLookupStatus, nsresult aChannelStatus) {
1114 // If the resolution fails in the TRR channel then we'll have a failed
1115 // aChannelStatus. Otherwise, we parse the response - if it's not a valid DNS
1116 // packet or doesn't contain the correct responses aLookupStatus will be a
1117 // failure code.
1118 if (aChannelStatus == NS_OK) {
1119 // Return + if confirmation was OK, or - if confirmation failed
1120 return aLookupStatus == NS_OK ? '+' : '-';
1123 if (nsCOMPtr<nsIIOService> ios = do_GetIOService()) {
1124 bool hasConnectiviy = true;
1125 ios->GetConnectivity(&hasConnectiviy);
1126 if (!hasConnectiviy) {
1127 // Browser has no active network interfaces = is offline.
1128 return 'o';
1132 switch (aChannelStatus) {
1133 case NS_ERROR_NET_TIMEOUT_EXTERNAL:
1134 // TRR timeout expired
1135 return 't';
1136 case NS_ERROR_UNKNOWN_HOST:
1137 // TRRServiceChannel failed to due to unresolved host
1138 return 'd';
1139 default:
1140 break;
1143 // The error is a network error
1144 if (NS_ERROR_GET_MODULE(aChannelStatus) == NS_ERROR_MODULE_NETWORK) {
1145 return 'n';
1148 // Some other kind of failure.
1149 return '?';
1152 void TRRService::RetryTRRConfirm() {
1153 if (mConfirmation.State() == CONFIRM_OK) {
1154 LOG(("TRRService::RetryTRRConfirm triggering confirmation"));
1155 mConfirmation.HandleEvent(ConfirmationEvent::RetryTRR);
1159 void TRRService::RecordTRRStatus(TRR* aTrrRequest) {
1160 MOZ_ASSERT_IF(XRE_IsParentProcess(), NS_IsMainThread() || IsOnTRRThread());
1161 MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
1163 nsresult channelStatus = aTrrRequest->ChannelStatus();
1165 Telemetry::AccumulateCategoricalKeyed(
1166 ProviderKey(), NS_SUCCEEDED(channelStatus)
1167 ? Telemetry::LABELS_DNS_TRR_SUCCESS3::Fine
1168 : (channelStatus == NS_ERROR_NET_TIMEOUT_EXTERNAL
1169 ? Telemetry::LABELS_DNS_TRR_SUCCESS3::Timeout
1170 : Telemetry::LABELS_DNS_TRR_SUCCESS3::Bad));
1172 mConfirmation.RecordTRRStatus(aTrrRequest);
1175 void TRRService::ConfirmationContext::RecordTRRStatus(TRR* aTrrRequest) {
1176 nsresult channelStatus = aTrrRequest->ChannelStatus();
1178 if (OwningObject()->Mode() == nsIDNSService::MODE_TRRONLY) {
1179 mLastConfirmationSkipReason = aTrrRequest->SkipReason();
1180 mLastConfirmationStatus = channelStatus;
1183 if (NS_SUCCEEDED(channelStatus)) {
1184 LOG(("TRRService::RecordTRRStatus channel success"));
1185 mTRRFailures = 0;
1186 return;
1189 if (OwningObject()->Mode() != nsIDNSService::MODE_TRRFIRST) {
1190 return;
1193 // only count failures while in OK state
1194 if (State() != CONFIRM_OK) {
1195 return;
1198 // When TRR retry is enabled, nsHostResolver will trigger Confirmation
1199 // immediately upon a lookup failure, so nothing to be done here.
1200 // nsHostResolver can assess the success of the lookup considering all the
1201 // involved results (A, AAAA) so we let it tell us when to re-Confirm.
1202 if (StaticPrefs::network_trr_retry_on_recoverable_errors()) {
1203 LOG(("TRRService not counting failures when retry is enabled"));
1204 return;
1207 mFailureReasons[mTRRFailures % ConfirmationContext::RESULTS_SIZE] =
1208 StatusToChar(NS_OK, channelStatus);
1209 uint32_t fails = ++mTRRFailures;
1210 LOG(("TRRService::RecordTRRStatus fails=%u", fails));
1212 if (fails >= StaticPrefs::network_trr_max_fails()) {
1213 LOG(("TRRService had %u failures in a row\n", fails));
1214 // When several failures occur we trigger a confirmation causing
1215 // us to transition into the CONFIRM_TRYING_OK state.
1216 // Only after the confirmation fails do we finally go into CONFIRM_FAILED
1217 // and start skipping TRR.
1219 // Trigger a confirmation immediately.
1220 // If it fails, it will fire off a timer to start retrying again.
1221 HandleEvent(ConfirmationEvent::FailedLookups);
1225 void TRRService::ConfirmationContext::RecordEvent(
1226 const char* aReason, const MutexSingleWriterAutoLock&) {
1227 // Reset the confirmation context attributes
1228 // Only resets the attributes that we keep for telemetry purposes.
1229 auto reset = [&]() {
1230 mAttemptCount = 0;
1231 mNetworkId.Truncate();
1232 mFirstRequestTime = TimeStamp();
1233 mContextChangeReason.Assign(aReason);
1234 mTrigger.Truncate();
1235 mFailedLookups.Truncate();
1237 mRetryInterval = StaticPrefs::network_trr_retry_timeout_ms();
1240 if (mAttemptCount == 0) {
1241 // XXX: resetting everything might not be the best thing here, even if the
1242 // context changes, because there might still be a confirmation pending.
1243 // But cancelling and retrying that confirmation might just make the whole
1244 // confirmation longer for no reason.
1245 reset();
1246 return;
1249 Telemetry::EventID eventType =
1250 Telemetry::EventID::NetworkDns_Trrconfirmation_Context;
1252 nsAutoCString results;
1253 static_assert(RESULTS_SIZE < 64);
1255 // mResults is a circular buffer ending at mAttemptCount
1256 if (mAttemptCount <= RESULTS_SIZE) {
1257 // We have fewer attempts than the size of the buffer, so all of the
1258 // results are in the buffer.
1259 results.Append(nsDependentCSubstring(mResults, mAttemptCount));
1260 } else {
1261 // More attempts than the buffer size.
1262 // That means past RESULTS_SIZE attempts in order are
1263 // [posInResults .. end-of-buffer) + [start-of-buffer .. posInResults)
1264 uint32_t posInResults = mAttemptCount % RESULTS_SIZE;
1266 results.Append(nsDependentCSubstring(mResults + posInResults,
1267 RESULTS_SIZE - posInResults));
1268 results.Append(nsDependentCSubstring(mResults, posInResults));
1271 auto extra = Some<nsTArray<mozilla::Telemetry::EventExtraEntry>>({
1272 Telemetry::EventExtraEntry{"trigger"_ns, mTrigger},
1273 Telemetry::EventExtraEntry{"contextReason"_ns, mContextChangeReason},
1274 Telemetry::EventExtraEntry{"attemptCount"_ns,
1275 nsPrintfCString("%u", mAttemptCount)},
1276 Telemetry::EventExtraEntry{"results"_ns, results},
1277 Telemetry::EventExtraEntry{
1278 "time"_ns,
1279 nsPrintfCString(
1280 "%f",
1281 !mFirstRequestTime.IsNull()
1282 ? (TimeStamp::Now() - mFirstRequestTime).ToMilliseconds()
1283 : 0.0)},
1284 Telemetry::EventExtraEntry{"networkID"_ns, mNetworkId},
1285 Telemetry::EventExtraEntry{"captivePortal"_ns,
1286 nsPrintfCString("%i", mCaptivePortalStatus)},
1289 if (mTrigger.Equals("failed-lookups"_ns)) {
1290 extra.ref().AppendElement(
1291 Telemetry::EventExtraEntry{"failedLookups"_ns, mFailedLookups});
1294 enum ConfirmationState state = mState;
1295 Telemetry::RecordEvent(eventType, mozilla::Some(nsPrintfCString("%u", state)),
1296 extra);
1298 reset();
1301 void TRRService::ConfirmationContext::RequestCompleted(
1302 nsresult aLookupStatus, nsresult aChannelStatus) {
1303 mResults[mAttemptCount % RESULTS_SIZE] =
1304 StatusToChar(aLookupStatus, aChannelStatus);
1305 mAttemptCount++;
1308 void TRRService::ConfirmationContext::CompleteConfirmation(nsresult aStatus,
1309 TRR* aTRRRequest) {
1311 MutexSingleWriterAutoLock lock(OwningObject()->mLock);
1312 // Ignore confirmations that dont match the pending task.
1313 if (mTask != aTRRRequest) {
1314 return;
1316 MOZ_ASSERT(State() == CONFIRM_TRYING_OK ||
1317 State() == CONFIRM_TRYING_FAILED);
1318 if (State() != CONFIRM_TRYING_OK && State() != CONFIRM_TRYING_FAILED) {
1319 return;
1322 RequestCompleted(aStatus, aTRRRequest->ChannelStatus());
1323 mLastConfirmationSkipReason = aTRRRequest->SkipReason();
1324 mLastConfirmationStatus = aTRRRequest->ChannelStatus();
1326 MOZ_ASSERT(mTask);
1327 if (NS_SUCCEEDED(aStatus)) {
1328 HandleEvent(ConfirmationEvent::ConfirmOK, lock);
1329 } else {
1330 HandleEvent(ConfirmationEvent::ConfirmFail, lock);
1333 if (State() == CONFIRM_OK) {
1334 // Record event and start new confirmation context
1335 RecordEvent("success", lock);
1337 LOG(("TRRService finishing confirmation test %s %d %X\n",
1338 OwningObject()->mPrivateURI.get(), State(), (unsigned int)aStatus));
1341 if (State() == CONFIRM_OK) {
1342 // A fresh confirmation means previous blocked entries might not
1343 // be valid anymore.
1344 auto bl = OwningObject()->mTRRBLStorage.Lock();
1345 bl->Clear();
1346 } else {
1347 MOZ_ASSERT(State() == CONFIRM_FAILED);
1350 Telemetry::Accumulate(Telemetry::DNS_TRR_NS_VERFIFIED3,
1351 TRRService::ProviderKey(), (State() == CONFIRM_OK));
1354 AHostResolver::LookupStatus TRRService::CompleteLookup(
1355 nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb,
1356 const nsACString& aOriginSuffix, TRRSkippedReason aReason,
1357 TRR* aTRRRequest) {
1358 // this is an NS check for the TRR blocklist or confirmationNS check
1360 MOZ_ASSERT_IF(XRE_IsParentProcess(), NS_IsMainThread() || IsOnTRRThread());
1361 MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
1362 MOZ_ASSERT(!rec);
1364 RefPtr<AddrInfo> newRRSet(aNewRRSet);
1365 MOZ_ASSERT(newRRSet && newRRSet->TRRType() == TRRTYPE_NS);
1367 if (aTRRRequest->Purpose() == TRR::Confirmation) {
1368 mConfirmation.CompleteConfirmation(status, aTRRRequest);
1369 return LOOKUP_OK;
1372 if (aTRRRequest->Purpose() == TRR::Blocklist) {
1373 if (NS_SUCCEEDED(status)) {
1374 LOG(("TRR verified %s to be fine!\n", newRRSet->Hostname().get()));
1375 } else {
1376 LOG(("TRR says %s doesn't resolve as NS!\n", newRRSet->Hostname().get()));
1377 AddToBlocklist(newRRSet->Hostname(), aOriginSuffix, pb, false);
1379 return LOOKUP_OK;
1382 MOZ_ASSERT_UNREACHABLE(
1383 "TRRService::CompleteLookup called for unexpected request");
1384 return LOOKUP_OK;
1387 AHostResolver::LookupStatus TRRService::CompleteLookupByType(
1388 nsHostRecord*, nsresult, mozilla::net::TypeRecordResultType& aResult,
1389 uint32_t aTtl, bool aPb) {
1390 return LOOKUP_OK;
1393 NS_IMETHODIMP TRRService::OnProxyConfigChanged() {
1394 LOG(("TRRService::OnProxyConfigChanged"));
1396 nsAutoCString uri;
1397 GetURI(uri);
1398 AsyncCreateTRRConnectionInfo(uri);
1400 return NS_OK;
1403 void TRRService::InitTRRConnectionInfo() {
1404 if (XRE_IsParentProcess()) {
1405 TRRServiceBase::InitTRRConnectionInfo();
1406 return;
1409 MOZ_ASSERT(XRE_IsSocketProcess());
1410 MOZ_ASSERT(NS_IsMainThread());
1412 TRRServiceChild* child = TRRServiceChild::GetSingleton();
1413 if (child && child->CanSend()) {
1414 LOG(("TRRService::SendInitTRRConnectionInfo"));
1415 Unused << child->SendInitTRRConnectionInfo();
1419 } // namespace mozilla::net