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 // Original author: ekr@rtfm.com
8
9 // Some of this code is cut-and-pasted from nICEr. Copyright is:
10
11 /*
12 Copyright (c) 2007, Adobe Systems, Incorporated
13 All rights reserved.
14
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions are
17 met:
18
19 * Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
21
22 * Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
25
26 * Neither the name of Adobe Systems, Network Resonance nor the names of its
27 contributors may be used to endorse or promote products derived from
28 this software without specific prior written permission.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
36 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 */
42
43 #include <string>
44 #include <vector>
45
46 #include "nr_socket_proxy_config.h"
47 #include "nsXULAppAPI.h"
48 #include "mozilla/UniquePtr.h"
49 #include "mozilla/Unused.h"
50
51 #include "logging.h"
52 #include "nspr.h"
53 #include "nss.h"
54 #include "pk11pub.h"
55 #include "plbase64.h"
56
57 #include "nsCOMPtr.h"
58 #include "nsComponentManagerUtils.h"
59 #include "nsError.h"
60 #include "nsNetCID.h"
61 #include "nsServiceManagerUtils.h"
62 #include "ScopedNSSTypes.h"
63 #include "runnable_utils.h"
64 #include "nsIPrefService.h"
65 #include "nsIPrefBranch.h"
66 #include "nsIUUIDGenerator.h"
67
68 // nICEr includes
69 extern "C" {
70 #include "nr_api.h"
71 #include "registry.h"
72 #include "async_timer.h"
73 #include "r_crc32.h"
74 #include "r_memory.h"
75 #include "ice_reg.h"
76 #include "ice_util.h"
77 #include "transport_addr.h"
78 #include "nr_crypto.h"
79 #include "nr_socket.h"
80 #include "nr_socket_local.h"
81 #include "stun_client_ctx.h"
82 #include "stun_reg.h"
83 #include "stun_server_ctx.h"
84 #include "stun_util.h"
85 #include "ice_codeword.h"
86 #include "ice_ctx.h"
87 #include "ice_candidate.h"
88 #include "ice_handler.h"
89 }
90
91 // Local includes
92 #include "nricectx.h"
93 #include "nricemediastream.h"
94 #include "nr_socket_prsock.h"
95 #include "nrinterfaceprioritizer.h"
96 #include "rlogconnector.h"
97 #include "test_nr_socket.h"
98
99 extern "C" {
100 #include "mdns_service/mdns_service.h"
101 }
102
103 namespace mozilla {
104
105 using std::shared_ptr;
106
nr_socket_short_term_violation_time()107 TimeStamp nr_socket_short_term_violation_time() {
108 return NrSocketBase::short_term_violation_time();
109 }
110
nr_socket_long_term_violation_time()111 TimeStamp nr_socket_long_term_violation_time() {
112 return NrSocketBase::long_term_violation_time();
113 }
114
115 MOZ_MTLOG_MODULE("mtransport")
116
117 const char kNrIceTransportUdp[] = "udp";
118 const char kNrIceTransportTcp[] = "tcp";
119 const char kNrIceTransportTls[] = "tls";
120
121 static bool initialized = false;
122
noop(void ** obj)123 static int noop(void** obj) { return 0; }
124
125 static nr_socket_factory_vtbl ctx_socket_factory_vtbl = {nr_socket_local_create,
126 noop};
127
128 // Implement NSPR-based crypto algorithms
nr_crypto_nss_random_bytes(UCHAR * buf,size_t len)129 static int nr_crypto_nss_random_bytes(UCHAR* buf, size_t len) {
130 UniquePK11SlotInfo slot(PK11_GetInternalSlot());
131 if (!slot) return R_INTERNAL;
132
133 SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), buf, len);
134 if (rv != SECSuccess) return R_INTERNAL;
135
136 return 0;
137 }
138
nr_crypto_nss_hmac(UCHAR * key,size_t keyl,UCHAR * buf,size_t bufl,UCHAR * result)139 static int nr_crypto_nss_hmac(UCHAR* key, size_t keyl, UCHAR* buf, size_t bufl,
140 UCHAR* result) {
141 CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC;
142 PK11SlotInfo* slot = nullptr;
143 MOZ_ASSERT(keyl > 0);
144 SECItem keyi = {siBuffer, key, static_cast<unsigned int>(keyl)};
145 PK11SymKey* skey = nullptr;
146 PK11Context* hmac_ctx = nullptr;
147 SECStatus status;
148 unsigned int hmac_len;
149 SECItem param = {siBuffer, nullptr, 0};
150 int err = R_INTERNAL;
151
152 slot = PK11_GetInternalKeySlot();
153 if (!slot) goto abort;
154
155 skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_SIGN, &keyi,
156 nullptr);
157 if (!skey) goto abort;
158
159 hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, skey, ¶m);
160 if (!hmac_ctx) goto abort;
161
162 status = PK11_DigestBegin(hmac_ctx);
163 if (status != SECSuccess) goto abort;
164
165 status = PK11_DigestOp(hmac_ctx, buf, bufl);
166 if (status != SECSuccess) goto abort;
167
168 status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
169 if (status != SECSuccess) goto abort;
170
171 MOZ_ASSERT(hmac_len == 20);
172
173 err = 0;
174
175 abort:
176 if (hmac_ctx) PK11_DestroyContext(hmac_ctx, PR_TRUE);
177 if (skey) PK11_FreeSymKey(skey);
178 if (slot) PK11_FreeSlot(slot);
179
180 return err;
181 }
182
nr_crypto_nss_md5(UCHAR * buf,size_t bufl,UCHAR * result)183 static int nr_crypto_nss_md5(UCHAR* buf, size_t bufl, UCHAR* result) {
184 int err = R_INTERNAL;
185 SECStatus rv;
186
187 const SECHashObject* ho = HASH_GetHashObject(HASH_AlgMD5);
188 MOZ_ASSERT(ho);
189 if (!ho) goto abort;
190
191 MOZ_ASSERT(ho->length == 16);
192
193 rv = HASH_HashBuf(ho->type, result, buf, bufl);
194 if (rv != SECSuccess) goto abort;
195
196 err = 0;
197 abort:
198 return err;
199 }
200
201 static nr_ice_crypto_vtbl nr_ice_crypto_nss_vtbl = {
202 nr_crypto_nss_random_bytes, nr_crypto_nss_hmac, nr_crypto_nss_md5};
203
ToNicerStunStruct(nr_ice_stun_server * server) const204 nsresult NrIceStunServer::ToNicerStunStruct(nr_ice_stun_server* server) const {
205 int r;
206
207 memset(server, 0, sizeof(nr_ice_stun_server));
208 uint8_t protocol;
209 if (transport_ == kNrIceTransportUdp) {
210 protocol = IPPROTO_UDP;
211 } else if (transport_ == kNrIceTransportTcp) {
212 protocol = IPPROTO_TCP;
213 } else if (transport_ == kNrIceTransportTls) {
214 protocol = IPPROTO_TCP;
215 } else {
216 MOZ_MTLOG(ML_ERROR, "Unsupported STUN server transport: " << transport_);
217 return NS_ERROR_FAILURE;
218 }
219
220 if (has_addr_) {
221 if (transport_ == kNrIceTransportTls) {
222 // Refuse to try TLS without an FQDN
223 return NS_ERROR_INVALID_ARG;
224 }
225 r = nr_praddr_to_transport_addr(&addr_, &server->addr, protocol, 0);
226 if (r) {
227 return NS_ERROR_FAILURE;
228 }
229 } else {
230 MOZ_ASSERT(sizeof(server->addr.fqdn) > host_.size());
231 // Dummy information to keep nICEr happy
232 if (use_ipv6_if_fqdn_) {
233 nr_str_port_to_transport_addr("::", port_, protocol, &server->addr);
234 } else {
235 nr_str_port_to_transport_addr("0.0.0.0", port_, protocol, &server->addr);
236 }
237 PL_strncpyz(server->addr.fqdn, host_.c_str(), sizeof(server->addr.fqdn));
238 if (transport_ == kNrIceTransportTls) {
239 server->addr.tls = 1;
240 }
241 }
242
243 nr_transport_addr_fmt_addr_string(&server->addr);
244
245 return NS_OK;
246 }
247
ToNicerTurnStruct(nr_ice_turn_server * server) const248 nsresult NrIceTurnServer::ToNicerTurnStruct(nr_ice_turn_server* server) const {
249 memset(server, 0, sizeof(nr_ice_turn_server));
250
251 nsresult rv = ToNicerStunStruct(&server->turn_server);
252 if (NS_FAILED(rv)) return rv;
253
254 if (!(server->username = r_strdup(username_.c_str())))
255 return NS_ERROR_OUT_OF_MEMORY;
256
257 // TODO(ekr@rtfm.com): handle non-ASCII passwords somehow?
258 // STUN requires they be SASLpreped, but we don't know if
259 // they are at this point.
260
261 // C++03 23.2.4, Paragraph 1 stipulates that the elements
262 // in std::vector must be contiguous, and can therefore be
263 // used as input to functions expecting C arrays.
264 const UCHAR* data = password_.empty() ? nullptr : &password_[0];
265 int r = r_data_create(&server->password, data, password_.size());
266 if (r) {
267 RFREE(server->username);
268 return NS_ERROR_OUT_OF_MEMORY;
269 }
270
271 return NS_OK;
272 }
273
NrIceCtx(const std::string & name)274 NrIceCtx::NrIceCtx(const std::string& name)
275 : connection_state_(ICE_CTX_INIT),
276 gathering_state_(ICE_CTX_GATHER_INIT),
277 name_(name),
278 ice_controlling_set_(false),
279 streams_(),
280 ctx_(nullptr),
281 peer_(nullptr),
282 ice_handler_vtbl_(nullptr),
283 ice_handler_(nullptr),
284 trickle_(true),
285 config_(),
286 nat_(nullptr),
287 proxy_config_(nullptr),
288 obfuscate_host_addresses_(false) {}
289
290 /* static */
Create(const std::string & aName)291 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& aName) {
292 RefPtr<NrIceCtx> ctx = new NrIceCtx(aName);
293
294 if (!ctx->Initialize()) {
295 return nullptr;
296 }
297
298 return ctx;
299 }
300
SetIceConfig(const Config & aConfig)301 nsresult NrIceCtx::SetIceConfig(const Config& aConfig) {
302 config_ = aConfig;
303 switch (config_.mPolicy) {
304 case ICE_POLICY_RELAY:
305 MOZ_MTLOG(ML_DEBUG, "SetIceConfig: relay only");
306 nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES);
307 nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_RELAY_ONLY);
308 break;
309 case ICE_POLICY_NO_HOST:
310 MOZ_MTLOG(ML_DEBUG, "SetIceConfig: no host");
311 nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES);
312 nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_RELAY_ONLY);
313 break;
314 case ICE_POLICY_ALL:
315 MOZ_MTLOG(ML_DEBUG, "SetIceConfig: all");
316 nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES);
317 nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_RELAY_ONLY);
318 break;
319 }
320
321 // TODO: Support re-configuring the test NAT someday?
322 if (!nat_ && config_.mNatSimulatorConfig.isSome()) {
323 TestNat* test_nat = new TestNat;
324 test_nat->filtering_type_ = TestNat::ToNatBehavior(
325 config_.mNatSimulatorConfig->mFilteringType.get());
326 test_nat->mapping_type_ =
327 TestNat::ToNatBehavior(config_.mNatSimulatorConfig->mMappingType.get());
328 test_nat->block_udp_ = config_.mNatSimulatorConfig->mBlockUdp;
329 test_nat->block_tcp_ = config_.mNatSimulatorConfig->mBlockTcp;
330 test_nat->block_tls_ = config_.mNatSimulatorConfig->mBlockTls;
331 test_nat->error_code_for_drop_ =
332 config_.mNatSimulatorConfig->mErrorCodeForDrop;
333 if (config_.mNatSimulatorConfig->mRedirectAddress.Length()) {
334 test_nat
335 ->stun_redirect_map_[config_.mNatSimulatorConfig->mRedirectAddress] =
336 config_.mNatSimulatorConfig->mRedirectTargets;
337 }
338 test_nat->enabled_ = true;
339 SetNat(test_nat);
340 }
341
342 return NS_OK;
343 }
344
CreateStream(const std::string & id,const std::string & name,int components)345 RefPtr<NrIceMediaStream> NrIceCtx::CreateStream(const std::string& id,
346 const std::string& name,
347 int components) {
348 if (streams_.count(id)) {
349 MOZ_ASSERT(false);
350 return nullptr;
351 }
352
353 RefPtr<NrIceMediaStream> stream =
354 new NrIceMediaStream(this, id, name, components);
355 streams_[id] = stream;
356 return stream;
357 }
358
DestroyStream(const std::string & id)359 void NrIceCtx::DestroyStream(const std::string& id) {
360 auto it = streams_.find(id);
361 if (it != streams_.end()) {
362 auto preexisting_stream = it->second;
363 streams_.erase(it);
364 preexisting_stream->Close();
365 }
366
367 if (streams_.empty()) {
368 SetGatheringState(ICE_CTX_GATHER_INIT);
369 }
370 }
371
372 // Handler callbacks
select_pair(void * obj,nr_ice_media_stream * stream,int component_id,nr_ice_cand_pair ** potentials,int potential_ct)373 int NrIceCtx::select_pair(void* obj, nr_ice_media_stream* stream,
374 int component_id, nr_ice_cand_pair** potentials,
375 int potential_ct) {
376 MOZ_MTLOG(ML_DEBUG, "select pair called: potential_ct = " << potential_ct);
377 MOZ_ASSERT(stream->local_stream);
378 MOZ_ASSERT(!stream->local_stream->obsolete);
379
380 return 0;
381 }
382
stream_ready(void * obj,nr_ice_media_stream * stream)383 int NrIceCtx::stream_ready(void* obj, nr_ice_media_stream* stream) {
384 MOZ_MTLOG(ML_DEBUG, "stream_ready called");
385 MOZ_ASSERT(!stream->local_stream);
386 MOZ_ASSERT(!stream->obsolete);
387
388 // Get the ICE ctx.
389 NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
390
391 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
392
393 // Streams which do not exist should never be ready.
394 MOZ_ASSERT(s);
395
396 s->Ready();
397
398 return 0;
399 }
400
stream_failed(void * obj,nr_ice_media_stream * stream)401 int NrIceCtx::stream_failed(void* obj, nr_ice_media_stream* stream) {
402 MOZ_MTLOG(ML_DEBUG, "stream_failed called");
403 MOZ_ASSERT(!stream->local_stream);
404 MOZ_ASSERT(!stream->obsolete);
405
406 // Get the ICE ctx
407 NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
408 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
409
410 // Streams which do not exist should never fail.
411 MOZ_ASSERT(s);
412
413 ctx->SetConnectionState(ICE_CTX_FAILED);
414 s->Failed();
415 return 0;
416 }
417
ice_checking(void * obj,nr_ice_peer_ctx * pctx)418 int NrIceCtx::ice_checking(void* obj, nr_ice_peer_ctx* pctx) {
419 MOZ_MTLOG(ML_DEBUG, "ice_checking called");
420
421 // Get the ICE ctx
422 NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
423
424 ctx->SetConnectionState(ICE_CTX_CHECKING);
425
426 return 0;
427 }
428
ice_connected(void * obj,nr_ice_peer_ctx * pctx)429 int NrIceCtx::ice_connected(void* obj, nr_ice_peer_ctx* pctx) {
430 MOZ_MTLOG(ML_DEBUG, "ice_connected called");
431
432 // Get the ICE ctx
433 NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
434
435 // This is called even on failed contexts.
436 if (ctx->connection_state() != ICE_CTX_FAILED) {
437 ctx->SetConnectionState(ICE_CTX_CONNECTED);
438 }
439
440 return 0;
441 }
442
ice_disconnected(void * obj,nr_ice_peer_ctx * pctx)443 int NrIceCtx::ice_disconnected(void* obj, nr_ice_peer_ctx* pctx) {
444 MOZ_MTLOG(ML_DEBUG, "ice_disconnected called");
445
446 // Get the ICE ctx
447 NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
448
449 ctx->SetConnectionState(ICE_CTX_DISCONNECTED);
450
451 return 0;
452 }
453
msg_recvd(void * obj,nr_ice_peer_ctx * pctx,nr_ice_media_stream * stream,int component_id,UCHAR * msg,int len)454 int NrIceCtx::msg_recvd(void* obj, nr_ice_peer_ctx* pctx,
455 nr_ice_media_stream* stream, int component_id,
456 UCHAR* msg, int len) {
457 // Get the ICE ctx
458 NrIceCtx* ctx = static_cast<NrIceCtx*>(obj);
459 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
460
461 // Streams which do not exist should never have packets.
462 MOZ_ASSERT(s);
463
464 s->SignalPacketReceived(s, component_id, msg, len);
465
466 return 0;
467 }
468
trickle_cb(void * arg,nr_ice_ctx * ice_ctx,nr_ice_media_stream * stream,int component_id,nr_ice_candidate * candidate)469 void NrIceCtx::trickle_cb(void* arg, nr_ice_ctx* ice_ctx,
470 nr_ice_media_stream* stream, int component_id,
471 nr_ice_candidate* candidate) {
472 if (stream->obsolete) {
473 // Stream was probably just marked obsolete, resulting in this callback
474 return;
475 }
476 // Get the ICE ctx
477 NrIceCtx* ctx = static_cast<NrIceCtx*>(arg);
478 RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
479
480 if (!s) {
481 // This stream has been removed because it is inactive
482 return;
483 }
484
485 if (!candidate) {
486 s->SignalCandidate(s, "", stream->ufrag, "", "");
487 return;
488 }
489
490 std::string actual_addr;
491 std::string mdns_addr;
492 ctx->GenerateObfuscatedAddress(candidate, &mdns_addr, &actual_addr);
493
494 // Format the candidate.
495 char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
496 int r = nr_ice_format_candidate_attribute(candidate, candidate_str,
497 sizeof(candidate_str),
498 ctx->obfuscate_host_addresses_);
499 MOZ_ASSERT(!r);
500 if (r) return;
501
502 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << ctx->name_ << "): trickling candidate "
503 << candidate_str);
504
505 s->SignalCandidate(s, candidate_str, stream->ufrag, mdns_addr, actual_addr);
506 }
507
InitializeGlobals(const GlobalConfig & aConfig)508 void NrIceCtx::InitializeGlobals(const GlobalConfig& aConfig) {
509 RLogConnector::CreateInstance();
510 // Initialize the crypto callbacks and logging stuff
511 if (!initialized) {
512 NR_reg_init(NR_REG_MODE_LOCAL);
513 nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
514 initialized = true;
515
516 // Set the priorites for candidate type preferences.
517 // These numbers come from RFC 5245 S. 4.1.2.2
518 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_SRV_RFLX, 100);
519 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_PEER_RFLX, 110);
520 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_HOST, 126);
521 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_RELAYED, 5);
522 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP, 99);
523 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP, 109);
524 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_HOST_TCP, 125);
525 NR_reg_set_uchar((char*)NR_ICE_REG_PREF_TYPE_RELAYED_TCP, 0);
526 NR_reg_set_uint4((char*)"stun.client.maximum_transmits",
527 aConfig.mStunClientMaxTransmits);
528 NR_reg_set_uint4((char*)NR_ICE_REG_TRICKLE_GRACE_PERIOD,
529 aConfig.mTrickleIceGracePeriod);
530 NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_SO_SOCK_COUNT,
531 aConfig.mIceTcpSoSockCount);
532 NR_reg_set_int4((char*)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
533 aConfig.mIceTcpListenBacklog);
534
535 NR_reg_set_char((char*)NR_ICE_REG_ICE_TCP_DISABLE, !aConfig.mTcpEnabled);
536
537 if (aConfig.mAllowLoopback) {
538 NR_reg_set_char((char*)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
539 }
540
541 if (aConfig.mAllowLinkLocal) {
542 NR_reg_set_char((char*)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
543 }
544 if (!aConfig.mForceNetInterface.Length()) {
545 NR_reg_set_string((char*)NR_ICE_REG_PREF_FORCE_INTERFACE_NAME,
546 const_cast<char*>(aConfig.mForceNetInterface.get()));
547 }
548
549 // For now, always use nr_resolver for UDP.
550 NR_reg_set_char((char*)NR_ICE_REG_USE_NR_RESOLVER_FOR_UDP, 1);
551
552 // Use nr_resolver for TCP only when not in e10s mode (for unit-tests)
553 if (XRE_IsParentProcess()) {
554 NR_reg_set_char((char*)NR_ICE_REG_USE_NR_RESOLVER_FOR_TCP, 1);
555 }
556 }
557 }
558
SetTargetForDefaultLocalAddressLookup(const std::string & target_ip,uint16_t target_port)559 void NrIceCtx::SetTargetForDefaultLocalAddressLookup(
560 const std::string& target_ip, uint16_t target_port) {
561 nr_ice_set_target_for_default_local_address_lookup(ctx_, target_ip.c_str(),
562 target_port);
563 }
564
565 #define MAXADDRS 100 // mirrors setting in ice_ctx.c
566
567 /* static */
GetStunAddrs()568 nsTArray<NrIceStunAddr> NrIceCtx::GetStunAddrs() {
569 nsTArray<NrIceStunAddr> addrs;
570
571 nr_local_addr local_addrs[MAXADDRS];
572 int addr_ct = 0;
573
574 // most likely running on parent process and need crypto vtbl
575 // initialized on Windows (Linux and OSX don't seem to care)
576 if (!initialized) {
577 nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
578 }
579
580 MOZ_MTLOG(ML_INFO, "NrIceCtx static call to find local stun addresses");
581 if (nr_stun_find_local_addresses(local_addrs, MAXADDRS, &addr_ct)) {
582 MOZ_MTLOG(ML_INFO, "Error finding local stun addresses");
583 } else {
584 for (int i = 0; i < addr_ct; ++i) {
585 NrIceStunAddr addr(&local_addrs[i]);
586 addrs.AppendElement(addr);
587 }
588 }
589
590 return addrs;
591 }
592
SetStunAddrs(const nsTArray<NrIceStunAddr> & addrs)593 void NrIceCtx::SetStunAddrs(const nsTArray<NrIceStunAddr>& addrs) {
594 nr_local_addr* local_addrs;
595 local_addrs = new nr_local_addr[addrs.Length()];
596
597 for (size_t i = 0; i < addrs.Length(); ++i) {
598 nr_local_addr_copy(&local_addrs[i],
599 const_cast<nr_local_addr*>(&addrs[i].localAddr()));
600 }
601 nr_ice_set_local_addresses(ctx_, local_addrs, addrs.Length());
602
603 delete[] local_addrs;
604 }
605
Initialize()606 bool NrIceCtx::Initialize() {
607 // Create the ICE context
608 int r;
609
610 UINT4 flags = NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
611 r = nr_ice_ctx_create(const_cast<char*>(name_.c_str()), flags, &ctx_);
612
613 if (r) {
614 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE ctx for '" << name_ << "'");
615 return false;
616 }
617
618 // override default factory to capture optional proxy config when creating
619 // sockets.
620 nr_socket_factory* factory;
621 r = nr_socket_factory_create_int(this, &ctx_socket_factory_vtbl, &factory);
622
623 if (r) {
624 MOZ_MTLOG(LogLevel::Error, "Couldn't create ctx socket factory.");
625 return false;
626 }
627 nr_ice_ctx_set_socket_factory(ctx_, factory);
628
629 nr_interface_prioritizer* prioritizer = CreateInterfacePrioritizer();
630 if (!prioritizer) {
631 MOZ_MTLOG(LogLevel::Error, "Couldn't create interface prioritizer.");
632 return false;
633 }
634
635 r = nr_ice_ctx_set_interface_prioritizer(ctx_, prioritizer);
636 if (r) {
637 MOZ_MTLOG(LogLevel::Error, "Couldn't set interface prioritizer.");
638 return false;
639 }
640
641 if (generating_trickle()) {
642 r = nr_ice_ctx_set_trickle_cb(ctx_, &NrIceCtx::trickle_cb, this);
643 if (r) {
644 MOZ_MTLOG(ML_ERROR, "Couldn't set trickle cb for '" << name_ << "'");
645 return false;
646 }
647 }
648
649 // Create the handler objects
650 ice_handler_vtbl_ = new nr_ice_handler_vtbl();
651 ice_handler_vtbl_->select_pair = &NrIceCtx::select_pair;
652 ice_handler_vtbl_->stream_ready = &NrIceCtx::stream_ready;
653 ice_handler_vtbl_->stream_failed = &NrIceCtx::stream_failed;
654 ice_handler_vtbl_->ice_connected = &NrIceCtx::ice_connected;
655 ice_handler_vtbl_->msg_recvd = &NrIceCtx::msg_recvd;
656 ice_handler_vtbl_->ice_checking = &NrIceCtx::ice_checking;
657 ice_handler_vtbl_->ice_disconnected = &NrIceCtx::ice_disconnected;
658
659 ice_handler_ = new nr_ice_handler();
660 ice_handler_->vtbl = ice_handler_vtbl_;
661 ice_handler_->obj = this;
662
663 // Create the peer ctx. Because we do not support parallel forking, we
664 // only have one peer ctx.
665 std::string peer_name = name_ + ":default";
666 r = nr_ice_peer_ctx_create(ctx_, ice_handler_,
667 const_cast<char*>(peer_name.c_str()), &peer_);
668 if (r) {
669 MOZ_MTLOG(ML_ERROR, "Couldn't create ICE peer ctx for '" << name_ << "'");
670 return false;
671 }
672
673 nsresult rv;
674 sts_target_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
675
676 if (!NS_SUCCEEDED(rv)) return false;
677
678 return true;
679 }
680
SetNat(const RefPtr<TestNat> & aNat)681 int NrIceCtx::SetNat(const RefPtr<TestNat>& aNat) {
682 nat_ = aNat;
683 nr_socket_factory* fac;
684 int r = nat_->create_socket_factory(&fac);
685 if (r) {
686 return r;
687 }
688 nr_ice_ctx_set_socket_factory(ctx_, fac);
689 return 0;
690 }
691
692 // ONLY USE THIS FOR TESTING. Will cause totally unpredictable and possibly very
693 // bad effects if ICE is still live.
internal_DeinitializeGlobal()694 void NrIceCtx::internal_DeinitializeGlobal() {
695 NR_reg_del((char*)"stun");
696 NR_reg_del((char*)"ice");
697 RLogConnector::DestroyInstance();
698 nr_crypto_vtbl = nullptr;
699 initialized = false;
700 }
701
internal_SetTimerAccelarator(int divider)702 void NrIceCtx::internal_SetTimerAccelarator(int divider) {
703 ctx_->test_timer_divider = divider;
704 }
705
AccumulateStats(const NrIceStats & stats)706 void NrIceCtx::AccumulateStats(const NrIceStats& stats) {
707 nr_accumulate_count(&(ctx_->stats.stun_retransmits), stats.stun_retransmits);
708 nr_accumulate_count(&(ctx_->stats.turn_401s), stats.turn_401s);
709 nr_accumulate_count(&(ctx_->stats.turn_403s), stats.turn_403s);
710 nr_accumulate_count(&(ctx_->stats.turn_438s), stats.turn_438s);
711 }
712
Destroy()713 NrIceStats NrIceCtx::Destroy() {
714 // designed to be called more than once so if stats are desired, this can be
715 // called just prior to the destructor
716 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
717
718 for (auto& idAndStream : streams_) {
719 idAndStream.second->Close();
720 }
721
722 NrIceStats stats;
723 if (ctx_) {
724 stats.stun_retransmits = ctx_->stats.stun_retransmits;
725 stats.turn_401s = ctx_->stats.turn_401s;
726 stats.turn_403s = ctx_->stats.turn_403s;
727 stats.turn_438s = ctx_->stats.turn_438s;
728 }
729
730 if (peer_) {
731 nr_ice_peer_ctx_destroy(&peer_);
732 }
733 if (ctx_) {
734 nr_ice_ctx_destroy(&ctx_);
735 }
736
737 delete ice_handler_vtbl_;
738 delete ice_handler_;
739
740 ice_handler_vtbl_ = nullptr;
741 ice_handler_ = nullptr;
742 proxy_config_ = nullptr;
743 streams_.clear();
744
745 return stats;
746 }
747
748 NrIceCtx::~NrIceCtx() = default;
749
destroy_peer_ctx()750 void NrIceCtx::destroy_peer_ctx() { nr_ice_peer_ctx_destroy(&peer_); }
751
SetControlling(Controlling controlling)752 nsresult NrIceCtx::SetControlling(Controlling controlling) {
753 if (!ice_controlling_set_) {
754 peer_->controlling = (controlling == ICE_CONTROLLING) ? 1 : 0;
755 ice_controlling_set_ = true;
756
757 MOZ_MTLOG(ML_DEBUG,
758 "ICE ctx " << name_ << " setting controlling to" << controlling);
759 }
760 return NS_OK;
761 }
762
GetControlling()763 NrIceCtx::Controlling NrIceCtx::GetControlling() {
764 return (peer_->controlling) ? ICE_CONTROLLING : ICE_CONTROLLED;
765 }
766
SetStunServers(const std::vector<NrIceStunServer> & stun_servers)767 nsresult NrIceCtx::SetStunServers(
768 const std::vector<NrIceStunServer>& stun_servers) {
769 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
770 // We assume nr_ice_stun_server is memmoveable. That's true right now.
771 std::vector<nr_ice_stun_server> servers;
772
773 for (size_t i = 0; i < stun_servers.size(); ++i) {
774 nr_ice_stun_server server;
775 nsresult rv = stun_servers[i].ToNicerStunStruct(&server);
776 if (NS_WARN_IF(NS_FAILED(rv))) {
777 MOZ_MTLOG(ML_ERROR, "Couldn't convert STUN server for '" << name_ << "'");
778 } else {
779 servers.push_back(server);
780 }
781 }
782
783 int r = nr_ice_ctx_set_stun_servers(ctx_, servers.data(),
784 static_cast<int>(servers.size()));
785 if (r) {
786 MOZ_MTLOG(ML_ERROR, "Couldn't set STUN servers for '" << name_ << "'");
787 return NS_ERROR_FAILURE;
788 }
789
790 return NS_OK;
791 }
792
793 // TODO(ekr@rtfm.com): This is just SetStunServers with s/Stun/Turn
794 // Could we do a template or something?
SetTurnServers(const std::vector<NrIceTurnServer> & turn_servers)795 nsresult NrIceCtx::SetTurnServers(
796 const std::vector<NrIceTurnServer>& turn_servers) {
797 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
798 // We assume nr_ice_turn_server is memmoveable. That's true right now.
799 std::vector<nr_ice_turn_server> servers;
800
801 for (size_t i = 0; i < turn_servers.size(); ++i) {
802 nr_ice_turn_server server;
803 nsresult rv = turn_servers[i].ToNicerTurnStruct(&server);
804 if (NS_WARN_IF(NS_FAILED(rv))) {
805 MOZ_MTLOG(ML_ERROR, "Couldn't convert TURN server for '" << name_ << "'");
806 } else {
807 servers.push_back(server);
808 }
809 }
810
811 int r = nr_ice_ctx_set_turn_servers(ctx_, servers.data(),
812 static_cast<int>(servers.size()));
813 if (r) {
814 MOZ_MTLOG(ML_ERROR, "Couldn't set TURN servers for '" << name_ << "'");
815 // TODO(ekr@rtfm.com): This leaks the username/password. Need to free that.
816 return NS_ERROR_FAILURE;
817 }
818
819 return NS_OK;
820 }
821
SetResolver(nr_resolver * resolver)822 nsresult NrIceCtx::SetResolver(nr_resolver* resolver) {
823 int r = nr_ice_ctx_set_resolver(ctx_, resolver);
824
825 if (r) {
826 MOZ_MTLOG(ML_ERROR, "Couldn't set resolver for '" << name_ << "'");
827 return NS_ERROR_FAILURE;
828 }
829
830 return NS_OK;
831 }
832
SetProxyConfig(NrSocketProxyConfig && config)833 nsresult NrIceCtx::SetProxyConfig(NrSocketProxyConfig&& config) {
834 proxy_config_.reset(new NrSocketProxyConfig(std::move(config)));
835 if (nat_) {
836 nat_->set_proxy_config(proxy_config_);
837 }
838 return NS_OK;
839 }
840
SetCtxFlags(bool default_route_only)841 void NrIceCtx::SetCtxFlags(bool default_route_only) {
842 ASSERT_ON_THREAD(sts_target_);
843
844 if (default_route_only) {
845 nr_ice_ctx_add_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS);
846 } else {
847 nr_ice_ctx_remove_flags(ctx_, NR_ICE_CTX_FLAGS_ONLY_DEFAULT_ADDRS);
848 }
849 }
850
StartGathering(bool default_route_only,bool obfuscate_host_addresses)851 nsresult NrIceCtx::StartGathering(bool default_route_only,
852 bool obfuscate_host_addresses) {
853 ASSERT_ON_THREAD(sts_target_);
854 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
855
856 obfuscate_host_addresses_ = obfuscate_host_addresses;
857
858 SetCtxFlags(default_route_only);
859
860 // This might start gathering for the first time, or again after
861 // renegotiation, or might do nothing at all if gathering has already
862 // finished.
863 int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this);
864
865 if (!r) {
866 SetGatheringState(ICE_CTX_GATHER_COMPLETE);
867 } else if (r == R_WOULDBLOCK) {
868 SetGatheringState(ICE_CTX_GATHER_STARTED);
869 } else {
870 SetGatheringState(ICE_CTX_GATHER_COMPLETE);
871 MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't gather ICE candidates for '"
872 << name_ << "', error=" << r);
873 SetConnectionState(ICE_CTX_FAILED);
874 return NS_ERROR_FAILURE;
875 }
876
877 return NS_OK;
878 }
879
FindStream(nr_ice_media_stream * stream)880 RefPtr<NrIceMediaStream> NrIceCtx::FindStream(nr_ice_media_stream* stream) {
881 for (auto& idAndStream : streams_) {
882 if (idAndStream.second->HasStream(stream)) {
883 return idAndStream.second;
884 }
885 }
886
887 return nullptr;
888 }
889
GetGlobalAttributes()890 std::vector<std::string> NrIceCtx::GetGlobalAttributes() {
891 char** attrs = nullptr;
892 int attrct;
893 int r;
894 std::vector<std::string> ret;
895
896 r = nr_ice_get_global_attributes(ctx_, &attrs, &attrct);
897 if (r) {
898 MOZ_MTLOG(ML_ERROR,
899 "Couldn't get ufrag and password for '" << name_ << "'");
900 return ret;
901 }
902
903 for (int i = 0; i < attrct; i++) {
904 ret.push_back(std::string(attrs[i]));
905 RFREE(attrs[i]);
906 }
907 RFREE(attrs);
908
909 return ret;
910 }
911
ParseGlobalAttributes(std::vector<std::string> attrs)912 nsresult NrIceCtx::ParseGlobalAttributes(std::vector<std::string> attrs) {
913 std::vector<char*> attrs_in;
914 attrs_in.reserve(attrs.size());
915 for (auto& attr : attrs) {
916 attrs_in.push_back(const_cast<char*>(attr.c_str()));
917 }
918
919 int r = nr_ice_peer_ctx_parse_global_attributes(
920 peer_, attrs_in.empty() ? nullptr : &attrs_in[0], attrs_in.size());
921 if (r) {
922 MOZ_MTLOG(ML_ERROR,
923 "Couldn't parse global attributes for " << name_ << "'");
924 return NS_ERROR_FAILURE;
925 }
926
927 return NS_OK;
928 }
929
HasStreamsToConnect() const930 bool NrIceCtx::HasStreamsToConnect() const {
931 for (auto& idAndStream : streams_) {
932 if (idAndStream.second->state() != NrIceMediaStream::ICE_CLOSED) {
933 return true;
934 }
935 }
936 return false;
937 }
938
StartChecks()939 nsresult NrIceCtx::StartChecks() {
940 int r;
941 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): " << __func__);
942
943 if (!HasStreamsToConnect()) {
944 MOZ_MTLOG(ML_NOTICE, "In StartChecks, nothing to do on " << name_);
945 return NS_OK;
946 }
947
948 r = nr_ice_peer_ctx_pair_candidates(peer_);
949 if (r) {
950 MOZ_MTLOG(ML_ERROR, "ICE FAILED: Couldn't pair candidates on " << name_);
951 SetConnectionState(ICE_CTX_FAILED);
952 return NS_ERROR_FAILURE;
953 }
954
955 r = nr_ice_peer_ctx_start_checks2(peer_, 1);
956 if (r) {
957 if (r == R_NOT_FOUND) {
958 MOZ_MTLOG(ML_INFO, "Couldn't start peer checks on "
959 << name_ << ", assuming trickle ICE");
960 } else {
961 MOZ_MTLOG(ML_ERROR,
962 "ICE FAILED: Couldn't start peer checks on " << name_);
963 SetConnectionState(ICE_CTX_FAILED);
964 return NS_ERROR_FAILURE;
965 }
966 }
967
968 return NS_OK;
969 }
970
gather_cb(NR_SOCKET s,int h,void * arg)971 void NrIceCtx::gather_cb(NR_SOCKET s, int h, void* arg) {
972 NrIceCtx* ctx = static_cast<NrIceCtx*>(arg);
973
974 ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);
975 }
976
UpdateNetworkState(bool online)977 void NrIceCtx::UpdateNetworkState(bool online) {
978 MOZ_MTLOG(ML_NOTICE, "NrIceCtx(" << name_ << "): updating network state to "
979 << (online ? "online" : "offline"));
980 if (connection_state_ == ICE_CTX_CLOSED) {
981 return;
982 }
983
984 if (online) {
985 nr_ice_peer_ctx_refresh_consent_all_streams(peer_);
986 } else {
987 nr_ice_peer_ctx_disconnect_all_streams(peer_);
988 }
989 }
990
SetConnectionState(ConnectionState state)991 void NrIceCtx::SetConnectionState(ConnectionState state) {
992 if (state == connection_state_) return;
993
994 MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " << connection_state_
995 << "->" << state);
996 connection_state_ = state;
997
998 if (connection_state_ == ICE_CTX_FAILED) {
999 MOZ_MTLOG(ML_INFO,
1000 "NrIceCtx(" << name_ << "): dumping r_log ringbuffer... ");
1001 std::deque<std::string> logs;
1002 RLogConnector::GetInstance()->GetAny(0, &logs);
1003 for (auto& log : logs) {
1004 MOZ_MTLOG(ML_INFO, log);
1005 }
1006 }
1007
1008 SignalConnectionStateChange(this, state);
1009 }
1010
SetGatheringState(GatheringState state)1011 void NrIceCtx::SetGatheringState(GatheringState state) {
1012 if (state == gathering_state_) return;
1013
1014 MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): gathering state "
1015 << gathering_state_ << "->" << state);
1016 gathering_state_ = state;
1017
1018 SignalGatheringStateChange(this, state);
1019 }
1020
GenerateObfuscatedAddress(nr_ice_candidate * candidate,std::string * mdns_address,std::string * actual_address)1021 void NrIceCtx::GenerateObfuscatedAddress(nr_ice_candidate* candidate,
1022 std::string* mdns_address,
1023 std::string* actual_address) {
1024 if (candidate->type == HOST && obfuscate_host_addresses_) {
1025 char addr[64];
1026 if (nr_transport_addr_get_addrstring(&candidate->addr, addr,
1027 sizeof(addr))) {
1028 return;
1029 }
1030
1031 *actual_address = addr;
1032
1033 const auto& iter = obfuscated_host_addresses_.find(*actual_address);
1034 if (iter != obfuscated_host_addresses_.end()) {
1035 *mdns_address = iter->second;
1036 } else {
1037 nsresult rv;
1038 nsCOMPtr<nsIUUIDGenerator> uuidgen =
1039 do_GetService("@mozilla.org/uuid-generator;1", &rv);
1040 // If this fails, we'll return a zero UUID rather than something
1041 // unexpected.
1042 nsID id = {};
1043 id.Clear();
1044 if (NS_SUCCEEDED(rv)) {
1045 rv = uuidgen->GenerateUUIDInPlace(&id);
1046 if (NS_FAILED(rv)) {
1047 id.Clear();
1048 }
1049 }
1050
1051 char chars[NSID_LENGTH];
1052 id.ToProvidedString(chars);
1053 // The string will look like {64888863-a253-424a-9b30-1ed285d20142},
1054 // we want to trim off the braces.
1055 const char* ptr_to_id = chars;
1056 ++ptr_to_id;
1057 chars[NSID_LENGTH - 2] = 0;
1058
1059 std::ostringstream o;
1060 o << ptr_to_id << ".local";
1061 *mdns_address = o.str();
1062
1063 obfuscated_host_addresses_[*actual_address] = *mdns_address;
1064 }
1065 candidate->mdns_addr = r_strdup(mdns_address->c_str());
1066 }
1067 }
1068
1069 } // namespace mozilla
1070
1071 // Reimplement nr_ice_compute_codeword to avoid copyright issues
nr_ice_compute_codeword(char * buf,int len,char * codeword)1072 void nr_ice_compute_codeword(char* buf, int len, char* codeword) {
1073 UINT4 c;
1074
1075 r_crc32(buf, len, &c);
1076
1077 PL_Base64Encode(reinterpret_cast<char*>(&c), 3, codeword);
1078 codeword[4] = 0;
1079 }
1080
nr_socket_local_create(void * obj,nr_transport_addr * addr,nr_socket ** sockp)1081 int nr_socket_local_create(void* obj, nr_transport_addr* addr,
1082 nr_socket** sockp) {
1083 using namespace mozilla;
1084
1085 RefPtr<NrSocketBase> sock;
1086 int r, _status;
1087 shared_ptr<NrSocketProxyConfig> config = nullptr;
1088
1089 if (obj) {
1090 config = static_cast<NrIceCtx*>(obj)->GetProxyConfig();
1091 }
1092
1093 r = NrSocketBase::CreateSocket(addr, &sock, config);
1094 if (r) {
1095 ABORT(r);
1096 }
1097
1098 r = nr_socket_create_int(static_cast<void*>(sock), sock->vtbl(), sockp);
1099 if (r) ABORT(r);
1100
1101 _status = 0;
1102
1103 {
1104 // We will release this reference in destroy(), not exactly the normal
1105 // ownership model, but it is what it is.
1106 NrSocketBase* dummy = sock.forget().take();
1107 (void)dummy;
1108 }
1109
1110 abort:
1111 return _status;
1112 }
1113