summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYouness Alaoui <kakaroto@kakaroto.(none)>2008-06-06 18:32:16 -0400
committerYouness Alaoui <kakaroto@kakaroto.(none)>2008-06-06 18:32:16 -0400
commitb9669017120b3dc12aa14e548201168e0e93f801 (patch)
tree7aece344441d63274fdcbd7e2d6f4dadab59d717
parentc07afc9a4bcd0557cecc2b4de8e8834f67c0844e (diff)
downloadlibnice-b9669017120b3dc12aa14e548201168e0e93f801.tar.gz
Updating stun to include an agent
-rw-r--r--stun/Makefile.am22
-rw-r--r--stun/constants.h4
-rw-r--r--stun/stun-msg.h328
-rw-r--r--stun/stun3489bis.c32
-rw-r--r--stun/stun3489bis.h4
-rw-r--r--stun/stunagent.c461
-rw-r--r--stun/stunagent.h111
-rw-r--r--stun/stuncrc32.c2
-rw-r--r--stun/stunhmac.c2
-rw-r--r--stun/stunhmac.h4
-rw-r--r--stun/stunmessage.c80
-rw-r--r--stun/stunmessage.h133
-rw-r--r--stun/stunrecv.c567
-rw-r--r--stun/stunsend.c481
-rw-r--r--stun/tests/test-parse.c3
-rw-r--r--stun/tools/stunbdc.c2
-rw-r--r--stun/utils.c205
-rw-r--r--stun/utils.h24
18 files changed, 915 insertions, 1550 deletions
diff --git a/stun/Makefile.am b/stun/Makefile.am
index 5e7ba52..1a1c03c 100644
--- a/stun/Makefile.am
+++ b/stun/Makefile.am
@@ -19,16 +19,18 @@ CLEANFILES += $(BUILT_SOURCES)
noinst_LTLIBRARIES = libstun.la
dist_noinst_SCRIPTS = build-unknown.sh
-libstun_la_SOURCES = \
- stun-msg.h stunsend.c stunrecv.c \
- stun3489bis.c \
- utils.c \
- unknown.c \
- crc32.c hmac.c \
- usages/timer.h usages/timer.c \
- usages/trans.h usages/trans.c \
- usages/stun-ice.c usages/stun-ice.h \
- usages/bind.c usages/bind.h
+libstun_la_SOURCES = stun.h constants.h \
+ stunagent.c stunagent.h \
+ stunmessage.c stunmessage.h \
+ stun3489bis.c stun3489bis.h \
+ stuncrc32.c stuncrc32.h \
+ stunhmac.c stunhmac.h \
+ utils.c utils.h
+
+# usages/timer.h usages/timer.c \
+# usages/trans.h usages/trans.c \
+# usages/stun-ice.c usages/stun-ice.h \
+# usages/bind.c usages/bind.h
libstun_la_LIBADD = $(OPENSSL_LIBS) $(LIBRT)
diff --git a/stun/constants.h b/stun/constants.h
index 4a13b53..f5f1e2d 100644
--- a/stun/constants.h
+++ b/stun/constants.h
@@ -67,9 +67,9 @@
#define STUN_ID_LEN 16
#define STUN_AGENT_MAX_SAVED_IDS 20
+#define STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES 256
-
-#define STUN_COOKIE 0x2112A442
+#define STUN_MAGIC_COOKIE 0x2112A442
#ifndef TRUE
#define TRUE (1 == 1)
diff --git a/stun/stun-msg.h b/stun/stun-msg.h
index fc759c7..0fded73 100644
--- a/stun/stun-msg.h
+++ b/stun/stun-msg.h
@@ -54,138 +54,12 @@
# define STUN_MAXCHR 127u
# define STUN_MAXSTR ((STUN_MAXCHR * 6u) + 1)
-# define STUN_COOKIE 0x2112A442
-
-typedef struct stun_hdr_s
-{
- uint16_t msg_type;
- uint16_t msg_len;
- uint32_t msg_cookie;
- uint32_t msg_id[3];
-} stun_hdr_t;
-
-
-typedef uint8_t stun_msg_t[STUN_MAXMSG];
-
-/* Message classes */
-typedef enum
-{
- STUN_REQUEST=0,
- STUN_INDICATION=1,
- STUN_RESPONSE=2,
- STUN_ERROR=3
-} stun_class_t;
-
-/* Message methods */
-typedef enum
-{
- STUN_BINDING=0x001, /* RFC3489bis-11 */
- STUN_OLD_SHARED_SECRET=0x002, /* old RFC3489 */
- STUN_ALLOCATE=0x003, /* TURN-04 */
- STUN_SET_ACTIVE_DST=0x004, /* TURN-04 */
- STUN_CONNECT=0x005, /* TURN-04 */
- STUN_IND_SEND=0x006, /* TURN-04 */
- STUN_IND_DATA=0x007, /* TURN-04 */
- STUN_IND_CONNECT_STATUS=0x008 /* TURN-04 */
-} stun_method_t;
-/**
- * STUN attribute types
- * Should be in sync with stun_is_unknown()
- */
-typedef enum
-{
- /* Mandatory attributes */
- /* 0x0000 */ /* reserved */
- STUN_MAPPED_ADDRESS=0x0001, /* RFC3489bis-11 */
- STUN_OLD_RESPONSE_ADDRESS=0x0002, /* old RFC3489 */
- STUN_OLD_CHANGE_REQUEST=0x0003, /* old RFC3489 */
- STUN_OLD_SOURCE_ADDRESS=0x0004, /* old RFC3489 */
- STUN_OLD_CHANGED_ADDRESS=0x0005, /* old RFC3489 */
- STUN_USERNAME=0x0006, /* RFC3489bis-11 */
- STUN_OLD_PASSWORD=0x0007, /* old RFC3489 */
- STUN_MESSAGE_INTEGRITY=0x0008, /* RFC3489bis-11 */
- STUN_ERROR_CODE=0x0009, /* RFC3489bis-11 */
- STUN_UNKNOWN_ATTRIBUTES=0x000A, /* RFC3489bis-11 */
- STUN_OLD_REFLECTED_FROM=0x000B, /* old RFC3489 */
- /* 0x000C */ /* reserved */
- STUN_LIFETIME=0x000D, /* TURN-04 */
- /* 0x000E */ /* reserved */
- /* 0x000F */ /* reserved */
- STUN_BANDWIDTH=0x0010, /* TURN-04 */
- /* 0x0011 */ /* reserved */
- STUN_REMOTE_ADDRESS=0x0012, /* TURN-04 */
- STUN_DATA=0x0013, /* TURN-04 */
- STUN_REALM=0x0014, /* RFC3489bis-11 */
- STUN_NONCE=0x0015, /* RFC3489bis-11 */
- STUN_RELAY_ADDRESS=0x0016, /* TURN-04 */
- STUN_REQUESTED_ADDRESS_TYPE=0x0017, /* TURN-IPv6-03 */
- STUN_REQUESTED_PORT_PROPS=0x0018, /* TURN-04 */
- STUN_REQUESTED_TRANSPORT=0x0019, /* TURN-04 */
- /* 0x001A */ /* reserved */
- /* 0x001B */ /* reserved */
- /* 0x001C */ /* reserved */
- /* 0x001D */ /* reserved */
- /* 0x001E */ /* reserved */
- /* 0x001F */ /* reserved */
- STUN_XOR_MAPPED_ADDRESS=0x0020, /* RFC3489bis-11 */
- STUN_TIMER_VAL=0x0021, /* TURN-04 */
- STUN_REQUESTED_IP=0x0022, /* TURN-04 */
- STUN_CONNECT_STAT=0x0023, /* TURN-04 */
- STUN_PRIORITY=0x0024, /* ICE-18 */
- STUN_USE_CANDIDATE=0x0025, /* ICE-18 */
- /* 0x0026 */ /* reserved */
- /* 0x0027 */ /* reserved */
- /* 0x0028 */ /* reserved */
- STUN_XOR_INTERNAL_ADDRESS=0x0029, /* wing-nat-control-04 */
- /* 0x002A-0x7fff */ /* reserved */
-
- /* Optional attributes */
- /* 0x8000-0x8021 */ /* reserved */
- STUN_SERVER=0x8022, /* RFC3489bis-11 */
- STUN_ALTERNATE_SERVER=0x8023, /* RFC3489bis-11 */
- STUN_REFRESH_INTERVAL=0x8024, /* wing-nat-control-04 */
- /* 0x8025 */ /* reserved */
- /* 0x8026 */ /* reserved */
- /* 0x8027 */ /* reserved */
- STUN_FINGERPRINT=0x8028, /* RFC3489bis-11 */
- STUN_ICE_CONTROLLED=0x8029, /* ICE-18 */
- STUN_ICE_CONTROLLING=0x802A, /* ICE-18 */
- /* 0x802B-0xFFFF */ /* reserved */
-} stun_attr_type_t;
-
-
-typedef uint8_t stun_transid_t[12];
-
-/**
- * STUN error codes
- * Should be in sync with stun_strerror()
- */
-typedef enum
-{
- STUN_TRY_ALTERNATE=300, /* RFC3489bis-11 */
- STUN_BAD_REQUEST=400, /* RFC3489bis-11 */
- STUN_UNAUTHORIZED=401, /* RFC3489bis-11 */
- STUN_UNKNOWN_ATTRIBUTE=420, /* RFC3489bis-11 */
- STUN_NO_BINDING=437, /* TURN-04 */
- STUN_STALE_NONCE=438, /* RFC3489bis-11 */
- STUN_ACT_DST_ALREADY=439, /* TURN-04 */
- STUN_UNSUPP_FAMILY=440, /* TURN-IPv6-03 */
- STUN_UNSUPP_TRANSPORT=442, /* TURN-04 */
- STUN_INVALID_IP=443, /* TURN-04 */
- STUN_INVALID_PORT=444, /* TURN-04 */
- STUN_OP_TCP_ONLY=445, /* TURN-04 */
- STUN_CONN_ALREADY=446, /* TURN-04 */
- STUN_ALLOC_OVER_QUOTA=486, /* TURN-04 */
- STUN_ROLE_CONFLICT=487, /* ICE-18 */
- STUN_SERVER_ERROR=500, /* RFC3489bis-11 */
- STUN_SERVER_CAPACITY=507, /* TURN-04 */
- STUN_ERROR_MAX=699
-} stun_error_t;
#include "utils.h"
#include "stun3489bis.h"
+#include "stunhmac.h"
# ifndef NDEBUG
# include <stdio.h>
@@ -204,31 +78,6 @@ extern "C" {
# endif
-/**
- * Computes the MESSAGE-INTEGRITY hash of a STUN message.
- * @param msg pointer to the STUN message
- * @param len size of the message from header (inclusive) and up to
- * MESSAGE-INTEGRITY attribute (inclusive)
- * @param sha output buffer for SHA1 hash (20 bytes)
- * @param key HMAC key
- * @param keylen HMAC key bytes length
- *
- * @return fingerprint value in <b>host</b> byte order.
- */
-void stun_sha1 (const uint8_t *msg, size_t len,
- uint8_t *sha, const void *key, size_t keylen);
-
-/**
- * SIP H(A1) computation
- */
-void stun_hash_creds (const char *realm, const char *login, const char *pw,
- unsigned char md5[16]);
-
-/**
- * Generates a pseudo-random secure STUN transaction ID.
- */
-void stun_make_transid (stun_transid_t id);
-
int stun_xor_address (const uint8_t *msg,
struct sockaddr *addr, socklen_t addrlen);
@@ -281,102 +130,6 @@ int stun_verify_password (const uint8_t *msg, const char *pw);
int stun_verify_username (const uint8_t *msg, const char *local_ufrag, uint32_t compat);
/**
- * Looks for an attribute in a *valid* STUN message.
- * @param msg message buffer
- * @param type STUN attribute type (host byte order)
- * @param palen [OUT] pointer to store the byte length of the attribute
- * @return a pointer to the start of the attribute payload if found,
- * otherwise NULL.
- */
-const void *
-stun_find (const uint8_t *restrict msg, stun_attr_type_t type,
- uint16_t *restrict palen);
-
-
-/**
- * Looks for a flag attribute within a valid STUN message.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @return 0 if flag is present, ENOENT if it is not, EINVAL if flag payload
- * size is not zero.
- */
-int stun_find_flag (const uint8_t *msg, stun_attr_type_t type);
-
-/**
- * Extracts a 32-bits attribute from a valid STUN message.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param pval [OUT] where to store the host byte ordered value
- *
- * @return 0 on success, ENOENT if attribute not found,
- * EINVAL if attribute payload was not 32-bits.
- * In case of error, @a *pval is not modified.
- */
-int stun_find32 (const uint8_t *msg, stun_attr_type_t type, uint32_t *pval);
-
-/**
- * Extracts a 64-bits attribute from a valid STUN message.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param pval [OUT] where to store the host byte ordered value
- * @return 0 on success, ENOENT if attribute not found,
- * EINVAL if attribute payload was not 64-bits.
- * In case of error, @a *pval is not modified.
- */
-int stun_find64 (const uint8_t *msg, stun_attr_type_t type, uint64_t *pval);
-
-/**
- * Extracts an UTF-8 string from a valid STUN message.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param buf buffer to store the extracted string
- * @param maxcp maximum number of code points allowed
- * (@a buf should be (6*maxcp+1) bytes long)
- *
- * @return 0 on success, ENOENT if attribute not found, EINVAL if attribute
- * improperly encoded, ENOBUFS if the buffer size was too small.
- *
- * @note A nul-byte is appended at the end.
- */
-int stun_find_string (const uint8_t *restrict msg, stun_attr_type_t type,
- char *buf, size_t buflen);
-
-# define STUN_MAX_STR (763u)
-# define STUN_MAX_CP (127u)
-
-/**
- * Extracts a network address attribute from a valid STUN message.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param addr [OUT] where to store the socket address
- * @param addrlen [IN/OUT] pointer to the size of the socket address
- * buffer upon entry, set to the length of the extracted socket
- * address upon return,
- * @return 0 on success, ENOENT if attribute not found,
- * EINVAL if attribute payload size was wrong or addrlen too small,
- * EAFNOSUPPORT if address family is unknown.
- */
-int stun_find_addr (const uint8_t *restrict msg, stun_attr_type_t type,
- struct sockaddr *restrict addr,
- socklen_t *restrict addrlen);
-
-/**
- * Extracts an obfuscated network address attribute from a valid STUN message.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param addr [OUT] where to store the socket address
- * @param addrlen [IN/OUT] pointer to the size of the socket address
- * buffer upon entry, set to the length of the extracted socket
- * address upon return,
- * @return 0 on success, ENOENT if attribute not found,
- * EINVAL if attribute payload size was wrong or addrlen too small,
- * EAFNOSUPPORT if address family is unknown.
- */
-int stun_find_xor_addr (const uint8_t *restrict msg, stun_attr_type_t type,
- struct sockaddr *restrict addr,
- socklen_t *restrict addrlen);
-
-/**
* Compares the length and content of an attribute.
*
* @param msg valid STUN message buffer
@@ -515,85 +268,6 @@ size_t stun_finish_short (uint8_t *msg, size_t *restrict plen,
size_t stun_finish (uint8_t *restrict msg, size_t *restrict plen, int compat);
-void *stun_append (uint8_t *msg, size_t msize, stun_attr_type_t type,
- size_t length);
-int stun_append_bytes (uint8_t *restrict msg, size_t msize,
- stun_attr_type_t type, const void *data, size_t len);
-
-/**
- * Appends an empty ("flag") attribute to a STUN message.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribute type (host byte order)
- * @return 0 on success, ENOBUFS on error.
- */
-int stun_append_flag (uint8_t *msg, size_t msize, stun_attr_type_t type);
-
-/**
- * Appends an attribute consisting of a 32-bits value to a STUN message.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribute type (host byte order)
- * @param value payload (host byte order)
- * @return 0 on success, ENOBUFS on error.
- */
-int stun_append32 (uint8_t *msg, size_t msize,
- stun_attr_type_t type, uint32_t value);
-
-/**
- * Appends an attribute consisting of a 64-bits value to a STUN message.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribute type (host byte order)
- * @param value payload (host byte order)
- * @return 0 on success, ENOBUFS on error.
- */
-int stun_append64 (uint8_t *msg, size_t msize,
- stun_attr_type_t type, uint64_t value);
-
-/**
- * Appends an attribute from a nul-terminated string.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribute type (host byte order)
- * @param str nul-terminated string
- * @return 0 on success, ENOBUFS on error.
- */
-int stun_append_string (uint8_t *restrict msg, size_t msize,
- stun_attr_type_t type, const char *str);
-
-/**
- * Appends an attribute consisting of a network address to a STUN message.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribyte type (host byte order)
- * @param addr socket address to convert into an attribute
- * @param addrlen byte length of socket address
- * @return 0 on success, ENOBUFS if the message buffer overflowed,
- * EAFNOSUPPORT is the socket address family is not supported,
- * EINVAL if the socket address length is too small w.r.t. the address family.
- */
-int stun_append_addr (uint8_t *restrict msg, size_t msize,
- stun_attr_type_t type,
- const struct sockaddr *restrict addr,
- socklen_t addrlen);
-
-/**
- * Appends an attribute consisting of a xor'ed network address.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribyte type (host byte order)
- * @param addr socket address to convert into an attribute
- * @param addrlen byte length of socket address
- * @return 0 on success, ENOBUFS if the message buffer overflowed,
- * EAFNOSUPPORT is the socket address family is not supported,
- * EINVAL if the socket address length is too small w.r.t. the address family.
- */
-int stun_append_xor_addr (uint8_t *restrict msg, size_t msize,
- stun_attr_type_t type,
- const struct sockaddr *restrict addr,
- socklen_t addrlen);
-
# ifdef __cplusplus
}
# endif
diff --git a/stun/stun3489bis.c b/stun/stun3489bis.c
index 11e0809..53518da 100644
--- a/stun/stun3489bis.c
+++ b/stun/stun3489bis.c
@@ -35,19 +35,24 @@
* file under either the MPL or the LGPL.
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include <sys/socket.h>
#include <netinet/in.h> /* htons() */
-#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
-#include "crc32.h"
-#include "stun-msg.h"
+#include "stuncrc32.h"
+#include "stunmessage.h"
uint32_t stun_fingerprint (const uint8_t *msg, size_t len)
{
struct iovec iov[3];
uint16_t fakelen = htons (len - 20u);
- assert (len >= 28u);
+ // assert (len >= 28u);
iov[0].iov_base = (void *)msg;
iov[0].iov_len = 2;
@@ -57,5 +62,22 @@ uint32_t stun_fingerprint (const uint8_t *msg, size_t len)
/* first 4 bytes done, last 8 bytes not summed */
iov[2].iov_len = len - 12u;
- return crc32 (iov, sizeof (iov) / sizeof (iov[0])) ^ 0x5354554e;
+ return htonl (crc32 (iov, sizeof (iov) / sizeof (iov[0])) ^ 0x5354554e);
+}
+
+bool stun_has_cookie (const StunMessage *msg)
+{
+ stun_transid_t id;
+ stun_message_id (msg, id);
+ uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
+ return memcmp (id, &cookie, sizeof (cookie)) == 0;
+}
+
+
+int stun_message_append_server (StunMessage *msg)
+{
+ static const char server[] = PACKAGE_STRING;
+ // assert (strlen (server) < 128);
+
+ return stun_message_append_string (msg, STUN_ATTRIBUTE_SERVER, server);
}
diff --git a/stun/stun3489bis.h b/stun/stun3489bis.h
index 6f18a51..1562839 100644
--- a/stun/stun3489bis.h
+++ b/stun/stun3489bis.h
@@ -54,8 +54,10 @@
*/
uint32_t stun_fingerprint (const uint8_t *msg, size_t len);
+bool stun_has_cookie (const StunMessage *msg);
+
+int stun_message_append_server (StunMessage *msg);
-bool stun_has_cookie (const uint8_t *msg);
#endif /* _STUN_3489BIS_H */
diff --git a/stun/stunagent.c b/stun/stunagent.c
new file mode 100644
index 0000000..c7e62f6
--- /dev/null
+++ b/stun/stunagent.c
@@ -0,0 +1,461 @@
+/*
+ * This file is part of the Nice GLib ICE library.
+ *
+ * (C) 2007 Nokia Corporation. All rights reserved.
+ * Contact: Rémi Denis-Courmont
+ *
+ * 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 the Nice GLib ICE library.
+ *
+ * The Initial Developers of the Original Code are Collabora Ltd and Nokia
+ * Corporation. All Rights Reserved.
+ *
+ * Contributors:
+ * Rémi Denis-Courmont, Nokia
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
+ * case the provisions of LGPL are applicable instead of those above. If you
+ * wish to allow use of your version of this file only under the terms of the
+ * LGPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replace
+ * them with the notice and other provisions required by the LGPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the LGPL.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "stunmessage.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <errno.h>
+#include <netinet/in.h>
+
+
+static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type);
+static unsigned stun_agent_find_unknowns (StunAgent *agent,
+ const StunMessage * msg, uint16_t *list, unsigned max);
+
+void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes,
+ StunCompatibility compatibility, uint32_t usage_flags)
+{
+ int i;
+
+ agent->known_attributes = (uint16_t *) known_attributes;
+ agent->compatibility = compatibility;
+ agent->usage_flags = usage_flags;
+
+ for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
+ agent->sent_ids[i].valid = FALSE;
+ }
+}
+
+
+StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
+ const uint8_t *buffer, size_t buffer_len,
+ StunMessageIntegrityValidate validater, void * validater_data)
+{
+ stun_transid_t msg_id;
+ uint32_t fpr;
+ uint32_t crc32;
+ int len;
+ int error_code;
+ uint8_t *username = NULL;
+ uint16_t username_len;
+ uint8_t *key = NULL;
+ size_t key_len;
+ uint8_t *hash;
+ uint8_t sha[20];
+ uint16_t hlen;
+ int sent_id_idx = -1;
+
+ len = stun_message_validate_buffer_length (buffer, buffer_len);
+ if (len == STUN_MESSAGE_BUFFER_INVALID) {
+ return STUN_VALIDATION_NOT_STUN;
+ } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
+ return STUN_VALIDATION_INCOMPLETE_STUN;
+ } else if (len != (int) buffer_len) {
+ return STUN_VALIDATION_NOT_STUN;
+ }
+
+ msg->buffer = (uint8_t *) buffer;
+ msg->buffer_len = buffer_len;
+ msg->agent = agent;
+ msg->key = NULL;
+ msg->key_len = 0;
+
+ /* TODO: reject it or not ? */
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS &&
+ !stun_has_cookie (msg)) {
+ stun_debug ("STUN demux error: no cookie!\n");
+ return STUN_VALIDATION_BAD_REQUEST;
+ }
+
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS &&
+ agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
+ /* Looks for FINGERPRINT */
+ if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) != 0) {
+ stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
+ return STUN_VALIDATION_BAD_REQUEST;
+ }
+
+ /* Checks FINGERPRINT */
+ crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg) - 8);
+ if (fpr != crc32) {
+ stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
+ " expected: 0x%08x!\n", fpr, crc32);
+ return STUN_VALIDATION_BAD_REQUEST;
+ }
+
+ stun_debug ("STUN demux: OK!\n");
+ }
+
+ if (stun_message_get_class (msg) == STUN_RESPONSE ||
+ stun_message_get_class (msg) == STUN_ERROR) {
+ stun_message_id (msg, msg_id);
+ for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) {
+ if (agent->sent_ids[sent_id_idx].valid == TRUE &&
+ agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) &&
+ memcmp (msg_id, agent->sent_ids[sent_id_idx].id,
+ sizeof(stun_transid_t)) == 0) {
+
+ if (stun_message_get_class (msg) == STUN_ERROR &&
+ stun_message_find_error (msg, &error_code) != 0) {
+ stun_debug ("STUN demux error: STUN_ERROR with no ERROR_CODE");
+ return STUN_VALIDATION_BAD_REQUEST;
+ }
+ key = agent->sent_ids[sent_id_idx].key;
+ key_len = agent->sent_ids[sent_id_idx].key_len;
+ break;
+ }
+ }
+ if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
+ return STUN_VALIDATION_UNMATCHED_RESPONSE;
+ }
+ }
+
+ if ((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS &&
+ (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
+ !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) ||
+ (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS &&
+ stun_message_get_class (msg) != STUN_INDICATION &&
+ (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
+ !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) ||
+ !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) ||
+ !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) ||
+ ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
+ stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) &&
+ !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) {
+ return STUN_VALIDATION_UNAUTHORIZED;
+ }
+
+ if ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
+ stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME)) {
+ username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME,
+ &username_len);
+ if (username) {
+ if (key == NULL) {
+ if (validater (agent, msg, username, username_len,
+ &key, &key_len, validater_data) == FALSE) {
+ return STUN_VALIDATION_UNAUTHORIZED;
+ }
+ }
+ }
+ }
+
+ if (key != NULL && key_len > 0) {
+ hash = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY,
+ &hlen);
+
+ stun_sha1 (msg->buffer, stun_message_length (msg), sha, key, key_len);
+ stun_debug (" Message HMAC-SHA1 fingerprint:");
+ stun_debug ("\nkey : ");
+ stun_debug_bytes (key, key_len);
+ stun_debug ("\n expected: ");
+ stun_debug_bytes (sha, sizeof (sha));
+ stun_debug ("\n received: ");
+ stun_debug_bytes (hash, sizeof (sha));
+ stun_debug ("\n");
+
+ if (memcmp (sha, hash, sizeof (sha))) {
+ stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
+ return STUN_VALIDATION_UNAUTHORIZED;
+ }
+
+ stun_debug ("STUN auth: OK!\n");
+ }
+
+ if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) {
+ agent->sent_ids[sent_id_idx].valid = FALSE;
+ }
+ return STUN_VALIDATION_SUCCESS;
+
+}
+
+
+bool stun_agent_init_request (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, stun_method_t m)
+{
+ bool ret;
+ stun_transid_t id;
+
+ msg->buffer = buffer;
+ msg->buffer_len = buffer_len;
+ msg->agent = agent;
+ msg->key = NULL;
+ msg->key_len = 0;
+
+ stun_make_transid (id);
+
+ ret = stun_message_init (msg, STUN_REQUEST, m, id);
+
+ if (ret) {
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS) {
+ uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
+ memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
+ }
+ }
+
+ return ret;
+}
+
+
+bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, stun_method_t m)
+{
+ bool ret;
+ stun_transid_t id;
+
+ msg->buffer = buffer;
+ msg->buffer_len = buffer_len;
+ msg->agent = agent;
+ msg->key = NULL;
+ msg->key_len = 0;
+
+ stun_make_transid (id);
+ ret = stun_message_init (msg, STUN_INDICATION, m, id);
+
+ if (ret) {
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS) {
+ uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
+ memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
+ }
+ }
+
+ return ret;
+}
+
+
+bool stun_agent_init_response (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, stun_method_t m, StunMessage *request)
+{
+
+ stun_transid_t id;
+
+ if (stun_message_get_class (request) != STUN_REQUEST) {
+ return FALSE;
+ }
+
+ msg->buffer = buffer;
+ msg->buffer_len = buffer_len;
+ msg->agent = agent;
+ msg->key = NULL;
+ msg->key_len = 0;
+
+ stun_message_id (request, id);
+
+ if (stun_message_init (msg, STUN_RESPONSE,
+ stun_message_get_method (request), id)) {
+
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS &&
+ agent->usage_flags & STUN_AGENT_USAGE_ADD_SERVER) {
+ stun_message_append_server (msg);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+bool stun_agent_init_error (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, StunMessage *request,
+ stun_error_t err)
+{
+ stun_transid_t id;
+
+ if (stun_message_get_class (request) != STUN_REQUEST) {
+ return FALSE;
+ }
+
+ msg->buffer = buffer;
+ msg->buffer_len = buffer_len;
+ msg->agent = agent;
+ msg->key = NULL;
+ msg->key_len = 0;
+
+ stun_message_id (request, id);
+
+
+ if (stun_message_init (msg, STUN_ERROR,
+ stun_message_get_method (request), id)) {
+
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS &&
+ agent->usage_flags & STUN_AGENT_USAGE_ADD_SERVER) {
+ stun_message_append_server (msg);
+ }
+ if (stun_message_append_error (msg, err) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+size_t stun_agent_build_unknown_attributes_error (StunAgent *agent,
+ StunMessage *msg, uint8_t *buffer, size_t buffer_len, StunMessage *request)
+{
+
+ unsigned counter;
+ uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES];
+
+ counter = stun_agent_find_unknowns (agent, request,
+ ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES);
+
+ if (stun_agent_init_error (agent, msg, buffer, buffer_len,
+ request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) {
+ return 0;
+ }
+
+ /* NOTE: Old RFC3489 compatibility:
+ * When counter is odd, duplicate one value for 32-bits padding. */
+ if (!stun_has_cookie (request) && (counter & 1))
+ ids[counter++] = ids[0];
+
+ if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES,
+ ids, counter * 2) == 0) {
+ return stun_agent_finish_message (agent, msg, request->key, request->key_len);
+ }
+
+ return 0;
+}
+
+
+size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
+ uint8_t *key, size_t key_len)
+{
+ uint8_t *ptr;
+ uint32_t fpr;
+ int i;
+ stun_transid_t id;
+
+ if (key != NULL) {
+ ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ stun_sha1 (msg->buffer, stun_message_length (msg), ptr, key, key_len);
+
+ stun_debug (" Message HMAC-SHA1 fingerprint:"
+ "\n key : ");
+ stun_debug_bytes (key, key_len);
+ stun_debug ("\n sent : ");
+ stun_debug_bytes (ptr, 20);
+ stun_debug ("\n");
+
+ }
+
+ if (agent->compatibility == STUN_COMPATIBILITY_3489BIS &&
+ agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
+ ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
+ if (ptr == NULL) {
+ return 0;
+ }
+
+ fpr = stun_fingerprint (msg->buffer, stun_message_length (msg));
+ memcpy (ptr, &fpr, sizeof (fpr));
+ }
+
+
+ if (stun_message_get_class (msg) == STUN_REQUEST) {
+ for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
+ if (agent->sent_ids[i].valid == FALSE) {
+ stun_message_id (msg, id);
+ memcpy (agent->sent_ids[i].id, id, sizeof(stun_transid_t));
+ agent->sent_ids[i].method = stun_message_get_method (msg);
+ agent->sent_ids[i].key = key;
+ agent->sent_ids[i].key_len = key_len;
+ agent->sent_ids[i].valid = TRUE;
+ return TRUE;
+ }
+ }
+ }
+
+ msg->key = key;
+ msg->key_len = key_len;
+ return stun_message_length (msg);
+
+}
+
+static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type)
+{
+
+ uint16_t *known_attr = agent->known_attributes;
+
+ while(*known_attr != 0) {
+ if (*known_attr == type) {
+ return FALSE;
+ }
+ known_attr++;
+ }
+
+ return TRUE;
+
+}
+
+
+static unsigned
+stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg,
+ uint16_t *list, unsigned max)
+{
+ unsigned count = 0;
+ uint16_t len = stun_message_length (msg);
+ size_t offset = 0;
+
+ offset = STUN_MESSAGE_ATTRIBUTES_POS;
+
+ while ((offset < len) && (count < max))
+ {
+ size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN);
+ uint16_t atype = stun_getw (msg->buffer + offset);
+
+ offset += STUN_ATTRIBUTE_VALUE_POS + stun_align (alen);
+
+ if (!stun_optional (atype) && stun_agent_is_unknown (agent, atype))
+ {
+ stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)\n",
+ (unsigned)atype, (unsigned)alen);
+ list[count++] = htons (atype);
+ }
+ }
+
+ stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count);
+ return count;
+}
diff --git a/stun/stunagent.h b/stun/stunagent.h
new file mode 100644
index 0000000..78ebcc1
--- /dev/null
+++ b/stun/stunagent.h
@@ -0,0 +1,111 @@
+/*
+ * This file is part of the Nice GLib ICE library.
+ *
+ * (C) 2008 Collabora Ltd.
+ * (C) 2008 Nokia Corporation. All rights reserved.
+ * Contact: Youness Alaoui
+ *
+ * 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 the Nice GLib ICE library.
+ *
+ * The Initial Developers of the Original Code are Collabora Ltd and Nokia
+ * Corporation. All Rights Reserved.
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
+ * case the provisions of LGPL are applicable instead of those above. If you
+ * wish to allow use of your version of this file only under the terms of the
+ * LGPL and not to allow others to use your version of this file under the
+ * MPL, indicate your decision by deleting the provisions above and replace
+ * them with the notice and other provisions required by the LGPL. If you do
+ * not delete the provisions above, a recipient may use your version of this
+ * file under either the MPL or the LGPL.
+ */
+
+#ifndef _STUN_AGENT_H
+#define _STUN_AGENT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+typedef struct stun_agent_t StunAgent;
+
+#include "stunmessage.h"
+
+typedef enum {
+ STUN_COMPATIBILITY_RFC3489,
+ STUN_COMPATIBILITY_3489BIS,
+ STUN_COMPATIBILITY_LAST = STUN_COMPATIBILITY_3489BIS
+} StunCompatibility;
+
+
+typedef enum {
+ STUN_VALIDATION_SUCCESS,
+ STUN_VALIDATION_NOT_STUN,
+ STUN_VALIDATION_INCOMPLETE_STUN,
+ STUN_VALIDATION_BAD_REQUEST,
+ STUN_VALIDATION_UNAUTHORIZED,
+ STUN_VALIDATION_UNMATCHED_RESPONSE,
+ STUN_VALIDATION_UNKNOWN_ATTRIBUTE,
+ STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE
+} StunValidationStatus;
+
+
+#define STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS 0x0001
+#define STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS 0x0002
+#define STUN_AGENT_USAGE_USE_FINGERPRINT 0x0004
+#define STUN_AGENT_USAGE_ADD_SERVER 0x0008
+#define STUN_AGENT_USAGE_IGNORE_CREDENTIALS 0x000F
+
+
+typedef struct {
+ stun_transid_t id;
+ stun_method_t method;
+ uint8_t *key;
+ size_t key_len;
+ bool valid;
+} StunAgentSavedIds;
+
+struct stun_agent_t {
+ StunCompatibility compatibility;
+ StunAgentSavedIds sent_ids[STUN_AGENT_MAX_SAVED_IDS];
+ uint16_t *known_attributes;
+ uint32_t usage_flags;
+};
+
+typedef bool (*StunMessageIntegrityValidate) (StunAgent *agent,
+ StunMessage *message, uint8_t *username, uint16_t username_len,
+ uint8_t **password, size_t *password_len, void *user_data);
+
+
+void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes,
+ StunCompatibility compatibility, uint32_t usage_flags);
+StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
+ const uint8_t *buffer, size_t buffer_len,
+ StunMessageIntegrityValidate validater, void * validater_data);
+bool stun_agent_init_request (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, stun_method_t m);
+bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, stun_method_t m);
+bool stun_agent_init_response (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, stun_method_t m, StunMessage *request);
+bool stun_agent_init_error (StunAgent *agent, StunMessage *msg,
+ uint8_t *buffer, size_t buffer_len, StunMessage *request,
+ stun_error_t err);
+size_t stun_agent_build_unknown_attributes_error (StunAgent *agent,
+ StunMessage *msg, uint8_t *buffer, size_t buffer_len, StunMessage *request);
+size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
+ uint8_t *key, size_t key_len);
+
+#endif /* _STUN_AGENT_H */
diff --git a/stun/stuncrc32.c b/stun/stuncrc32.c
index 0d11475..3d1e253 100644
--- a/stun/stuncrc32.c
+++ b/stun/stuncrc32.c
@@ -87,7 +87,7 @@
# include <config.h>
#endif
-#include "crc32.h"
+#include "stuncrc32.h"
static const uint32_t crc32_tab[] = {
diff --git a/stun/stunhmac.c b/stun/stunhmac.c
index 7aa5f96..edfec86 100644
--- a/stun/stunhmac.c
+++ b/stun/stunhmac.c
@@ -45,7 +45,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
-#include "stun-msg.h"
+#include "stunmessage.h"
#include "stunhmac.h"
#include <string.h>
diff --git a/stun/stunhmac.h b/stun/stunhmac.h
index 1ece62f..b4fa833 100644
--- a/stun/stunhmac.h
+++ b/stun/stunhmac.h
@@ -35,6 +35,8 @@
#ifndef _STUN_HMAC_H
#define _STUN_HMAC_H
+#include "stunmessage.h"
+
/**
* Computes the MESSAGE-INTEGRITY hash of a STUN message.
* @param msg pointer to the STUN message
@@ -61,4 +63,4 @@ void stun_hash_creds (const char *realm, const char *login, const char *pw,
void stun_make_transid (stun_transid_t id);
-/* _STUN_HMAC_H */
+#endif /* _STUN_HMAC_H */
diff --git a/stun/stunmessage.c b/stun/stunmessage.c
index ba1de5d..eac9f4a 100644
--- a/stun/stunmessage.c
+++ b/stun/stunmessage.c
@@ -61,12 +61,8 @@ bool stun_message_init (StunMessage *msg, stun_class_t c, stun_method_t m,
memset (msg->buffer, 0, 4);
stun_set_type (msg->buffer, c, m);
- if (msg->buffer != id)
- {
- uint32_t cookie = htonl (STUN_COOKIE);
- memcpy (msg->buffer + 4, &cookie, sizeof (cookie));
- memcpy (msg->buffer + 8, id, 12);
- }
+ memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS,
+ id, sizeof (STUN_MESSAGE_TRANS_ID_LEN));
return TRUE;
}
@@ -107,12 +103,12 @@ stun_message_find (const StunMessage *msg, stun_attr_type_t type,
/* Look for and ignore misordered attributes */
switch (atype)
{
- case STUN_MESSAGE_INTEGRITY:
+ case STUN_ATTRIBUTE_MESSAGE_INTEGRITY:
/* Only fingerprint may come after M-I */
- if (type == STUN_FINGERPRINT)
+ if (type == STUN_ATTRIBUTE_FINGERPRINT)
break;
- case STUN_FINGERPRINT:
+ case STUN_ATTRIBUTE_FINGERPRINT:
/* Nothing may come after FPR */
return NULL;
}
@@ -273,10 +269,10 @@ stun_message_find_xor_addr (const StunMessage *msg, stun_attr_type_t type,
return stun_xor_address (msg, addr, *addrlen);
}
-int stun_message_find_errno (const StunMessage *msg, int *restrict code)
+int stun_message_find_error (const StunMessage *msg, int *restrict code)
{
uint16_t alen;
- const uint8_t *ptr = stun_message_find (msg, STUN_ERROR_CODE, &alen);
+ const uint8_t *ptr = stun_message_find (msg, STUN_ATTRIBUTE_ERROR_CODE, &alen);
uint8_t class, number;
if (ptr == NULL)
@@ -319,7 +315,7 @@ stun_message_append (StunMessage *msg, stun_attr_type_t type, size_t length)
a = stun_setw (a, type);
/* NOTE: If cookie is not present, we need to force the attribute length
* to a multiple of 4 for compatibility with old RFC3489 */
- a = stun_setw (a, stun_has_cookie (msg->buffer) ? length : stun_align (length));
+ a = stun_setw (a, stun_has_cookie (msg) ? length : stun_align (length));
mlen += 4 + length;
/* Add padding if needed */
@@ -473,7 +469,7 @@ stun_message_append_error (StunMessage *msg, stun_error_t code)
size_t len = strlen (str);
div_t d = div (code, 100);
- uint8_t *ptr = stun_message_append (msg, STUN_ERROR_CODE, 4 + len);
+ uint8_t *ptr = stun_message_append (msg, STUN_ATTRIBUTE_ERROR_CODE, 4 + len);
if (ptr == NULL)
return ENOBUFS;
@@ -484,7 +480,7 @@ stun_message_append_error (StunMessage *msg, stun_error_t code)
return 0;
}
-bool stun_message_is_valid (const uint8_t *msg, size_t length)
+int stun_message_validate_buffer_length (const uint8_t *msg, size_t length)
{
size_t mlen;
size_t len;
@@ -492,19 +488,19 @@ bool stun_message_is_valid (const uint8_t *msg, size_t length)
if (length < 1)
{
stun_debug ("STUN error: No data!\n");
- return FALSE;
+ return STUN_MESSAGE_BUFFER_INVALID;
}
if (msg[0] >> 6)
{
stun_debug ("STUN error: RTP or other non-protocol packet!\n");
- return FALSE; // RTP or other non-STUN packet
+ return STUN_MESSAGE_BUFFER_INVALID; // RTP or other non-STUN packet
}
if (length < 4)
{
stun_debug ("STUN error: Incomplete STUN message header!\n");
- return FALSE;
+ return STUN_MESSAGE_BUFFER_INCOMPLETE;
}
mlen = stun_getw (msg + STUN_MESSAGE_LENGTH_POS) +
@@ -513,14 +509,14 @@ bool stun_message_is_valid (const uint8_t *msg, size_t length)
if (stun_padding (mlen))
{
stun_debug ("STUN error: Invalid message length: %u!\n", (unsigned)mlen);
- return FALSE; // wrong padding
+ return STUN_MESSAGE_BUFFER_INVALID; // wrong padding
}
if (length < mlen)
{
stun_debug ("STUN error: Incomplete message: %u of %u bytes!\n",
(unsigned)length, (unsigned)mlen);
- return FALSE; // partial message
+ return STUN_MESSAGE_BUFFER_INCOMPLETE; // partial message
}
msg += 20;
@@ -539,12 +535,54 @@ bool stun_message_is_valid (const uint8_t *msg, size_t length)
{
stun_debug ("STUN error: %u instead of %u bytes for attribute!\n",
(unsigned)len, (unsigned)alen);
- return -1; // no room for attribute value + padding
+ return STUN_MESSAGE_BUFFER_INVALID; // no room for attribute value + padding
}
len -= alen;
msg += 4 + alen;
}
- return mlen == length;
+ return mlen;
+}
+
+/**
+ * copies STUN message transaction ID
+ */
+void stun_message_id (const StunMessage *msg, stun_transid_t id)
+{
+ memcpy (id, msg->buffer + STUN_MESSAGE_TRANS_ID_POS, STUN_MESSAGE_TRANS_ID_LEN);
+}
+
+/**
+ * @return STUN message method (value from 0 to 0xfff)
+ */
+stun_method_t stun_message_get_method (const StunMessage *msg)
+{
+ uint16_t t = stun_getw (msg->buffer);
+ return (stun_method_t)(((t & 0x3e00) >> 2) | ((t & 0x00e0) >> 1) |
+ (t & 0x000f));
+}
+
+
+/**
+ * @return STUN message class in host byte order (value from 0 to 3)
+ */
+stun_class_t stun_message_get_class (const StunMessage *msg)
+{
+ uint16_t t = stun_getw (msg->buffer);
+ return (stun_class_t)(((t & 0x0100) >> 7) | ((t & 0x0010) >> 4));
+}
+
+/**
+ * Checks if an attribute is present within a STUN message.
+ *
+ * @param msg valid STUN message
+ * @param type STUN attribute type (host byte order)
+ *
+ * @return whether there is a MESSAGE-INTEGRITY attribute
+ */
+bool stun_message_has_attribute (const StunMessage *msg, stun_attr_type_t type)
+{
+ uint16_t dummy;
+ return stun_message_find (msg, type, &dummy) != NULL;
}
diff --git a/stun/stunmessage.h b/stun/stunmessage.h
index fdcc8c7..8428d32 100644
--- a/stun/stunmessage.h
+++ b/stun/stunmessage.h
@@ -41,12 +41,7 @@
#include <stdbool.h>
#include "constants.h"
-typedef struct {
- uint8_t *buffer;
- size_t buffer_len;
- bool message_id_validated;
-} StunMessage;
-
+typedef struct stun_message_t StunMessage;
/* Message classes */
typedef enum
@@ -78,65 +73,65 @@ typedef enum
{
/* Mandatory attributes */
/* 0x0000 */ /* reserved */
- STUN_MAPPED_ADDRESS=0x0001, /* RFC3489bis-11 */
- STUN_OLD_RESPONSE_ADDRESS=0x0002, /* old RFC3489 */
- STUN_OLD_CHANGE_REQUEST=0x0003, /* old RFC3489 */
- STUN_OLD_SOURCE_ADDRESS=0x0004, /* old RFC3489 */
- STUN_OLD_CHANGED_ADDRESS=0x0005, /* old RFC3489 */
- STUN_USERNAME=0x0006, /* RFC3489bis-11 */
- STUN_OLD_PASSWORD=0x0007, /* old RFC3489 */
- STUN_MESSAGE_INTEGRITY=0x0008, /* RFC3489bis-11 */
- STUN_ERROR_CODE=0x0009, /* RFC3489bis-11 */
- STUN_UNKNOWN_ATTRIBUTES=0x000A, /* RFC3489bis-11 */
- STUN_OLD_REFLECTED_FROM=0x000B, /* old RFC3489 */
+ STUN_ATTRIBUTE_MAPPED_ADDRESS=0x0001, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_OLD_RESPONSE_ADDRESS=0x0002, /* old RFC3489 */
+ STUN_ATTRIBUTE_OLD_CHANGE_REQUEST=0x0003, /* old RFC3489 */
+ STUN_ATTRIBUTE_OLD_SOURCE_ADDRESS=0x0004, /* old RFC3489 */
+ STUN_ATTRIBUTE_OLD_CHANGED_ADDRESS=0x0005, /* old RFC3489 */
+ STUN_ATTRIBUTE_USERNAME=0x0006, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_OLD_PASSWORD=0x0007, /* old RFC3489 */
+ STUN_ATTRIBUTE_MESSAGE_INTEGRITY=0x0008, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_ERROR_CODE=0x0009, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES=0x000A, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_OLD_REFLECTED_FROM=0x000B, /* old RFC3489 */
/* 0x000C */ /* reserved */
- STUN_LIFETIME=0x000D, /* TURN-04 */
+ STUN_ATTRIBUTE_LIFETIME=0x000D, /* TURN-04 */
/* 0x000E */ /* reserved */
/* 0x000F */ /* reserved */
- STUN_BANDWIDTH=0x0010, /* TURN-04 */
+ STUN_ATTRIBUTE_BANDWIDTH=0x0010, /* TURN-04 */
/* 0x0011 */ /* reserved */
- STUN_REMOTE_ADDRESS=0x0012, /* TURN-04 */
- STUN_DATA=0x0013, /* TURN-04 */
- STUN_REALM=0x0014, /* RFC3489bis-11 */
- STUN_NONCE=0x0015, /* RFC3489bis-11 */
- STUN_RELAY_ADDRESS=0x0016, /* TURN-04 */
- STUN_REQUESTED_ADDRESS_TYPE=0x0017, /* TURN-IPv6-03 */
- STUN_REQUESTED_PORT_PROPS=0x0018, /* TURN-04 */
- STUN_REQUESTED_TRANSPORT=0x0019, /* TURN-04 */
+ STUN_ATTRIBUTE_REMOTE_ADDRESS=0x0012, /* TURN-04 */
+ STUN_ATTRIBUTE_DATA=0x0013, /* TURN-04 */
+ STUN_ATTRIBUTE_REALM=0x0014, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_NONCE=0x0015, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_RELAY_ADDRESS=0x0016, /* TURN-04 */
+ STUN_ATTRIBUTE_REQUESTED_ADDRESS_TYPE=0x0017, /* TURN-IPv6-03 */
+ STUN_ATTRIBUTE_REQUESTED_PORT_PROPS=0x0018, /* TURN-04 */
+ STUN_ATTRIBUTE_REQUESTED_TRANSPORT=0x0019, /* TURN-04 */
/* 0x001A */ /* reserved */
/* 0x001B */ /* reserved */
/* 0x001C */ /* reserved */
/* 0x001D */ /* reserved */
/* 0x001E */ /* reserved */
/* 0x001F */ /* reserved */
- STUN_XOR_MAPPED_ADDRESS=0x0020, /* RFC3489bis-11 */
- STUN_TIMER_VAL=0x0021, /* TURN-04 */
- STUN_REQUESTED_IP=0x0022, /* TURN-04 */
- STUN_CONNECT_STAT=0x0023, /* TURN-04 */
- STUN_PRIORITY=0x0024, /* ICE-18 */
- STUN_USE_CANDIDATE=0x0025, /* ICE-18 */
+ STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS=0x0020, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_TIMER_VAL=0x0021, /* TURN-04 */
+ STUN_ATTRIBUTE_REQUESTED_IP=0x0022, /* TURN-04 */
+ STUN_ATTRIBUTE_CONNECT_STAT=0x0023, /* TURN-04 */
+ STUN_ATTRIBUTE_PRIORITY=0x0024, /* ICE-18 */
+ STUN_ATTRIBUTE_USE_CANDIDATE=0x0025, /* ICE-18 */
/* 0x0026 */ /* reserved */
/* 0x0027 */ /* reserved */
/* 0x0028 */ /* reserved */
- STUN_XOR_INTERNAL_ADDRESS=0x0029, /* wing-nat-control-04 */
+ STUN_ATTRIBUTE_XOR_INTERNAL_ADDRESS=0x0029, /* wing-nat-control-04 */
/* 0x002A-0x7fff */ /* reserved */
/* Optional attributes */
/* 0x8000-0x8021 */ /* reserved */
- STUN_SERVER=0x8022, /* RFC3489bis-11 */
- STUN_ALTERNATE_SERVER=0x8023, /* RFC3489bis-11 */
- STUN_REFRESH_INTERVAL=0x8024, /* wing-nat-control-04 */
+ STUN_ATTRIBUTE_SERVER=0x8022, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_ALTERNATE_SERVER=0x8023, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_REFRESH_INTERVAL=0x8024, /* wing-nat-control-04 */
/* 0x8025 */ /* reserved */
/* 0x8026 */ /* reserved */
/* 0x8027 */ /* reserved */
- STUN_FINGERPRINT=0x8028, /* RFC3489bis-11 */
- STUN_ICE_CONTROLLED=0x8029, /* ICE-18 */
- STUN_ICE_CONTROLLING=0x802A, /* ICE-18 */
+ STUN_ATTRIBUTE_FINGERPRINT=0x8028, /* RFC3489bis-11 */
+ STUN_ATTRIBUTE_ICE_CONTROLLED=0x8029, /* ICE-18 */
+ STUN_ATTRIBUTE_ICE_CONTROLLING=0x802A, /* ICE-18 */
/* 0x802B-0xFFFF */ /* reserved */
} stun_attr_type_t;
-typedef uint8_t stun_transid_t[12];
+typedef uint8_t stun_transid_t[STUN_MESSAGE_TRANS_ID_LEN];
/**
@@ -145,32 +140,41 @@ typedef uint8_t stun_transid_t[12];
*/
typedef enum
{
- STUN_TRY_ALTERNATE=300, /* RFC3489bis-11 */
- STUN_BAD_REQUEST=400, /* RFC3489bis-11 */
- STUN_UNAUTHORIZED=401, /* RFC3489bis-11 */
- STUN_UNKNOWN_ATTRIBUTE=420, /* RFC3489bis-11 */
- STUN_NO_BINDING=437, /* TURN-04 */
- STUN_STALE_NONCE=438, /* RFC3489bis-11 */
- STUN_ACT_DST_ALREADY=439, /* TURN-04 */
- STUN_UNSUPP_FAMILY=440, /* TURN-IPv6-03 */
- STUN_UNSUPP_TRANSPORT=442, /* TURN-04 */
- STUN_INVALID_IP=443, /* TURN-04 */
- STUN_INVALID_PORT=444, /* TURN-04 */
- STUN_OP_TCP_ONLY=445, /* TURN-04 */
- STUN_CONN_ALREADY=446, /* TURN-04 */
- STUN_ALLOC_OVER_QUOTA=486, /* TURN-04 */
- STUN_ROLE_CONFLICT=487, /* ICE-18 */
- STUN_SERVER_ERROR=500, /* RFC3489bis-11 */
- STUN_SERVER_CAPACITY=507, /* TURN-04 */
+ STUN_ERROR_TRY_ALTERNATE=300, /* RFC3489bis-11 */
+ STUN_ERROR_BAD_REQUEST=400, /* RFC3489bis-11 */
+ STUN_ERROR_UNAUTHORIZED=401, /* RFC3489bis-11 */
+ STUN_ERROR_UNKNOWN_ATTRIBUTE=420, /* RFC3489bis-11 */
+ STUN_ERROR_NO_BINDING=437, /* TURN-04 */
+ STUN_ERROR_STALE_NONCE=438, /* RFC3489bis-11 */
+ STUN_ERROR_ACT_DST_ALREADY=439, /* TURN-04 */
+ STUN_ERROR_UNSUPP_FAMILY=440, /* TURN-IPv6-03 */
+ STUN_ERROR_UNSUPP_TRANSPORT=442, /* TURN-04 */
+ STUN_ERROR_INVALID_IP=443, /* TURN-04 */
+ STUN_ERROR_INVALID_PORT=444, /* TURN-04 */
+ STUN_ERROR_OP_TCP_ONLY=445, /* TURN-04 */
+ STUN_ERROR_CONN_ALREADY=446, /* TURN-04 */
+ STUN_ERROR_ALLOC_OVER_QUOTA=486, /* TURN-04 */
+ STUN_ERROR_ROLE_CONFLICT=487, /* ICE-18 */
+ STUN_ERROR_SERVER_ERROR=500, /* RFC3489bis-11 */
+ STUN_ERROR_SERVER_CAPACITY=507, /* TURN-04 */
STUN_ERROR_MAX=699
} stun_error_t;
+#include "stunagent.h"
#include "stunhmac.h"
#include "stuncrc32.h"
#include "utils.h"
#include "stun3489bis.h"
+struct stun_message_t {
+ StunAgent *agent;
+ uint8_t *buffer;
+ size_t buffer_len;
+ uint8_t *key;
+ size_t key_len;
+};
+
/**
* Initializes a STUN message buffer, with no attributes.
* @param c STUN message class (host byte order)
@@ -281,7 +285,7 @@ int stun_message_find_xor_addr (const StunMessage *msg, stun_attr_type_t type,
struct sockaddr *restrict addr, socklen_t *restrict addrlen);
-int stun_message_find_errno (const StunMessage *msg, int *restrict code);
+int stun_message_find_error (const StunMessage *msg, int *restrict code);
void *stun_message_append (StunMessage *msg, stun_attr_type_t type,
size_t length);
@@ -368,7 +372,16 @@ int stun_message_append_xor_addr (StunMessage * msg, stun_attr_type_t type,
*/
int stun_message_append_error (StunMessage * msg, stun_error_t code);
-bool stun_message_is_valid (const uint8_t *msg, size_t length);
+#define STUN_MESSAGE_BUFFER_INCOMPLETE 0
+#define STUN_MESSAGE_BUFFER_INVALID -1
+
+
+int stun_message_validate_buffer_length (const uint8_t *msg, size_t length);
+
+void stun_message_id (const StunMessage *msg, stun_transid_t id);
+stun_class_t stun_message_get_class (const StunMessage *msg);
+stun_method_t stun_message_get_method (const StunMessage *msg);
+bool stun_message_has_attribute (const StunMessage *msg, stun_attr_type_t type);
#endif /* _STUN_MESSAGE_H */
diff --git a/stun/stunrecv.c b/stun/stunrecv.c
index 771ec19..7ca097d 100644
--- a/stun/stunrecv.c
+++ b/stun/stunrecv.c
@@ -48,446 +48,6 @@
#include <errno.h>
#include <netinet/in.h>
-ssize_t stun_validate (const uint8_t *msg, size_t len)
-{
- size_t mlen;
-
- if (len < 1)
- {
- DBG ("STUN error: No data!\n");
- return 0;
- }
-
- if (msg[0] >> 6)
- {
- DBG ("STUN error: RTP or other non-protocol packet!\n");
- return -1; // RTP or other non-STUN packet
- }
-
- if (len < 4)
- {
- DBG ("STUN error: Incomplete STUN message header!\n");
- return 0;
- }
-
- mlen = 20u + stun_length (msg);
- if (stun_padding (mlen))
- {
- DBG ("STUN error: Invalid message length: %u!\n", (unsigned)mlen);
- return -1; // wrong padding
- }
-
- if (len < mlen)
- {
- DBG ("STUN error: Incomplete message: %u of %u bytes!\n",
- (unsigned)len, (unsigned)mlen);
- return 0; // partial message
- }
-
- msg += 20;
- len = mlen - 20;
-
- /* from then on, we know we have the entire packet in buffer */
- while (len > 0)
- {
- size_t alen = stun_align (stun_length (msg));
-
- /* thanks to padding check, if (end > msg) then there is not only one
- * but at least 4 bytes left */
- assert (len >= 4);
- len -= 4;
-
- if (len < alen)
- {
- DBG ("STUN error: %u instead of %u bytes for attribute!\n",
- (unsigned)len, (unsigned)alen);
- return -1; // no room for attribute value + padding
- }
-
- len -= alen;
- msg += 4 + alen;
- }
-
- return mlen;
-}
-
-
-const void *
-stun_find (const uint8_t *restrict msg, stun_attr_type_t type,
- uint16_t *restrict palen)
-{
- size_t length = stun_length (msg);
-
- assert (stun_valid (msg));
- assert (palen != NULL);
-
- msg += 20;
-
- while (length > 0)
- {
- size_t alen = stun_length (msg);
- uint16_t atype = stun_getw (msg);
-
- assert (length >= 4);
-
- length -= 4;
- msg += 4;
-
- assert (length >= stun_align (alen));
- if (atype == type)
- {
- assert (alen <= 0xffff);
- *palen = alen;
- return msg;
- }
-
- /* Look for and ignore misordered attributes */
- switch (atype)
- {
- case STUN_MESSAGE_INTEGRITY:
- /* Only fingerprint may come after M-I */
- if (type == STUN_FINGERPRINT)
- break;
-
- case STUN_FINGERPRINT:
- /* Nothing may come after FPR */
- return NULL;
- }
-
- alen = stun_align (alen);
- length -= alen;
- msg += alen;
- }
-
- return NULL;
-}
-
-
-int stun_find_flag (const uint8_t *msg, stun_attr_type_t type)
-{
- const void *ptr;
- uint16_t len;
-
- ptr = stun_find (msg, type, &len);
- if (ptr == NULL)
- return ENOENT;
- return (len == 0) ? 0 : EINVAL;
-}
-
-
-int
-stun_find32 (const uint8_t *restrict msg, stun_attr_type_t type,
- uint32_t *restrict pval)
-{
- const void *ptr;
- uint16_t len;
-
- ptr = stun_find (msg, type, &len);
- if (ptr == NULL)
- return ENOENT;
-
- if (len == 4)
- {
- uint32_t val;
-
- memcpy (&val, ptr, sizeof (val));
- *pval = ntohl (val);
- return 0;
- }
- return EINVAL;
-}
-
-
-int stun_find64 (const uint8_t *msg, stun_attr_type_t type, uint64_t *pval)
-{
- const void *ptr;
- uint16_t len;
-
- ptr = stun_find (msg, type, &len);
- if (ptr == NULL)
- return ENOENT;
-
- if (len == 8)
- {
- uint32_t tab[2];
-
- memcpy (tab, ptr, sizeof (tab));
- *pval = ((uint64_t)ntohl (tab[0]) << 32) | ntohl (tab[1]);
- return 0;
- }
- return EINVAL;
-}
-
-
-int stun_find_string (const uint8_t *restrict msg, stun_attr_type_t type,
- char *buf, size_t buflen)
-{
- const unsigned char *ptr;
- uint16_t len;
-
- ptr = stun_find (msg, type, &len);
- if (ptr == NULL)
- return ENOENT;
-
- if (len >= buflen)
- return ENOBUFS;
-
- memcpy (buf, ptr, len);
- buf[len] = '\0';
- return 0;
-}
-
-
-int
-stun_find_addr (const uint8_t *restrict msg, stun_attr_type_t type,
- struct sockaddr *restrict addr, socklen_t *restrict addrlen)
-{
- const uint8_t *ptr;
- uint16_t len;
-
- ptr = stun_find (msg, type, &len);
- if (ptr == NULL)
- return ENOENT;
-
- if (len < 4)
- return EINVAL;
-
- assert (addrlen != NULL);
- switch (ptr[1])
- {
- case 1:
- {
- struct sockaddr_in *ip4 = (struct sockaddr_in *)addr;
- if ((*addrlen < sizeof (*ip4)) || (len != 8))
- {
- *addrlen = sizeof (*ip4);
- return EINVAL;
- }
-
- memset (ip4, 0, *addrlen);
- ip4->sin_family = AF_INET;
-#ifdef HAVE_SA_LEN
- ip4->sin_len =
-#endif
- *addrlen = sizeof (*ip4);
- memcpy (&ip4->sin_port, ptr + 2, 2);
- memcpy (&ip4->sin_addr, ptr + 4, 4);
- return 0;
- }
-
- case 2:
- {
- struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)addr;
- if ((*addrlen < sizeof (*ip6)) || (len != 20))
- {
- *addrlen = sizeof (*ip6);
- return EINVAL;
- }
-
- memset (ip6, 0, *addrlen);
- ip6->sin6_family = AF_INET6;
-#ifdef HAVE_SA_LEN
- ip6->sin6_len =
-#endif
- *addrlen = sizeof (*ip6);
- memcpy (&ip6->sin6_port, ptr + 2, 2);
- memcpy (&ip6->sin6_addr, ptr + 4, 16);
- return 0;
- }
- }
-
- return EAFNOSUPPORT;
-}
-
-
-int stun_xor_address (const uint8_t *restrict msg,
- struct sockaddr *restrict addr, socklen_t addrlen)
-{
- switch (addr->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *ip4 = (struct sockaddr_in *)addr;
- if (addrlen < sizeof (*ip4))
- return EINVAL;
-
- ip4->sin_port ^= htons (STUN_COOKIE >> 16);
- ip4->sin_addr.s_addr ^= htonl (STUN_COOKIE);
- return 0;
- }
-
- case AF_INET6:
- {
- struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)addr;
- unsigned short i;
-
- if (addrlen < sizeof (*ip6))
- return EINVAL;
-
- ip6->sin6_port ^= htons (STUN_COOKIE >> 16);
- for (i = 0; i < 16; i++)
- ip6->sin6_addr.s6_addr[i] ^= ((uint8_t *)msg)[4 + i];
- return 0;
- }
- }
- return EAFNOSUPPORT;
-}
-
-
-int
-stun_find_xor_addr (const uint8_t *restrict msg, stun_attr_type_t type,
- struct sockaddr *restrict addr,
- socklen_t *restrict addrlen)
-{
- int val = stun_find_addr (msg, type, addr, addrlen);
- if (val)
- return val;
-
- return stun_xor_address (msg, addr, *addrlen);
-}
-
-
-/**
- * Compares the length and content of an attribute.
- *
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param data pointer to value to compare with
- * @param len byte length of the value
- * @return 0 in case of match, ENOENT if attribute was not found,
- * EINVAL if it did not match (different length, or same length but
- * different content)
- */
-int stun_memcmp (const uint8_t *msg, stun_attr_type_t type,
- const void *data, size_t len)
-{
- uint16_t alen;
- const void *ptr = stun_find (msg, type, &alen);
- if (ptr == NULL)
- return ENOENT;
-
- if ((len != alen) || memcmp (ptr, data, len))
- return EINVAL;
- return 0;
-}
-
-
-/**
- * Compares the content of an attribute with a string.
- * @param msg valid STUN message buffer
- * @param type STUN attribute type (host byte order)
- * @param str string to compare with
- * @return 0 in case of match, ENOENT if attribute was not found,
- * EINVAL if it did not match
- */
-int stun_strcmp (const uint8_t *msg, stun_attr_type_t type, const char *str)
-{
- return stun_memcmp (msg, type, str, strlen (str));
-}
-
-
-bool stun_has_cookie (const uint8_t *msg)
-{
- uint32_t cookie = htonl (STUN_COOKIE);
- return memcmp (msg + 4, &cookie, sizeof (cookie)) == 0;
-}
-
-
-bool stun_demux (const uint8_t *msg)
-{
- const uint8_t *fpr;
- uint32_t crc32;
- uint16_t fprlen;
-
- assert (stun_valid (msg));
-
- /* Checks cookie */
- if (!stun_has_cookie (msg))
- {
- DBG ("STUN demux error: no cookie!\n");
- return 0;
- }
-
- /* Looks for FINGERPRINT */
- fpr = stun_find (msg, STUN_FINGERPRINT, &fprlen);
- if ((fpr == NULL) || (fprlen != 4))
- {
- DBG ("STUN demux error: no FINGERPRINT attribute!\n");
- return 0;
- }
-
- /* Checks FINGERPRINT */
- crc32 = htonl (stun_fingerprint (msg, fpr + 4 - msg));
- if (memcmp (fpr, &crc32, 4))
- {
- DBG ("STUN demux error: bad fingerprint: 0x%08x, expected: 0x%08x!\n",
- (fpr[0] << 24) | (fpr[1] << 16) | (fpr[2] << 8) | fpr[3],
- stun_fingerprint (msg, fpr + 4 - msg));
- return 0;
- }
-
- DBG ("STUN demux: OK!\n");
- return 1;
-}
-
-
-/**
- * @param msg valid STUN message
- * @param key HMAC shared secret key pointer
- * @param keylen HMAC shared secret key byte length
- * @return 0 if the message integrity has been successfully verified with the
- * specified key. EPERM if the hash was incorrect. ENOENT if there was no
- * valid MESSAGE-INTEGRITY attribute.
- */
-int
-stun_verify_key (const uint8_t *msg, const void *key, size_t keylen)
-{
- const uint8_t *hash;
- uint8_t sha[20];
- uint16_t hlen;
-
- assert (msg != NULL);
- assert ((keylen == 0) || (key != NULL));
-
- hash = stun_find (msg, STUN_MESSAGE_INTEGRITY, &hlen);
- if ((hash == NULL) || (hlen != 20))
- {
- DBG ("STUN auth error: no MESSAGE-INTEGRITY attribute!\n");
- return ENOENT;
- }
-
- stun_sha1 (msg, hash + 20 - msg, sha, key, keylen);
- DBG (" Message HMAC-SHA1 fingerprint:"
- "\n key : ");
- DBG_bytes (key, keylen);
- DBG ("\n expected: ");
- DBG_bytes (sha, sizeof (sha));
- DBG ("\n received: ");
- DBG_bytes (hash, sizeof (sha));
- DBG ("\n");
-
- if (memcmp (sha, hash, sizeof (sha)))
- {
- DBG ("STUN auth error: SHA1 fingerprint mismatch!\n");
- return EPERM;
- }
-
- DBG ("STUN auth: OK!\n");
- return 0;
-}
-
-
-/**
- * @param msg valid STUN message
- * @param pw nul-terminated HMAC shared secret password
- * @return 0 if the message integrity has been successfully verified with the
- * specified key. EPERM if the hash was incorrect. ENOENT if there was no
- * valid MESSAGE-INTEGRITY attribute.
- */
-int stun_verify_password (const uint8_t *msg, const char *pw)
-{
- return stun_verify_key (msg, pw, strlen (pw));
-}
/**
* @param msg valid STUN message
@@ -529,130 +89,3 @@ int stun_verify_username (const uint8_t *msg, const char *local_ufrag, uint32_t
return 0;
}
-
-static
-int stun_find_errno (const uint8_t *restrict msg, int *restrict code)
-{
- uint16_t alen;
- const uint8_t *ptr = stun_find (msg, STUN_ERROR_CODE, &alen);
- uint8_t class, number;
-
- if (ptr == NULL)
- return ENOENT;
- if (alen < 4)
- return EINVAL;
-
- class = ptr[2] & 0x7;
- number = ptr[3];
- if ((class < 3) || (class > 6) || (number > 99))
- return EINVAL;
-
- *code = (class * 100) + number;
- return 0;
-}
-
-
-/**
- * @param msg valid STUN message
- * @param method STUN method number (host byte order)
- * @param id STUN transaction id
- * @param key HMAC key, or NULL if there is no authentication
- * @param keylen HMAC key byte length, must be 0 if @a key is NULL
- * @param error [OUT] set to -1 if the response is not an error,
- * to the error code ([0..799]) if it is an error response.
- *
- * @return true if and only if the message is a response or an error response
- * with the STUN cookie and specified method and transaction identifier.
- */
-static bool
-stun_match_answer (const uint8_t *msg, stun_method_t method,
- const uint8_t *id, const uint8_t *key, size_t keylen,
- int *restrict error)
-{
- assert (stun_valid (msg));
- assert (error != NULL);
-
- if ((stun_get_method (msg) != method) /* wrong request type */
- || !stun_has_cookie (msg) /* response to old-style request */
- || memcmp (msg + 8, id, 12)) /* wrong transaction ID */
- return false;
-
- switch (stun_get_class (msg))
- {
- case STUN_REQUEST:
- case STUN_INDICATION:
- return false;
-
- case STUN_RESPONSE:
- *error = -1;
- break;
-
- case STUN_ERROR:
- if (stun_find_errno (msg, error) != 0)
- return false; // missing ERROR-CODE: ignore message
- break;
- }
-
- /* If a shared secret exists, verify the message hash.
- * If there is no shared secret, verify there is no hash at all. */
- if (key != NULL)
- {
- /* FIXME: 401 errors do not have MESSAGE-INTEGRITY, so that we
- * currently ignore them. */
- if (stun_verify_key (msg, key, keylen) != 0)
- return false;
- }/*
- else
- {
- if (stun_present (msg, STUN_MESSAGE_INTEGRITY))
- return false;
- }*/
-
- return true;
-}
-
-
-bool stun_match_messages (const uint8_t *restrict resp,
- const uint8_t *restrict req,
- const uint8_t *key, size_t keylen,
- int *restrict error)
-{
- assert (stun_valid (resp));
- assert (stun_valid (req));
- assert ((stun_get_class (req) >> 1) == 0);
-
- return stun_match_answer (resp, stun_get_method (req),
- stun_id (req), key, keylen, error);
-}
-
-
-unsigned
-stun_find_unknown (const uint8_t *restrict msg, uint16_t *restrict list,
- unsigned max)
-{
- unsigned count = 0;
- uint16_t len = stun_length (msg);
-
- assert (stun_valid (msg));
- msg += 20;
-
- while ((len > 0) && (count < max))
- {
- size_t alen = stun_align (stun_length (msg));
- uint16_t atype = stun_getw (msg);
-
- msg += 4 + alen;
- assert (len >= (4 + alen));
- len -= 4 + alen;
-
- if (!stun_optional (atype) && stun_is_unknown (atype))
- {
- DBG ("STUN unknown: attribute 0x%04x(%u bytes)\n",
- (unsigned)atype, (unsigned)alen);
- list[count++] = atype;
- }
- }
-
- DBG ("STUN unknown: %u mandatory attribute(s)!\n", count);
- return count;
-}
diff --git a/stun/stunsend.c b/stun/stunsend.c
index d245b9e..6b08691 100644
--- a/stun/stunsend.c
+++ b/stun/stunsend.c
@@ -50,484 +50,3 @@
#include <netinet/in.h>
-static
-void *stun_setw (uint8_t *ptr, uint16_t value)
-{
- *ptr++ = value >> 8;
- *ptr++ = value & 0xff;
- return ptr;
-}
-
-
-static
-void stun_set_type (uint8_t *h, stun_class_t c, stun_method_t m)
-{
- assert (c < 4);
- assert (m < (1 << 12));
-
- h[0] = (c >> 1) | ((m >> 6) & 0x3e);
- h[1] = ((c << 4) & 0x10) | ((m << 1) & 0xe0) | (m & 0x0f);
-
- assert (stun_getw (h) < (1 << 14));
- assert (stun_get_class (h) == c);
- assert (stun_get_method (h) == m);
-}
-
-
-/**
- * Initializes a STUN message buffer, with no attributes.
- * @param c STUN message class (host byte order)
- * @param m STUN message method (host byte order)
- * @param id 16-bytes transaction ID
- */
-static void stun_init (uint8_t *msg, stun_class_t c, stun_method_t m,
- const stun_transid_t id)
-{
- memset (msg, 0, 4);
- stun_set_type (msg, c, m);
- msg += 8;
-
- if (msg != id)
- {
- uint32_t cookie = htonl (STUN_COOKIE);
- memcpy (msg - 4, &cookie, sizeof (cookie));
- memcpy (msg, id, 12);
- }
-}
-
-
-void stun_init_request (uint8_t *req, stun_method_t m)
-{
- stun_transid_t id;
-
- stun_make_transid (id);
- stun_init (req, STUN_REQUEST, m, id);
-}
-
-
-void stun_init_indication (uint8_t *req, stun_method_t m)
-{
- stun_transid_t id;
-
- stun_make_transid (id);
- stun_init (req, STUN_INDICATION, m, id);
-}
-
-
-/**
- * Reserves room for appending an attribute to an unfinished STUN message.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type message type (host byte order)
- * @param length attribute payload byte length
- * @return a pointer to an unitialized buffer of <length> bytes to
- * where the attribute payload must be written, or NULL if there is not
- * enough room in the STUN message buffer. Return value is always on a
- * 32-bits boundary.
- */
-void *
-stun_append (uint8_t *msg, size_t msize, stun_attr_type_t type, size_t length)
-{
- uint8_t *a;
- uint16_t mlen = stun_length (msg);
-
- assert (stun_valid (msg));
- assert (stun_padding (mlen) == 0);
-
- if (msize > STUN_MAXMSG)
- msize = STUN_MAXMSG;
-
- if ((((size_t)mlen) + 24u + length) > msize)
- return NULL;
-
- assert (length < 0xffff);
-
- a = msg + 20u + mlen;
- a = stun_setw (a, type);
- /* NOTE: If cookie is not present, we need to force the attribute length
- * to a multiple of 4 for compatibility with old RFC3489 */
- a = stun_setw (a, stun_has_cookie (msg) ? length : stun_align (length));
-
- mlen += 4 + length;
- /* Add padding if needed */
- memset (a + length, ' ', stun_padding (length));
- mlen += stun_padding (length);
-
- stun_setw (msg + 2, mlen);
- return a;
-}
-
-
-/**
- * Appends an attribute from memory.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param type attribute type (host byte order)
- * @param data memory address to copy payload from
- * @param len attribute payload length
- * @return 0 on success, ENOBUFS on error.
- */
-int
-stun_append_bytes (uint8_t *restrict msg, size_t msize, stun_attr_type_t type,
- const void *data, size_t len)
-{
- void *ptr = stun_append (msg, msize, type, len);
- if (ptr == NULL)
- return ENOBUFS;
-
- memcpy (ptr, data, len);
- return 0;
-}
-
-
-int stun_append_flag (uint8_t *msg, size_t msize, stun_attr_type_t type)
-{
- return stun_append_bytes (msg, msize, type, NULL, 0);
-}
-
-
-int
-stun_append32 (uint8_t *msg, size_t msize, stun_attr_type_t type,
- uint32_t value)
-{
- value = htonl (value);
- return stun_append_bytes (msg, msize, type, &value, 4);
-}
-
-
-int stun_append64 (uint8_t *msg, size_t msize, stun_attr_type_t type,
- uint64_t value)
-{
- uint32_t tab[2];
- tab[0] = htonl ((uint32_t)(value >> 32));
- tab[1] = htonl ((uint32_t)value);
- return stun_append_bytes (msg, msize, type, tab, 8);
-}
-
-
-int
-stun_append_string (uint8_t *restrict msg, size_t msize,
- stun_attr_type_t type, const char *str)
-{
- return stun_append_bytes (msg, msize, type, str, strlen (str));
-}
-
-
-static int stun_append_server (uint8_t *restrict msg, size_t msize, int compat)
-{
- static const char server[] = PACKAGE_STRING;
- assert (strlen (server) < 128);
-
- if (compat == 1)
- return 0;
- else
- return stun_append_string (msg, msize, STUN_SERVER, server);
-}
-
-
-void stun_init_response (uint8_t *ans, size_t msize, const uint8_t *req, int compat)
-{
- assert (stun_valid (req));
- assert (stun_get_class (req) == STUN_REQUEST);
- assert (msize >= 20u);
-
- stun_init (ans, STUN_RESPONSE, stun_get_method (req), stun_id (req));
- /* For RFC3489 compatibility, we cannot assume the cookie */
- memcpy (ans + 4, req + 4, 4);
- (void)stun_append_server (ans, msize, compat);
-}
-
-
-/**
- * @param code host-byte order error code
- * @return a static pointer to a nul-terminated error message string.
- */
-static const char *stun_strerror (stun_error_t code)
-{
- static const struct
- {
- stun_error_t code;
- char phrase[32];
- } tab[] =
- {
- { STUN_TRY_ALTERNATE, "Try alternate server" },
- { STUN_BAD_REQUEST, "Bad request" },
- { STUN_UNAUTHORIZED, "Authorization required" },
- { STUN_UNKNOWN_ATTRIBUTE, "Unknown attribute" },
- /*
- { STUN_STALE_CREDENTIALS, "Authentication expired" },
- { STUN_INTEGRITY_CHECK_FAILURE, "Incorrect username/password" },
- { STUN_MISSING_USERNAME, "Username required" },
- { STUN_USE_TLS, "Secure connection required" },
- { STUN_MISSING_REALM, "Authentication domain required" },
- { STUN_MISSING_NONCE, "Authentication token missing" },
- { STUN_UNKNOWN_USERNAME, "Unknown user name" },
- */
- { STUN_NO_BINDING, "Session expired" },
- { STUN_STALE_NONCE, "Authentication token expired" },
- { STUN_ACT_DST_ALREADY, "Changing remote peer forbidden" },
- { STUN_UNSUPP_TRANSPORT, "Unknown transport protocol" },
- { STUN_INVALID_IP, "Address unavailable" },
- { STUN_INVALID_PORT, "Port unavailable" },
- { STUN_OP_TCP_ONLY, "Invalid operation" },
- { STUN_CONN_ALREADY, "Connection already established" },
- { STUN_ALLOC_OVER_QUOTA, "Quota reached" },
- { STUN_ROLE_CONFLICT, "Role conflict" },
- { STUN_SERVER_ERROR, "Temporary server error" },
- { STUN_SERVER_CAPACITY, "Temporary server congestion" },
- };
- const char *str = "Unknown error";
- size_t i;
-
- for (i = 0; i < (sizeof (tab) / sizeof (tab[0])); i++)
- {
- if (tab[i].code == code)
- {
- str = tab[i].phrase;
- break;
- }
- }
-
- /* Maximum allowed error message length */
- assert (strlen (str) < 128);
- return str;
-}
-
-
-/**
- * Appends an ERROR-CODE attribute.
- * @param msg STUN message buffer
- * @param msize STUN message buffer size
- * @param code STUN host-byte order integer error code
- * @return 0 on success, or ENOBUFS otherwise
- */
-static int
-stun_append_error (uint8_t *restrict msg, size_t msize, stun_error_t code)
-{
- const char *str = stun_strerror (code);
- size_t len = strlen (str);
- div_t d = div (code, 100);
-
- uint8_t *ptr = stun_append (msg, msize, STUN_ERROR_CODE, 4 + len);
- if (ptr == NULL)
- return ENOBUFS;
-
- memset (ptr, 0, 2);
- assert (d.quot <= 0x7);
- ptr[2] = d.quot;
- ptr[3] = d.rem;
- memcpy (ptr + 4, str, len);
- return 0;
-}
-
-
-int stun_init_error (uint8_t *ans, size_t msize, const uint8_t *req,
- stun_error_t err, int compat)
-{
- assert (stun_valid (req));
- assert (msize >= 20u);
- assert (stun_get_class (req) == STUN_REQUEST);
-
- stun_init (ans, STUN_ERROR, stun_get_method (req), stun_id (req));
- /* For RFC3489 compatibility, we cannot assume the cookie */
- memcpy (ans + 4, req + 4, 4);
- (void)stun_append_server (ans, msize, compat);
- return stun_append_error (ans, msize, err);
-}
-
-
-int stun_init_error_unknown (uint8_t *ans, size_t msize, const uint8_t *req,
- int compat)
-{
- unsigned counter, i;
-#ifdef HAVE_C_VARARRAYS
- uint16_t ids[1 + (stun_length (req) / 4)];
-#else
- uint16_t ids[256];
-#endif
-
- counter = stun_find_unknown (req, ids, sizeof (ids) / sizeof (ids[0]));
- assert (counter > 0);
-
- if (stun_init_error (ans, msize, req, STUN_UNKNOWN_ATTRIBUTE, compat))
- return ENOBUFS;
-
- for (i = 0; i < counter; i++)
- ids[i] = htons (ids[i]);
-
- /* NOTE: Old RFC3489 compatibility:
- * When counter is odd, duplicate one value for 32-bits padding. */
- if (!stun_has_cookie (req) && (counter & 1))
- ids[counter++] = ids[0];
-
- return stun_append_bytes (ans, msize, STUN_UNKNOWN_ATTRIBUTES, ids,
- counter * 2);
-}
-
-
-int
-stun_append_addr (uint8_t *restrict msg, size_t msize, stun_attr_type_t type,
- const struct sockaddr *restrict addr, socklen_t addrlen)
-{
- const void *pa;
- uint8_t *ptr;
- uint16_t alen, port;
- uint8_t family;
-
- if (addrlen < sizeof (struct sockaddr))
- return EINVAL;
-
- switch (addr->sa_family)
- {
- case AF_INET:
- {
- const struct sockaddr_in *ip4 = (const struct sockaddr_in *)addr;
- assert (addrlen >= sizeof (*ip4));
- family = 1;
- port = ip4->sin_port;
- alen = 4;
- pa = &ip4->sin_addr;
- break;
- }
-
- case AF_INET6:
- {
- const struct sockaddr_in6 *ip6 = (const struct sockaddr_in6 *)addr;
- if (addrlen < sizeof (*ip6))
- return EINVAL;
-
- family = 2;
- port = ip6->sin6_port;
- alen = 16;
- pa = &ip6->sin6_addr;
- break;
- }
-
- default:
- return EAFNOSUPPORT;
- }
-
- ptr = stun_append (msg, msize, type, 4 + alen);
- if (ptr == NULL)
- return ENOBUFS;
-
- ptr[0] = 0;
- ptr[1] = family;
- memcpy (ptr + 2, &port, 2);
- memcpy (ptr + 4, pa, alen);
- return 0;
-}
-
-
-int stun_append_xor_addr (uint8_t *restrict msg, size_t msize,
- stun_attr_type_t type,
- const struct sockaddr *restrict addr,
- socklen_t addrlen)
-{
- int val;
- /* Must be big enough to hold any supported address: */
- struct sockaddr_storage xor;
-
- if (addrlen > sizeof (xor))
- addrlen = sizeof (xor);
- memcpy (&xor, addr, addrlen);
-
- val = stun_xor_address (msg, (struct sockaddr *)&xor, addrlen);
- if (val)
- return val;
-
- return stun_append_addr (msg, msize, type, (struct sockaddr *)&xor,
- addrlen);
-}
-
-
-size_t
-stun_finish_long (uint8_t *msg, size_t *restrict plen,
- const char *realm, const char *username, const char *nonce,
- const void *restrict key, size_t keylen, int compat)
-{
- size_t len = *plen;
- uint8_t *ptr;
- int val = ENOBUFS;
- uint32_t fpr;
-
- if (realm != NULL)
- {
- /*if (utf32_strlen (realm) > 127))
- return EINVAL;*/
- val = stun_append_string (msg, len, STUN_REALM, realm);
- if (val)
- return val;
- }
-
- if (username != NULL)
- {
- if (strlen (username) >= 513)
- return EINVAL;
-
- val = stun_append_string (msg, len, STUN_USERNAME, username);
- if (val)
- return val;
- }
-
- if (nonce != NULL)
- {
- /*if (utf32_strlen (nonce) > 127))
- return EINVAL;*/
-
- val = stun_append_string (msg, len, STUN_NONCE, nonce);
- if (val)
- return val;
- }
-
- if (key != NULL)
- {
- ptr = stun_append (msg, len, STUN_MESSAGE_INTEGRITY, 20);
- if (ptr == NULL)
- return ENOBUFS;
-
- stun_sha1 (msg, ptr + 20 - msg, ptr, key, keylen);
-
- DBG (" Message HMAC-SHA1 fingerprint:"
- "\n key : ");
- DBG_bytes (key, keylen);
- DBG ("\n sent : ");
- DBG_bytes (ptr, 20);
- DBG ("\n");
-
- }
-
- if (compat != 1) {
- /*
- * NOTE: we always add a FINGERPRINT, even when it's not needed.
- * This is OK, as it is an optional attribute. It also makes my
- * software engineer's life easier.
- */
- ptr = stun_append (msg, len, STUN_FINGERPRINT, 4);
- if (ptr == NULL)
- return ENOBUFS;
-
- *plen = ptr + 4 -msg;
-
- fpr = htonl (stun_fingerprint (msg, *plen));
- memcpy (ptr, &fpr, sizeof (fpr));
- }
-
- *plen = stun_length (msg) + 20;
- return 0;
-}
-
-
-size_t stun_finish_short (uint8_t *msg, size_t *restrict plen,
- const char *username, const char *restrict password,
- const char *nonce, int compat)
-{
- return stun_finish_long (msg, plen, NULL, username, nonce,
- password, password ? strlen (password) : 0, compat);
-}
-
-
-size_t stun_finish (uint8_t *msg, size_t *restrict plen, int compat)
-{
- return stun_finish_short (msg, plen, NULL, NULL, NULL, compat);
-}
diff --git a/stun/tests/test-parse.c b/stun/tests/test-parse.c
index 03c9c34..a4d94b2 100644
--- a/stun/tests/test-parse.c
+++ b/stun/tests/test-parse.c
@@ -50,6 +50,9 @@
#include <errno.h>
+# define STUN_MAX_STR (763u)
+# define STUN_MAX_CP (127u)
+
static void fatal (const char *msg, ...)
{
va_list ap;
diff --git a/stun/tools/stunbdc.c b/stun/tools/stunbdc.c
index 56e7ffd..4ba0056 100644
--- a/stun/tools/stunbdc.c
+++ b/stun/tools/stunbdc.c
@@ -39,7 +39,7 @@
#include <sys/types.h>
#include <sys/socket.h>
-#include "stun/usages/bind.h"
+#include "stunagent.h"
#include <unistd.h>
#include <getopt.h>
diff --git a/stun/utils.c b/stun/utils.c
index 300d8df..ca3db3a 100644
--- a/stun/utils.c
+++ b/stun/utils.c
@@ -38,9 +38,13 @@
#endif
#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <errno.h>
#include "utils.h"
/** Compares two socket addresses */
@@ -115,97 +119,180 @@ uint16_t stun_getw (const uint8_t *ptr)
return ((ptr)[0] << 8) | ptr[1];
}
-uint16_t stun_length (const uint8_t *ptr)
-{
- return stun_getw (ptr + 2);
-}
-/**
- * @return STUN message class in host byte order (value from 0 to 3)
- */
-stun_class_t stun_get_class (const uint8_t *msg)
+/* /\** */
+/* * @param msg valid STUN message */
+/* * @return true if there is at least one unknown mandatory attribute. */
+/* *\/ */
+/* bool stun_has_unknown (const void *msg) */
+/* { */
+/* uint16_t dummy; */
+/* return stun_find_unknown (msg, &dummy, 1); */
+/* } */
+
+void stun_debug (const char *fmt, ...)
{
- uint16_t t = stun_getw (msg);
- return (stun_class_t)(((t & 0x0100) >> 7) | ((t & 0x0010) >> 4));
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
}
-/**
- * @return STUN message method (value from 0 to 0xfff)
- */
-stun_method_t stun_get_method (const uint8_t *msg)
+void stun_debug_bytes (const void *data, size_t len)
{
- uint16_t t = stun_getw (msg);
- return (stun_method_t)(((t & 0x3e00) >> 2) | ((t & 0x00e0) >> 1) |
- (t & 0x000f));
-}
+ size_t i;
+ stun_debug ("0x");
+ for (i = 0; i < len; i++)
+ stun_debug ("%02x", ((const unsigned char *)data)[i]);
+}
-/**
- * @return STUN message transaction ID
- */
-const uint8_t *stun_id (const uint8_t *msg)
+int stun_xor_address (const StunMessage *msg,
+ struct sockaddr *restrict addr, socklen_t addrlen)
{
- //assert (stun_valid (req));
- return msg + 8;
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *ip4 = (struct sockaddr_in *)addr;
+ if (addrlen < sizeof (*ip4))
+ return EINVAL;
+
+ ip4->sin_port ^= htons (STUN_MAGIC_COOKIE >> 16);
+ ip4->sin_addr.s_addr ^= htonl (STUN_MAGIC_COOKIE);
+ return 0;
+ }
+
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)addr;
+ unsigned short i;
+
+ if (addrlen < sizeof (*ip6))
+ return EINVAL;
+
+ ip6->sin6_port ^= htons (STUN_MAGIC_COOKIE >> 16);
+ for (i = 0; i < 16; i++)
+ ip6->sin6_addr.s6_addr[i] ^= msg->buffer[4 + i];
+ return 0;
+ }
+ }
+ return EAFNOSUPPORT;
}
/**
- * Checks if an attribute is present within a STUN message.
+ * Compares the length and content of an attribute.
*
- * @param msg valid STUN message
+ * @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
- *
- * @return whether there is a MESSAGE-INTEGRITY attribute
+ * @param data pointer to value to compare with
+ * @param len byte length of the value
+ * @return 0 in case of match, ENOENT if attribute was not found,
+ * EINVAL if it did not match (different length, or same length but
+ * different content)
*/
-bool stun_present (const uint8_t *msg, stun_attr_type_t type)
+int stun_memcmp (const StunMessage *msg, stun_attr_type_t type,
+ const void *data, size_t len)
{
- uint16_t dummy;
- return stun_find (msg, type, &dummy) != NULL;
+ uint16_t alen;
+ const void *ptr = stun_message_find (msg, type, &alen);
+ if (ptr == NULL)
+ return ENOENT;
+
+ if ((len != alen) || memcmp (ptr, data, len))
+ return EINVAL;
+ return 0;
}
/**
- * @param msg valid STUN message
- * @return true if there is at least one unknown mandatory attribute.
+ * Compares the content of an attribute with a string.
+ * @param msg valid STUN message buffer
+ * @param type STUN attribute type (host byte order)
+ * @param str string to compare with
+ * @return 0 in case of match, ENOENT if attribute was not found,
+ * EINVAL if it did not match
*/
-bool stun_has_unknown (const void *msg)
+int stun_strcmp (const StunMessage *msg, stun_attr_type_t type, const char *str)
{
- uint16_t dummy;
- return stun_find_unknown (msg, &dummy, 1);
+ return stun_memcmp (msg, type, str, strlen (str));
}
-# ifndef NDEBUG
-/**
- * This function is for debugging only, which is why it is only defined under
- * !NDEBUG. It should really only be used in run-time assertions, as it cannot
- * detect all possible errors. stun_validate() should be used instead in real
- * code.
- *
- * @param msg pointer to a potential STUN message
- * @return whether the pointer refers to a valid STUN message
- */
-bool stun_valid (const uint8_t *msg)
+void *stun_setw (uint8_t *ptr, uint16_t value)
{
- size_t length = 20u + stun_length (msg);
- return stun_validate (msg, length) == (ssize_t)length;
+ *ptr++ = value >> 8;
+ *ptr++ = value & 0xff;
+ return ptr;
}
-# endif
-void stun_debug (const char *fmt, ...)
+
+void stun_set_type (uint8_t *h, stun_class_t c, stun_method_t m)
{
- va_list ap;
- va_start (ap, fmt);
- vfprintf (stderr, fmt, ap);
- va_end (ap);
+/* assert (c < 4); */
+/* assert (m < (1 << 12)); */
+
+ h[0] = (c >> 1) | ((m >> 6) & 0x3e);
+ h[1] = ((c << 4) & 0x10) | ((m << 1) & 0xe0) | (m & 0x0f);
+
+/* assert (stun_getw (h) < (1 << 14)); */
+/* assert (stun_get_class (h) == c); */
+/* assert (stun_get_method (h) == m); */
}
-void stun_debug_bytes (const void *data, size_t len)
+
+/**
+ * @param code host-byte order error code
+ * @return a static pointer to a nul-terminated error message string.
+ */
+const char *stun_strerror (stun_error_t code)
{
+ static const struct
+ {
+ stun_error_t code;
+ char phrase[32];
+ } tab[] =
+ {
+ { STUN_ERROR_TRY_ALTERNATE, "Try alternate server" },
+ { STUN_ERROR_BAD_REQUEST, "Bad request" },
+ { STUN_ERROR_UNAUTHORIZED, "Authorization required" },
+ { STUN_ERROR_UNKNOWN_ATTRIBUTE, "Unknown attribute" },
+ /*
+ { STUN_STALE_CREDENTIALS, "Authentication expired" },
+ { STUN_INTEGRITY_CHECK_FAILURE, "Incorrect username/password" },
+ { STUN_MISSING_USERNAME, "Username required" },
+ { STUN_USE_TLS, "Secure connection required" },
+ { STUN_MISSING_REALM, "Authentication domain required" },
+ { STUN_MISSING_NONCE, "Authentication token missing" },
+ { STUN_UNKNOWN_USERNAME, "Unknown user name" },
+ */
+ { STUN_ERROR_NO_BINDING, "Session expired" },
+ { STUN_ERROR_STALE_NONCE, "Authentication token expired" },
+ { STUN_ERROR_ACT_DST_ALREADY, "Changing remote peer forbidden" },
+ { STUN_ERROR_UNSUPP_TRANSPORT, "Unknown transport protocol" },
+ { STUN_ERROR_INVALID_IP, "Address unavailable" },
+ { STUN_ERROR_INVALID_PORT, "Port unavailable" },
+ { STUN_ERROR_OP_TCP_ONLY, "Invalid operation" },
+ { STUN_ERROR_CONN_ALREADY, "Connection already established" },
+ { STUN_ERROR_ALLOC_OVER_QUOTA, "Quota reached" },
+ { STUN_ERROR_ROLE_CONFLICT, "Role conflict" },
+ { STUN_ERROR_SERVER_ERROR, "Temporary server error" },
+ { STUN_ERROR_SERVER_CAPACITY, "Temporary server congestion" },
+ };
+ const char *str = "Unknown error";
size_t i;
- DBG ("0x");
- for (i = 0; i < len; i++)
- DBG ("%02x", ((const unsigned char *)data)[i]);
+ for (i = 0; i < (sizeof (tab) / sizeof (tab[0])); i++)
+ {
+ if (tab[i].code == code)
+ {
+ str = tab[i].phrase;
+ break;
+ }
+ }
+
+ /* Maximum allowed error message length */
+ // assert (strlen (str) < 128);
+ return str;
}
diff --git a/stun/utils.h b/stun/utils.h
index 688ddd6..ef17a03 100644
--- a/stun/utils.h
+++ b/stun/utils.h
@@ -41,7 +41,7 @@
* @brief STUN client generic utility functions
*/
-#include "stun-msg.h"
+#include "stunmessage.h"
# ifdef __cplusplus
extern "C" {
@@ -58,25 +58,23 @@ size_t stun_align (size_t l);
uint16_t stun_getw (const uint8_t *ptr);
-uint16_t stun_length (const uint8_t *ptr);
-
-stun_class_t stun_get_class (const uint8_t *msg);
+void stun_debug (const char *fmt, ...);
-stun_method_t stun_get_method (const uint8_t *msg);
+void stun_debug_bytes (const void *data, size_t len);
-const uint8_t *stun_id (const uint8_t *msg);
+int stun_xor_address (const StunMessage *msg,
+ struct sockaddr *restrict addr, socklen_t addrlen);
-bool stun_present (const uint8_t *msg, stun_attr_type_t type);
+int stun_memcmp (const StunMessage *msg, stun_attr_type_t type,
+ const void *data, size_t len);
-bool stun_has_unknown (const void *msg);
+int stun_strcmp (const StunMessage *msg, stun_attr_type_t type, const char *str);
-# ifndef NDEBUG
-bool stun_valid (const uint8_t *msg);
-# endif
+void *stun_setw (uint8_t *ptr, uint16_t value);
-void stun_debug (const char *fmt, ...);
+void stun_set_type (uint8_t *h, stun_class_t c, stun_method_t m);
-void stun_debug_bytes (const void *data, size_t len);
+const char *stun_strerror (stun_error_t code);
# ifdef __cplusplus
}