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