Bug 870660: Part 1: Add packat filter to UDPSocketParent/Child. r=jduell
authorPatrick Wang <kk1fff@patrickz.net>
Sat, 30 Nov 2013 00:13:44 +0800
changeset 158234 3f2e8b809678e566f9024191e871467012410258
parent 158233 7fc2faac8321831bdb53e6155e37607461781262
child 158235 c039384c1dfa12d243642a5ffa2cf1c5186311c0
push id25739
push usercbook@mozilla.com
push dateMon, 02 Dec 2013 11:47:10 +0000
treeherdermozilla-central@2581b84e0ca1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs870660
milestone28.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 870660: Part 1: Add packat filter to UDPSocketParent/Child. r=jduell
dom/network/interfaces/nsIUDPSocketChild.idl
dom/network/src/UDPSocketChild.cpp
dom/network/src/UDPSocketChild.h
dom/network/src/UDPSocketParent.cpp
dom/network/src/UDPSocketParent.h
netwerk/base/public/moz.build
netwerk/base/public/nsIUDPSocketFilter.idl
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
--- a/dom/network/interfaces/nsIUDPSocketChild.idl
+++ b/dom/network/interfaces/nsIUDPSocketChild.idl
@@ -17,16 +17,18 @@ union NetAddr;
 native NetAddr(mozilla::net::NetAddr);
 [ptr] native NetAddrPtr(mozilla::net::NetAddr);
 
 [scriptable, uuid(B47E5A0F-D384-48EF-8885-4259793D9CF0)]
 interface nsIUDPSocketChild : nsISupports
 {
   readonly attribute unsigned short localPort;
   readonly attribute AUTF8String localAddress;
+  attribute AUTF8String filterName;
+
   // Tell the chrome process to bind the UDP socket to a given local host and port
   void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port);
 
   // Tell the chrome process to perform equivalent operations to all following methods
   void send(in AUTF8String host, in unsigned short port,
             [const, array, size_is(byteLength)] in uint8_t bytes,
             in unsigned long byteLength);
   // Send without DNS query
