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