Bug 1641600 - Check RTX blocklist pref in PeerConnectionImpl; r=bwc
authorDan Minor <dminor@mozilla.com>
Thu, 04 Jun 2020 14:42:15 +0000
changeset 534202 173f863893da0aabe541380aa6184d2a881047aa
parent 534201 b6cc21d51827dce745d756214173e13354b8a5e1
child 534203 edcc03ec3ea042fc756169b1858640ff3bafc006
push id37484
push userdluca@mozilla.com
push dateSat, 06 Jun 2020 09:46:03 +0000
treeherdermozilla-central@6237102f005d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbwc
bugs1641600
milestone79.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 1641600 - Check RTX blocklist pref in PeerConnectionImpl; r=bwc Differential Revision: https://phabricator.services.mozilla.com/D77814
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -14,16 +14,17 @@
 #include "timecard.h"
 
 #include "jsapi.h"
 #include "nspr.h"
 #include "nss.h"
 #include "pk11pub.h"
 
 #include "nsNetCID.h"
+#include "nsIIDNService.h"
 #include "nsILoadContext.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsProxyRelease.h"
 #include "prtime.h"
 
@@ -316,16 +317,20 @@ PeerConnectionImpl::PeerConnectionImpl(c
   MOZ_ASSERT(NS_IsMainThread());
   if (aGlobal) {
     mWindow = do_QueryInterface(aGlobal->GetAsSupports());
     if (IsPrivateBrowsing(mWindow)) {
       mPrivateWindow = true;
     }
     mWindow->AddPeerConnection();
     mActiveOnWindow = true;
+
+    mRtxIsAllowed =
+        !HostnameInPref("media.peerconnection.video.use_rtx.blocklist",
+                        mWindow->GetDocumentURI());
   }
   CSFLogInfo(LOGTAG, "%s: PeerConnectionImpl constructor for %s", __FUNCTION__,
              mHandle.c_str());
   STAMP_TIMECARD(mTimeCard, "Constructor Completed");
   mForceIceTcp =
       Preferences::GetBool("media.peerconnection.ice.force_ice_tcp", false);
   memset(mMaxReceiving, 0, sizeof(mMaxReceiving));
   memset(mMaxSending, 0, sizeof(mMaxSending));
@@ -463,16 +468,17 @@ nsresult PeerConnectionImpl::Initialize(
                                         aConfiguration.mIceTransportPolicy);
   if (NS_FAILED(res)) {
     CSFLogError(LOGTAG, "%s: Failed to init mtransport", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   mJsepSession =
       MakeUnique<JsepSessionImpl>(mName, MakeUnique<PCUuidGenerator>());
+  mJsepSession->SetRtxIsAllowed(mRtxIsAllowed);
 
   res = mJsepSession->Init();
   if (NS_FAILED(res)) {
     CSFLogError(LOGTAG, "%s: Couldn't init JSEP Session, res=%u", __FUNCTION__,
                 static_cast<unsigned>(res));
     return res;
   }
 
@@ -1021,16 +1027,18 @@ already_AddRefed<TransceiverImpl> PeerCo
 
   if (jrv.Failed()) {
     // Would be nice if we could peek at the rv without stealing it, so we
     // could log...
     CSFLogError(LOGTAG, "%s: failed", __FUNCTION__);
     return nullptr;
   }
 
+  jsepTransceiver->SetRtxIsAllowed(mRtxIsAllowed);
+
   // Do this last, since it is not possible to roll back.
   nsresult rv = AddRtpTransceiverToJsepSession(jsepTransceiver);
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "%s: AddRtpTransceiverToJsepSession failed, res=%u",
                 __FUNCTION__, static_cast<unsigned>(rv));
     jrv = rv;
     return nullptr;
   }
@@ -1693,16 +1701,83 @@ void PeerConnectionImpl::DumpPacket_m(si
   if (!arrayBuffer.Init(jsobj)) {
     return;
   }
 
   JSErrorResult jrv;
   mPCObserver->OnPacket(level, type, sending, arrayBuffer, jrv);
 }
 
+bool PeerConnectionImpl::HostnameInPref(const char* aPref, nsIURI* aDocURI) {
+  auto HostInDomain = [](const nsCString& aHost, const nsCString& aPattern) {
+    int32_t patternOffset = 0;
+    int32_t hostOffset = 0;
+
+    // Act on '*.' wildcard in the left-most position in a domain pattern.
+    if (StringBeginsWith(aPattern, nsCString("*."))) {
+      patternOffset = 2;
+
+      // Ignore the lowest level sub-domain for the hostname.
+      hostOffset = aHost.FindChar('.') + 1;
+
+      if (hostOffset <= 1) {
+        // Reject a match between a wildcard and a TLD or '.foo' form.
+        return false;
+      }
+    }
+
+    nsDependentCString hostRoot(aHost, hostOffset);
+    return hostRoot.EqualsIgnoreCase(aPattern.BeginReading() + patternOffset);
+  };
+
+  if (!aDocURI) {
+    return false;
+  }
+
+  nsCString hostName;
+  aDocURI->GetAsciiHost(hostName);  // normalize UTF8 to ASCII equivalent
+  nsCString domainList;
+  nsresult nr = Preferences::GetCString(aPref, domainList);
+
+  if (NS_FAILED(nr)) {
+    return false;
+  }
+
+  domainList.StripWhitespace();
+
+  if (domainList.IsEmpty() || hostName.IsEmpty()) {
+    return false;
+  }
+
+  // Get UTF8 to ASCII domain name normalization service
+  nsresult rv;
+  nsCOMPtr<nsIIDNService> idnService =
+      do_GetService("@mozilla.org/network/idn-service;1", &rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  // Test each domain name in the comma separated list
+  // after converting from UTF8 to ASCII. Each domain
+  // must match exactly or have a single leading '*.' wildcard.
+  for (const nsACString& each : domainList.Split(',')) {
+    nsCString domainName;
+    rv = idnService->ConvertUTF8toACE(each, domainName);
+    if (NS_SUCCEEDED(rv)) {
+      if (HostInDomain(hostName, domainName)) {
+        return true;
+      }
+    } else {
+      NS_WARNING("Failed to convert UTF-8 host to ASCII");
+    }
+  }
+
+  return false;
+}
+
 nsresult PeerConnectionImpl::EnablePacketDump(unsigned long level,
                                               dom::mozPacketDumpType type,
                                               bool sending) {
   mPacketDumpEnabled = true;
   std::vector<unsigned>* packetDumpFlags;
   if (sending) {
     packetDumpFlags = &mSendPacketDumpFlags;
   } else {
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -436,16 +436,21 @@ class PeerConnectionImpl final
 
   void DumpPacket_m(size_t level, dom::mozPacketDumpType type, bool sending,
                     UniquePtr<uint8_t[]>& packet, size_t size);
 
   const dom::RTCStatsTimestampMaker& GetTimestampMaker() const {
     return mTimestampMaker;
   }
 
+  // Utility function, given a string pref and an URI, returns whether or not
+  // the URI occurs in the pref. Wildcards are supported (e.g. *.example.com)
+  // and multiple hostnames can be present, separated by commas.
+  static bool HostnameInPref(const char* aPrefList, nsIURI* aDocURI);
+
  private:
   virtual ~PeerConnectionImpl();
   PeerConnectionImpl(const PeerConnectionImpl& rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
 
   RefPtr<dom::RTCStatsPromise> GetReceiverStats(
       const RefPtr<MediaPipelineReceive>& aPipeline);
   RefPtr<dom::RTCStatsPromise> GetSenderStats(
@@ -604,16 +609,19 @@ class PeerConnectionImpl final
   RefPtr<RTCStatsIdGenerator> mIdGenerator;
   // Ordinarily, I would use a std::map here, but this used to be a JS Map
   // which iterates in insertion order, and I want to avoid changing this.
   nsTArray<RefPtr<DOMMediaStream>> mReceiveStreams;
 
   DOMMediaStream* GetReceiveStream(const std::string& aId) const;
   DOMMediaStream* CreateReceiveStream(const std::string& aId);
 
+  // See Bug 1642419, this can be removed when all sites are working with RTX.
+  bool mRtxIsAllowed = true;
+
  public:
   // these are temporary until the DataChannel Listen/Connect API is removed
   unsigned short listenPort;
   unsigned short connectPort;
   char* connectStr;  // XXX ownership/free
 };
 
 // This is what is returned when you acquire on a handle
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -323,109 +323,28 @@ bool PeerConnectionMedia::GetPrefDefault
 
   bool default_address_only = Preferences::GetBool(
       "media.peerconnection.ice.default_address_only", false);
   default_address_only |=
       !MediaManager::Get()->IsActivelyCapturingOrHasAPermission(winId);
   return default_address_only;
 }
 
-static bool HostInDomain(const nsCString& aHost, const nsCString& aPattern) {
-  int32_t patternOffset = 0;
-  int32_t hostOffset = 0;
-
-  // Act on '*.' wildcard in the left-most position in a domain pattern.
-  if (aPattern.Length() > 2 && aPattern[0] == '*' && aPattern[1] == '.') {
-    patternOffset = 2;
-
-    // Ignore the lowest level sub-domain for the hostname.
-    hostOffset = aHost.FindChar('.') + 1;
-
-    if (hostOffset <= 1) {
-      // Reject a match between a wildcard and a TLD or '.foo' form.
-      return false;
-    }
-  }
-
-  nsDependentCString hostRoot(aHost, hostOffset);
-  return hostRoot.EqualsIgnoreCase(aPattern.BeginReading() + patternOffset);
-}
-
-static bool HostInObfuscationWhitelist(nsIURI* docURI) {
-  if (!docURI) {
-    return false;
-  }
-
-  nsCString hostName;
-  docURI->GetAsciiHost(hostName);  // normalize UTF8 to ASCII equivalent
-  nsCString domainWhiteList;
-  nsresult nr = Preferences::GetCString(
-      "media.peerconnection.ice.obfuscate_host_addresses.whitelist",
-      domainWhiteList);
-
-  if (NS_FAILED(nr)) {
-    return false;
-  }
-
-  domainWhiteList.StripWhitespace();
-
-  if (domainWhiteList.IsEmpty() || hostName.IsEmpty()) {
-    return false;
-  }
-
-  // Get UTF8 to ASCII domain name normalization service
-  nsresult rv;
-  nsCOMPtr<nsIIDNService> idnService =
-      do_GetService("@mozilla.org/network/idn-service;1", &rv);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  uint32_t begin = 0;
-  uint32_t end = 0;
-  nsCString domainName;
-  /*
-     Test each domain name in the comma separated list
-     after converting from UTF8 to ASCII. Each domain
-     must match exactly or have a single leading '*.' wildcard
-  */
-  do {
-    end = domainWhiteList.FindChar(',', begin);
-    if (end == (uint32_t)-1) {
-      // Last or only domain name in the comma separated list
-      end = domainWhiteList.Length();
-    }
-
-    rv = idnService->ConvertUTF8toACE(
-        Substring(domainWhiteList, begin, end - begin), domainName);
-    if (NS_SUCCEEDED(rv)) {
-      if (HostInDomain(hostName, domainName)) {
-        return true;
-      }
-    } else {
-      NS_WARNING("Failed to convert UTF-8 host to ASCII");
-    }
-
-    begin = end + 1;
-  } while (end < domainWhiteList.Length());
-
-  return false;
-}
-
 bool PeerConnectionMedia::GetPrefObfuscateHostAddresses() const {
   ASSERT_ON_THREAD(mMainThread);  // will crash on STS thread
 
   uint64_t winId = mParent->GetWindow()->WindowID();
 
   bool obfuscate_host_addresses = Preferences::GetBool(
       "media.peerconnection.ice.obfuscate_host_addresses", false);
   obfuscate_host_addresses &=
       !MediaManager::Get()->IsActivelyCapturingOrHasAPermission(winId);
-  obfuscate_host_addresses &=
-      !HostInObfuscationWhitelist(mParent->GetWindow()->GetDocumentURI());
+  obfuscate_host_addresses &= !PeerConnectionImpl::HostnameInPref(
+      "media.peerconnection.ice.obfuscate_host_addresses.whitelist",
+      mParent->GetWindow()->GetDocumentURI());
   obfuscate_host_addresses &= XRE_IsContentProcess();
 
   return obfuscate_host_addresses;
 }
 
 void PeerConnectionMedia::ConnectSignals() {
   mTransportHandler->SignalGatheringStateChange.connect(
       this, &PeerConnectionMedia::IceGatheringStateChange_s);