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