a stunning new change

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1037 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2006-04-04 16:08:30 +00:00
parent 4fa64dd6d2
commit 48792eb5fc
2 changed files with 488 additions and 0 deletions

220
src/include/switch_stun.h Normal file
View File

@ -0,0 +1,220 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* switch_stun.h STUN (Simple Traversal of UDP over NAT)
*
*/
/*!
\defgroup stun1 STUN code
\ingroup FREESWITCH
\{
*/
#ifndef _SWITCH_STUN_PARSER_H
#define _SWITCH_STUN_PARSER_H
#define SWITCH_STUN_PACKET_MIN_LEN 20
typedef enum {
SWITCH_STUN_BINDING_REQUEST = 0x0001,
SWITCH_STUN_BINDING_RESPONSE = 0x0101,
SWITCH_STUN_BINDING_ERROR_RESPONSE = 0x0111,
SWITCH_STUN_SHARED_SECRET_REQUEST = 0x0002,
SWITCH_STUN_SHARED_SECRET_RESPONSE = 0x0102,
SWITCH_STUN_SHARED_SECRET_ERROR_RESPONSE = 0x0112,
SWITCH_STUN_ALLOCATE_REQUEST = 0x0003,
SWITCH_STUN_ALLOCATE_RESPONSE = 0x0103,
SWITCH_STUN_ALLOCATE_ERROR_RESPONSE = 0x0113,
SWITCH_STUN_SEND_REQUEST = 0x0004,
SWITCH_STUN_SEND_RESPONSE = 0x0104,
SWITCH_STUN_SEND_ERROR_RESPONSE = 0x0114,
SWITCH_STUN_DATA_INDICATION = 0x0115
} switch_stun_message_t;
typedef enum {
SWITCH_STUN_ATTR_MAPPED_ADDRESS = 0x0001, /* Address */
SWITCH_STUN_ATTR_RESPONSE_ADDRESS = 0x0002, /* Address */
SWITCH_STUN_ATTR_CHANGE_REQUEST = 0x0003, /* UInt32 */
SWITCH_STUN_ATTR_SOURCE_ADDRESS = 0x0004, /* Address */
SWITCH_STUN_ATTR_CHANGED_ADDRESS = 0x0005, /* Address */
SWITCH_STUN_ATTR_USERNAME = 0x0006, /* ByteString, multiple of 4 bytes */
SWITCH_STUN_ATTR_PASSWORD = 0x0007, /* ByteString, multiple of 4 bytes */
SWITCH_STUN_ATTR_MESSAGE_INTEGRITY = 0x0008, /* ByteString, 20 bytes */
SWITCH_STUN_ATTR_ERROR_CODE = 0x0009, /* ErrorCode */
SWITCH_STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000a, /* UInt16List */
SWITCH_STUN_ATTR_REFLECTED_FROM = 0x000b, /* Address */
SWITCH_STUN_ATTR_TRANSPORT_PREFERENCES = 0x000c, /* TransportPrefs */
SWITCH_STUN_ATTR_LIFETIME = 0x000d, /* UInt32 */
SWITCH_STUN_ATTR_ALTERNATE_SERVER = 0x000e, /* Address */
SWITCH_STUN_ATTR_MAGIC_COOKIE = 0x000f, /* ByteString, 4 bytes */
SWITCH_STUN_ATTR_BANDWIDTH = 0x0010, /* UInt32 */
SWITCH_STUN_ATTR_DESTINATION_ADDRESS = 0x0011, /* Address */
SWITCH_STUN_ATTR_SOURCE_ADDRESS2 = 0x0012, /* Address */
SWITCH_STUN_ATTR_DATA = 0x0013, /* ByteString */
SWITCH_STUN_ATTR_OPTIONS = 0x8001 /* UInt32 */
} switch_stun_attribute_t;
typedef enum {
SWITCH_STUN_ERROR_BAD_REQUEST = 400,
SWITCH_STUN_ERROR_UNAUTHORIZED = 401,
SWITCH_STUN_ERROR_UNKNOWN_ATTRIBUTE = 420,
SWITCH_STUN_ERROR_STALE_CREDENTIALS = 430,
SWITCH_STUN_ERROR_INTEGRITY_CHECK_FAILURE = 431,
SWITCH_STUN_ERROR_MISSING_USERNAME = 432,
SWITCH_STUN_ERROR_USE_TLS = 433,
SWITCH_STUN_ERROR_SERVER_ERROR = 500,
SWITCH_STUN_ERROR_GLOBAL_FAILURE = 600
} switch_stun_error_t;
typedef enum {
SWITCH_STUN_TYPE_PACKET_TYPE,
SWITCH_STUN_TYPE_ATTRIBUTE,
SWITCH_STUN_TYPE_ERROR
} switch_stun_type_t;
typedef struct {
int16_t type;
int16_t length;
char id[16];
} switch_stun_packet_header_t;
typedef struct {
int16_t type;
uint16_t length;
char value[0];
} switch_stun_packet_attribute_t;
typedef struct {
switch_stun_packet_header_t header;
switch_stun_packet_attribute_t first_attribute;
} switch_stun_packet_t;
typedef struct {
int8_t wasted;
int8_t family;
int16_t port;
int32_t address;
} switch_stun_ip_t;
/*!
\brief Writes random characters into a buffer
\param buf the buffer
\param len the length of the data
\param set the set of chars to use (NULL for auto)
*/
SWITCH_DECLARE(void) switch_stun_random_string(char *buf, uint16_t len, char *set);
/*!
\brief Prepare a raw packet for parsing
\param buf the raw data
\param len the length of the data
\return a stun packet pointer to buf to use as an access point
*/
SWITCH_DECLARE(switch_stun_packet_t *)switch_stun_packet_parse(uint8_t *buf, uint32_t len);
/*!
\brief Obtain a printable string form of a given value
\param type the type of message
\param value the value to look up
\return a sring version of value
*/
SWITCH_DECLARE(const char *)switch_stun_value_to_name(int32_t type, int32_t value);
/*!
\brief Extract a mapped address (IP:PORT) from a packet attribute
\param attribute the attribute from which to extract
\param ipstr a buffer to write the string representation of the ip
\param port the port
\return true or false
*/
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_mapped_address(switch_stun_packet_attribute_t *attribute, char *ipstr, uint16_t *port);
/*!
\brief Extract a username from a packet attribute
\param attribute the attribute from which to extract
\param username a buffer to write the string representation of the username
\param len the maximum size of the username buffer
\return a pointer to the username or NULL
*/
SWITCH_DECLARE(char *)switch_stun_packet_attribute_get_username(switch_stun_packet_attribute_t *attribute, char *username, uint16_t len);
/*!
\brief Prepare a new outbound packet of a certian type and id
\param id id to use (NULL for an auto generated id)
\param type the stun packet type
\param buf a pointer to data to use for the packet
\return a pointer to a ready-to-use stun packet
*/
SWITCH_DECLARE(switch_stun_packet_t *)switch_stun_packet_build_header(switch_stun_message_t type,
char *id,
uint8_t *buf
);
/*!
\brief Add a username packet attribute
\param packet the packet to add the attribute to
\param username the string representation of the username
\param ulen the length of the username
\return true or false
*/
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_username(switch_stun_packet_t *packet, char *username, uint16_t ulen);
/*!
\brief Add a binded address packet attribute
\param packet the packet to add the attribute to
\param ipstr the string representation of the ip
\param port the port of the mapped address
\return true or false
*/
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_binded_address(switch_stun_packet_t *packet, char *ipstr, uint16_t port);
/*!
\brief set a switch_stun_packet_attribute_t pointer to point at the first attribute in a packet
\param packet the packet in question
\param attribute the pointer to set up
*/
#define switch_stun_packet_first_attribute(packet, attribute) attribute = &packet->first_attribute;
/*!
\brief Increment an attribute pointer to the next attribute in it's packet
\param attribute the pointer to increment
\return true or false depending on if there are any more attributes
*/
#define switch_stun_packet_next_attribute(attribute) (attribute = (switch_stun_packet_attribute_t *) (attribute->value + attribute->length)) && attribute->length
/*!
\brief Obtain the correct length in bytes of a stun packet
\param packet the packet in question
\return the size in bytes (host order) of the entire packet
*/
#define switch_stun_packet_length(packet) ntohs(packet->header.length) + sizeof(switch_stun_packet_header_t)
///\}
#endif

