UDPSocketParent.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  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 file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsIServiceManager.h"
  6. #include "UDPSocketParent.h"
  7. #include "UDPSocket.h"
  8. #include "nsComponentManagerUtils.h"
  9. #include "nsIUDPSocket.h"
  10. #include "nsINetAddr.h"
  11. #include "nsNetCID.h"
  12. #include "mozilla/AppProcessChecker.h"
  13. #include "mozilla/Unused.h"
  14. #include "mozilla/ipc/InputStreamUtils.h"
  15. #include "mozilla/net/DNS.h"
  16. #include "mozilla/net/NeckoCommon.h"
  17. #include "mozilla/net/PNeckoParent.h"
  18. #include "nsIPermissionManager.h"
  19. #include "nsIScriptSecurityManager.h"
  20. #include "mozilla/dom/ContentParent.h"
  21. #include "mozilla/ipc/PBackgroundParent.h"
  22. #include "mtransport/runnable_utils.h"
  23. using namespace mozilla::net;
  24. namespace mozilla {
  25. namespace dom {
  26. NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
  27. UDPSocketParent::UDPSocketParent(PBackgroundParent* aManager)
  28. : mBackgroundManager(aManager)
  29. , mNeckoManager(nullptr)
  30. , mIPCOpen(true)
  31. {
  32. }
  33. UDPSocketParent::UDPSocketParent(PNeckoParent* aManager)
  34. : mBackgroundManager(nullptr)
  35. , mNeckoManager(aManager)
  36. , mIPCOpen(true)
  37. {
  38. }
  39. UDPSocketParent::~UDPSocketParent()
  40. {
  41. }
  42. bool
  43. UDPSocketParent::Init(const IPC::Principal& aPrincipal,
  44. const nsACString& aFilter)
  45. {
  46. MOZ_ASSERT_IF(mBackgroundManager, !aPrincipal);
  47. // will be used once we move all UDPSocket to PBackground, or
  48. // if we add in Principal checking for mtransport
  49. Unused << mBackgroundManager;
  50. mPrincipal = aPrincipal;
  51. if (net::UsingNeckoIPCSecurity() &&
  52. mPrincipal &&
  53. !ContentParent::IgnoreIPCPrincipal()) {
  54. if (mNeckoManager) {
  55. if (!AssertAppPrincipal(mNeckoManager->Manager(), mPrincipal)) {
  56. return false;
  57. }
  58. } else {
  59. // PBackground is (for now) using a STUN filter for verification
  60. // it's not being used for DoS
  61. }
  62. nsCOMPtr<nsIPermissionManager> permMgr =
  63. services::GetPermissionManager();
  64. if (!permMgr) {
  65. NS_WARNING("No PermissionManager available!");
  66. return false;
  67. }
  68. uint32_t permission = nsIPermissionManager::DENY_ACTION;
  69. permMgr->TestExactPermissionFromPrincipal(mPrincipal, "udp-socket",
  70. &permission);
  71. if (permission != nsIPermissionManager::ALLOW_ACTION) {
  72. return false;
  73. }
  74. }
  75. if (!aFilter.IsEmpty()) {
  76. nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
  77. contractId.Append(aFilter);
  78. nsCOMPtr<nsISocketFilterHandler> filterHandler =
  79. do_GetService(contractId.get());
  80. if (filterHandler) {
  81. nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
  82. if (NS_FAILED(rv)) {
  83. printf_stderr("Cannot create filter that content specified. "
  84. "filter name: %s, error code: %u.", aFilter.BeginReading(), static_cast<uint32_t>(rv));
  85. return false;
  86. }
  87. } else {
  88. printf_stderr("Content doesn't have a valid filter. "
  89. "filter name: %s.", aFilter.BeginReading());
  90. return false;
  91. }
  92. }
  93. // We don't have browser actors in xpcshell, and hence can't run automated
  94. // tests without this loophole.
  95. if (net::UsingNeckoIPCSecurity() && !mFilter &&
  96. (!mPrincipal || ContentParent::IgnoreIPCPrincipal())) {
  97. return false;
  98. }
  99. return true;
  100. }
  101. // PUDPSocketParent methods
  102. bool
  103. UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
  104. const bool& aAddressReuse, const bool& aLoopback,
  105. const uint32_t& recvBufferSize,
  106. const uint32_t& sendBufferSize)
  107. {
  108. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
  109. if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(),
  110. aAddressReuse, aLoopback, recvBufferSize,
  111. sendBufferSize))) {
  112. FireInternalError(__LINE__);
  113. return true;
  114. }
  115. nsCOMPtr<nsINetAddr> localAddr;
  116. mSocket->GetLocalAddr(getter_AddRefs(localAddr));
  117. nsCString addr;
  118. if (NS_FAILED(localAddr->GetAddress(addr))) {
  119. FireInternalError(__LINE__);
  120. return true;
  121. }
  122. uint16_t port;
  123. if (NS_FAILED(localAddr->GetPort(&port))) {
  124. FireInternalError(__LINE__);
  125. return true;
  126. }
  127. UDPSOCKET_LOG(("%s: SendCallbackOpened: %s:%u", __FUNCTION__, addr.get(), port));
  128. mozilla::Unused << SendCallbackOpened(UDPAddressInfo(addr, port));
  129. return true;
  130. }
  131. nsresult
  132. UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
  133. const bool& aAddressReuse, const bool& aLoopback,
  134. const uint32_t& recvBufferSize,
  135. const uint32_t& sendBufferSize)
  136. {
  137. nsresult rv;
  138. UDPSOCKET_LOG(("%s: [this=%p] %s:%u addressReuse: %d loopback: %d recvBufferSize: %lu, sendBufferSize: %lu",
  139. __FUNCTION__, this, nsCString(aHost).get(), aPort,
  140. aAddressReuse, aLoopback, recvBufferSize, sendBufferSize));
  141. nsCOMPtr<nsIUDPSocket> sock =
  142. do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
  143. if (NS_WARN_IF(NS_FAILED(rv))) {
  144. return rv;
  145. }
  146. if (aHost.IsEmpty()) {
  147. rv = sock->Init(aPort, false, mPrincipal, aAddressReuse,
  148. /* optional_argc = */ 1);
  149. } else {
  150. PRNetAddr prAddr;
  151. PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
  152. PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
  153. if (status != PR_SUCCESS) {
  154. return NS_ERROR_FAILURE;
  155. }
  156. mozilla::net::NetAddr addr;
  157. PRNetAddrToNetAddr(&prAddr, &addr);
  158. rv = sock->InitWithAddress(&addr, mPrincipal, aAddressReuse,
  159. /* optional_argc = */ 1);
  160. }
  161. if (NS_WARN_IF(NS_FAILED(rv))) {
  162. return rv;
  163. }
  164. nsCOMPtr<nsINetAddr> laddr;
  165. rv = sock->GetLocalAddr(getter_AddRefs(laddr));
  166. if (NS_WARN_IF(NS_FAILED(rv))) {
  167. return rv;
  168. }
  169. uint16_t family;
  170. rv = laddr->GetFamily(&family);
  171. if (NS_WARN_IF(NS_FAILED(rv))) {
  172. return rv;
  173. }
  174. if (family == nsINetAddr::FAMILY_INET) {
  175. rv = sock->SetMulticastLoopback(aLoopback);
  176. if (NS_WARN_IF(NS_FAILED(rv))) {
  177. return rv;
  178. }
  179. }
  180. // TODO: once bug 1252759 is fixed query buffer first and only increase
  181. if (recvBufferSize != 0) {
  182. rv = sock->SetRecvBufferSize(recvBufferSize);
  183. if (NS_WARN_IF(NS_FAILED(rv))) {
  184. UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set recv buffer size to: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, recvBufferSize));
  185. }
  186. }
  187. if (sendBufferSize != 0) {
  188. rv = sock->SetSendBufferSize(sendBufferSize);
  189. if (NS_WARN_IF(NS_FAILED(rv))) {
  190. UDPSOCKET_LOG(("%s: [this=%p] %s:%u failed to set send buffer size to: %lu", __FUNCTION__, this, nsCString(aHost).get(), aPort, sendBufferSize));
  191. }
  192. }
  193. // register listener
  194. rv = sock->AsyncListen(this);
  195. if (NS_WARN_IF(NS_FAILED(rv))) {
  196. return rv;
  197. }
  198. mSocket = sock;
  199. return NS_OK;
  200. }
  201. static nsCOMPtr<nsIEventTarget> GetSTSThread()
  202. {
  203. nsresult rv;
  204. nsCOMPtr<nsIEventTarget> sts_thread;
  205. sts_thread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  206. MOZ_ASSERT(NS_SUCCEEDED(rv));
  207. return sts_thread;
  208. }
  209. static void CheckSTSThread()
  210. {
  211. DebugOnly<nsCOMPtr<nsIEventTarget>> sts_thread = GetSTSThread();
  212. ASSERT_ON_THREAD(sts_thread.value);
  213. }
  214. // Proxy the Connect() request to the STS thread, since it may block and
  215. // should be done there.
  216. bool
  217. UDPSocketParent::RecvConnect(const UDPAddressInfo& aAddressInfo)
  218. {
  219. nsCOMPtr<nsIEventTarget> thread(NS_GetCurrentThread());
  220. Unused <<
  221. NS_WARN_IF(NS_FAILED(GetSTSThread()->Dispatch(WrapRunnable(
  222. RefPtr<UDPSocketParent>(this),
  223. &UDPSocketParent::DoConnect,
  224. mSocket,
  225. thread,
  226. aAddressInfo),
  227. NS_DISPATCH_NORMAL)));
  228. return true;
  229. }
  230. void
  231. UDPSocketParent::DoSendConnectResponse(const UDPAddressInfo& aAddressInfo)
  232. {
  233. // can't use directly with WrapRunnable due to warnings
  234. mozilla::Unused << SendCallbackConnected(aAddressInfo);
  235. }
  236. void
  237. UDPSocketParent::SendConnectResponse(nsIEventTarget *aThread,
  238. const UDPAddressInfo& aAddressInfo)
  239. {
  240. Unused <<
  241. NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
  242. RefPtr<UDPSocketParent>(this),
  243. &UDPSocketParent::DoSendConnectResponse,
  244. aAddressInfo),
  245. NS_DISPATCH_NORMAL)));
  246. }
  247. // Runs on STS thread
  248. void
  249. UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
  250. nsCOMPtr<nsIEventTarget>& aReturnThread,
  251. const UDPAddressInfo& aAddressInfo)
  252. {
  253. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
  254. if (NS_FAILED(ConnectInternal(aAddressInfo.addr(), aAddressInfo.port()))) {
  255. SendInternalError(aReturnThread, __LINE__);
  256. return;
  257. }
  258. CheckSTSThread();
  259. nsCOMPtr<nsINetAddr> localAddr;
  260. aSocket->GetLocalAddr(getter_AddRefs(localAddr));
  261. nsCString addr;
  262. if (NS_FAILED(localAddr->GetAddress(addr))) {
  263. SendInternalError(aReturnThread, __LINE__);
  264. return;
  265. }
  266. uint16_t port;
  267. if (NS_FAILED(localAddr->GetPort(&port))) {
  268. SendInternalError(aReturnThread, __LINE__);
  269. return;
  270. }
  271. UDPSOCKET_LOG(("%s: SendConnectResponse: %s:%u", __FUNCTION__, addr.get(), port));
  272. SendConnectResponse(aReturnThread, UDPAddressInfo(addr, port));
  273. }
  274. nsresult
  275. UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort)
  276. {
  277. nsresult rv;
  278. UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
  279. if (!mSocket) {
  280. return NS_ERROR_NOT_AVAILABLE;
  281. }
  282. PRNetAddr prAddr;
  283. PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
  284. PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
  285. if (status != PR_SUCCESS) {
  286. return NS_ERROR_FAILURE;
  287. }
  288. mozilla::net::NetAddr addr;
  289. PRNetAddrToNetAddr(&prAddr, &addr);
  290. rv = mSocket->Connect(&addr);
  291. if (NS_WARN_IF(NS_FAILED(rv))) {
  292. return rv;
  293. }
  294. return NS_OK;
  295. }
  296. bool
  297. UDPSocketParent::RecvOutgoingData(const UDPData& aData,
  298. const UDPSocketAddr& aAddr)
  299. {
  300. if (!mSocket) {
  301. NS_WARNING("sending socket is closed");
  302. FireInternalError(__LINE__);
  303. return true;
  304. }
  305. nsresult rv;
  306. if (mFilter) {
  307. if (aAddr.type() != UDPSocketAddr::TNetAddr) {
  308. return true;
  309. }
  310. // TODO, Packet filter doesn't support input stream yet.
  311. if (aData.type() != UDPData::TArrayOfuint8_t) {
  312. return true;
  313. }
  314. bool allowed;
  315. const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
  316. rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
  317. data.Length(), nsISocketFilter::SF_OUTGOING,
  318. &allowed);
  319. // Sending unallowed data, kill content.
  320. if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
  321. return false;
  322. }
  323. }
  324. switch(aData.type()) {
  325. case UDPData::TArrayOfuint8_t:
  326. Send(aData.get_ArrayOfuint8_t(), aAddr);
  327. break;
  328. case UDPData::TInputStreamParams:
  329. Send(aData.get_InputStreamParams(), aAddr);
  330. break;
  331. default:
  332. MOZ_ASSERT(false, "Invalid data type!");
  333. return true;
  334. }
  335. return true;
  336. }
  337. void
  338. UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
  339. const UDPSocketAddr& aAddr)
  340. {
  341. nsresult rv;
  342. uint32_t count;
  343. switch(aAddr.type()) {
  344. case UDPSocketAddr::TUDPAddressInfo: {
  345. const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
  346. rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
  347. aData.Elements(), aData.Length(), &count);
  348. break;
  349. }
  350. case UDPSocketAddr::TNetAddr: {
  351. const NetAddr& addr(aAddr.get_NetAddr());
  352. rv = mSocket->SendWithAddress(&addr, aData.Elements(),
  353. aData.Length(), &count);
  354. break;
  355. }
  356. default:
  357. MOZ_ASSERT(false, "Invalid address type!");
  358. return;
  359. }
  360. if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
  361. FireInternalError(__LINE__);
  362. }
  363. }
  364. void
  365. UDPSocketParent::Send(const InputStreamParams& aStream,
  366. const UDPSocketAddr& aAddr)
  367. {
  368. nsTArray<mozilla::ipc::FileDescriptor> fds;
  369. nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
  370. if (NS_WARN_IF(!stream)) {
  371. return;
  372. }
  373. nsresult rv;
  374. switch(aAddr.type()) {
  375. case UDPSocketAddr::TUDPAddressInfo: {
  376. const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
  377. rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
  378. break;
  379. }
  380. case UDPSocketAddr::TNetAddr: {
  381. const NetAddr& addr(aAddr.get_NetAddr());
  382. rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
  383. break;
  384. }
  385. default:
  386. MOZ_ASSERT(false, "Invalid address type!");
  387. return;
  388. }
  389. if (NS_FAILED(rv)) {
  390. FireInternalError(__LINE__);
  391. }
  392. }
  393. bool
  394. UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
  395. const nsCString& aInterface)
  396. {
  397. nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
  398. if (NS_WARN_IF(NS_FAILED(rv))) {
  399. FireInternalError(__LINE__);
  400. }
  401. return true;
  402. }
  403. bool
  404. UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
  405. const nsCString& aInterface)
  406. {
  407. nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
  408. if (NS_WARN_IF(NS_FAILED(rv))) {
  409. FireInternalError(__LINE__);
  410. }
  411. return true;
  412. }
  413. bool
  414. UDPSocketParent::RecvClose()
  415. {
  416. if (!mSocket) {
  417. return true;
  418. }
  419. nsresult rv = mSocket->Close();
  420. mSocket = nullptr;
  421. mozilla::Unused << NS_WARN_IF(NS_FAILED(rv));
  422. return true;
  423. }
  424. bool
  425. UDPSocketParent::RecvRequestDelete()
  426. {
  427. mozilla::Unused << Send__delete__(this);
  428. return true;
  429. }
  430. void
  431. UDPSocketParent::ActorDestroy(ActorDestroyReason why)
  432. {
  433. MOZ_ASSERT(mIPCOpen);
  434. mIPCOpen = false;
  435. if (mSocket) {
  436. mSocket->Close();
  437. }
  438. mSocket = nullptr;
  439. }
  440. // nsIUDPSocketListener
  441. NS_IMETHODIMP
  442. UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
  443. {
  444. // receiving packet from remote host, forward the message content to child process
  445. if (!mIPCOpen) {
  446. return NS_OK;
  447. }
  448. uint16_t port;
  449. nsCString ip;
  450. nsCOMPtr<nsINetAddr> fromAddr;
  451. aMessage->GetFromAddr(getter_AddRefs(fromAddr));
  452. fromAddr->GetPort(&port);
  453. fromAddr->GetAddress(ip);
  454. nsCString data;
  455. aMessage->GetData(data);
  456. const char* buffer = data.get();
  457. uint32_t len = data.Length();
  458. UDPSOCKET_LOG(("%s: %s:%u, length %u", __FUNCTION__, ip.get(), port, len));
  459. if (mFilter) {
  460. bool allowed;
  461. mozilla::net::NetAddr addr;
  462. fromAddr->GetNetAddr(&addr);
  463. nsresult rv = mFilter->FilterPacket(&addr,
  464. (const uint8_t*)buffer, len,
  465. nsISocketFilter::SF_INCOMING,
  466. &allowed);
  467. // Receiving unallowed data, drop.
  468. if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
  469. if (!allowed) {
  470. UDPSOCKET_LOG(("%s: not allowed", __FUNCTION__));
  471. }
  472. return NS_OK;
  473. }
  474. }
  475. FallibleTArray<uint8_t> fallibleArray;
  476. if (!fallibleArray.InsertElementsAt(0, buffer, len, fallible)) {
  477. FireInternalError(__LINE__);
  478. return NS_ERROR_OUT_OF_MEMORY;
  479. }
  480. InfallibleTArray<uint8_t> infallibleArray;
  481. infallibleArray.SwapElements(fallibleArray);
  482. // compose callback
  483. mozilla::Unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
  484. return NS_OK;
  485. }
  486. NS_IMETHODIMP
  487. UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
  488. {
  489. // underlying socket is dead, send state update to child process
  490. if (mIPCOpen) {
  491. mozilla::Unused << SendCallbackClosed();
  492. }
  493. return NS_OK;
  494. }
  495. void
  496. UDPSocketParent::FireInternalError(uint32_t aLineNo)
  497. {
  498. if (!mIPCOpen) {
  499. return;
  500. }
  501. mozilla::Unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
  502. NS_LITERAL_CSTRING(__FILE__), aLineNo);
  503. }
  504. void
  505. UDPSocketParent::SendInternalError(nsIEventTarget *aThread,
  506. uint32_t aLineNo)
  507. {
  508. UDPSOCKET_LOG(("SendInternalError: %u", aLineNo));
  509. Unused <<
  510. NS_WARN_IF(NS_FAILED(aThread->Dispatch(WrapRunnable(
  511. RefPtr<UDPSocketParent>(this),
  512. &UDPSocketParent::FireInternalError,
  513. aLineNo),
  514. NS_DISPATCH_NORMAL)));
  515. }
  516. } // namespace dom
  517. } // namespace mozilla