LCOV - code coverage report
Current view: top level - media/mtransport/third_party/nICEr/src/stun - stun_codec.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 630 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 60 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13