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 
34 
35 static char *RCSSTRING __UNUSED__="$Id: ice_parser.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
36 
37 #include <csi_platform.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 #include <strings.h>
46 #endif
47 #include <string.h>
48 #include <assert.h>
49 #include <ctype.h>
50 #include "nr_api.h"
51 #include "ice_ctx.h"
52 #include "ice_candidate.h"
53 #include "ice_reg.h"
54 
55 static void
skip_whitespace(char ** str)56 skip_whitespace(char **str)
57 {
58     char *c = *str;
59     while (*c == ' ')
60         ++c;
61 
62     *str = c;
63 }
64 
65 static void
fast_forward(char ** str,int skip)66 fast_forward(char **str, int skip)
67 {
68     char *c = *str;
69     while (*c != '\0' && skip-- > 0)
70         ++c;
71 
72     *str = c;
73 }
74 
75 static void
skip_to_past_space(char ** str)76 skip_to_past_space(char **str)
77 {
78     char *c = *str;
79     while (*c != ' ' && *c != '\0')
80         ++c;
81 
82     *str = c;
83 
84     skip_whitespace(str);
85 }
86 
87 static int
grab_token(char ** str,char ** out)88 grab_token(char **str, char **out)
89 {
90     int _status;
91     char *c = *str;
92     int len;
93     char *tmp;
94 
95     while (*c != ' ' && *c != '\0')
96         ++c;
97 
98     len = c - *str;
99 
100     tmp = RMALLOC(len + 1);
101     if (!tmp)
102         ABORT(R_NO_MEMORY);
103 
104     memcpy(tmp, *str, len);
105     tmp[len] = '\0';
106 
107     *str = c;
108     *out = tmp;
109 
110     _status = 0;
111 abort:
112     return _status;
113 }
114 
115 int
nr_ice_peer_candidate_from_attribute(nr_ice_ctx * ctx,char * orig,nr_ice_media_stream * stream,nr_ice_candidate ** candp)116 nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_stream *stream,nr_ice_candidate **candp)
117 {
118     int r,_status;
119     char* str = orig;
120     nr_ice_candidate *cand;
121     char *connection_address=0;
122     unsigned int port;
123     int i;
124     unsigned int component_id;
125     char *rel_addr=0;
126     unsigned char transport;
127 
128     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
129         ABORT(R_NO_MEMORY);
130 
131     if(!(cand->label=r_strdup(orig)))
132         ABORT(R_NO_MEMORY);
133 
134     cand->ctx=ctx;
135     cand->isock=0;
136     cand->state=NR_ICE_CAND_PEER_CANDIDATE_UNPAIRED;
137     cand->stream=stream;
138     skip_whitespace(&str);
139 
140     /* Skip a= if present */
141     if (!strncmp(str, "a=", 2))
142         str += 2;
143 
144     /* Candidate attr */
145     if (strncasecmp(str, "candidate:", 10))
146         ABORT(R_BAD_DATA);
147 
148     fast_forward(&str, 10);
149     if (*str == '\0')
150         ABORT(R_BAD_DATA);
151 
152     skip_whitespace(&str);
153     if (*str == '\0')
154         ABORT(R_BAD_DATA);
155 
156     /* Foundation */
157     if ((r=grab_token(&str, &cand->foundation)))
158         ABORT(r);
159 
160     if (*str == '\0')
161         ABORT(R_BAD_DATA);
162 
163     skip_whitespace(&str);
164     if (*str == '\0')
165         ABORT(R_BAD_DATA);
166 
167     /* component */
168     if (sscanf(str, "%u", &component_id) != 1)
169         ABORT(R_BAD_DATA);
170 
171     if (component_id < 1 || component_id > 256)
172         ABORT(R_BAD_DATA);
173 
174     cand->component_id = (UCHAR)component_id;
175 
176     skip_to_past_space(&str);
177     if (*str == '\0')
178         ABORT(R_BAD_DATA);
179 
180     /* Protocol */
181     if (!strncasecmp(str, "UDP", 3))
182       transport=IPPROTO_UDP;
183     else if (!strncasecmp(str, "TCP", 3))
184       transport=IPPROTO_TCP;
185     else
186       ABORT(R_BAD_DATA);
187 
188     fast_forward(&str, 3);
189     if (*str == '\0')
190         ABORT(R_BAD_DATA);
191 
192     skip_whitespace(&str);
193     if (*str == '\0')
194         ABORT(R_BAD_DATA);
195 
196     /* priority */
197     if (sscanf(str, "%u", &cand->priority) != 1)
198         ABORT(R_BAD_DATA);
199 
200     if (cand->priority < 1)
201         ABORT(R_BAD_DATA);
202 
203     skip_to_past_space(&str);
204     if (*str == '\0')
205         ABORT(R_BAD_DATA);
206 
207     /* Peer address/port */
208     if ((r=grab_token(&str, &connection_address)))
209         ABORT(r);
210 
211     if (*str == '\0')
212         ABORT(R_BAD_DATA);
213 
214     skip_whitespace(&str);
215     if (*str == '\0')
216         ABORT(R_BAD_DATA);
217 
218     if (sscanf(str, "%u", &port) != 1)
219         ABORT(R_BAD_DATA);
220 
221     if (port < 1 || port > 0x0FFFF)
222         ABORT(R_BAD_DATA);
223 
224     if ((r=nr_str_port_to_transport_addr(connection_address,port,transport,&cand->addr)))
225       ABORT(r);
226 
227     skip_to_past_space(&str);
228     if (*str == '\0')
229         ABORT(R_BAD_DATA);
230 
231     /* Type */
232     if (strncasecmp("typ", str, 3))
233         ABORT(R_BAD_DATA);
234 
235     fast_forward(&str, 3);
236     if (*str == '\0')
237         ABORT(R_BAD_DATA);
238 
239     skip_whitespace(&str);
240     if (*str == '\0')
241         ABORT(R_BAD_DATA);
242 
243     assert(nr_ice_candidate_type_names[0] == 0);
244 
245     for (i = 1; nr_ice_candidate_type_names[i]; ++i) {
246         if(!strncasecmp(nr_ice_candidate_type_names[i], str, strlen(nr_ice_candidate_type_names[i]))) {
247             cand->type=i;
248             break;
249         }
250     }
251     if (nr_ice_candidate_type_names[i] == 0)
252         ABORT(R_BAD_DATA);
253 
254     fast_forward(&str, strlen(nr_ice_candidate_type_names[i]));
255 
256     /* Look for the other side's raddr, rport */
257     /* raddr, rport */
258     switch (cand->type) {
259     case HOST:
260         break;
261     case SERVER_REFLEXIVE:
262     case PEER_REFLEXIVE:
263     case RELAYED:
264 
265         skip_whitespace(&str);
266         if (*str == '\0')
267             ABORT(R_BAD_DATA);
268 
269         if (strncasecmp("raddr", str, 5))
270             ABORT(R_BAD_DATA);
271 
272         fast_forward(&str, 5);
273         if (*str == '\0')
274             ABORT(R_BAD_DATA);
275 
276         skip_whitespace(&str);
277         if (*str == '\0')
278             ABORT(R_BAD_DATA);
279 
280         if ((r=grab_token(&str, &rel_addr)))
281             ABORT(r);
282 
283         if (*str == '\0')
284             ABORT(R_BAD_DATA);
285 
286         skip_whitespace(&str);
287         if (*str == '\0')
288             ABORT(R_BAD_DATA);
289 
290         if (strncasecmp("rport", str, 5))
291               ABORT(R_BAD_DATA);
292 
293         fast_forward(&str, 5);
294         if (*str == '\0')
295             ABORT(R_BAD_DATA);
296 
297         skip_whitespace(&str);
298         if (*str == '\0')
299             ABORT(R_BAD_DATA);
300 
301         if (sscanf(str, "%u", &port) != 1)
302             ABORT(R_BAD_DATA);
303 
304         if (port > 0x0FFFF)
305             ABORT(R_BAD_DATA);
306 
307         if ((r=nr_str_port_to_transport_addr(rel_addr,port,transport,&cand->base)))
308           ABORT(r);
309 
310         skip_to_past_space(&str);
311         /* it's expected to be at EOD at this point */
312 
313         break;
314     default:
315         ABORT(R_INTERNAL);
316         break;
317     }
318 
319     skip_whitespace(&str);
320 
321     if (transport == IPPROTO_TCP && cand->type != RELAYED) {
322       /* Parse tcptype extension per RFC 6544 S 4.5 */
323       if (strncasecmp("tcptype ", str, 8))
324         ABORT(R_BAD_DATA);
325 
326       fast_forward(&str, 8);
327       skip_whitespace(&str);
328 
329       for (i = 1; nr_ice_candidate_tcp_type_names[i]; ++i) {
330         if(!strncasecmp(nr_ice_candidate_tcp_type_names[i], str, strlen(nr_ice_candidate_tcp_type_names[i]))) {
331           cand->tcp_type=i;
332           fast_forward(&str, strlen(nr_ice_candidate_tcp_type_names[i]));
333           break;
334         }
335       }
336 
337       if (cand->tcp_type == 0)
338         ABORT(R_BAD_DATA);
339 
340       if (*str && *str != ' ')
341         ABORT(R_BAD_DATA);
342     }
343     /* Ignore extensions per RFC 5245 S 15.1 */
344 #if 0
345     /* This used to be an assert, but we don't want to exit on invalid
346        remote data */
347     if (strlen(str) != 0) {
348       ABORT(R_BAD_DATA);
349     }
350 #endif
351 
352     nr_ice_candidate_compute_codeword(cand);
353 
354     *candp=cand;
355 
356     _status=0;
357   abort:
358     if (_status){
359         r_log(LOG_ICE,LOG_WARNING,"ICE(%s): Error parsing attribute: %s",ctx->label,orig);
360         nr_ice_candidate_destroy(&cand);
361     }
362 
363     RFREE(connection_address);
364     RFREE(rel_addr);
365     return(_status);
366 }
367 
368 
369 int
nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx * pctx,nr_ice_media_stream * stream,char * attr)370 nr_ice_peer_ctx_parse_media_stream_attribute(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream, char *attr)
371 {
372     int r,_status;
373     char *orig = 0;
374     char *str;
375 
376     orig = str = attr;
377 
378     if (!strncasecmp(str, "ice-ufrag:", 10)) {
379       fast_forward(&str, 10);
380       if (*str == '\0')
381         ABORT(R_BAD_DATA);
382 
383       skip_whitespace(&str);
384       if (*str == '\0')
385         ABORT(R_BAD_DATA);
386 
387       if ((r=grab_token(&str, &stream->ufrag)))
388         ABORT(r);
389     }
390     else if (!strncasecmp(str, "ice-pwd:", 8)) {
391       fast_forward(&str, 8);
392       if (*str == '\0')
393         ABORT(R_BAD_DATA);
394 
395       skip_whitespace(&str);
396       if (*str == '\0')
397         ABORT(R_BAD_DATA);
398 
399       if ((r=grab_token(&str, &stream->pwd)))
400         ABORT(r);
401     }
402     else {
403       ABORT(R_BAD_DATA);
404     }
405 
406     skip_whitespace(&str);
407 
408     /* RFC 5245 grammar doesn't have an extension point for ice-pwd or
409        ice-ufrag: if there's anything left on the line, we treat it as bad. */
410     if (str[0] != '\0') {
411       ABORT(R_BAD_DATA);
412     }
413 
414     _status=0;
415   abort:
416     if (_status) {
417       if (orig)
418         r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
419     }
420 
421     return(_status);
422 }
423 
424 int
nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx * pctx,char ** attrs,int attr_ct)425 nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs, int attr_ct)
426 {
427     int r,_status;
428     int i;
429     char *orig = 0;
430     char *str;
431     char *component_id = 0;
432     char *connection_address = 0;
433     unsigned int port;
434     in_addr_t addr;
435     char *ice_option_tag = 0;
436 
437     for(i=0;i<attr_ct;i++){
438         orig = str = attrs[i];
439 
440         component_id = 0;
441         connection_address = 0;
442         ice_option_tag = 0;
443 
444         if (!strncasecmp(str, "remote-candidates:", 18)) {
445             fast_forward(&str, 18);
446             skip_whitespace(&str);
447 
448             while (*str != '\0') {
449                 if ((r=grab_token(&str, &component_id)))
450                     ABORT(r);
451 
452                 if (*str == '\0')
453                     ABORT(R_BAD_DATA);
454 
455                 skip_whitespace(&str);
456                 if (*str == '\0')
457                     ABORT(R_BAD_DATA);
458 
459                 if ((r=grab_token(&str, &connection_address)))
460                     ABORT(r);
461 
462                 if (*str == '\0')
463                     ABORT(R_BAD_DATA);
464 
465                 addr = inet_addr(connection_address);
466                 if (addr == INADDR_NONE)
467                     ABORT(R_BAD_DATA);
468 
469                 skip_whitespace(&str);
470                 if (*str == '\0')
471                     ABORT(R_BAD_DATA);
472 
473                 if (sscanf(str, "%u", &port) != 1)
474                     ABORT(R_BAD_DATA);
475 
476                 if (port < 1 || port > 0x0FFFF)
477                     ABORT(R_BAD_DATA);
478 
479                 skip_to_past_space(&str);
480 
481 #if 0
482                 /* TODO: !nn! just drop on the floor for now, later put somewhere */
483                 /* Assume v4 for now */
484                 if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,IPPROTO_UDP,&candidate->base))
485                   ABORT(r);
486 
487                 TAILQ_INSERT_TAIL(head, elm, field);
488 #endif
489 
490                 component_id = 0;  /* prevent free */
491                 RFREE(connection_address);
492                 connection_address = 0;  /* prevent free */
493             }
494         }
495         else if (!strncasecmp(str, "ice-lite", 8)) {
496             pctx->peer_lite = 1;
497 
498             fast_forward(&str, 8);
499         }
500         else if (!strncasecmp(str, "ice-mismatch", 12)) {
501             pctx->peer_ice_mismatch = 1;
502 
503             fast_forward(&str, 12);
504         }
505         else if (!strncasecmp(str, "ice-ufrag:", 10)) {
506             fast_forward(&str, 10);
507             if (*str == '\0')
508                 ABORT(R_BAD_DATA);
509 
510             skip_whitespace(&str);
511             if (*str == '\0')
512                 ABORT(R_BAD_DATA);
513 
514             RFREE(pctx->peer_ufrag);
515             pctx->peer_ufrag = 0;
516             if ((r=grab_token(&str, &pctx->peer_ufrag)))
517                 ABORT(r);
518         }
519         else if (!strncasecmp(str, "ice-pwd:", 8)) {
520             fast_forward(&str, 8);
521             if (*str == '\0')
522                 ABORT(R_BAD_DATA);
523 
524             skip_whitespace(&str);
525             if (*str == '\0')
526                 ABORT(R_BAD_DATA);
527 
528             RFREE(pctx->peer_pwd);
529             pctx->peer_pwd = 0;
530             if ((r=grab_token(&str, &pctx->peer_pwd)))
531                 ABORT(r);
532         }
533         else if (!strncasecmp(str, "ice-options:", 12)) {
534             fast_forward(&str, 12);
535             skip_whitespace(&str);
536 
537             while (*str != '\0') {
538                 if ((r=grab_token(&str, &ice_option_tag)))
539                     ABORT(r);
540 
541                 skip_whitespace(&str);
542 
543                 //TODO: for now, just throw away; later put somewhere
544                 RFREE(ice_option_tag);
545 
546                 ice_option_tag = 0;  /* prevent free */
547             }
548         }
549         else {
550             ABORT(R_BAD_DATA);
551         }
552 
553         skip_whitespace(&str);
554 
555       /* RFC 5245 grammar doesn't have an extension point for any of the
556          preceding attributes: if there's anything left on the line, we
557          treat it as bad data. */
558       if (str[0] != '\0') {
559         ABORT(R_BAD_DATA);
560       }
561     }
562 
563     _status=0;
564   abort:
565     if (_status) {
566       if (orig)
567         r_log(LOG_ICE,LOG_WARNING,"ICE-PEER(%s): Error parsing attribute: %s",pctx->label,orig);
568     }
569 
570     RFREE(connection_address);
571     RFREE(component_id);
572     RFREE(ice_option_tag);
573     return(_status);
574 }
575 
576