Bug 1866777 - Disable test_race_cache_with_network.js on windows opt for frequent...
[gecko.git] / netwerk / dns / TRRService.cpp
blobfbaa67ee144fc78710d0e65719d8dc583f3d6a39
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";
36 #define TRR_PREF_PREFIX "network.trr."
37 #define TRR_PREF(x) TRR_PREF_PREFIX x
39 namespace mozilla::net {
41 StaticRefPtr<nsIThread> sTRRBackgroundThread;
42 static Atomic<TRRService*> sTRRServicePtr;
44 static Atomic<size_t, Relaxed> sDomainIndex(0);
45 static Atomic<size_t, Relaxed> sCurrentTRRModeIndex(0);
47 constexpr nsLiteralCString kTRRDomains[3][7] = {
48 // clang-format off
50 // When mode is 0, the provider key has no postfix.
51 "(other)"_ns,
52 "mozilla.cloudflare-dns.com"_ns,
53 "firefox.dns.nextdns.io"_ns,
54 "private.canadianshield.cira.ca"_ns,
55 "doh.xfinity.com"_ns, // Steered clients
56 "dns.shaw.ca"_ns, // Steered clients
57 "dooh.cloudflare-dns.com"_ns, // DNS over Oblivious HTTP
60 "(other)_2"_ns,
61 "mozilla.cloudflare-dns.com_2"_ns,
62 "firefox.dns.nextdns.io_2"_ns,
63 "private.canadianshield.cira.ca_2"_ns,
64 "doh.xfinity.com_2"_ns, // Steered clients
65 "dns.shaw.ca_2"_ns, // Steered clients
66 "dooh.cloudflare-dns.com_2"_ns, // DNS over Oblivious HTTP
69 "(other)_3"_ns,
70 "mozilla.cloudflare-dns.com_3"_ns,
71 "firefox.dns.nextdns.io_3"_ns,
72 "private.canadianshield.cira.ca_3"_ns,
73 "doh.xfinity.com_3"_ns, // Steered clients
74 "dns.shaw.ca_3"_ns, // Steered clients
75 "dooh.cloudflare-dns.com_3"_ns, // DNS over Oblivious HTTP
77 // clang-format on
80 // static
81 void TRRService::SetCurrentTRRMode(nsIDNSService::ResolverMode aMode) {
82 // A table to map ResolverMode to the row of kTRRDomains.
83 // When the aMode is 2, we use kTRRDomains[1] as provider keys. When aMode is
84 // 3, we use kTRRDomains[2]. Otherwise, we kTRRDomains[0] is used.
85 static const uint32_t index[] = {0, 0, 1, 2, 0, 0};
86 if (aMode > nsIDNSService::MODE_TRROFF) {
87 aMode = nsIDNSService::MODE_TRROFF;
89 sCurrentTRRModeIndex = index[static_cast<size_t>(aMode)];
92 // static
93 void TRRService::SetProviderDomain(const nsACString& aTRRDomain) {
94 sDomainIndex = 0;
95 for (size_t i = 1; i < std::size(kTRRDomains[0]); i++) {
96 if (aTRRDomain.Equals(kTRRDomains[0][i])) {
97 sDomainIndex = i;
98 break;
103 // static
104 const nsCString& TRRService::ProviderKey() {
105 return kTRRDomains[sCurrentTRRModeIndex][sDomainIndex];
108 NS_IMPL_ISUPPORTS_INHERITED(TRRService, TRRServiceBase, nsIObserver,
109 nsISupportsWeakReference)
111 NS_IMPL_ADDREF_USING_AGGREGATOR(TRRService::ConfirmationContext, OwningObject())
112 NS_IMPL_RELEASE_USING_AGGREGATOR(TRRService::ConfirmationContext,
113 OwningObject())
114 NS_IMPL_QUERY_INTERFACE(TRRService::ConfirmationContext, nsITimerCallback,
115 nsINamed)
117 TRRService::TRRService() : mLock("TRRService", this) {
118 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
121 // static
122 TRRService* TRRService::Get() { return sTRRServicePtr; }
124 // static
125 void TRRService::AddObserver(nsIObserver* aObserver,
126 nsIObserverService* aObserverService) {
127 nsCOMPtr<nsIObserverService> observerService;
128 if (aObserverService) {
129 observerService = aObserverService;
130 } else {
131 observerService = mozilla::services::GetObserverService();
134 if (observerService) {
135 observerService->AddObserver(aObserver, NS_CAPTIVE_PORTAL_CONNECTIVITY,
136 true);
137 observerService->AddObserver(aObserver, kOpenCaptivePortalLoginEvent, true);
138 observerService->AddObserver(aObserver, kClearPrivateData, true);
139 observerService->AddObserver(aObserver, kPurge, true);
140 observerService->AddObserver(aObserver, NS_NETWORK_LINK_TOPIC, true);
141 observerService->AddObserver(aObserver, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC,
142 true);
143 observerService->AddObserver(aObserver, "xpcom-shutdown-threads", true);
147 // static
148 bool TRRService::CheckCaptivePortalIsPassed() {
149 bool result = false;
150 nsCOMPtr<nsICaptivePortalService> captivePortalService =
151 do_GetService(NS_CAPTIVEPORTAL_CID);
152 if (captivePortalService) {
153 int32_t captiveState;
154 MOZ_ALWAYS_SUCCEEDS(captivePortalService->GetState(&captiveState));
156 if ((captiveState == nsICaptivePortalService::UNLOCKED_PORTAL) ||
157 (captiveState == nsICaptivePortalService::NOT_CAPTIVE)) {
158 result = true;
160 LOG(("TRRService::Init mCaptiveState=%d mCaptiveIsPassed=%d\n",
161 captiveState, (int)result));
164 return result;
167 static void EventTelemetryPrefChanged(const char* aPref, void* aData) {
168 Telemetry::SetEventRecordingEnabled(
169 "network.dns"_ns,
170 StaticPrefs::network_trr_confirmation_telemetry_enabled());
173 nsresult TRRService::Init() {
174 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
175 if (mInitialized) {
176 return NS_OK;
178 mInitialized = true;
180 AddObserver(this);
182 nsCOMPtr<nsIPrefBranch> prefBranch;
183 GetPrefBranch(getter_AddRefs(prefBranch));
184 if (prefBranch) {
185 prefBranch->AddObserver(TRR_PREF_PREFIX, this, true);
186 prefBranch->AddObserver(kRolloutURIPref, this, true);
187 prefBranch->AddObserver(kRolloutModePref, this, true);
190 sTRRServicePtr = this;
192 ReadPrefs(nullptr);
193 mConfirmation.HandleEvent(ConfirmationEvent::Init);
195 if (XRE_IsParentProcess()) {
196 mCaptiveIsPassed = CheckCaptivePortalIsPassed();
198 mParentalControlEnabled = GetParentalControlEnabledInternal();
200 mLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
201 if (mLinkService) {
202 nsTArray<nsCString> suffixList;
203 mLinkService->GetDnsSuffixList(suffixList);
204 RebuildSuffixList(std::move(suffixList));
207 nsCOMPtr<nsIThread> thread;
208 if (NS_FAILED(
209 NS_NewNamedThread("TRR Background", getter_AddRefs(thread)))) {
210 NS_WARNING("NS_NewNamedThread failed!");
211 return NS_ERROR_FAILURE;
214 sTRRBackgroundThread = thread;
217 Preferences::RegisterCallbackAndCall(
218 EventTelemetryPrefChanged,
219 "network.trr.confirmation_telemetry_enabled"_ns);
221 LOG(("Initialized TRRService\n"));
222 return NS_OK;
225 // static
226 bool TRRService::GetParentalControlEnabledInternal() {
227 nsCOMPtr<nsIParentalControlsService> pc =
228 do_CreateInstance("@mozilla.org/parental-controls-service;1");
229 if (pc) {
230 bool result = false;
231 pc->GetParentalControlsEnabled(&result);
232 LOG(("TRRService::GetParentalControlEnabledInternal=%d\n", result));
233 return result;
236 return false;
239 void TRRService::SetDetectedTrrURI(const nsACString& aURI) {
240 LOG(("SetDetectedTrrURI(%s", nsPromiseFlatCString(aURI).get()));
241 // If the user has set a custom URI then we don't want to override that.
242 // If the URI is set via doh-rollout.uri, mURIPref will be empty
243 // (see TRRServiceBase::OnTRRURIChange)
244 if (!mURIPref.IsEmpty()) {
245 LOG(("Already has user value. Not setting URI"));
246 return;
249 if (StaticPrefs::network_trr_use_ohttp()) {
250 LOG(("No autodetection when using OHTTP"));
251 return;
254 mURISetByDetection = MaybeSetPrivateURI(aURI);
257 bool TRRService::Enabled(nsIRequest::TRRMode aRequestMode) {
258 if (mMode == nsIDNSService::MODE_TRROFF ||
259 aRequestMode == nsIRequest::TRR_DISABLED_MODE) {
260 LOG(("TRR service not enabled - off or disabled"));
261 return false;
264 // If already confirmed, service is enabled.
265 if (mConfirmation.State() == CONFIRM_OK ||
266 aRequestMode == nsIRequest::TRR_ONLY_MODE) {
267 LOG(("TRR service enabled - confirmed or trr_only request"));
268 return true;
271 // If this is a TRR_FIRST request but the resolver has a different mode,
272 // just go ahead and let it try to use TRR.
273 if (aRequestMode == nsIRequest::TRR_FIRST_MODE &&
274 mMode != nsIDNSService::MODE_TRRFIRST) {
275 LOG(("TRR service enabled - trr_first request"));
276 return true;
279 // In TRR_ONLY_MODE / confirmationNS == "skip" we don't try to confirm.
280 if (mConfirmation.State() == CONFIRM_DISABLED) {
281 LOG(("TRRService service enabled - confirmation is disabled"));
282 return true;
285 LOG(("TRRService::Enabled mConfirmation.mState=%d mCaptiveIsPassed=%d\n",
286 mConfirmation.State(), (int)mCaptiveIsPassed));
288 if (StaticPrefs::network_trr_wait_for_confirmation()) {
289 return mConfirmation.State() == CONFIRM_OK;
292 if (StaticPrefs::network_trr_attempt_when_retrying_confirmation()) {
293 return mConfirmation.State() == CONFIRM_OK ||
294 mConfirmation.State() == CONFIRM_TRYING_OK ||
295 mConfirmation.State() == CONFIRM_TRYING_FAILED;
298 return mConfirmation.State() == CONFIRM_OK ||
299 mConfirmation.State() == CONFIRM_TRYING_OK;
302 void TRRService::GetPrefBranch(nsIPrefBranch** result) {
303 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
304 *result = nullptr;
305 CallGetService(NS_PREFSERVICE_CONTRACTID, result);
308 bool TRRService::MaybeSetPrivateURI(const nsACString& aURI) {
309 bool clearCache = false;
310 nsAutoCString newURI(aURI);
311 LOG(("MaybeSetPrivateURI(%s)", newURI.get()));
313 ProcessURITemplate(newURI);
315 MutexSingleWriterAutoLock lock(mLock);
316 if (mPrivateURI.Equals(newURI)) {
317 return false;
320 if (!mPrivateURI.IsEmpty()) {
321 LOG(("TRRService clearing blocklist because of change in uri service\n"));
322 auto bl = mTRRBLStorage.Lock();
323 bl->Clear();
324 clearCache = true;
327 nsAutoCString host;
329 nsCOMPtr<nsIURI> url;
330 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(url), newURI))) {
331 url->GetHost(host);
334 SetProviderDomain(host);
336 mPrivateURI = newURI;
338 // Notify the content processes of the new TRR
339 for (auto* cp :
340 dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
341 PNeckoParent* neckoParent =
342 SingleManagedOrNull(cp->ManagedPNeckoParent());
343 if (!neckoParent) {
344 continue;
346 Unused << neckoParent->SendSetTRRDomain(host);
349 AsyncCreateTRRConnectionInfo(mPrivateURI);
351 // The URI has changed. We should trigger a new confirmation immediately.
352 // We must do this here because the URI could also change because of
353 // steering.
354 mConfirmationTriggered =
355 mConfirmation.HandleEvent(ConfirmationEvent::URIChange, lock);
358 // Clear the cache because we changed the URI
359 if (clearCache) {
360 ClearEntireCache();
363 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
364 if (obs) {
365 obs->NotifyObservers(nullptr, NS_NETWORK_TRR_URI_CHANGED_TOPIC, nullptr);
367 return true;
370 nsresult TRRService::ReadPrefs(const char* name) {
371 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
373 // Whenever a pref change occurs that would cause us to clear the cache
374 // we set this to true then do it at the end of the method.
375 bool clearEntireCache = false;
377 if (!name || !strcmp(name, TRR_PREF("mode")) ||
378 !strcmp(name, kRolloutModePref)) {
379 nsIDNSService::ResolverMode prevMode = Mode();
381 OnTRRModeChange();
382 // When the TRR service gets disabled we should purge the TRR cache to
383 // make sure we don't use any of the cached entries on a network where
384 // they are invalid - for example after turning on a VPN.
385 if (TRR_DISABLED(Mode()) && !TRR_DISABLED(prevMode)) {
386 clearEntireCache = true;
389 if (!name || !strcmp(name, TRR_PREF("uri")) ||
390 !strcmp(name, TRR_PREF("default_provider_uri")) ||
391 !strcmp(name, kRolloutURIPref) || !strcmp(name, TRR_PREF("ohttp.uri")) ||
392 !strcmp(name, TRR_PREF("use_ohttp"))) {
393 OnTRRURIChange();
395 if (!name || !strcmp(name, TRR_PREF("credentials"))) {
396 MutexSingleWriterAutoLock lock(mLock);
397 Preferences::GetCString(TRR_PREF("credentials"), mPrivateCred);
399 if (!name || !strcmp(name, TRR_PREF("confirmationNS"))) {
400 MutexSingleWriterAutoLock lock(mLock);
401 Preferences::GetCString(TRR_PREF("confirmationNS"), mConfirmationNS);
402 LOG(("confirmationNS = %s", mConfirmationNS.get()));
404 if (!name || !strcmp(name, TRR_PREF("bootstrapAddr"))) {
405 MutexSingleWriterAutoLock lock(mLock);
406 Preferences::GetCString(TRR_PREF("bootstrapAddr"), mBootstrapAddr);
407 clearEntireCache = true;
409 if (!name || !strcmp(name, TRR_PREF("excluded-domains")) ||
410 !strcmp(name, TRR_PREF("builtin-excluded-domains"))) {
411 MutexSingleWriterAutoLock lock(mLock);
412 mExcludedDomains.Clear();
414 auto parseExcludedDomains = [this](const char* aPrefName) {
415 nsAutoCString excludedDomains;
416 mLock.AssertCurrentThreadOwns();
417 Preferences::GetCString(aPrefName, excludedDomains);
418 if (excludedDomains.IsEmpty()) {
419 return;
422 for (const nsACString& tokenSubstring :
423 nsCCharSeparatedTokenizerTemplate<
424 NS_IsAsciiWhitespace, nsTokenizerFlags::SeparatorOptional>(
425 excludedDomains, ',')
426 .ToRange()) {
427 nsCString token{tokenSubstring};
428 LOG(("TRRService::ReadPrefs %s host:[%s]\n", aPrefName, token.get()));
429 mExcludedDomains.Insert(token);
433 parseExcludedDomains(TRR_PREF("excluded-domains"));
434 parseExcludedDomains(TRR_PREF("builtin-excluded-domains"));
435 clearEntireCache = true;
438 // if name is null, then we're just now initializing. In that case we don't
439 // need to clear the cache.
440 if (name && clearEntireCache) {
441 ClearEntireCache();
444 return NS_OK;
447 void TRRService::ClearEntireCache() {
448 if (!StaticPrefs::network_trr_clear_cache_on_pref_change()) {
449 return;
451 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
452 if (!dns) {
453 return;
455 dns->ClearCache(true);
458 void TRRService::AddEtcHosts(const nsTArray<nsCString>& aArray) {
459 MutexSingleWriterAutoLock lock(mLock);
460 for (const auto& item : aArray) {
461 LOG(("Adding %s from /etc/hosts to excluded domains", item.get()));
462 mEtcHostsDomains.Insert(item);
466 void TRRService::ReadEtcHostsFile() {
467 if (!XRE_IsParentProcess()) {
468 return;
471 DoReadEtcHostsFile([](const nsTArray<nsCString>* aArray) -> bool {
472 RefPtr<TRRService> service(sTRRServicePtr);
473 if (service && aArray) {
474 service->AddEtcHosts(*aArray);
476 return !!service;
480 void TRRService::GetURI(nsACString& result) {
481 MutexSingleWriterAutoLock lock(mLock);
482 result = mPrivateURI;
485 nsresult TRRService::GetCredentials(nsCString& result) {
486 MutexSingleWriterAutoLock lock(mLock);
487 result = mPrivateCred;
488 return NS_OK;
491 uint32_t TRRService::GetRequestTimeout() {
492 if (mMode == nsIDNSService::MODE_TRRONLY) {
493 return StaticPrefs::network_trr_request_timeout_mode_trronly_ms();
496 if (StaticPrefs::network_trr_strict_native_fallback()) {
497 return StaticPrefs::network_trr_strict_fallback_request_timeout_ms();
500 return StaticPrefs::network_trr_request_timeout_ms();
503 nsresult TRRService::Start() {
504 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
505 if (!mInitialized) {
506 return NS_ERROR_NOT_INITIALIZED;
508 return NS_OK;
511 TRRService::~TRRService() {
512 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
513 LOG(("Exiting TRRService\n"));
516 nsresult TRRService::DispatchTRRRequest(TRR* aTrrRequest) {
517 return DispatchTRRRequestInternal(aTrrRequest, true);
520 nsresult TRRService::DispatchTRRRequestInternal(TRR* aTrrRequest,
521 bool aWithLock) {
522 NS_ENSURE_ARG_POINTER(aTrrRequest);
524 nsCOMPtr<nsIThread> thread = MainThreadOrTRRThread(aWithLock);
525 if (!thread) {
526 return NS_ERROR_FAILURE;
529 RefPtr<TRR> trr = aTrrRequest;
530 return thread->Dispatch(trr.forget());
533 already_AddRefed<nsIThread> TRRService::MainThreadOrTRRThread(bool aWithLock) {
534 if (!StaticPrefs::network_trr_fetch_off_main_thread() ||
535 XRE_IsSocketProcess() || mDontUseTRRThread) {
536 return do_GetMainThread();
539 nsCOMPtr<nsIThread> thread = aWithLock ? TRRThread() : TRRThread_locked();
540 return thread.forget();
543 already_AddRefed<nsIThread> TRRService::TRRThread() {
544 MutexSingleWriterAutoLock lock(mLock);
545 return TRRThread_locked();
548 already_AddRefed<nsIThread> TRRService::TRRThread_locked() {
549 RefPtr<nsIThread> thread = sTRRBackgroundThread;
550 return thread.forget();
553 bool TRRService::IsOnTRRThread() {
554 nsCOMPtr<nsIThread> thread;
556 MutexSingleWriterAutoLock lock(mLock);
557 thread = sTRRBackgroundThread;
559 if (!thread) {
560 return false;
563 return thread->IsOnCurrentThread();
566 NS_IMETHODIMP
567 TRRService::Observe(nsISupports* aSubject, const char* aTopic,
568 const char16_t* aData) {
569 MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
570 LOG(("TRR::Observe() topic=%s\n", aTopic));
571 if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
572 // Reset the state of whether a confirmation is triggered, so we can check
573 // if we create a new one after ReadPrefs().
574 mConfirmationTriggered = false;
575 ReadPrefs(NS_ConvertUTF16toUTF8(aData).get());
577 MutexSingleWriterAutoLock lock(mLock);
578 mConfirmation.RecordEvent("pref-change", lock);
581 // We should only trigger a new confirmation if reading the prefs didn't
582 // already trigger one.
583 if (!mConfirmationTriggered) {
584 mConfirmation.HandleEvent(ConfirmationEvent::PrefChange);
586 } else if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
587 // We are in a captive portal
588 LOG(("TRRservice in captive portal\n"));
589 mCaptiveIsPassed = false;
590 mConfirmation.SetCaptivePortalStatus(
591 nsICaptivePortalService::LOCKED_PORTAL);
592 } else if (!strcmp(aTopic, NS_CAPTIVE_PORTAL_CONNECTIVITY)) {
593 nsAutoCString data = NS_ConvertUTF16toUTF8(aData);
594 LOG(("TRRservice captive portal was %s\n", data.get()));
595 nsCOMPtr<nsICaptivePortalService> cps = do_QueryInterface(aSubject);
596 if (cps) {
597 mConfirmation.SetCaptivePortalStatus(cps->State());
600 // If we were previously in a captive portal, this event means we will
601 // need to trigger confirmation again. Otherwise it's just a periodical
602 // captive-portal check that completed and we don't need to react to it.
603 if (!mCaptiveIsPassed) {
604 mConfirmation.HandleEvent(ConfirmationEvent::CaptivePortalConnectivity);
607 mCaptiveIsPassed = true;
608 } else if (!strcmp(aTopic, kClearPrivateData) || !strcmp(aTopic, kPurge)) {
609 // flush the TRR blocklist
610 auto bl = mTRRBLStorage.Lock();
611 bl->Clear();
612 } else if (!strcmp(aTopic, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC) ||
613 !strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
614 // nsINetworkLinkService is only available on parent process.
615 if (XRE_IsParentProcess()) {
616 nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
617 // The network link service notification normally passes itself as the
618 // subject, but some unit tests will sometimes pass a null subject.
619 if (link) {
620 nsTArray<nsCString> suffixList;
621 link->GetDnsSuffixList(suffixList);
622 RebuildSuffixList(std::move(suffixList));
626 if (!strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
627 if (NS_ConvertUTF16toUTF8(aData).EqualsLiteral(
628 NS_NETWORK_LINK_DATA_DOWN)) {
629 MutexSingleWriterAutoLock lock(mLock);
630 mConfirmation.RecordEvent("network-change", lock);
633 if (mURISetByDetection) {
634 // If the URI was set via SetDetectedTrrURI we need to restore it to the
635 // default pref when a network link change occurs.
636 CheckURIPrefs();
639 if (NS_ConvertUTF16toUTF8(aData).EqualsLiteral(NS_NETWORK_LINK_DATA_UP)) {
640 mConfirmation.HandleEvent(ConfirmationEvent::NetworkUp);
643 } else if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
644 mShutdown = true;
645 // If a confirmation is still in progress we record the event.
646 // Since there should be no more confirmations after this, the shutdown
647 // reason would not really be recorded in telemetry.
649 MutexSingleWriterAutoLock lock(mLock);
650 mConfirmation.RecordEvent("shutdown", lock);
653 if (sTRRBackgroundThread) {
654 nsCOMPtr<nsIThread> thread;
655 thread = sTRRBackgroundThread.get();
656 sTRRBackgroundThread = nullptr;
657 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
658 sTRRServicePtr = nullptr;
661 return NS_OK;
664 void TRRService::RebuildSuffixList(nsTArray<nsCString>&& aSuffixList) {
665 if (!StaticPrefs::network_trr_split_horizon_mitigations() || mShutdown) {
666 return;
669 MutexSingleWriterAutoLock lock(mLock);
670 mDNSSuffixDomains.Clear();
671 for (const auto& item : aSuffixList) {
672 LOG(("TRRService adding %s to suffix list", item.get()));
673 mDNSSuffixDomains.Insert(item);
677 void TRRService::ConfirmationContext::SetState(
678 enum ConfirmationState aNewState) {
679 mState = aNewState;
681 enum ConfirmationState state = mState;
682 if (XRE_IsParentProcess()) {
683 NS_DispatchToMainThread(NS_NewRunnableFunction(
684 "TRRService::ConfirmationContextNotify", [state] {
685 if (nsCOMPtr<nsIObserverService> obs =
686 mozilla::services::GetObserverService()) {
687 auto stateString =
688 [](enum ConfirmationState aState) -> const char16_t* {
689 switch (aState) {
690 case CONFIRM_OFF:
691 return u"CONFIRM_OFF";
692 case CONFIRM_TRYING_OK:
693 return u"CONFIRM_TRYING_OK";
694 case CONFIRM_OK:
695 return u"CONFIRM_OK";
696 case CONFIRM_FAILED:
697 return u"CONFIRM_FAILED";
698 case CONFIRM_TRYING_FAILED:
699 return u"CONFIRM_TRYING_FAILED";
700 case CONFIRM_DISABLED:
701 return u"CONFIRM_DISABLED";
703 MOZ_ASSERT_UNREACHABLE();
704 return u"";
707 obs->NotifyObservers(nullptr, "network:trr-confirmation",
708 stateString(state));
710 }));
713 if (XRE_IsParentProcess()) {
714 return;
717 MOZ_ASSERT(XRE_IsSocketProcess());
718 MOZ_ASSERT(NS_IsMainThread());
720 TRRServiceChild* child = TRRServiceChild::GetSingleton();
721 if (child && child->CanSend()) {
722 LOG(("TRRService::SendSetConfirmationState"));
723 Unused << child->SendSetConfirmationState(mState);
727 bool TRRService::ConfirmationContext::HandleEvent(ConfirmationEvent aEvent) {
728 MutexSingleWriterAutoLock lock(OwningObject()->mLock);
729 return HandleEvent(aEvent, lock);
732 // We're protected by service->mLock
733 bool TRRService::ConfirmationContext::HandleEvent(
734 ConfirmationEvent aEvent, const MutexSingleWriterAutoLock&) {
735 auto prevAddr = TaskAddr();
736 TRRService* service = OwningObject();
737 service->mLock.AssertCurrentThreadOwns();
738 nsIDNSService::ResolverMode mode = service->Mode();
740 auto resetConfirmation = [&]() {
741 service->mLock.AssertCurrentThreadOwns();
742 mTask = nullptr;
743 nsCOMPtr<nsITimer> timer = std::move(mTimer);
744 if (timer) {
745 timer->Cancel();
748 mRetryInterval = StaticPrefs::network_trr_retry_timeout_ms();
749 mTRRFailures = 0;
751 if (TRR_DISABLED(mode)) {
752 LOG(("TRR is disabled. mConfirmation.mState -> CONFIRM_OFF"));
753 SetState(CONFIRM_OFF);
754 return;
757 if (mode == nsIDNSService::MODE_TRRONLY) {
758 LOG(("TRR_ONLY_MODE. mConfirmation.mState -> CONFIRM_DISABLED"));
759 SetState(CONFIRM_DISABLED);
760 return;
763 if (service->mConfirmationNS.Equals("skip"_ns)) {
764 LOG((
765 "mConfirmationNS == skip. mConfirmation.mState -> CONFIRM_DISABLED"));
766 SetState(CONFIRM_DISABLED);
767 return;
770 // The next call to maybeConfirm will transition to CONFIRM_TRYING_OK
771 LOG(("mConfirmation.mState -> CONFIRM_OK"));
772 SetState(CONFIRM_OK);
775 auto maybeConfirm = [&](const char* aReason) {
776 service->mLock.AssertCurrentThreadOwns();
777 if (TRR_DISABLED(mode) || mState == CONFIRM_DISABLED || mTask) {
778 LOG(
779 ("TRRService:MaybeConfirm(%s) mode=%d, mTask=%p "
780 "mState=%d\n",
781 aReason, (int)mode, (void*)mTask, (int)mState));
782 return;
785 MOZ_ASSERT(mode != nsIDNSService::MODE_TRRONLY,
786 "Confirmation should be disabled");
787 MOZ_ASSERT(!service->mConfirmationNS.Equals("skip"),
788 "Confirmation should be disabled");
790 LOG(("maybeConfirm(%s) starting confirmation test %s %s\n", aReason,
791 service->mPrivateURI.get(), service->mConfirmationNS.get()));
793 MOZ_ASSERT(mState == CONFIRM_OK || mState == CONFIRM_FAILED);
795 if (mState == CONFIRM_FAILED) {
796 LOG(("mConfirmation.mState -> CONFIRM_TRYING_FAILED"));
797 SetState(CONFIRM_TRYING_FAILED);
798 } else {
799 LOG(("mConfirmation.mState -> CONFIRM_TRYING_OK"));
800 SetState(CONFIRM_TRYING_OK);
803 nsCOMPtr<nsITimer> timer = std::move(mTimer);
804 if (timer) {
805 timer->Cancel();
808 MOZ_ASSERT(mode == nsIDNSService::MODE_TRRFIRST,
809 "Should only confirm in TRR first mode");
810 // Set aUseFreshConnection if TRR lookups are retried.
811 mTask = new TRR(service, service->mConfirmationNS, TRRTYPE_NS, ""_ns, false,
812 StaticPrefs::network_trr_retry_on_recoverable_errors());
813 mTask->SetTimeout(StaticPrefs::network_trr_confirmation_timeout_ms());
814 mTask->SetPurpose(TRR::Confirmation);
816 if (service->mLinkService) {
817 service->mLinkService->GetNetworkID(mNetworkId);
820 if (mFirstRequestTime.IsNull()) {
821 mFirstRequestTime = TimeStamp::Now();
823 if (mTrigger.IsEmpty()) {
824 mTrigger.Assign(aReason);
827 LOG(("Dispatching confirmation task: %p", mTask.get()));
828 service->DispatchTRRRequestInternal(mTask, false);
831 switch (aEvent) {
832 case ConfirmationEvent::Init:
833 resetConfirmation();
834 maybeConfirm("context-init");
835 break;
836 case ConfirmationEvent::PrefChange:
837 resetConfirmation();
838 maybeConfirm("pref-change");
839 break;
840 case ConfirmationEvent::ConfirmationRetry:
841 MOZ_ASSERT(mState == CONFIRM_FAILED);
842 if (mState == CONFIRM_FAILED) {
843 maybeConfirm("confirmation-retry");
845 break;
846 case ConfirmationEvent::FailedLookups:
847 MOZ_ASSERT(mState == CONFIRM_OK);
848 mTrigger.Assign("failed-lookups");
849 mFailedLookups = nsDependentCSubstring(
850 mFailureReasons, mTRRFailures % ConfirmationContext::RESULTS_SIZE);
851 maybeConfirm("failed-lookups");
852 break;
853 case ConfirmationEvent::RetryTRR:
854 MOZ_ASSERT(mState == CONFIRM_OK);
855 maybeConfirm("retry-trr");
856 break;
857 case ConfirmationEvent::URIChange:
858 resetConfirmation();
859 maybeConfirm("uri-change");
860 break;
861 case ConfirmationEvent::CaptivePortalConnectivity:
862 // If we area already confirmed then we're fine.
863 // If there is a confirmation in progress, likely it started before
864 // we had full connectivity, so it may be hanging. We reset and try again.
865 if (mState == CONFIRM_FAILED || mState == CONFIRM_TRYING_FAILED ||
866 mState == CONFIRM_TRYING_OK) {
867 resetConfirmation();
868 maybeConfirm("cp-connectivity");
870 break;
871 case ConfirmationEvent::NetworkUp:
872 if (mState != CONFIRM_OK) {
873 resetConfirmation();
874 maybeConfirm("network-up");
876 break;
877 case ConfirmationEvent::ConfirmOK:
878 SetState(CONFIRM_OK);
879 mTask = nullptr;
880 break;
881 case ConfirmationEvent::ConfirmFail:
882 MOZ_ASSERT(mState == CONFIRM_TRYING_OK ||
883 mState == CONFIRM_TRYING_FAILED);
884 SetState(CONFIRM_FAILED);
885 mTask = nullptr;
886 // retry failed NS confirmation
888 NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, mRetryInterval,
889 nsITimer::TYPE_ONE_SHOT);
890 if (mRetryInterval < 64000) {
891 // double the interval up to this point
892 mRetryInterval *= 2;
894 break;
895 default:
896 MOZ_ASSERT_UNREACHABLE("Unexpected ConfirmationEvent");
899 return prevAddr != TaskAddr();
902 bool TRRService::MaybeBootstrap(const nsACString& aPossible,
903 nsACString& aResult) {
904 MutexSingleWriterAutoLock lock(mLock);
905 if (mMode == nsIDNSService::MODE_TRROFF || mBootstrapAddr.IsEmpty()) {
906 return false;
909 nsCOMPtr<nsIURI> url;
910 nsresult rv =
911 NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
912 .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_STANDARD,
913 443, mPrivateURI, nullptr, nullptr, nullptr)
914 .Finalize(url);
915 if (NS_FAILED(rv)) {
916 LOG(("TRRService::MaybeBootstrap failed to create URI!\n"));
917 return false;
920 nsAutoCString host;
921 url->GetHost(host);
922 if (!aPossible.Equals(host)) {
923 return false;
925 LOG(("TRRService::MaybeBootstrap: use %s instead of %s\n",
926 mBootstrapAddr.get(), host.get()));
927 aResult = mBootstrapAddr;
928 return true;
931 bool TRRService::IsDomainBlocked(const nsACString& aHost,
932 const nsACString& aOriginSuffix,
933 bool aPrivateBrowsing) {
934 auto bl = mTRRBLStorage.Lock();
935 if (bl->IsEmpty()) {
936 return false;
939 // use a unified casing for the hashkey
940 nsAutoCString hashkey(aHost + aOriginSuffix);
941 if (auto val = bl->Lookup(hashkey)) {
942 int32_t until =
943 *val + int32_t(StaticPrefs::network_trr_temp_blocklist_duration_sec());
944 int32_t expire = NowInSeconds();
945 if (until > expire) {
946 LOG(("Host [%s] is TRR blocklisted\n", nsCString(aHost).get()));
947 return true;
950 // the blocklisted entry has expired
951 val.Remove();
953 return false;
956 // When running in TRR-only mode, the blocklist is not used and it will also
957 // try resolving the localhost / .local names.
958 bool TRRService::IsTemporarilyBlocked(const nsACString& aHost,
959 const nsACString& aOriginSuffix,
960 bool aPrivateBrowsing,
961 bool aParentsToo) // false if domain
963 if (!StaticPrefs::network_trr_temp_blocklist()) {
964 LOG(("TRRService::IsTemporarilyBlocked temp blocklist disabled by pref"));
965 return false;
968 if (mMode == nsIDNSService::MODE_TRRONLY) {
969 return false; // might as well try
972 LOG(("Checking if host [%s] is blocklisted", aHost.BeginReading()));
974 int32_t dot = aHost.FindChar('.');
975 if ((dot == kNotFound) && aParentsToo) {
976 // Only if a full host name. Domains can be dotless to be able to
977 // blocklist entire TLDs
978 return true;
981 if (IsDomainBlocked(aHost, aOriginSuffix, aPrivateBrowsing)) {
982 return true;
985 nsDependentCSubstring domain = Substring(aHost, 0);
986 while (dot != kNotFound) {
987 dot++;
988 domain.Rebind(domain, dot, domain.Length() - dot);
990 if (IsDomainBlocked(domain, aOriginSuffix, aPrivateBrowsing)) {
991 return true;
994 dot = domain.FindChar('.');
997 return false;
1000 bool TRRService::IsExcludedFromTRR(const nsACString& aHost) {
1001 // This method may be called off the main thread. We need to lock so
1002 // mExcludedDomains and mDNSSuffixDomains don't change while this code
1003 // is running.
1004 MutexSingleWriterAutoLock lock(mLock);
1006 return IsExcludedFromTRR_unlocked(aHost);
1009 bool TRRService::IsExcludedFromTRR_unlocked(const nsACString& aHost) {
1010 mLock.AssertOnWritingThreadOrHeld();
1012 int32_t dot = 0;
1013 // iteratively check the sub-domain of |aHost|
1014 while (dot < static_cast<int32_t>(aHost.Length())) {
1015 nsDependentCSubstring subdomain =
1016 Substring(aHost, dot, aHost.Length() - dot);
1018 if (mExcludedDomains.Contains(subdomain)) {
1019 LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR via pref\n",
1020 subdomain.BeginReading(), aHost.BeginReading()));
1021 return true;
1023 if (mDNSSuffixDomains.Contains(subdomain)) {
1024 LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR via pref\n",
1025 subdomain.BeginReading(), aHost.BeginReading()));
1026 return true;
1028 if (mEtcHostsDomains.Contains(subdomain)) {
1029 LOG(("Subdomain [%s] of host [%s] Is Excluded From TRR by /etc/hosts\n",
1030 subdomain.BeginReading(), aHost.BeginReading()));
1031 return true;
1034 dot = aHost.FindChar('.', dot + 1);
1035 if (dot == kNotFound) {
1036 break;
1038 dot++;
1041 return false;
1044 void TRRService::AddToBlocklist(const nsACString& aHost,
1045 const nsACString& aOriginSuffix,
1046 bool privateBrowsing, bool aParentsToo) {
1047 if (!StaticPrefs::network_trr_temp_blocklist()) {
1048 LOG(("TRRService::AddToBlocklist temp blocklist disabled by pref"));
1049 return;
1052 LOG(("TRR blocklist %s\n", nsCString(aHost).get()));
1053 nsAutoCString hashkey(aHost + aOriginSuffix);
1055 // this overwrites any existing entry
1057 auto bl = mTRRBLStorage.Lock();
1058 bl->InsertOrUpdate(hashkey, NowInSeconds());
1061 // See bug 1700405. Some test expects 15 trr consecutive failures, but the NS
1062 // check against the base domain is successful. So, we skip this NS check when
1063 // the pref said so in order to pass the test reliably.
1064 if (aParentsToo && !StaticPrefs::network_trr_skip_check_for_blocked_host()) {
1065 // when given a full host name, verify its domain as well
1066 int32_t dot = aHost.FindChar('.');
1067 if (dot != kNotFound) {
1068 // this has a domain to be checked
1069 dot++;
1070 nsDependentCSubstring domain =
1071 Substring(aHost, dot, aHost.Length() - dot);
1072 nsAutoCString check(domain);
1073 if (IsTemporarilyBlocked(check, aOriginSuffix, privateBrowsing, false)) {
1074 // the domain part is already blocklisted, no need to add this entry
1075 return;
1077 // verify 'check' over TRR
1078 LOG(("TRR: verify if '%s' resolves as NS\n", check.get()));
1080 // check if there's an NS entry for this name
1081 RefPtr<TRR> trr = new TRR(this, check, TRRTYPE_NS, aOriginSuffix,
1082 privateBrowsing, false);
1083 trr->SetPurpose(TRR::Blocklist);
1084 DispatchTRRRequest(trr);
1089 NS_IMETHODIMP
1090 TRRService::ConfirmationContext::Notify(nsITimer* aTimer) {
1091 MutexSingleWriterAutoLock lock(OwningObject()->mLock);
1092 if (aTimer == mTimer) {
1093 HandleEvent(ConfirmationEvent::ConfirmationRetry, lock);
1096 return NS_OK;
1099 NS_IMETHODIMP
1100 TRRService::ConfirmationContext::GetName(nsACString& aName) {
1101 aName.AssignLiteral("TRRService::ConfirmationContext");
1102 return NS_OK;
1105 static char StatusToChar(nsresult aLookupStatus, nsresult aChannelStatus) {
1106 // If the resolution fails in the TRR channel then we'll have a failed
1107 // aChannelStatus. Otherwise, we parse the response - if it's not a valid DNS
1108 // packet or doesn't contain the correct responses aLookupStatus will be a
1109 // failure code.
1110 if (aChannelStatus == NS_OK) {
1111 // Return + if confirmation was OK, or - if confirmation failed
1112 return aLookupStatus == NS_OK ? '+' : '-';
1115 if (nsCOMPtr<nsIIOService> ios = do_GetIOService()) {
1116 bool hasConnectiviy = true;
1117 ios->GetConnectivity(&hasConnectiviy);
1118 if (!hasConnectiviy) {
1119 // Browser has no active network interfaces = is offline.
1120 return 'o';
1124 switch (aChannelStatus) {
1125 case NS_ERROR_NET_TIMEOUT_EXTERNAL:
1126 // TRR timeout expired
1127 return 't';
1128 case NS_ERROR_UNKNOWN_HOST:
1129 // TRRServiceChannel failed to due to unresolved host
1130 return 'd';
1131 default:
1132 break;
1135 // The error is a network error
1136 if (NS_ERROR_GET_MODULE(aChannelStatus) == NS_ERROR_MODULE_NETWORK) {
1137 return 'n';
1140 // Some other kind of failure.
1141 return '?';
1144 void TRRService::RetryTRRConfirm() {
1145 if (mConfirmation.State() == CONFIRM_OK) {
1146 LOG(("TRRService::RetryTRRConfirm triggering confirmation"));
1147 mConfirmation.HandleEvent(ConfirmationEvent::RetryTRR);
1151 void TRRService::RecordTRRStatus(TRR* aTrrRequest) {
1152 MOZ_ASSERT_IF(XRE_IsParentProcess(), NS_IsMainThread() || IsOnTRRThread());
1153 MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
1155 nsresult channelStatus = aTrrRequest->ChannelStatus();
1157 Telemetry::AccumulateCategoricalKeyed(
1158 ProviderKey(), NS_SUCCEEDED(channelStatus)
1159 ? Telemetry::LABELS_DNS_TRR_SUCCESS3::Fine
1160 : (channelStatus == NS_ERROR_NET_TIMEOUT_EXTERNAL
1161 ? Telemetry::LABELS_DNS_TRR_SUCCESS3::Timeout
1162 : Telemetry::LABELS_DNS_TRR_SUCCESS3::Bad));
1164 mConfirmation.RecordTRRStatus(aTrrRequest);
1167 void TRRService::ConfirmationContext::RecordTRRStatus(TRR* aTrrRequest) {
1168 nsresult channelStatus = aTrrRequest->ChannelStatus();
1170 if (OwningObject()->Mode() == nsIDNSService::MODE_TRRONLY) {
1171 mLastConfirmationSkipReason = aTrrRequest->SkipReason();
1172 mLastConfirmationStatus = channelStatus;
1175 if (NS_SUCCEEDED(channelStatus)) {
1176 LOG(("TRRService::RecordTRRStatus channel success"));
1177 mTRRFailures = 0;
1178 return;
1181 if (OwningObject()->Mode() != nsIDNSService::MODE_TRRFIRST) {
1182 return;
1185 // only count failures while in OK state
1186 if (State() != CONFIRM_OK) {
1187 return;
1190 // When TRR retry is enabled, nsHostResolver will trigger Confirmation
1191 // immediately upon a lookup failure, so nothing to be done here.
1192 // nsHostResolver can assess the success of the lookup considering all the
1193 // involved results (A, AAAA) so we let it tell us when to re-Confirm.
1194 if (StaticPrefs::network_trr_retry_on_recoverable_errors()) {
1195 LOG(("TRRService not counting failures when retry is enabled"));
1196 return;
1199 mFailureReasons[mTRRFailures % ConfirmationContext::RESULTS_SIZE] =
1200 StatusToChar(NS_OK, channelStatus);
1201 uint32_t fails = ++mTRRFailures;
1202 LOG(("TRRService::RecordTRRStatus fails=%u", fails));
1204 if (fails >= StaticPrefs::network_trr_max_fails()) {
1205 LOG(("TRRService had %u failures in a row\n", fails));
1206 // When several failures occur we trigger a confirmation causing
1207 // us to transition into the CONFIRM_TRYING_OK state.
1208 // Only after the confirmation fails do we finally go into CONFIRM_FAILED
1209 // and start skipping TRR.
1211 // Trigger a confirmation immediately.
1212 // If it fails, it will fire off a timer to start retrying again.
1213 HandleEvent(ConfirmationEvent::FailedLookups);
1217 void TRRService::ConfirmationContext::RecordEvent(
1218 const char* aReason, const MutexSingleWriterAutoLock&) {
1219 // Reset the confirmation context attributes
1220 // Only resets the attributes that we keep for telemetry purposes.
1221 auto reset = [&]() {
1222 mAttemptCount = 0;
1223 mNetworkId.Truncate();
1224 mFirstRequestTime = TimeStamp();
1225 mContextChangeReason.Assign(aReason);
1226 mTrigger.Truncate();
1227 mFailedLookups.Truncate();
1229 mRetryInterval = StaticPrefs::network_trr_retry_timeout_ms();
1232 if (mAttemptCount == 0) {
1233 // XXX: resetting everything might not be the best thing here, even if the
1234 // context changes, because there might still be a confirmation pending.
1235 // But cancelling and retrying that confirmation might just make the whole
1236 // confirmation longer for no reason.
1237 reset();
1238 return;
1241 Telemetry::EventID eventType =
1242 Telemetry::EventID::NetworkDns_Trrconfirmation_Context;
1244 nsAutoCString results;
1245 static_assert(RESULTS_SIZE < 64);
1247 // mResults is a circular buffer ending at mAttemptCount
1248 if (mAttemptCount <= RESULTS_SIZE) {
1249 // We have fewer attempts than the size of the buffer, so all of the
1250 // results are in the buffer.
1251 results.Append(nsDependentCSubstring(mResults, mAttemptCount));
1252 } else {
1253 // More attempts than the buffer size.
1254 // That means past RESULTS_SIZE attempts in order are
1255 // [posInResults .. end-of-buffer) + [start-of-buffer .. posInResults)
1256 uint32_t posInResults = mAttemptCount % RESULTS_SIZE;
1258 results.Append(nsDependentCSubstring(mResults + posInResults,
1259 RESULTS_SIZE - posInResults));
1260 results.Append(nsDependentCSubstring(mResults, posInResults));
1263 auto extra = Some<nsTArray<mozilla::Telemetry::EventExtraEntry>>({
1264 Telemetry::EventExtraEntry{"trigger"_ns, mTrigger},
1265 Telemetry::EventExtraEntry{"contextReason"_ns, mContextChangeReason},
1266 Telemetry::EventExtraEntry{"attemptCount"_ns,
1267 nsPrintfCString("%u", mAttemptCount)},
1268 Telemetry::EventExtraEntry{"results"_ns, results},
1269 Telemetry::EventExtraEntry{
1270 "time"_ns,
1271 nsPrintfCString(
1272 "%f",
1273 !mFirstRequestTime.IsNull()
1274 ? (TimeStamp::Now() - mFirstRequestTime).ToMilliseconds()
1275 : 0.0)},
1276 Telemetry::EventExtraEntry{"networkID"_ns, mNetworkId},
1277 Telemetry::EventExtraEntry{"captivePortal"_ns,
1278 nsPrintfCString("%i", mCaptivePortalStatus)},
1281 if (mTrigger.Equals("failed-lookups"_ns)) {
1282 extra.ref().AppendElement(
1283 Telemetry::EventExtraEntry{"failedLookups"_ns, mFailedLookups});
1286 enum ConfirmationState state = mState;
1287 Telemetry::RecordEvent(eventType, mozilla::Some(nsPrintfCString("%u", state)),
1288 extra);
1290 reset();
1293 void TRRService::ConfirmationContext::RequestCompleted(
1294 nsresult aLookupStatus, nsresult aChannelStatus) {
1295 mResults[mAttemptCount % RESULTS_SIZE] =
1296 StatusToChar(aLookupStatus, aChannelStatus);
1297 mAttemptCount++;
1300 void TRRService::ConfirmationContext::CompleteConfirmation(nsresult aStatus,
1301 TRR* aTRRRequest) {
1303 MutexSingleWriterAutoLock lock(OwningObject()->mLock);
1304 // Ignore confirmations that dont match the pending task.
1305 if (mTask != aTRRRequest) {
1306 return;
1308 MOZ_ASSERT(State() == CONFIRM_TRYING_OK ||
1309 State() == CONFIRM_TRYING_FAILED);
1310 if (State() != CONFIRM_TRYING_OK && State() != CONFIRM_TRYING_FAILED) {
1311 return;
1314 RequestCompleted(aStatus, aTRRRequest->ChannelStatus());
1315 mLastConfirmationSkipReason = aTRRRequest->SkipReason();
1316 mLastConfirmationStatus = aTRRRequest->ChannelStatus();
1318 MOZ_ASSERT(mTask);
1319 if (NS_SUCCEEDED(aStatus)) {
1320 HandleEvent(ConfirmationEvent::ConfirmOK, lock);
1321 } else {
1322 HandleEvent(ConfirmationEvent::ConfirmFail, lock);
1325 if (State() == CONFIRM_OK) {
1326 // Record event and start new confirmation context
1327 RecordEvent("success", lock);
1329 LOG(("TRRService finishing confirmation test %s %d %X\n",
1330 OwningObject()->mPrivateURI.get(), State(), (unsigned int)aStatus));
1333 if (State() == CONFIRM_OK) {
1334 // A fresh confirmation means previous blocked entries might not
1335 // be valid anymore.
1336 auto bl = OwningObject()->mTRRBLStorage.Lock();
1337 bl->Clear();
1338 } else {
1339 MOZ_ASSERT(State() == CONFIRM_FAILED);
1342 Telemetry::Accumulate(Telemetry::DNS_TRR_NS_VERFIFIED3,
1343 TRRService::ProviderKey(), (State() == CONFIRM_OK));
1346 AHostResolver::LookupStatus TRRService::CompleteLookup(
1347 nsHostRecord* rec, nsresult status, AddrInfo* aNewRRSet, bool pb,
1348 const nsACString& aOriginSuffix, TRRSkippedReason aReason,
1349 TRR* aTRRRequest) {
1350 // this is an NS check for the TRR blocklist or confirmationNS check
1352 MOZ_ASSERT_IF(XRE_IsParentProcess(), NS_IsMainThread() || IsOnTRRThread());
1353 MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
1354 MOZ_ASSERT(!rec);
1356 RefPtr<AddrInfo> newRRSet(aNewRRSet);
1357 MOZ_ASSERT(newRRSet && newRRSet->TRRType() == TRRTYPE_NS);
1359 if (aTRRRequest->Purpose() == TRR::Confirmation) {
1360 mConfirmation.CompleteConfirmation(status, aTRRRequest);
1361 return LOOKUP_OK;
1364 if (aTRRRequest->Purpose() == TRR::Blocklist) {
1365 if (NS_SUCCEEDED(status)) {
1366 LOG(("TRR verified %s to be fine!\n", newRRSet->Hostname().get()));
1367 } else {
1368 LOG(("TRR says %s doesn't resolve as NS!\n", newRRSet->Hostname().get()));
1369 AddToBlocklist(newRRSet->Hostname(), aOriginSuffix, pb, false);
1371 return LOOKUP_OK;
1374 MOZ_ASSERT_UNREACHABLE(
1375 "TRRService::CompleteLookup called for unexpected request");
1376 return LOOKUP_OK;
1379 AHostResolver::LookupStatus TRRService::CompleteLookupByType(
1380 nsHostRecord*, nsresult, mozilla::net::TypeRecordResultType& aResult,
1381 mozilla::net::TRRSkippedReason aReason, uint32_t aTtl, bool aPb) {
1382 return LOOKUP_OK;
1385 NS_IMETHODIMP TRRService::OnProxyConfigChanged() {
1386 LOG(("TRRService::OnProxyConfigChanged"));
1388 nsAutoCString uri;
1389 GetURI(uri);
1390 AsyncCreateTRRConnectionInfo(uri);
1392 return NS_OK;
1395 void TRRService::InitTRRConnectionInfo() {
1396 if (XRE_IsParentProcess()) {
1397 TRRServiceBase::InitTRRConnectionInfo();
1398 return;
1401 MOZ_ASSERT(XRE_IsSocketProcess());
1402 MOZ_ASSERT(NS_IsMainThread());
1404 TRRServiceChild* child = TRRServiceChild::GetSingleton();
1405 if (child && child->CanSend()) {
1406 LOG(("TRRService::SendInitTRRConnectionInfo"));
1407 Unused << child->SendInitTRRConnectionInfo();
1411 } // namespace mozilla::net