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