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