Bug 1326483 - Part 1, not allow non-loopback UDP socket be created in offline mode. r=drno draft
authorShih-Chiang Chien <schien@mozilla.com>
Tue, 10 Jan 2017 19:19:03 +0800
changeset 459486 257b80aaf7af653ef0adbc2f92e64607527c7121
parent 459458 13603af3862d9583ed2feefb06e0988c2d7fed8c
child 459487 e78bc411625cfe46980e45091a7a2a8c0191eae7
push id41232
push userschien@mozilla.com
push dateThu, 12 Jan 2017 01:41:37 +0000
reviewersdrno
bugs1326483
milestone53.0a1
Bug 1326483 - Part 1, not allow non-loopback UDP socket be created in offline mode. r=drno MozReview-Commit-ID: IpnHjmW3RYr
netwerk/base/nsUDPSocket.cpp
--- a/netwerk/base/nsUDPSocket.cpp
+++ b/netwerk/base/nsUDPSocket.cpp
@@ -66,16 +66,32 @@ ResolveHost(const nsACString &host, nsID
   }
 
   nsCOMPtr<nsICancelable> tmpOutstanding;
   return dns->AsyncResolve(host, 0, listener, nullptr,
                            getter_AddRefs(tmpOutstanding));
 
 }
 
+static nsresult
+CheckIOStatus(const NetAddr *aAddr)
+{
+  MOZ_ASSERT(gIOService);
+
+  if (gIOService->IsNetTearingDown()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (gIOService->IsOffline() && !IsLoopBackAddress(aAddr)) {
+    return NS_ERROR_OFFLINE;
+  }
+
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 
 class SetSocketOptionRunnable : public Runnable
 {
 public:
   SetSocketOptionRunnable(nsUDPSocket* aSocket, const PRSocketOptionData& aOpt)
     : mSocket(aSocket)
     , mOpt(aOpt)
@@ -315,18 +331,19 @@ nsUDPSocket::OnMsgAttach()
 nsresult
 nsUDPSocket::TryAttach()
 {
   nsresult rv;
 
   if (!gSocketTransportService)
     return NS_ERROR_FAILURE;
 
-  if (gIOService->IsNetTearingDown()) {
-    return NS_ERROR_FAILURE;
+  rv = CheckIOStatus(&mAddr);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
   //
   // find out if it is going to be ok to attach another socket to the STS.
   // if not then we have to wait for the STS to tell us that it is ok.
   // the notification is asynchronous, which means that when we could be
   // in a race to call AttachSocket once notified.  for this reason, when
   // we get notified, we just re-enter this function.  as a result, we are
@@ -525,17 +542,17 @@ nsUDPSocket::OnSocketDetached(PRFileDesc
     }
   }
 }
 
 void
 nsUDPSocket::IsLocal(bool *aIsLocal)
 {
   // If bound to loopback, this UDP socket only accepts local connections.
-  *aIsLocal = mAddr.raw.family == nsINetAddr::FAMILY_LOCAL;
+  *aIsLocal = IsLoopBackAddress(&mAddr);
 }
 
 //-----------------------------------------------------------------------------
 // nsSocket::nsISupports
 //-----------------------------------------------------------------------------
 
 NS_IMPL_ISUPPORTS(nsUDPSocket, nsIUDPSocket)
 
@@ -568,40 +585,54 @@ NS_IMETHODIMP
 nsUDPSocket::Init2(const nsACString& aAddr, int32_t aPort, nsIPrincipal *aPrincipal,
                    bool aAddressReuse, uint8_t aOptionalArgc)
 {
   if (NS_WARN_IF(aAddr.IsEmpty())) {
     return NS_ERROR_INVALID_ARG;
   }
 
   PRNetAddr prAddr;
+  memset(&prAddr, 0, sizeof(prAddr));
   if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
     return NS_ERROR_FAILURE;
   }
 
-  NetAddr addr;
-
-  if (aPort < 0)
+  if (aPort < 0) {
     aPort = 0;
+  }
 
-  addr.raw.family = AF_INET;
-  addr.inet.port = htons(aPort);
-  addr.inet.ip = prAddr.inet.ip;
+  switch (prAddr.raw.family) {
+    case PR_AF_INET:
+      prAddr.inet.port = PR_htons(aPort);
+      break;
+    case PR_AF_INET6:
+      prAddr.ipv6.port = PR_htons(aPort);
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Dont accept address other than IPv4 and IPv6");
+      return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  NetAddr addr;
+  PRNetAddrToNetAddr(&prAddr, &addr);
 
   return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
 }
 
 NS_IMETHODIMP
 nsUDPSocket::InitWithAddress(const NetAddr *aAddr, nsIPrincipal *aPrincipal,
                              bool aAddressReuse, uint8_t aOptionalArgc)
 {
   NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
 
-  if (gIOService->IsNetTearingDown()) {
-    return NS_ERROR_FAILURE;
+  nsresult rv;
+
+  rv = CheckIOStatus(aAddr);
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
   bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
 
   //
   // configure listening socket...
   //
 
@@ -670,16 +701,23 @@ nsUDPSocket::Connect(const NetAddr *aAdd
   UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
 
   NS_ENSURE_ARG(aAddr);
 
   if (NS_WARN_IF(!mFD)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
+  nsresult rv;
+
+  rv = CheckIOStatus(aAddr);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
   bool onSTSThread = false;
   mSts->IsOnCurrentThread(&onSTSThread);
   NS_ASSERTION(onSTSThread, "NOT ON STS THREAD");
   if (!onSTSThread) {
     return NS_ERROR_FAILURE;
   }
 
   PRNetAddr prAddr;