--- a/dom/network/src/UDPSocketChild.cpp
+++ b/dom/network/src/UDPSocketChild.cpp
@@ -62,17 +62,17 @@ UDPSocketChild::Bind(nsIUDPSocketInterna
                      const nsACString& aHost,
                      uint16_t aPort)
 {
   NS_ENSURE_ARG(aSocket);
 
   mSocket = aSocket;
   AddIPDLReference();
 
-  gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort);
+  gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort, mFilterName);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 UDPSocketChild::Close()
 {
   SendClose();
@@ -144,16 +144,34 @@ UDPSocketChild::GetLocalPort(uint16_t *a
 
 NS_IMETHODIMP
 UDPSocketChild::GetLocalAddress(nsACString &aLocalAddress)
 {
   aLocalAddress = mLocalAddress;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+UDPSocketChild::SetFilterName(const nsACString &aFilterName)
+{
+  if (!mFilterName.IsEmpty()) {
+    // filter name can only be set once.
+    return NS_ERROR_FAILURE;
+  }
+  mFilterName = aFilterName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UDPSocketChild::GetFilterName(nsACString &aFilterName)
+{
+  aFilterName = mFilterName;
+  return NS_OK;
+}
+
 // PUDPSocketChild Methods
 bool
 UDPSocketChild::RecvCallback(const nsCString &aType,
                              const UDPCallbackData &aData,
                              const nsCString &aState)
 {
   if (NS_FAILED(mSocket->UpdateReadyState(aState)))
     NS_ERROR("Shouldn't fail!");
--- a/dom/network/src/UDPSocketChild.h
+++ b/dom/network/src/UDPSocketChild.h
@@ -41,14 +41,15 @@ public:
   virtual ~UDPSocketChild();
 
   virtual bool RecvCallback(const nsCString& aType,
                             const UDPCallbackData& aData,
                             const nsCString& aState) MOZ_OVERRIDE;
 private:
   uint16_t mLocalPort;
   nsCString mLocalAddress;
+  nsCString mFilterName;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // !defined(mozilla_dom_UDPSocketChild_h__)
--- a/dom/network/src/UDPSocketParent.cpp
+++ b/dom/network/src/UDPSocketParent.cpp
@@ -1,12 +1,15 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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 "nsIServiceManager.h"
 #include "UDPSocketParent.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIUDPSocket.h"
 #include "nsINetAddr.h"
 #include "mozilla/unused.h"
 #include "mozilla/net/DNS.h"
 
 namespace mozilla {
@@ -60,16 +63,17 @@ UDPSocketParent::~UDPSocketParent()
 }
 
 // PUDPSocketParent methods
 
 bool
 UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort)
 {
   nsresult rv;
+  NS_ASSERTION(mFilter, "No packet filter");
 
   nsCOMPtr<nsIUDPSocket> sock =
       do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
   if (NS_FAILED(rv)) {
     FireInternalError(this, __LINE__);
     return true;
   }
 
@@ -119,37 +123,56 @@ UDPSocketParent::Init(const nsCString &a
 }
 
 bool
 UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData,
                           const nsCString& aRemoteAddress,
                           const uint16_t& aPort)
 {
   NS_ENSURE_TRUE(mSocket, true);
+  NS_ASSERTION(mFilter, "No packet filter");
+  // TODO, Bug 933102, filter packets that are sent with hostname.
+  // Until then we simply throw away packets that are sent to a hostname.
+  return true;
+
+#if 0
+  // Enable this once we have filtering working with hostname delivery.
   uint32_t count;
   nsresult rv = mSocket->Send(aRemoteAddress,
                               aPort, aData.Elements(),
                               aData.Length(), &count);
   mozilla::unused <<
       PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
                                      UDPSendResult(rv),
                                      NS_LITERAL_CSTRING("connected"));
   NS_ENSURE_SUCCESS(rv, true);
   NS_ENSURE_TRUE(count > 0, true);
   return true;
+#endif
 }
 
 bool
 UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData,
                                      const mozilla::net::NetAddr& aAddr)
 {
   NS_ENSURE_TRUE(mSocket, true);
+  NS_ASSERTION(mFilter, "No packet filter");
+
   uint32_t count;
-  nsresult rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
-                                         aData.Length(), &count);
+  nsresult rv;
+  bool allowed;
+  rv = mFilter->FilterPacket(&aAddr, aData.Elements(),
+                             aData.Length(), nsIUDPSocketFilter::SF_OUTGOING,
+                             &allowed);
+  // Sending unallowed data, kill content.
+  NS_ENSURE_SUCCESS(rv, false);
+  NS_ENSURE_TRUE(allowed, false);
+
+  rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
+                                aData.Length(), &count);
   mozilla::unused <<
       PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
                                      UDPSendResult(rv),
                                      NS_LITERAL_CSTRING("connected"));
   NS_ENSURE_SUCCESS(rv, true);
   NS_ENSURE_TRUE(count > 0, true);
   return true;
 }
