summaryrefslogtreecommitdiff
path: root/stun
diff options
context:
space:
mode:
authorJakub Adam <jakub.adam@ktknet.cz>2010-10-01 08:18:18 +0200
committerYouness Alaoui <youness.alaoui@collabora.co.uk>2010-10-01 17:00:00 -0400
commitdc8badef5d5d91a97b7f07d0e30472b4f38105a2 (patch)
tree5396d21ca9bcc309cfc9592dac32be985bd87569 /stun
parent9cf4e79cb9086e13dc52b5687f0a7eea713be2a3 (diff)
downloadlibnice-dc8badef5d5d91a97b7f07d0e30472b4f38105a2.tar.gz
MS-TURN support for Microsoft Office Communicator
Diffstat (limited to 'stun')
-rw-r--r--stun/stunagent.c22
-rw-r--r--stun/stunagent.h10
-rw-r--r--stun/stunmessage.c48
-rw-r--r--stun/stunmessage.h47
-rw-r--r--stun/tests/test-parse.c12
-rw-r--r--stun/usages/turn.c7
-rw-r--r--stun/usages/turn.h1
7 files changed, 119 insertions, 28 deletions
diff --git a/stun/stunagent.c b/stun/stunagent.c
index be2a9cf..d143599 100644
--- a/stun/stunagent.c
+++ b/stun/stunagent.c
@@ -117,7 +117,8 @@ StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
uint8_t long_term_key[16];
bool long_term_key_valid = FALSE;
- len = stun_message_validate_buffer_length (buffer, buffer_len);
+ len = stun_message_validate_buffer_length (buffer, buffer_len,
+ !(agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES));
if (len == STUN_MESSAGE_BUFFER_INVALID) {
return STUN_VALIDATION_NOT_STUN;
} else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
@@ -257,7 +258,8 @@ StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
memcpy (msg->long_term_key, md5, sizeof(md5));
msg->long_term_valid = TRUE;
- if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
+ if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
+ agent->compatibility == STUN_COMPATIBILITY_OC2007) {
stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
sha, md5, sizeof(md5), TRUE);
} else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
@@ -268,7 +270,8 @@ StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
hash - msg->buffer, sha, md5, sizeof(md5), FALSE);
}
} else {
- if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
+ if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
+ agent->compatibility == STUN_COMPATIBILITY_OC2007) {
stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
sha, key, key_len, TRUE);
} else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
@@ -564,7 +567,8 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
return 0;
}
if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
- if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
+ if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
+ agent->compatibility == STUN_COMPATIBILITY_OC2007) {
stun_sha1 (msg->buffer, stun_message_length (msg),
stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
} else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
@@ -579,7 +583,8 @@ size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
}
} else {
- if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
+ if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
+ agent->compatibility == STUN_COMPATIBILITY_OC2007) {
stun_sha1 (msg->buffer, stun_message_length (msg),
stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
} else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
@@ -671,14 +676,17 @@ stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg,
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);
}
+
+ if (!(agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES))
+ alen = stun_align (alen);
+
+ offset += STUN_ATTRIBUTE_VALUE_POS + alen;
}
stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count);
diff --git a/stun/stunagent.h b/stun/stunagent.h
index 2a8fc84..e6a7eb5 100644
--- a/stun/stunagent.h
+++ b/stun/stunagent.h
@@ -82,6 +82,9 @@ typedef struct stun_agent_t StunAgent;
* @STUN_COMPATIBILITY_WLM2009: Use the STUN specifications compatible with
* Windows Live Messenger 2009 (a mix between RFC3489 and RFC5389, as well as
* a special usecase against a typo in their code)
+ * @STUN_COMPATIBILITY_OC2007: Use the STUN specifications compatible with
+ * Microsoft Office Communicator 2007 (basically RFC3489 with swapped
+ * REALM and NONCE attribute hex IDs, attributes are not aligned)
* @STUN_COMPATIBILITY_LAST: Dummy last compatibility mode
*
* Enum that specifies the STUN compatibility mode of the #StunAgent
@@ -90,7 +93,8 @@ typedef enum {
STUN_COMPATIBILITY_RFC3489,
STUN_COMPATIBILITY_RFC5389,
STUN_COMPATIBILITY_WLM2009,
- STUN_COMPATIBILITY_LAST = STUN_COMPATIBILITY_WLM2009
+ STUN_COMPATIBILITY_OC2007,
+ STUN_COMPATIBILITY_LAST = STUN_COMPATIBILITY_OC2007
} StunCompatibility;
@@ -157,6 +161,9 @@ typedef enum {
* should be (a response to a previously created request). This means that the
* #StunMessageIntegrityValidate callback will always be called when there is
* a MESSAGE-INTEGRITY attribute.
+ * @STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES: The agent should not assume STUN
+ * attributes are aligned on 32-bit boundaries when parsing messages and also
+ * do not add padding when creating messages.
*
* This enum defines a bitflag usages for a #StunAgent and they will define how
* the agent should behave, independently of the compatibility mode it uses.
@@ -171,6 +178,7 @@ typedef enum {
STUN_AGENT_USAGE_IGNORE_CREDENTIALS = (1 << 4),
STUN_AGENT_USAGE_NO_INDICATION_AUTH = (1 << 5),
STUN_AGENT_USAGE_FORCE_VALIDATER = (1 << 6),
+ STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES = (1 << 7),
} StunAgentUsageFlags;
diff --git a/stun/stunmessage.c b/stun/stunmessage.c
index 0f677a1..5401acd 100644
--- a/stun/stunmessage.c
+++ b/stun/stunmessage.c
@@ -88,6 +88,14 @@ stun_message_find (const StunMessage *msg, StunAttribute type,
size_t length = stun_message_length (msg);
size_t offset = 0;
+ /* In MS-TURN, IDs of REALM and NONCE STUN attributes are swapped. */
+ if (msg->agent && msg->agent->compatibility == STUN_COMPATIBILITY_OC2007)
+ {
+ if (type == STUN_ATTRIBUTE_REALM)
+ type = STUN_ATTRIBUTE_NONCE;
+ else if (type == STUN_ATTRIBUTE_NONCE)
+ type = STUN_ATTRIBUTE_REALM;
+ }
offset = STUN_MESSAGE_ATTRIBUTES_POS;
@@ -118,7 +126,9 @@ stun_message_find (const StunMessage *msg, StunAttribute type,
return NULL;
}
- alen = stun_align (alen);
+ if (!(msg->agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES))
+ alen = stun_align (alen);
+
offset += alen;
}
@@ -317,20 +327,35 @@ stun_message_append (StunMessage *msg, StunAttribute type, size_t length)
uint8_t *a;
uint16_t mlen = stun_message_length (msg);
+ /* In MS-TURN, IDs of REALM and NONCE STUN attributes are swapped. */
+ if (msg->agent && msg->agent->compatibility == STUN_COMPATIBILITY_OC2007)
+ {
+ if (type == STUN_ATTRIBUTE_NONCE)
+ type = STUN_ATTRIBUTE_REALM;
+ else if (type == STUN_ATTRIBUTE_REALM)
+ type = STUN_ATTRIBUTE_NONCE;
+ }
+
if ((size_t)mlen + STUN_ATTRIBUTE_HEADER_LENGTH + length > msg->buffer_len)
return NULL;
a = msg->buffer + 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_message_has_cookie (msg) ? length : stun_align (length));
+ if (msg->agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES)
+ {
+ a = stun_setw (a, length);
+ } else {
+ /* 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_message_has_cookie (msg) ? length : stun_align (length));
+
+ /* Add padding if needed */
+ memset (a + length, ' ', stun_padding (length));
+ mlen += stun_padding (length);
+ }
mlen += 4 + length;
- /* Add padding if needed */
- memset (a + length, ' ', stun_padding (length));
- mlen += stun_padding (length);
stun_setw (msg->buffer + STUN_MESSAGE_LENGTH_POS, mlen - STUN_MESSAGE_HEADER_LENGTH);
return a;
@@ -499,7 +524,8 @@ stun_message_append_error (StunMessage *msg, StunError code)
return STUN_MESSAGE_RETURN_SUCCESS;
}
-int stun_message_validate_buffer_length (const uint8_t *msg, size_t length)
+int stun_message_validate_buffer_length (const uint8_t *msg, size_t length,
+ bool has_padding)
{
size_t mlen;
size_t len;
@@ -525,7 +551,7 @@ int stun_message_validate_buffer_length (const uint8_t *msg, size_t length)
mlen = stun_getw (msg + STUN_MESSAGE_LENGTH_POS) +
STUN_MESSAGE_HEADER_LENGTH;
- if (stun_padding (mlen))
+ if (has_padding && stun_padding (mlen))
{
stun_debug ("STUN error: Invalid message length: %u!\n", (unsigned)mlen);
return STUN_MESSAGE_BUFFER_INVALID; // wrong padding
@@ -544,7 +570,9 @@ int stun_message_validate_buffer_length (const uint8_t *msg, size_t length)
/* from then on, we know we have the entire packet in buffer */
while (len > 0)
{
- size_t alen = stun_align (stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN));
+ size_t alen = stun_getw (msg + STUN_ATTRIBUTE_TYPE_LEN);
+ if (has_padding)
+ alen = stun_align (alen);
/* thanks to padding check, if (end > msg) then there is not only one
* but at least 4 bytes left */
diff --git a/stun/stunmessage.h b/stun/stunmessage.h
index f92afac..b31189e 100644
--- a/stun/stunmessage.h
+++ b/stun/stunmessage.h
@@ -209,6 +209,8 @@ typedef enum
* ICE draft 19
* @STUN_ATTRIBUTE_OPTIONS: The OPTIONS optional attribute as defined by
* libjingle
+ * @STUN_ATTRIBUTE_MS_VERSION: The MS-VERSION optional attribute as defined
+ * by [MS-TURN]
* @STUN_ATTRIBUTE_SOFTWARE: The SOFTWARE optional attribute as defined by RFC5389
* @STUN_ATTRIBUTE_ALTERNATE_SERVER: The ALTERNATE-SERVER optional attribute as
* defined by RFC5389
@@ -218,6 +220,8 @@ typedef enum
* defined by ICE draft 19
* @STUN_ATTRIBUTE_ICE_CONTROLLING: The ICE-CONTROLLING optional attribute as
* defined by ICE draft 19
+ * @STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER: The MS-SEQUENCE NUMBER optional attribute
+ * as defined by [MS-TURN]
* @STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER: The CANDIDATE-IDENTIFIER optional
* attribute as defined by [MS-ICE2]
*
@@ -241,7 +245,9 @@ typedef enum
STUN_ATTRIBUTE_REFLECTED_FROM=0x000B, /* old RFC3489 */
STUN_ATTRIBUTE_CHANNEL_NUMBER=0x000C, /* TURN-12 */
STUN_ATTRIBUTE_LIFETIME=0x000D, /* TURN-12 */
- /* 0x000E */ /* reserved (was ALTERNATE-SERVER from midcom-TURN 08 */
+ /* MS_ALTERNATE_SERVER is only used by Microsoft's dialect, probably should
+ * not to be placed in STUN_ALL_KNOWN_ATTRIBUTES */
+ STUN_ATTRIBUTE_MS_ALTERNATE_SERVER=0x000E, /* MS-TURN */
STUN_ATTRIBUTE_MAGIC_COOKIE=0x000F, /* midcom-TURN 08 */
STUN_ATTRIBUTE_BANDWIDTH=0x0010, /* TURN-04 */
STUN_ATTRIBUTE_DESTINATION_ADDRESS=0x0011, /* midcom-TURN 08 */
@@ -281,6 +287,7 @@ typedef enum
/* Optional attributes */
/* 0x8000-0x8021 */ /* reserved */
STUN_ATTRIBUTE_OPTIONS=0x8001, /* libjingle */
+ STUN_ATTRIBUTE_MS_VERSION=0x8008, /* MS-TURN */
STUN_ATTRIBUTE_SOFTWARE=0x8022, /* RFC5389 */
STUN_ATTRIBUTE_ALTERNATE_SERVER=0x8023, /* RFC5389 */
/* 0x8024 */ /* reserved */
@@ -290,7 +297,9 @@ typedef enum
STUN_ATTRIBUTE_FINGERPRINT=0x8028, /* RFC5389 */
STUN_ATTRIBUTE_ICE_CONTROLLED=0x8029, /* ICE-19 */
STUN_ATTRIBUTE_ICE_CONTROLLING=0x802A, /* ICE-19 */
- /* 0x802B-0x8053 */ /* reserved */
+ /* 0x802B-0x804F */ /* reserved */
+ STUN_ATTRIBUTE_MS_SEQUENCE_NUMBER=0x8050, /* MS-TURN */
+ /* 0x8051-0x8053 */ /* reserved */
STUN_ATTRIBUTE_CANDIDATE_IDENTIFIER=0x8054 /* MS-ICE2 */
/* 0x8055-0xFFFF */ /* reserved */
} StunAttribute;
@@ -347,6 +356,36 @@ static const uint16_t STUN_ALL_KNOWN_ATTRIBUTES[] =
};
/**
+ * STUN_MSOC_KNOWN_ATTRIBUTES:
+ *
+ * An array containing all the currently known mandatory attributes used by
+ * Microsoft Office Communicator as defined in [MS-TURN]
+ */
+static const uint16_t STUN_MSOC_KNOWN_ATTRIBUTES[] =
+ {
+ STUN_ATTRIBUTE_MAPPED_ADDRESS,
+ STUN_ATTRIBUTE_USERNAME,
+ STUN_ATTRIBUTE_MESSAGE_INTEGRITY,
+ STUN_ATTRIBUTE_ERROR_CODE,
+ STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES,
+ STUN_ATTRIBUTE_LIFETIME,
+ STUN_ATTRIBUTE_MS_ALTERNATE_SERVER,
+ STUN_ATTRIBUTE_MAGIC_COOKIE,
+ STUN_ATTRIBUTE_BANDWIDTH,
+ STUN_ATTRIBUTE_DESTINATION_ADDRESS,
+ STUN_ATTRIBUTE_REMOTE_ADDRESS,
+ STUN_ATTRIBUTE_DATA,
+ /* REALM and NONCE have swapped hexadecimal IDs in [MS-TURN]. Libnice users
+ * or developers can still use these enumeration values in their original
+ * meanings from StunAttribute anywhere in the code, as stun_message_find()
+ * and stun_message_append() will choose correct ID in MSOC compatibility
+ * modes. */
+ STUN_ATTRIBUTE_NONCE,
+ STUN_ATTRIBUTE_REALM,
+ 0
+ };
+
+/**
* StunTransactionId:
*
* A type that holds a STUN transaction id.
@@ -826,6 +865,7 @@ StunMessageReturn stun_message_append_error (StunMessage * msg,
* stun_message_validate_buffer_length:
* @msg: The buffer to validate
* @length: The length of the buffer
+ * @has_padding: Set TRUE if attributes should be padded to multiple of 4 bytes
*
* This function will take a data buffer and will try to validate whether it is
* a STUN message or if it's not or if it's an incomplete STUN message and will
@@ -835,7 +875,8 @@ StunMessageReturn stun_message_append_error (StunMessage * msg,
* <para> See also: #STUN_MESSAGE_BUFFER_INCOMPLETE </para>
* <para> See also: #STUN_MESSAGE_BUFFER_INVALID </para>
*/
-int stun_message_validate_buffer_length (const uint8_t *msg, size_t length);
+int stun_message_validate_buffer_length (const uint8_t *msg, size_t length,
+ bool has_padding);
/**
* stun_message_id:
diff --git a/stun/tests/test-parse.c b/stun/tests/test-parse.c
index e4f6813..524f7f2 100644
--- a/stun/tests/test-parse.c
+++ b/stun/tests/test-parse.c
@@ -73,7 +73,7 @@ static void validate (const uint8_t *msg, unsigned len)
do
{
- size_t vlen = stun_message_validate_buffer_length (msg, i);
+ size_t vlen = stun_message_validate_buffer_length (msg, i, TRUE);
if ((vlen & 3) || (vlen != ((i >= len) * len)))
fatal ("%u/%u short message test failed", i, len);
}
@@ -242,16 +242,16 @@ static void test_message (void)
fatal ("Binding Error Response failed");
- if (stun_message_validate_buffer_length (NULL, 0) !=
+ if (stun_message_validate_buffer_length (NULL, 0, TRUE) !=
STUN_MESSAGE_BUFFER_INVALID)
fatal ("0 bytes test failed");
- if (stun_message_validate_buffer_length ((uint8_t *)"\xf0", 1) >= 0)
+ if (stun_message_validate_buffer_length ((uint8_t *)"\xf0", 1, TRUE) >= 0)
fatal ("1 byte test failed");
- if (stun_message_validate_buffer_length (bad1, sizeof (bad1)) >= 0)
+ if (stun_message_validate_buffer_length (bad1, sizeof (bad1), TRUE) >= 0)
fatal ("Badness 1 test failed");
- if (stun_message_validate_buffer_length (bad2, sizeof (bad2)) >= 0)
+ if (stun_message_validate_buffer_length (bad2, sizeof (bad2), TRUE) >= 0)
fatal ("Badness 2 test failed");
- if (stun_message_validate_buffer_length (bad3, sizeof (bad3)) != 0)
+ if (stun_message_validate_buffer_length (bad3, sizeof (bad3), TRUE) != 0)
fatal ("Badness 3 test failed");
validate (simple_resp, 20);
validate (old_ind, 20);
diff --git a/stun/usages/turn.c b/stun/usages/turn.c
index 64dc604..b691fbe 100644
--- a/stun/usages/turn.c
+++ b/stun/usages/turn.c
@@ -94,6 +94,10 @@ size_t stun_usage_turn_create (StunAgent *agent, StunMessage *msg,
return 0;
}
+ if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
+ stun_message_append32(msg, STUN_ATTRIBUTE_MS_VERSION, 1);
+ }
+
if (lifetime >= 0) {
if (stun_message_append32 (msg, STUN_ATTRIBUTE_LIFETIME, lifetime) !=
STUN_MESSAGE_RETURN_SUCCESS)
@@ -284,7 +288,8 @@ StunUsageTurnReturn stun_usage_turn_process (StunMessage *msg,
stun_debug (" No MAPPED-ADDRESS: %d\n", val);
return STUN_USAGE_TURN_RETURN_ERROR;
}
- } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN) {
+ } else if (compatibility == STUN_USAGE_TURN_COMPATIBILITY_MSN ||
+ compatibility == STUN_USAGE_TURN_COMPATIBILITY_OC2007) {
val = stun_message_find_addr (msg,
STUN_ATTRIBUTE_MSN_MAPPED_ADDRESS, addr, addrlen);
diff --git a/stun/usages/turn.h b/stun/usages/turn.h
index 00374e1..f95ff6b 100644
--- a/stun/usages/turn.h
+++ b/stun/usages/turn.h
@@ -96,6 +96,7 @@ typedef enum {
STUN_USAGE_TURN_COMPATIBILITY_DRAFT9,
STUN_USAGE_TURN_COMPATIBILITY_GOOGLE,
STUN_USAGE_TURN_COMPATIBILITY_MSN,
+ STUN_USAGE_TURN_COMPATIBILITY_OC2007
} StunUsageTurnCompatibility;
/**