michael@0: /* michael@0: Copyright (c) 2007, Adobe Systems, Incorporated michael@0: All rights reserved. michael@0: michael@0: Redistribution and use in source and binary forms, with or without michael@0: modification, are permitted provided that the following conditions are michael@0: met: michael@0: michael@0: * Redistributions of source code must retain the above copyright michael@0: notice, this list of conditions and the following disclaimer. michael@0: michael@0: * Redistributions in binary form must reproduce the above copyright michael@0: notice, this list of conditions and the following disclaimer in the michael@0: documentation and/or other materials provided with the distribution. michael@0: michael@0: * Neither the name of Adobe Systems, Network Resonance nor the names of its michael@0: contributors may be used to endorse or promote products derived from michael@0: this software without specific prior written permission. michael@0: michael@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: michael@0: static char *RCSSTRING __UNUSED__="$Id: stun_util.c,v 1.2 2008/04/28 18:21:30 ekr Exp $"; michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #else /* UNIX */ michael@0: #include michael@0: #endif /* end UNIX */ michael@0: #include michael@0: michael@0: #include "stun.h" michael@0: #include "stun_reg.h" michael@0: #include "registry.h" michael@0: #include "addrs.h" michael@0: #include "transport_addr_reg.h" michael@0: #include "nr_crypto.h" michael@0: #include "hex.h" michael@0: michael@0: michael@0: int NR_LOG_STUN = 0; michael@0: michael@0: int michael@0: nr_stun_startup(void) michael@0: { michael@0: int r,_status; michael@0: michael@0: if ((r=r_log_register("stun", &NR_LOG_STUN))) michael@0: ABORT(r); michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to) michael@0: { michael@0: int _status; michael@0: michael@0: switch (from->ip_version) { michael@0: case NR_IPV4: michael@0: nr_ip4_port_to_transport_addr( michael@0: (ntohl(from->u.addr4.sin_addr.s_addr) ^ magicCookie), michael@0: (ntohs(from->u.addr4.sin_port) ^ (magicCookie>>16)), michael@0: from->protocol, to); michael@0: break; michael@0: case NR_IPV6: michael@0: assert(0); michael@0: ABORT(R_INTERNAL); michael@0: break; michael@0: default: michael@0: assert(0); michael@0: ABORT(R_INTERNAL); michael@0: break; michael@0: } michael@0: michael@0: _status = 0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count) michael@0: { michael@0: int r,_status; michael@0: NR_registry *children = 0; michael@0: michael@0: if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count))) michael@0: if (r == R_NOT_FOUND) michael@0: *count = 0; michael@0: else michael@0: ABORT(r); michael@0: michael@0: if (*count == 0) { michael@0: if ((r=nr_stun_get_addrs(addrs, maxaddrs, 1, count))) michael@0: ABORT(r); michael@0: michael@0: goto done; michael@0: } michael@0: michael@0: if (*count >= maxaddrs) { michael@0: r_log(NR_LOG_STUN, LOG_INFO, "Address list truncated from %d to %d", *count, maxaddrs); michael@0: *count = maxaddrs; michael@0: } michael@0: michael@0: #if 0 michael@0: if (*count > 0) { michael@0: /* TODO(ekr@rtfm.com): Commented out 2012-07-26. michael@0: michael@0: This code is currently not used in Firefox and needs to be michael@0: ported to 64-bit */ michael@0: children = RCALLOC((*count + 10) * sizeof(*children)); michael@0: if (!children) michael@0: ABORT(R_NO_MEMORY); michael@0: michael@0: assert(sizeof(size_t) == sizeof(*count)); michael@0: michael@0: if ((r=NR_reg_get_children(NR_STUN_REG_PREF_ADDRESS_PRFX, children, (size_t)(*count + 10), (size_t*)count))) michael@0: ABORT(r); michael@0: michael@0: for (i = 0; i < *count; ++i) { michael@0: if ((r=nr_reg_get_transport_addr(children[i], 0, &addrs[i].addr))) michael@0: ABORT(r); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: done: michael@0: michael@0: _status=0; michael@0: abort: michael@0: RFREE(children); michael@0: return _status; michael@0: } michael@0: michael@0: int michael@0: nr_stun_different_transaction(UCHAR *msg, int len, nr_stun_message *req) michael@0: { michael@0: int _status; michael@0: nr_stun_message_header header; michael@0: char reqid[44]; michael@0: char msgid[44]; michael@0: int len2; michael@0: michael@0: if (sizeof(header) > len) michael@0: ABORT(R_FAILED); michael@0: michael@0: assert(sizeof(header.id) == sizeof(UINT12)); michael@0: michael@0: memcpy(&header, msg, sizeof(header)); michael@0: michael@0: if (memcmp(&req->header.id, &header.id, sizeof(header.id))) { michael@0: nr_nbin2hex((UCHAR*)&req->header.id, sizeof(req->header.id), reqid, sizeof(reqid), &len2); michael@0: nr_nbin2hex((UCHAR*)&header.id, sizeof(header.id), msgid, sizeof(msgid), &len2); michael@0: r_log(NR_LOG_STUN, LOG_DEBUG, "Mismatched message IDs %s/%s", reqid, msgid); michael@0: ABORT(R_NOT_FOUND); michael@0: } michael@0: michael@0: _status=0; michael@0: abort: michael@0: return _status; michael@0: } michael@0: michael@0: char* michael@0: nr_stun_msg_type(int type) michael@0: { michael@0: char *ret = 0; michael@0: michael@0: switch (type) { michael@0: case NR_STUN_MSG_BINDING_REQUEST: michael@0: ret = "BINDING-REQUEST"; michael@0: break; michael@0: case NR_STUN_MSG_BINDING_INDICATION: michael@0: ret = "BINDING-INDICATION"; michael@0: break; michael@0: case NR_STUN_MSG_BINDING_RESPONSE: michael@0: ret = "BINDING-RESPONSE"; michael@0: break; michael@0: case NR_STUN_MSG_BINDING_ERROR_RESPONSE: michael@0: ret = "BINDING-ERROR-RESPONSE"; michael@0: break; michael@0: michael@0: #ifdef USE_TURN michael@0: case NR_STUN_MSG_ALLOCATE_REQUEST: michael@0: ret = "ALLOCATE-REQUEST"; michael@0: break; michael@0: case NR_STUN_MSG_ALLOCATE_RESPONSE: michael@0: ret = "ALLOCATE-RESPONSE"; michael@0: break; michael@0: case NR_STUN_MSG_ALLOCATE_ERROR_RESPONSE: michael@0: ret = "ALLOCATE-ERROR-RESPONSE"; michael@0: break; michael@0: case NR_STUN_MSG_REFRESH_REQUEST: michael@0: ret = "REFRESH-REQUEST"; michael@0: break; michael@0: case NR_STUN_MSG_REFRESH_RESPONSE: michael@0: ret = "REFRESH-RESPONSE"; michael@0: break; michael@0: case NR_STUN_MSG_REFRESH_ERROR_RESPONSE: michael@0: ret = "REFRESH-ERROR-RESPONSE"; michael@0: break; michael@0: case NR_STUN_MSG_SEND_INDICATION: michael@0: ret = "SEND-INDICATION"; michael@0: break; michael@0: case NR_STUN_MSG_DATA_INDICATION: michael@0: ret = "DATA-INDICATION"; michael@0: break; michael@0: case NR_STUN_MSG_PERMISSION_REQUEST: michael@0: ret = "PERMISSION-REQUEST"; michael@0: break; michael@0: case NR_STUN_MSG_PERMISSION_RESPONSE: michael@0: ret = "PERMISSION-RESPONSE"; michael@0: break; michael@0: case NR_STUN_MSG_PERMISSION_ERROR_RESPONSE: michael@0: ret = "PERMISSION-ERROR-RESPONSE"; michael@0: break; michael@0: #endif /* USE_TURN */ michael@0: michael@0: default: michael@0: /* ret remains 0 */ michael@0: break; michael@0: } michael@0: michael@0: return ret; michael@0: } michael@0: michael@0: int michael@0: nr_random_alphanum(char *alphanum, int size) michael@0: { michael@0: static char alphanums[256] = { michael@0: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', michael@0: 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', michael@0: 'U', 'V', 'W', 'X', 'Y', 'Z', michael@0: 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', michael@0: 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', michael@0: 'u', 'v', 'w', 'x', 'y', 'z', michael@0: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', michael@0: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', michael@0: 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', michael@0: 'U', 'V', 'W', 'X', 'Y', 'Z', michael@0: 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', michael@0: 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', michael@0: 'u', 'v', 'w', 'x', 'y', 'z', michael@0: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', michael@0: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', michael@0: 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', michael@0: 'U', 'V', 'W', 'X', 'Y', 'Z', michael@0: 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', michael@0: 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', michael@0: 'u', 'v', 'w', 'x', 'y', 'z', michael@0: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', michael@0: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', michael@0: 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', michael@0: 'U', 'V', 'W', 'X', 'Y', 'Z', michael@0: 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', michael@0: 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', michael@0: 'u', 'v', 'w', 'x', 'y', 'z', michael@0: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', michael@0: 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' }; michael@0: int i; michael@0: michael@0: nr_crypto_random_bytes((UCHAR*)alphanum, size); michael@0: michael@0: /* now convert from binary to alphanumeric */ michael@0: for (i = 0; i < size; ++i) michael@0: alphanum[i] = alphanums[(UCHAR)alphanum[i]]; michael@0: michael@0: return 0; michael@0: }