Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 // Original author: ekr@rtfm.com
9 /*
10 Original code from nICEr and nrappkit.
12 nICEr copyright:
14 Copyright (c) 2007, Adobe Systems, Incorporated
15 All rights reserved.
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions are
19 met:
21 * Redistributions of source code must retain the above copyright
22 notice, this list of conditions and the following disclaimer.
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.
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.
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.
45 nrappkit copyright:
47 Copyright (C) 2001-2003, Network Resonance, Inc.
48 Copyright (C) 2006, Network Resonance, Inc.
49 All Rights Reserved
51 Redistribution and use in source and binary forms, with or without
52 modification, are permitted provided that the following conditions
53 are met:
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.
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.
78 ekr@rtfm.com Thu Dec 20 20:14:49 2001
79 */
80 #include "logging.h"
81 #include "mozilla/Scoped.h"
82 #include "databuffer.h"
84 extern "C" {
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 "transport_addr.h"
91 #include "addrs.h"
92 #include "local_addr.h"
93 #include "stun_util.h"
94 #include "registry.h"
95 }
97 #include "stunserver.h"
99 #include <string>
101 MOZ_MTLOG_MODULE("stunserver");
103 namespace mozilla {
105 // Wrapper nr_socket which allows us to lie to the stun server about the
106 // IP address.
107 struct nr_socket_wrapped {
108 nr_socket *sock_;
109 nr_transport_addr addr_;
110 };
112 static int nr_socket_wrapped_destroy(void **objp) {
113 if (!objp || !*objp)
114 return 0;
116 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(*objp);
117 *objp = 0;
119 delete wrapped;
121 return 0;
122 }
124 static int nr_socket_wrapped_sendto(void *obj, const void *msg, size_t len, int flags,
125 nr_transport_addr *addr) {
126 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj);
128 return nr_socket_sendto(wrapped->sock_, msg, len, flags, &wrapped->addr_);
129 }
131 static int nr_socket_wrapped_recvfrom(void *obj, void * restrict buf, size_t maxlen,
132 size_t *len, int flags, nr_transport_addr *addr) {
133 MOZ_CRASH();
134 }
136 static int nr_socket_wrapped_getfd(void *obj, NR_SOCKET *fd) {
137 MOZ_CRASH();
138 }
140 static int nr_socket_wrapped_getaddr(void *obj, nr_transport_addr *addrp) {
141 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(obj);
143 return nr_socket_getaddr(wrapped->sock_, addrp);
144 }
146 static int nr_socket_wrapped_close(void *obj) {
147 MOZ_CRASH();
148 }
150 static int nr_socket_wrapped_set_send_addr(nr_socket *sock, nr_transport_addr *addr) {
151 nr_socket_wrapped *wrapped = static_cast<nr_socket_wrapped *>(sock->obj);
153 return nr_transport_addr_copy(&wrapped->addr_, addr);
154 }
156 static nr_socket_vtbl nr_socket_wrapped_vtbl = {
157 1,
158 nr_socket_wrapped_destroy,
159 nr_socket_wrapped_sendto,
160 nr_socket_wrapped_recvfrom,
161 nr_socket_wrapped_getfd,
162 nr_socket_wrapped_getaddr,
163 0,
164 0,
165 0,
166 nr_socket_wrapped_close
167 };
169 int nr_socket_wrapped_create(nr_socket *inner, nr_socket **outp) {
170 ScopedDeletePtr<nr_socket_wrapped> wrapped(new nr_socket_wrapped());
172 wrapped->sock_ = inner;
174 int r = nr_socket_create_int(wrapped.get(), &nr_socket_wrapped_vtbl, outp);
175 if (r)
176 return r;
178 wrapped.forget();
179 return 0;
180 }
183 // Instance static.
184 // Note: Calling Create() at static init time is not going to be safe, since
185 // we have no reason to expect this will be initted to a nullptr yet.
186 TestStunServer* TestStunServer::instance;
187 uint16_t TestStunServer::instance_port = 3478;
189 TestStunServer::~TestStunServer() {
190 // TODO(ekr@rtfm.com): Put this on the right thread.
192 // Unhook callback from our listen socket.
193 if (listen_sock_) {
194 NR_SOCKET fd;
195 if (!nr_socket_getfd(listen_sock_, &fd)) {
196 NR_ASYNC_CANCEL(fd, NR_ASYNC_WAIT_READ);
197 }
198 }
200 // Free up stun context and network resources
201 nr_stun_server_ctx_destroy(&stun_server_);
202 nr_socket_destroy(&listen_sock_);
203 nr_socket_destroy(&send_sock_);
205 // Make sure we aren't still waiting on a deferred response timer to pop
206 if (timer_handle_)
207 NR_async_timer_cancel(timer_handle_);
209 delete response_addr_;
210 }
212 int TestStunServer::TryOpenListenSocket(nr_local_addr* addr, uint16_t port) {
214 if (nr_transport_addr_set_port(&addr->addr, port)) {
215 MOZ_MTLOG(ML_ERROR, "Couldn't set port");
216 return R_INTERNAL;
217 }
219 if (nr_transport_addr_fmt_addr_string(&addr->addr)) {
220 MOZ_MTLOG(ML_ERROR, "Couldn't re-set addr string");
221 return R_INTERNAL;
222 }
224 if (nr_socket_local_create(&addr->addr, &listen_sock_)) {
225 MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
226 return R_ALREADY;
227 }
229 return 0;
230 }
232 TestStunServer* TestStunServer::Create() {
233 NR_reg_init(NR_REG_MODE_LOCAL);
235 ScopedDeletePtr<TestStunServer> server(new TestStunServer());
237 nr_local_addr addrs[100];
238 int addr_ct;
239 int r;
241 r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
242 if (r) {
243 MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
244 return nullptr;
245 }
247 if (addr_ct < 1) {
248 MOZ_MTLOG(ML_ERROR, "No local addresses");
249 return nullptr;
250 }
252 NR_SOCKET fd;
253 int tries = 10;
254 while (tries--) {
255 // Bind to the first address (arbitrarily) on configured port (default 3478)
256 r = server->TryOpenListenSocket(&addrs[0], instance_port);
257 // We interpret R_ALREADY to mean the addr is probably in use. Try another.
258 // Otherwise, it either worked or it didn't, and we check below.
259 if (r != R_ALREADY) {
260 break;
261 }
262 ++instance_port;
263 }
265 if (r) {
266 return nullptr;
267 }
269 r = nr_socket_getfd(server->listen_sock_, &fd);
270 if (r) {
271 MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
272 return nullptr;
273 }
275 r = nr_socket_wrapped_create(server->listen_sock_, &server->send_sock_);
276 if (r) {
277 MOZ_MTLOG(ML_ERROR, "Couldn't create send socket");
278 return nullptr;
279 }
281 r = nr_stun_server_ctx_create(const_cast<char *>("Test STUN server"),
282 server->send_sock_,
283 &server->stun_server_);
284 if (r) {
285 MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
286 return nullptr;
287 }
289 // Cache the address and port.
290 char addr_string[INET6_ADDRSTRLEN];
291 r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
292 sizeof(addr_string));
293 if (r) {
294 MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
295 return nullptr;
296 }
298 server->listen_addr_ = addr_string;
299 server->listen_port_ = instance_port;
301 NR_ASYNC_WAIT(fd, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server.get());
303 return server.forget();
304 }
306 void TestStunServer::ConfigurePort(uint16_t port) {
307 instance_port = port;
308 }
310 TestStunServer* TestStunServer::GetInstance() {
311 if (!instance)
312 instance = Create();
314 MOZ_ASSERT(instance);
315 return instance;
316 }
318 void TestStunServer::ShutdownInstance() {
319 delete instance;
321 instance = nullptr;
322 }
325 struct DeferredStunOperation {
326 DeferredStunOperation(TestStunServer *server,
327 const char *data, size_t len,
328 nr_transport_addr *addr) :
329 server_(server),
330 buffer_(reinterpret_cast<const uint8_t *>(data), len) {
331 nr_transport_addr_copy(&addr_, addr);
332 }
334 TestStunServer *server_;
335 DataBuffer buffer_;
336 nr_transport_addr addr_;
337 };
339 void TestStunServer::Process(const uint8_t *msg, size_t len, nr_transport_addr *addr) {
340 // Set the wrapped address so that the response goes to the right place.
341 nr_socket_wrapped_set_send_addr(send_sock_, addr);
342 nr_stun_server_process_request(stun_server_, send_sock_,
343 const_cast<char *>(reinterpret_cast<const char *>(msg)),
344 len,
345 response_addr_ ?
346 response_addr_ : addr,
347 NR_STUN_AUTH_RULE_OPTIONAL);
348 }
350 void TestStunServer::process_cb(NR_SOCKET s, int how, void *cb_arg) {
351 DeferredStunOperation *op = static_cast<DeferredStunOperation *>(cb_arg);
352 op->server_->timer_handle_ = nullptr;
353 op->server_->Process(op->buffer_.data(), op->buffer_.len(), &op->addr_);
355 delete op;
356 }
358 void TestStunServer::readable_cb(NR_SOCKET s, int how, void *cb_arg) {
359 TestStunServer* server = static_cast<TestStunServer*>(cb_arg);
361 char message[4096];
362 size_t message_len;
363 nr_transport_addr addr;
365 int r = nr_socket_recvfrom(server->listen_sock_, message, sizeof(message),
366 &message_len, 0, &addr);
368 if (r) {
369 MOZ_MTLOG(ML_ERROR, "Couldn't read STUN message");
370 return;
371 }
373 MOZ_MTLOG(ML_DEBUG, "Received data of length " << message_len);
375 // Re-arm.
376 NR_ASYNC_WAIT(s, NR_ASYNC_WAIT_READ, &TestStunServer::readable_cb, server);
379 // If we have initial dropping set, check at this point.
380 std::string key(addr.as_string);
382 if (server->received_ct_.count(key) == 0) {
383 server->received_ct_[key] = 0;
384 }
386 ++server->received_ct_[key];
388 if (!server->active_ || (server->received_ct_[key] <= server->initial_ct_)) {
389 MOZ_MTLOG(ML_DEBUG, "Dropping message #"
390 << server->received_ct_[key] << " from " << key);
391 return;
392 }
394 if (server->delay_ms_) {
395 NR_ASYNC_TIMER_SET(server->delay_ms_,
396 process_cb,
397 new DeferredStunOperation(
398 server,
399 message, message_len,
400 &addr),
401 &server->timer_handle_);
402 } else {
403 server->Process(reinterpret_cast<const uint8_t *>(message), message_len, &addr);
404 }
405 }
407 void TestStunServer::SetActive(bool active) {
408 active_ = active;
409 }
411 void TestStunServer::SetDelay(uint32_t delay_ms) {
412 delay_ms_ = delay_ms;
413 }
415 void TestStunServer::SetDropInitialPackets(uint32_t count) {
416 initial_ct_ = count;
417 }
419 nsresult TestStunServer::SetResponseAddr(nr_transport_addr *addr) {
420 delete response_addr_;
422 response_addr_ = new nr_transport_addr();
424 int r = nr_transport_addr_copy(response_addr_, addr);
425 if (r)
426 return NS_ERROR_FAILURE;
428 return NS_OK;
429 }
431 nsresult TestStunServer::SetResponseAddr(const std::string& addr,
432 uint16_t port) {
433 nr_transport_addr addr2;
435 int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
436 port, IPPROTO_UDP,
437 &addr2);
438 if (r)
439 return NS_ERROR_FAILURE;
441 return SetResponseAddr(&addr2);
442 }
444 void TestStunServer::Reset() {
445 delay_ms_ = 0;
446 if (timer_handle_) {
447 NR_async_timer_cancel(timer_handle_);
448 timer_handle_ = nullptr;
449 }
450 delete response_addr_;
451 response_addr_ = nullptr;
452 }
454 } // close namespace