@@ -186,30 +209,42 @@ UDPSocketParent::ActorDestroy(ActorDestr
 
 NS_IMETHODIMP
 UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
 {
   // receiving packet from remote host, forward the message content to child process
   if (!mIPCOpen) {
     return NS_OK;
   }
+  NS_ASSERTION(mFilter, "No packet filter");
 
   uint16_t port;
   nsCString ip;
   nsCOMPtr<nsINetAddr> fromAddr;
   aMessage->GetFromAddr(getter_AddRefs(fromAddr));
   fromAddr->GetPort(&port);
   fromAddr->GetAddress(ip);
 
   nsCString data;
   aMessage->GetData(data);
 
   const char* buffer = data.get();
   uint32_t len = data.Length();
 
+  bool allowed;
+  mozilla::net::NetAddr addr;
+  fromAddr->GetNetAddr(&addr);
+  nsresult rv = mFilter->FilterPacket(&addr,
+                                      (const uint8_t*)buffer, len,
+                                      nsIUDPSocketFilter::SF_INCOMING,
+                                      &allowed);
+  // Receiving unallowed data, drop.
+  NS_ENSURE_SUCCESS(rv, NS_OK);
+  NS_ENSURE_TRUE(allowed, NS_OK);
+
   FallibleTArray<uint8_t> fallibleArray;
   if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
     FireInternalError(this, __LINE__);
     return NS_ERROR_OUT_OF_MEMORY;
   }
   InfallibleTArray<uint8_t> infallibleArray;
   infallibleArray.SwapElements(fallibleArray);
 
--- a/dom/network/src/UDPSocketParent.h
+++ b/dom/network/src/UDPSocketParent.h
@@ -1,30 +1,36 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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_dom_UDPSocketParent_h__
 #define mozilla_dom_UDPSocketParent_h__
 
 #include "mozilla/net/PUDPSocketParent.h"
 #include "nsCOMPtr.h"
 #include "nsIUDPSocket.h"
+#include "nsIUDPSocketFilter.h"
 
 namespace mozilla {
 namespace dom {
 
 class UDPSocketParent : public mozilla::net::PUDPSocketParent
                       , public nsIUDPSocketListener
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIUDPSOCKETLISTENER
 
-  UDPSocketParent() : mIPCOpen(true) {}
+  UDPSocketParent(nsIUDPSocketFilter* filter) :
+    mIPCOpen(true),
+    mFilter(filter) {}
+
   virtual ~UDPSocketParent();
 
   bool Init(const nsCString& aHost, const uint16_t aPort);
 
   virtual bool RecvClose() MOZ_OVERRIDE;
   virtual bool RecvData(const InfallibleTArray<uint8_t>& aData,
                         const nsCString& aRemoteAddress,
                         const uint16_t& aPort) MOZ_OVERRIDE;
@@ -32,14 +38,15 @@ public:
                                     const mozilla::net::NetAddr& addr);
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   bool mIPCOpen;
   nsCOMPtr<nsIUDPSocket> mSocket;
+  nsCOMPtr<nsIUDPSocketFilter> mFilter;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // !defined(mozilla_dom_UDPSocketParent_h__)
--- a/netwerk/base/public/moz.build
+++ b/netwerk/base/public/moz.build
@@ -102,16 +102,17 @@ XPIDL_SOURCES += [
     'nsISyncStreamListener.idl',
     'nsISystemProxySettings.idl',
     'nsIThreadRetargetableRequest.idl',
     'nsIThreadRetargetableStreamListener.idl',
     'nsITimedChannel.idl',
     'nsITraceableChannel.idl',
     'nsITransport.idl',
     'nsIUDPSocket.idl',
+    'nsIUDPSocketFilter.idl',
     'nsIUnicharStreamLoader.idl',
     'nsIUploadChannel.idl',
     'nsIUploadChannel2.idl',
     'nsIURI.idl',
     'nsIURIChecker.idl',
     'nsIURIClassifier.idl',
     'nsIURIWithPrincipal.idl',
     'nsIURL.idl',
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIUDPSocketFilter.idl
@@ -0,0 +1,45 @@
+/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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 "nsISupports.idl"
+#include "nsINetAddr.idl"
+
+native NetAddr(mozilla::net::NetAddr);
+[ptr] native NetAddrPtr(mozilla::net::NetAddr);
+
+
+/**
+ * Filters are created and run on the parent, and filter all UDP packets, both
+ * ingoing and outgoing. The child must specify the name of a recognized filter
+ * in order to create a UDP socket.
+ */
+[uuid(24f20de4-09e9-42ab-947a-0d6a3d103d59)]
+interface nsIUDPSocketFilter : nsISupports
+{
+  const long SF_INCOMING = 0;
+  const long SF_OUTGOING = 1;
+
+  bool filterPacket([const]in NetAddrPtr remote_addr,
+                    [const, array, size_is(len)]in uint8_t data,
+                    in unsigned long len,
+                    in long direction);
+};
+
+/**
+ * Factory of a specified filter.
+ */
+[uuid(81ee76c6-4753-4125-9c8c-290ed9ba62fb)]
+interface nsIUDPSocketFilterHandler : nsISupports
+{
+   nsIUDPSocketFilter newFilter();
+};
+
+%{C++
+/**
+ * Filter handlers are registered with XPCOM under the following CONTRACTID prefix:
+ */
+#define NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX "@mozilla.org/network/udp-filter-handler;1?name="
+%}
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -209,17 +209,18 @@ NeckoChild::DeallocPTCPServerSocketChild
 {
   TCPServerSocketChild* p = static_cast<TCPServerSocketChild*>(child);
   p->ReleaseIPDLReference();
   return true;
 }
 
 PUDPSocketChild*
 NeckoChild::AllocPUDPSocketChild(const nsCString& aHost,
-                                 const uint16_t& aPort)
+                                 const uint16_t& aPort,
+                                 const nsCString& aFilter)
 {
   NS_NOTREACHED("AllocPUDPSocket should not be called");
   return nullptr;
 }
 
 bool
 NeckoChild::DeallocPUDPSocketChild(PUDPSocketChild* child)
 {
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -43,17 +43,18 @@ protected:
   virtual bool DeallocPWebSocketChild(PWebSocketChild*);
   virtual PTCPSocketChild* AllocPTCPSocketChild();
   virtual bool DeallocPTCPSocketChild(PTCPSocketChild*);
   virtual PTCPServerSocketChild* AllocPTCPServerSocketChild(const uint16_t& aLocalPort,
                                                        const uint16_t& aBacklog,
                                                        const nsString& aBinaryType);
   virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*);
   virtual PUDPSocketChild* AllocPUDPSocketChild(const nsCString& aHost,
-                                                const uint16_t& aPort);
+                                                const uint16_t& aPort,
+                                                const nsCString& aFilter);
   virtual bool DeallocPUDPSocketChild(PUDPSocketChild*);
   virtual PRemoteOpenFileChild* AllocPRemoteOpenFileChild(const URIParams&,
                                                           const OptionalURIParams&);
   virtual bool DeallocPRemoteOpenFileChild(PRemoteOpenFileChild*);
   virtual PRtspControllerChild* AllocPRtspControllerChild();
   virtual bool DeallocPRtspControllerChild(PRtspControllerChild*);
 };
 
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/dom/network/TCPServerSocketParent.h"
 #include "mozilla/dom/network/UDPSocketParent.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/LoadContext.h"
 #include "mozilla/AppProcessChecker.h"
 #include "nsPrintfCString.h"
 #include "nsHTMLDNSPrefetch.h"
 #include "nsIAppsService.h"
