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 #ifndef test_nr_socket__
84 #define test_nr_socket__
85 
86 extern "C" {
87 #include "transport_addr.h"
88 }
89 
90 #include "nr_socket_prsock.h"
91 
92 extern "C" {
93 #include "nr_socket.h"
94 }
95 
96 #include <set>
97 #include <vector>
98 #include <map>
99 #include <list>
100 #include <string>
101 
102 #include "mozilla/UniquePtr.h"
103 #include "prinrval.h"
104 #include "mediapacket.h"
105 
106 namespace mozilla {
107 
108 class TestNrSocket;
109 class NrSocketProxyConfig;
110 
111 /**
112  * A group of TestNrSockets that behave as if they were behind the same NAT.
113  * @note We deliberately avoid addref/release of TestNrSocket here to avoid
114  *       masking lifetime errors elsewhere.
115  */
116 class TestNat {
117  public:
118   /**
119    * This allows TestNat traffic to be passively inspected.
120    * If a non-zero (error) value is returned, the packet will be dropped,
121    * allowing for tests to extend how packet manipulation is done by
122    * TestNat with having to modify TestNat itself.
123    */
124   class NatDelegate {
125    public:
126     virtual int on_read(TestNat* nat, void* buf, size_t maxlen,
127                         size_t* len) = 0;
128     virtual int on_sendto(TestNat* nat, const void* msg, size_t len, int flags,
129                           const nr_transport_addr* to) = 0;
130     virtual int on_write(TestNat* nat, const void* msg, size_t len,
131                          size_t* written) = 0;
132   };
133 
134   typedef enum {
135     /** For mapping, one port is used for all destinations.
136      *  For filtering, allow any external address/port. */
137     ENDPOINT_INDEPENDENT,
138 
139     /** For mapping, one port for each destination address (for any port).
140      *  For filtering, allow incoming traffic from addresses that outgoing
141      *  traffic has been sent to. */
142     ADDRESS_DEPENDENT,
143 
144     /** For mapping, one port for each destination address/port.
145      *  For filtering, allow incoming traffic only from addresses/ports that
146      *  outgoing traffic has been sent to. */
147     PORT_DEPENDENT,
148   } NatBehavior;
149 
TestNat()150   TestNat()
151       : enabled_(false),
152         filtering_type_(ENDPOINT_INDEPENDENT),
153         mapping_type_(ENDPOINT_INDEPENDENT),
154         mapping_timeout_(30000),
155         allow_hairpinning_(false),
156         refresh_on_ingress_(false),
157         block_udp_(false),
158         block_stun_(false),
159         block_tcp_(false),
160         block_tls_(false),
161         error_code_for_drop_(0),
162         delay_stun_resp_ms_(0),
163         nat_delegate_(nullptr),
164         sockets_() {}
165 
166   bool has_port_mappings() const;
167 
168   // Helps determine whether we're hairpinning
169   bool is_my_external_tuple(const nr_transport_addr& addr) const;
170   bool is_an_internal_tuple(const nr_transport_addr& addr) const;
171 
172   int create_socket_factory(nr_socket_factory** factorypp);
173 
insert_socket(TestNrSocket * socket)174   void insert_socket(TestNrSocket* socket) { sockets_.insert(socket); }
175 
erase_socket(TestNrSocket * socket)176   void erase_socket(TestNrSocket* socket) { sockets_.erase(socket); }
177 
178   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNat);
179 
180   static NatBehavior ToNatBehavior(const std::string& type);
181 
182   void set_proxy_config(std::shared_ptr<NrSocketProxyConfig> aProxyConfig);
183 
184   bool enabled_;
185   TestNat::NatBehavior filtering_type_;
186   TestNat::NatBehavior mapping_type_;
187   uint32_t mapping_timeout_;
188   bool allow_hairpinning_;
189   bool refresh_on_ingress_;
190   bool block_udp_;
191   bool block_stun_;
192   bool block_tcp_;
193   bool block_tls_;
194   bool error_code_for_drop_;
195   /* Note: this can only delay a single response so far (bug 1253657) */
196   uint32_t delay_stun_resp_ms_;
197 
198   // When we see an outgoing STUN request with a destination address or
199   // destination FQDN that matches a key in this map, we respond with a STUN/300
200   // with a list of ALTERNATE-SERVER fields based on the value in this map.
201   std::map<nsCString, CopyableTArray<nsCString>> stun_redirect_map_;
202 
203   NatDelegate* nat_delegate_;
204   std::shared_ptr<NrSocketProxyConfig> proxy_config_;
205 
206  private:
207   std::set<TestNrSocket*> sockets_;
208 
209   ~TestNat() = default;
210 };
211 
212 /**
213  * Subclass of NrSocketBase that can simulate things like being behind a NAT,
214  * packet loss, latency, packet rewriting, etc. Also exposes some stuff that
215  * assists in diagnostics.
216  * This is accomplished by wrapping an "internal" socket (that handles traffic
217  * behind the NAT), and a collection of "external" sockets (that handle traffic
218  * into/out of the NAT)
219  */
220 class TestNrSocket : public NrSocketBase {
221  public:
222   explicit TestNrSocket(TestNat* nat);
223 
224   bool has_port_mappings() const;
225   bool is_my_external_tuple(const nr_transport_addr& addr) const;
226 
227   // Overrides of NrSocketBase
228   int create(nr_transport_addr* addr) override;
229   int sendto(const void* msg, size_t len, int flags,
230              const nr_transport_addr* to) override;
231   int recvfrom(void* buf, size_t maxlen, size_t* len, int flags,
232                nr_transport_addr* from) override;
233   int getaddr(nr_transport_addr* addrp) override;
234   void close() override;
235   int connect(const nr_transport_addr* addr) override;
236   int write(const void* msg, size_t len, size_t* written) override;
237   int read(void* buf, size_t maxlen, size_t* len) override;
238 
239   int listen(int backlog) override;
240   int accept(nr_transport_addr* addrp, nr_socket** sockp) override;
241   int async_wait(int how, NR_async_cb cb, void* cb_arg, char* function,
242                  int line) override;
243   int cancel(int how) override;
244 
245   // Need override since this is virtual in NrSocketBase
246   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNrSocket, override)
247 
248  private:
249   virtual ~TestNrSocket();
250 
251   class UdpPacket {
252    public:
UdpPacket(const void * msg,size_t len,const nr_transport_addr & addr)253     UdpPacket(const void* msg, size_t len, const nr_transport_addr& addr)
254         : buffer_(new MediaPacket) {
255       buffer_->Copy(static_cast<const uint8_t*>(msg), len);
256       nr_transport_addr_copy(&remote_address_, &addr);
257     }
258 
259     UdpPacket(UdpPacket&& aOrig) = default;
260 
261     ~UdpPacket() = default;
262 
263     nr_transport_addr remote_address_;
264     UniquePtr<MediaPacket> buffer_;
265   };
266 
267   class PortMapping {
268    public:
269     PortMapping(const nr_transport_addr& remote_address,
270                 const RefPtr<NrSocketBase>& external_socket);
271 
272     int sendto(const void* msg, size_t len, const nr_transport_addr& to);
273     int async_wait(int how, NR_async_cb cb, void* cb_arg, char* function,
274                    int line);
275     int cancel(int how);
276     int send_from_queue();
277     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PortMapping);
278 
279     PRIntervalTime last_used_;
280     RefPtr<NrSocketBase> external_socket_;
281     // For non-symmetric, most of the data here doesn't matter
282     nr_transport_addr remote_address_;
283 
284    private:
~PortMapping()285     ~PortMapping() { external_socket_->close(); }
286 
287     // If external_socket_ returns E_WOULDBLOCK, we don't want to propagate
288     // that to the code using the TestNrSocket. We can also perhaps use this
289     // to help simulate things like latency.
290     std::list<UdpPacket> send_queue_;
291   };
292 
293   struct DeferredPacket {
DeferredPacketDeferredPacket294     DeferredPacket(TestNrSocket* sock, const void* data, size_t len, int flags,
295                    const nr_transport_addr* addr,
296                    RefPtr<NrSocketBase> internal_socket)
297         : socket_(sock),
298           buffer_(),
299           flags_(flags),
300           internal_socket_(internal_socket) {
301       buffer_.Copy(reinterpret_cast<const uint8_t*>(data), len);
302       nr_transport_addr_copy(&to_, addr);
303     }
304 
305     TestNrSocket* socket_;
306     MediaPacket buffer_;
307     int flags_;
308     nr_transport_addr to_;
309     RefPtr<NrSocketBase> internal_socket_;
310   };
311 
312   bool is_port_mapping_stale(const PortMapping& port_mapping) const;
313   bool allow_ingress(const nr_transport_addr& to, const nr_transport_addr& from,
314                      PortMapping** port_mapping_used) const;
315   void destroy_stale_port_mappings();
316 
317   static void socket_readable_callback(void* real_sock_v, int how,
318                                        void* test_sock_v);
319   void on_socket_readable(NrSocketBase* external_or_internal_socket);
320   void fire_readable_callback();
321 
322   static void port_mapping_tcp_passthrough_callback(void* ext_sock_v, int how,
323                                                     void* test_sock_v);
324   void cancel_port_mapping_async_wait(int how);
325 
326   static void port_mapping_writeable_callback(void* ext_sock_v, int how,
327                                               void* test_sock_v);
328   void write_to_port_mapping(NrSocketBase* external_socket);
329   bool is_tcp_connection_behind_nat() const;
330 
331   PortMapping* get_port_mapping(const nr_transport_addr& remote_addr,
332                                 TestNat::NatBehavior filter) const;
333   static bool port_mapping_matches(const PortMapping& port_mapping,
334                                    const nr_transport_addr& remote_addr,
335                                    TestNat::NatBehavior filter);
336   PortMapping* create_port_mapping(
337       const nr_transport_addr& remote_addr,
338       const RefPtr<NrSocketBase>& external_socket) const;
339   RefPtr<NrSocketBase> create_external_socket(
340       const nr_transport_addr& remote_addr) const;
341 
342   static void process_delayed_cb(NR_SOCKET s, int how, void* cb_arg);
343 
344   bool maybe_send_fake_response(const void* msg, size_t len,
345                                 const nr_transport_addr* to);
346   Maybe<nsTArray<nsCString>> maybe_get_redirect_targets(
347       const nr_transport_addr* to) const;
348 
349   RefPtr<NrSocketBase> readable_socket_;
350   // The socket for the "internal" address; used to talk to stuff behind the
351   // same nat.
352   RefPtr<NrSocketBase> internal_socket_;
353   RefPtr<TestNat> nat_;
354   bool tls_;
355   // Since our comparison logic is different depending on what kind of NAT
356   // we simulate, and the STL does not make it very easy to switch out the
357   // comparison function at runtime, and these lists are going to be very
358   // small anyway, we just brute-force it.
359   std::list<RefPtr<PortMapping>> port_mappings_;
360 
361   void* timer_handle_;
362 
363   // Just used for fake stun responses right now. Not _necessarily_ just UDP
364   // stuff, UdpPacket just has what we need to make this work for UDP.
365   std::list<UdpPacket> read_buffer_;
366   std::unique_ptr<nr_transport_addr> connect_fake_stun_address_;
367 };
368 
369 }  // namespace mozilla
370 
371 #endif  // test_nr_socket__
372