]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
a stunning new change
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 4 Apr 2006 16:08:30 +0000 (16:08 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 4 Apr 2006 16:08:30 +0000 (16:08 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1037 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_stun.h [new file with mode: 0644]
src/switch_stun.c [new file with mode: 0644]

diff --git a/src/include/switch_stun.h b/src/include/switch_stun.h
new file mode 100644 (file)
index 0000000..2aaf587
--- /dev/null
@@ -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
diff --git a/src/switch_stun.c b/src/switch_stun.c
new file mode 100644 (file)
index 0000000..c7850d2
--- /dev/null
@@ -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;
+}