+#include "nsIUDPSocketFilter.h"
 #include "nsEscape.h"
 #include "RemoteOpenFileParent.h"
 #include "SerializedLoadContext.h"
 
 using mozilla::dom::ContentParent;
 using mozilla::dom::TabParent;
 using mozilla::net::PTCPSocketParent;
 using mozilla::dom::TCPSocketParent;
@@ -374,33 +375,52 @@ NeckoParent::DeallocPTCPServerSocketPare
 {
   TCPServerSocketParent* p = static_cast<TCPServerSocketParent*>(actor);
    p->ReleaseIPDLReference();
   return true;
 }
 
 PUDPSocketParent*
 NeckoParent::AllocPUDPSocketParent(const nsCString& aHost,
-                                   const uint16_t& aPort)
+                                   const uint16_t& aPort,
+                                   const nsCString& aFilter)
 {
-  bool enabled = Preferences::GetBool("media.peerconnection.ipc.enabled", false);
-  if (!enabled) {
-    NS_WARNING("Not support UDP socket in content process, aborting subprocess");
-    return nullptr;
+  UDPSocketParent* p;
+
+  // Only allow socket if it specifies a valid packet filter.
+  nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
+  contractId.Append(aFilter);
+
+  if (!aFilter.IsEmpty()) {
+    nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
+      do_GetService(contractId.get());
+    if (filterHandler) {
+      nsCOMPtr<nsIUDPSocketFilter> filter;
+      nsresult rv = filterHandler->NewFilter(getter_AddRefs(filter));
+      if (NS_SUCCEEDED(rv)) {
+        p = new UDPSocketParent(filter);
+      } else {
+        printf_stderr("Cannot create filter that content specified. "
+                      "filter name: %s, error code: %d.", aFilter.get(), rv);
+      }
+    } else {
+      printf_stderr("Content doesn't have a valid filter. "
+                    "filter name: %s.", aFilter.get());
+    }
   }
-  UDPSocketParent* p = new UDPSocketParent();
-  p->AddRef();
+
+  NS_IF_ADDREF(p);
   return p;
-
 }
 
 bool
 NeckoParent::RecvPUDPSocketConstructor(PUDPSocketParent* aActor,
                                        const nsCString& aHost,
-                                       const uint16_t& aPort)
+                                       const uint16_t& aPort,
+                                       const nsCString& aFilter)
 {
   return static_cast<UDPSocketParent*>(aActor)->Init(aHost, aPort);
 }
 
 bool
 NeckoParent::DeallocPUDPSocketParent(PUDPSocketParent* actor)
 {
   UDPSocketParent* p = static_cast<UDPSocketParent*>(actor);
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -112,20 +112,22 @@ protected:
                                                         const uint16_t& aBacklog,
                                                         const nsString& aBinaryType);
   virtual bool RecvPTCPServerSocketConstructor(PTCPServerSocketParent*,
                                                const uint16_t& aLocalPort,
                                                const uint16_t& aBacklog,
                                                const nsString& aBinaryType);
   virtual bool DeallocPTCPServerSocketParent(PTCPServerSocketParent*);
   virtual PUDPSocketParent* AllocPUDPSocketParent(const nsCString& aHost,
-                                                  const uint16_t& aPort);
+                                                  const uint16_t& aPort,
+                                                  const nsCString& aFilter);
   virtual bool RecvPUDPSocketConstructor(PUDPSocketParent*,
                                          const nsCString& aHost,
-                                         const uint16_t& aPort);
+                                         const uint16_t& aPort,
+                                         const nsCString& aFilter);
   virtual bool DeallocPUDPSocketParent(PUDPSocketParent*);
   virtual bool RecvHTMLDNSPrefetch(const nsString& hostname,
                                    const uint16_t& flags);
   virtual bool RecvCancelHTMLDNSPrefetch(const nsString& hostname,
                                          const uint16_t& flags,
                                          const nsresult& reason);
 
   virtual mozilla::ipc::IProtocol*
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -52,17 +52,17 @@ parent:
                SerializedLoadContext loadContext,
                HttpChannelCreationArgs args);
   PWyciwygChannel();
   PFTPChannel(PBrowser browser, SerializedLoadContext loadContext,
               FTPChannelCreationArgs args);
 
   PWebSocket(PBrowser browser, SerializedLoadContext loadContext);
   PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
-  PUDPSocket(nsCString host, uint16_t port);
+  PUDPSocket(nsCString host, uint16_t port, nsCString filter);
 
   PRemoteOpenFile(URIParams fileuri, OptionalURIParams appuri);
 
   HTMLDNSPrefetch(nsString hostname, uint16_t flags);
   CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
   PRtspController();
 
 both: