test_nr_socket.h (13658B)
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 <list> 97 #include <map> 98 #include <set> 99 #include <string> 100 101 #include "mediapacket.h" 102 #include "mozilla/UniquePtr.h" 103 #include "prinrval.h" 104 105 namespace mozilla { 106 107 class TestNrSocket; 108 class NrSocketProxyConfig; 109 110 /** 111 * A group of TestNrSockets that behave as if they were behind the same NAT. 112 * @note We deliberately avoid addref/release of TestNrSocket here to avoid 113 * masking lifetime errors elsewhere. 114 */ 115 class TestNat { 116 public: 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, 126 size_t* len) = 0; 127 virtual int on_sendto(TestNat* nat, const void* msg, size_t len, int flags, 128 const nr_transport_addr* to) = 0; 129 virtual int on_write(TestNat* nat, const void* msg, size_t len, 130 size_t* written) = 0; 131 }; 132 133 typedef enum { 134 /** For mapping, one port is used for all destinations. 135 * For filtering, allow any external address/port. */ 136 ENDPOINT_INDEPENDENT, 137 138 /** For mapping, one port for each destination address (for any port). 139 * For filtering, allow incoming traffic from addresses that outgoing 140 * traffic has been sent to. */ 141 ADDRESS_DEPENDENT, 142 143 /** For mapping, one port for each destination address/port. 144 * For filtering, allow incoming traffic only from addresses/ports that 145 * outgoing traffic has been sent to. */ 146 PORT_DEPENDENT, 147 } NatBehavior; 148 149 TestNat() 150 : enabled_(false), 151 filtering_type_(ENDPOINT_INDEPENDENT), 152 mapping_type_(ENDPOINT_INDEPENDENT), 153 mapping_timeout_(30000), 154 allow_hairpinning_(false), 155 refresh_on_ingress_(false), 156 block_udp_(false), 157 block_stun_(false), 158 block_tcp_(false), 159 block_tls_(false), 160 error_code_for_drop_(0), 161 delay_stun_resp_ms_(0), 162 nat_delegate_(nullptr), 163 network_delay_ms_(0) {} 164 165 bool has_port_mappings() const; 166 167 // Helps determine whether we're hairpinning 168 bool is_my_external_tuple(const nr_transport_addr& addr) const; 169 bool is_an_internal_tuple(const nr_transport_addr& addr) const; 170 171 int create_socket_factory(nr_socket_factory** factorypp); 172 173 void insert_socket(TestNrSocket* socket) { sockets_.insert(socket); } 174 175 void erase_socket(TestNrSocket* socket) { sockets_.erase(socket); } 176 177 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestNat); 178 179 static NatBehavior ToNatBehavior(const std::string& type); 180 181 void set_proxy_config(std::shared_ptr<NrSocketProxyConfig> aProxyConfig); 182 183 bool enabled_; 184 TestNat::NatBehavior filtering_type_; 185 TestNat::NatBehavior mapping_type_; 186 uint32_t mapping_timeout_; 187 bool allow_hairpinning_; 188 bool refresh_on_ingress_; 189 bool block_udp_; 190 bool block_stun_; 191 bool block_tcp_; 192 bool block_tls_; 193 bool error_code_for_drop_; 194 /* Note: this can only delay a single response so far (bug 1253657) */ 195 uint32_t delay_stun_resp_ms_; 196 197 // When we see an outgoing STUN request with a destination address or 198 // destination FQDN that matches a key in this map, we respond with a STUN/300 199 // with a list of ALTERNATE-SERVER fields based on the value in this map. 200 std::map<nsCString, CopyableTArray<nsCString>> stun_redirect_map_; 201 202 NatDelegate* nat_delegate_; 203 unsigned int network_delay_ms_; 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: 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: 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 { 294 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), flags_(flags), internal_socket_(internal_socket) { 298 buffer_.Copy(reinterpret_cast<const uint8_t*>(data), len); 299 nr_transport_addr_copy(&to_, addr); 300 } 301 302 TestNrSocket* socket_; 303 MediaPacket buffer_; 304 int flags_; 305 nr_transport_addr to_; 306 RefPtr<NrSocketBase> internal_socket_; 307 }; 308 309 bool is_port_mapping_stale(const PortMapping& port_mapping) const; 310 bool allow_ingress(const nr_transport_addr& to, const nr_transport_addr& from, 311 PortMapping** port_mapping_used) const; 312 void destroy_stale_port_mappings(); 313 314 static void socket_readable_callback(void* real_sock_v, int how, 315 void* test_sock_v); 316 void on_socket_readable(NrSocketBase* external_or_internal_socket); 317 void fire_readable_callback(); 318 319 static void port_mapping_tcp_passthrough_callback(void* ext_sock_v, int how, 320 void* test_sock_v); 321 void cancel_port_mapping_async_wait(int how); 322 323 static void port_mapping_writeable_callback(void* ext_sock_v, 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 static bool port_mapping_matches(const PortMapping& port_mapping, 331 const nr_transport_addr& remote_addr, 332 TestNat::NatBehavior filter); 333 PortMapping* create_port_mapping( 334 const nr_transport_addr& remote_addr, 335 const RefPtr<NrSocketBase>& external_socket) const; 336 RefPtr<NrSocketBase> create_external_socket( 337 const nr_transport_addr& remote_addr) const; 338 339 static void process_delayed_cb(NR_SOCKET s, int how, void* cb_arg); 340 341 bool maybe_send_fake_response(const void* msg, size_t len, 342 const nr_transport_addr* to); 343 Maybe<nsTArray<nsCString>> maybe_get_redirect_targets( 344 const nr_transport_addr* to) const; 345 346 RefPtr<NrSocketBase> readable_socket_; 347 // The socket for the "internal" address; used to talk to stuff behind the 348 // same nat. 349 RefPtr<NrSocketBase> internal_socket_; 350 RefPtr<TestNat> nat_; 351 bool tls_; 352 // Since our comparison logic is different depending on what kind of NAT 353 // we simulate, and the STL does not make it very easy to switch out the 354 // comparison function at runtime, and these lists are going to be very 355 // small anyway, we just brute-force it. 356 std::list<RefPtr<PortMapping>> port_mappings_; 357 358 void* timer_handle_; 359 nsTArray<nsCOMPtr<nsITimer>> mTimers; 360 361 // Just used for fake stun responses right now. Not _necessarily_ just UDP 362 // stuff, UdpPacket just has what we need to make this work for UDP. 363 std::list<UdpPacket> read_buffer_; 364 std::unique_ptr<nr_transport_addr> connect_fake_stun_address_; 365 }; 366 367 } // namespace mozilla 368 369 #endif // test_nr_socket__