media/mtransport/test/stunserver.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 // Original author: ekr@rtfm.com
michael@0 8
michael@0 9 /*
michael@0 10 Original code from nICEr and nrappkit.
michael@0 11
michael@0 12 nICEr copyright:
michael@0 13
michael@0 14 Copyright (c) 2007, Adobe Systems, Incorporated
michael@0 15 All rights reserved.
michael@0 16
michael@0 17 Redistribution and use in source and binary forms, with or without
michael@0 18 modification, are permitted provided that the following conditions are
michael@0 19 met:
michael@0 20
michael@0 21 * Redistributions of source code must retain the above copyright
michael@0 22 notice, this list of conditions and the following disclaimer.
michael@0 23
michael@0 24 * Redistributions in binary form must reproduce the above copyright
michael@0 25 notice, this list of conditions and the following disclaimer in the
michael@0 26 documentation and/or other materials provided with the distribution.
michael@0 27
michael@0 28 * Neither the name of Adobe Systems, Network Resonance nor the names of its
michael@0 29 contributors may be used to endorse or promote products derived from
michael@0 30 this software without specific prior written permission.
michael@0 31
michael@0 32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 33 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 34 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 35 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 36 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 37 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 38 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 39 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 40 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 41 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 42 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 43
michael@0 44
michael@0 45 nrappkit copyright:
michael@0 46
michael@0 47 Copyright (C) 2001-2003, Network Resonance, Inc.
michael@0 48 Copyright (C) 2006, Network Resonance, Inc.
michael@0 49 All Rights Reserved
michael@0 50
michael@0 51 Redistribution and use in source and binary forms, with or without
michael@0 52 modification, are permitted provided that the following conditions
michael@0 53 are met:
michael@0 54
michael@0 55 1. Redistributions of source code must retain the above copyright
michael@0 56 notice, this list of conditions and the following disclaimer.
michael@0 57 2. Redistributions in binary form must reproduce the above copyright
michael@0 58 notice, this list of conditions and the following disclaimer in the
michael@0 59 documentation and/or other materials provided with the distribution.
michael@0 60 3. Neither the name of Network Resonance, Inc. nor the name of any
michael@0 61 contributors to this software may be used to endorse or promote
michael@0 62 products derived from this software without specific prior written
michael@0 63 permission.
michael@0 64
michael@0 65 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
michael@0 66 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
michael@0 67 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
michael@0 68 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
michael@0 69 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
michael@0 70 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
michael@0 71 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
michael@0 72 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
michael@0 73 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
michael@0 74 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
michael@0 75 POSSIBILITY OF SUCH DAMAGE.
michael@0 76
michael@0 77
michael@0 78 ekr@rtfm.com Thu Dec 20 20:14:49 2001
michael@0 79 */
michael@0 80 #include "logging.h"
michael@0 81 #include "mozilla/Scoped.h"
michael@0 82 #include "databuffer.h"
michael@0 83
michael@0 84 extern "C" {
michael@0 85 #include "nr_api.h"
michael@0 86 #include "async_wait.h"
michael@0 87 #include "async_timer.h"
michael@0 88 #include "nr_socket.h"
michael@0 89 #include "nr_socket_local.h"
michael@0 90 #include "transport_addr.h"
michael@0 91 #include "addrs.h"
michael@0 92 #include "local_addr.h"
michael@0 93 #include "stun_util.h"
michael@0 94 #include "registry.h"
michael@0 95 }
michael@0 96
michael@0 97 #include "stunserver.h"
michael@0 98
michael@0 99 #include <string>
michael@0 100
michael@0 101 MOZ_MTLOG_MODULE("stunserver");
michael@0 102
michael@0 103 namespace mozilla {
michael@0 104
michael@0 105 // Wrapper nr_socket which allows us to lie to the stun server about the
michael@0 106 // IP address.
michael@0 107 struct nr_socket_wrapped {
michael@0 108 nr_socket *sock_;
michael@0 109 nr_transport_addr addr_;
michael@0 110 };
michael@0 111
michael@0 112 static int nr_socket_wrapped_destroy(void **objp) {
michael@0 113 if (!objp || !*objp)
michael@0 114 return 0;
michael@0 115
michael@0 116 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(*objp);
michael@0 117 *objp = 0;
michael@0 118
michael@0 119 delete wrapped;
michael@0 120
michael@0 121 return 0;
michael@0 122 }
michael@0 123
michael@0 124 static int nr_socket_wrapped_sendto(void *obj, const void *msg, size_t len, int flags,
michael@0 125 nr_transport_addr *addr) {
michael@0 126 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj);
michael@0 127
michael@0 128 return nr_socket_sendto(wrapped->sock_, msg, len, flags, &wrapped->addr_);
michael@0 129 }
michael@0 130
michael@0 131 static int nr_socket_wrapped_recvfrom(void *obj, void * restrict buf, size_t maxlen,
michael@0 132 size_t *len, int flags, nr_transport_addr *addr) {
michael@0 133 MOZ_CRASH();
michael@0 134 }
michael@0 135
michael@0 136 static int nr_socket_wrapped_getfd(void *obj, NR_SOCKET *fd) {
michael@0 137 MOZ_CRASH();
michael@0 138 }
michael@0 139
michael@0 140 static int nr_socket_wrapped_getaddr(void *obj, nr_transport_addr *addrp) {
michael@0 141 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj);
michael@0 142
michael@0 143 return nr_socket_getaddr(wrapped->sock_, addrp);
michael@0 144 }
michael@0 145
michael@0 146 static int nr_socket_wrapped_close(void *obj) {
michael@0 147 MOZ_CRASH();
michael@0 148 }
michael@0 149
michael@0 150 static int nr_socket_wrapped_set_send_addr(nr_socket *sock, nr_transport_addr *addr) {
michael@0 151 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(sock->obj);
michael@0 152
michael@0 153 return nr_transport_addr_copy(&wrapped->addr_, addr);
michael@0 154 }
michael@0 155
michael@0 156 static nr_socket_vtbl nr_socket_wrapped_vtbl = {
michael@0 157 1,
michael@0 158 nr_socket_wrapped_destroy,
michael@0 159 nr_socket_wrapped_sendto,
michael@0 160 nr_socket_wrapped_recvfrom,
michael@0 161 nr_socket_wrapped_getfd,
michael@0 162 nr_socket_wrapped_getaddr,
michael@0 163 0,
michael@0 164 0,
michael@0 165 0,
michael@0 166 nr_socket_wrapped_close
michael@0 167 };
michael@0 168
michael@0 169 int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) {
michael@0 170 ScopedDeletePtr<nr_socket_wrapped> wrapped(new nr_socket_wrapped());
michael@0 171
michael@0 172 wrapped->sock_ = inner;
michael@0 173
michael@0 174 int r = nr_socket_create_int(wrapped.get(), &nr_socket_wrapped_vtbl, outp);
michael@0 175 if (r)
michael@0 176 return r;
michael@0 177
michael@0 178 wrapped.forget();
michael@0 179 return 0;
michael@0 180 }
michael@0 181
michael@0 182
michael@0 183 // Instance static.
michael@0 184 // Note: Calling Create() at static init time is not going to be safe, since
michael@0 185 // we have no reason to expect this will be initted to a nullptr yet.
michael@0 186 TestStunServer* TestStunServer::instance;
michael@0 187 uint16_t TestStunServer::instance_port = 3478;
michael@0 188
michael@0 189 TestStunServer::~TestStunServer() {
michael@0 190 // TODO(ekr@rtfm.com): Put this on the right thread.
michael@0 191
michael@0 192 // Unhook callback from our listen socket.
michael@0 193 if (listen_sock_) {
michael@0 194 NR_SOCKET fd;
michael@0 195 if (!nr_socket_getfd(listen_sock_, &fd)) {
michael@0 196 NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
michael@0 197 }
michael@0 198 }
michael@0 199
michael@0 200 // Free up stun context and network resources
michael@0 201 nr_stun_server_ctx_destroy(&stun_server_);
michael@0 202 nr_socket_destroy(&listen_sock_);
michael@0 203 nr_socket_destroy(&send_sock_);
michael@0 204
michael@0 205 // Make sure we aren't still waiting on a deferred response timer to pop
michael@0 206 if (timer_handle_)
michael@0 207 NR_async_timer_cancel(timer_handle_);
michael@0 208
michael@0 209 delete response_addr_;
michael@0 210 }
michael@0 211
michael@0 212 int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
michael@0 213
michael@0 214 if (nr_transport_addr_set_port(&addr->addr, port)) {
michael@0 215 MOZ_MTLOG(ML_ERROR, "Couldn't set port");
michael@0 216 return R_INTERNAL;
michael@0 217 }
michael@0 218
michael@0 219 if (nr_transport_addr_fmt_addr_string(&addr->addr)) {
michael@0 220 MOZ_MTLOG(ML_ERROR, "Couldn't re-set addr string");
michael@0 221 return R_INTERNAL;
michael@0 222 }
michael@0 223
michael@0 224 if (nr_socket_local_create(&addr->addr, &listen_sock_)) {
michael@0 225 MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
michael@0 226 return R_ALREADY;
michael@0 227 }
michael@0 228
michael@0 229 return 0;
michael@0 230 }
michael@0 231
michael@0 232 TestStunServer* TestStunServer::Create() {
michael@0 233 NR_reg_init(NR_REG_MODE_LOCAL);
michael@0 234
michael@0 235 ScopedDeletePtr<TestStunServer> server(new TestStunServer());
michael@0 236
michael@0 237 nr_local_addr addrs[100];
michael@0 238 int addr_ct;
michael@0 239 int r;
michael@0 240
michael@0 241 r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
michael@0 242 if (r) {
michael@0 243 MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
michael@0 244 return nullptr;
michael@0 245 }
michael@0 246
michael@0 247 if (addr_ct < 1) {
michael@0 248 MOZ_MTLOG(ML_ERROR, "No local addresses");
michael@0 249 return nullptr;
michael@0 250 }
michael@0 251
michael@0 252 NR_SOCKET fd;
michael@0 253 int tries = 10;
michael@0 254 while (tries--) {
michael@0 255 // Bind to the first address (arbitrarily) on configured port (default 3478)
michael@0 256 r = server->TryOpenListenSocket(&addrs[0], instance_port);
michael@0 257 // We interpret R_ALREADY to mean the addr is probably in use. Try another.
michael@0 258 // Otherwise, it either worked or it didn't, and we check below.
michael@0 259 if (r != R_ALREADY) {
michael@0 260 break;
michael@0 261 }
michael@0 262 ++instance_port;
michael@0 263 }
michael@0 264
michael@0 265 if (r) {
michael@0 266 return nullptr;
michael@0 267 }
michael@0 268
michael@0 269 r = nr_socket_getfd(server->listen_sock_, &fd);
michael@0 270 if (r) {
michael@0 271 MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
michael@0 272 return nullptr;
michael@0 273 }
michael@0 274
michael@0 275 r = nr_socket_wrapped_create(server->listen_sock_, &server->send_sock_);
michael@0 276 if (r) {
michael@0 277 MOZ_MTLOG(ML_ERROR, "Couldn't create send socket");
michael@0 278 return nullptr;
michael@0 279 }
michael@0 280
michael@0 281 r = nr_stun_server_ctx_create(const_cast<char *>("Test STUN server"),
michael@0 282 server->send_sock_,
michael@0 283 &server->stun_server_);
michael@0 284 if (r) {
michael@0 285 MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
michael@0 286 return nullptr;
michael@0 287 }
michael@0 288
michael@0 289 // Cache the address and port.
michael@0 290 char addr_string[INET6_ADDRSTRLEN];
michael@0 291 r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
michael@0 292 sizeof(addr_string));
michael@0 293 if (r) {
michael@0 294 MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
michael@0 295 return nullptr;
michael@0 296 }
michael@0 297
michael@0 298 server->listen_addr_ = addr_string;
michael@0 299 server->listen_port_ = instance_port;
michael@0 300
michael@0 301 NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server.get());
michael@0 302
michael@0 303 return server.forget();
michael@0 304 }
michael@0 305
michael@0 306 void TestStunServer::ConfigurePort(uint16_t port) {
michael@0 307 instance_port = port;
michael@0 308 }
michael@0 309
michael@0 310 TestStunServer* TestStunServer::GetInstance() {
michael@0 311 if (!instance)
michael@0 312 instance = Create();
michael@0 313
michael@0 314 MOZ_ASSERT(instance);
michael@0 315 return instance;
michael@0 316 }
michael@0 317
michael@0 318 void TestStunServer::ShutdownInstance() {
michael@0 319 delete instance;
michael@0 320
michael@0 321 instance = nullptr;
michael@0 322 }
michael@0 323
michael@0 324
michael@0 325 struct DeferredStunOperation {
michael@0 326 DeferredStunOperation(TestStunServer *server,
michael@0 327 const char *data, size_t len,
michael@0 328 nr_transport_addr *addr) :
michael@0 329 server_(server),
michael@0 330 buffer_(reinterpret_cast<const uint8_t *>(data), len) {
michael@0 331 nr_transport_addr_copy(&addr_, addr);
michael@0 332 }
michael@0 333
michael@0 334 TestStunServer *server_;
michael@0 335 DataBuffer buffer_;
michael@0 336 nr_transport_addr addr_;
michael@0 337 };
michael@0 338
michael@0 339 void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr) {
michael@0 340 // Set the wrapped address so that the response goes to the right place.
michael@0 341 nr_socket_wrapped_set_send_addr(send_sock_, addr);
michael@0 342 nr_stun_server_process_request(stun_server_, send_sock_,
michael@0 343 const_cast<char *>(reinterpret_cast<const char *>(msg)),
michael@0 344 len,
michael@0 345 response_addr_ ?
michael@0 346 response_addr_ : addr,
michael@0 347 NR_STUN_AUTH_RULE_OPTIONAL);
michael@0 348 }
michael@0 349
michael@0 350 void TestStunServer::process_cb(NR_SOCKET s, int how, void *cb_arg) {
michael@0 351 DeferredStunOperation *op = static_cast<DeferredStunOperation *>(cb_arg);
michael@0 352 op->server_->timer_handle_ = nullptr;
michael@0 353 op->server_->Process(op->buffer_.data(), op->buffer_.len(), &op->addr_);
michael@0 354
michael@0 355 delete op;
michael@0 356 }
michael@0 357
michael@0 358 void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) {
michael@0 359 TestStunServer* server = static_cast<TestStunServer*>(cb_arg);
michael@0 360
michael@0 361 char message[4096];
michael@0 362 size_t message_len;
michael@0 363 nr_transport_addr addr;
michael@0 364
michael@0 365 int r = nr_socket_recvfrom(server->listen_sock_, message, sizeof(message),
michael@0 366 &message_len, 0, &addr);
michael@0 367
michael@0 368 if (r) {
michael@0 369 MOZ_MTLOG(ML_ERROR, "Couldn't read STUN message");
michael@0 370 return;
michael@0 371 }
michael@0 372
michael@0 373 MOZ_MTLOG(ML_DEBUG, "Received data of length " << message_len);
michael@0 374
michael@0 375 // Re-arm.
michael@0 376 NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server);
michael@0 377
michael@0 378
michael@0 379 // If we have initial dropping set, check at this point.
michael@0 380 std::string key(addr.as_string);
michael@0 381
michael@0 382 if (server->received_ct_.count(key) == 0) {
michael@0 383 server->received_ct_[key] = 0;
michael@0 384 }
michael@0 385
michael@0 386 ++server->received_ct_[key];
michael@0 387
michael@0 388 if (!server->active_ || (server->received_ct_[key] <= server->initial_ct_)) {
michael@0 389 MOZ_MTLOG(ML_DEBUG, "Dropping message #"
michael@0 390 << server->received_ct_[key] << " from " << key);
michael@0 391 return;
michael@0 392 }
michael@0 393
michael@0 394 if (server->delay_ms_) {
michael@0 395 NR_ASYNC_TIMER_SET(server->delay_ms_,
michael@0 396 process_cb,
michael@0 397 new DeferredStunOperation(
michael@0 398 server,
michael@0 399 message, message_len,
michael@0 400 &addr),
michael@0 401 &server->timer_handle_);
michael@0 402 } else {
michael@0 403 server->Process(reinterpret_cast<const uint8_t *>(message), message_len, &addr);
michael@0 404 }
michael@0 405 }
michael@0 406
michael@0 407 void TestStunServer::SetActive(bool active) {
michael@0 408 active_ = active;
michael@0 409 }
michael@0 410
michael@0 411 void TestStunServer::SetDelay(uint32_t delay_ms) {
michael@0 412 delay_ms_ = delay_ms;
michael@0 413 }
michael@0 414
michael@0 415 void TestStunServer::SetDropInitialPackets(uint32_t count) {
michael@0 416 initial_ct_ = count;
michael@0 417 }
michael@0 418
michael@0 419 nsresult TestStunServer::SetResponseAddr(nr_transport_addr *addr) {
michael@0 420 delete response_addr_;
michael@0 421
michael@0 422 response_addr_ = new nr_transport_addr();
michael@0 423
michael@0 424 int r = nr_transport_addr_copy(response_addr_, addr);
michael@0 425 if (r)
michael@0 426 return NS_ERROR_FAILURE;
michael@0 427
michael@0 428 return NS_OK;
michael@0 429 }
michael@0 430
michael@0 431 nsresult TestStunServer::SetResponseAddr(const std::string& addr,
michael@0 432 uint16_t port) {
michael@0 433 nr_transport_addr addr2;
michael@0 434
michael@0 435 int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
michael@0 436 port, IPPROTO_UDP,
michael@0 437 &addr2);
michael@0 438 if (r)
michael@0 439 return NS_ERROR_FAILURE;
michael@0 440
michael@0 441 return SetResponseAddr(&addr2);
michael@0 442 }
michael@0 443
michael@0 444 void TestStunServer::Reset() {
michael@0 445 delay_ms_ = 0;
michael@0 446 if (timer_handle_) {
michael@0 447 NR_async_timer_cancel(timer_handle_);
michael@0 448 timer_handle_ = nullptr;
michael@0 449 }
michael@0 450 delete response_addr_;
michael@0 451 response_addr_ = nullptr;
michael@0 452 }
michael@0 453
michael@0 454 } // close namespace

mercurial