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

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial