2006-04-04 16:08:30 +00:00
|
|
|
/*
|
|
|
|
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
2009-02-13 23:37:37 +00:00
|
|
|
* Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
|
2006-04-04 16:08:30 +00:00
|
|
|
*
|
|
|
|
* Version: MPL 1.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
2009-02-04 21:20:54 +00:00
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
2006-04-04 16:08:30 +00:00
|
|
|
* Portions created by the Initial Developer are Copyright (C)
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
2009-02-04 21:20:54 +00:00
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
2006-08-22 14:48:35 +00:00
|
|
|
* Fanzhou Zhao <fanzhou@gmail.com> 2006-08-22 (Bugfix 2357-2358)
|
2006-04-04 16:08:30 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* switch_stun.c STUN (Simple Traversal of UDP over NAT)
|
|
|
|
*
|
|
|
|
*/
|
2008-01-27 17:42:51 +00:00
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
#include <switch.h>
|
2007-06-20 09:02:30 +00:00
|
|
|
#include <switch_stun.h>
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
struct value_mapping {
|
|
|
|
const uint32_t value;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct value_mapping PACKET_TYPES[] = {
|
2007-03-29 22:31:56 +00:00
|
|
|
{SWITCH_STUN_BINDING_REQUEST, "BINDING_REQUEST"},
|
|
|
|
{SWITCH_STUN_BINDING_RESPONSE, "BINDING_RESPONSE"},
|
|
|
|
{SWITCH_STUN_BINDING_ERROR_RESPONSE, "BINDING_ERROR_RESPONSE"},
|
|
|
|
{SWITCH_STUN_SHARED_SECRET_REQUEST, "SHARED_SECRET_REQUEST"},
|
|
|
|
{SWITCH_STUN_SHARED_SECRET_RESPONSE, "SHARED_SECRET_RESPONSE"},
|
|
|
|
{SWITCH_STUN_SHARED_SECRET_ERROR_RESPONSE, "SHARED_SECRET_ERROR_RESPONSE"},
|
|
|
|
{SWITCH_STUN_ALLOCATE_REQUEST, "ALLOCATE_REQUEST"},
|
|
|
|
{SWITCH_STUN_ALLOCATE_RESPONSE, "ALLOCATE_RESPONSE"},
|
|
|
|
{SWITCH_STUN_ALLOCATE_ERROR_RESPONSE, "ALLOCATE_ERROR_RESPONSE"},
|
|
|
|
{SWITCH_STUN_SEND_REQUEST, "SEND_REQUEST"},
|
|
|
|
{SWITCH_STUN_SEND_RESPONSE, "SEND_RESPONSE"},
|
|
|
|
{SWITCH_STUN_SEND_ERROR_RESPONSE, "SEND_ERROR_RESPONSE"},
|
|
|
|
{SWITCH_STUN_DATA_INDICATION, "DATA_INDICATION"},
|
|
|
|
{0, 0}
|
|
|
|
};
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
static const struct value_mapping ATTR_TYPES[] = {
|
2007-03-29 22:31:56 +00:00
|
|
|
{SWITCH_STUN_ATTR_MAPPED_ADDRESS, "MAPPED_ADDRESS"},
|
|
|
|
{SWITCH_STUN_ATTR_RESPONSE_ADDRESS, "RESPONSE_ADDRESS"},
|
|
|
|
{SWITCH_STUN_ATTR_CHANGE_REQUEST, "CHANGE_REQUEST"},
|
|
|
|
{SWITCH_STUN_ATTR_SOURCE_ADDRESS, "SOURCE_ADDRESS"},
|
|
|
|
{SWITCH_STUN_ATTR_CHANGED_ADDRESS, "CHANGED_ADDRESS"},
|
|
|
|
{SWITCH_STUN_ATTR_USERNAME, "USERNAME"},
|
|
|
|
{SWITCH_STUN_ATTR_PASSWORD, "PASSWORD"},
|
|
|
|
{SWITCH_STUN_ATTR_MESSAGE_INTEGRITY, "MESSAGE_INTEGRITY"},
|
|
|
|
{SWITCH_STUN_ATTR_ERROR_CODE, "ERROR_CODE"},
|
|
|
|
{SWITCH_STUN_ATTR_UNKNOWN_ATTRIBUTES, "UNKNOWN_ATTRIBUTES"},
|
|
|
|
{SWITCH_STUN_ATTR_REFLECTED_FROM, "REFLECTED_FROM"},
|
|
|
|
{SWITCH_STUN_ATTR_TRANSPORT_PREFERENCES, "TRANSPORT_PREFERENCES"},
|
|
|
|
{SWITCH_STUN_ATTR_LIFETIME, "LIFETIME"},
|
|
|
|
{SWITCH_STUN_ATTR_ALTERNATE_SERVER, "ALTERNATE_SERVER"},
|
|
|
|
{SWITCH_STUN_ATTR_MAGIC_COOKIE, "MAGIC_COOKIE"},
|
|
|
|
{SWITCH_STUN_ATTR_BANDWIDTH, "BANDWIDTH"},
|
|
|
|
{SWITCH_STUN_ATTR_DESTINATION_ADDRESS, "DESTINATION_ADDRESS"},
|
|
|
|
{SWITCH_STUN_ATTR_SOURCE_ADDRESS2, "SOURCE_ADDRESS2"},
|
|
|
|
{SWITCH_STUN_ATTR_DATA, "DATA"},
|
|
|
|
{SWITCH_STUN_ATTR_OPTIONS, "OPTIONS"},
|
|
|
|
{0, 0}
|
|
|
|
};
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
static const struct value_mapping ERROR_TYPES[] = {
|
2007-03-29 22:31:56 +00:00
|
|
|
{SWITCH_STUN_ERROR_BAD_REQUEST, "BAD_REQUEST"},
|
|
|
|
{SWITCH_STUN_ERROR_UNAUTHORIZED, "UNAUTHORIZED"},
|
|
|
|
{SWITCH_STUN_ERROR_UNKNOWN_ATTRIBUTE, "UNKNOWN_ATTRIBUTE"},
|
|
|
|
{SWITCH_STUN_ERROR_STALE_CREDENTIALS, "STALE_CREDENTIALS"},
|
|
|
|
{SWITCH_STUN_ERROR_INTEGRITY_CHECK_FAILURE, "INTEGRITY_CHECK_FAILURE"},
|
|
|
|
{SWITCH_STUN_ERROR_MISSING_USERNAME, "MISSING_USERNAME"},
|
|
|
|
{SWITCH_STUN_ERROR_USE_TLS, "USE_TLS"},
|
|
|
|
{SWITCH_STUN_ERROR_SERVER_ERROR, "SERVER_ERROR"},
|
|
|
|
{SWITCH_STUN_ERROR_GLOBAL_FAILURE, "GLOBAL_FAILURE"},
|
|
|
|
{0, 0}
|
|
|
|
};
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
SWITCH_DECLARE(void) switch_stun_random_string(char *buf, uint16_t len, char *set)
|
|
|
|
{
|
|
|
|
char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
|
|
int max;
|
2006-08-22 14:48:35 +00:00
|
|
|
uint16_t x;
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
if (!set) {
|
|
|
|
set = chars;
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
max = (int) strlen(set);
|
2006-04-05 21:38:31 +00:00
|
|
|
|
2009-01-25 21:23:07 +00:00
|
|
|
srand((unsigned int) switch_micro_time_now());
|
2006-04-05 21:38:31 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
for (x = 0; x < len; x++) {
|
|
|
|
int j = (int) (max * 1.0 * rand() / (RAND_MAX + 1.0));
|
2006-04-04 16:08:30 +00:00
|
|
|
buf[x] = set[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-13 00:17:58 +00:00
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_stun_packet_t *) switch_stun_packet_parse(uint8_t *buf, uint32_t len)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
switch_stun_packet_t *packet;
|
|
|
|
switch_stun_packet_attribute_t *attr;
|
2008-05-13 06:23:47 +00:00
|
|
|
uint32_t bytes_left = len;
|
2008-05-10 21:10:44 +00:00
|
|
|
void *end_buf = buf + len;
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
if (len < SWITCH_STUN_PACKET_MIN_LEN) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
packet = (switch_stun_packet_t *) buf;
|
|
|
|
packet->header.type = ntohs(packet->header.type);
|
|
|
|
packet->header.length = ntohs(packet->header.length);
|
2008-05-13 00:17:58 +00:00
|
|
|
bytes_left -= packet->header.length + 20;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check packet type (RFC3489(bis?) values)
|
|
|
|
*/
|
2008-05-27 04:30:03 +00:00
|
|
|
switch (packet->header.type) {
|
2008-05-13 00:17:58 +00:00
|
|
|
case SWITCH_STUN_BINDING_REQUEST:
|
|
|
|
case SWITCH_STUN_BINDING_RESPONSE:
|
|
|
|
case SWITCH_STUN_BINDING_ERROR_RESPONSE:
|
|
|
|
case SWITCH_STUN_SHARED_SECRET_REQUEST:
|
|
|
|
case SWITCH_STUN_SHARED_SECRET_RESPONSE:
|
|
|
|
case SWITCH_STUN_SHARED_SECRET_ERROR_RESPONSE:
|
|
|
|
case SWITCH_STUN_ALLOCATE_REQUEST:
|
|
|
|
case SWITCH_STUN_ALLOCATE_RESPONSE:
|
|
|
|
case SWITCH_STUN_ALLOCATE_ERROR_RESPONSE:
|
|
|
|
case SWITCH_STUN_SEND_REQUEST:
|
|
|
|
case SWITCH_STUN_SEND_RESPONSE:
|
|
|
|
case SWITCH_STUN_SEND_ERROR_RESPONSE:
|
|
|
|
case SWITCH_STUN_DATA_INDICATION:
|
|
|
|
/* Valid */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Invalid value */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for length overflow
|
|
|
|
*/
|
|
|
|
if (bytes_left <= 0) {
|
|
|
|
/* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No payload?
|
|
|
|
*/
|
|
|
|
if (packet->header.length == 0) {
|
|
|
|
/* Invalid?! */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if we have enough bytes left for an attribute */
|
|
|
|
if (bytes_left < SWITCH_STUN_ATTRIBUTE_MIN_LEN) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
switch_stun_packet_first_attribute(packet, attr);
|
|
|
|
do {
|
|
|
|
attr->length = ntohs(attr->length);
|
|
|
|
attr->type = ntohs(attr->type);
|
2008-05-27 04:30:03 +00:00
|
|
|
bytes_left -= 4; /* attribute header consumed */
|
2008-05-13 00:17:58 +00:00
|
|
|
|
|
|
|
if (!attr->length || switch_stun_attribute_padded_length(attr) > bytes_left) {
|
|
|
|
/*
|
|
|
|
* Note we simply don't "break" here out of the loop anymore because
|
|
|
|
* we don't want the upper layers to have to deal with attributes without a value
|
|
|
|
* (or worse: invalid length)
|
|
|
|
*/
|
|
|
|
return NULL;
|
2006-04-04 16:08:30 +00:00
|
|
|
}
|
2008-05-13 00:17:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle STUN attributes
|
|
|
|
*/
|
2007-03-29 22:31:56 +00:00
|
|
|
switch (attr->type) {
|
2008-05-27 04:30:03 +00:00
|
|
|
case SWITCH_STUN_ATTR_MAPPED_ADDRESS: /* Address, we only care about this one, but parse the others too */
|
2008-05-13 00:17:58 +00:00
|
|
|
case SWITCH_STUN_ATTR_RESPONSE_ADDRESS:
|
|
|
|
case SWITCH_STUN_ATTR_SOURCE_ADDRESS:
|
|
|
|
case SWITCH_STUN_ATTR_CHANGED_ADDRESS:
|
|
|
|
case SWITCH_STUN_ATTR_REFLECTED_FROM:
|
|
|
|
case SWITCH_STUN_ATTR_ALTERNATE_SERVER:
|
|
|
|
case SWITCH_STUN_ATTR_DESTINATION_ADDRESS:
|
|
|
|
case SWITCH_STUN_ATTR_SOURCE_ADDRESS2:
|
|
|
|
{
|
2006-04-04 16:08:30 +00:00
|
|
|
switch_stun_ip_t *ip;
|
2008-05-13 00:17:58 +00:00
|
|
|
uint32_t addr_length = 0;
|
2006-04-04 16:08:30 +00:00
|
|
|
ip = (switch_stun_ip_t *) attr->value;
|
2008-05-13 00:17:58 +00:00
|
|
|
|
|
|
|
switch (ip->family) {
|
|
|
|
case 0x01: /* IPv4 */
|
|
|
|
addr_length = 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x02: /* IPv6 */
|
|
|
|
addr_length = 16;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: /* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* attribute payload length must be == address length + size of other payload fields (family...) */
|
|
|
|
if (attr->length != addr_length + 4) {
|
|
|
|
/* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
ip->port = ntohs(ip->port);
|
|
|
|
}
|
|
|
|
break;
|
2008-05-13 00:17:58 +00:00
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
case SWITCH_STUN_ATTR_CHANGE_REQUEST: /* UInt32 */
|
2008-05-13 00:17:58 +00:00
|
|
|
case SWITCH_STUN_ATTR_LIFETIME:
|
|
|
|
case SWITCH_STUN_ATTR_BANDWIDTH:
|
|
|
|
case SWITCH_STUN_ATTR_OPTIONS:
|
|
|
|
{
|
|
|
|
uint32_t *val = (uint32_t *) attr->value;
|
|
|
|
|
|
|
|
if (attr->length != sizeof(uint32_t)) {
|
|
|
|
/* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*val = ntohl(*val); /* should we do this here? */
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
case SWITCH_STUN_ATTR_USERNAME: /* ByteString, multiple of 4 bytes */
|
|
|
|
case SWITCH_STUN_ATTR_PASSWORD: /* ByteString, multiple of 4 bytes */
|
2008-05-13 00:17:58 +00:00
|
|
|
if (attr->length % 4 != 0) {
|
|
|
|
/* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
case SWITCH_STUN_ATTR_DATA: /* ByteString */
|
|
|
|
case SWITCH_STUN_ATTR_ERROR_CODE: /* ErrorCode */
|
2008-05-13 00:17:58 +00:00
|
|
|
case SWITCH_STUN_ATTR_TRANSPORT_PREFERENCES: /* TransportPrefs */
|
|
|
|
/*
|
|
|
|
* No length checking here, since we already checked against the padded length
|
|
|
|
* before
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SWITCH_STUN_ATTR_MESSAGE_INTEGRITY: /* ByteString, 20 bytes */
|
|
|
|
if (attr->length != 20) {
|
|
|
|
/* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
case SWITCH_STUN_ATTR_MAGIC_COOKIE: /* ByteString, 4 bytes */
|
2008-05-13 00:17:58 +00:00
|
|
|
if (attr->length != 4) {
|
|
|
|
/* Invalid */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SWITCH_STUN_ATTR_UNKNOWN_ATTRIBUTES: /* UInt16List (= multiple of 2 bytes) */
|
|
|
|
if (attr->length % 2 != 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Mandatory attribute range? => invalid */
|
|
|
|
if (attr->type <= 0x7FFF) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
2006-04-04 16:08:30 +00:00
|
|
|
}
|
2008-05-13 00:17:58 +00:00
|
|
|
bytes_left -= switch_stun_attribute_padded_length(attr); /* attribute value consumed, substract padded length */
|
|
|
|
|
|
|
|
} while (bytes_left >= SWITCH_STUN_ATTRIBUTE_MIN_LEN && switch_stun_packet_next_attribute(attr, end_buf));
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
if ((uint32_t) (packet->header.length + 20) > (uint32_t) (len - bytes_left)) {
|
2008-05-13 00:17:58 +00:00
|
|
|
/*
|
|
|
|
* the packet length is longer than the length of all attributes?
|
|
|
|
* for now simply decrease the packet size
|
|
|
|
*/
|
2008-05-27 04:30:03 +00:00
|
|
|
packet->header.length = (uint16_t) ((len - bytes_left) - 20);
|
2008-05-13 00:17:58 +00:00
|
|
|
}
|
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
return packet;
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
SWITCH_DECLARE(const char *) switch_stun_value_to_name(int32_t type, uint32_t value)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
uint32_t x = 0;
|
|
|
|
const struct value_mapping *map = NULL;
|
|
|
|
switch (type) {
|
|
|
|
case SWITCH_STUN_TYPE_PACKET_TYPE:
|
|
|
|
map = PACKET_TYPES;
|
|
|
|
break;
|
|
|
|
case SWITCH_STUN_TYPE_ATTRIBUTE:
|
|
|
|
map = ATTR_TYPES;
|
|
|
|
break;
|
|
|
|
case SWITCH_STUN_TYPE_ERROR:
|
|
|
|
map = ERROR_TYPES;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
map = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (map) {
|
2007-03-29 22:31:56 +00:00
|
|
|
for (x = 0; map[x].value; x++) {
|
2006-04-04 16:08:30 +00:00
|
|
|
if (map[x].value == value) {
|
|
|
|
return map[x].name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
return "INVALID";
|
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_mapped_address(switch_stun_packet_attribute_t *attribute, char *ipstr, uint16_t *port)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
switch_stun_ip_t *ip;
|
|
|
|
uint8_t x, *i;
|
|
|
|
char *p = ipstr;
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
ip = (switch_stun_ip_t *) attribute->value;
|
2008-05-27 04:30:03 +00:00
|
|
|
i = (uint8_t *) &ip->address;
|
2006-04-04 16:08:30 +00:00
|
|
|
*ipstr = 0;
|
2007-03-29 22:31:56 +00:00
|
|
|
for (x = 0; x < 4; x++) {
|
2006-04-04 16:08:30 +00:00
|
|
|
sprintf(p, "%u%s", i[x], x == 3 ? "" : ".");
|
|
|
|
p = ipstr + strlen(ipstr);
|
|
|
|
}
|
|
|
|
*port = ip->port;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-03-30 00:13:31 +00:00
|
|
|
SWITCH_DECLARE(char *) switch_stun_packet_attribute_get_username(switch_stun_packet_attribute_t *attribute, char *username, uint16_t len)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
uint16_t cpylen;
|
|
|
|
|
2008-01-24 16:01:25 +00:00
|
|
|
cpylen = attribute->length < len ? attribute->length : len;
|
2006-04-04 16:08:30 +00:00
|
|
|
return memcpy(username, attribute->value, cpylen);
|
|
|
|
}
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
SWITCH_DECLARE(switch_stun_packet_t *) switch_stun_packet_build_header(switch_stun_message_t type, char *id, uint8_t *buf)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
switch_stun_packet_header_t *header;
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
header = (switch_stun_packet_header_t *) buf;
|
|
|
|
header->type = htons(type);
|
|
|
|
header->length = 0;
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-04 16:08:30 +00:00
|
|
|
if (id) {
|
|
|
|
memcpy(header->id, id, 16);
|
|
|
|
} else {
|
|
|
|
switch_stun_random_string(header->id, 16, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (switch_stun_packet_t *) buf;
|
|
|
|
}
|
|
|
|
|
2007-03-30 00:13:31 +00:00
|
|
|
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_binded_address(switch_stun_packet_t *packet, char *ipstr, uint16_t port)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
switch_stun_packet_attribute_t *attribute;
|
|
|
|
switch_stun_ip_t *ip;
|
|
|
|
uint8_t *i, x;
|
|
|
|
char *p = ipstr;
|
|
|
|
|
2008-05-27 04:30:03 +00:00
|
|
|
attribute = (switch_stun_packet_attribute_t *) ((uint8_t *) &packet->first_attribute + ntohs(packet->header.length));
|
2006-04-04 16:08:30 +00:00
|
|
|
attribute->type = htons(SWITCH_STUN_ATTR_MAPPED_ADDRESS);
|
|
|
|
attribute->length = htons(8);
|
|
|
|
ip = (switch_stun_ip_t *) attribute->value;
|
|
|
|
|
|
|
|
ip->port = htons(port);
|
|
|
|
ip->family = 1;
|
2008-05-27 04:30:03 +00:00
|
|
|
i = (uint8_t *) &ip->address;
|
2006-04-04 16:08:30 +00:00
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
for (x = 0; x < 4; x++) {
|
|
|
|
i[x] = (uint8_t) atoi(p);
|
2006-04-04 16:08:30 +00:00
|
|
|
if ((p = strchr(p, '.'))) {
|
|
|
|
p++;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
packet->header.length += htons(sizeof(switch_stun_packet_attribute_t)) + attribute->length;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-03-30 00:13:31 +00:00
|
|
|
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_username(switch_stun_packet_t *packet, char *username, uint16_t ulen)
|
2006-04-04 16:08:30 +00:00
|
|
|
{
|
|
|
|
switch_stun_packet_attribute_t *attribute;
|
|
|
|
|
|
|
|
if (ulen % 4 != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2008-05-27 04:30:03 +00:00
|
|
|
attribute = (switch_stun_packet_attribute_t *) ((uint8_t *) &packet->first_attribute + ntohs(packet->header.length));
|
2006-04-04 16:08:30 +00:00
|
|
|
attribute->type = htons(SWITCH_STUN_ATTR_USERNAME);
|
|
|
|
attribute->length = htons(ulen);
|
|
|
|
if (username) {
|
|
|
|
memcpy(attribute->value, username, ulen);
|
|
|
|
} else {
|
|
|
|
switch_stun_random_string(attribute->value, ulen, NULL);
|
2007-03-29 22:31:56 +00:00
|
|
|
}
|
2006-04-04 16:08:30 +00:00
|
|
|
|
|
|
|
packet->header.length += htons(sizeof(switch_stun_packet_attribute_t)) + attribute->length;
|
|
|
|
return 1;
|
|
|
|
}
|
2006-04-05 20:17:22 +00:00
|
|
|
|
2008-11-27 02:30:11 +00:00
|
|
|
SWITCH_DECLARE(char *) switch_stun_host_lookup(const char *host, switch_memory_pool_t *pool)
|
|
|
|
{
|
|
|
|
switch_sockaddr_t *addr = NULL;
|
|
|
|
char buf[30];
|
|
|
|
|
|
|
|
switch_sockaddr_info_get(&addr, host, SWITCH_UNSPEC, 0, 0, pool);
|
|
|
|
return switch_core_strdup(pool, switch_str_nil(switch_get_addr(buf, sizeof(buf), addr)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
SWITCH_DECLARE(switch_status_t) switch_stun_lookup(char **ip,
|
2007-03-30 00:15:25 +00:00
|
|
|
switch_port_t *port, char *stunip, switch_port_t stunport, char **err, switch_memory_pool_t *pool)
|
2006-04-05 20:17:22 +00:00
|
|
|
{
|
|
|
|
switch_sockaddr_t *local_addr = NULL, *remote_addr = NULL, *from_addr = NULL;
|
|
|
|
switch_socket_t *sock = NULL;
|
2008-07-18 16:18:31 +00:00
|
|
|
uint8_t buf[260] = { 0 };
|
|
|
|
uint8_t *start = buf;
|
2008-05-10 21:10:44 +00:00
|
|
|
void *end_buf;
|
2006-04-05 20:17:22 +00:00
|
|
|
switch_stun_packet_t *packet;
|
|
|
|
switch_stun_packet_attribute_t *attr;
|
|
|
|
switch_size_t bytes = 0;
|
2007-03-29 22:31:56 +00:00
|
|
|
char username[33] = { 0 };
|
2007-12-22 01:00:10 +00:00
|
|
|
char rip[16] = { 0 };
|
2006-04-05 20:17:22 +00:00
|
|
|
uint16_t rport = 0;
|
|
|
|
switch_time_t started = 0;
|
|
|
|
unsigned int elapsed = 0;
|
2008-07-18 16:18:31 +00:00
|
|
|
int funny = 0;
|
|
|
|
int size = sizeof(buf);
|
|
|
|
|
|
|
|
switch_assert(err);
|
|
|
|
|
|
|
|
if (!strcmp(*err, "funny")) {
|
|
|
|
funny = 1;
|
|
|
|
}
|
2006-04-05 20:17:22 +00:00
|
|
|
|
|
|
|
*err = "Success";
|
|
|
|
|
|
|
|
switch_sockaddr_info_get(&from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
|
|
|
|
|
|
|
|
if (switch_sockaddr_info_get(&local_addr, *ip, SWITCH_UNSPEC, *port, 0, pool) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
*err = "Local Address Error!";
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switch_sockaddr_info_get(&remote_addr, stunip, SWITCH_UNSPEC, stunport, 0, pool) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
*err = "Remote Address Error!";
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (switch_socket_create(&sock, AF_INET, SOCK_DGRAM, 0, pool) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
*err = "Socket Error!";
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-05 20:17:22 +00:00
|
|
|
if (switch_socket_bind(sock, local_addr) != SWITCH_STATUS_SUCCESS) {
|
|
|
|
*err = "Bind Error!";
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2008-07-18 16:18:31 +00:00
|
|
|
if (funny) {
|
|
|
|
*start++ = 0;
|
|
|
|
*start++ = 0;
|
|
|
|
*start++ = 0x22;
|
|
|
|
*start++ = 0x22;
|
|
|
|
}
|
|
|
|
|
2007-03-09 20:44:13 +00:00
|
|
|
switch_socket_opt_set(sock, SWITCH_SO_NONBLOCK, TRUE);
|
2008-07-18 16:18:31 +00:00
|
|
|
packet = switch_stun_packet_build_header(SWITCH_STUN_BINDING_REQUEST, NULL, start);
|
2006-04-05 20:17:22 +00:00
|
|
|
switch_stun_random_string(username, 32, NULL);
|
|
|
|
switch_stun_packet_attribute_add_username(packet, username, 32);
|
|
|
|
bytes = switch_stun_packet_length(packet);
|
2008-07-18 22:04:10 +00:00
|
|
|
|
|
|
|
if (funny) {
|
|
|
|
packet = (switch_stun_packet_t *) buf;
|
|
|
|
bytes += 4;
|
2008-07-21 16:48:05 +00:00
|
|
|
buf[bytes++] = 0;
|
|
|
|
buf[bytes++] = 0;
|
|
|
|
buf[bytes++] = 0;
|
|
|
|
buf[bytes++] = 0;
|
2008-07-18 22:04:10 +00:00
|
|
|
}
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
switch_socket_sendto(sock, remote_addr, 0, (void *) packet, &bytes);
|
2009-01-25 21:23:07 +00:00
|
|
|
started = switch_micro_time_now();
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-05 20:17:22 +00:00
|
|
|
*ip = NULL;
|
|
|
|
*port = 0;
|
|
|
|
|
|
|
|
|
2007-03-29 22:31:56 +00:00
|
|
|
for (;;) {
|
2006-04-05 20:17:22 +00:00
|
|
|
bytes = sizeof(buf);
|
2007-03-29 22:31:56 +00:00
|
|
|
if (switch_socket_recvfrom(from_addr, sock, 0, (char *) &buf, &bytes) == SWITCH_STATUS_SUCCESS && bytes > 0) {
|
2006-04-05 20:17:22 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-01-25 21:23:07 +00:00
|
|
|
if ((elapsed = (unsigned int) ((switch_micro_time_now() - started) / 1000)) > 5000) {
|
2006-04-05 20:17:22 +00:00
|
|
|
*err = "Timeout";
|
2007-03-09 20:44:13 +00:00
|
|
|
switch_socket_shutdown(sock, SWITCH_SHUTDOWN_READWRITE);
|
2006-04-05 20:17:22 +00:00
|
|
|
switch_socket_close(sock);
|
|
|
|
return SWITCH_STATUS_TIMEOUT;
|
|
|
|
}
|
2008-11-14 23:31:21 +00:00
|
|
|
switch_cond_next();
|
2006-04-05 20:17:22 +00:00
|
|
|
}
|
|
|
|
switch_socket_close(sock);
|
|
|
|
|
2008-07-18 16:18:31 +00:00
|
|
|
if (funny) {
|
|
|
|
size -= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
packet = switch_stun_packet_parse(start, size);
|
2008-05-13 00:17:58 +00:00
|
|
|
if (!packet) {
|
|
|
|
*err = "Invalid STUN/ICE packet";
|
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
|
|
|
end_buf = buf + ((sizeof(buf) > packet->header.length) ? packet->header.length : sizeof(buf));
|
2006-04-05 20:17:22 +00:00
|
|
|
|
2008-05-13 00:17:58 +00:00
|
|
|
switch_stun_packet_first_attribute(packet, attr);
|
2006-04-05 20:17:22 +00:00
|
|
|
do {
|
2007-03-29 22:31:56 +00:00
|
|
|
switch (attr->type) {
|
2006-04-05 20:17:22 +00:00
|
|
|
case SWITCH_STUN_ATTR_MAPPED_ADDRESS:
|
|
|
|
if (attr->type) {
|
2008-10-06 19:21:59 +00:00
|
|
|
if (funny) {
|
2008-07-21 16:48:05 +00:00
|
|
|
((switch_stun_ip_t *) attr->value)->address ^= ntohl(0xabcdabcd);
|
|
|
|
}
|
2006-04-05 20:17:22 +00:00
|
|
|
switch_stun_packet_attribute_get_mapped_address(attr, rip, &rport);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SWITCH_STUN_ATTR_USERNAME:
|
2007-03-29 22:31:56 +00:00
|
|
|
if (attr->type) {
|
2006-04-05 20:17:22 +00:00
|
|
|
switch_stun_packet_attribute_get_username(attr, username, 32);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2008-05-10 21:10:44 +00:00
|
|
|
} while (switch_stun_packet_next_attribute(attr, end_buf));
|
2006-04-05 20:17:22 +00:00
|
|
|
|
|
|
|
if (packet->header.type == SWITCH_STUN_BINDING_RESPONSE) {
|
|
|
|
*ip = switch_core_strdup(pool, rip);
|
|
|
|
*port = rport;
|
|
|
|
return SWITCH_STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
*err = "Invalid Reply";
|
|
|
|
}
|
2007-03-29 22:31:56 +00:00
|
|
|
|
2006-04-05 20:17:22 +00:00
|
|
|
return SWITCH_STATUS_FALSE;
|
|
|
|
}
|
2006-11-27 22:30:48 +00:00
|
|
|
|
|
|
|
/* For Emacs:
|
|
|
|
* Local Variables:
|
|
|
|
* mode:c
|
2008-02-03 22:14:57 +00:00
|
|
|
* indent-tabs-mode:t
|
2006-11-27 22:30:48 +00:00
|
|
|
* tab-width:4
|
|
|
|
* c-basic-offset:4
|
|
|
|
* End:
|
|
|
|
* For VIM:
|
2008-07-03 19:12:26 +00:00
|
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
|
2006-11-27 22:30:48 +00:00
|
|
|
*/
|