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