1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 * Neither the name of Adobe Systems, Network Resonance nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <csi_platform.h>
34 #include <assert.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/queue.h>
38 #include <sys/types.h>
39 #ifdef WIN32
40 #include <winsock2.h>
41 #else
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #endif
46 #include "nr_api.h"
47 #include "registry.h"
48 #include "nr_socket.h"
49 #include "async_timer.h"
50
51 #include "stun_client_ctx.h"
52 #include "stun_server_ctx.h"
53 #include "turn_client_ctx.h"
54 #include "ice_ctx.h"
55 #include "ice_candidate.h"
56 #include "ice_codeword.h"
57 #include "ice_reg.h"
58 #include "ice_util.h"
59 #include "nr_socket_turn.h"
60 #include "nr_socket.h"
61 #include "nr_socket_multi_tcp.h"
62
63 static int next_automatic_preference = 127;
64
65 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
66 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
67 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
68 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
69 #ifdef USE_TURN
70 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
71 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
72 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr);
73 #endif /* USE_TURN */
74
nr_ice_candidate_compute_codeword(nr_ice_candidate * cand)75 void nr_ice_candidate_compute_codeword(nr_ice_candidate *cand)
76 {
77 char as_string[1024];
78
79 snprintf(as_string,
80 sizeof(as_string),
81 "%s(%s)",
82 cand->addr.as_string,
83 cand->label);
84
85 nr_ice_compute_codeword(as_string,strlen(as_string),cand->codeword);
86 }
87
88 char *nr_ice_candidate_type_names[]={0,"host","srflx","prflx","relay",0};
89 char *nr_ice_candidate_tcp_type_names[]={0,"active","passive","so",0};
90
nr_ctype_name(nr_ice_candidate_type ctype)91 static const char *nr_ctype_name(nr_ice_candidate_type ctype) {
92 assert(ctype<CTYPE_MAX && ctype>0);
93 if (ctype <= 0 || ctype >= CTYPE_MAX) {
94 return "ERROR";
95 }
96 return nr_ice_candidate_type_names[ctype];
97 }
98
nr_tcp_type_name(nr_socket_tcp_type tcp_type)99 static const char *nr_tcp_type_name(nr_socket_tcp_type tcp_type) {
100 assert(tcp_type<TCP_TYPE_MAX && tcp_type>0);
101 if (tcp_type <= 0 || tcp_type >= TCP_TYPE_MAX) {
102 return "ERROR";
103 }
104 return nr_ice_candidate_tcp_type_names[tcp_type];
105 }
106
nr_ice_candidate_format_stun_label(char * label,size_t size,nr_ice_candidate * cand)107 static int nr_ice_candidate_format_stun_label(char *label, size_t size, nr_ice_candidate *cand)
108 {
109 *label = 0;
110 snprintf(label, size, "%s(%s|%s)", nr_ctype_name(cand->type),
111 cand->base.as_string, cand->stun_server->addr.as_string);
112
113 return (0);
114 }
115
nr_ice_candidate_create(nr_ice_ctx * ctx,nr_ice_component * comp,nr_ice_socket * isock,nr_socket * osock,nr_ice_candidate_type ctype,nr_socket_tcp_type tcp_type,nr_ice_stun_server * stun_server,UCHAR component_id,nr_ice_candidate ** candp)116 int nr_ice_candidate_create(nr_ice_ctx *ctx,nr_ice_component *comp,nr_ice_socket *isock, nr_socket *osock, nr_ice_candidate_type ctype, nr_socket_tcp_type tcp_type, nr_ice_stun_server *stun_server, UCHAR component_id, nr_ice_candidate **candp)
117 {
118 assert(!(ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) || ctype == RELAYED);
119 nr_ice_candidate *cand=0;
120 nr_ice_candidate *tmp=0;
121 int r,_status;
122 char label[512];
123
124 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
125 ABORT(R_NO_MEMORY);
126 cand->state=NR_ICE_CAND_STATE_CREATED;
127 cand->ctx=ctx;
128 cand->isock=isock;
129 cand->osock=osock;
130 cand->type=ctype;
131 cand->tcp_type=tcp_type;
132 cand->stun_server=stun_server;
133 cand->component_id=component_id;
134 cand->component=comp;
135 cand->stream=comp->stream;
136
137 /* Extract the addr as the base */
138 if(r=nr_socket_getaddr(cand->isock->sock,&cand->base))
139 ABORT(r);
140
141 switch(ctype) {
142 case HOST:
143 snprintf(label, sizeof(label), "host(%s)", cand->base.as_string);
144 break;
145
146 case SERVER_REFLEXIVE:
147 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label), cand))
148 ABORT(r);
149 break;
150
151 case RELAYED:
152 if(r=nr_ice_candidate_format_stun_label(label, sizeof(label), cand))
153 ABORT(r);
154 break;
155
156 case PEER_REFLEXIVE:
157 snprintf(label, sizeof(label), "prflx");
158 break;
159
160 default:
161 assert(0); /* Can't happen */
162 ABORT(R_BAD_ARGS);
163 }
164
165 if (tcp_type) {
166 const char* ttype = nr_tcp_type_name(tcp_type);
167 const int tlen = strlen(ttype)+1; /* plus space */
168 const size_t llen=strlen(label);
169 if (snprintf(label+llen, sizeof(label)-llen, " %s", ttype) != tlen) {
170 r_log(LOG_ICE,LOG_ERR,"ICE(%s): truncated tcp type added to buffer",
171 ctx->label);
172 }
173 }
174
175 if(!(cand->label=r_strdup(label)))
176 ABORT(R_NO_MEMORY);
177
178 if(r=nr_ice_get_foundation(ctx,cand))
179 ABORT(r);
180 if(r=nr_ice_candidate_compute_priority(cand))
181 ABORT(r);
182
183 TAILQ_FOREACH(tmp,&isock->candidates,entry_sock){
184 if(cand->priority==tmp->priority){
185 r_log(LOG_ICE,LOG_ERR,"ICE(%s): duplicate priority %u candidate %s and candidate %s",
186 ctx->label,cand->priority,cand->label,tmp->label);
187 }
188 }
189
190 if(ctype==RELAYED)
191 cand->u.relayed.turn_sock=osock;
192
193
194 /* Add the candidate to the isock list*/
195 TAILQ_INSERT_TAIL(&isock->candidates,cand,entry_sock);
196
197 nr_ice_candidate_compute_codeword(cand);
198
199 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): created candidate %s with type %s",
200 ctx->label,cand->codeword,cand->label,nr_ctype_name(ctype));
201
202 *candp=cand;
203
204 _status=0;
205 abort:
206 if (_status){
207 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Failed to create candidate of type %s", ctx->label,nr_ctype_name(ctype));
208 nr_ice_candidate_destroy(&cand);
209 }
210 return(_status);
211 }
212
213
214 /* Create a peer reflexive candidate */
nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx * ctx,char * label,nr_ice_component * comp,nr_transport_addr * addr,nr_ice_candidate ** candp)215 int nr_ice_peer_peer_rflx_candidate_create(nr_ice_ctx *ctx,char *label, nr_ice_component *comp,nr_transport_addr *addr, nr_ice_candidate **candp)
216 {
217 nr_ice_candidate *cand=0;
218 nr_ice_candidate_type ctype=PEER_REFLEXIVE;
219 int r,_status;
220
221 if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
222 ABORT(R_NO_MEMORY);
223 if(!(cand->label=r_strdup(label)))
224 ABORT(R_NO_MEMORY);
225
226 cand->state=NR_ICE_CAND_STATE_INITIALIZED;
227 cand->ctx=ctx;
228 cand->type=ctype;
229 cand->component_id=comp->component_id;
230 cand->component=comp;
231 cand->stream=comp->stream;
232
233
234 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): creating candidate with type %s",
235 ctx->label,label,nr_ctype_name(ctype));
236
237 if(r=nr_transport_addr_copy(&cand->base,addr))
238 ABORT(r);
239 if(r=nr_transport_addr_copy(&cand->addr,addr))
240 ABORT(r);
241 /* Bogus foundation */
242 if(!(cand->foundation=r_strdup(cand->addr.as_string)))
243 ABORT(R_NO_MEMORY);
244
245 nr_ice_candidate_compute_codeword(cand);
246
247 *candp=cand;
248
249 _status=0;
250 abort:
251 if (_status){
252 nr_ice_candidate_destroy(&cand);
253 }
254 return(_status);
255 }
256
nr_ice_candidate_mark_done(nr_ice_candidate * cand,int state)257 static void nr_ice_candidate_mark_done(nr_ice_candidate *cand, int state)
258 {
259 if (!cand) {
260 assert(0);
261 return;
262 }
263
264 /* If this is a relay candidate, there's likely to be a srflx that is
265 * piggybacking on it. Make sure it is marked done too. */
266 if ((cand->type == RELAYED) && cand->u.relayed.srvflx_candidate) {
267 nr_ice_candidate *srflx=cand->u.relayed.srvflx_candidate;
268 if (state == NR_ICE_CAND_STATE_INITIALIZED &&
269 nr_turn_client_get_mapped_address(cand->u.relayed.turn,
270 &srflx->addr)) {
271 r_log(LOG_ICE, LOG_WARNING, "ICE(%s)/CAND(%s): Failed to get mapped address from TURN allocate response, srflx failed.", cand->ctx->label, cand->label);
272 nr_ice_candidate_mark_done(srflx, NR_ICE_CAND_STATE_FAILED);
273 } else {
274 nr_ice_candidate_mark_done(srflx, state);
275 }
276 }
277
278 NR_async_cb done_cb=cand->done_cb;
279 cand->done_cb=0;
280 cand->state=state;
281 /* This might destroy cand! */
282 if (done_cb) {
283 done_cb(0,0,cand->cb_arg);
284 }
285 }
286
nr_ice_candidate_destroy(nr_ice_candidate ** candp)287 int nr_ice_candidate_destroy(nr_ice_candidate **candp)
288 {
289 nr_ice_candidate *cand=0;
290
291 if(!candp || !*candp)
292 return(0);
293
294 cand=*candp;
295
296 nr_ice_candidate_stop_gathering(cand);
297
298 switch(cand->type){
299 case HOST:
300 break;
301 #ifdef USE_TURN
302 case RELAYED:
303 // record stats back to the ice ctx on destruction
304 if (cand->u.relayed.turn) {
305 nr_accumulate_count(&(cand->ctx->stats.turn_401s), cand->u.relayed.turn->cnt_401s);
306 nr_accumulate_count(&(cand->ctx->stats.turn_403s), cand->u.relayed.turn->cnt_403s);
307 nr_accumulate_count(&(cand->ctx->stats.turn_438s), cand->u.relayed.turn->cnt_438s);
308
309 nr_turn_stun_ctx* stun_ctx;
310 stun_ctx = STAILQ_FIRST(&cand->u.relayed.turn->stun_ctxs);
311 while (stun_ctx) {
312 nr_accumulate_count(&(cand->ctx->stats.stun_retransmits), stun_ctx->stun->retransmit_ct);
313
314 stun_ctx = STAILQ_NEXT(stun_ctx, entry);
315 }
316 }
317 if (cand->u.relayed.turn_handle)
318 nr_ice_socket_deregister(cand->isock, cand->u.relayed.turn_handle);
319 if (cand->u.relayed.srvflx_candidate)
320 cand->u.relayed.srvflx_candidate->u.srvrflx.relay_candidate=0;
321 nr_turn_client_ctx_destroy(&cand->u.relayed.turn);
322 nr_socket_destroy(&cand->u.relayed.turn_sock);
323 break;
324 #endif /* USE_TURN */
325 case SERVER_REFLEXIVE:
326 if (cand->u.srvrflx.stun_handle)
327 nr_ice_socket_deregister(cand->isock, cand->u.srvrflx.stun_handle);
328 if (cand->u.srvrflx.relay_candidate)
329 cand->u.srvrflx.relay_candidate->u.relayed.srvflx_candidate=0;
330 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
331 break;
332 default:
333 break;
334 }
335
336 RFREE(cand->mdns_addr);
337 RFREE(cand->foundation);
338 RFREE(cand->label);
339 RFREE(cand);
340
341 return(0);
342 }
343
nr_ice_candidate_stop_gathering(nr_ice_candidate * cand)344 void nr_ice_candidate_stop_gathering(nr_ice_candidate *cand)
345 {
346 if (cand->state == NR_ICE_CAND_STATE_INITIALIZING) {
347 /* Make sure the ICE ctx isn't still waiting around for this candidate
348 * to init. */
349 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
350 }
351
352 NR_async_timer_cancel(cand->delay_timer);
353 cand->delay_timer=0;
354 NR_async_timer_cancel(cand->ready_cb_timer);
355 cand->ready_cb_timer=0;
356
357 if(cand->resolver_handle){
358 nr_resolver_cancel(cand->ctx->resolver,cand->resolver_handle);
359 cand->resolver_handle=0;
360 }
361 }
362
363 /* This algorithm is not super-fast, but I don't think we need a hash
364 table just yet and it produces a small foundation string */
nr_ice_get_foundation(nr_ice_ctx * ctx,nr_ice_candidate * cand)365 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand)
366 {
367 nr_ice_foundation *foundation;
368 int i=0;
369 char fnd[20];
370 int _status;
371
372 foundation=STAILQ_FIRST(&ctx->foundations);
373 while(foundation){
374 if(nr_transport_addr_cmp(&cand->base,&foundation->addr,NR_TRANSPORT_ADDR_CMP_MODE_ADDR))
375 goto next;
376 // cast necessary because there is no guarantee that enum is signed.
377 // foundation->type should probably match nr_ice_candidate_type
378 if((int)cand->type != foundation->type)
379 goto next;
380 if(cand->stun_server != foundation->stun_server)
381 goto next;
382
383 snprintf(fnd,sizeof(fnd),"%d",i);
384 if(!(cand->foundation=r_strdup(fnd)))
385 ABORT(R_NO_MEMORY);
386 return(0);
387
388 next:
389 foundation=STAILQ_NEXT(foundation,entry);
390 i++;
391 }
392
393 if(!(foundation=RCALLOC(sizeof(nr_ice_foundation))))
394 ABORT(R_NO_MEMORY);
395 nr_transport_addr_copy(&foundation->addr,&cand->base);
396 foundation->type=cand->type;
397 foundation->stun_server=cand->stun_server;
398 STAILQ_INSERT_TAIL(&ctx->foundations,foundation,entry);
399
400 snprintf(fnd,sizeof(fnd),"%d",i);
401 if(!(cand->foundation=r_strdup(fnd)))
402 ABORT(R_NO_MEMORY);
403
404 _status=0;
405 abort:
406 return(_status);
407 }
408
nr_ice_candidate_compute_priority(nr_ice_candidate * cand)409 int nr_ice_candidate_compute_priority(nr_ice_candidate *cand)
410 {
411 UCHAR type_preference;
412 UCHAR interface_preference;
413 UCHAR stun_priority;
414 UCHAR direction_priority=0;
415 int r,_status;
416
417 if (cand->base.protocol != IPPROTO_UDP && cand->base.protocol != IPPROTO_TCP){
418 r_log(LOG_ICE,LOG_ERR,"Unknown protocol type %u",
419 (unsigned int)cand->base.protocol);
420 ABORT(R_INTERNAL);
421 }
422
423 switch(cand->type){
424 case HOST:
425 if(cand->base.protocol == IPPROTO_UDP) {
426 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST,&type_preference))
427 ABORT(r);
428 } else if(cand->base.protocol == IPPROTO_TCP) {
429 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_HOST_TCP,&type_preference))
430 ABORT(r);
431 }
432 stun_priority=0;
433 break;
434 case RELAYED:
435 if(cand->base.protocol == IPPROTO_UDP) {
436 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED,&type_preference))
437 ABORT(r);
438 } else if(cand->base.protocol == IPPROTO_TCP) {
439 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_RELAYED_TCP,&type_preference))
440 ABORT(r);
441 }
442 stun_priority=31-cand->stun_server->id;
443 break;
444 case SERVER_REFLEXIVE:
445 if(cand->base.protocol == IPPROTO_UDP) {
446 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX,&type_preference))
447 ABORT(r);
448 } else if(cand->base.protocol == IPPROTO_TCP) {
449 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_SRV_RFLX_TCP,&type_preference))
450 ABORT(r);
451 }
452 stun_priority=31-cand->stun_server->id;
453 break;
454 case PEER_REFLEXIVE:
455 if(cand->base.protocol == IPPROTO_UDP) {
456 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX,&type_preference))
457 ABORT(r);
458 } else if(cand->base.protocol == IPPROTO_TCP) {
459 if(r=NR_reg_get_uchar(NR_ICE_REG_PREF_TYPE_PEER_RFLX_TCP,&type_preference))
460 ABORT(r);
461 }
462 stun_priority=0;
463 break;
464 default:
465 ABORT(R_INTERNAL);
466 }
467
468 if(cand->base.protocol == IPPROTO_TCP){
469 switch (cand->tcp_type) {
470 case TCP_TYPE_ACTIVE:
471 if (cand->type == HOST)
472 direction_priority=6;
473 else
474 direction_priority=4;
475 break;
476 case TCP_TYPE_PASSIVE:
477 if (cand->type == HOST)
478 direction_priority=4;
479 else
480 direction_priority=2;
481 break;
482 case TCP_TYPE_SO:
483 if (cand->type == HOST)
484 direction_priority=2;
485 else
486 direction_priority=6;
487 break;
488 case TCP_TYPE_NONE:
489 break;
490 case TCP_TYPE_MAX:
491 default:
492 assert(0);
493 ABORT(R_INTERNAL);
494 }
495 }
496
497 if(type_preference > 126)
498 r_log(LOG_ICE,LOG_ERR,"Illegal type preference %d",type_preference);
499
500 if(!cand->ctx->interface_prioritizer) {
501 /* Prioritizer is not set, read from registry */
502 if(r=NR_reg_get2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,
503 &interface_preference)) {
504 if (r==R_NOT_FOUND) {
505 if (next_automatic_preference == 1) {
506 r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
507 ABORT(R_NOT_FOUND);
508 }
509 r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
510 next_automatic_preference);
511 if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
512 ABORT(r);
513 }
514 interface_preference=next_automatic_preference << 1;
515 next_automatic_preference--;
516 if (cand->base.ip_version == NR_IPV6) {
517 /* Prefer IPV6 over IPV4 on the same interface. */
518 interface_preference += 1;
519 }
520 }
521 else {
522 ABORT(r);
523 }
524 }
525 }
526 else {
527 char key_of_interface[MAXIFNAME + 41];
528 nr_transport_addr addr;
529
530 if(r=nr_socket_getaddr(cand->isock->sock, &addr))
531 ABORT(r);
532
533 if(r=nr_transport_addr_fmt_ifname_addr_string(&addr,key_of_interface,
534 sizeof(key_of_interface))) {
535 ABORT(r);
536 }
537 if(r=nr_interface_prioritizer_get_priority(cand->ctx->interface_prioritizer,
538 key_of_interface,&interface_preference)) {
539 ABORT(r);
540 }
541 }
542
543 assert(stun_priority < 32);
544 assert(direction_priority < 8);
545
546 cand->priority=
547 (type_preference << 24) |
548 (interface_preference << 16) |
549 (direction_priority << 13) |
550 (stun_priority << 8) |
551 (256 - cand->component_id);
552
553 /* S 4.1.2 */
554 assert(cand->priority>=1&&cand->priority<=2147483647);
555
556 _status=0;
557 abort:
558 return(_status);
559 }
560
nr_ice_candidate_fire_ready_cb(NR_SOCKET s,int how,void * cb_arg)561 static void nr_ice_candidate_fire_ready_cb(NR_SOCKET s, int how, void *cb_arg)
562 {
563 nr_ice_candidate *cand = cb_arg;
564
565 cand->ready_cb_timer = 0;
566 cand->ready_cb(0, 0, cand->ready_cb_arg);
567 }
568
nr_ice_candidate_use_nr_resolver(nr_transport_addr * addr)569 static int nr_ice_candidate_use_nr_resolver(nr_transport_addr *addr)
570 {
571 if(addr->fqdn[0] == 0) {
572 return 0;
573 }
574
575 char use = 0;
576 if(addr->protocol == IPPROTO_UDP) {
577 NR_reg_get_char(NR_ICE_REG_USE_NR_RESOLVER_FOR_UDP, &use);
578 } else if(addr->protocol == IPPROTO_TCP) {
579 NR_reg_get_char(NR_ICE_REG_USE_NR_RESOLVER_FOR_TCP, &use);
580 } else {
581 assert(0);
582 }
583
584 return use;
585 }
586
nr_ice_candidate_initialize(nr_ice_candidate * cand,NR_async_cb ready_cb,void * cb_arg)587 int nr_ice_candidate_initialize(nr_ice_candidate *cand, NR_async_cb ready_cb, void *cb_arg)
588 {
589 int r,_status;
590 int protocol=NR_RESOLVE_PROTOCOL_STUN;
591 cand->done_cb=ready_cb;
592 cand->cb_arg=cb_arg;
593 cand->state=NR_ICE_CAND_STATE_INITIALIZING;
594
595 switch(cand->type){
596 case HOST:
597 if(r=nr_socket_getaddr(cand->isock->sock,&cand->addr))
598 ABORT(r);
599 cand->osock=cand->isock->sock;
600 // Post this so that it doesn't happen in-line
601 cand->ready_cb = ready_cb;
602 cand->ready_cb_arg = cb_arg;
603 NR_ASYNC_TIMER_SET(0, nr_ice_candidate_fire_ready_cb, (void *)cand, &cand->ready_cb_timer);
604 break;
605 #ifdef USE_TURN
606 case RELAYED:
607 protocol=NR_RESOLVE_PROTOCOL_TURN;
608 /* Fall through */
609 #endif
610 case SERVER_REFLEXIVE:
611 if (nr_transport_addr_cmp(&cand->base, &cand->stun_server->addr,
612 NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL)) {
613 r_log(LOG_ICE, LOG_INFO,
614 "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate because "
615 "of IP version/transport mis-match with STUN/TURN server "
616 "(%u/%s - %u/%s).",
617 cand->label, cand->base.ip_version,
618 cand->base.protocol == IPPROTO_UDP ? "UDP" : "TCP",
619 cand->stun_server->addr.ip_version,
620 cand->stun_server->addr.protocol == IPPROTO_UDP ? "UDP"
621 : "TCP");
622 ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */
623 }
624
625 if(nr_ice_candidate_use_nr_resolver(&cand->stun_server->addr)) {
626 r_log(
627 LOG_ICE, LOG_DEBUG,
628 "ICE-CANDIDATE(%s): Starting DNS resolution (%u/%s - %u/%s).",
629 cand->label, cand->base.ip_version,
630 cand->base.protocol == IPPROTO_UDP ? "UDP" : "TCP",
631 cand->stun_server->addr.ip_version,
632 cand->stun_server->addr.protocol == IPPROTO_UDP ? "UDP" : "TCP");
633 nr_resolver_resource resource;
634 int port;
635 resource.domain_name = cand->stun_server->addr.fqdn;
636 if (r = nr_transport_addr_get_port(&cand->stun_server->addr, &port)) {
637 ABORT(r);
638 }
639 resource.port = (uint16_t)port;
640 resource.stun_turn=protocol;
641 resource.transport_protocol = cand->stun_server->addr.protocol;
642
643 switch (cand->base.ip_version) {
644 case NR_IPV4:
645 resource.address_family=AF_INET;
646 break;
647 case NR_IPV6:
648 resource.address_family=AF_INET6;
649 break;
650 default:
651 assert(0);
652 ABORT(R_BAD_ARGS);
653 }
654
655 /* Try to resolve */
656 if(!cand->ctx->resolver) {
657 r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
658 ABORT(R_BAD_ARGS);
659 }
660
661 if(r=nr_resolver_resolve(cand->ctx->resolver,
662 &resource,
663 nr_ice_candidate_resolved_cb,
664 (void *)cand,
665 &cand->resolver_handle)){
666 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not invoke DNS resolver",cand->label);
667 ABORT(r);
668 }
669 } else {
670 /* No nr_resolver for this, just copy the address and finish init */
671 if (r = nr_transport_addr_copy(&cand->stun_server_addr,
672 &cand->stun_server->addr)) {
673 r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
674 ABORT(r);
675 }
676
677 if(r=nr_ice_candidate_initialize2(cand))
678 ABORT(r);
679 }
680 break;
681 default:
682 ABORT(R_INTERNAL);
683 }
684
685 nr_ice_candidate_compute_codeword(cand);
686
687 _status=0;
688 abort:
689 if(_status && _status!=R_WOULDBLOCK)
690 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
691 return(_status);
692 }
693
694
nr_ice_candidate_resolved_cb(void * cb_arg,nr_transport_addr * addr)695 static int nr_ice_candidate_resolved_cb(void *cb_arg, nr_transport_addr *addr)
696 {
697 nr_ice_candidate *cand=cb_arg;
698 int r,_status;
699
700 cand->resolver_handle=0;
701
702 if(addr){
703 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): resolved candidate %s. addr=%s",
704 cand->ctx->label,cand->label,addr->as_string);
705 }
706 else {
707 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): failed to resolve candidate %s.",
708 cand->ctx->label,cand->label);
709 ABORT(R_NOT_FOUND);
710 }
711
712 if (nr_transport_addr_check_compatibility(addr, &cand->base)) {
713 r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Skipping STUN server because of link local mis-match for candidate %s",cand->ctx->label,cand->label);
714 ABORT(R_NOT_FOUND);
715 }
716
717 /* Copy the address */
718 if(r=nr_transport_addr_copy(&cand->stun_server_addr,addr))
719 ABORT(r);
720
721 if (cand->tcp_type == TCP_TYPE_PASSIVE || cand->tcp_type == TCP_TYPE_SO){
722 if (r=nr_socket_multi_tcp_stun_server_connect(cand->osock, addr))
723 ABORT(r);
724 }
725
726 /* Now start initializing */
727 if(r=nr_ice_candidate_initialize2(cand))
728 ABORT(r);
729
730 _status=0;
731 abort:
732 if(_status && _status!=R_WOULDBLOCK) {
733 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
734 }
735 return(_status);
736 }
737
nr_ice_candidate_initialize2(nr_ice_candidate * cand)738 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand)
739 {
740 int r,_status;
741
742 switch(cand->type){
743 case HOST:
744 assert(0); /* Can't happen */
745 ABORT(R_INTERNAL);
746 break;
747 #ifdef USE_TURN
748 case RELAYED:
749 if(r=nr_ice_start_relay_turn(cand))
750 ABORT(r);
751 ABORT(R_WOULDBLOCK);
752 break;
753 #endif /* USE_TURN */
754 case SERVER_REFLEXIVE:
755 /* Need to start stun */
756 if(r=nr_ice_srvrflx_start_stun(cand))
757 ABORT(r);
758 cand->osock=cand->isock->sock;
759 ABORT(R_WOULDBLOCK);
760 break;
761 default:
762 ABORT(R_INTERNAL);
763 }
764
765 _status=0;
766 abort:
767 return(_status);
768 }
769
nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s,int how,void * cb_arg)770 static void nr_ice_srvrflx_start_stun_timer_cb(NR_SOCKET s, int how, void *cb_arg)
771 {
772 nr_ice_candidate *cand=cb_arg;
773 int r,_status;
774
775 cand->delay_timer=0;
776
777 /* TODO: if the response is a BINDING-ERROR-RESPONSE, then restart
778 * TODO: using NR_STUN_CLIENT_MODE_BINDING_REQUEST because the
779 * TODO: server may not have understood the 0.96-style request */
780 if(r=nr_stun_client_start(cand->u.srvrflx.stun, NR_STUN_CLIENT_MODE_BINDING_REQUEST_NO_AUTH, nr_ice_srvrflx_stun_finished_cb, cand))
781 ABORT(r);
782
783 if(r=nr_ice_ctx_remember_id(cand->ctx, cand->u.srvrflx.stun->request))
784 ABORT(r);
785
786 if(r=nr_ice_socket_register_stun_client(cand->isock,cand->u.srvrflx.stun,&cand->u.srvrflx.stun_handle))
787 ABORT(r);
788
789 _status=0;
790 abort:
791 if (_status && (cand->u.srvrflx.stun->state==NR_STUN_CLIENT_STATE_RUNNING)) {
792 nr_stun_client_failed(cand->u.srvrflx.stun);
793 }
794 return;
795 }
796
nr_ice_srvrflx_start_stun(nr_ice_candidate * cand)797 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand)
798 {
799 int r,_status;
800
801 assert(!cand->delay_timer);
802 if(r=nr_stun_client_ctx_create(cand->label, cand->isock->sock,
803 &cand->stun_server_addr, cand->stream->ctx->gather_rto,
804 &cand->u.srvrflx.stun))
805 ABORT(r);
806
807 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_srvrflx_start_stun_timer_cb,cand,&cand->delay_timer);
808 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
809
810 _status=0;
811 abort:
812 return(_status);
813 }
814
815 #ifdef USE_TURN
nr_ice_start_relay_turn_timer_cb(NR_SOCKET s,int how,void * cb_arg)816 static void nr_ice_start_relay_turn_timer_cb(NR_SOCKET s, int how, void *cb_arg)
817 {
818 nr_ice_candidate *cand=cb_arg;
819 int r,_status;
820
821 cand->delay_timer=0;
822
823 if(r=nr_turn_client_allocate(cand->u.relayed.turn, nr_ice_turn_allocated_cb, cb_arg))
824 ABORT(r);
825
826 if(r=nr_ice_socket_register_turn_client(cand->isock, cand->u.relayed.turn,
827 cand->osock, &cand->u.relayed.turn_handle))
828 ABORT(r);
829
830 _status=0;
831 abort:
832 if(_status && (cand->u.relayed.turn->state==NR_TURN_CLIENT_STATE_ALLOCATING)){
833 nr_turn_client_failed(cand->u.relayed.turn);
834 }
835 return;
836 }
837
nr_ice_start_relay_turn(nr_ice_candidate * cand)838 static int nr_ice_start_relay_turn(nr_ice_candidate *cand)
839 {
840 int r,_status;
841 assert(!cand->delay_timer);
842 if(r=nr_turn_client_ctx_create(cand->label, cand->isock->sock,
843 cand->u.relayed.server->username,
844 cand->u.relayed.server->password,
845 &cand->stun_server_addr,
846 cand->component->ctx,
847 &cand->u.relayed.turn))
848 ABORT(r);
849
850 if(r=nr_socket_turn_set_ctx(cand->osock, cand->u.relayed.turn))
851 ABORT(r);
852
853 NR_ASYNC_TIMER_SET(cand->stream->ctx->stun_delay,nr_ice_start_relay_turn_timer_cb,cand,&cand->delay_timer);
854 cand->stream->ctx->stun_delay += cand->stream->ctx->Ta;
855
856 _status=0;
857 abort:
858 return(_status);
859 }
860 #endif /* USE_TURN */
861
nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock,int how,void * cb_arg)862 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg)
863 {
864 int _status;
865 nr_ice_candidate *cand=cb_arg;
866
867 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): %s",cand->ctx->label,cand->label,__FUNCTION__);
868
869 /* Deregister to suppress duplicates */
870 if(cand->u.srvrflx.stun_handle){ /* This test because we might have failed before CB registered */
871 nr_ice_socket_deregister(cand->isock,cand->u.srvrflx.stun_handle);
872 cand->u.srvrflx.stun_handle=0;
873 }
874
875 switch(cand->u.srvrflx.stun->state){
876 /* OK, we should have a mapped address */
877 case NR_STUN_CLIENT_STATE_DONE:
878 /* Copy the address */
879 nr_transport_addr_copy(&cand->addr, &cand->u.srvrflx.stun->results.stun_binding_response.mapped_addr);
880 cand->addr.protocol=cand->base.protocol;
881 nr_transport_addr_fmt_addr_string(&cand->addr);
882 nr_stun_client_ctx_destroy(&cand->u.srvrflx.stun);
883 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_INITIALIZED);
884 cand=0;
885 break;
886
887 /* This failed, so go to the next STUN server if there is one */
888 case NR_STUN_CLIENT_STATE_FAILED:
889 ABORT(R_NOT_FOUND);
890 break;
891 default:
892 ABORT(R_INTERNAL);
893 }
894 _status = 0;
895 abort:
896 if(_status){
897 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
898 }
899 }
900
901 #ifdef USE_TURN
nr_ice_turn_allocated_cb(NR_SOCKET s,int how,void * cb_arg)902 static void nr_ice_turn_allocated_cb(NR_SOCKET s, int how, void *cb_arg)
903 {
904 int r,_status;
905 nr_ice_candidate *cand=cb_arg;
906 nr_turn_client_ctx *turn=cand->u.relayed.turn;
907 char *label;
908 nr_transport_addr relay_addr;
909
910 switch(turn->state){
911 /* OK, we should have a mapped address */
912 case NR_TURN_CLIENT_STATE_ALLOCATED:
913 if (r=nr_turn_client_get_relayed_address(turn, &relay_addr))
914 ABORT(r);
915
916 if(r=nr_concat_strings(&label,"turn-relay(",cand->base.as_string,"|",
917 relay_addr.as_string,")",NULL))
918 ABORT(r);
919
920 r_log(LOG_ICE,LOG_DEBUG,"TURN-CLIENT(%s)/CAND(%s): Switching from TURN to RELAY (%s)",cand->u.relayed.turn->label,cand->label,label);
921
922 /* Copy the relayed address into the candidate addr and
923 into the candidate base. Note that we need to keep the
924 ifname in the base. */
925 if (r=nr_transport_addr_copy(&cand->addr, &relay_addr))
926 ABORT(r);
927 if (r=nr_transport_addr_copy_keep_ifname(&cand->base, &relay_addr)) /* Need to keep interface for priority calculation */
928 ABORT(r);
929
930 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/CAND(%s): new relay base=%s addr=%s", cand->ctx->label, cand->label, cand->base.as_string, cand->addr.as_string);
931
932 RFREE(cand->label);
933 cand->label=label;
934 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_INITIALIZED);
935 cand = 0;
936
937 break;
938
939 case NR_TURN_CLIENT_STATE_FAILED:
940 case NR_TURN_CLIENT_STATE_CANCELLED:
941 r_log(NR_LOG_TURN, LOG_WARNING,
942 "ICE-CANDIDATE(%s): nr_turn_allocated_cb called with state %d",
943 cand->label, turn->state);
944 /* This failed, so go to the next TURN server if there is one */
945 ABORT(R_NOT_FOUND);
946 break;
947 default:
948 assert(0); /* should never happen */
949 ABORT(R_INTERNAL);
950 }
951
952 _status=0;
953 abort:
954 if(_status){
955 if (cand) {
956 r_log(NR_LOG_TURN, LOG_WARNING,
957 "ICE-CANDIDATE(%s): nr_turn_allocated_cb failed", cand->label);
958 nr_ice_candidate_mark_done(cand, NR_ICE_CAND_STATE_FAILED);
959 }
960 }
961 }
962 #endif /* USE_TURN */
963
964 /* Format the candidate attribute as per ICE S 15.1 */
nr_ice_format_candidate_attribute(nr_ice_candidate * cand,char * attr,int maxlen,int obfuscate_srflx_addr)965 int nr_ice_format_candidate_attribute(nr_ice_candidate *cand, char *attr, int maxlen, int obfuscate_srflx_addr)
966 {
967 int r,_status;
968 char addr[64];
969 int port;
970 int len;
971 nr_transport_addr *raddr;
972
973 assert(!strcmp(nr_ice_candidate_type_names[HOST], "host"));
974 assert(!strcmp(nr_ice_candidate_type_names[RELAYED], "relay"));
975
976 if (cand->mdns_addr) {
977 /* mdns_addr is NSID_LENGTH which is 39, - 2 for removing the "{" and "}"
978 + 6 for ".local" for a total of 43. */
979 strncpy(addr, cand->mdns_addr, sizeof(addr) - 1);
980 } else {
981 if(r=nr_transport_addr_get_addrstring(&cand->addr,addr,sizeof(addr)))
982 ABORT(r);
983 }
984 if(r=nr_transport_addr_get_port(&cand->addr,&port))
985 ABORT(r);
986 /* https://tools.ietf.org/html/rfc6544#section-4.5 */
987 if (cand->base.protocol==IPPROTO_TCP && cand->tcp_type==TCP_TYPE_ACTIVE)
988 port=9;
989 snprintf(attr,maxlen,"candidate:%s %d %s %u %s %d typ %s",
990 cand->foundation, cand->component_id, cand->addr.protocol==IPPROTO_UDP?"UDP":"TCP",cand->priority, addr, port,
991 nr_ctype_name(cand->type));
992
993 len=strlen(attr); attr+=len; maxlen-=len;
994
995 /* raddr, rport */
996 raddr = (cand->stream->ctx->flags &
997 (NR_ICE_CTX_FLAGS_RELAY_ONLY |
998 NR_ICE_CTX_FLAGS_HIDE_HOST_CANDIDATES)) ?
999 &cand->addr : &cand->base;
1000
1001 switch(cand->type){
1002 case HOST:
1003 break;
1004 case SERVER_REFLEXIVE:
1005 if (obfuscate_srflx_addr) {
1006 snprintf(attr,maxlen," raddr 0.0.0.0 rport 0");
1007 } else {
1008 if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
1009 ABORT(r);
1010 if(r=nr_transport_addr_get_port(raddr,&port))
1011 ABORT(r);
1012 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
1013 }
1014 break;
1015 case PEER_REFLEXIVE:
1016 if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
1017 ABORT(r);
1018 if(r=nr_transport_addr_get_port(raddr,&port))
1019 ABORT(r);
1020 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
1021 break;
1022 case RELAYED:
1023 // comes from XorMappedAddress via AllocateResponse
1024 if(r=nr_transport_addr_get_addrstring(raddr,addr,sizeof(addr)))
1025 ABORT(r);
1026 if(r=nr_transport_addr_get_port(raddr,&port))
1027 ABORT(r);
1028
1029 snprintf(attr,maxlen," raddr %s rport %d",addr,port);
1030 break;
1031 default:
1032 assert(0);
1033 ABORT(R_INTERNAL);
1034 break;
1035 }
1036
1037 if (cand->base.protocol==IPPROTO_TCP && cand->tcp_type){
1038 len=strlen(attr);
1039 attr+=len;
1040 maxlen-=len;
1041 snprintf(attr,maxlen," tcptype %s",nr_tcp_type_name(cand->tcp_type));
1042 }
1043
1044 _status=0;
1045 abort:
1046 return(_status);
1047 }
1048
1049