Bug 1539819 - P1: Make TRRService work in socket process r=dragana,necko-reviewers
authorKershaw Chang <kershaw@mozilla.com>
Mon, 18 May 2020 20:18:03 +0000
changeset 530703 d23855057df71e5add44e08e507033f4f4c8446b
parent 530702 e867d81f901948a82da3d6294cb36ae24ffad424
child 530704 3c13d25cab1eff31c39c7fa3b121fe58d24f71ca
push id116316
push userkjang@mozilla.com
push dateMon, 18 May 2020 20:28:45 +0000
treeherderautoland@7c84257e93be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdragana, necko-reviewers
bugs1539819
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1539819 - P1: Make TRRService work in socket process r=dragana,necko-reviewers Differential Revision: https://phabricator.services.mozilla.com/D68880
dom/canvas/QueueParamTraits.h
netwerk/base/NetworkConnectivityService.cpp
netwerk/base/nsIOService.cpp
netwerk/dns/ChildDNSService.cpp
netwerk/dns/ChildDNSService.h
netwerk/dns/PTRRService.ipdl
netwerk/dns/TRRService.cpp
netwerk/dns/TRRService.h
netwerk/dns/TRRServiceChild.cpp
netwerk/dns/TRRServiceChild.h
netwerk/dns/TRRServiceParent.cpp
netwerk/dns/TRRServiceParent.h
netwerk/dns/moz.build
netwerk/ipc/PSocketProcess.ipdl
netwerk/ipc/SocketProcessChild.cpp
netwerk/ipc/SocketProcessChild.h
--- a/dom/canvas/QueueParamTraits.h
+++ b/dom/canvas/QueueParamTraits.h
@@ -5,16 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _QUEUEPARAMTRAITS_H_
 #define _QUEUEPARAMTRAITS_H_ 1
 
 #include "mozilla/ipc/SharedMemoryBasic.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/IntegerRange.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/Logging.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TypeTraits.h"
 #include "nsString.h"
 
 namespace IPC {
--- a/netwerk/base/NetworkConnectivityService.cpp
+++ b/netwerk/base/NetworkConnectivityService.cpp
@@ -19,16 +19,20 @@ namespace net {
 NS_IMPL_ISUPPORTS(NetworkConnectivityService, nsIDNSListener, nsIObserver,
                   nsINetworkConnectivityService, nsIStreamListener)
 
 static StaticRefPtr<NetworkConnectivityService> gConnService;
 
 // static
 already_AddRefed<NetworkConnectivityService>
 NetworkConnectivityService::GetSingleton() {
+  if (!XRE_IsParentProcess()) {
+    return nullptr;
+  }
+
   if (gConnService) {
     return do_AddRef(gConnService);
   }
 
   RefPtr<NetworkConnectivityService> service = new NetworkConnectivityService();
   service->Init();
 
   gConnService = std::move(service);
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -218,16 +218,19 @@ static const char* gCallbackPrefs[] = {
     nullptr,
 };
 
 static const char* gCallbackPrefsForSocketProcess[] = {
     WEBRTC_PREF_PREFIX,
     NETWORK_DNS_PREF,
     "network.ssl_tokens_cache_enabled",
     "network.send_ODA_to_content_directly",
+    "network.trr.",
+    "network.dns.disableIPv6",
+    "network.dns.skipTRR-when-parental-control-enabled",
     nullptr,
 };
 
 static const char* gCallbackSecurityPrefs[] = {
     // Note the prefs listed below should be in sync with the code in
     // HandleTLSPrefChange().
     "security.tls.version.min",
     "security.tls.version.max",
@@ -380,21 +383,22 @@ nsresult nsIOService::InitializeNetworkL
   if (mNetworkLinkServiceInitialized) return rv;
 
   if (!NS_IsMainThread()) {
     NS_WARNING("Network link service should be created on main thread");
     return NS_ERROR_FAILURE;
   }
 
   // go into managed mode if we can, and chrome process
-  if (XRE_IsParentProcess()) {
-    mNetworkLinkService =
-        do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
+  if (!XRE_IsParentProcess()) {
+    return NS_ERROR_NOT_AVAILABLE;
   }
 
+  mNetworkLinkService = do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
+
   if (mNetworkLinkService) {
     mNetworkLinkServiceInitialized = true;
   }
 
   // After initializing the networkLinkService, query the connectivity state
   OnNetworkLinkEvent(NS_NETWORK_LINK_DATA_UNKNOWN);
 
   return rv;
--- a/netwerk/dns/ChildDNSService.cpp
+++ b/netwerk/dns/ChildDNSService.cpp
@@ -9,16 +9,17 @@
 #include "nsThreadUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIProtocolProxyService.h"
 #include "nsNetCID.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/net/DNSListenerProxy.h"
+#include "mozilla/net/TRRServiceParent.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
 namespace net {
 
 //-----------------------------------------------------------------------------
 // ChildDNSService
 //-----------------------------------------------------------------------------
@@ -47,16 +48,18 @@ ChildDNSService::ChildDNSService()
       mDisablePrefetch(false),
       mPendingRequestsLock("DNSPendingRequestsLock") {
   MOZ_ASSERT_IF(nsIOService::UseSocketProcess(),
                 XRE_IsContentProcess() || XRE_IsParentProcess());
   MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(),
                 XRE_IsContentProcess() || XRE_IsSocketProcess());
   if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) {
     nsDNSPrefetch::Initialize(this);
+    mTRRServiceParent = new TRRServiceParent();
+    mTRRServiceParent->Init();
   }
 }
 
 void ChildDNSService::GetDNSRecordHashKey(
     const nsACString& aHost, const nsACString& aTrrServer, uint16_t aType,
     const OriginAttributes& aOriginAttributes, uint32_t aFlags,
     nsIDNSListener* aListener, nsACString& aHashKey) {
   aHashKey.Assign(aHost);
--- a/netwerk/dns/ChildDNSService.h
+++ b/netwerk/dns/ChildDNSService.h
@@ -14,16 +14,18 @@
 #include "DNSRequestChild.h"
 #include "DNSRequestParent.h"
 #include "nsHashKeys.h"
 #include "nsClassHashtable.h"
 
 namespace mozilla {
 namespace net {
 
+class TRRServiceParent;
+
 class ChildDNSService final : public nsPIDNSService, public nsIObserver {
  public:
   // AsyncResolve (and CancelAsyncResolve) can be called off-main
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSPIDNSSERVICE
   NS_DECL_NSIDNSSERVICE
   NS_DECL_NSIOBSERVER
 
@@ -53,14 +55,15 @@ class ChildDNSService final : public nsP
 
   bool mFirstTime;
   bool mDisablePrefetch;
 
   // We need to remember pending dns requests to be able to cancel them.
   nsClassHashtable<nsCStringHashKey, nsTArray<RefPtr<DNSRequestSender>>>
       mPendingRequests;
   Mutex mPendingRequestsLock;
+  RefPtr<TRRServiceParent> mTRRServiceParent;
 };
 
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // mozilla_net_ChildDNSService_h
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/PTRRService.ipdl
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PSocketProcess;
+
+include PSMIPCTypes;
+
+namespace mozilla {
+namespace net {
+
+async refcounted protocol PTRRService
+{
+  manager PSocketProcess;
+
+child:
+  async __delete__();
+  async NotifyObserver(nsCString aTopic, nsString aData);
+  async UpdatePlatformDNSInformation(nsCString[] aSuffixList,
+                                     bool aPlatformDisabledTRR);
+  async InitTRRBLStorage(DataStorageEntry aEntry, FileDescriptor aWriteFd);
+
+};
+
+} //namespace net
+} //namespace mozilla
--- a/netwerk/dns/TRRService.cpp
+++ b/netwerk/dns/TRRService.cpp
@@ -60,87 +60,115 @@ TRRService::TRRService()
       mClearTRRBLStorage(false),
       mConfirmationState(CONFIRM_INIT),
       mRetryConfirmInterval(1000),
       mTRRFailures(0),
       mParentalControlEnabled(false) {
   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
 }
 
+// static
+void TRRService::AddObserver(nsIObserver* aObserver) {
+  nsCOMPtr<nsIObserverService> observerService =
+      mozilla::services::GetObserverService();
+  if (observerService) {
+    observerService->AddObserver(aObserver, NS_CAPTIVE_PORTAL_CONNECTIVITY,
+                                 true);
+    observerService->AddObserver(aObserver, kOpenCaptivePortalLoginEvent, true);
+    observerService->AddObserver(aObserver, kClearPrivateData, true);
+    observerService->AddObserver(aObserver, kPurge, true);
+    observerService->AddObserver(aObserver, NS_NETWORK_LINK_TOPIC, true);
+    observerService->AddObserver(aObserver, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC,
+                                 true);
+    observerService->AddObserver(aObserver, "xpcom-shutdown-threads", true);
+  }
+}
+
+// static
+bool TRRService::CheckCaptivePortalIsPassed() {
+  bool result = false;
+  nsCOMPtr<nsICaptivePortalService> captivePortalService =
+      do_GetService(NS_CAPTIVEPORTAL_CID);
+  if (captivePortalService) {
+    int32_t captiveState;
+    MOZ_ALWAYS_SUCCEEDS(captivePortalService->GetState(&captiveState));
+
+    if ((captiveState == nsICaptivePortalService::UNLOCKED_PORTAL) ||
+        (captiveState == nsICaptivePortalService::NOT_CAPTIVE)) {
+      result = true;
+    }
+    LOG(("TRRService::Init mCaptiveState=%d mCaptiveIsPassed=%d\n",
+         captiveState, (int)result));
+  }
+
+  return result;
+}
+
 nsresult TRRService::Init() {
   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   if (mInitialized) {
     return NS_OK;
   }
   mInitialized = true;
 
-  nsCOMPtr<nsIObserverService> observerService =
-      mozilla::services::GetObserverService();
-  if (observerService) {
-    observerService->AddObserver(this, NS_CAPTIVE_PORTAL_CONNECTIVITY, true);
-    observerService->AddObserver(this, kOpenCaptivePortalLoginEvent, true);
-    observerService->AddObserver(this, kClearPrivateData, true);
-    observerService->AddObserver(this, kPurge, true);
-    observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, true);
-    observerService->AddObserver(this, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC, true);
-    observerService->AddObserver(this, "xpcom-shutdown-threads", true);
-  }
+  AddObserver(this);
+
   nsCOMPtr<nsIPrefBranch> prefBranch;
   GetPrefBranch(getter_AddRefs(prefBranch));
   if (prefBranch) {
     prefBranch->AddObserver(TRR_PREF_PREFIX, this, true);
     prefBranch->AddObserver(kDisableIpv6Pref, this, true);
     prefBranch->AddObserver(kPrefSkipTRRParentalControl, this, true);
     prefBranch->AddObserver(kRolloutURIPref, this, true);
     prefBranch->AddObserver(kRolloutModePref, this, true);
   }
-  nsCOMPtr<nsICaptivePortalService> captivePortalService =
-      do_GetService(NS_CAPTIVEPORTAL_CID);
-  if (captivePortalService) {
-    int32_t captiveState;
-    MOZ_ALWAYS_SUCCEEDS(captivePortalService->GetState(&captiveState));
-
-    if ((captiveState == nsICaptivePortalService::UNLOCKED_PORTAL) ||
-        (captiveState == nsICaptivePortalService::NOT_CAPTIVE)) {
-      mCaptiveIsPassed = true;
-    }
-    LOG(("TRRService::Init mCaptiveState=%d mCaptiveIsPassed=%d\n",
-         captiveState, (int)mCaptiveIsPassed));
-  }
-
-  GetParentalControlEnabledInternal();
 
   ReadPrefs(nullptr);
 
   gTRRService = this;
 
-  nsCOMPtr<nsINetworkLinkService> nls =
-      do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
-  RebuildSuffixList(nls);
+  if (XRE_IsParentProcess()) {
+    mCaptiveIsPassed = CheckCaptivePortalIsPassed();
+
+    mParentalControlEnabled = GetParentalControlEnabledInternal();
 
-  nsCOMPtr<nsIThread> thread;
-  if (NS_FAILED(NS_NewNamedThread("TRR Background", getter_AddRefs(thread)))) {
-    NS_WARNING("NS_NewNamedThread failed!");
-    return NS_ERROR_FAILURE;
+    nsCOMPtr<nsINetworkLinkService> nls =
+        do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
+    if (nls) {
+      nsTArray<nsCString> suffixList;
+      nls->GetDnsSuffixList(suffixList);
+      RebuildSuffixList(std::move(suffixList));
+    }
+
+    nsCOMPtr<nsIThread> thread;
+    if (NS_FAILED(
+            NS_NewNamedThread("TRR Background", getter_AddRefs(thread)))) {
+      NS_WARNING("NS_NewNamedThread failed!");
+      return NS_ERROR_FAILURE;
+    }
+
+    sTRRBackgroundThread = thread;
   }
 
-  sTRRBackgroundThread = thread;
-
   LOG(("Initialized TRRService\n"));
   return NS_OK;
 }
 
-void TRRService::GetParentalControlEnabledInternal() {
+// static
+bool TRRService::GetParentalControlEnabledInternal() {
   nsCOMPtr<nsIParentalControlsService> pc =
       do_CreateInstance("@mozilla.org/parental-controls-service;1");
   if (pc) {
-    pc->GetParentalControlsEnabled(&mParentalControlEnabled);
-    LOG(("TRRService::GetParentalControlEnabledInternal=%d\n",
-         mParentalControlEnabled));
+    bool result = false;
+    pc->GetParentalControlsEnabled(&result);
+    LOG(("TRRService::GetParentalControlEnabledInternal=%d\n", result));
+    return result;
   }
+
+  return false;
 }
 
 void TRRService::SetDetectedTrrURI(const nsACString& aURI) {
   // If the user has set a custom URI then we don't want to override that.
   if (mURIPrefHasUserValue) {
     return;
   }
 
@@ -611,19 +639,28 @@ TRRService::Observe(nsISupports* aSubjec
 
   } else if (!strcmp(aTopic, kClearPrivateData) || !strcmp(aTopic, kPurge)) {
     // flush the TRR blacklist, both in-memory and on-disk
     if (mTRRBLStorage) {
       mTRRBLStorage->Clear();
     }
   } else if (!strcmp(aTopic, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC) ||
              !strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
-    nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
-    RebuildSuffixList(link);
-    CheckPlatformDNSStatus(link);
+    // nsINetworkLinkService is only available on parent process.
+    if (XRE_IsParentProcess()) {
+      nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
+      // The network link service notification normally passes itself as the
+      // subject, but some unit tests will sometimes pass a null subject.
+      if (link) {
+        nsTArray<nsCString> suffixList;
+        link->GetDnsSuffixList(suffixList);
+        RebuildSuffixList(std::move(suffixList));
+      }
+      mPlatformDisabledTRR = CheckPlatformDNSStatus(link);
+    }
 
     if (!strcmp(aTopic, NS_NETWORK_LINK_TOPIC) && mURISetByDetection) {
       // If the URI was set via SetDetectedTrrURI we need to restore it to the
       // default pref when a network link change occurs.
       CheckURIPrefs();
     }
   } else if (!strcmp(aTopic, "xpcom-shutdown-threads")) {
     if (sTRRBackgroundThread) {
@@ -634,49 +671,40 @@ TRRService::Observe(nsISupports* aSubjec
         sTRRBackgroundThread = nullptr;
       }
       MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
     }
   }
   return NS_OK;
 }
 
-void TRRService::RebuildSuffixList(nsINetworkLinkService* aLinkService) {
-  // The network link service notification normally passes itself as the
-  // subject, but some unit tests will sometimes pass a null subject.
-  if (!aLinkService) {
-    return;
-  }
-
-  nsTArray<nsCString> suffixList;
-  aLinkService->GetDnsSuffixList(suffixList);
-
+void TRRService::RebuildSuffixList(nsTArray<nsCString>&& aSuffixList) {
   MutexAutoLock lock(mLock);
   mDNSSuffixDomains.Clear();
-  for (const auto& item : suffixList) {
+  for (const auto& item : aSuffixList) {
     LOG(("TRRService adding %s to suffix list", item.get()));
     mDNSSuffixDomains.PutEntry(item);
   }
 }
 
-void TRRService::CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService) {
+// static
+bool TRRService::CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService) {
   if (!aLinkService) {
-    return;
+    return false;
   }
 
   uint32_t platformIndications = nsINetworkLinkService::NONE_DETECTED;
   aLinkService->GetPlatformDNSIndications(&platformIndications);
   LOG(("TRRService platformIndications=%u", platformIndications));
-  mPlatformDisabledTRR =
-      (!StaticPrefs::network_trr_enable_when_vpn_detected() &&
-       (platformIndications & nsINetworkLinkService::VPN_DETECTED)) ||
-      (!StaticPrefs::network_trr_enable_when_proxy_detected() &&
-       (platformIndications & nsINetworkLinkService::PROXY_DETECTED)) ||
-      (!StaticPrefs::network_trr_enable_when_nrpt_detected() &&
-       (platformIndications & nsINetworkLinkService::NRPT_DETECTED));
+  return (!StaticPrefs::network_trr_enable_when_vpn_detected() &&
+          (platformIndications & nsINetworkLinkService::VPN_DETECTED)) ||
+         (!StaticPrefs::network_trr_enable_when_proxy_detected() &&
+          (platformIndications & nsINetworkLinkService::PROXY_DETECTED)) ||
+         (!StaticPrefs::network_trr_enable_when_nrpt_detected() &&
+          (platformIndications & nsINetworkLinkService::NRPT_DETECTED));
 }
 
 void TRRService::MaybeConfirm() {
   MutexAutoLock lock(mLock);
   MaybeConfirm_locked();
 }
 
 void TRRService::MaybeConfirm_locked() {
--- a/netwerk/dns/TRRService.h
+++ b/netwerk/dns/TRRService.h
@@ -14,16 +14,19 @@
 
 class nsDNSService;
 class nsIPrefBranch;
 class nsINetworkLinkService;
 
 namespace mozilla {
 namespace net {
 
+class TRRServiceChild;
+class TRRServiceParent;
+
 class TRRService : public nsIObserver,
                    public nsITimerCallback,
                    public nsSupportsWeakReference,
                    public AHostResolver {
  public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
@@ -68,31 +71,37 @@ class TRRService : public nsIObserver,
   bool ParentalControlEnabled() const { return mParentalControlEnabled; }
 
   nsresult DispatchTRRRequest(TRR* aTrrRequest);
   already_AddRefed<nsIThread> TRRThread();
   bool IsOnTRRThread();
 
  private:
   virtual ~TRRService();
+
+  friend class TRRServiceChild;
+  friend class TRRServiceParent;
+  static void AddObserver(nsIObserver* aObserver);
+  static bool CheckCaptivePortalIsPassed();
+  static bool GetParentalControlEnabledInternal();
+  static bool CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService);
+
   nsresult ReadPrefs(const char* name);
   void GetPrefBranch(nsIPrefBranch** result);
   void MaybeConfirm();
   void MaybeConfirm_locked();
   friend class ::nsDNSService;
-  void GetParentalControlEnabledInternal();
   void SetDetectedTrrURI(const nsACString& aURI);
 
   bool IsDomainBlacklisted(const nsACString& aHost,
                            const nsACString& aOriginSuffix,
                            bool aPrivateBrowsing);
   bool IsExcludedFromTRR_unlocked(const nsACString& aHost);
 
-  void RebuildSuffixList(nsINetworkLinkService* aLinkService);
-  void CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService);
+  void RebuildSuffixList(nsTArray<nsCString>&& aSuffixList);
 
   nsresult DispatchTRRRequestInternal(TRR* aTrrRequest, bool aWithLock);
   already_AddRefed<nsIThread> TRRThread_locked();
 
   // This method will process the URI and try to set mPrivateURI to that value.
   // Will return true if performed the change (if the value was different)
   // or false if mPrivateURI already had that value.
   bool MaybeSetPrivateURI(const nsACString& aURI);
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/TRRServiceChild.cpp
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/net/TRRServiceChild.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/DataStorage.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIDNService.h"
+#include "nsIObserverService.h"
+#include "TRRService.h"
+
+namespace mozilla {
+namespace net {
+
+static StaticRefPtr<nsIDNSService> sDNSService;
+
+void TRRServiceChild::Init(const bool& aCaptiveIsPassed,
+                           const bool& aParentalControlEnabled,
+                           nsTArray<nsCString>&& aDNSSuffixList) {
+  nsCOMPtr<nsIDNSService> dns =
+      do_GetService("@mozilla.org/network/dns-service;1");
+  sDNSService = dns;
+  ClearOnShutdown(&sDNSService);
+  MOZ_ASSERT(sDNSService);
+  MOZ_ASSERT(gTRRService);
+
+  gTRRService->mCaptiveIsPassed = aCaptiveIsPassed;
+  gTRRService->mParentalControlEnabled = aParentalControlEnabled;
+  gTRRService->RebuildSuffixList(std::move(aDNSSuffixList));
+}
+
+mozilla::ipc::IPCResult TRRServiceChild::RecvNotifyObserver(
+    const nsCString& aTopic, const nsString& aData) {
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr, aTopic.get(), aData.get());
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TRRServiceChild::RecvUpdatePlatformDNSInformation(
+    nsTArray<nsCString>&& aDNSSuffixList, const bool& aPlatformDisabledTRR) {
+  gTRRService->RebuildSuffixList(std::move(aDNSSuffixList));
+  gTRRService->mPlatformDisabledTRR = aPlatformDisabledTRR;
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult TRRServiceChild::RecvInitTRRBLStorage(
+    const psm::DataStorageEntry& aEntry, const FileDescriptor& aWriteFd) {
+  RefPtr<DataStorage> storage =
+      DataStorage::Get(DataStorageClass::TRRBlacklist);
+  if (storage) {
+    storage->Init(&aEntry.items(), aWriteFd);
+  }
+  return IPC_OK();
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/TRRServiceChild.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_net_TRRServiceChild_h
+#define mozilla_net_TRRServiceChild_h
+
+#include "mozilla/net/PTRRServiceChild.h"
+
+namespace mozilla {
+
+namespace ipc {
+class FileDescriptor;
+}  // namespace ipc
+
+namespace net {
+
+class TRRServiceChild : public PTRRServiceChild {
+ public:
+  NS_INLINE_DECL_REFCOUNTING(TRRServiceChild, override)
+
+  explicit TRRServiceChild() = default;
+
+  void Init(const bool& aCaptiveIsPassed, const bool& aParentalControlEnabled,
+            nsTArray<nsCString>&& aDNSSuffixList);
+  mozilla::ipc::IPCResult RecvNotifyObserver(const nsCString& aTopic,
+                                             const nsString& aData);
+  mozilla::ipc::IPCResult RecvUpdatePlatformDNSInformation(
+      nsTArray<nsCString>&& aDNSSuffixList, const bool& aPlatformDisabledTRR);
+  mozilla::ipc::IPCResult RecvInitTRRBLStorage(
+      const psm::DataStorageEntry& aEntry, const FileDescriptor& aWriteFd);
+
+ private:
+  virtual ~TRRServiceChild() = default;
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif  // mozilla_net_TRRServiceChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/TRRServiceParent.cpp
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/net/TRRServiceParent.h"
+
+#include "mozilla/ipc/FileDescriptor.h"
+#include "mozilla/net/SocketProcessParent.h"
+#include "mozilla/psm/PSMIPCTypes.h"
+#include "mozilla/Unused.h"
+#include "nsICaptivePortalService.h"
+#include "nsIParentalControlsService.h"
+#include "nsINetworkLinkService.h"
+#include "nsIObserverService.h"
+#include "nsIOService.h"
+#include "TRRService.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS(TRRServiceParent, nsIObserver, nsISupportsWeakReference)
+
+void TRRServiceParent::Init() {
+  MOZ_ASSERT(gIOService);
+
+  if (!gIOService->SocketProcessReady()) {
+    RefPtr<TRRServiceParent> self = this;
+    gIOService->CallOrWaitForSocketProcess([self]() { self->Init(); });
+    return;
+  }
+
+  SocketProcessParent* socketParent = SocketProcessParent::GetSingleton();
+  if (!socketParent) {
+    return;
+  }
+
+  TRRService::AddObserver(this);
+  bool captiveIsPassed = TRRService::CheckCaptivePortalIsPassed();
+  bool parentalControlEnabled = TRRService::GetParentalControlEnabledInternal();
+
+  nsCOMPtr<nsINetworkLinkService> nls =
+      do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID);
+  nsTArray<nsCString> suffixList;
+  if (nls) {
+    nls->GetDnsSuffixList(suffixList);
+  }
+
+  Unused << socketParent->SendPTRRServiceConstructor(
+      this, captiveIsPassed, parentalControlEnabled, suffixList);
+}
+
+NS_IMETHODIMP
+TRRServiceParent::Observe(nsISupports* aSubject, const char* aTopic,
+                          const char16_t* aData) {
+  if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
+    Unused << SendNotifyObserver(
+        nsDependentCString(aTopic),
+        aData ? nsDependentString(aData) : VoidString());
+  } else if (!strcmp(aTopic, NS_CAPTIVE_PORTAL_CONNECTIVITY)) {
+    if (!mTRRBLStorageInited) {
+      RefPtr<DataStorage> storage =
+          DataStorage::Get(DataStorageClass::TRRBlacklist);
+      if (storage) {
+        nsresult rv = storage->Init(nullptr);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          Unused << SendNotifyObserver(
+              nsDependentCString(aTopic),
+              aData ? nsDependentString(aData) : VoidString());
+          return NS_OK;
+        }
+
+        psm::DataStorageEntry entry;
+        storage->GetAll(&entry.items());
+
+        RefPtr<TRRServiceParent> self = this;
+        nsCString topic(aTopic);
+        nsString data(aData);
+        rv = storage->AsyncTakeFileDesc(
+            [self, entry, topic, data](ipc::FileDescriptor&& aWriteFd) {
+              // We need to send this message before
+              // NS_CAPTIVE_PORTAL_CONNECTIVITY notification to make sure
+              // TRRBLStorage got inited properly.
+              Unused << self->SendInitTRRBLStorage(entry, aWriteFd);
+              Unused << self->SendNotifyObserver(topic, data);
+              self->mTRRBLStorageInited = true;
+            });
+
+        if (NS_SUCCEEDED(rv)) {
+          return NS_OK;
+        }
+      }
+    }
+
+    Unused << SendNotifyObserver(
+        nsDependentCString(aTopic),
+        aData ? nsDependentString(aData) : VoidString());
+  } else if (!strcmp(aTopic, kClearPrivateData) || !strcmp(aTopic, kPurge)) {
+    Unused << SendNotifyObserver(
+        nsDependentCString(aTopic),
+        aData ? nsDependentString(aData) : VoidString());
+  } else if (!strcmp(aTopic, NS_DNS_SUFFIX_LIST_UPDATED_TOPIC) ||
+             !strcmp(aTopic, NS_NETWORK_LINK_TOPIC)) {
+    nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
+    // The network link service notification normally passes itself as the
+    // subject, but some unit tests will sometimes pass a null subject.
+    if (link) {
+      nsTArray<nsCString> suffixList;
+      link->GetDnsSuffixList(suffixList);
+      bool platformDisabledTRR = TRRService::CheckPlatformDNSStatus(link);
+      Unused << SendUpdatePlatformDNSInformation(suffixList,
+                                                 platformDisabledTRR);
+    }
+  }
+
+  return NS_OK;
+}
+
+}  // namespace net
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/TRRServiceParent.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_net_TRRServiceParent_h
+#define mozilla_net_TRRServiceParent_h
+
+#include "mozilla/DataStorage.h"
+#include "mozilla/net/PTRRServiceParent.h"
+#include "nsIObserver.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+namespace net {
+
+class TRRServiceParent : public nsIObserver,
+                         public nsSupportsWeakReference,
+                         public PTRRServiceParent {
+ public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  explicit TRRServiceParent() : mTRRBLStorageInited(false) {}
+  void Init();
+
+ private:
+  virtual ~TRRServiceParent() = default;
+
+  bool mTRRBLStorageInited;
+};
+
+}  // namespace net
+}  // namespace mozilla
+
+#endif  // mozilla_net_TRRServiceParent_h
--- a/netwerk/dns/moz.build
+++ b/netwerk/dns/moz.build
@@ -41,16 +41,18 @@ EXPORTS.mozilla.net += [
     'DNSByTypeRecord.h',
     'DNSListenerProxy.h',
     'DNSRequestBase.h',
     'DNSRequestChild.h',
     'DNSRequestParent.h',
     'HTTPSSVC.h',
     'IDNBlocklistUtils.h',
     'TRRService.h',
+    'TRRServiceChild.h',
+    'TRRServiceParent.h',
 ]
 
 SOURCES += [
     'nsEffectiveTLDService.cpp', # Excluded from UNIFIED_SOURCES due to special build flags.
     'nsHostResolver.cpp', # Redefines LOG
 ]
 
 UNIFIED_SOURCES += [
@@ -62,21 +64,24 @@ UNIFIED_SOURCES += [
     'GetAddrInfo.cpp',
     'HTTPSSVC.cpp',
     'IDNBlocklistUtils.cpp',
     'nsDNSService2.cpp',
     'nsIDNService.cpp',
     'punycode.c',
     'TRR.cpp',
     'TRRService.cpp',
+    'TRRServiceChild.cpp',
+    'TRRServiceParent.cpp',
 ]
 
 IPDL_SOURCES = [
     'PDNSRequest.ipdl',
     'PDNSRequestParams.ipdlh',
+    'PTRRService.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 GeneratedFile('etld_data.inc', script='prepare_tlds.py',
               inputs=['effective_tld_names.dat'])
--- a/netwerk/ipc/PSocketProcess.ipdl
+++ b/netwerk/ipc/PSocketProcess.ipdl
@@ -11,16 +11,17 @@ include protocol PHttpTransaction;
 include protocol PHttpConnectionMgr;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PInputChannelThrottleQueue;
 include protocol PBackground;
 include protocol PAltService;
 include protocol PAltSvcTransaction;
+include protocol PTRRService;
 
 include MemoryReportTypes;
 include NeckoChannelParams;
 include PrefsTypes;
 include PSMIPCTypes;
 
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
@@ -44,16 +45,17 @@ sync protocol PSocketProcess
   manages PFileDescriptorSet;
   manages PHttpTransaction;
   manages PHttpConnectionMgr;
   manages PChildToParentStream;
   manages PParentToChildStream;
   manages PInputChannelThrottleQueue;
   manages PAltService;
   manages PAltSvcTransaction;
+  manages PTRRService;
 
 parent:
   async InitCrashReporter(NativeThreadId threadId);
   async AddMemoryReport(MemoryReport aReport);
   async FinishMemoryReport(uint32_t aGeneration);
   // Messages for sending telemetry to parent process.
   async AccumulateChildHistograms(HistogramAccumulation[] accumulations);
   async AccumulateChildKeyedHistograms(KeyedHistogramAccumulation[] accumulations);
@@ -101,16 +103,19 @@ child:
   async PHttpConnectionMgr();
 
   async OnHttpActivityDistributorActivated(bool aIsActivated);
   async PInputChannelThrottleQueue(uint32_t meanBytesPerSecond,
                                    uint32_t maxBytesPerSecond);
   async PAltSvcTransaction(HttpConnectionInfoCloneArgs aConnInfo,
                            uint32_t aCaps);
   async ClearSessionCache();
+  async PTRRService(bool aCaptiveIsPassed,
+                    bool aParentalControlEnabled,
+                    nsCString[] aDNSSuffixList);
 
 both:
   async PFileDescriptorSet(FileDescriptor fd);
   async PDNSRequest(nsCString hostName, nsCString trrServer, uint16_t type,
                     OriginAttributes originAttributes, uint32_t flags);
 };
 
 } // namespace net
--- a/netwerk/ipc/SocketProcessChild.cpp
+++ b/netwerk/ipc/SocketProcessChild.cpp
@@ -17,16 +17,17 @@
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/IPCStreamAlloc.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/net/AltSvcTransactionChild.h"
 #include "mozilla/net/BackgroundDataBridgeParent.h"
 #include "mozilla/net/DNSRequestChild.h"
 #include "mozilla/net/DNSRequestParent.h"
+#include "mozilla/net/TRRServiceChild.h"
 #include "mozilla/ipc/PChildToParentStreamChild.h"
 #include "mozilla/ipc/PParentToChildStreamChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "nsDebugImpl.h"
 #include "nsHttpConnectionInfo.h"
 #include "nsHttpHandler.h"
 #include "nsIDNSService.h"
@@ -406,10 +407,25 @@ SocketProcessChild::GetAndRemoveDataBrid
 
 mozilla::ipc::IPCResult SocketProcessChild::RecvClearSessionCache() {
   if (EnsureNSSInitializedChromeOrContent()) {
     nsNSSComponent::DoClearSSLExternalAndInternalSessionCache();
   }
   return IPC_OK();
 }
 
+already_AddRefed<PTRRServiceChild> SocketProcessChild::AllocPTRRServiceChild(
+    const bool& aCaptiveIsPassed, const bool& aParentalControlEnabled,
+    const nsTArray<nsCString>& aDNSSuffixList) {
+  RefPtr<TRRServiceChild> actor = new TRRServiceChild();
+  return actor.forget();
+}
+
+mozilla::ipc::IPCResult SocketProcessChild::RecvPTRRServiceConstructor(
+    PTRRServiceChild* aActor, const bool& aCaptiveIsPassed,
+    const bool& aParentalControlEnabled, nsTArray<nsCString>&& aDNSSuffixList) {
+  static_cast<TRRServiceChild*>(aActor)->Init(
+      aCaptiveIsPassed, aParentalControlEnabled, std::move(aDNSSuffixList));
+  return IPC_OK();
+}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/ipc/SocketProcessChild.h
+++ b/netwerk/ipc/SocketProcessChild.h
@@ -101,16 +101,24 @@ class SocketProcessChild final
   void AddDataBridgeToMap(uint64_t aChannelId,
                           BackgroundDataBridgeParent* aActor);
   void RemoveDataBridgeFromMap(uint64_t aChannelId);
   Maybe<RefPtr<BackgroundDataBridgeParent>> GetAndRemoveDataBridge(
       uint64_t aChannelId);
 
   mozilla::ipc::IPCResult RecvClearSessionCache();
 
+  already_AddRefed<PTRRServiceChild> AllocPTRRServiceChild(
+      const bool& aCaptiveIsPassed, const bool& aParentalControlEnabled,
+      const nsTArray<nsCString>& aDNSSuffixList);
+  mozilla::ipc::IPCResult RecvPTRRServiceConstructor(
+      PTRRServiceChild* aActor, const bool& aCaptiveIsPassed,
+      const bool& aParentalControlEnabled,
+      nsTArray<nsCString>&& aDNSSuffixList) override;
+
  protected:
   friend class SocketProcessImpl;
   ~SocketProcessChild();
 
  private:
   // Mapping of content process id and the SocketProcessBridgeParent.
   // This table keeps SocketProcessBridgeParent alive in socket process.
   nsRefPtrHashtable<nsUint32HashKey, SocketProcessBridgeParent>