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