268
src/switch_stun.c Normal file
View File

@ -0,0 +1,268 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* switch_stun.c STUN (Simple Traversal of UDP over NAT)
*
*/
#include <switch.h>
struct value_mapping {
const uint32_t value;
const char *name;
};
static const struct value_mapping PACKET_TYPES[] = {
{ 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} };
static const struct value_mapping ATTR_TYPES[] = {
{ 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} };
static const struct value_mapping ERROR_TYPES[] = {
{ 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 }};
SWITCH_DECLARE(void) switch_stun_random_string(char *buf, uint16_t len, char *set)
{
char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int max;
uint8_t x;
if (!set) {
set = chars;
}
max = (int)strlen(set) - 1;
for(x = 0; x < len; x++) {
int j = 1+(int)(max*1.0*rand()/(RAND_MAX+1.0));
buf[x] = set[j];
}
}
SWITCH_DECLARE(switch_stun_packet_t *)switch_stun_packet_parse(uint8_t *buf, uint32_t len)
{
switch_stun_packet_t *packet;
switch_stun_packet_attribute_t *attr;
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);
attr = &packet->first_attribute;
switch_stun_packet_first_attribute(packet, attr);
do {
attr->length = ntohs(attr->length);
attr->type = ntohs(attr->type);
if (!attr->length) {
break;
}
switch(attr->type) {
case SWITCH_STUN_ATTR_MAPPED_ADDRESS:
if (attr->type) {
switch_stun_ip_t *ip;
ip = (switch_stun_ip_t *) attr->value;
ip->port = ntohs(ip->port);
}
break;
}
} while (switch_stun_packet_next_attribute(attr));
return packet;
}
SWITCH_DECLARE(const char *)switch_stun_value_to_name(int32_t type, int32_t value)
{
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) {
for(x = 0; map[x].value; x++) {
if (map[x].value == value) {
return map[x].name;
}
}
}
return "INVALID";
}
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_get_mapped_address(switch_stun_packet_attribute_t *attribute, char *ipstr, uint16_t *port)
{
switch_stun_ip_t *ip;
uint8_t x, *i;
char *p = ipstr;
ip = (switch_stun_ip_t *) attribute->value;
i = (uint8_t *) &ip->address;
*ipstr = 0;
for(x =0; x < 4; x++) {
sprintf(p, "%u%s", i[x], x == 3 ? "" : ".");
p = ipstr + strlen(ipstr);
}
*port = ip->port;
return 1;
}
SWITCH_DECLARE(char *)switch_stun_packet_attribute_get_username(switch_stun_packet_attribute_t *attribute, char *username, uint16_t len)
{
uint16_t cpylen;
cpylen = attribute->length > len ? attribute->length : len;
return memcpy(username, attribute->value, cpylen);
}
SWITCH_DECLARE(switch_stun_packet_t *)switch_stun_packet_build_header(switch_stun_message_t type,
char *id,
uint8_t *buf
)
{
switch_stun_packet_header_t *header;
header = (switch_stun_packet_header_t *) buf;
header->type = htons(type);
header->length = 0;
if (id) {
memcpy(header->id, id, 16);
} else {
switch_stun_random_string(header->id, 16, NULL);
}
return (switch_stun_packet_t *) buf;
}
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_binded_address(switch_stun_packet_t *packet, char *ipstr, uint16_t port)
{
switch_stun_packet_attribute_t *attribute;
switch_stun_ip_t *ip;
uint8_t *i, x;
char *p = ipstr;
attribute = (switch_stun_packet_attribute_t *) ((uint8_t *) &packet->first_attribute + ntohs(packet->header.length));
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;
i = (uint8_t *) &ip->address;
for(x = 0; x < 4 ; x++) {
i[x] = atoi(p);
if ((p = strchr(p, '.'))) {
p++;
} else {
break;
}
}
packet->header.length += htons(sizeof(switch_stun_packet_attribute_t)) + attribute->length;
return 1;
}
SWITCH_DECLARE(uint8_t) switch_stun_packet_attribute_add_username(switch_stun_packet_t *packet, char *username, uint16_t ulen)
{
switch_stun_packet_attribute_t *attribute;
if (ulen % 4 != 0) {
return 0;
}
attribute = (switch_stun_packet_attribute_t *) ((uint8_t *) &packet->first_attribute + ntohs(packet->header.length));
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);
}
packet->header.length += htons(sizeof(switch_stun_packet_attribute_t)) + attribute->length;
return 1;
}