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

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial