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