1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1512 @@ 1.4 +/* 1.5 +Copyright (c) 2007, Adobe Systems, Incorporated 1.6 +All rights reserved. 1.7 + 1.8 +Redistribution and use in source and binary forms, with or without 1.9 +modification, are permitted provided that the following conditions are 1.10 +met: 1.11 + 1.12 +* Redistributions of source code must retain the above copyright 1.13 + notice, this list of conditions and the following disclaimer. 1.14 + 1.15 +* Redistributions in binary form must reproduce the above copyright 1.16 + notice, this list of conditions and the following disclaimer in the 1.17 + documentation and/or other materials provided with the distribution. 1.18 + 1.19 +* Neither the name of Adobe Systems, Network Resonance nor the names of its 1.20 + contributors may be used to endorse or promote products derived from 1.21 + this software without specific prior written permission. 1.22 + 1.23 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.24 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.25 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.26 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.27 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.28 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.29 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.30 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.31 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.32 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.33 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.34 +*/ 1.35 + 1.36 + 1.37 +static char *RCSSTRING __UNUSED__="$Id: stun_codec.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; 1.38 + 1.39 +#include <errno.h> 1.40 +#include <csi_platform.h> 1.41 + 1.42 +#ifdef WIN32 1.43 +#include <winsock2.h> 1.44 +#include <stdlib.h> 1.45 +#include <io.h> 1.46 +#include <time.h> 1.47 +#else /* UNIX */ 1.48 +#include <string.h> 1.49 +#endif /* end UNIX */ 1.50 +#include <assert.h> 1.51 +#include <stddef.h> 1.52 + 1.53 +#include "nr_api.h" 1.54 +#include "stun.h" 1.55 +#include "byteorder.h" 1.56 +#include "r_crc32.h" 1.57 +#include "nr_crypto.h" 1.58 +#include "mbslen.h" 1.59 + 1.60 +#define NR_STUN_IPV4_FAMILY 0x01 1.61 +#define NR_STUN_IPV6_FAMILY 0x02 1.62 + 1.63 +#define SKIP_ATTRIBUTE_DECODE -1 1.64 + 1.65 +static int nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info); 1.66 + 1.67 +static int nr_stun_fix_attribute_ordering(nr_stun_message *msg); 1.68 + 1.69 +static int nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset); 1.70 +static int nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset); 1.71 +static int nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset); 1.72 +static int nr_stun_encode(UCHAR *data, int length, int buflen, UCHAR *buf, int *offset); 1.73 + 1.74 +static int nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data); 1.75 +static int nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data); 1.76 +static int nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data); 1.77 +static int nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data); 1.78 + 1.79 +static int nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars); 1.80 + 1.81 +static int nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); 1.82 +static int nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); 1.83 +static int nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); 1.84 +static int nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); 1.85 +static int nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data); 1.86 +static int 1.87 +nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data); 1.88 + 1.89 + 1.90 +int 1.91 +nr_stun_encode_htons(UINT2 data, int buflen, UCHAR *buf, int *offset) 1.92 +{ 1.93 + UINT2 d = htons(data); 1.94 + 1.95 + if (*offset + sizeof(d) >= buflen) { 1.96 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd >= %d", *offset, sizeof(d), buflen); 1.97 + return R_BAD_DATA; 1.98 + } 1.99 + 1.100 + memcpy(&buf[*offset], &d, sizeof(d)); 1.101 + *offset += sizeof(d); 1.102 + 1.103 + return 0; 1.104 +} 1.105 + 1.106 +int 1.107 +nr_stun_encode_htonl(UINT4 data, int buflen, UCHAR *buf, int *offset) 1.108 +{ 1.109 + UINT4 d = htonl(data); 1.110 + 1.111 + if (*offset + sizeof(d) > buflen) { 1.112 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen); 1.113 + return R_BAD_DATA; 1.114 + } 1.115 + 1.116 + memcpy(&buf[*offset], &d, sizeof(d)); 1.117 + *offset += sizeof(d); 1.118 + 1.119 + return 0; 1.120 +} 1.121 + 1.122 +int 1.123 +nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset) 1.124 +{ 1.125 + UINT8 d = nr_htonll(data); 1.126 + 1.127 + if (*offset + sizeof(d) > buflen) { 1.128 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen); 1.129 + return R_BAD_DATA; 1.130 + } 1.131 + 1.132 + memcpy(&buf[*offset], &d, sizeof(d)); 1.133 + *offset += sizeof(d); 1.134 + 1.135 + return 0; 1.136 +} 1.137 + 1.138 +int 1.139 +nr_stun_encode(UCHAR *data, int length, int buflen, UCHAR *buf, int *offset) 1.140 +{ 1.141 + if (*offset + length > buflen) { 1.142 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen); 1.143 + return R_BAD_DATA; 1.144 + } 1.145 + 1.146 + memcpy(&buf[*offset], data, length); 1.147 + *offset += length; 1.148 + 1.149 + return 0; 1.150 +} 1.151 + 1.152 + 1.153 +int 1.154 +nr_stun_decode_htons(UCHAR *buf, int buflen, int *offset, UINT2 *data) 1.155 +{ 1.156 + UINT2 d; 1.157 + 1.158 + if (*offset + sizeof(d) > buflen) { 1.159 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen); 1.160 + return R_BAD_DATA; 1.161 + } 1.162 + 1.163 + memcpy(&d, &buf[*offset], sizeof(d)); 1.164 + *offset += sizeof(d); 1.165 + *data = htons(d); 1.166 + 1.167 + return 0; 1.168 +} 1.169 + 1.170 +int 1.171 +nr_stun_decode_htonl(UCHAR *buf, int buflen, int *offset, UINT4 *data) 1.172 +{ 1.173 + UINT4 d; 1.174 + 1.175 + if (*offset + sizeof(d) > buflen) { 1.176 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen); 1.177 + return R_BAD_DATA; 1.178 + } 1.179 + 1.180 + memcpy(&d, &buf[*offset], sizeof(d)); 1.181 + *offset += sizeof(d); 1.182 + *data = htonl(d); 1.183 + 1.184 + return 0; 1.185 +} 1.186 + 1.187 +int 1.188 +nr_stun_decode_htonll(UCHAR *buf, int buflen, int *offset, UINT8 *data) 1.189 +{ 1.190 + UINT8 d; 1.191 + 1.192 + if (*offset + sizeof(d) > buflen) { 1.193 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen); 1.194 + return R_BAD_DATA; 1.195 + } 1.196 + 1.197 + memcpy(&d, &buf[*offset], sizeof(d)); 1.198 + *offset += sizeof(d); 1.199 + *data = nr_htonll(d); 1.200 + 1.201 + return 0; 1.202 +} 1.203 + 1.204 +int 1.205 +nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data) 1.206 +{ 1.207 + if (*offset + length > buflen) { 1.208 + r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %d > %d", *offset, length, buflen); 1.209 + return R_BAD_DATA; 1.210 + } 1.211 + 1.212 + memcpy(data, &buf[*offset], length); 1.213 + *offset += length; 1.214 + 1.215 + return 0; 1.216 +} 1.217 + 1.218 +int 1.219 +nr_stun_attr_string_illegal(nr_stun_attr_info *attr_info, int len, void *data, int max_bytes, int max_chars) 1.220 +{ 1.221 + int _status; 1.222 + char *s = data; 1.223 + size_t nchars; 1.224 + 1.225 + if (len > max_bytes) { 1.226 + r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %d bytes", attr_info->name, len); 1.227 + ABORT(R_FAILED); 1.228 + } 1.229 + 1.230 + if (max_chars >= 0) { 1.231 + if (mbslen(s, &nchars)) { 1.232 + /* who knows what to do, just assume everything is working ok */ 1.233 + } 1.234 + else if (nchars > max_chars) { 1.235 + r_log(NR_LOG_STUN, LOG_WARNING, "%s is too large: %zd characters", attr_info->name, nchars); 1.236 + ABORT(R_FAILED); 1.237 + } 1.238 + } 1.239 + 1.240 + _status = 0; 1.241 + abort: 1.242 + return _status; 1.243 +} 1.244 + 1.245 +int 1.246 +nr_stun_attr_error_code_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data) 1.247 +{ 1.248 + int r,_status; 1.249 + nr_stun_attr_error_code *ec = data; 1.250 + 1.251 + if (ec->number < 300 || ec->number > 699) 1.252 + ABORT(R_FAILED); 1.253 + 1.254 + 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))) 1.255 + ABORT(r); 1.256 + 1.257 + _status = 0; 1.258 + abort: 1.259 + return _status; 1.260 +} 1.261 + 1.262 +int 1.263 +nr_stun_attr_nonce_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data) 1.264 +{ 1.265 + return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_NONCE_BYTES, NR_STUN_MAX_NONCE_CHARS); 1.266 +} 1.267 + 1.268 +int 1.269 +nr_stun_attr_realm_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data) 1.270 +{ 1.271 + return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_REALM_BYTES, NR_STUN_MAX_REALM_CHARS); 1.272 +} 1.273 + 1.274 +int 1.275 +nr_stun_attr_server_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data) 1.276 +{ 1.277 + return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_SERVER_BYTES, NR_STUN_MAX_SERVER_CHARS); 1.278 +} 1.279 + 1.280 +int 1.281 +nr_stun_attr_username_illegal(nr_stun_attr_info *attr_info, int attrlen, void *data) 1.282 +{ 1.283 + return nr_stun_attr_string_illegal(attr_info, attrlen, data, NR_STUN_MAX_USERNAME_BYTES, -1); 1.284 +} 1.285 + 1.286 +static int 1.287 +nr_stun_attr_codec_UCHAR_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.288 +{ 1.289 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UCHAR*)data); 1.290 + return 0; 1.291 +} 1.292 + 1.293 +static int 1.294 +nr_stun_attr_codec_UCHAR_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.295 +{ 1.296 + int start = offset; 1.297 + UINT4 tmp = *((UCHAR *)data); 1.298 + tmp <<= 24; 1.299 + 1.300 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.301 + || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset) 1.302 + || nr_stun_encode_htonl(tmp , buflen, buf, &offset)) 1.303 + return R_FAILED; 1.304 + 1.305 + *attrlen = offset - start; 1.306 + 1.307 + return 0; 1.308 +} 1.309 + 1.310 +static int 1.311 +nr_stun_attr_codec_UCHAR_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.312 +{ 1.313 + UINT4 tmp; 1.314 + 1.315 + if (attrlen != sizeof(UINT4)) { 1.316 + r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen); 1.317 + return R_FAILED; 1.318 + } 1.319 + 1.320 + if (nr_stun_decode_htonl(buf, buflen, &offset, &tmp)) 1.321 + return R_FAILED; 1.322 + 1.323 + *((UCHAR *)data) = (tmp >> 24) & 0xff; 1.324 + 1.325 + return 0; 1.326 +} 1.327 + 1.328 +nr_stun_attr_codec nr_stun_attr_codec_UCHAR = { 1.329 + "UCHAR", 1.330 + nr_stun_attr_codec_UCHAR_print, 1.331 + nr_stun_attr_codec_UCHAR_encode, 1.332 + nr_stun_attr_codec_UCHAR_decode 1.333 +}; 1.334 + 1.335 +static int 1.336 +nr_stun_attr_codec_UINT4_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.337 +{ 1.338 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %u", msg, attr_info->name, *(UINT4*)data); 1.339 + return 0; 1.340 +} 1.341 + 1.342 +static int 1.343 +nr_stun_attr_codec_UINT4_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.344 +{ 1.345 + int start = offset; 1.346 + 1.347 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.348 + || nr_stun_encode_htons(sizeof(UINT4) , buflen, buf, &offset) 1.349 + || nr_stun_encode_htonl(*(UINT4*)data , buflen, buf, &offset)) 1.350 + return R_FAILED; 1.351 + 1.352 + *attrlen = offset - start; 1.353 + 1.354 + return 0; 1.355 +} 1.356 + 1.357 +static int 1.358 +nr_stun_attr_codec_UINT4_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.359 +{ 1.360 + if (attrlen != sizeof(UINT4)) { 1.361 + r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen); 1.362 + return R_FAILED; 1.363 + } 1.364 + 1.365 + if (nr_stun_decode_htonl(buf, buflen, &offset, (UINT4*)data)) 1.366 + return R_FAILED; 1.367 + 1.368 + return 0; 1.369 +} 1.370 + 1.371 +nr_stun_attr_codec nr_stun_attr_codec_UINT4 = { 1.372 + "UINT4", 1.373 + nr_stun_attr_codec_UINT4_print, 1.374 + nr_stun_attr_codec_UINT4_encode, 1.375 + nr_stun_attr_codec_UINT4_decode 1.376 +}; 1.377 + 1.378 +static int 1.379 +nr_stun_attr_codec_UINT8_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.380 +{ 1.381 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %llu", msg, attr_info->name, *(UINT8*)data); 1.382 + return 0; 1.383 +} 1.384 + 1.385 +static int 1.386 +nr_stun_attr_codec_UINT8_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.387 +{ 1.388 + int start = offset; 1.389 + 1.390 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.391 + || nr_stun_encode_htons(sizeof(UINT8) , buflen, buf, &offset) 1.392 + || nr_stun_encode_htonll(*(UINT8*)data , buflen, buf, &offset)) 1.393 + return R_FAILED; 1.394 + 1.395 + *attrlen = offset - start; 1.396 + 1.397 + return 0; 1.398 +} 1.399 + 1.400 +static int 1.401 +nr_stun_attr_codec_UINT8_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.402 +{ 1.403 + if (attrlen != sizeof(UINT8)) { 1.404 + r_log(NR_LOG_STUN, LOG_WARNING, "Integer is illegal size: %d", attrlen); 1.405 + return R_FAILED; 1.406 + } 1.407 + 1.408 + if (nr_stun_decode_htonll(buf, buflen, &offset, (UINT8*)data)) 1.409 + return R_FAILED; 1.410 + 1.411 + return 0; 1.412 +} 1.413 + 1.414 +nr_stun_attr_codec nr_stun_attr_codec_UINT8 = { 1.415 + "UINT8", 1.416 + nr_stun_attr_codec_UINT8_print, 1.417 + nr_stun_attr_codec_UINT8_encode, 1.418 + nr_stun_attr_codec_UINT8_decode 1.419 +}; 1.420 + 1.421 +static int 1.422 +nr_stun_attr_codec_addr_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.423 +{ 1.424 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s", msg, attr_info->name, ((nr_transport_addr*)data)->as_string); 1.425 + return 0; 1.426 +} 1.427 + 1.428 +static int 1.429 +nr_stun_attr_codec_addr_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.430 +{ 1.431 + int r,_status; 1.432 + int start = offset; 1.433 + nr_transport_addr *addr = data; 1.434 + UCHAR pad = '\0'; 1.435 + UCHAR family; 1.436 + 1.437 + if ((r=nr_stun_encode_htons(attr_info->type, buflen, buf, &offset))) 1.438 + ABORT(r); 1.439 + 1.440 + switch (addr->ip_version) { 1.441 + case NR_IPV4: 1.442 + family = NR_STUN_IPV4_FAMILY; 1.443 + if (nr_stun_encode_htons(8 , buflen, buf, &offset) 1.444 + || nr_stun_encode(&pad, 1 , buflen, buf, &offset) 1.445 + || nr_stun_encode(&family, 1 , buflen, buf, &offset) 1.446 + || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port), buflen, buf, &offset) 1.447 + || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset)) 1.448 + ABORT(R_FAILED); 1.449 + break; 1.450 + 1.451 + case NR_IPV6: 1.452 + assert(0); 1.453 + ABORT(R_INTERNAL); 1.454 + break; 1.455 + default: 1.456 + assert(0); 1.457 + ABORT(R_INTERNAL); 1.458 + break; 1.459 + } 1.460 + 1.461 + *attrlen = offset - start; 1.462 + 1.463 + _status = 0; 1.464 + abort: 1.465 + return _status; 1.466 +} 1.467 + 1.468 +static int 1.469 +nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.470 +{ 1.471 + int _status; 1.472 + UCHAR pad; 1.473 + UCHAR family; 1.474 + UINT2 port; 1.475 + UINT4 addr4; 1.476 + nr_transport_addr *result = data; 1.477 + 1.478 + if (nr_stun_decode(1, buf, buflen, &offset, &pad) 1.479 + || nr_stun_decode(1, buf, buflen, &offset, &family)) 1.480 + ABORT(R_FAILED); 1.481 + 1.482 + switch (family) { 1.483 + case NR_STUN_IPV4_FAMILY: 1.484 + if (attrlen != 8) { 1.485 + r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen); 1.486 + ABORT(R_FAILED); 1.487 + } 1.488 + 1.489 + if (nr_stun_decode_htons(buf, buflen, &offset, &port) 1.490 + || nr_stun_decode_htonl(buf, buflen, &offset, &addr4)) 1.491 + ABORT(R_FAILED); 1.492 + 1.493 + if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result)) 1.494 + ABORT(R_FAILED); 1.495 + break; 1.496 + 1.497 + case NR_STUN_IPV6_FAMILY: 1.498 + if (attrlen != 16) { 1.499 + r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen); 1.500 + ABORT(R_FAILED); 1.501 + } 1.502 + 1.503 + r_log(NR_LOG_STUN, LOG_WARNING, "IPv6 not supported"); 1.504 +#ifdef NDEBUG 1.505 + ABORT(SKIP_ATTRIBUTE_DECODE); 1.506 +#else 1.507 + UNIMPLEMENTED; 1.508 +#endif /* NDEBUG */ 1.509 + break; 1.510 + 1.511 + default: 1.512 + r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family); 1.513 + ABORT(R_FAILED); 1.514 + break; 1.515 + } 1.516 + 1.517 + _status = 0; 1.518 + abort: 1.519 + return _status; 1.520 +} 1.521 + 1.522 +nr_stun_attr_codec nr_stun_attr_codec_addr = { 1.523 + "addr", 1.524 + nr_stun_attr_codec_addr_print, 1.525 + nr_stun_attr_codec_addr_encode, 1.526 + nr_stun_attr_codec_addr_decode 1.527 +}; 1.528 + 1.529 +static int 1.530 +nr_stun_attr_codec_data_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.531 +{ 1.532 + nr_stun_attr_data *d = data; 1.533 + r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)d->data, d->length); 1.534 + return 0; 1.535 +} 1.536 + 1.537 +static int 1.538 +nr_stun_attr_codec_data_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.539 +{ 1.540 + nr_stun_attr_data *d = data; 1.541 + int start = offset; 1.542 + 1.543 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.544 + || nr_stun_encode_htons(d->length , buflen, buf, &offset) 1.545 + || nr_stun_encode(d->data, d->length , buflen, buf, &offset)) 1.546 + return R_FAILED; 1.547 + 1.548 + *attrlen = offset - start; 1.549 + 1.550 + return 0; 1.551 +} 1.552 + 1.553 +static int 1.554 +nr_stun_attr_codec_data_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.555 +{ 1.556 + int _status; 1.557 + nr_stun_attr_data *result = data; 1.558 + 1.559 + /* -1 because it is going to be null terminated just to be safe */ 1.560 + if (attrlen >= (sizeof(result->data) - 1)) { 1.561 + r_log(NR_LOG_STUN, LOG_WARNING, "Too much data: %d bytes", attrlen); 1.562 + ABORT(R_FAILED); 1.563 + } 1.564 + 1.565 + if (nr_stun_decode(attrlen, buf, buflen, &offset, result->data)) 1.566 + ABORT(R_FAILED); 1.567 + 1.568 + result->length = attrlen; 1.569 + result->data[attrlen] = '\0'; /* just to be nice */ 1.570 + 1.571 + _status=0; 1.572 + abort: 1.573 + return _status; 1.574 +} 1.575 + 1.576 +nr_stun_attr_codec nr_stun_attr_codec_data = { 1.577 + "data", 1.578 + nr_stun_attr_codec_data_print, 1.579 + nr_stun_attr_codec_data_encode, 1.580 + nr_stun_attr_codec_data_decode 1.581 +}; 1.582 + 1.583 +static int 1.584 +nr_stun_attr_codec_error_code_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.585 +{ 1.586 + nr_stun_attr_error_code *error_code = data; 1.587 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %d %s", 1.588 + msg, attr_info->name, error_code->number, 1.589 + error_code->reason); 1.590 + return 0; 1.591 +} 1.592 + 1.593 +static int 1.594 +nr_stun_attr_codec_error_code_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.595 +{ 1.596 + nr_stun_attr_error_code *error_code = data; 1.597 + int start = offset; 1.598 + int length = strlen(error_code->reason); 1.599 + UCHAR pad[2] = { 0 }; 1.600 + UCHAR class = error_code->number / 100; 1.601 + UCHAR number = error_code->number % 100; 1.602 + 1.603 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.604 + || nr_stun_encode_htons(4 + length , buflen, buf, &offset) 1.605 + || nr_stun_encode(pad, 2 , buflen, buf, &offset) 1.606 + || nr_stun_encode(&class, 1 , buflen, buf, &offset) 1.607 + || nr_stun_encode(&number, 1 , buflen, buf, &offset) 1.608 + || nr_stun_encode((UCHAR*)error_code->reason, length, buflen, buf, &offset)) 1.609 + return R_FAILED; 1.610 + 1.611 + *attrlen = offset - start; 1.612 + 1.613 + return 0; 1.614 +} 1.615 + 1.616 +static int 1.617 +nr_stun_attr_codec_error_code_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.618 +{ 1.619 + int _status; 1.620 + nr_stun_attr_error_code *result = data; 1.621 + UCHAR pad[2]; 1.622 + UCHAR class; 1.623 + UCHAR number; 1.624 + int size_reason; 1.625 + 1.626 + if (nr_stun_decode(2, buf, buflen, &offset, pad) 1.627 + || nr_stun_decode(1, buf, buflen, &offset, &class) 1.628 + || nr_stun_decode(1, buf, buflen, &offset, &number)) 1.629 + ABORT(R_FAILED); 1.630 + 1.631 + result->number = (class * 100) + number; 1.632 + 1.633 + size_reason = attrlen - 4; 1.634 + 1.635 + /* -1 because the string will be null terminated */ 1.636 + if (size_reason > (sizeof(result->reason) - 1)) { 1.637 + r_log(NR_LOG_STUN, LOG_WARNING, "Reason is too large, truncating"); 1.638 + /* don't fail, but instead truncate the reason */ 1.639 + size_reason = sizeof(result->reason) - 1; 1.640 + } 1.641 + 1.642 + if (nr_stun_decode(size_reason, buf, buflen, &offset, (UCHAR*)result->reason)) 1.643 + ABORT(R_FAILED); 1.644 + result->reason[size_reason] = '\0'; 1.645 + 1.646 + _status=0; 1.647 + abort: 1.648 + return _status; 1.649 +} 1.650 + 1.651 +nr_stun_attr_codec nr_stun_attr_codec_error_code = { 1.652 + "error_code", 1.653 + nr_stun_attr_codec_error_code_print, 1.654 + nr_stun_attr_codec_error_code_encode, 1.655 + nr_stun_attr_codec_error_code_decode 1.656 +}; 1.657 + 1.658 +static int 1.659 +nr_stun_attr_codec_fingerprint_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.660 +{ 1.661 + nr_stun_attr_fingerprint *fingerprint = data; 1.662 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %08x", msg, attr_info->name, fingerprint->checksum); 1.663 + return 0; 1.664 +} 1.665 + 1.666 +static int 1.667 +nr_stun_attr_codec_fingerprint_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.668 +{ 1.669 + UINT4 checksum; 1.670 + nr_stun_attr_fingerprint *fingerprint = data; 1.671 + nr_stun_message_header *header = (nr_stun_message_header*)buf; 1.672 + 1.673 + /* the length must include the FINGERPRINT attribute when computing 1.674 + * the fingerprint */ 1.675 + header->length = ntohs(header->length); 1.676 + header->length += 8; /* Fingerprint */ 1.677 + header->length = htons(header->length); 1.678 + 1.679 + if (r_crc32((char*)buf, offset, &checksum)) { 1.680 + r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint"); 1.681 + return R_FAILED; 1.682 + } 1.683 + 1.684 + fingerprint->checksum = checksum ^ 0x5354554e; 1.685 + 1.686 + r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", fingerprint->checksum); 1.687 + 1.688 + fingerprint->valid = 1; 1.689 + return nr_stun_attr_codec_UINT4.encode(attr_info, &fingerprint->checksum, offset, buflen, buf, attrlen); 1.690 +} 1.691 + 1.692 +static int 1.693 +nr_stun_attr_codec_fingerprint_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.694 +{ 1.695 + int r,_status; 1.696 + nr_stun_attr_fingerprint *fingerprint = data; 1.697 + nr_stun_message_header *header = (nr_stun_message_header*)buf; 1.698 + int length; 1.699 + UINT4 checksum; 1.700 + 1.701 + if ((r=nr_stun_attr_codec_UINT4.decode(attr_info, attrlen, buf, offset, buflen, &fingerprint->checksum))) 1.702 + ABORT(r); 1.703 + 1.704 + offset -= 4; /* rewind to before the length and type fields */ 1.705 + 1.706 + /* the length must include the FINGERPRINT attribute when computing 1.707 + * the fingerprint */ 1.708 + length = offset; /* right before FINGERPRINT */ 1.709 + length -= sizeof(*header); /* remove header length */ 1.710 + length += 8; /* add length of Fingerprint */ 1.711 + header->length = htons(length); 1.712 + 1.713 + /* make sure FINGERPRINT is final attribute in message */ 1.714 + assert(length + sizeof(*header) == buflen); 1.715 + 1.716 + if (r_crc32((char*)buf, offset, &checksum)) { 1.717 + r_log(NR_LOG_STUN, LOG_WARNING, "Unable to compute fingerprint"); 1.718 + ABORT(R_FAILED); 1.719 + } 1.720 + 1.721 + fingerprint->valid = (fingerprint->checksum == (checksum ^ 0x5354554e)); 1.722 + 1.723 + r_log(NR_LOG_STUN, LOG_DEBUG, "Computed FINGERPRINT %08x", (checksum ^ 0x5354554e)); 1.724 + if (! fingerprint->valid) 1.725 + r_log(NR_LOG_STUN, LOG_WARNING, "Invalid FINGERPRINT %08x", fingerprint->checksum); 1.726 + 1.727 + _status=0; 1.728 + abort: 1.729 + return _status; 1.730 +} 1.731 + 1.732 +nr_stun_attr_codec nr_stun_attr_codec_fingerprint = { 1.733 + "fingerprint", 1.734 + nr_stun_attr_codec_fingerprint_print, 1.735 + nr_stun_attr_codec_fingerprint_encode, 1.736 + nr_stun_attr_codec_fingerprint_decode 1.737 +}; 1.738 + 1.739 +static int 1.740 +nr_stun_attr_codec_flag_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.741 +{ 1.742 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: on", msg, attr_info->name); 1.743 + return 0; 1.744 +} 1.745 + 1.746 +static int 1.747 +nr_stun_attr_codec_flag_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.748 +{ 1.749 + int start = offset; 1.750 + 1.751 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.752 + || nr_stun_encode_htons(0 , buflen, buf, &offset)) 1.753 + return R_FAILED; 1.754 + 1.755 + *attrlen = offset - start; 1.756 + 1.757 + return 0; 1.758 +} 1.759 + 1.760 +static int 1.761 +nr_stun_attr_codec_flag_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.762 +{ 1.763 + if (attrlen != 0) { 1.764 + r_log(NR_LOG_STUN, LOG_WARNING, "Illegal flag length: %d", attrlen); 1.765 + return R_FAILED; 1.766 + } 1.767 + 1.768 + return 0; 1.769 +} 1.770 + 1.771 +nr_stun_attr_codec nr_stun_attr_codec_flag = { 1.772 + "flag", 1.773 + nr_stun_attr_codec_flag_print, 1.774 + nr_stun_attr_codec_flag_encode, 1.775 + nr_stun_attr_codec_flag_decode 1.776 +}; 1.777 + 1.778 +static int 1.779 +nr_stun_attr_codec_message_integrity_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.780 +{ 1.781 + nr_stun_attr_message_integrity *integrity = data; 1.782 + r_dump(NR_LOG_STUN, LOG_DEBUG, attr_info->name, (char*)integrity->hash, sizeof(integrity->hash)); 1.783 + return 0; 1.784 +} 1.785 + 1.786 +static int 1.787 +nr_stun_compute_message_integrity(UCHAR *buf, int offset, UCHAR *password, int passwordlen, UCHAR *computedHMAC) 1.788 +{ 1.789 + int r,_status; 1.790 + UINT2 hold; 1.791 + UINT2 length; 1.792 + nr_stun_message_header *header; 1.793 + 1.794 + r_log(NR_LOG_STUN, LOG_DEBUG, "Computing MESSAGE-INTEGRITY"); 1.795 + 1.796 + header = (nr_stun_message_header*)buf; 1.797 + hold = header->length; 1.798 + 1.799 + /* adjust the length of the message */ 1.800 + length = offset; 1.801 + length -= sizeof(*header); 1.802 + length += 24; /* for MESSAGE-INTEGRITY attribute */ 1.803 + header->length = htons(length); 1.804 + 1.805 + if ((r=nr_crypto_hmac_sha1((UCHAR*)password, passwordlen, 1.806 + buf, offset, computedHMAC))) 1.807 + ABORT(r); 1.808 + 1.809 + r_dump(NR_LOG_STUN, LOG_DEBUG, "Computed MESSAGE-INTEGRITY ", (char*)computedHMAC, 20); 1.810 + 1.811 + _status=0; 1.812 + abort: 1.813 + header->length = hold; 1.814 + return _status; 1.815 +} 1.816 + 1.817 +static int 1.818 +nr_stun_attr_codec_message_integrity_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.819 +{ 1.820 + int start = offset; 1.821 + nr_stun_attr_message_integrity *integrity = data; 1.822 + 1.823 + if (nr_stun_compute_message_integrity(buf, offset, integrity->password, integrity->passwordlen, integrity->hash)) 1.824 + return R_FAILED; 1.825 + 1.826 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.827 + || nr_stun_encode_htons(sizeof(integrity->hash) , buflen, buf, &offset) 1.828 + || nr_stun_encode(integrity->hash, sizeof(integrity->hash) , buflen, buf, &offset)) 1.829 + return R_FAILED; 1.830 + 1.831 + *attrlen = offset - start; 1.832 + 1.833 + return 0; 1.834 +} 1.835 + 1.836 +static int 1.837 +nr_stun_attr_codec_message_integrity_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.838 +{ 1.839 + int _status; 1.840 + int start; 1.841 + nr_stun_attr_message_integrity *result = data; 1.842 + UCHAR computedHMAC[20]; 1.843 + 1.844 + result->valid = 0; 1.845 + 1.846 + if (attrlen != 20) { 1.847 + r_log(NR_LOG_STUN, LOG_WARNING, "%s must be 20 bytes, not %d", attr_info->name, attrlen); 1.848 + ABORT(R_FAILED); 1.849 + } 1.850 + 1.851 + start = offset - 4; /* rewind to before the length and type fields */ 1.852 + if (start < 0) 1.853 + ABORT(R_INTERNAL); 1.854 + 1.855 + if (nr_stun_decode(attrlen, buf, buflen, &offset, result->hash)) 1.856 + ABORT(R_FAILED); 1.857 + 1.858 + if (result->unknown_user) { 1.859 + result->valid = 0; 1.860 + } 1.861 + else { 1.862 + if (nr_stun_compute_message_integrity(buf, start, result->password, result->passwordlen, computedHMAC)) 1.863 + ABORT(R_FAILED); 1.864 + 1.865 + assert(sizeof(computedHMAC) == sizeof(result->hash)); 1.866 + 1.867 + result->valid = (memcmp(computedHMAC, result->hash, 20) == 0); 1.868 + } 1.869 + 1.870 + _status=0; 1.871 + abort: 1.872 + return _status; 1.873 +} 1.874 + 1.875 +nr_stun_attr_codec nr_stun_attr_codec_message_integrity = { 1.876 + "message_integrity", 1.877 + nr_stun_attr_codec_message_integrity_print, 1.878 + nr_stun_attr_codec_message_integrity_encode, 1.879 + nr_stun_attr_codec_message_integrity_decode 1.880 +}; 1.881 + 1.882 +static int 1.883 +nr_stun_attr_codec_noop_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.884 +{ 1.885 + return SKIP_ATTRIBUTE_DECODE; 1.886 +} 1.887 + 1.888 +nr_stun_attr_codec nr_stun_attr_codec_noop = { 1.889 + "NOOP", 1.890 + 0, /* ignore, never print these attributes */ 1.891 + 0, /* ignore, never encode these attributes */ 1.892 + nr_stun_attr_codec_noop_decode 1.893 +}; 1.894 + 1.895 +static int 1.896 +nr_stun_attr_codec_quoted_string_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.897 +{ 1.898 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s", 1.899 + msg, attr_info->name, (char*)data); 1.900 + return 0; 1.901 +} 1.902 + 1.903 +static int 1.904 +nr_stun_attr_codec_quoted_string_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.905 +{ 1.906 +//TODO: !nn! syntax check, conversion if not quoted already? 1.907 +//We'll just restrict this in the API -- EKR 1.908 + return nr_stun_attr_codec_string.encode(attr_info, data, offset, buflen, buf, attrlen); 1.909 +} 1.910 + 1.911 +static int 1.912 +nr_stun_attr_codec_quoted_string_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.913 +{ 1.914 +//TODO: !nn! I don't see any need to unquote this but we may 1.915 +//find one later -- EKR 1.916 + return nr_stun_attr_codec_string.decode(attr_info, attrlen, buf, offset, buflen, data); 1.917 +} 1.918 + 1.919 +nr_stun_attr_codec nr_stun_attr_codec_quoted_string = { 1.920 + "quoted_string", 1.921 + nr_stun_attr_codec_quoted_string_print, 1.922 + nr_stun_attr_codec_quoted_string_encode, 1.923 + nr_stun_attr_codec_quoted_string_decode 1.924 +}; 1.925 + 1.926 +static int 1.927 +nr_stun_attr_codec_string_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.928 +{ 1.929 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s", 1.930 + msg, attr_info->name, (char*)data); 1.931 + return 0; 1.932 +} 1.933 + 1.934 +static int 1.935 +nr_stun_attr_codec_string_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.936 +{ 1.937 + int start = offset; 1.938 + char *str = data; 1.939 + int length = strlen(str); 1.940 + 1.941 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.942 + || nr_stun_encode_htons(length , buflen, buf, &offset) 1.943 + || nr_stun_encode((UCHAR*)str, length , buflen, buf, &offset)) 1.944 + return R_FAILED; 1.945 + 1.946 + *attrlen = offset - start; 1.947 + 1.948 + return 0; 1.949 +} 1.950 + 1.951 +static int 1.952 +nr_stun_attr_codec_string_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.953 +{ 1.954 + int _status; 1.955 + char *result = data; 1.956 + 1.957 + /* actual enforcement of the specific string size happens elsewhere */ 1.958 + if (attrlen >= NR_STUN_MAX_STRING_SIZE) { 1.959 + r_log(NR_LOG_STUN, LOG_WARNING, "String is too large: %d bytes", attrlen); 1.960 + ABORT(R_FAILED); 1.961 + } 1.962 + 1.963 + if (nr_stun_decode(attrlen, buf, buflen, &offset, (UCHAR*)result)) 1.964 + ABORT(R_FAILED); 1.965 + result[attrlen] = '\0'; /* just to be nice */ 1.966 + 1.967 + if (strlen(result) != attrlen) { 1.968 + /* stund 0.96 sends a final null in the Server attribute, so 1.969 + * only error if the null appears anywhere else in a string */ 1.970 + if (strlen(result) != attrlen-1) { 1.971 + r_log(NR_LOG_STUN, LOG_WARNING, "Error in string: %zd/%d", strlen(result), attrlen); 1.972 + ABORT(R_FAILED); 1.973 + } 1.974 + } 1.975 + 1.976 + _status = 0; 1.977 + abort: 1.978 + return _status; 1.979 +} 1.980 + 1.981 +nr_stun_attr_codec nr_stun_attr_codec_string = { 1.982 + "string", 1.983 + nr_stun_attr_codec_string_print, 1.984 + nr_stun_attr_codec_string_encode, 1.985 + nr_stun_attr_codec_string_decode 1.986 +}; 1.987 + 1.988 +static int 1.989 +nr_stun_attr_codec_unknown_attributes_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.990 +{ 1.991 + nr_stun_attr_unknown_attributes *unknown_attributes = data; 1.992 + char type[9]; 1.993 + char str[64 + (NR_STUN_MAX_UNKNOWN_ATTRIBUTES * sizeof(type))]; 1.994 + int i; 1.995 + 1.996 + snprintf(str, sizeof(str), "%s %s:", msg, attr_info->name); 1.997 + for (i = 0; i < unknown_attributes->num_attributes; ++i) { 1.998 + snprintf(type, sizeof(type), "%s 0x%04x", ((i>0)?",":""), unknown_attributes->attribute[i]); 1.999 + strlcat(str, type, sizeof(str)); 1.1000 + } 1.1001 + 1.1002 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s", str); 1.1003 + return 0; 1.1004 +} 1.1005 + 1.1006 +static int 1.1007 +nr_stun_attr_codec_unknown_attributes_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.1008 +{ 1.1009 + int _status; 1.1010 + int start = offset; 1.1011 + nr_stun_attr_unknown_attributes *unknown_attributes = data; 1.1012 + int length = (2 * unknown_attributes->num_attributes); 1.1013 + int i; 1.1014 + 1.1015 + if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) { 1.1016 + r_log(NR_LOG_STUN, LOG_WARNING, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes); 1.1017 + ABORT(R_FAILED); 1.1018 + } 1.1019 + 1.1020 + if (nr_stun_encode_htons(attr_info->type , buflen, buf, &offset) 1.1021 + || nr_stun_encode_htons(length , buflen, buf, &offset)) 1.1022 + ABORT(R_FAILED); 1.1023 + 1.1024 + for (i = 0; i < unknown_attributes->num_attributes; ++i) { 1.1025 + if (nr_stun_encode_htons(unknown_attributes->attribute[i], buflen, buf, &offset)) 1.1026 + ABORT(R_FAILED); 1.1027 + } 1.1028 + 1.1029 + *attrlen = offset - start; 1.1030 + 1.1031 + _status = 0; 1.1032 + abort: 1.1033 + return _status; 1.1034 +} 1.1035 + 1.1036 +static int 1.1037 +nr_stun_attr_codec_unknown_attributes_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.1038 +{ 1.1039 + int _status; 1.1040 + nr_stun_attr_unknown_attributes *unknown_attributes = data; 1.1041 + int i; 1.1042 + UINT2 *a; 1.1043 + 1.1044 + if ((attrlen % 4) != 0) { 1.1045 + r_log(NR_LOG_STUN, LOG_WARNING, "Attribute is illegal size: %d", attrlen); 1.1046 + ABORT(R_REJECTED); 1.1047 + } 1.1048 + 1.1049 + unknown_attributes->num_attributes = attrlen / 2; 1.1050 + 1.1051 + if (unknown_attributes->num_attributes > NR_STUN_MAX_UNKNOWN_ATTRIBUTES) { 1.1052 + r_log(NR_LOG_STUN, LOG_WARNING, "Too many UNKNOWN-ATTRIBUTES: %d", unknown_attributes->num_attributes); 1.1053 + ABORT(R_REJECTED); 1.1054 + } 1.1055 + 1.1056 + for (i = 0; i < unknown_attributes->num_attributes; ++i) { 1.1057 + a = &(unknown_attributes->attribute[i]); 1.1058 + if (nr_stun_decode_htons(buf, buflen, &offset, a)) 1.1059 + return R_FAILED; 1.1060 + } 1.1061 + 1.1062 + _status = 0; 1.1063 + abort: 1.1064 + return _status; 1.1065 +} 1.1066 + 1.1067 +nr_stun_attr_codec nr_stun_attr_codec_unknown_attributes = { 1.1068 + "unknown_attributes", 1.1069 + nr_stun_attr_codec_unknown_attributes_print, 1.1070 + nr_stun_attr_codec_unknown_attributes_encode, 1.1071 + nr_stun_attr_codec_unknown_attributes_decode 1.1072 +}; 1.1073 + 1.1074 +static int 1.1075 +nr_stun_attr_codec_xor_mapped_address_print(nr_stun_attr_info *attr_info, char *msg, void *data) 1.1076 +{ 1.1077 + nr_stun_attr_xor_mapped_address *xor_mapped_address = data; 1.1078 + r_log(NR_LOG_STUN, LOG_DEBUG, "%s %s: %s (unmasked) %s (masked)", 1.1079 + msg, attr_info->name, 1.1080 + xor_mapped_address->unmasked.as_string, 1.1081 + xor_mapped_address->masked.as_string); 1.1082 + return 0; 1.1083 +} 1.1084 + 1.1085 +static int 1.1086 +nr_stun_attr_codec_xor_mapped_address_encode(nr_stun_attr_info *attr_info, void *data, int offset, int buflen, UCHAR *buf, int *attrlen) 1.1087 +{ 1.1088 + nr_stun_attr_xor_mapped_address *xor_mapped_address = data; 1.1089 + nr_stun_message_header *header = (nr_stun_message_header*)buf; 1.1090 + UINT4 magic_cookie; 1.1091 + 1.1092 + r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string); 1.1093 + 1.1094 + /* this needs to be the magic cookie in the header and not 1.1095 + * the MAGIC_COOKIE constant because if we're talking to 1.1096 + * older servers (that don't have a magic cookie) they use 1.1097 + * message ID for this */ 1.1098 + magic_cookie = ntohl(header->magic_cookie); 1.1099 + 1.1100 + nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked); 1.1101 + 1.1102 + r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string); 1.1103 + 1.1104 + if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen)) 1.1105 + return R_FAILED; 1.1106 + 1.1107 + return 0; 1.1108 +} 1.1109 + 1.1110 +static int 1.1111 +nr_stun_attr_codec_xor_mapped_address_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data) 1.1112 +{ 1.1113 + int r,_status; 1.1114 + nr_stun_attr_xor_mapped_address *xor_mapped_address = data; 1.1115 + nr_stun_message_header *header = (nr_stun_message_header*)buf; 1.1116 + UINT4 magic_cookie; 1.1117 + 1.1118 + if ((r=nr_stun_attr_codec_addr.decode(attr_info, attrlen, buf, offset, buflen, &xor_mapped_address->masked))) 1.1119 + ABORT(r); 1.1120 + 1.1121 + r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string); 1.1122 + 1.1123 + /* this needs to be the magic cookie in the header and not 1.1124 + * the MAGIC_COOKIE constant because if we're talking to 1.1125 + * older servers (that don't have a magic cookie) they use 1.1126 + * message ID for this */ 1.1127 + magic_cookie = ntohl(header->magic_cookie); 1.1128 + 1.1129 + nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked); 1.1130 + 1.1131 + r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string); 1.1132 + 1.1133 + _status = 0; 1.1134 + abort: 1.1135 + return _status; 1.1136 +} 1.1137 + 1.1138 +nr_stun_attr_codec nr_stun_attr_codec_xor_mapped_address = { 1.1139 + "xor_mapped_address", 1.1140 + nr_stun_attr_codec_xor_mapped_address_print, 1.1141 + nr_stun_attr_codec_xor_mapped_address_encode, 1.1142 + nr_stun_attr_codec_xor_mapped_address_decode 1.1143 +}; 1.1144 + 1.1145 +nr_stun_attr_codec nr_stun_attr_codec_old_xor_mapped_address = { 1.1146 + "xor_mapped_address", 1.1147 + nr_stun_attr_codec_xor_mapped_address_print, 1.1148 + 0, /* never encode this type */ 1.1149 + nr_stun_attr_codec_xor_mapped_address_decode 1.1150 +}; 1.1151 + 1.1152 +nr_stun_attr_codec nr_stun_attr_codec_xor_peer_address = { 1.1153 + "xor_peer_address", 1.1154 + nr_stun_attr_codec_xor_mapped_address_print, 1.1155 + nr_stun_attr_codec_xor_mapped_address_encode, 1.1156 + nr_stun_attr_codec_xor_mapped_address_decode 1.1157 +}; 1.1158 + 1.1159 +#define NR_ADD_STUN_ATTRIBUTE(type, name, codec, illegal) \ 1.1160 + { (type), (name), &(codec), illegal }, 1.1161 + 1.1162 +#define NR_ADD_STUN_ATTRIBUTE_IGNORE(type, name) \ 1.1163 + { (type), (name), &nr_stun_attr_codec_noop, 0 }, 1.1164 + 1.1165 + 1.1166 +static nr_stun_attr_info attrs[] = { 1.1167 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ALTERNATE_SERVER, "ALTERNATE-SERVER", nr_stun_attr_codec_addr, 0) 1.1168 +#ifdef USE_STUND_0_96 1.1169 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_CHANGE_REQUEST, "CHANGE-REQUEST", nr_stun_attr_codec_UINT4, 0) 1.1170 +#endif 1.1171 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ERROR_CODE, "ERROR-CODE", nr_stun_attr_codec_error_code, nr_stun_attr_error_code_illegal) 1.1172 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_FINGERPRINT, "FINGERPRINT", nr_stun_attr_codec_fingerprint, 0) 1.1173 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MAPPED_ADDRESS, "MAPPED-ADDRESS", nr_stun_attr_codec_addr, 0) 1.1174 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_MESSAGE_INTEGRITY, "MESSAGE-INTEGRITY", nr_stun_attr_codec_message_integrity, 0) 1.1175 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_NONCE, "NONCE", nr_stun_attr_codec_quoted_string, nr_stun_attr_nonce_illegal) 1.1176 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REALM, "REALM", nr_stun_attr_codec_quoted_string, nr_stun_attr_realm_illegal) 1.1177 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_SERVER, "SERVER", nr_stun_attr_codec_string, nr_stun_attr_server_illegal) 1.1178 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_UNKNOWN_ATTRIBUTES, "UNKNOWN-ATTRIBUTES", nr_stun_attr_codec_unknown_attributes, 0) 1.1179 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USERNAME, "USERNAME", nr_stun_attr_codec_string, nr_stun_attr_username_illegal) 1.1180 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_MAPPED_ADDRESS, "XOR-MAPPED-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0) 1.1181 + 1.1182 +#ifdef USE_ICE 1.1183 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLED, "ICE-CONTROLLED", nr_stun_attr_codec_UINT8, 0) 1.1184 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_ICE_CONTROLLING, "ICE-CONTROLLING", nr_stun_attr_codec_UINT8, 0) 1.1185 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_PRIORITY, "PRIORITY", nr_stun_attr_codec_UINT4, 0) 1.1186 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_USE_CANDIDATE, "USE-CANDIDATE", nr_stun_attr_codec_flag, 0) 1.1187 +#endif 1.1188 + 1.1189 +#ifdef USE_TURN 1.1190 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_DATA, "DATA", nr_stun_attr_codec_data, 0) 1.1191 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_LIFETIME, "LIFETIME", nr_stun_attr_codec_UINT4, 0) 1.1192 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_RELAY_ADDRESS, "XOR-RELAY-ADDRESS", nr_stun_attr_codec_xor_mapped_address, 0) 1.1193 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_XOR_PEER_ADDRESS, "XOR-PEER-ADDRESS", nr_stun_attr_codec_xor_peer_address, 0) 1.1194 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_REQUESTED_TRANSPORT, "REQUESTED-TRANSPORT", nr_stun_attr_codec_UCHAR, 0) 1.1195 +#endif /* USE_TURN */ 1.1196 + 1.1197 + /* for backwards compatibilty */ 1.1198 + NR_ADD_STUN_ATTRIBUTE(NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS, "Old XOR-MAPPED-ADDRESS", nr_stun_attr_codec_old_xor_mapped_address, 0) 1.1199 +#ifdef USE_RFC_3489_BACKWARDS_COMPATIBLE 1.1200 + NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_RESPONSE_ADDRESS, "RESPONSE-ADDRESS") 1.1201 + NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_SOURCE_ADDRESS, "SOURCE-ADDRESS") 1.1202 + NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_CHANGED_ADDRESS, "CHANGED-ADDRESS") 1.1203 + NR_ADD_STUN_ATTRIBUTE_IGNORE(NR_STUN_ATTR_OLD_PASSWORD, "PASSWORD") 1.1204 +#endif /* USE_RFC_3489_BACKWARDS_COMPATIBLE */ 1.1205 +}; 1.1206 + 1.1207 + 1.1208 +int 1.1209 +nr_stun_find_attr_info(UINT2 type, nr_stun_attr_info **info) 1.1210 +{ 1.1211 + int _status; 1.1212 + int i; 1.1213 + 1.1214 + *info = 0; 1.1215 + for (i = 0; i < sizeof(attrs)/sizeof(*attrs); ++i) { 1.1216 + if (type == attrs[i].type) { 1.1217 + *info = &attrs[i]; 1.1218 + break; 1.1219 + } 1.1220 + } 1.1221 + 1.1222 + if (*info == 0) 1.1223 + ABORT(R_NOT_FOUND); 1.1224 + 1.1225 + _status=0; 1.1226 + abort: 1.1227 + return(_status); 1.1228 +} 1.1229 + 1.1230 +int 1.1231 +nr_stun_fix_attribute_ordering(nr_stun_message *msg) 1.1232 +{ 1.1233 + nr_stun_message_attribute *message_integrity; 1.1234 + nr_stun_message_attribute *fingerprint; 1.1235 + 1.1236 + /* 2nd to the last */ 1.1237 + if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_MESSAGE_INTEGRITY, &message_integrity)) { 1.1238 + TAILQ_REMOVE(&msg->attributes, message_integrity, entry); 1.1239 + TAILQ_INSERT_TAIL(&msg->attributes, message_integrity, entry); 1.1240 + } 1.1241 + 1.1242 + /* last */ 1.1243 + if (nr_stun_message_has_attribute(msg, NR_STUN_ATTR_FINGERPRINT, &fingerprint)) { 1.1244 + TAILQ_REMOVE(&msg->attributes, fingerprint, entry); 1.1245 + TAILQ_INSERT_TAIL(&msg->attributes, fingerprint, entry); 1.1246 + } 1.1247 + 1.1248 + return 0; 1.1249 +} 1.1250 + 1.1251 +#ifdef SANITY_CHECKS 1.1252 +static void sanity_check_encoding_stuff(nr_stun_message *msg) 1.1253 +{ 1.1254 + nr_stun_message_attribute *attr = 0; 1.1255 + int padding_bytes; 1.1256 + int l; 1.1257 + 1.1258 + r_log(NR_LOG_STUN, LOG_DEBUG, "Starting to sanity check encoding"); 1.1259 + 1.1260 + l = 0; 1.1261 + TAILQ_FOREACH(attr, &msg->attributes, entry) { 1.1262 + padding_bytes = 0; 1.1263 + if ((attr->length % 4) != 0) { 1.1264 + padding_bytes = 4 - (attr->length % 4); 1.1265 + } 1.1266 + assert(attr->length == (attr->encoding_length - (4 + padding_bytes))); 1.1267 + assert(((void*)attr->encoding) == (msg->buffer + 20 + l)); 1.1268 + l += attr->encoding_length; 1.1269 + assert((l % 4) == 0); 1.1270 + } 1.1271 + assert(l == msg->header.length); 1.1272 +} 1.1273 +#endif /* SANITY_CHECKS */ 1.1274 + 1.1275 + 1.1276 +int 1.1277 +nr_stun_encode_message(nr_stun_message *msg) 1.1278 +{ 1.1279 + int r,_status; 1.1280 + int length_offset; 1.1281 + int length_offset_hold; 1.1282 + nr_stun_attr_info *attr_info; 1.1283 + nr_stun_message_attribute *attr; 1.1284 + int padding_bytes; 1.1285 + 1.1286 + r_log(NR_LOG_STUN, LOG_DEBUG, "Encoding STUN message"); 1.1287 + 1.1288 + nr_stun_fix_attribute_ordering(msg); 1.1289 + 1.1290 + msg->name = nr_stun_msg_type(msg->header.type); 1.1291 + msg->length = 0; 1.1292 + msg->header.length = 0; 1.1293 + 1.1294 + if ((r=nr_stun_encode_htons(msg->header.type, sizeof(msg->buffer), msg->buffer, &msg->length))) 1.1295 + ABORT(r); 1.1296 + if (msg->name) 1.1297 + r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded MsgType: %s", msg->name); 1.1298 + else 1.1299 + r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded MsgType: 0x%03x", msg->header.type); 1.1300 + 1.1301 + /* grab the offset to be used later to re-write the header length field */ 1.1302 + length_offset_hold = msg->length; 1.1303 + 1.1304 + if ((r=nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &msg->length))) 1.1305 + ABORT(r); 1.1306 + 1.1307 + if ((r=nr_stun_encode_htonl(msg->header.magic_cookie, sizeof(msg->buffer), msg->buffer, &msg->length))) 1.1308 + ABORT(r); 1.1309 + r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Cookie: %08x", msg->header.magic_cookie); 1.1310 + 1.1311 + if ((r=nr_stun_encode((UCHAR*)(&msg->header.id), sizeof(msg->header.id), sizeof(msg->buffer), msg->buffer, &msg->length))) 1.1312 + ABORT(r); 1.1313 + r_dump(NR_LOG_STUN, LOG_DEBUG, "Encoded ID", (void*)&msg->header.id, sizeof(msg->header.id)); 1.1314 + 1.1315 + TAILQ_FOREACH(attr, &msg->attributes, entry) { 1.1316 + if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) { 1.1317 + r_log(NR_LOG_STUN, LOG_WARNING, "Unrecognized attribute: 0x%04x", attr->type); 1.1318 + ABORT(R_INTERNAL); 1.1319 + } 1.1320 + 1.1321 + attr_info->name = attr_info->name; 1.1322 + attr->type_name = attr_info->codec->name; 1.1323 + attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[msg->length]; 1.1324 + 1.1325 + if (attr_info->codec->encode != 0) { 1.1326 + if ((r=attr_info->codec->encode(attr_info, &attr->u, msg->length, sizeof(msg->buffer), msg->buffer, &attr->encoding_length))) { 1.1327 + r_log(NR_LOG_STUN, LOG_WARNING, "Unable to encode %s", attr_info->name); 1.1328 + ABORT(r); 1.1329 + } 1.1330 + 1.1331 + msg->length += attr->encoding_length; 1.1332 + attr->length = attr->encoding_length - 4; /* -4 for type and length fields */ 1.1333 + 1.1334 + if (attr_info->illegal) { 1.1335 + if ((r=attr_info->illegal(attr_info, attr->length, &attr->u))) 1.1336 + ABORT(r); 1.1337 + } 1.1338 + 1.1339 + attr_info->codec->print(attr_info, "Encoded", &attr->u); 1.1340 + 1.1341 + if ((attr->length % 4) == 0) { 1.1342 + padding_bytes = 0; 1.1343 + } 1.1344 + else { 1.1345 + padding_bytes = 4 - (attr->length % 4); 1.1346 + nr_stun_encode((UCHAR*)"\0\0\0\0", padding_bytes, sizeof(msg->buffer), msg->buffer, &msg->length); 1.1347 + attr->encoding_length += padding_bytes; 1.1348 + } 1.1349 + 1.1350 + msg->header.length += attr->encoding_length; 1.1351 + length_offset = length_offset_hold; 1.1352 + (void)nr_stun_encode_htons(msg->header.length, sizeof(msg->buffer), msg->buffer, &length_offset); 1.1353 + } 1.1354 + } 1.1355 + 1.1356 + r_log(NR_LOG_STUN, LOG_DEBUG, "Encoded Length: %d", msg->header.length); 1.1357 + 1.1358 + assert(msg->length < NR_STUN_MAX_MESSAGE_SIZE); 1.1359 + 1.1360 +#ifdef SANITY_CHECKS 1.1361 + sanity_check_encoding_stuff(msg); 1.1362 +#endif /* SANITY_CHECKS */ 1.1363 + 1.1364 + _status=0; 1.1365 +abort: 1.1366 + return _status; 1.1367 +} 1.1368 + 1.1369 +int 1.1370 +nr_stun_decode_message(nr_stun_message *msg, int (*get_password)(void *arg, nr_stun_message *msg, Data **password), void *arg) 1.1371 +{ 1.1372 + int r,_status; 1.1373 + int offset; 1.1374 + int size; 1.1375 + int padding_bytes; 1.1376 + nr_stun_message_attribute *attr; 1.1377 + nr_stun_attr_info *attr_info; 1.1378 + Data *password; 1.1379 + 1.1380 + r_log(NR_LOG_STUN, LOG_DEBUG, "Parsing STUN message of %d bytes", msg->length); 1.1381 + 1.1382 + if (!TAILQ_EMPTY(&msg->attributes)) 1.1383 + ABORT(R_BAD_ARGS); 1.1384 + 1.1385 + if (sizeof(nr_stun_message_header) > msg->length) { 1.1386 + r_log(NR_LOG_STUN, LOG_WARNING, "Message too small"); 1.1387 + ABORT(R_FAILED); 1.1388 + } 1.1389 + 1.1390 + memcpy(&msg->header, msg->buffer, sizeof(msg->header)); 1.1391 + msg->header.type = ntohs(msg->header.type); 1.1392 + msg->header.length = ntohs(msg->header.length); 1.1393 + msg->header.magic_cookie = ntohl(msg->header.magic_cookie); 1.1394 + 1.1395 + msg->name = nr_stun_msg_type(msg->header.type); 1.1396 + 1.1397 + if (msg->name) 1.1398 + r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed MsgType: %s", msg->name); 1.1399 + else 1.1400 + r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed MsgType: 0x%03x", msg->header.type); 1.1401 + r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed Length: %d", msg->header.length); 1.1402 + r_log(NR_LOG_STUN, LOG_DEBUG, "Parsed Cookie: %08x", msg->header.magic_cookie); 1.1403 + r_dump(NR_LOG_STUN, LOG_DEBUG, "Parsed ID", (void*)&msg->header.id, sizeof(msg->header.id)); 1.1404 + 1.1405 + if (msg->header.length + sizeof(msg->header) != msg->length) { 1.1406 + r_log(NR_LOG_STUN, LOG_WARNING, "Inconsistent message header length: %d/%d", 1.1407 + msg->header.length, msg->length); 1.1408 + ABORT(R_FAILED); 1.1409 + } 1.1410 + 1.1411 + size = msg->header.length; 1.1412 + 1.1413 + if ((size % 4) != 0) { 1.1414 + r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message size: %d", msg->header.length); 1.1415 + ABORT(R_FAILED); 1.1416 + } 1.1417 + 1.1418 + offset = sizeof(msg->header); 1.1419 + 1.1420 + while (size > 0) { 1.1421 + r_log(NR_LOG_STUN, LOG_DEBUG, "size = %d", size); 1.1422 + 1.1423 + if (size < 4) { 1.1424 + r_log(NR_LOG_STUN, LOG_WARNING, "Illegal message length: %d", size); 1.1425 + ABORT(R_FAILED); 1.1426 + } 1.1427 + 1.1428 + if ((r=nr_stun_message_attribute_create(msg, &attr))) 1.1429 + ABORT(R_NO_MEMORY); 1.1430 + 1.1431 + attr->encoding = (nr_stun_encoded_attribute*)&msg->buffer[offset]; 1.1432 + attr->type = ntohs(attr->encoding->type); 1.1433 + attr->length = ntohs(attr->encoding->length); 1.1434 + attr->encoding_length = attr->length + 4; 1.1435 + 1.1436 + if ((attr->length % 4) != 0) { 1.1437 + padding_bytes = 4 - (attr->length % 4); 1.1438 + attr->encoding_length += padding_bytes; 1.1439 + } 1.1440 + 1.1441 + if ((attr->encoding_length) > size) { 1.1442 + r_log(NR_LOG_STUN, LOG_WARNING, "Attribute length larger than remaining message size: %d/%d", attr->encoding_length, size); 1.1443 + ABORT(R_FAILED); 1.1444 + } 1.1445 + 1.1446 + if ((r=nr_stun_find_attr_info(attr->type, &attr_info))) { 1.1447 + if (attr->type <= 0x7FFF) 1.1448 + ++msg->comprehension_required_unknown_attributes; 1.1449 + else 1.1450 + ++msg->comprehension_optional_unknown_attributes; 1.1451 + r_log(NR_LOG_STUN, LOG_INFO, "Unrecognized attribute: 0x%04x", attr->type); 1.1452 + } 1.1453 + else { 1.1454 + attr_info->name = attr_info->name; 1.1455 + attr->type_name = attr_info->codec->name; 1.1456 + 1.1457 + if (attr->type == NR_STUN_ATTR_MESSAGE_INTEGRITY) { 1.1458 + if (get_password && get_password(arg, msg, &password) == 0) { 1.1459 + if (password->len > sizeof(attr->u.message_integrity.password)) { 1.1460 + r_log(NR_LOG_STUN, LOG_WARNING, "Password too long: %d bytes", password->len); 1.1461 + ABORT(R_FAILED); 1.1462 + } 1.1463 + 1.1464 + memcpy(attr->u.message_integrity.password, password->data, password->len); 1.1465 + attr->u.message_integrity.passwordlen = password->len; 1.1466 + } 1.1467 + else { 1.1468 + /* set to user "not found" */ 1.1469 + attr->u.message_integrity.unknown_user = 1; 1.1470 + } 1.1471 + } 1.1472 + else if (attr->type == NR_STUN_ATTR_OLD_XOR_MAPPED_ADDRESS) { 1.1473 + attr->type = NR_STUN_ATTR_XOR_MAPPED_ADDRESS; 1.1474 + r_log(NR_LOG_STUN, LOG_INFO, "Translating obsolete XOR-MAPPED-ADDRESS type"); 1.1475 + } 1.1476 + 1.1477 + if ((r=attr_info->codec->decode(attr_info, attr->length, msg->buffer, offset+4, msg->length, &attr->u))) { 1.1478 + if (r == SKIP_ATTRIBUTE_DECODE) { 1.1479 + r_log(NR_LOG_STUN, LOG_INFO, "Skipping %s", attr_info->name); 1.1480 + } 1.1481 + else { 1.1482 + r_log(NR_LOG_STUN, LOG_WARNING, "Unable to parse %s", attr_info->name); 1.1483 + } 1.1484 + 1.1485 + attr->invalid = 1; 1.1486 + } 1.1487 + else { 1.1488 + attr_info->codec->print(attr_info, "Parsed", &attr->u); 1.1489 + 1.1490 +#ifdef USE_STUN_PEDANTIC 1.1491 + r_log(NR_LOG_STUN, LOG_DEBUG, "Before pedantic attr_info checks"); 1.1492 + if (attr_info->illegal) { 1.1493 + if ((r=attr_info->illegal(attr_info, attr->length, &attr->u))) { 1.1494 + r_log(NR_LOG_STUN, LOG_WARNING, "Failed pedantic attr_info checks"); 1.1495 + ABORT(r); 1.1496 + } 1.1497 + } 1.1498 + r_log(NR_LOG_STUN, LOG_DEBUG, "After pedantic attr_info checks"); 1.1499 +#endif /* USE_STUN_PEDANTIC */ 1.1500 + } 1.1501 + } 1.1502 + 1.1503 + offset += attr->encoding_length; 1.1504 + size -= attr->encoding_length; 1.1505 + } 1.1506 + 1.1507 +#ifdef SANITY_CHECKS 1.1508 + sanity_check_encoding_stuff(msg); 1.1509 +#endif /* SANITY_CHECKS */ 1.1510 + 1.1511 + _status=0; 1.1512 + abort: 1.1513 + return _status; 1.1514 +} 1.1515 +