tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

UDPSocketParent.cpp (15976B)


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