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