media/mtransport/third_party/nICEr/src/stun/stun_codec.c

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:3c6a33b547dd
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 static char *RCSSTRING __UNUSED__="$Id: stun_codec.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
35
36 #include <errno.h>
37 #include <csi_platform.h>
38
39 #ifdef WIN32
40 #include <winsock2.h>
41 #include <stdlib.h>
42 #include <io.h>
43 #include <time.h>
44 #else /* UNIX */
45 #include <string.h>
46 #endif /* end UNIX */
47 #include <assert.h>
48 #include <stddef.h>
49
50 #include "nr_api.h"
51 #include "stun.h"
52 #include "byteorder.h"
53 #include "r_crc32.h"
54 #include "nr_crypto.h"
55 #include "mbslen.h"
56
57 #define NR_STUN_IPV4_FAMILY 0x01
58 #define NR_STUN_IPV6_FAMILY 0x02
59
60 #define SKIP_ATTRIBUTE_DECODE -1
61
62 static int nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info);
63
64 static int nr_stun_fix_attribute_ordering(nr_stun_message *msg);
65
66 static int nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset);
67 static int nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset);
68 static int nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset);
69 static int nr_stun_encode(UCHAR *data, int length, int buflen, UCHAR *buf, int *offset);
70
71 static int nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data);
72 static int nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data);
73 static int nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data);
74 static int nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data);
75
76 static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars);
77
78 static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
79 static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
80 static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
81 static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
82 static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data);
83 static int
84 nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data);
85
86
87 int
88 nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset)
89 {
90 UINT2 d = htons(data);
91
92 if (*offset + sizeof(d) >= buflen) {
93 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd >= %d", *offset, sizeof(d), buflen);
94 return R_BAD_DATA;
95 }
96
97 memcpy(&buf[*offset], &d, sizeof(d));
98 *offset += sizeof(d);
99
100 return 0;
101 }
102
103 int
104 nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset)
105 {
106 UINT4 d = htonl(data);
107
108 if (*offset + sizeof(d) > buflen) {
109 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
110 return R_BAD_DATA;
111 }
112
113 memcpy(&buf[*offset], &d, sizeof(d));
114 *offset += sizeof(d);
115
116 return 0;
117 }
118
119 int
120 nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset)
121 {
122 UINT8 d = nr_htonll(data);
123
124 if (*offset + sizeof(d) > buflen) {
125 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
126 return R_BAD_DATA;
127 }
128
129 memcpy(&buf[*offset], &d, sizeof(d));
130 *offset += sizeof(d);
131
132 return 0;
133 }
134
135 int
136 nr_stun_encode(UCHAR *data, int length, int buflen, UCHAR *buf, int *offset)
137 {
138 if (*offset + length > buflen) {
139 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
140 return R_BAD_DATA;
141 }
142
143 memcpy(&buf[*offset], data, length);
144 *offset += length;
145
146 return 0;
147 }
148
149
150 int
151 nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data)
152 {
153 UINT2 d;
154
155 if (*offset + sizeof(d) > buflen) {
156 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
157 return R_BAD_DATA;
158 }
159
160 memcpy(&d, &buf[*offset], sizeof(d));
161 *offset += sizeof(d);
162 *data = htons(d);
163
164 return 0;
165 }
166
167 int
168 nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data)
169 {
170 UINT4 d;
171
172 if (*offset + sizeof(d) > buflen) {
173 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
174 return R_BAD_DATA;
175 }
176
177 memcpy(&d, &buf[*offset], sizeof(d));
178 *offset += sizeof(d);
179 *data = htonl(d);
180
181 return 0;
182 }
183
184 int
185 nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data)
186 {
187 UINT8 d;
188
189 if (*offset + sizeof(d) > buflen) {
190 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
191 return R_BAD_DATA;
192 }
193
194 memcpy(&d, &buf[*offset], sizeof(d));
195 *offset += sizeof(d);
196 *data = nr_htonll(d);
197
198 return 0;
199 }
200
201 int
202 nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data)
203 {
204 if (*offset + length > buflen) {
205 r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen);
206 return R_BAD_DATA;
207 }
208
209 memcpy(data, &buf[*offset], length);
210 *offset += length;
211
212 return 0;
213 }
214
215 int
216 nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars)
217 {
218 int _status;
219 char *s = data;
220 size_t nchars;
221
222 if (len > max_bytes) {
223 r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %d bytes", attr_info->name, len);
224 ABORT(R_FAILED);
225 }
226
227 if (max_chars >= 0) {
228 if (mbslen(s, &nchars)) {
229 /* who knows what to do, just assume everything is working ok */
230 }
231 else if (nchars > max_chars) {
232 r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %zd characters", attr_info->name, nchars);
233 ABORT(R_FAILED);
234 }
235 }
236
237 _status = 0;
238 abort:
239 return _status;
240 }
241
242 int
243 nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
244 {
245 int r,_status;
246 nr_stun_attr_error_code *ec = data;
247
248 if (ec->number < 300 || ec->number > 699)
249 ABORT(R_FAILED);
250
251 if ((r=nr_stun_attr_string_illegal(attr_info, strlen(ec->reason), ec->reason, NR_STUN_MAX_ERROR_CODE_REASON_BYTES, NR_STUN_MAX_ERROR_CODE_REASON_CHARS)))
252 ABORT(r);
253
254 _status = 0;
255 abort:
256 return _status;
257 }
258
259 int
260 nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
261 {
262 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_NONCE_BYTES, NR_STUN_MAX_NONCE_CHARS);
263 }
264
265 int
266 nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
267 {
268 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_REALM_BYTES, NR_STUN_MAX_REALM_CHARS);
269 }
270
271 int
272 nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
273 {
274 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_SERVER_BYTES, NR_STUN_MAX_SERVER_CHARS);
275 }
276
277 int
278 nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data)
279 {
280 return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_USERNAME_BYTES, -1);
281 }
282
283 static int
284 nr_stun_attr_codec_UCHAR_print(nr_stun_attr_info *attr_info, char *msg, void *data)
285 {
286 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UCHAR*)data);
287 return 0;
288 }
289
290 static int
291 nr_stun_attr_codec_UCHAR_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
292 {
293 int start = offset;
294 UINT4 tmp = *((UCHAR *)data);
295 tmp <<= 24;
296
297 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
298 || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset)
299 || nr_stun_encode_htonl(tmp , buflen, buf, &offset))
300 return R_FAILED;
301
302 *attrlen = offset - start;
303
304 return 0;
305 }
306
307 static int
308 nr_stun_attr_codec_UCHAR_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
309 {
310 UINT4 tmp;
311
312 if (attrlen != sizeof(UINT4)) {
313 r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
314 return R_FAILED;
315 }
316
317 if (nr_stun_decode_htonl(buf, buflen, &offset, &tmp))
318 return R_FAILED;
319
320 *((UCHAR *)data) = (tmp >> 24) & 0xff;
321
322 return 0;
323 }
324
325 nr_stun_attr_codec nr_stun_attr_codec_UCHAR = {
326 "UCHAR",
327 nr_stun_attr_codec_UCHAR_print,
328 nr_stun_attr_codec_UCHAR_encode,
329 nr_stun_attr_codec_UCHAR_decode
330 };
331
332 static int
333 nr_stun_attr_codec_UINT4_print(nr_stun_attr_info *attr_info, char *msg, void *data)
334 {
335 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UINT4*)data);
336 return 0;
337 }
338
339 static int
340 nr_stun_attr_codec_UINT4_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
341 {
342 int start = offset;
343
344 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
345 || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset)
346 || nr_stun_encode_htonl(*(UINT4*)data , buflen, buf, &offset))
347 return R_FAILED;
348
349 *attrlen = offset - start;
350
351 return 0;
352 }
353
354 static int
355 nr_stun_attr_codec_UINT4_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
356 {
357 if (attrlen != sizeof(UINT4)) {
358 r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
359 return R_FAILED;
360 }
361
362 if (nr_stun_decode_htonl(buf, buflen, &offset, (UINT4*)data))
363 return R_FAILED;
364
365 return 0;
366 }
367
368 nr_stun_attr_codec nr_stun_attr_codec_UINT4 = {
369 "UINT4",
370 nr_stun_attr_codec_UINT4_print,
371 nr_stun_attr_codec_UINT4_encode,
372 nr_stun_attr_codec_UINT4_decode
373 };
374
375 static int
376 nr_stun_attr_codec_UINT8_print(nr_stun_attr_info *attr_info, char *msg, void *data)
377 {
378 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %llu", msg, attr_info->name, *(UINT8*)data);
379 return 0;
380 }
381
382 static int
383 nr_stun_attr_codec_UINT8_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
384 {
385 int start = offset;
386
387 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
388 || nr_stun_encode_htons(sizeof(UINT8) , buflen, buf, &offset)
389 || nr_stun_encode_htonll(*(UINT8*)data , buflen, buf, &offset))
390 return R_FAILED;
391
392 *attrlen = offset - start;
393
394 return 0;
395 }
396
397 static int
398 nr_stun_attr_codec_UINT8_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
399 {
400 if (attrlen != sizeof(UINT8)) {
401 r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
402 return R_FAILED;
403 }
404
405 if (nr_stun_decode_htonll(buf, buflen, &offset, (UINT8*)data))
406 return R_FAILED;
407
408 return 0;
409 }
410
411 nr_stun_attr_codec nr_stun_attr_codec_UINT8 = {
412 "UINT8",
413 nr_stun_attr_codec_UINT8_print,
414 nr_stun_attr_codec_UINT8_encode,
415 nr_stun_attr_codec_UINT8_decode
416 };
417
418 static int
419 nr_stun_attr_codec_addr_print(nr_stun_attr_info *attr_info, char *msg, void *data)
420 {
421 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s", msg, attr_info->name, ((nr_transport_addr*)data)->as_string);
422 return 0;
423 }
424
425 static int
426 nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
427 {
428 int r,_status;
429 int start = offset;
430 nr_transport_addr *addr = data;
431 UCHAR pad = '\0';
432 UCHAR family;
433
434 if ((r=nr_stun_encode_htons(attr_info->type, buflen, buf, &offset)))
435 ABORT(r);
436
437 switch (addr->ip_version) {
438 case NR_IPV4:
439 family = NR_STUN_IPV4_FAMILY;
440 if (nr_stun_encode_htons(8 , buflen, buf, &offset)
441 || nr_stun_encode(&pad, 1 , buflen, buf, &offset)
442 || nr_stun_encode(&family, 1 , buflen, buf, &offset)
443 || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port), buflen, buf, &offset)
444 || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset))
445 ABORT(R_FAILED);
446 break;
447
448 case NR_IPV6:
449 assert(0);
450 ABORT(R_INTERNAL);
451 break;
452 default:
453 assert(0);
454 ABORT(R_INTERNAL);
455 break;
456 }
457
458 *attrlen = offset - start;
459
460 _status = 0;
461 abort:
462 return _status;
463 }
464
465 static int
466 nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
467 {
468 int _status;
469 UCHAR pad;
470 UCHAR family;
471 UINT2 port;
472 UINT4 addr4;
473 nr_transport_addr *result = data;
474
475 if (nr_stun_decode(1, buf, buflen, &offset, &pad)
476 || nr_stun_decode(1, buf, buflen, &offset, &family))
477 ABORT(R_FAILED);
478
479 switch (family) {
480 case NR_STUN_IPV4_FAMILY:
481 if (attrlen != 8) {
482 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
483 ABORT(R_FAILED);
484 }
485
486 if (nr_stun_decode_htons(buf, buflen, &offset, &port)
487 || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
488 ABORT(R_FAILED);
489
490 if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result))
491 ABORT(R_FAILED);
492 break;
493
494 case NR_STUN_IPV6_FAMILY:
495 if (attrlen != 16) {
496 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
497 ABORT(R_FAILED);
498 }
499
500 r_log(NR_LOG_STUN, LOG_WARNING, "IPv6 not supported");
501 #ifdef NDEBUG
502 ABORT(SKIP_ATTRIBUTE_DECODE);
503 #else
504 UNIMPLEMENTED;
505 #endif /* NDEBUG */
506 break;
507
508 default:
509 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family);
510 ABORT(R_FAILED);
511 break;
512 }
513
514 _status = 0;
515 abort:
516 return _status;
517 }
518
519 nr_stun_attr_codec nr_stun_attr_codec_addr = {
520 "addr",
521 nr_stun_attr_codec_addr_print,
522 nr_stun_attr_codec_addr_encode,
523 nr_stun_attr_codec_addr_decode
524 };
525
526 static int
527 nr_stun_attr_codec_data_print(nr_stun_attr_info *attr_info, char *msg, void *data)
528 {
529 nr_stun_attr_data *d = data;
530 r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)d->data, d->length);
531 return 0;
532 }
533
534 static int
535 nr_stun_attr_codec_data_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
536 {
537 nr_stun_attr_data *d = data;
538 int start = offset;
539
540 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
541 || nr_stun_encode_htons(d->length , buflen, buf, &offset)
542 || nr_stun_encode(d->data, d->length , buflen, buf, &offset))
543 return R_FAILED;
544
545 *attrlen = offset - start;
546
547 return 0;
548 }
549
550 static int
551 nr_stun_attr_codec_data_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
552 {
553 int _status;
554 nr_stun_attr_data *result = data;
555
556 /* -1 because it is going to be null terminated just to be safe */
557 if (attrlen >= (sizeof(result->data) - 1)) {
558 r_log(NR_LOG_STUN, LOG_WARNING, "Too much data: %d bytes", attrlen);
559 ABORT(R_FAILED);
560 }
561
562 if (nr_stun_decode(attrlen, buf, buflen, &offset, result->data))
563 ABORT(R_FAILED);
564
565 result->length = attrlen;
566 result->data[attrlen] = '\0'; /* just to be nice */
567
568 _status=0;
569 abort:
570 return _status;
571 }
572
573 nr_stun_attr_codec nr_stun_attr_codec_data = {
574 "data",
575 nr_stun_attr_codec_data_print,
576 nr_stun_attr_codec_data_encode,
577 nr_stun_attr_codec_data_decode
578 };
579
580 static int
581 nr_stun_attr_codec_error_code_print(nr_stun_attr_info *attr_info, char *msg, void *data)
582 {
583 nr_stun_attr_error_code *error_code = data;
584 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %d %s",
585 msg, attr_info->name, error_code->number,
586 error_code->reason);
587 return 0;
588 }
589
590 static int
591 nr_stun_attr_codec_error_code_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
592 {
593 nr_stun_attr_error_code *error_code = data;
594 int start = offset;
595 int length = strlen(error_code->reason);
596 UCHAR pad[2] = { 0 };
597 UCHAR class = error_code->number / 100;
598 UCHAR number = error_code->number % 100;
599
600 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
601 || nr_stun_encode_htons(4 + length , buflen, buf, &offset)
602 || nr_stun_encode(pad, 2 , buflen, buf, &offset)
603 || nr_stun_encode(&class, 1 , buflen, buf, &offset)
604 || nr_stun_encode(&number, 1 , buflen, buf, &offset)
605 || nr_stun_encode((UCHAR*)error_code->reason, length, buflen, buf, &offset))
606 return R_FAILED;
607
608 *attrlen = offset - start;
609
610 return 0;
611 }
612
613 static int
614 nr_stun_attr_codec_error_code_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
615 {
616 int _status;
617 nr_stun_attr_error_code *result = data;
618 UCHAR pad[2];
619 UCHAR class;
620 UCHAR number;
621 int size_reason;
622
623 if (nr_stun_decode(2, buf, buflen, &offset, pad)
624 || nr_stun_decode(1, buf, buflen, &offset, &class)
625 || nr_stun_decode(1, buf, buflen, &offset, &number))
626 ABORT(R_FAILED);
627
628 result->number = (class * 100) + number;
629
630 size_reason = attrlen - 4;
631
632 /* -1 because the string will be null terminated */
633 if (size_reason > (sizeof(result->reason) - 1)) {
634 r_log(NR_LOG_STUN, LOG_WARNING, "Reason is too large, truncating");
635 /* don't fail, but instead truncate the reason */
636 size_reason = sizeof(result->reason) - 1;
637 }
638
639 if (nr_stun_decode(size_reason, buf, buflen, &offset, (UCHAR*)result->reason))
640 ABORT(R_FAILED);
641 result->reason[size_reason] = '\0';
642
643 _status=0;
644 abort:
645 return _status;
646 }
647
648 nr_stun_attr_codec nr_stun_attr_codec_error_code = {
649 "error_code",
650 nr_stun_attr_codec_error_code_print,
651 nr_stun_attr_codec_error_code_encode,
652 nr_stun_attr_codec_error_code_decode
653 };
654
655 static int
656 nr_stun_attr_codec_fingerprint_print(nr_stun_attr_info *attr_info, char *msg, void *data)
657 {
658 nr_stun_attr_fingerprint *fingerprint = data;
659 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %08x", msg, attr_info->name, fingerprint->checksum);
660 return 0;
661 }
662
663 static int
664 nr_stun_attr_codec_fingerprint_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
665 {
666 UINT4 checksum;
667 nr_stun_attr_fingerprint *fingerprint = data;
668 nr_stun_message_header *header = (nr_stun_message_header*)buf;
669
670 /* the length must include the FINGERPRINT attribute when computing
671 * the fingerprint */
672 header->length = ntohs(header->length);
673 header->length += 8; /* Fingerprint */
674 header->length = htons(header->length);
675
676 if (r_crc32((char*)buf, offset, &checksum)) {
677 r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint");
678 return R_FAILED;
679 }
680
681 fingerprint->checksum = checksum ^ 0x5354554e;
682
683 r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum);
684
685 fingerprint->valid = 1;
686 return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen);
687 }
688
689 static int
690 nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
691 {
692 int r,_status;
693 nr_stun_attr_fingerprint *fingerprint = data;
694 nr_stun_message_header *header = (nr_stun_message_header*)buf;
695 int length;
696 UINT4 checksum;
697
698 if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum)))
699 ABORT(r);
700
701 offset -= 4; /* rewind to before the length and type fields */
702
703 /* the length must include the FINGERPRINT attribute when computing
704 * the fingerprint */
705 length = offset; /* right before FINGERPRINT */
706 length -= sizeof(*header); /* remove header length */
707 length += 8; /* add length of Fingerprint */
708 header->length = htons(length);
709
710 /* make sure FINGERPRINT is final attribute in message */
711 assert(length + sizeof(*header) == buflen);
712
713 if (r_crc32((char*)buf, offset, &checksum)) {
714 r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint");
715 ABORT(R_FAILED);
716 }
717
718 fingerprint->valid = (fingerprint->checksum == (checksum ^ 0x5354554e));
719
720 r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", (checksum ^ 0x5354554e));
721 if (! fingerprint->valid)
722 r_log(NR_LOG_STUN, LOG_WARNING, "Invalid FINGERPRINT %08x", fingerprint->checksum);
723
724 _status=0;
725 abort:
726 return _status;
727 }
728
729 nr_stun_attr_codec nr_stun_attr_codec_fingerprint = {
730 "fingerprint",
731 nr_stun_attr_codec_fingerprint_print,
732 nr_stun_attr_codec_fingerprint_encode,
733 nr_stun_attr_codec_fingerprint_decode
734 };
735
736 static int
737 nr_stun_attr_codec_flag_print(nr_stun_attr_info *attr_info, char *msg, void *data)
738 {
739 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: on", msg, attr_info->name);
740 return 0;
741 }
742
743 static int
744 nr_stun_attr_codec_flag_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
745 {
746 int start = offset;
747
748 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
749 || nr_stun_encode_htons(0 , buflen, buf, &offset))
750 return R_FAILED;
751
752 *attrlen = offset - start;
753
754 return 0;
755 }
756
757 static int
758 nr_stun_attr_codec_flag_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
759 {
760 if (attrlen != 0) {
761 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal flag length: %d", attrlen);
762 return R_FAILED;
763 }
764
765 return 0;
766 }
767
768 nr_stun_attr_codec nr_stun_attr_codec_flag = {
769 "flag",
770 nr_stun_attr_codec_flag_print,
771 nr_stun_attr_codec_flag_encode,
772 nr_stun_attr_codec_flag_decode
773 };
774
775 static int
776 nr_stun_attr_codec_message_integrity_print(nr_stun_attr_info *attr_info, char *msg, void *data)
777 {
778 nr_stun_attr_message_integrity *integrity = data;
779 r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)integrity->hash, sizeof(integrity->hash));
780 return 0;
781 }
782
783 static int
784 nr_stun_compute_message_integrity(UCHAR *buf, int offset, UCHAR *password, int passwordlen, UCHAR *computedHMAC)
785 {
786 int r,_status;
787 UINT2 hold;
788 UINT2 length;
789 nr_stun_message_header *header;
790
791 r_log(NR_LOG_STUN, LOG_DEBUG, "Computing MESSAGE-INTEGRITY");
792
793 header = (nr_stun_message_header*)buf;
794 hold = header->length;
795
796 /* adjust the length of the message */
797 length = offset;
798 length -= sizeof(*header);
799 length += 24; /* for MESSAGE-INTEGRITY attribute */
800 header->length = htons(length);
801
802 if ((r=nr_crypto_hmac_sha1((UCHAR*)password, passwordlen,
803 buf, offset, computedHMAC)))
804 ABORT(r);
805
806 r_dump(NR_LOG_STUN, LOG_DEBUG, "Computed MESSAGE-INTEGRITY ", (char*)computedHMAC, 20);
807
808 _status=0;
809 abort:
810 header->length = hold;
811 return _status;
812 }
813
814 static int
815 nr_stun_attr_codec_message_integrity_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
816 {
817 int start = offset;
818 nr_stun_attr_message_integrity *integrity = data;
819
820 if (nr_stun_compute_message_integrity(buf, offset, integrity->password, integrity->passwordlen, integrity->hash))
821 return R_FAILED;
822
823 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
824 || nr_stun_encode_htons(sizeof(integrity->hash) , buflen, buf, &offset)
825 || nr_stun_encode(integrity->hash, sizeof(integrity->hash) , buflen, buf, &offset))
826 return R_FAILED;
827
828 *attrlen = offset - start;
829
830 return 0;
831 }
832
833 static int
834 nr_stun_attr_codec_message_integrity_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
835 {
836 int _status;
837 int start;
838 nr_stun_attr_message_integrity *result = data;
839 UCHAR computedHMAC[20];
840
841 result->valid = 0;
842
843 if (attrlen != 20) {
844 r_log(NR_LOG_STUN, LOG_WARNING, "%s must be 20 bytes, not %d", attr_info->name, attrlen);
845 ABORT(R_FAILED);
846 }
847
848 start = offset - 4; /* rewind to before the length and type fields */
849 if (start < 0)
850 ABORT(R_INTERNAL);
851
852 if (nr_stun_decode(attrlen, buf, buflen, &offset, result->hash))
853 ABORT(R_FAILED);
854
855 if (result->unknown_user) {
856 result->valid = 0;
857 }
858 else {
859 if (nr_stun_compute_message_integrity(buf, start, result->password, result->passwordlen, computedHMAC))
860 ABORT(R_FAILED);
861
862 assert(sizeof(computedHMAC) == sizeof(result->hash));
863
864 result->valid = (memcmp(computedHMAC, result->hash, 20) == 0);
865 }
866
867 _status=0;
868 abort:
869 return _status;
870 }
871
872 nr_stun_attr_codec nr_stun_attr_codec_message_integrity = {
873 "message_integrity",
874 nr_stun_attr_codec_message_integrity_print,
875 nr_stun_attr_codec_message_integrity_encode,
876 nr_stun_attr_codec_message_integrity_decode
877 };
878
879 static int
880 nr_stun_attr_codec_noop_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
881 {
882 return SKIP_ATTRIBUTE_DECODE;
883 }
884
885 nr_stun_attr_codec nr_stun_attr_codec_noop = {
886 "NOOP",
887 0, /* ignore, never print these attributes */
888 0, /* ignore, never encode these attributes */
889 nr_stun_attr_codec_noop_decode
890 };
891
892 static int
893 nr_stun_attr_codec_quoted_string_print(nr_stun_attr_info *attr_info, char *msg, void *data)
894 {
895 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s",
896 msg, attr_info->name, (char*)data);
897 return 0;
898 }
899
900 static int
901 nr_stun_attr_codec_quoted_string_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
902 {
903 //TODO: !nn! syntax check, conversion if not quoted already?
904 //We'll just restrict this in the API -- EKR
905 return nr_stun_attr_codec_string.encode(attr_info, data, offset, buflen, buf, attrlen);
906 }
907
908 static int
909 nr_stun_attr_codec_quoted_string_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
910 {
911 //TODO: !nn! I don't see any need to unquote this but we may
912 //find one later -- EKR
913 return nr_stun_attr_codec_string.decode(attr_info, attrlen, buf, offset, buflen, data);
914 }
915
916 nr_stun_attr_codec nr_stun_attr_codec_quoted_string = {
917 "quoted_string",
918 nr_stun_attr_codec_quoted_string_print,
919 nr_stun_attr_codec_quoted_string_encode,
920 nr_stun_attr_codec_quoted_string_decode
921 };
922
923 static int
924 nr_stun_attr_codec_string_print(nr_stun_attr_info *attr_info, char *msg, void *data)
925 {
926 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s",
927 msg, attr_info->name, (char*)data);
928 return 0;
929 }
930
931 static int
932 nr_stun_attr_codec_string_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
933 {
934 int start = offset;
935 char *str = data;
936 int length = strlen(str);
937
938 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
939 || nr_stun_encode_htons(length , buflen, buf, &offset)
940 || nr_stun_encode((UCHAR*)str, length , buflen, buf, &offset))
941 return R_FAILED;
942
943 *attrlen = offset - start;
944
945 return 0;
946 }
947
948 static int
949 nr_stun_attr_codec_string_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
950 {
951 int _status;
952 char *result = data;
953
954 /* actual enforcement of the specific string size happens elsewhere */
955 if (attrlen >= NR_STUN_MAX_STRING_SIZE) {
956 r_log(NR_LOG_STUN, LOG_WARNING, "String is too large: %d bytes", attrlen);
957 ABORT(R_FAILED);
958 }
959
960 if (nr_stun_decode(attrlen, buf, buflen, &offset, (UCHAR*)result))
961 ABORT(R_FAILED);
962 result[attrlen] = '\0'; /* just to be nice */
963
964 if (strlen(result) != attrlen) {
965 /* stund 0.96 sends a final null in the Server attribute, so
966 * only error if the null appears anywhere else in a string */
967 if (strlen(result) != attrlen-1) {
968 r_log(NR_LOG_STUN, LOG_WARNING, "Error in string: %zd/%d", strlen(result), attrlen);
969 ABORT(R_FAILED);
970 }
971 }
972
973 _status = 0;
974 abort:
975 return _status;
976 }
977
978 nr_stun_attr_codec nr_stun_attr_codec_string = {
979 "string",
980 nr_stun_attr_codec_string_print,
981 nr_stun_attr_codec_string_encode,
982 nr_stun_attr_codec_string_decode
983 };
984
985 static int
986 nr_stun_attr_codec_unknown_attributes_print(nr_stun_attr_info *attr_info, char *msg, void *data)
987 {
988 nr_stun_attr_unknown_attributes *unknown_attributes = data;
989 char type[9];
990 char str[64 + (NR_STUN_MAX_UNKNOWN_ATTRIBUTES * sizeof(type))];
991 int i;
992
993 snprintf(str, sizeof(str), "%s %s:", msg, attr_info->name);
994 for (i = 0; i < unknown_attributes->num_attributes; ++i) {
995 snprintf(type, sizeof(type), "%s 0x%04x", ((i>0)?",":""), unknown_attributes->attribute[i]);
996 strlcat(str, type, sizeof(str));
997 }
998
999 r_log(NR_LOG_STUN, LOG_DEBUG, "%s", str);
1000 return 0;
1001 }
1002
1003 static int
1004 nr_stun_attr_codec_unknown_attributes_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
1005 {
1006 int _status;
1007 int start = offset;
1008 nr_stun_attr_unknown_attributes *unknown_attributes = data;
1009 int length = (2 * unknown_attributes->num_attributes);
1010 int i;
1011
1012 if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) {
1013 r_log(NR_LOG_STUN, LOG_WARNING, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes);
1014 ABORT(R_FAILED);
1015 }
1016
1017 if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset)
1018 || nr_stun_encode_htons(length , buflen, buf, &offset))
1019 ABORT(R_FAILED);
1020
1021 for (i = 0; i < unknown_attributes->num_attributes; ++i) {
1022 if (nr_stun_encode_htons(unknown_attributes->attribute[i], buflen, buf, &offset))
1023 ABORT(R_FAILED);
1024 }
1025
1026 *attrlen = offset - start;
1027
1028 _status = 0;
1029 abort:
1030 return _status;
1031 }
1032
1033 static int
1034 nr_stun_attr_codec_unknown_attributes_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
1035 {
1036 int _status;
1037 nr_stun_attr_unknown_attributes *unknown_attributes = data;
1038 int i;
1039 UINT2 *a;
1040
1041 if ((attrlen % 4) != 0) {
1042 r_log(NR_LOG_STUN, LOG_WARNING, "Attribute is illegal size: %d", attrlen);
1043 ABORT(R_REJECTED);
1044 }
1045
1046 unknown_attributes->num_attributes = attrlen / 2;
1047
1048 if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) {
1049 r_log(NR_LOG_STUN, LOG_WARNING, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes);
1050 ABORT(R_REJECTED);
1051 }
1052
1053 for (i = 0; i < unknown_attributes->num_attributes; ++i) {
1054 a = &(unknown_attributes->attribute[i]);
1055 if (nr_stun_decode_htons(buf, buflen, &offset, a))
1056 return R_FAILED;
1057 }
1058
1059 _status = 0;
1060 abort:
1061 return _status;
1062 }
1063
1064 nr_stun_attr_codec nr_stun_attr_codec_unknown_attributes = {
1065 "unknown_attributes",
1066 nr_stun_attr_codec_unknown_attributes_print,
1067 nr_stun_attr_codec_unknown_attributes_encode,
1068 nr_stun_attr_codec_unknown_attributes_decode
1069 };
1070
1071 static int
1072 nr_stun_attr_codec_xor_mapped_address_print(nr_stun_attr_info *attr_info, char *msg, void *data)
1073 {
1074 nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
1075 r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s (unmasked) %s (masked)",
1076 msg, attr_info->name,
1077 xor_mapped_address->unmasked.as_string,
1078 xor_mapped_address->masked.as_string);
1079 return 0;
1080 }
1081
1082 static int
1083 nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen)
1084 {
1085 nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
1086 nr_stun_message_header *header = (nr_stun_message_header*)buf;
1087 UINT4 magic_cookie;
1088
1089 r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
1090
1091 /* this needs to be the magic cookie in the header and not
1092 * the MAGIC_COOKIE constant because if we're talking to
1093 * older servers (that don't have a magic cookie) they use
1094 * message ID for this */
1095 magic_cookie = ntohl(header->magic_cookie);
1096
1097 nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
1098
1099 r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
1100
1101 if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
1102 return R_FAILED;
1103
1104 return 0;
1105 }
1106
1107 static int
1108 nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
1109 {
1110 int r,_status;
1111 nr_stun_attr_xor_mapped_address *xor_mapped_address = data;
1112 nr_stun_message_header *header = (nr_stun_message_header*)buf;
1113 UINT4 magic_cookie;
1114
1115 if ((r=nr_stun_attr_codec_addr.decode(attr_info, attrlen, buf, offset, buflen, &xor_mapped_address->masked)))
1116 ABORT(r);
1117
1118 r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
1119
1120 /* this needs to be the magic cookie in the header and not
1121 * the MAGIC_COOKIE constant because if we're talking to
1122 * older servers (that don't have a magic cookie) they use
1123 * message ID for this */
1124 magic_cookie = ntohl(header->magic_cookie);
1125
1126 nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
1127
1128 r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
1129
1130 _status = 0;
1131 abort:
1132 return _status;
1133 }
1134
1135 nr_stun_attr_codec nr_stun_attr_codec_xor_mapped_address = {
1136 "xor_mapped_address",
1137 nr_stun_attr_codec_xor_mapped_address_print,
1138 nr_stun_attr_codec_xor_mapped_address_encode,
1139 nr_stun_attr_codec_xor_mapped_address_decode
1140 };
1141
1142 nr_stun_attr_codec nr_stun_attr_codec_old_xor_mapped_address = {
1143 "xor_mapped_address",
1144 nr_stun_attr_codec_xor_mapped_address_print,
1145 0, /* never encode this type */
1146 nr_stun_attr_codec_xor_mapped_address_decode
1147 };
1148
1149 nr_stun_attr_codec nr_stun_attr_codec_xor_peer_address = {
1150 "xor_peer_address",
1151 nr_stun_attr_codec_xor_mapped_address_print,
1152 nr_stun_attr_codec_xor_mapped_address_encode,
1153 nr_stun_attr_codec_xor_mapped_address_decode
1154 };
1155
1156 #define NR_ADD_STUN_ATTRIBUTE(type, name, codec, illegal) \
1157 { (type), (name), &(codec), illegal },
1158
1159 #define NR_ADD_STUN_ATTRIBUTE_IGNORE(type, name) \
1160 { (type), (name), &nr_stun_attr_codec_noop, 0 },
1161
1162
1163 static nr_stun_attr_info attrs[] = {
1164 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ALTERNATE_SERVER, "ALTERNATE-SERVER", nr_stun_attr_codec_addr, 0)
1165 #ifdef USE_STUND_0_96
1166 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_CHANGE_REQUEST, "CHANGE-REQUEST", nr_stun_attr_codec_UINT4, 0)
1167 #endif
1168 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ERROR_CODE, "ERROR-CODE", nr_stun_attr_codec_error_code, nr_stun_attr_error_code_illegal)
1169 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_FINGERPRINT, "FINGERPRINT", nr_stun_attr_codec_fingerprint, 0)
1170 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MAPPED_ADDRESS, "MAPPED-ADDRESS", nr_stun_attr_codec_addr, 0)
1171 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY", nr_stun_attr_codec_message_integrity, 0)
1172 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_NONCE, "NONCE", nr_stun_attr_codec_quoted_string, nr_stun_attr_nonce_illegal)
1173 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REALM, "REALM", nr_stun_attr_codec_quoted_string, nr_stun_attr_realm_illegal)
1174 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_SERVER, "SERVER", nr_stun_attr_codec_string, nr_stun_attr_server_illegal)
1175 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_UNKNOWN_ATTRIBUTES, "UNKNOWN-ATTRIBUTES", nr_stun_attr_codec_unknown_attributes, 0)
1176 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USERNAME, "USERNAME", nr_stun_attr_codec_string, nr_stun_attr_username_illegal)
1177 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_MAPPED_ADDRESS, "XOR-MAPPED-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0)
1178
1179 #ifdef USE_ICE
1180 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLED, "ICE-CONTROLLED", nr_stun_attr_codec_UINT8, 0)
1181 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLING, "ICE-CONTROLLING", nr_stun_attr_codec_UINT8, 0)
1182 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_PRIORITY, "PRIORITY", nr_stun_attr_codec_UINT4, 0)
1183 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USE_CANDIDATE, "USE-CANDIDATE", nr_stun_attr_codec_flag, 0)
1184 #endif
1185
1186 #ifdef USE_TURN
1187 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_DATA, "DATA", nr_stun_attr_codec_data, 0)
1188 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_LIFETIME, "LIFETIME", nr_stun_attr_codec_UINT4, 0)
1189 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_RELAY_ADDRESS, "XOR-RELAY-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0)
1190 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_PEER_ADDRESS, "XOR-PEER-ADDRESS", nr_stun_attr_codec_xor_peer_address, 0)
1191 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REQUESTED_TRANSPORT, "REQUESTED-TRANSPORT", nr_stun_attr_codec_UCHAR, 0)
1192 #endif /* USE_TURN */
1193
1194 /* for backwards compatibilty */
1195 NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS, "Old XOR-MAPPED-ADDRESS", nr_stun_attr_codec_old_xor_mapped_address, 0)
1196 #ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE
1197 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_RESPONSE_ADDRESS, "RESPONSE-ADDRESS")
1198 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_SOURCE_ADDRESS, "SOURCE-ADDRESS")
1199 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_CHANGED_ADDRESS, "CHANGED-ADDRESS")
1200 NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_PASSWORD, "PASSWORD")
1201 #endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */
1202 };
1203
1204
1205 int
1206 nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info)
1207 {
1208 int _status;
1209 int i;
1210
1211 *info = 0;
1212 for (i = 0; i < sizeof(attrs)/sizeof(*attrs); ++i) {
1213 if (type == attrs[i].type) {
1214 *info = &attrs[i];
1215 break;
1216 }
1217 }
1218
1219 if (*info == 0)
1220 ABORT(R_NOT_FOUND);
1221
1222 _status=0;
1223 abort:
1224 return(_status);
1225 }
1226
1227 int
1228 nr_stun_fix_attribute_ordering(nr_stun_message *msg)
1229 {
1230 nr_stun_message_attribute *message_integrity;
1231 nr_stun_message_attribute *fingerprint;
1232
1233 /* 2nd to the last */
1234 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &message_integrity)) {
1235 TAILQ_REMOVE(&msg->attributes, message_integrity, entry);
1236 TAILQ_INSERT_TAIL(&msg->attributes, message_integrity, entry);
1237 }
1238
1239 /* last */
1240 if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &fingerprint)) {
1241 TAILQ_REMOVE(&msg->attributes, fingerprint, entry);
1242 TAILQ_INSERT_TAIL(&msg->attributes, fingerprint, entry);
1243 }
1244
1245 return 0;
1246 }
1247
1248 #ifdef SANITY_CHECKS
1249 static void sanity_check_encoding_stuff(nr_stun_message *msg)
1250 {
1251 nr_stun_message_attribute *attr = 0;
1252 int padding_bytes;
1253 int l;
1254
1255 r_log(NR_LOG_STUN, LOG_DEBUG, "Starting to sanity check encoding");
1256
1257 l = 0;
1258 TAILQ_FOREACH(attr, &msg->attributes, entry) {
1259 padding_bytes = 0;
1260 if ((attr->length % 4) != 0) {
1261 padding_bytes = 4 - (attr->length % 4);
1262 }
1263 assert(attr->length == (attr->encoding_length - (4 + padding_bytes)));
1264 assert(((void*)attr->encoding) == (msg->buffer + 20 + l));
1265 l += attr->encoding_length;
1266 assert((l % 4) == 0);
1267 }
1268 assert(l == msg->header.length);
1269 }
1270 #endif /* SANITY_CHECKS */
1271
1272
1273 int
1274 nr_stun_encode_message(nr_stun_message *msg)
1275 {
1276 int r,_status;
1277 int length_offset;
1278 int length_offset_hold;
1279 nr_stun_attr_info *attr_info;
1280 nr_stun_message_attribute *attr;
1281 int padding_bytes;
1282
1283 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoding STUN message");
1284
1285 nr_stun_fix_attribute_ordering(msg);
1286
1287 msg->name = nr_stun_msg_type(msg->header.type);
1288 msg->length = 0;
1289 msg->header.length = 0;
1290
1291 if ((r=nr_stun_encode_htons(msg->header.type, sizeof(msg->buffer), msg->buffer, &msg->length)))
1292 ABORT(r);
1293 if (msg->name)
1294 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded MsgType: %s", msg->name);
1295 else
1296 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded MsgType: 0x%03x", msg->header.type);
1297
1298 /* grab the offset to be used later to re-write the header length field */
1299 length_offset_hold = msg->length;
1300
1301 if ((r=nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &msg->length)))
1302 ABORT(r);
1303
1304 if ((r=nr_stun_encode_htonl(msg->header.magic_cookie, sizeof(msg->buffer), msg->buffer, &msg->length)))
1305 ABORT(r);
1306 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Cookie: %08x", msg->header.magic_cookie);
1307
1308 if ((r=nr_stun_encode((UCHAR*)(&msg->header.id), sizeof(msg->header.id), sizeof(msg->buffer), msg->buffer, &msg->length)))
1309 ABORT(r);
1310 r_dump(NR_LOG_STUN, LOG_DEBUG, "Encoded ID", (void*)&msg->header.id, sizeof(msg->header.id));
1311
1312 TAILQ_FOREACH(attr, &msg->attributes, entry) {
1313 if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
1314 r_log(NR_LOG_STUN, LOG_WARNING, "Unrecognized attribute: 0x%04x", attr->type);
1315 ABORT(R_INTERNAL);
1316 }
1317
1318 attr_info->name = attr_info->name;
1319 attr->type_name = attr_info->codec->name;
1320 attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[msg->length];
1321
1322 if (attr_info->codec->encode != 0) {
1323 if ((r=attr_info->codec->encode(attr_info, &attr->u, msg->length, sizeof(msg->buffer), msg->buffer, &attr->encoding_length))) {
1324 r_log(NR_LOG_STUN, LOG_WARNING, "Unable to encode %s", attr_info->name);
1325 ABORT(r);
1326 }
1327
1328 msg->length += attr->encoding_length;
1329 attr->length = attr->encoding_length - 4; /* -4 for type and length fields */
1330
1331 if (attr_info->illegal) {
1332 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u)))
1333 ABORT(r);
1334 }
1335
1336 attr_info->codec->print(attr_info, "Encoded", &attr->u);
1337
1338 if ((attr->length % 4) == 0) {
1339 padding_bytes = 0;
1340 }
1341 else {
1342 padding_bytes = 4 - (attr->length % 4);
1343 nr_stun_encode((UCHAR*)"\0\0\0\0", padding_bytes, sizeof(msg->buffer), msg->buffer, &msg->length);
1344 attr->encoding_length += padding_bytes;
1345 }
1346
1347 msg->header.length += attr->encoding_length;
1348 length_offset = length_offset_hold;
1349 (void)nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &length_offset);
1350 }
1351 }
1352
1353 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Length: %d", msg->header.length);
1354
1355 assert(msg->length < NR_STUN_MAX_MESSAGE_SIZE);
1356
1357 #ifdef SANITY_CHECKS
1358 sanity_check_encoding_stuff(msg);
1359 #endif /* SANITY_CHECKS */
1360
1361 _status=0;
1362 abort:
1363 return _status;
1364 }
1365
1366 int
1367 nr_stun_decode_message(nr_stun_message *msg, int (*get_password)(void *arg, nr_stun_message *msg, Data **password), void *arg)
1368 {
1369 int r,_status;
1370 int offset;
1371 int size;
1372 int padding_bytes;
1373 nr_stun_message_attribute *attr;
1374 nr_stun_attr_info *attr_info;
1375 Data *password;
1376
1377 r_log(NR_LOG_STUN, LOG_DEBUG, "Parsing STUN message of %d bytes", msg->length);
1378
1379 if (!TAILQ_EMPTY(&msg->attributes))
1380 ABORT(R_BAD_ARGS);
1381
1382 if (sizeof(nr_stun_message_header) > msg->length) {
1383 r_log(NR_LOG_STUN, LOG_WARNING, "Message too small");
1384 ABORT(R_FAILED);
1385 }
1386
1387 memcpy(&msg->header, msg->buffer, sizeof(msg->header));
1388 msg->header.type = ntohs(msg->header.type);
1389 msg->header.length = ntohs(msg->header.length);
1390 msg->header.magic_cookie = ntohl(msg->header.magic_cookie);
1391
1392 msg->name = nr_stun_msg_type(msg->header.type);
1393
1394 if (msg->name)
1395 r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed MsgType: %s", msg->name);
1396 else
1397 r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed MsgType: 0x%03x", msg->header.type);
1398 r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed Length: %d", msg->header.length);
1399 r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed Cookie: %08x", msg->header.magic_cookie);
1400 r_dump(NR_LOG_STUN, LOG_DEBUG, "Parsed ID", (void*)&msg->header.id, sizeof(msg->header.id));
1401
1402 if (msg->header.length + sizeof(msg->header) != msg->length) {
1403 r_log(NR_LOG_STUN, LOG_WARNING, "Inconsistent message header length: %d/%d",
1404 msg->header.length, msg->length);
1405 ABORT(R_FAILED);
1406 }
1407
1408 size = msg->header.length;
1409
1410 if ((size % 4) != 0) {
1411 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message size: %d", msg->header.length);
1412 ABORT(R_FAILED);
1413 }
1414
1415 offset = sizeof(msg->header);
1416
1417 while (size > 0) {
1418 r_log(NR_LOG_STUN, LOG_DEBUG, "size = %d", size);
1419
1420 if (size < 4) {
1421 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message length: %d", size);
1422 ABORT(R_FAILED);
1423 }
1424
1425 if ((r=nr_stun_message_attribute_create(msg, &attr)))
1426 ABORT(R_NO_MEMORY);
1427
1428 attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[offset];
1429 attr->type = ntohs(attr->encoding->type);
1430 attr->length = ntohs(attr->encoding->length);
1431 attr->encoding_length = attr->length + 4;
1432
1433 if ((attr->length % 4) != 0) {
1434 padding_bytes = 4 - (attr->length % 4);
1435 attr->encoding_length += padding_bytes;
1436 }
1437
1438 if ((attr->encoding_length) > size) {
1439 r_log(NR_LOG_STUN, LOG_WARNING, "Attribute length larger than remaining message size: %d/%d", attr->encoding_length, size);
1440 ABORT(R_FAILED);
1441 }
1442
1443 if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) {
1444 if (attr->type <= 0x7FFF)
1445 ++msg->comprehension_required_unknown_attributes;
1446 else
1447 ++msg->comprehension_optional_unknown_attributes;
1448 r_log(NR_LOG_STUN, LOG_INFO, "Unrecognized attribute: 0x%04x", attr->type);
1449 }
1450 else {
1451 attr_info->name = attr_info->name;
1452 attr->type_name = attr_info->codec->name;
1453
1454 if (attr->type == NR_STUN_ATTR_MESSAGE_INTEGRITY) {
1455 if (get_password && get_password(arg, msg, &password) == 0) {
1456 if (password->len > sizeof(attr->u.message_integrity.password)) {
1457 r_log(NR_LOG_STUN, LOG_WARNING, "Password too long: %d bytes", password->len);
1458 ABORT(R_FAILED);
1459 }
1460
1461 memcpy(attr->u.message_integrity.password, password->data, password->len);
1462 attr->u.message_integrity.passwordlen = password->len;
1463 }
1464 else {
1465 /* set to user "not found" */
1466 attr->u.message_integrity.unknown_user = 1;
1467 }
1468 }
1469 else if (attr->type == NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS) {
1470 attr->type = NR_STUN_ATTR_XOR_MAPPED_ADDRESS;
1471 r_log(NR_LOG_STUN, LOG_INFO, "Translating obsolete XOR-MAPPED-ADDRESS type");
1472 }
1473
1474 if ((r=attr_info->codec->decode(attr_info, attr->length, msg->buffer, offset+4, msg->length, &attr->u))) {
1475 if (r == SKIP_ATTRIBUTE_DECODE) {
1476 r_log(NR_LOG_STUN, LOG_INFO, "Skipping %s", attr_info->name);
1477 }
1478 else {
1479 r_log(NR_LOG_STUN, LOG_WARNING, "Unable to parse %s", attr_info->name);
1480 }
1481
1482 attr->invalid = 1;
1483 }
1484 else {
1485 attr_info->codec->print(attr_info, "Parsed", &attr->u);
1486
1487 #ifdef USE_STUN_PEDANTIC
1488 r_log(NR_LOG_STUN, LOG_DEBUG, "Before pedantic attr_info checks");
1489 if (attr_info->illegal) {
1490 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u))) {
1491 r_log(NR_LOG_STUN, LOG_WARNING, "Failed pedantic attr_info checks");
1492 ABORT(r);
1493 }
1494 }
1495 r_log(NR_LOG_STUN, LOG_DEBUG, "After pedantic attr_info checks");
1496 #endif /* USE_STUN_PEDANTIC */
1497 }
1498 }
1499
1500 offset += attr->encoding_length;
1501 size -= attr->encoding_length;
1502 }
1503
1504 #ifdef SANITY_CHECKS
1505 sanity_check_encoding_stuff(msg);
1506 #endif /* SANITY_CHECKS */
1507
1508 _status=0;
1509 abort:
1510 return _status;
1511 }
1512

mercurial