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