Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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 */
34 static char *RCSSTRING __UNUSED__="$Id: stun_codec.c,v 1.2 2008/04/28 18:21:30 ekr Exp $";
36 #include <errno.h>
37 #include <csi_platform.h>
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>
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"
57 #define NR_STUN_IPV4_FAMILY 0x01
58 #define NR_STUN_IPV6_FAMILY 0x02
60 #define SKIP_ATTRIBUTE_DECODE -1
62 static int nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info);
64 static int nr_stun_fix_attribute_ordering(nr_stun_message *msg);
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);
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);
76 static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars);
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);
87 int
88 nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset)
89 {
90 UINT2 d = htons(data);
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 }
97 memcpy(&buf[*offset], &d, sizeof(d));
98 *offset += sizeof(d);
100 return 0;
101 }
103 int
104 nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset)
105 {
106 UINT4 d = htonl(data);
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 }
113 memcpy(&buf[*offset], &d, sizeof(d));
114 *offset += sizeof(d);
116 return 0;
117 }
119 int
120 nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset)
121 {
122 UINT8 d = nr_htonll(data);
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 }
129 memcpy(&buf[*offset], &d, sizeof(d));
130 *offset += sizeof(d);
132 return 0;
133 }
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 }
143 memcpy(&buf[*offset], data, length);
144 *offset += length;
146 return 0;
147 }
150 int
151 nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data)
152 {
153 UINT2 d;
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 }
160 memcpy(&d, &buf[*offset], sizeof(d));
161 *offset += sizeof(d);
162 *data = htons(d);
164 return 0;
165 }
167 int
168 nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data)
169 {
170 UINT4 d;
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 }
177 memcpy(&d, &buf[*offset], sizeof(d));
178 *offset += sizeof(d);
179 *data = htonl(d);
181 return 0;
182 }
184 int
185 nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data)
186 {
187 UINT8 d;
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 }
194 memcpy(&d, &buf[*offset], sizeof(d));
195 *offset += sizeof(d);
196 *data = nr_htonll(d);
198 return 0;
199 }
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 }
209 memcpy(data, &buf[*offset], length);
210 *offset += length;
212 return 0;
213 }
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;
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 }
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 }
237 _status = 0;
238 abort:
239 return _status;
240 }
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;
248 if (ec->number < 300 || ec->number > 699)
249 ABORT(R_FAILED);
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);
254 _status = 0;
255 abort:
256 return _status;
257 }
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 }
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 }
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 }
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 }
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 }
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;
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;
302 *attrlen = offset - start;
304 return 0;
305 }
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;
312 if (attrlen != sizeof(UINT4)) {
313 r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen);
314 return R_FAILED;
315 }
317 if (nr_stun_decode_htonl(buf, buflen, &offset, &tmp))
318 return R_FAILED;
320 *((UCHAR *)data) = (tmp >> 24) & 0xff;
322 return 0;
323 }
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 };
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 }
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;
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;
349 *attrlen = offset - start;
351 return 0;
352 }
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 }
362 if (nr_stun_decode_htonl(buf, buflen, &offset, (UINT4*)data))
363 return R_FAILED;
365 return 0;
366 }
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 };
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 }
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;
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;
392 *attrlen = offset - start;
394 return 0;
395 }
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 }
405 if (nr_stun_decode_htonll(buf, buflen, &offset, (UINT8*)data))
406 return R_FAILED;
408 return 0;
409 }
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 };
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 }
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;
434 if ((r=nr_stun_encode_htons(attr_info->type, buflen, buf, &offset)))
435 ABORT(r);
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;
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 }
458 *attrlen = offset - start;
460 _status = 0;
461 abort:
462 return _status;
463 }
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;
475 if (nr_stun_decode(1, buf, buflen, &offset, &pad)
476 || nr_stun_decode(1, buf, buflen, &offset, &family))
477 ABORT(R_FAILED);
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 }
486 if (nr_stun_decode_htons(buf, buflen, &offset, &port)
487 || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
488 ABORT(R_FAILED);
490 if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result))
491 ABORT(R_FAILED);
492 break;
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 }
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;
508 default:
509 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family);
510 ABORT(R_FAILED);
511 break;
512 }
514 _status = 0;
515 abort:
516 return _status;
517 }
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 };
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 }
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;
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;
545 *attrlen = offset - start;
547 return 0;
548 }
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;
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 }
562 if (nr_stun_decode(attrlen, buf, buflen, &offset, result->data))
563 ABORT(R_FAILED);
565 result->length = attrlen;
566 result->data[attrlen] = '\0'; /* just to be nice */
568 _status=0;
569 abort:
570 return _status;
571 }
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 };
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 }
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;
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;
608 *attrlen = offset - start;
610 return 0;
611 }
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;
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);
628 result->number = (class * 100) + number;
630 size_reason = attrlen - 4;
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 }
639 if (nr_stun_decode(size_reason, buf, buflen, &offset, (UCHAR*)result->reason))
640 ABORT(R_FAILED);
641 result->reason[size_reason] = '\0';
643 _status=0;
644 abort:
645 return _status;
646 }
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 };
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 }
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;
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);
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 }
681 fingerprint->checksum = checksum ^ 0x5354554e;
683 r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum);
685 fingerprint->valid = 1;
686 return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen);
687 }
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;
698 if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum)))
699 ABORT(r);
701 offset -= 4; /* rewind to before the length and type fields */
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);
710 /* make sure FINGERPRINT is final attribute in message */
711 assert(length + sizeof(*header) == buflen);
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 }
718 fingerprint->valid = (fingerprint->checksum == (checksum ^ 0x5354554e));
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);
724 _status=0;
725 abort:
726 return _status;
727 }
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 };
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 }
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;
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;
752 *attrlen = offset - start;
754 return 0;
755 }
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 }
765 return 0;
766 }
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 };
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 }
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;
791 r_log(NR_LOG_STUN, LOG_DEBUG, "Computing MESSAGE-INTEGRITY");
793 header = (nr_stun_message_header*)buf;
794 hold = header->length;
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);
802 if ((r=nr_crypto_hmac_sha1((UCHAR*)password, passwordlen,
803 buf, offset, computedHMAC)))
804 ABORT(r);
806 r_dump(NR_LOG_STUN, LOG_DEBUG, "Computed MESSAGE-INTEGRITY ", (char*)computedHMAC, 20);
808 _status=0;
809 abort:
810 header->length = hold;
811 return _status;
812 }
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;
820 if (nr_stun_compute_message_integrity(buf, offset, integrity->password, integrity->passwordlen, integrity->hash))
821 return R_FAILED;
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;
828 *attrlen = offset - start;
830 return 0;
831 }
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];
841 result->valid = 0;
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 }
848 start = offset - 4; /* rewind to before the length and type fields */
849 if (start < 0)
850 ABORT(R_INTERNAL);
852 if (nr_stun_decode(attrlen, buf, buflen, &offset, result->hash))
853 ABORT(R_FAILED);
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);
862 assert(sizeof(computedHMAC) == sizeof(result->hash));
864 result->valid = (memcmp(computedHMAC, result->hash, 20) == 0);
865 }
867 _status=0;
868 abort:
869 return _status;
870 }
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 };
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 }
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 };
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 }
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 }
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 }
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 };
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 }
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);
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;
943 *attrlen = offset - start;
945 return 0;
946 }
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;
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 }
960 if (nr_stun_decode(attrlen, buf, buflen, &offset, (UCHAR*)result))
961 ABORT(R_FAILED);
962 result[attrlen] = '\0'; /* just to be nice */
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 }
973 _status = 0;
974 abort:
975 return _status;
976 }
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 };
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;
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 }
999 r_log(NR_LOG_STUN, LOG_DEBUG, "%s", str);
1000 return 0;
1001 }
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;
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 }
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);
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 }
1026 *attrlen = offset - start;
1028 _status = 0;
1029 abort:
1030 return _status;
1031 }
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;
1041 if ((attrlen % 4) != 0) {
1042 r_log(NR_LOG_STUN, LOG_WARNING, "Attribute is illegal size: %d", attrlen);
1043 ABORT(R_REJECTED);
1044 }
1046 unknown_attributes->num_attributes = attrlen / 2;
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 }
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 }
1059 _status = 0;
1060 abort:
1061 return _status;
1062 }
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 };
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 }
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;
1089 r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
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);
1097 nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
1099 r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
1101 if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
1102 return R_FAILED;
1104 return 0;
1105 }
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;
1115 if ((r=nr_stun_attr_codec_addr.decode(attr_info, attrlen, buf, offset, buflen, &xor_mapped_address->masked)))
1116 ABORT(r);
1118 r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
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);
1126 nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
1128 r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
1130 _status = 0;
1131 abort:
1132 return _status;
1133 }
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 };
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 };
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 };
1156 #define NR_ADD_STUN_ATTRIBUTE(type, name, codec, illegal) \
1157 { (type), (name), &(codec), illegal },
1159 #define NR_ADD_STUN_ATTRIBUTE_IGNORE(type, name) \
1160 { (type), (name), &nr_stun_attr_codec_noop, 0 },
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)
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
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 */
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 };
1205 int
1206 nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info)
1207 {
1208 int _status;
1209 int i;
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 }
1219 if (*info == 0)
1220 ABORT(R_NOT_FOUND);
1222 _status=0;
1223 abort:
1224 return(_status);
1225 }
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;
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 }
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 }
1245 return 0;
1246 }
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;
1255 r_log(NR_LOG_STUN, LOG_DEBUG, "Starting to sanity check encoding");
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 */
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;
1283 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoding STUN message");
1285 nr_stun_fix_attribute_ordering(msg);
1287 msg->name = nr_stun_msg_type(msg->header.type);
1288 msg->length = 0;
1289 msg->header.length = 0;
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);
1298 /* grab the offset to be used later to re-write the header length field */
1299 length_offset_hold = msg->length;
1301 if ((r=nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &msg->length)))
1302 ABORT(r);
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);
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));
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 }
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];
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 }
1328 msg->length += attr->encoding_length;
1329 attr->length = attr->encoding_length - 4; /* -4 for type and length fields */
1331 if (attr_info->illegal) {
1332 if ((r=attr_info->illegal(attr_info, attr->length, &attr->u)))
1333 ABORT(r);
1334 }
1336 attr_info->codec->print(attr_info, "Encoded", &attr->u);
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 }
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 }
1353 r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Length: %d", msg->header.length);
1355 assert(msg->length < NR_STUN_MAX_MESSAGE_SIZE);
1357 #ifdef SANITY_CHECKS
1358 sanity_check_encoding_stuff(msg);
1359 #endif /* SANITY_CHECKS */
1361 _status=0;
1362 abort:
1363 return _status;
1364 }
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;
1377 r_log(NR_LOG_STUN, LOG_DEBUG, "Parsing STUN message of %d bytes", msg->length);
1379 if (!TAILQ_EMPTY(&msg->attributes))
1380 ABORT(R_BAD_ARGS);
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 }
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);
1392 msg->name = nr_stun_msg_type(msg->header.type);
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));
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 }
1408 size = msg->header.length;
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 }
1415 offset = sizeof(msg->header);
1417 while (size > 0) {
1418 r_log(NR_LOG_STUN, LOG_DEBUG, "size = %d", size);
1420 if (size < 4) {
1421 r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message length: %d", size);
1422 ABORT(R_FAILED);
1423 }
1425 if ((r=nr_stun_message_attribute_create(msg, &attr)))
1426 ABORT(R_NO_MEMORY);
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;
1433 if ((attr->length % 4) != 0) {
1434 padding_bytes = 4 - (attr->length % 4);
1435 attr->encoding_length += padding_bytes;
1436 }
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 }
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;
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 }
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 }
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 }
1482 attr->invalid = 1;
1483 }
1484 else {
1485 attr_info->codec->print(attr_info, "Parsed", &attr->u);
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 }
1500 offset += attr->encoding_length;
1501 size -= attr->encoding_length;
1502 }
1504 #ifdef SANITY_CHECKS
1505 sanity_check_encoding_stuff(msg);
1506 #endif /* SANITY_CHECKS */
1508 _status=0;
1509 abort:
1510 return _status;
1511 }