tor-browser

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

test_nr_socket.cpp (39667B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=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 */
      8 
      9 /*
     10 Based partially on original code from nICEr and nrappkit.
     11 
     12 nICEr copyright:
     13 
     14 Copyright (c) 2007, Adobe Systems, Incorporated
     15 All rights reserved.
     16 
     17 Redistribution and use in source and binary forms, with or without
     18 modification, are permitted provided that the following conditions are
     19 met:
     20 
     21 * Redistributions of source code must retain the above copyright
     22  notice, this list of conditions and the following disclaimer.
     23 
     24 * Redistributions in binary form must reproduce the above copyright
     25  notice, this list of conditions and the following disclaimer in the
     26  documentation and/or other materials provided with the distribution.
     27 
     28 * Neither the name of Adobe Systems, Network Resonance nor the names of its
     29  contributors may be used to endorse or promote products derived from
     30  this software without specific prior written permission.
     31 
     32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     33 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     34 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     35 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     36 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     37 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     38 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     39 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     40 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     41 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     42 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     43 
     44 
     45 nrappkit copyright:
     46 
     47   Copyright (C) 2001-2003, Network Resonance, Inc.
     48   Copyright (C) 2006, Network Resonance, Inc.
     49   All Rights Reserved
     50 
     51   Redistribution and use in source and binary forms, with or without
     52   modification, are permitted provided that the following conditions
     53   are met:
     54 
     55   1. Redistributions of source code must retain the above copyright
     56      notice, this list of conditions and the following disclaimer.
     57   2. Redistributions in binary form must reproduce the above copyright
     58      notice, this list of conditions and the following disclaimer in the
     59      documentation and/or other materials provided with the distribution.
     60   3. Neither the name of Network Resonance, Inc. nor the name of any
     61      contributors to this software may be used to endorse or promote
     62      products derived from this software without specific prior written
     63      permission.
     64 
     65   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
     66   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     67   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     68   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     69   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     70   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     71   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     72   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     73   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     74   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     75   POSSIBILITY OF SUCH DAMAGE.
     76 
     77 
     78   ekr@rtfm.com  Thu Dec 20 20:14:49 2001
     79 */
     80 
     81 // Original author: bcampen@mozilla.com [:bwc]
     82 
     83 extern "C" {
     84 // clang-format off
     85 #include "stun_msg.h"  // for NR_STUN_MAX_MESSAGE_SIZE
     86 #include "async_wait.h"
     87 #include "async_timer.h"
     88 #include "nr_socket.h"
     89 #include "stun.h"
     90 #include "transport_addr.h"
     91 // clang-format on
     92 }
     93 
     94 #include "test_nr_socket.h"
     95 
     96 #include "mozilla/RefPtr.h"
     97 
     98 namespace mozilla {
     99 
    100 static int test_nat_socket_create(void* obj, nr_transport_addr* addr,
    101                                  nr_socket** sockp) {
    102  RefPtr<NrSocketBase> sock = new TestNrSocket(static_cast<TestNat*>(obj));
    103 
    104  int r, _status;
    105 
    106  r = sock->create(addr);
    107  if (r) ABORT(r);
    108 
    109  r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp);
    110  if (r) ABORT(r);
    111 
    112  _status = 0;
    113 
    114  {
    115    // We will release this reference in destroy(), not exactly the normal
    116    // ownership model, but it is what it is.
    117    NrSocketBase* dummy = sock.forget().take();
    118    (void)dummy;
    119  }
    120 
    121 abort:
    122  return _status;
    123 }
    124 
    125 static int test_nat_socket_factory_destroy(void** obj) {
    126  TestNat* nat = static_cast<TestNat*>(*obj);
    127  *obj = nullptr;
    128  nat->Release();
    129  return 0;
    130 }
    131 
    132 static nr_socket_factory_vtbl test_nat_socket_factory_vtbl = {
    133    test_nat_socket_create, test_nat_socket_factory_destroy};
    134 
    135 /* static */
    136 TestNat::NatBehavior TestNat::ToNatBehavior(const std::string& type) {
    137  if (type.empty() || !type.compare("ENDPOINT_INDEPENDENT")) {
    138    return TestNat::ENDPOINT_INDEPENDENT;
    139  }
    140  if (!type.compare("ADDRESS_DEPENDENT")) {
    141    return TestNat::ADDRESS_DEPENDENT;
    142  }
    143  if (!type.compare("PORT_DEPENDENT")) {
    144    return TestNat::PORT_DEPENDENT;
    145  }
    146 
    147  MOZ_CRASH("Invalid NAT behavior");
    148 }
    149 
    150 bool TestNat::has_port_mappings() const {
    151  for (TestNrSocket* sock : sockets_) {
    152    if (sock->has_port_mappings()) {
    153      return true;
    154    }
    155  }
    156  return false;
    157 }
    158 
    159 bool TestNat::is_my_external_tuple(const nr_transport_addr& addr) const {
    160  for (TestNrSocket* sock : sockets_) {
    161    if (sock->is_my_external_tuple(addr)) {
    162      return true;
    163    }
    164  }
    165 
    166  return false;
    167 }
    168 
    169 bool TestNat::is_an_internal_tuple(const nr_transport_addr& addr) const {
    170  for (TestNrSocket* sock : sockets_) {
    171    nr_transport_addr addr_behind_nat;
    172    if (sock->getaddr(&addr_behind_nat)) {
    173      MOZ_CRASH("TestNrSocket::getaddr failed!");
    174    }
    175 
    176    if (!nr_transport_addr_cmp(&addr, &addr_behind_nat,
    177                               NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
    178      return true;
    179    }
    180  }
    181  return false;
    182 }
    183 
    184 int TestNat::create_socket_factory(nr_socket_factory** factorypp) {
    185  int r = nr_socket_factory_create_int(this, &test_nat_socket_factory_vtbl,
    186                                       factorypp);
    187  if (!r) {
    188    AddRef();
    189  }
    190  return r;
    191 }
    192 
    193 void TestNat::set_proxy_config(
    194    std::shared_ptr<NrSocketProxyConfig> aProxyConfig) {
    195  proxy_config_ = std::move(aProxyConfig);
    196 }
    197 
    198 TestNrSocket::TestNrSocket(TestNat* nat)
    199    : nat_(nat), tls_(false), timer_handle_(nullptr) {
    200  nat_->insert_socket(this);
    201 }
    202 
    203 TestNrSocket::~TestNrSocket() { nat_->erase_socket(this); }
    204 
    205 RefPtr<NrSocketBase> TestNrSocket::create_external_socket(
    206    const nr_transport_addr& dest_addr) const {
    207  MOZ_RELEASE_ASSERT(nat_->enabled_);
    208  MOZ_RELEASE_ASSERT(!nat_->is_an_internal_tuple(dest_addr));
    209 
    210  int r;
    211  nr_transport_addr nat_external_addr;
    212 
    213  // Open the socket on an arbitrary port, on the same address.
    214  if ((r = nr_transport_addr_copy(&nat_external_addr,
    215                                  &internal_socket_->my_addr()))) {
    216    r_log(LOG_GENERIC, LOG_CRIT, "%s: Failure in nr_transport_addr_copy: %d",
    217          __FUNCTION__, r);
    218    return nullptr;
    219  }
    220 
    221  if ((r = nr_transport_addr_set_port(&nat_external_addr, 0))) {
    222    r_log(LOG_GENERIC, LOG_CRIT,
    223          "%s: Failure in nr_transport_addr_set_port: %d", __FUNCTION__, r);
    224    return nullptr;
    225  }
    226 
    227  RefPtr<NrSocketBase> external_socket;
    228  r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket,
    229                                 nat_->proxy_config_);
    230 
    231  if (r) {
    232    r_log(LOG_GENERIC, LOG_CRIT, "%s: Failure in NrSocket::create: %d",
    233          __FUNCTION__, r);
    234    return nullptr;
    235  }
    236 
    237  return external_socket;
    238 }
    239 
    240 int TestNrSocket::create(nr_transport_addr* addr) {
    241  tls_ = addr->tls;
    242 
    243  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p create %s", this,
    244        addr->as_string);
    245  return NrSocketBase::CreateSocket(addr, &internal_socket_, nullptr);
    246 }
    247 
    248 int TestNrSocket::getaddr(nr_transport_addr* addrp) {
    249  return internal_socket_->getaddr(addrp);
    250 }
    251 
    252 void TestNrSocket::close() {
    253  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s closing", this,
    254        internal_socket_->my_addr().as_string);
    255  if (timer_handle_) {
    256    NR_async_timer_cancel(timer_handle_);
    257    timer_handle_ = nullptr;
    258  }
    259  for (auto& timer : mTimers) {
    260    timer->Cancel();
    261  }
    262  mTimers.Clear();
    263  internal_socket_->close();
    264  for (RefPtr<PortMapping>& port_mapping : port_mappings_) {
    265    port_mapping->external_socket_->close();
    266  }
    267 }
    268 
    269 int TestNrSocket::listen(int backlog) {
    270  MOZ_RELEASE_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
    271  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s listening", this,
    272        internal_socket_->my_addr().as_string);
    273 
    274  return internal_socket_->listen(backlog);
    275 }
    276 
    277 int TestNrSocket::accept(nr_transport_addr* addrp, nr_socket** sockp) {
    278  MOZ_RELEASE_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
    279  int r = internal_socket_->accept(addrp, sockp);
    280  if (r) {
    281    return r;
    282  }
    283 
    284  if (nat_->enabled_ && !nat_->is_an_internal_tuple(*addrp)) {
    285    nr_socket_destroy(sockp);
    286    return R_IO_ERROR;
    287  }
    288 
    289  return 0;
    290 }
    291 
    292 void TestNrSocket::process_delayed_cb(NR_SOCKET s, int how, void* cb_arg) {
    293  DeferredPacket* op = static_cast<DeferredPacket*>(cb_arg);
    294  op->socket_->timer_handle_ = nullptr;
    295  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s sending delayed STUN response",
    296        op->internal_socket_->my_addr().as_string);
    297  op->internal_socket_->sendto(op->buffer_.data(), op->buffer_.len(),
    298                               op->flags_, &op->to_);
    299 
    300  delete op;
    301 }
    302 
    303 int TestNrSocket::sendto(const void* msg, size_t len, int flags,
    304                         const nr_transport_addr* to) {
    305  MOZ_RELEASE_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
    306  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s %s", this, __FUNCTION__,
    307        to->as_string);
    308 
    309  if (nat_->nat_delegate_ &&
    310      nat_->nat_delegate_->on_sendto(nat_, msg, len, flags, to)) {
    311    return nat_->error_code_for_drop_;
    312  }
    313 
    314  UCHAR* buf = static_cast<UCHAR*>(const_cast<void*>(msg));
    315  if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
    316    return nat_->error_code_for_drop_;
    317  }
    318 
    319  if (nr_is_stun_request_message(buf, len) &&
    320      maybe_send_fake_response(buf, len, to)) {
    321    return 0;
    322  }
    323 
    324  /* TODO: improve the functionality of this in bug 1253657 */
    325  if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) {
    326    if (nat_->delay_stun_resp_ms_ && nr_is_stun_response_message(buf, len)) {
    327      NR_ASYNC_TIMER_SET(
    328          nat_->delay_stun_resp_ms_, process_delayed_cb,
    329          new DeferredPacket(this, msg, len, flags, to, internal_socket_),
    330          &timer_handle_);
    331      return 0;
    332    }
    333    return internal_socket_->sendto(msg, len, flags, to);
    334  }
    335 
    336  destroy_stale_port_mappings();
    337 
    338  if (to->protocol == IPPROTO_UDP && nat_->block_udp_) {
    339    return nat_->error_code_for_drop_;
    340  }
    341 
    342  // Choose our port mapping based on our most selective criteria
    343  PortMapping* port_mapping = get_port_mapping(
    344      *to, std::max(nat_->filtering_type_, nat_->mapping_type_));
    345 
    346  if (!port_mapping) {
    347    // See if we have already made the external socket we need to use.
    348    PortMapping* similar_port_mapping =
    349        get_port_mapping(*to, nat_->mapping_type_);
    350    RefPtr<NrSocketBase> external_socket;
    351 
    352    if (similar_port_mapping) {
    353      external_socket = similar_port_mapping->external_socket_;
    354    } else {
    355      external_socket = create_external_socket(*to);
    356      MOZ_RELEASE_ASSERT(external_socket);
    357    }
    358 
    359    port_mapping = create_port_mapping(*to, external_socket);
    360    port_mappings_.push_back(port_mapping);
    361 
    362    if (poll_flags() & PR_POLL_READ) {
    363      // Make sure the new port mapping is ready to receive traffic if the
    364      // TestNrSocket is already waiting.
    365      port_mapping->async_wait(NR_ASYNC_WAIT_READ, socket_readable_callback,
    366                               this, (char*)__FUNCTION__, __LINE__);
    367    }
    368  }
    369 
    370  if (nat_->enabled_ && nat_->network_delay_ms_) {
    371    // nsITimer uses std::function to handle lambdas, but std::function must
    372    // be copyable. That means we cannot use non-copyable captures, even if we
    373    // never actually copy the lambda. Until nsITimer supports bare lambdas,
    374    // we need to use a shared_ptr, instead of using a UniquePtr. Sadface. :(
    375    r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s delaying packet",
    376          internal_socket_->my_addr().as_string);
    377    std::shared_ptr<UdpPacket> packet(new UdpPacket(msg, len, *to));
    378    auto callback = [this, self = RefPtr<TestNrSocket>(this), packet,
    379                     port_mapping =
    380                         RefPtr<PortMapping>(port_mapping)](nsITimer* timer) {
    381      mTimers.RemoveElement(timer);
    382      port_mapping->sendto(packet->buffer_->data(), packet->buffer_->len(),
    383                           packet->remote_address_);
    384    };
    385    auto result = NS_NewTimerWithCallback(
    386        std::move(callback), nat_->network_delay_ms_, nsITimer::TYPE_ONE_SHOT,
    387        "TestNrSocket::sendto"_ns);
    388    if (result.isOk()) {
    389      mTimers.AppendElement(result.unwrap());
    390    }
    391    return 0;
    392  }
    393 
    394  // We probably don't want to propagate the flags, since this is a simulated
    395  // external IP address.
    396  return port_mapping->sendto(msg, len, *to);
    397 }
    398 
    399 int TestNrSocket::recvfrom(void* buf, size_t maxlen, size_t* len, int flags,
    400                           nr_transport_addr* from) {
    401  MOZ_RELEASE_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
    402 
    403  if (!read_buffer_.empty()) {
    404    UdpPacket& packet = read_buffer_.front();
    405    *len = std::min(maxlen, packet.buffer_->len());
    406    memcpy(buf, packet.buffer_->data(), *len);
    407    nr_transport_addr_copy(from, &packet.remote_address_);
    408    read_buffer_.pop_front();
    409    return 0;
    410  }
    411 
    412  int r;
    413  bool ingress_allowed = false;
    414 
    415  if (readable_socket_) {
    416    // If any of the external sockets got data, see if it will be passed through
    417    r = readable_socket_->recvfrom(buf, maxlen, len, 0, from);
    418    const nr_transport_addr to = readable_socket_->my_addr();
    419    readable_socket_ = nullptr;
    420    if (!r) {
    421      PortMapping* port_mapping_used;
    422      ingress_allowed = allow_ingress(to, *from, &port_mapping_used);
    423      if (ingress_allowed) {
    424        r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s received from %s via %s",
    425              internal_socket_->my_addr().as_string, from->as_string,
    426              port_mapping_used->external_socket_->my_addr().as_string);
    427        if (nat_->refresh_on_ingress_) {
    428          port_mapping_used->last_used_ = PR_IntervalNow();
    429        }
    430      }
    431    }
    432  } else {
    433    // If no external socket has data, see if there's any data that was sent
    434    // directly to the TestNrSocket, and eat it if it isn't supposed to get
    435    // through.
    436    r = internal_socket_->recvfrom(buf, maxlen, len, flags, from);
    437    if (!r) {
    438      // We do not use allow_ingress() here because that only handles traffic
    439      // landing on an external port.
    440      ingress_allowed = (!nat_->enabled_ || nat_->is_an_internal_tuple(*from));
    441      if (!ingress_allowed) {
    442        r_log(LOG_GENERIC, LOG_INFO,
    443              "TestNrSocket %s denying ingress from %s: "
    444              "Not behind the same NAT",
    445              internal_socket_->my_addr().as_string, from->as_string);
    446      } else {
    447        r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s received from %s",
    448              internal_socket_->my_addr().as_string, from->as_string);
    449      }
    450    }
    451  }
    452 
    453  // Kinda bad that we are forced to give the app a readable callback and then
    454  // say "Oh, never mind...", but the alternative is to totally decouple the
    455  // callbacks from STS and the callbacks the app sets. On the bright side, this
    456  // speeds up unit tests where we are verifying that ingress is forbidden,
    457  // since they'll get a readable callback and then an error, instead of having
    458  // to wait for a timeout.
    459  if (!ingress_allowed) {
    460    *len = 0;
    461    r = R_WOULDBLOCK;
    462  }
    463 
    464  return r;
    465 }
    466 
    467 bool TestNrSocket::allow_ingress(const nr_transport_addr& to,
    468                                 const nr_transport_addr& from,
    469                                 PortMapping** port_mapping_used) const {
    470  // This is only called for traffic arriving at a port mapping
    471  MOZ_RELEASE_ASSERT(nat_->enabled_);
    472  MOZ_RELEASE_ASSERT(!nat_->is_an_internal_tuple(from));
    473 
    474  // Find the port mapping (if any) that this packet landed on
    475  *port_mapping_used = nullptr;
    476  for (PortMapping* port_mapping : port_mappings_) {
    477    if (!nr_transport_addr_cmp(&to, &port_mapping->external_socket_->my_addr(),
    478                               NR_TRANSPORT_ADDR_CMP_MODE_ALL) &&
    479        !is_port_mapping_stale(*port_mapping)) {
    480      *port_mapping_used = port_mapping;
    481      // TODO: Bug 1857149
    482      // Adding a break here causes test failures, but we would not expect to
    483      // find more than one matching mapping at a time.
    484    }
    485  }
    486 
    487  if (!(*port_mapping_used)) {
    488    r_log(LOG_GENERIC, LOG_INFO,
    489          "TestNrSocket %s denying ingress from %s: "
    490          "No non-stale port mapping for this local port.",
    491          internal_socket_->my_addr().as_string, from.as_string);
    492    return false;
    493  }
    494 
    495  if (!port_mapping_matches(**port_mapping_used, from, nat_->filtering_type_)) {
    496    r_log(LOG_GENERIC, LOG_INFO,
    497          "TestNrSocket %s denying ingress from %s: "
    498          "Filtered (no port mapping for source)",
    499          internal_socket_->my_addr().as_string, from.as_string);
    500    return false;
    501  }
    502 
    503  if (!nat_->allow_hairpinning_ && nat_->is_my_external_tuple(from)) {
    504    r_log(LOG_GENERIC, LOG_INFO,
    505          "TestNrSocket %s denying ingress from %s: "
    506          "Hairpinning disallowed",
    507          internal_socket_->my_addr().as_string, from.as_string);
    508    return false;
    509  }
    510 
    511  return true;
    512 }
    513 
    514 int TestNrSocket::connect(const nr_transport_addr* addr) {
    515  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s connecting to %s", this,
    516        internal_socket_->my_addr().as_string, addr->as_string);
    517 
    518  if (connect_invoked_ || !port_mappings_.empty()) {
    519    MOZ_CRASH("TestNrSocket::connect() called more than once!");
    520    return R_INTERNAL;
    521  }
    522 
    523  if (maybe_get_redirect_targets(addr).isSome()) {
    524    // If we are simulating STUN redirects for |addr|, we need to pretend that
    525    // the TCP connection worked, since |addr| probably does not actually point
    526    // at something that exists.
    527    connect_fake_stun_address_.reset(new nr_transport_addr);
    528    nr_transport_addr_copy(connect_fake_stun_address_.get(), addr);
    529 
    530    // We dispatch this, otherwise nICEr can trip over its shoelaces
    531    GetCurrentSerialEventTarget()->Dispatch(
    532        NS_NewRunnableFunction("Async writeable callback for TestNrSocket",
    533                               [this, self = RefPtr<TestNrSocket>(this)] {
    534                                 if (poll_flags() & PR_POLL_WRITE) {
    535                                   fire_callback(NR_ASYNC_WAIT_WRITE);
    536                                 }
    537                               }));
    538 
    539    return R_WOULDBLOCK;
    540  }
    541 
    542  if (!nat_->enabled_ ||
    543      addr->protocol == IPPROTO_UDP  // Horrible hack to allow default address
    544                                     // discovery to work. Only works because
    545                                     // we don't normally connect on UDP.
    546      || nat_->is_an_internal_tuple(*addr)) {
    547    // This will set connect_invoked_
    548    return internal_socket_->connect(addr);
    549  }
    550 
    551  RefPtr<NrSocketBase> external_socket(create_external_socket(*addr));
    552  if (!external_socket) {
    553    return R_INTERNAL;
    554  }
    555 
    556  PortMapping* port_mapping = create_port_mapping(*addr, external_socket);
    557  port_mappings_.push_back(port_mapping);
    558  int r = port_mapping->external_socket_->connect(addr);
    559  if (r && r != R_WOULDBLOCK) {
    560    return r;
    561  }
    562 
    563  port_mapping->last_used_ = PR_IntervalNow();
    564 
    565  if (poll_flags() & PR_POLL_READ) {
    566    port_mapping->async_wait(NR_ASYNC_WAIT_READ,
    567                             port_mapping_tcp_passthrough_callback, this,
    568                             (char*)__FUNCTION__, __LINE__);
    569  }
    570 
    571  return r;
    572 }
    573 
    574 int TestNrSocket::write(const void* msg, size_t len, size_t* written) {
    575  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s writing", this,
    576        internal_socket_->my_addr().as_string);
    577 
    578  UCHAR* buf = static_cast<UCHAR*>(const_cast<void*>(msg));
    579 
    580  if (nat_->nat_delegate_ &&
    581      nat_->nat_delegate_->on_write(nat_, msg, len, written)) {
    582    return R_INTERNAL;
    583  }
    584 
    585  if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
    586    // Should cause this socket to be abandoned
    587    r_log(LOG_GENERIC, LOG_DEBUG,
    588          "TestNrSocket %s dropping outgoing TCP "
    589          "because it is configured to drop STUN",
    590          my_addr().as_string);
    591    return R_INTERNAL;
    592  }
    593 
    594  if (nr_is_stun_request_message(buf, len) && connect_fake_stun_address_ &&
    595      maybe_send_fake_response(buf, len, connect_fake_stun_address_.get())) {
    596    return 0;
    597  }
    598 
    599  if (nat_->block_tcp_ && !tls_) {
    600    // Should cause this socket to be abandoned
    601    r_log(LOG_GENERIC, LOG_DEBUG,
    602          "TestNrSocket %s dropping outgoing TCP "
    603          "because it is configured to drop TCP",
    604          my_addr().as_string);
    605    return R_INTERNAL;
    606  }
    607 
    608  if (nat_->block_tls_ && tls_) {
    609    // Should cause this socket to be abandoned
    610    r_log(LOG_GENERIC, LOG_DEBUG,
    611          "TestNrSocket %s dropping outgoing TLS "
    612          "because it is configured to drop TLS",
    613          my_addr().as_string);
    614    return R_INTERNAL;
    615  }
    616 
    617  if (port_mappings_.empty()) {
    618    // The no-nat case, just pass call through.
    619    r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s writing",
    620          my_addr().as_string);
    621 
    622    return internal_socket_->write(msg, len, written);
    623  }
    624  destroy_stale_port_mappings();
    625  if (port_mappings_.empty()) {
    626    r_log(LOG_GENERIC, LOG_DEBUG,
    627          "TestNrSocket %s dropping outgoing TCP "
    628          "because the port mapping was stale",
    629          my_addr().as_string);
    630    return R_INTERNAL;
    631  }
    632  // This is TCP only
    633  MOZ_RELEASE_ASSERT(port_mappings_.size() == 1);
    634  r_log(LOG_GENERIC, LOG_DEBUG, "PortMapping %s -> %s writing",
    635        port_mappings_.front()->external_socket_->my_addr().as_string,
    636        port_mappings_.front()->remote_address_.as_string);
    637  port_mappings_.front()->last_used_ = PR_IntervalNow();
    638  return port_mappings_.front()->external_socket_->write(msg, len, written);
    639 }
    640 
    641 int TestNrSocket::read(void* buf, size_t maxlen, size_t* len) {
    642  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s reading", this,
    643        internal_socket_->my_addr().as_string);
    644 
    645  if (!read_buffer_.empty()) {
    646    r_log(LOG_GENERIC, LOG_DEBUG,
    647          "TestNrSocket %p %s has stuff in read_buffer_", this,
    648          internal_socket_->my_addr().as_string);
    649    UdpPacket packet(std::move(read_buffer_.front()));
    650    read_buffer_.pop_front();
    651    *len = std::min(maxlen, packet.buffer_->len());
    652    memcpy(buf, packet.buffer_->data(), *len);
    653    if (*len != packet.buffer_->len()) {
    654      // Put remaining bytes in new packet, at the front.
    655      read_buffer_.emplace_front(packet.buffer_->data() + *len,
    656                                 packet.buffer_->len() - *len,
    657                                 packet.remote_address_);
    658    }
    659    return 0;
    660  }
    661 
    662  if (connect_fake_stun_address_) {
    663    return R_WOULDBLOCK;
    664  }
    665 
    666  int r;
    667 
    668  if (port_mappings_.empty()) {
    669    r = internal_socket_->read(buf, maxlen, len);
    670  } else {
    671    MOZ_RELEASE_ASSERT(port_mappings_.size() == 1);
    672    r = port_mappings_.front()->external_socket_->read(buf, maxlen, len);
    673    if (!r && nat_->refresh_on_ingress_) {
    674      port_mappings_.front()->last_used_ = PR_IntervalNow();
    675    }
    676  }
    677 
    678  if (r) {
    679    return r;
    680  }
    681 
    682  if (nat_->nat_delegate_ &&
    683      nat_->nat_delegate_->on_read(nat_, buf, maxlen, len)) {
    684    return R_INTERNAL;
    685  }
    686 
    687  if (nat_->block_tcp_ && !tls_) {
    688    // Should cause this socket to be abandoned
    689    return R_INTERNAL;
    690  }
    691 
    692  if (nat_->block_tls_ && tls_) {
    693    // Should cause this socket to be abandoned
    694    return R_INTERNAL;
    695  }
    696 
    697  UCHAR* cbuf = static_cast<UCHAR*>(const_cast<void*>(buf));
    698  if (nat_->block_stun_ && nr_is_stun_message(cbuf, *len)) {
    699    // Should cause this socket to be abandoned
    700    return R_INTERNAL;
    701  }
    702 
    703  return r;
    704 }
    705 
    706 int TestNrSocket::async_wait(int how, NR_async_cb cb, void* cb_arg,
    707                             char* function, int line) {
    708  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s waiting for %s",
    709        internal_socket_->my_addr().as_string,
    710        how == NR_ASYNC_WAIT_READ ? "read" : "write");
    711 
    712  int r;
    713 
    714  if (how == NR_ASYNC_WAIT_READ) {
    715    NrSocketBase::async_wait(how, cb, cb_arg, function, line);
    716    if (!read_buffer_.empty()) {
    717      fire_readable_callback();
    718      return 0;
    719    }
    720 
    721    // Make sure we're waiting on the socket for the internal address
    722    r = internal_socket_->async_wait(how, socket_readable_callback, this,
    723                                     function, line);
    724  } else {
    725    if (connect_fake_stun_address_) {
    726      // Fake TCP connection case; register the callback on this socket, not
    727      // a real one.
    728      return NrSocketBase::async_wait(how, cb, cb_arg, function, line);
    729    }
    730 
    731    // For write, just use the readiness of the internal socket, since we queue
    732    // everything for the port mappings.
    733    r = internal_socket_->async_wait(how, cb, cb_arg, function, line);
    734  }
    735 
    736  if (r) {
    737    r_log(LOG_GENERIC, LOG_ERR,
    738          "TestNrSocket %s failed to async_wait for "
    739          "internal socket: %d\n",
    740          internal_socket_->my_addr().as_string, r);
    741    return r;
    742  }
    743 
    744  if (is_tcp_connection_behind_nat()) {
    745    // Bypass all port-mapping related logic
    746    return 0;
    747  }
    748 
    749  if (internal_socket_->my_addr().protocol == IPPROTO_TCP) {
    750    // For a TCP connection through a simulated NAT, these signals are
    751    // just passed through.
    752    MOZ_RELEASE_ASSERT(port_mappings_.size() == 1);
    753 
    754    return port_mappings_.front()->async_wait(
    755        how, port_mapping_tcp_passthrough_callback, this, function, line);
    756  }
    757  if (how == NR_ASYNC_WAIT_READ) {
    758    // For UDP port mappings, we decouple the writeable callbacks
    759    for (PortMapping* port_mapping : port_mappings_) {
    760      // Be ready to receive traffic on our port mappings
    761      r = port_mapping->async_wait(how, socket_readable_callback, this,
    762                                   function, line);
    763      if (r) {
    764        r_log(LOG_GENERIC, LOG_ERR,
    765              "TestNrSocket %s failed to async_wait for "
    766              "port mapping: %d\n",
    767              internal_socket_->my_addr().as_string, r);
    768        return r;
    769      }
    770    }
    771  }
    772 
    773  return 0;
    774 }
    775 
    776 void TestNrSocket::cancel_port_mapping_async_wait(int how) {
    777  for (PortMapping* port_mapping : port_mappings_) {
    778    port_mapping->cancel(how);
    779  }
    780 }
    781 
    782 int TestNrSocket::cancel(int how) {
    783  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s stop waiting for %s",
    784        internal_socket_->my_addr().as_string,
    785        how == NR_ASYNC_WAIT_READ ? "read" : "write");
    786 
    787  if (connect_fake_stun_address_) {
    788    return NrSocketBase::cancel(how);
    789  }
    790 
    791  // Writable callbacks are decoupled except for the TCP case
    792  if (how == NR_ASYNC_WAIT_READ ||
    793      internal_socket_->my_addr().protocol == IPPROTO_TCP) {
    794    cancel_port_mapping_async_wait(how);
    795  }
    796 
    797  return internal_socket_->cancel(how);
    798 }
    799 
    800 bool TestNrSocket::has_port_mappings() const { return !port_mappings_.empty(); }
    801 
    802 bool TestNrSocket::is_my_external_tuple(const nr_transport_addr& addr) const {
    803  for (PortMapping* port_mapping : port_mappings_) {
    804    nr_transport_addr port_mapping_addr;
    805    if (port_mapping->external_socket_->getaddr(&port_mapping_addr)) {
    806      MOZ_CRASH("NrSocket::getaddr failed!");
    807    }
    808 
    809    if (!nr_transport_addr_cmp(&addr, &port_mapping_addr,
    810                               NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
    811      return true;
    812    }
    813  }
    814  return false;
    815 }
    816 
    817 bool TestNrSocket::is_port_mapping_stale(
    818    const PortMapping& port_mapping) const {
    819  PRIntervalTime now = PR_IntervalNow();
    820  PRIntervalTime elapsed_ticks = now - port_mapping.last_used_;
    821  uint32_t idle_duration = PR_IntervalToMilliseconds(elapsed_ticks);
    822  r_log(LOG_GENERIC, LOG_INFO,
    823        "TestNrSocket %s port mapping %s -> %s last used %u",
    824        internal_socket_->my_addr().as_string,
    825        port_mapping.external_socket_->my_addr().as_string,
    826        port_mapping.remote_address_.as_string,
    827        static_cast<unsigned>(idle_duration));
    828  return idle_duration > nat_->mapping_timeout_;
    829 }
    830 
    831 void TestNrSocket::destroy_stale_port_mappings() {
    832  for (auto i = port_mappings_.begin(); i != port_mappings_.end();) {
    833    auto temp = i;
    834    ++i;
    835    if (is_port_mapping_stale(**temp)) {
    836      r_log(LOG_GENERIC, LOG_INFO,
    837            "TestNrSocket %s destroying port mapping %s -> %s",
    838            internal_socket_->my_addr().as_string,
    839            (*temp)->external_socket_->my_addr().as_string,
    840            (*temp)->remote_address_.as_string);
    841 
    842      port_mappings_.erase(temp);
    843    }
    844  }
    845 }
    846 
    847 void TestNrSocket::socket_readable_callback(void* real_sock_v, int how,
    848                                            void* test_sock_v) {
    849  TestNrSocket* test_socket = static_cast<TestNrSocket*>(test_sock_v);
    850  NrSocketBase* real_socket = static_cast<NrSocketBase*>(real_sock_v);
    851 
    852  test_socket->on_socket_readable(real_socket);
    853 }
    854 
    855 void TestNrSocket::on_socket_readable(NrSocketBase* real_socket) {
    856  if (!readable_socket_ && (real_socket != internal_socket_)) {
    857    readable_socket_ = real_socket;
    858  }
    859 
    860  fire_readable_callback();
    861 }
    862 
    863 void TestNrSocket::fire_readable_callback() {
    864  MOZ_RELEASE_ASSERT(poll_flags() & PR_POLL_READ);
    865  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %p %s ready for read", this,
    866        internal_socket_->my_addr().as_string);
    867  fire_callback(NR_ASYNC_WAIT_READ);
    868 }
    869 
    870 void TestNrSocket::port_mapping_writeable_callback(void* ext_sock_v, int how,
    871                                                   void* test_sock_v) {
    872  TestNrSocket* test_socket = static_cast<TestNrSocket*>(test_sock_v);
    873  NrSocketBase* external_socket = static_cast<NrSocketBase*>(ext_sock_v);
    874 
    875  test_socket->write_to_port_mapping(external_socket);
    876 }
    877 
    878 void TestNrSocket::write_to_port_mapping(NrSocketBase* external_socket) {
    879  MOZ_RELEASE_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
    880 
    881  int r = 0;
    882  for (PortMapping* port_mapping : port_mappings_) {
    883    if (port_mapping->external_socket_ == external_socket) {
    884      // If the send succeeds, or if there was nothing to send, we keep going
    885      r = port_mapping->send_from_queue();
    886      if (r) {
    887        break;
    888      }
    889    }
    890  }
    891 
    892  if (r == R_WOULDBLOCK) {
    893    // Re-register for writeable callbacks, since we still have stuff to send
    894    NR_ASYNC_WAIT(external_socket, NR_ASYNC_WAIT_WRITE,
    895                  &TestNrSocket::port_mapping_writeable_callback, this);
    896  }
    897 }
    898 
    899 void TestNrSocket::port_mapping_tcp_passthrough_callback(void* ext_sock_v,
    900                                                         int how,
    901                                                         void* test_sock_v) {
    902  TestNrSocket* test_socket = static_cast<TestNrSocket*>(test_sock_v);
    903  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s firing %s callback",
    904        test_socket->internal_socket_->my_addr().as_string,
    905        how == NR_ASYNC_WAIT_READ ? "readable" : "writeable");
    906 
    907  test_socket->internal_socket_->fire_callback(how);
    908 }
    909 
    910 bool TestNrSocket::is_tcp_connection_behind_nat() const {
    911  return internal_socket_->my_addr().protocol == IPPROTO_TCP &&
    912         port_mappings_.empty();
    913 }
    914 
    915 TestNrSocket::PortMapping* TestNrSocket::get_port_mapping(
    916    const nr_transport_addr& remote_address,
    917    TestNat::NatBehavior filter) const {
    918  for (PortMapping* port_mapping : port_mappings_) {
    919    if (port_mapping_matches(*port_mapping, remote_address, filter)) {
    920      return port_mapping;
    921    }
    922  }
    923  return nullptr;
    924 }
    925 
    926 /* static */
    927 bool TestNrSocket::port_mapping_matches(const PortMapping& port_mapping,
    928                                        const nr_transport_addr& remote_addr,
    929                                        TestNat::NatBehavior filter) {
    930  int compare_flags;
    931  switch (filter) {
    932    case TestNat::ENDPOINT_INDEPENDENT:
    933      compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL;
    934      break;
    935    case TestNat::ADDRESS_DEPENDENT:
    936      compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_ADDR;
    937      break;
    938    case TestNat::PORT_DEPENDENT:
    939      compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_ALL;
    940      break;
    941  }
    942 
    943  return !nr_transport_addr_cmp(&remote_addr, &port_mapping.remote_address_,
    944                                compare_flags);
    945 }
    946 
    947 TestNrSocket::PortMapping* TestNrSocket::create_port_mapping(
    948    const nr_transport_addr& remote_address,
    949    const RefPtr<NrSocketBase>& external_socket) const {
    950  r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s creating port mapping %s -> %s",
    951        internal_socket_->my_addr().as_string,
    952        external_socket->my_addr().as_string, remote_address.as_string);
    953 
    954  return new PortMapping(remote_address, external_socket);
    955 }
    956 
    957 TestNrSocket::PortMapping::PortMapping(
    958    const nr_transport_addr& remote_address,
    959    const RefPtr<NrSocketBase>& external_socket)
    960    : external_socket_(external_socket) {
    961  nr_transport_addr_copy(&remote_address_, &remote_address);
    962 }
    963 
    964 int TestNrSocket::PortMapping::send_from_queue() {
    965  MOZ_RELEASE_ASSERT(remote_address_.protocol != IPPROTO_TCP);
    966  int r = 0;
    967 
    968  while (!send_queue_.empty()) {
    969    UdpPacket& packet = send_queue_.front();
    970    r_log(LOG_GENERIC, LOG_DEBUG,
    971          "PortMapping %s -> %s sending from queue to %s",
    972          external_socket_->my_addr().as_string, remote_address_.as_string,
    973          packet.remote_address_.as_string);
    974 
    975    r = external_socket_->sendto(packet.buffer_->data(), packet.buffer_->len(),
    976                                 0, &packet.remote_address_);
    977 
    978    if (r) {
    979      if (r != R_WOULDBLOCK) {
    980        r_log(LOG_GENERIC, LOG_ERR, "%s: Fatal error %d, stop trying",
    981              __FUNCTION__, r);
    982        send_queue_.clear();
    983      } else {
    984        r_log(LOG_GENERIC, LOG_DEBUG, "Would block, will retry later");
    985      }
    986      break;
    987    }
    988 
    989    send_queue_.pop_front();
    990  }
    991 
    992  return r;
    993 }
    994 
    995 int TestNrSocket::PortMapping::sendto(const void* msg, size_t len,
    996                                      const nr_transport_addr& to) {
    997  MOZ_RELEASE_ASSERT(remote_address_.protocol != IPPROTO_TCP);
    998  r_log(LOG_GENERIC, LOG_DEBUG, "PortMapping %s -> %s sending to %s",
    999        external_socket_->my_addr().as_string, remote_address_.as_string,
   1000        to.as_string);
   1001 
   1002  last_used_ = PR_IntervalNow();
   1003  int r = external_socket_->sendto(msg, len, 0, &to);
   1004 
   1005  if (r == R_WOULDBLOCK) {
   1006    r_log(LOG_GENERIC, LOG_DEBUG, "Enqueueing UDP packet to %s", to.as_string);
   1007    send_queue_.emplace_back(msg, len, to);
   1008    return 0;
   1009  }
   1010  if (r) {
   1011    r_log(LOG_GENERIC, LOG_ERR, "Error: %d", r);
   1012  }
   1013 
   1014  return r;
   1015 }
   1016 
   1017 int TestNrSocket::PortMapping::async_wait(int how, NR_async_cb cb, void* cb_arg,
   1018                                          char* function, int line) {
   1019  r_log(LOG_GENERIC, LOG_DEBUG, "PortMapping %s -> %s waiting for %s",
   1020        external_socket_->my_addr().as_string, remote_address_.as_string,
   1021        how == NR_ASYNC_WAIT_READ ? "read" : "write");
   1022 
   1023  return external_socket_->async_wait(how, cb, cb_arg, function, line);
   1024 }
   1025 
   1026 int TestNrSocket::PortMapping::cancel(int how) {
   1027  r_log(LOG_GENERIC, LOG_DEBUG, "PortMapping %s -> %s stop waiting for %s",
   1028        external_socket_->my_addr().as_string, remote_address_.as_string,
   1029        how == NR_ASYNC_WAIT_READ ? "read" : "write");
   1030 
   1031  return external_socket_->cancel(how);
   1032 }
   1033 
   1034 class nr_stun_message_deleter {
   1035 public:
   1036  nr_stun_message_deleter() = default;
   1037  void operator()(nr_stun_message* msg) const { nr_stun_message_destroy(&msg); }
   1038 };
   1039 
   1040 bool TestNrSocket::maybe_send_fake_response(const void* msg, size_t len,
   1041                                            const nr_transport_addr* to) {
   1042  Maybe<nsTArray<nsCString>> redirect_targets = maybe_get_redirect_targets(to);
   1043  if (!redirect_targets.isSome()) {
   1044    return false;
   1045  }
   1046 
   1047  std::unique_ptr<nr_stun_message, nr_stun_message_deleter> request;
   1048  {
   1049    nr_stun_message* temp = nullptr;
   1050    if (NS_WARN_IF(nr_stun_message_create2(&temp, (unsigned char*)msg, len))) {
   1051      return false;
   1052    }
   1053    request.reset(temp);
   1054  }
   1055 
   1056  if (NS_WARN_IF(nr_stun_decode_message(request.get(), nullptr, nullptr))) {
   1057    return false;
   1058  }
   1059 
   1060  std::unique_ptr<nr_stun_message, nr_stun_message_deleter> response;
   1061  {
   1062    nr_stun_message* temp = nullptr;
   1063    if (nr_stun_message_create(&temp)) {
   1064      MOZ_CRASH("nr_stun_message_create failed!");
   1065    }
   1066    response.reset(temp);
   1067  }
   1068 
   1069  nr_stun_form_error_response(request.get(), response.get(), 300,
   1070                              (char*)"Try alternate");
   1071 
   1072  int port = 0;
   1073  if (nr_transport_addr_get_port(to, &port)) {
   1074    MOZ_CRASH();
   1075  }
   1076 
   1077  for (const nsCString& address : *redirect_targets) {
   1078    r_log(LOG_GENERIC, LOG_DEBUG,
   1079          "TestNrSocket attempting to add alternate server %s", address.Data());
   1080    nr_transport_addr addr;
   1081    if (NS_WARN_IF(nr_str_port_to_transport_addr(address.Data(), port,
   1082                                                 IPPROTO_UDP, &addr))) {
   1083      continue;
   1084    }
   1085    if (nr_stun_message_add_alternate_server_attribute(response.get(), &addr)) {
   1086      MOZ_CRASH("nr_stun_message_add_alternate_server_attribute failed!");
   1087    }
   1088  }
   1089 
   1090  if (nr_stun_encode_message(response.get())) {
   1091    MOZ_CRASH("nr_stun_encode_message failed!");
   1092  }
   1093 
   1094  nr_transport_addr response_from;
   1095  if (nr_transport_addr_is_wildcard(to)) {
   1096    // |to| points to an FQDN, and nICEr is delegating DNS lookup to us; we
   1097    // aren't _actually_ going to do that though, so we select a bogus address
   1098    // for the response to come from. TEST-NET is a fairly reasonable thing to
   1099    // use for this.
   1100    int port = 0;
   1101    if (nr_transport_addr_get_port(to, &port)) {
   1102      MOZ_CRASH();
   1103    }
   1104    switch (to->ip_version) {
   1105      case NR_IPV4:
   1106        if (nr_str_port_to_transport_addr("198.51.100.1", port, to->protocol,
   1107                                          &response_from)) {
   1108          MOZ_CRASH();
   1109        }
   1110        break;
   1111      case NR_IPV6:
   1112        if (nr_str_port_to_transport_addr("::ffff:198.51.100.1", port,
   1113                                          to->protocol, &response_from)) {
   1114          MOZ_CRASH();
   1115        }
   1116        break;
   1117      default:
   1118        MOZ_CRASH();
   1119    }
   1120  } else {
   1121    nr_transport_addr_copy(&response_from, to);
   1122  }
   1123 
   1124  read_buffer_.emplace_back(response->buffer, response->length, response_from);
   1125 
   1126  // We dispatch this, otherwise nICEr can trip over its shoelaces
   1127  r_log(LOG_GENERIC, LOG_DEBUG,
   1128        "TestNrSocket %p scheduling callback for redirect response", this);
   1129  GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
   1130      "Async readable callback for TestNrSocket",
   1131      [this, self = RefPtr<TestNrSocket>(this)] {
   1132        if (poll_flags() & PR_POLL_READ) {
   1133          fire_readable_callback();
   1134        } else {
   1135          r_log(LOG_GENERIC, LOG_DEBUG,
   1136                "TestNrSocket %p deferring callback for redirect response",
   1137                this);
   1138        }
   1139      }));
   1140 
   1141  return true;
   1142 }
   1143 
   1144 Maybe<nsTArray<nsCString>> TestNrSocket::maybe_get_redirect_targets(
   1145    const nr_transport_addr* to) const {
   1146  Maybe<nsTArray<nsCString>> result;
   1147 
   1148  // 256 is overkill, but it hardly matters
   1149  char addrstring[256];
   1150  if (nr_transport_addr_get_addrstring(to, addrstring, 256)) {
   1151    MOZ_CRASH("nr_transport_addr_get_addrstring failed!");
   1152  }
   1153 
   1154  r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket checking redirect rules for %s",
   1155        addrstring);
   1156  auto it = nat_->stun_redirect_map_.find(nsCString(addrstring));
   1157  if (it != nat_->stun_redirect_map_.end()) {
   1158    result = Some(it->second);
   1159  }
   1160 
   1161  return result;
   1162 }
   1163 
   1164 }  // namespace mozilla