Line data Source code
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_hint.h"
91 : #include "transport_addr.h"
92 : }
93 :
94 : #include "mozilla/RefPtr.h"
95 : #include "test_nr_socket.h"
96 : #include "runnable_utils.h"
97 :
98 : namespace mozilla {
99 :
100 0 : static int test_nat_socket_create(void *obj,
101 : nr_transport_addr *addr,
102 : nr_socket **sockp) {
103 0 : RefPtr<NrSocketBase> sock = new TestNrSocket(static_cast<TestNat*>(obj));
104 :
105 : int r, _status;
106 :
107 0 : r = sock->create(addr);
108 0 : if (r)
109 0 : ABORT(r);
110 :
111 0 : r = nr_socket_create_int(static_cast<void *>(sock),
112 0 : sock->vtbl(), sockp);
113 0 : if (r)
114 0 : ABORT(r);
115 :
116 0 : _status = 0;
117 :
118 : {
119 : // We will release this reference in destroy(), not exactly the normal
120 : // ownership model, but it is what it is.
121 0 : NrSocketBase *dummy = sock.forget().take();
122 : (void)dummy;
123 : }
124 :
125 : abort:
126 0 : return _status;
127 : }
128 :
129 0 : static int test_nat_socket_factory_destroy(void **obj) {
130 0 : TestNat *nat = static_cast<TestNat*>(*obj);
131 0 : *obj = nullptr;
132 0 : nat->Release();
133 0 : return 0;
134 : }
135 :
136 : static nr_socket_factory_vtbl test_nat_socket_factory_vtbl = {
137 : test_nat_socket_create,
138 : test_nat_socket_factory_destroy
139 : };
140 :
141 : /* static */
142 : TestNat::NatBehavior
143 0 : TestNat::ToNatBehavior(const std::string& type) {
144 0 : if (!type.compare("ENDPOINT_INDEPENDENT")) {
145 0 : return TestNat::ENDPOINT_INDEPENDENT;
146 : }
147 0 : if (!type.compare("ADDRESS_DEPENDENT")) {
148 0 : return TestNat::ADDRESS_DEPENDENT;
149 : }
150 0 : if (!type.compare("PORT_DEPENDENT")) {
151 0 : return TestNat::PORT_DEPENDENT;
152 : }
153 :
154 0 : MOZ_ASSERT(false, "Invalid NAT behavior");
155 : return TestNat::ENDPOINT_INDEPENDENT;
156 : }
157 :
158 0 : bool TestNat::has_port_mappings() const {
159 0 : for (TestNrSocket *sock : sockets_) {
160 0 : if (sock->has_port_mappings()) {
161 0 : return true;
162 : }
163 : }
164 0 : return false;
165 : }
166 :
167 0 : bool TestNat::is_my_external_tuple(const nr_transport_addr &addr) const {
168 0 : for (TestNrSocket *sock : sockets_) {
169 0 : if (sock->is_my_external_tuple(addr)) {
170 0 : return true;
171 : }
172 : }
173 :
174 0 : return false;
175 : }
176 :
177 0 : bool TestNat::is_an_internal_tuple(const nr_transport_addr &addr) const {
178 0 : for (TestNrSocket *sock : sockets_) {
179 : nr_transport_addr addr_behind_nat;
180 0 : if (sock->getaddr(&addr_behind_nat)) {
181 0 : MOZ_CRASH("TestNrSocket::getaddr failed!");
182 : }
183 :
184 : // TODO(bug 1170299): Remove const_cast when no longer necessary
185 0 : if (!nr_transport_addr_cmp(const_cast<nr_transport_addr*>(&addr),
186 : &addr_behind_nat,
187 : NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
188 0 : return true;
189 : }
190 : }
191 0 : return false;
192 : }
193 :
194 0 : int TestNat::create_socket_factory(nr_socket_factory **factorypp) {
195 : int r = nr_socket_factory_create_int(this,
196 : &test_nat_socket_factory_vtbl,
197 0 : factorypp);
198 0 : if (!r) {
199 0 : AddRef();
200 : }
201 0 : return r;
202 : }
203 :
204 0 : TestNrSocket::TestNrSocket(TestNat *nat)
205 : : nat_(nat),
206 : tls_(false),
207 0 : timer_handle_(nullptr) {
208 0 : nat_->insert_socket(this);
209 0 : }
210 :
211 0 : TestNrSocket::~TestNrSocket() {
212 0 : nat_->erase_socket(this);
213 0 : }
214 :
215 0 : RefPtr<NrSocketBase> TestNrSocket::create_external_socket(
216 : const nr_transport_addr &dest_addr) const {
217 0 : MOZ_ASSERT(nat_->enabled_);
218 0 : MOZ_ASSERT(!nat_->is_an_internal_tuple(dest_addr));
219 :
220 : int r;
221 : nr_transport_addr nat_external_addr;
222 :
223 : // Open the socket on an arbitrary port, on the same address.
224 : // TODO(bug 1170299): Remove const_cast when no longer necessary
225 0 : if ((r = nr_transport_addr_copy(
226 : &nat_external_addr,
227 0 : const_cast<nr_transport_addr*>(&internal_socket_->my_addr())))) {
228 : r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_copy: %d",
229 0 : __FUNCTION__, r);
230 0 : return nullptr;
231 : }
232 :
233 0 : if ((r = nr_transport_addr_set_port(&nat_external_addr, 0))) {
234 : r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in nr_transport_addr_set_port: %d",
235 0 : __FUNCTION__, r);
236 0 : return nullptr;
237 : }
238 :
239 0 : RefPtr<NrSocketBase> external_socket;
240 0 : r = NrSocketBase::CreateSocket(&nat_external_addr, &external_socket);
241 :
242 0 : if (r) {
243 : r_log(LOG_GENERIC,LOG_CRIT, "%s: Failure in NrSocket::create: %d",
244 0 : __FUNCTION__, r);
245 0 : return nullptr;
246 : }
247 :
248 0 : return external_socket;
249 : }
250 :
251 0 : int TestNrSocket::create(nr_transport_addr *addr) {
252 0 : if (addr->tls_host[0] != '\0') {
253 0 : tls_ = true;
254 : }
255 :
256 0 : return NrSocketBase::CreateSocket(addr, &internal_socket_);
257 : }
258 :
259 0 : int TestNrSocket::getaddr(nr_transport_addr *addrp) {
260 0 : return internal_socket_->getaddr(addrp);
261 : }
262 :
263 0 : void TestNrSocket::close() {
264 0 : if (timer_handle_) {
265 0 : NR_async_timer_cancel(timer_handle_);
266 0 : timer_handle_ = nullptr;
267 : }
268 0 : internal_socket_->close();
269 0 : for (RefPtr<PortMapping>& port_mapping : port_mappings_) {
270 0 : port_mapping->external_socket_->close();
271 : }
272 0 : }
273 :
274 0 : int TestNrSocket::listen(int backlog) {
275 0 : MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
276 0 : r_log(LOG_GENERIC, LOG_DEBUG,
277 : "TestNrSocket %s listening",
278 0 : internal_socket_->my_addr().as_string);
279 :
280 0 : return internal_socket_->listen(backlog);
281 : }
282 :
283 0 : int TestNrSocket::accept(nr_transport_addr *addrp, nr_socket **sockp) {
284 0 : MOZ_ASSERT(internal_socket_->my_addr().protocol == IPPROTO_TCP);
285 0 : int r = internal_socket_->accept(addrp, sockp);
286 0 : if (r) {
287 0 : return r;
288 : }
289 :
290 0 : if (nat_->enabled_ && !nat_->is_an_internal_tuple(*addrp)) {
291 0 : nr_socket_destroy(sockp);
292 0 : return R_IO_ERROR;
293 : }
294 :
295 0 : return 0;
296 : }
297 :
298 0 : void TestNrSocket::process_delayed_cb(NR_SOCKET s, int how, void *cb_arg) {
299 0 : DeferredPacket *op = static_cast<DeferredPacket *>(cb_arg);
300 0 : op->socket_->timer_handle_ = nullptr;
301 0 : r_log(LOG_GENERIC, LOG_DEBUG,
302 : "TestNrSocket %s sending delayed STUN response",
303 0 : op->internal_socket_->my_addr().as_string);
304 0 : op->internal_socket_->sendto(op->buffer_.data(), op->buffer_.len(),
305 0 : op->flags_, &op->to_);
306 :
307 0 : delete op;
308 0 : }
309 :
310 0 : int TestNrSocket::sendto(const void *msg, size_t len,
311 : int flags, nr_transport_addr *to) {
312 0 : MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
313 :
314 0 : if (nat_->nat_delegate_ && nat_->nat_delegate_->on_sendto(nat_, msg, len, flags, to)) {
315 0 : return 0;
316 : }
317 :
318 0 : UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
319 0 : if (nat_->block_stun_ &&
320 0 : nr_is_stun_message(buf, len)) {
321 0 : return 0;
322 : }
323 :
324 : /* TODO: improve the functionality of this in bug 1253657 */
325 0 : if (!nat_->enabled_ || nat_->is_an_internal_tuple(*to)) {
326 0 : if (nat_->delay_stun_resp_ms_ &&
327 0 : nr_is_stun_response_message(buf, len)) {
328 0 : NR_ASYNC_TIMER_SET(nat_->delay_stun_resp_ms_,
329 : process_delayed_cb,
330 : new DeferredPacket(this, msg, len, flags, to,
331 : internal_socket_),
332 0 : &timer_handle_);
333 0 : return 0;
334 : }
335 0 : return internal_socket_->sendto(msg, len, flags, to);
336 : }
337 :
338 0 : destroy_stale_port_mappings();
339 :
340 0 : if (to->protocol == IPPROTO_UDP && nat_->block_udp_) {
341 : // Silently eat the packet
342 0 : return 0;
343 : }
344 :
345 : // Choose our port mapping based on our most selective criteria
346 0 : PortMapping *port_mapping = get_port_mapping(*to,
347 0 : std::max(nat_->filtering_type_,
348 0 : nat_->mapping_type_));
349 :
350 0 : if (!port_mapping) {
351 : // See if we have already made the external socket we need to use.
352 : PortMapping *similar_port_mapping =
353 0 : get_port_mapping(*to, nat_->mapping_type_);
354 0 : RefPtr<NrSocketBase> external_socket;
355 :
356 0 : if (similar_port_mapping) {
357 0 : external_socket = similar_port_mapping->external_socket_;
358 : } else {
359 0 : external_socket = create_external_socket(*to);
360 0 : if (!external_socket) {
361 0 : MOZ_ASSERT(false);
362 : return R_INTERNAL;
363 : }
364 : }
365 :
366 0 : port_mapping = create_port_mapping(*to, external_socket);
367 0 : port_mappings_.push_back(port_mapping);
368 :
369 0 : if (poll_flags() & PR_POLL_READ) {
370 : // Make sure the new port mapping is ready to receive traffic if the
371 : // TestNrSocket is already waiting.
372 : port_mapping->async_wait(NR_ASYNC_WAIT_READ,
373 : socket_readable_callback,
374 : this,
375 : (char*)__FUNCTION__,
376 0 : __LINE__);
377 : }
378 : }
379 :
380 : // We probably don't want to propagate the flags, since this is a simulated
381 : // external IP address.
382 0 : return port_mapping->sendto(msg, len, *to);
383 : }
384 :
385 0 : int TestNrSocket::recvfrom(void *buf, size_t maxlen,
386 : size_t *len, int flags,
387 : nr_transport_addr *from) {
388 0 : MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
389 :
390 : int r;
391 0 : bool ingress_allowed = false;
392 :
393 0 : if (readable_socket_) {
394 : // If any of the external sockets got data, see if it will be passed through
395 0 : r = readable_socket_->recvfrom(buf, maxlen, len, 0, from);
396 0 : readable_socket_ = nullptr;
397 0 : if (!r) {
398 : PortMapping *port_mapping_used;
399 0 : ingress_allowed = allow_ingress(*from, &port_mapping_used);
400 0 : if (ingress_allowed) {
401 0 : r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s received from %s via %s",
402 0 : internal_socket_->my_addr().as_string,
403 : from->as_string,
404 0 : port_mapping_used->external_socket_->my_addr().as_string);
405 0 : if (nat_->refresh_on_ingress_) {
406 0 : port_mapping_used->last_used_ = PR_IntervalNow();
407 : }
408 : }
409 : }
410 : } else {
411 : // If no external socket has data, see if there's any data that was sent
412 : // directly to the TestNrSocket, and eat it if it isn't supposed to get
413 : // through.
414 0 : r = internal_socket_->recvfrom(buf, maxlen, len, flags, from);
415 0 : if (!r) {
416 : // We do not use allow_ingress() here because that only handles traffic
417 : // landing on an external port.
418 0 : ingress_allowed = (!nat_->enabled_ ||
419 0 : nat_->is_an_internal_tuple(*from));
420 0 : if (!ingress_allowed) {
421 0 : r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
422 : "Not behind the same NAT",
423 0 : internal_socket_->my_addr().as_string,
424 0 : from->as_string);
425 : } else {
426 0 : r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s received from %s",
427 0 : internal_socket_->my_addr().as_string,
428 0 : from->as_string);
429 : }
430 : }
431 : }
432 :
433 : // Kinda lame that we are forced to give the app a readable callback and then
434 : // say "Oh, never mind...", but the alternative is to totally decouple the
435 : // callbacks from STS and the callbacks the app sets. On the bright side, this
436 : // speeds up unit tests where we are verifying that ingress is forbidden,
437 : // since they'll get a readable callback and then an error, instead of having
438 : // to wait for a timeout.
439 0 : if (!ingress_allowed) {
440 0 : *len = 0;
441 0 : r = R_WOULDBLOCK;
442 : }
443 :
444 0 : return r;
445 : }
446 :
447 0 : bool TestNrSocket::allow_ingress(const nr_transport_addr &from,
448 : PortMapping **port_mapping_used) const {
449 : // This is only called for traffic arriving at a port mapping
450 0 : MOZ_ASSERT(nat_->enabled_);
451 0 : MOZ_ASSERT(!nat_->is_an_internal_tuple(from));
452 :
453 0 : *port_mapping_used = get_port_mapping(from, nat_->filtering_type_);
454 0 : if (!(*port_mapping_used)) {
455 0 : r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
456 : "Filtered",
457 0 : internal_socket_->my_addr().as_string,
458 0 : from.as_string);
459 0 : return false;
460 : }
461 :
462 0 : if (is_port_mapping_stale(**port_mapping_used)) {
463 0 : r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
464 : "Stale port mapping",
465 0 : internal_socket_->my_addr().as_string,
466 0 : from.as_string);
467 0 : return false;
468 : }
469 :
470 0 : if (!nat_->allow_hairpinning_ && nat_->is_my_external_tuple(from)) {
471 0 : r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s denying ingress from %s: "
472 : "Hairpinning disallowed",
473 0 : internal_socket_->my_addr().as_string,
474 0 : from.as_string);
475 0 : return false;
476 : }
477 :
478 0 : return true;
479 : }
480 :
481 0 : int TestNrSocket::connect(nr_transport_addr *addr) {
482 :
483 0 : if (connect_invoked_ || !port_mappings_.empty()) {
484 0 : MOZ_CRASH("TestNrSocket::connect() called more than once!");
485 : return R_INTERNAL;
486 : }
487 :
488 0 : if (!nat_->enabled_
489 0 : || addr->protocol==IPPROTO_UDP // Horrible hack to allow default address
490 : // discovery to work. Only works because
491 : // we don't normally connect on UDP.
492 0 : || nat_->is_an_internal_tuple(*addr)) {
493 : // This will set connect_invoked_
494 0 : return internal_socket_->connect(addr);
495 : }
496 :
497 0 : RefPtr<NrSocketBase> external_socket(create_external_socket(*addr));
498 0 : if (!external_socket) {
499 0 : return R_INTERNAL;
500 : }
501 :
502 0 : PortMapping *port_mapping = create_port_mapping(*addr, external_socket);
503 0 : port_mappings_.push_back(port_mapping);
504 0 : int r = port_mapping->external_socket_->connect(addr);
505 0 : if (r && r != R_WOULDBLOCK) {
506 0 : return r;
507 : }
508 :
509 0 : port_mapping->last_used_ = PR_IntervalNow();
510 :
511 0 : if (poll_flags() & PR_POLL_READ) {
512 : port_mapping->async_wait(NR_ASYNC_WAIT_READ,
513 : port_mapping_tcp_passthrough_callback,
514 : this,
515 : (char*)__FUNCTION__,
516 0 : __LINE__);
517 : }
518 :
519 0 : return r;
520 : }
521 :
522 0 : int TestNrSocket::write(const void *msg, size_t len, size_t *written) {
523 0 : UCHAR *buf = static_cast<UCHAR*>(const_cast<void*>(msg));
524 :
525 0 : if (nat_->nat_delegate_ && nat_->nat_delegate_->on_write(nat_, msg, len, written)) {
526 0 : return R_INTERNAL;
527 : }
528 :
529 0 : if (nat_->block_stun_ && nr_is_stun_message(buf, len)) {
530 : // Should cause this socket to be abandoned
531 0 : r_log(LOG_GENERIC, LOG_DEBUG,
532 : "TestNrSocket %s dropping outgoing TCP "
533 : "because it is configured to drop STUN",
534 0 : my_addr().as_string);
535 0 : return R_INTERNAL;
536 : }
537 :
538 0 : if (nat_->block_tcp_ && !tls_) {
539 : // Should cause this socket to be abandoned
540 0 : r_log(LOG_GENERIC, LOG_DEBUG,
541 : "TestNrSocket %s dropping outgoing TCP "
542 : "because it is configured to drop TCP",
543 0 : my_addr().as_string);
544 0 : return R_INTERNAL;
545 : }
546 :
547 0 : if (port_mappings_.empty()) {
548 : // The no-nat case, just pass call through.
549 0 : r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s writing",
550 0 : my_addr().as_string);
551 :
552 0 : return internal_socket_->write(msg, len, written);
553 : }
554 0 : destroy_stale_port_mappings();
555 0 : if (port_mappings_.empty()) {
556 0 : r_log(LOG_GENERIC, LOG_DEBUG,
557 : "TestNrSocket %s dropping outgoing TCP "
558 : "because the port mapping was stale",
559 0 : my_addr().as_string);
560 0 : return R_INTERNAL;
561 : }
562 : // This is TCP only
563 0 : MOZ_ASSERT(port_mappings_.size() == 1);
564 0 : r_log(LOG_GENERIC, LOG_DEBUG,
565 : "PortMapping %s -> %s writing",
566 0 : port_mappings_.front()->external_socket_->my_addr().as_string,
567 0 : port_mappings_.front()->remote_address_.as_string);
568 0 : port_mappings_.front()->last_used_ = PR_IntervalNow();
569 0 : return port_mappings_.front()->external_socket_->write(msg, len, written);
570 : }
571 :
572 0 : int TestNrSocket::read(void *buf, size_t maxlen, size_t *len) {
573 : int r;
574 :
575 0 : if (port_mappings_.empty()) {
576 0 : r = internal_socket_->read(buf, maxlen, len);
577 : } else {
578 0 : MOZ_ASSERT(port_mappings_.size() == 1);
579 0 : r = port_mappings_.front()->external_socket_->read(buf, maxlen, len);
580 0 : if (!r && nat_->refresh_on_ingress_) {
581 0 : port_mappings_.front()->last_used_ = PR_IntervalNow();
582 : }
583 : }
584 :
585 0 : if (r) {
586 0 : return r;
587 : }
588 :
589 0 : if (nat_->nat_delegate_ && nat_->nat_delegate_->on_read(nat_, buf, maxlen, len)) {
590 0 : return R_INTERNAL;
591 : }
592 :
593 0 : if (nat_->block_tcp_ && !tls_) {
594 : // Should cause this socket to be abandoned
595 0 : return R_INTERNAL;
596 : }
597 :
598 0 : UCHAR *cbuf = static_cast<UCHAR*>(const_cast<void*>(buf));
599 0 : if (nat_->block_stun_ && nr_is_stun_message(cbuf, *len)) {
600 : // Should cause this socket to be abandoned
601 0 : return R_INTERNAL;
602 : }
603 :
604 0 : return r;
605 : }
606 :
607 0 : int TestNrSocket::async_wait(int how, NR_async_cb cb, void *cb_arg,
608 : char *function, int line) {
609 0 : r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s waiting for %s",
610 0 : internal_socket_->my_addr().as_string,
611 0 : how == NR_ASYNC_WAIT_READ ? "read" : "write");
612 :
613 : int r;
614 :
615 0 : if (how == NR_ASYNC_WAIT_READ) {
616 0 : NrSocketBase::async_wait(how, cb, cb_arg, function, line);
617 :
618 : // Make sure we're waiting on the socket for the internal address
619 0 : r = internal_socket_->async_wait(how,
620 : socket_readable_callback,
621 : this,
622 : function,
623 0 : line);
624 : } else {
625 : // For write, just use the readiness of the internal socket, since we queue
626 : // everything for the port mappings.
627 0 : r = internal_socket_->async_wait(how,
628 : cb,
629 : cb_arg,
630 : function,
631 0 : line);
632 : }
633 :
634 0 : if (r) {
635 0 : r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for "
636 : "internal socket: %d\n",
637 0 : internal_socket_->my_addr().as_string,
638 0 : r);
639 0 : return r;
640 : }
641 :
642 0 : if (is_tcp_connection_behind_nat()) {
643 : // Bypass all port-mapping related logic
644 0 : return 0;
645 : }
646 :
647 0 : if (internal_socket_->my_addr().protocol == IPPROTO_TCP) {
648 : // For a TCP connection through a simulated NAT, these signals are
649 : // just passed through.
650 0 : MOZ_ASSERT(port_mappings_.size() == 1);
651 :
652 0 : return port_mappings_.front()->async_wait(
653 : how,
654 : port_mapping_tcp_passthrough_callback,
655 : this,
656 : function,
657 0 : line);
658 : }
659 0 : if (how == NR_ASYNC_WAIT_READ) {
660 : // For UDP port mappings, we decouple the writeable callbacks
661 0 : for (PortMapping *port_mapping : port_mappings_) {
662 : // Be ready to receive traffic on our port mappings
663 : r = port_mapping->async_wait(how,
664 : socket_readable_callback,
665 : this,
666 : function,
667 0 : line);
668 0 : if (r) {
669 0 : r_log(LOG_GENERIC, LOG_ERR, "TestNrSocket %s failed to async_wait for "
670 : "port mapping: %d\n",
671 0 : internal_socket_->my_addr().as_string,
672 0 : r);
673 0 : return r;
674 : }
675 : }
676 : }
677 :
678 0 : return 0;
679 : }
680 :
681 0 : void TestNrSocket::cancel_port_mapping_async_wait(int how) {
682 0 : for (PortMapping *port_mapping : port_mappings_) {
683 0 : port_mapping->cancel(how);
684 : }
685 0 : }
686 :
687 0 : int TestNrSocket::cancel(int how) {
688 :
689 0 : r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s stop waiting for %s",
690 0 : internal_socket_->my_addr().as_string,
691 0 : how == NR_ASYNC_WAIT_READ ? "read" : "write");
692 :
693 : // Writable callbacks are decoupled except for the TCP case
694 0 : if (how == NR_ASYNC_WAIT_READ ||
695 0 : internal_socket_->my_addr().protocol == IPPROTO_TCP) {
696 0 : cancel_port_mapping_async_wait(how);
697 : }
698 :
699 0 : return internal_socket_->cancel(how);
700 : }
701 :
702 0 : bool TestNrSocket::has_port_mappings() const {
703 0 : return !port_mappings_.empty();
704 : }
705 :
706 0 : bool TestNrSocket::is_my_external_tuple(const nr_transport_addr &addr) const {
707 0 : for (PortMapping *port_mapping : port_mappings_) {
708 : nr_transport_addr port_mapping_addr;
709 0 : if (port_mapping->external_socket_->getaddr(&port_mapping_addr)) {
710 0 : MOZ_CRASH("NrSocket::getaddr failed!");
711 : }
712 :
713 : // TODO(bug 1170299): Remove const_cast when no longer necessary
714 0 : if (!nr_transport_addr_cmp(const_cast<nr_transport_addr*>(&addr),
715 : &port_mapping_addr,
716 : NR_TRANSPORT_ADDR_CMP_MODE_ALL)) {
717 0 : return true;
718 : }
719 : }
720 0 : return false;
721 : }
722 :
723 0 : bool TestNrSocket::is_port_mapping_stale(
724 : const PortMapping &port_mapping) const {
725 0 : PRIntervalTime now = PR_IntervalNow();
726 0 : PRIntervalTime elapsed_ticks = now - port_mapping.last_used_;
727 0 : uint32_t idle_duration = PR_IntervalToMilliseconds(elapsed_ticks);
728 0 : return idle_duration > nat_->mapping_timeout_;
729 : }
730 :
731 0 : void TestNrSocket::destroy_stale_port_mappings() {
732 0 : for (auto i = port_mappings_.begin(); i != port_mappings_.end();) {
733 0 : auto temp = i;
734 0 : ++i;
735 0 : if (is_port_mapping_stale(**temp)) {
736 0 : r_log(LOG_GENERIC, LOG_INFO,
737 : "TestNrSocket %s destroying port mapping %s -> %s",
738 0 : internal_socket_->my_addr().as_string,
739 0 : (*temp)->external_socket_->my_addr().as_string,
740 0 : (*temp)->remote_address_.as_string);
741 :
742 0 : port_mappings_.erase(temp);
743 : }
744 : }
745 0 : }
746 :
747 0 : void TestNrSocket::socket_readable_callback(void *real_sock_v,
748 : int how,
749 : void *test_sock_v) {
750 0 : TestNrSocket *test_socket = static_cast<TestNrSocket*>(test_sock_v);
751 0 : NrSocketBase *real_socket = static_cast<NrSocketBase*>(real_sock_v);
752 :
753 0 : test_socket->on_socket_readable(real_socket);
754 0 : }
755 :
756 0 : void TestNrSocket::on_socket_readable(NrSocketBase *real_socket) {
757 0 : if (!readable_socket_ && (real_socket != internal_socket_)) {
758 0 : readable_socket_ = real_socket;
759 : }
760 :
761 0 : fire_readable_callback();
762 0 : }
763 :
764 0 : void TestNrSocket::fire_readable_callback() {
765 0 : MOZ_ASSERT(poll_flags() & PR_POLL_READ);
766 0 : r_log(LOG_GENERIC, LOG_DEBUG, "TestNrSocket %s ready for read",
767 0 : internal_socket_->my_addr().as_string);
768 0 : fire_callback(NR_ASYNC_WAIT_READ);
769 0 : }
770 :
771 0 : void TestNrSocket::port_mapping_writeable_callback(void *ext_sock_v,
772 : int how,
773 : void *test_sock_v) {
774 0 : TestNrSocket *test_socket = static_cast<TestNrSocket*>(test_sock_v);
775 0 : NrSocketBase *external_socket = static_cast<NrSocketBase*>(ext_sock_v);
776 :
777 0 : test_socket->write_to_port_mapping(external_socket);
778 0 : }
779 :
780 0 : void TestNrSocket::write_to_port_mapping(NrSocketBase *external_socket) {
781 0 : MOZ_ASSERT(internal_socket_->my_addr().protocol != IPPROTO_TCP);
782 :
783 0 : int r = 0;
784 0 : for (PortMapping *port_mapping : port_mappings_) {
785 0 : if (port_mapping->external_socket_ == external_socket) {
786 : // If the send succeeds, or if there was nothing to send, we keep going
787 0 : r = port_mapping->send_from_queue();
788 0 : if (r) {
789 0 : break;
790 : }
791 : }
792 : }
793 :
794 0 : if (r == R_WOULDBLOCK) {
795 : // Re-register for writeable callbacks, since we still have stuff to send
796 : NR_ASYNC_WAIT(external_socket,
797 : NR_ASYNC_WAIT_WRITE,
798 : &TestNrSocket::port_mapping_writeable_callback,
799 0 : this);
800 : }
801 0 : }
802 :
803 0 : void TestNrSocket::port_mapping_tcp_passthrough_callback(void *ext_sock_v,
804 : int how,
805 : void *test_sock_v) {
806 0 : TestNrSocket *test_socket = static_cast<TestNrSocket*>(test_sock_v);
807 0 : r_log(LOG_GENERIC, LOG_DEBUG,
808 : "TestNrSocket %s firing %s callback",
809 0 : test_socket->internal_socket_->my_addr().as_string,
810 0 : how == NR_ASYNC_WAIT_READ ? "readable" : "writeable");
811 :
812 :
813 0 : test_socket->internal_socket_->fire_callback(how);
814 0 : }
815 :
816 0 : bool TestNrSocket::is_tcp_connection_behind_nat() const {
817 0 : return internal_socket_->my_addr().protocol == IPPROTO_TCP &&
818 0 : port_mappings_.empty();
819 : }
820 :
821 0 : TestNrSocket::PortMapping* TestNrSocket::get_port_mapping(
822 : const nr_transport_addr &remote_address,
823 : TestNat::NatBehavior filter) const {
824 : int compare_flags;
825 0 : switch (filter) {
826 : case TestNat::ENDPOINT_INDEPENDENT:
827 0 : compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL;
828 0 : break;
829 : case TestNat::ADDRESS_DEPENDENT:
830 0 : compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_ADDR;
831 0 : break;
832 : case TestNat::PORT_DEPENDENT:
833 0 : compare_flags = NR_TRANSPORT_ADDR_CMP_MODE_ALL;
834 0 : break;
835 : }
836 :
837 0 : for (PortMapping *port_mapping : port_mappings_) {
838 : // TODO(bug 1170299): Remove const_cast when no longer necessary
839 0 : if (!nr_transport_addr_cmp(const_cast<nr_transport_addr*>(&remote_address),
840 : &port_mapping->remote_address_,
841 : compare_flags))
842 0 : return port_mapping;
843 : }
844 0 : return nullptr;
845 : }
846 :
847 0 : TestNrSocket::PortMapping* TestNrSocket::create_port_mapping(
848 : const nr_transport_addr &remote_address,
849 : const RefPtr<NrSocketBase> &external_socket) const {
850 0 : r_log(LOG_GENERIC, LOG_INFO, "TestNrSocket %s creating port mapping %s -> %s",
851 0 : internal_socket_->my_addr().as_string,
852 0 : external_socket->my_addr().as_string,
853 0 : remote_address.as_string);
854 :
855 0 : return new PortMapping(remote_address, external_socket);
856 : }
857 :
858 0 : TestNrSocket::PortMapping::PortMapping(
859 : const nr_transport_addr &remote_address,
860 0 : const RefPtr<NrSocketBase> &external_socket) :
861 0 : external_socket_(external_socket) {
862 : // TODO(bug 1170299): Remove const_cast when no longer necessary
863 0 : nr_transport_addr_copy(&remote_address_,
864 0 : const_cast<nr_transport_addr*>(&remote_address));
865 0 : }
866 :
867 0 : int TestNrSocket::PortMapping::send_from_queue() {
868 0 : MOZ_ASSERT(remote_address_.protocol != IPPROTO_TCP);
869 0 : int r = 0;
870 :
871 0 : while (!send_queue_.empty()) {
872 0 : UdpPacket &packet = *send_queue_.front();
873 0 : r_log(LOG_GENERIC, LOG_DEBUG,
874 : "PortMapping %s -> %s sending from queue to %s",
875 0 : external_socket_->my_addr().as_string,
876 : remote_address_.as_string,
877 0 : packet.remote_address_.as_string);
878 :
879 0 : r = external_socket_->sendto(packet.buffer_->data(),
880 : packet.buffer_->len(),
881 : 0,
882 0 : &packet.remote_address_);
883 :
884 0 : if (r) {
885 0 : if (r != R_WOULDBLOCK) {
886 : r_log(LOG_GENERIC, LOG_ERR, "%s: Fatal error %d, stop trying",
887 0 : __FUNCTION__, r);
888 0 : send_queue_.clear();
889 : } else {
890 0 : r_log(LOG_GENERIC, LOG_DEBUG, "Would block, will retry later");
891 : }
892 0 : break;
893 : }
894 :
895 0 : send_queue_.pop_front();
896 : }
897 :
898 0 : return r;
899 : }
900 :
901 0 : int TestNrSocket::PortMapping::sendto(const void *msg,
902 : size_t len,
903 : const nr_transport_addr &to) {
904 0 : MOZ_ASSERT(remote_address_.protocol != IPPROTO_TCP);
905 0 : r_log(LOG_GENERIC, LOG_DEBUG,
906 : "PortMapping %s -> %s sending to %s",
907 0 : external_socket_->my_addr().as_string,
908 : remote_address_.as_string,
909 0 : to.as_string);
910 :
911 0 : last_used_ = PR_IntervalNow();
912 0 : int r = external_socket_->sendto(msg, len, 0,
913 : // TODO(bug 1170299): Remove const_cast when no longer necessary
914 0 : const_cast<nr_transport_addr*>(&to));
915 :
916 0 : if (r == R_WOULDBLOCK) {
917 0 : r_log(LOG_GENERIC, LOG_DEBUG, "Enqueueing UDP packet to %s", to.as_string);
918 0 : send_queue_.push_back(RefPtr<UdpPacket>(new UdpPacket(msg, len, to)));
919 0 : return 0;
920 : }
921 0 : if (r) {
922 0 : r_log(LOG_GENERIC,LOG_ERR, "Error: %d", r);
923 : }
924 :
925 0 : return r;
926 : }
927 :
928 0 : int TestNrSocket::PortMapping::async_wait(int how, NR_async_cb cb, void *cb_arg,
929 : char *function, int line) {
930 0 : r_log(LOG_GENERIC, LOG_DEBUG,
931 : "PortMapping %s -> %s waiting for %s",
932 0 : external_socket_->my_addr().as_string,
933 : remote_address_.as_string,
934 0 : how == NR_ASYNC_WAIT_READ ? "read" : "write");
935 :
936 0 : return external_socket_->async_wait(how, cb, cb_arg, function, line);
937 : }
938 :
939 0 : int TestNrSocket::PortMapping::cancel(int how) {
940 0 : r_log(LOG_GENERIC, LOG_DEBUG,
941 : "PortMapping %s -> %s stop waiting for %s",
942 0 : external_socket_->my_addr().as_string,
943 : remote_address_.as_string,
944 0 : how == NR_ASYNC_WAIT_READ ? "read" : "write");
945 :
946 0 : return external_socket_->cancel(how);
947 : }
948 :
949 : } // namespace mozilla
950 :
|