summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Adam <jakub.adam@ktknet.cz>2016-06-29 06:40:12 +0000
committerOlivier CrĂȘte <olivier.crete@collabora.com>2016-10-26 17:50:37 -0400
commit7e5ab23cbb7b2d1e4023a8016abf4793e9606bbb (patch)
treea234c1795e53e596c66602e3fa3fffd6afd0aca6
parentdab341608736327831720ac44df807ac669fbe7e (diff)
downloadlibnice-7e5ab23cbb7b2d1e4023a8016abf4793e9606bbb.tar.gz
ms-ice: legacy FINGERPRINT mode
In order to preserve compatibility with clients which use custom CRC lookup table from [MS-ICE2], whenever a connectivity check request or reply is sent, an additional message is sent along. These two messages differ only in FINGERPRINT attribute - one uses regular CRC lookup table for calculation, the other uses the modified table. When a message is received and FINGERPRINT doesn't pass validation using regular CRC table, the receiver also tries to verify using the modified table. [MS-ICE2] 3.1.4.8.2 describes this procedure. The commit fixes compatibility with older MSOC and Lync clients. Differential Revision: https://phabricator.freedesktop.org/D1138
-rw-r--r--agent/conncheck.c55
-rw-r--r--stun/stunagent.c52
2 files changed, 89 insertions, 18 deletions
diff --git a/agent/conncheck.c b/agent/conncheck.c
index e913153..b7ae90a 100644
--- a/agent/conncheck.c
+++ b/agent/conncheck.c
@@ -57,6 +57,7 @@
#include "agent-priv.h"
#include "conncheck.h"
#include "discovery.h"
+#include "stun/stun5389.h"
#include "stun/usages/ice.h"
#include "stun/usages/bind.h"
#include "stun/usages/turn.h"
@@ -778,7 +779,37 @@ static guint32 peer_reflexive_candidate_priority (NiceAgent *agent,
return priority;
}
+static void ms_ice2_legacy_conncheck_send(StunMessage *msg, NiceSocket *sock,
+ const NiceAddress *remote_addr)
+{
+ uint32_t *fingerprint_attr;
+ uint32_t fingerprint_orig;
+ uint16_t fingerprint_len;
+ size_t buffer_len;
+
+ fingerprint_attr = (uint32_t *)stun_message_find (msg,
+ STUN_ATTRIBUTE_FINGERPRINT, &fingerprint_len);
+
+ if (fingerprint_attr == NULL) {
+ nice_debug ("FINGERPRINT not found.");
+ return;
+ }
+
+ if (fingerprint_len != sizeof (fingerprint_orig)) {
+ nice_debug ("Unexpected FINGERPRINT length %u.", fingerprint_len);
+ return;
+ }
+
+ memcpy (&fingerprint_orig, fingerprint_attr, sizeof (fingerprint_orig));
+ buffer_len = stun_message_length (msg);
+
+ *fingerprint_attr = stun_fingerprint (msg->buffer, buffer_len, TRUE);
+
+ agent_socket_send (sock, remote_addr, buffer_len, (gchar *)msg->buffer);
+
+ memcpy (fingerprint_attr, &fingerprint_orig, sizeof (fingerprint_orig));
+}
/*
* Timer callback that handles initiating and managing connectivity
@@ -883,6 +914,11 @@ static gboolean priv_conn_keepalive_tick_unlocked (NiceAgent *agent)
agent_socket_send (p->local->sockptr, &p->remote->addr, buf_len,
(gchar *)p->keepalive.stun_buffer);
+ if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
+ ms_ice2_legacy_conncheck_send (&p->keepalive.stun_message,
+ p->local->sockptr, &p->remote->addr);
+ }
+
nice_debug ("Agent %p : stun_bind_keepalive for pair %p res %d.",
agent, p, (int) buf_len);
} else {
@@ -2167,6 +2203,11 @@ int conn_check_send (NiceAgent *agent, CandidateCheckPair *pair)
agent_socket_send (pair->sockptr, &pair->remote->addr,
buffer_len, (gchar *)pair->stun_buffer);
+ if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
+ ms_ice2_legacy_conncheck_send (&pair->stun_message, pair->sockptr,
+ &pair->remote->addr);
+ }
+
timeout = stun_timer_remainder (&pair->timer);
/* note: convert from milli to microseconds for g_time_val_add() */
g_get_current_time (&pair->next_tick);
@@ -2372,12 +2413,15 @@ static gboolean priv_schedule_triggered_check (NiceAgent *agent, NiceStream *str
* @param toaddr address to which reply is sent
* @param socket the socket over which the request came
* @param rbuf_len length of STUN message to send
- * @param rbuf buffer containing the STUN message to send
+ * @param msg the STUN message to send
* @param use_candidate whether the request had USE_CANDIDATE attribute
*
* @pre (rcand == NULL || nice_address_equal(rcand->addr, toaddr) == TRUE)
*/
-static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand, const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len, uint8_t *rbuf, gboolean use_candidate)
+static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream,
+ NiceComponent *component, NiceCandidate *lcand, NiceCandidate *rcand,
+ const NiceAddress *toaddr, NiceSocket *sockptr, size_t rbuf_len,
+ StunMessage *msg, gboolean use_candidate)
{
g_assert (rcand == NULL || nice_address_equal(&rcand->addr, toaddr) == TRUE);
@@ -2393,7 +2437,10 @@ static void priv_reply_to_conn_check (NiceAgent *agent, NiceStream *stream, Nice
(int)use_candidate);
}
- agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)rbuf);
+ agent_socket_send (sockptr, toaddr, rbuf_len, (const gchar*)msg->buffer);
+ if (agent->compatibility == NICE_COMPATIBILITY_OC2007R2) {
+ ms_ice2_legacy_conncheck_send(msg, sockptr, toaddr);
+ }
if (rcand) {
/* note: upon successful check, make the reserve check immediately */
@@ -3601,7 +3648,7 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
}
priv_reply_to_conn_check (agent, stream, component, local_candidate,
- remote_candidate, from, nicesock, rbuf_len, rbuf, use_candidate);
+ remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate);
if (component->remote_candidates == NULL) {
/* case: We've got a valid binding request to a local candidate
diff --git a/stun/stunagent.c b/stun/stunagent.c
index 461a8e3..cd97684 100644
--- a/stun/stunagent.c
+++ b/stun/stunagent.c
@@ -98,13 +98,48 @@ bool stun_agent_default_validater (StunAgent *agent,
}
+static bool stun_agent_check_fingerprint(StunAgent *agent, StunMessage *msg)
+{
+ uint32_t fpr;
+ uint32_t crc32;
+ uint16_t msg_len;
+
+ /* Looks for FINGERPRINT */
+ if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
+ STUN_MESSAGE_RETURN_SUCCESS) {
+ stun_debug ("STUN demux error: no FINGERPRINT attribute!");
+ return FALSE;
+ }
+
+ msg_len = stun_message_length (msg);
+
+ /* Checks FINGERPRINT */
+ crc32 = stun_fingerprint (msg->buffer, msg_len, FALSE);
+ fpr = ntohl (fpr);
+ if (fpr != crc32) {
+ uint16_t palen;
+
+ /* [MS-ICE2] 3.1.4.8.2 Connectivity Checks Phase - legacy compatibility */
+ if (agent->compatibility == STUN_COMPATIBILITY_MSICE2 &&
+ stun_message_find (msg, STUN_ATTRIBUTE_MS_IMPLEMENTATION_VERSION,
+ &palen) == NULL &&
+ fpr == stun_fingerprint (msg->buffer, msg_len, TRUE)) {
+ return TRUE;
+ }
+
+ stun_debug ("STUN demux error: bad fingerprint: 0x%08x, expected: 0x%08x!",
+ fpr, crc32);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
const uint8_t *buffer, size_t buffer_len,
StunMessageIntegrityValidate validater, void * validater_data)
{
StunTransactionId msg_id;
- uint32_t fpr;
- uint32_t crc32;
int len;
uint8_t *username = NULL;
uint16_t username_len;
@@ -148,18 +183,7 @@ StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
agent->compatibility == STUN_COMPATIBILITY_MSICE2) &&
agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
- /* Looks for FINGERPRINT */
- if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
- STUN_MESSAGE_RETURN_SUCCESS) {
- stun_debug ("STUN demux error: no FINGERPRINT attribute!");
- return STUN_VALIDATION_BAD_REQUEST;
- }
- /* Checks FINGERPRINT */
- crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg), FALSE);
- fpr = ntohl (fpr);
- if (fpr != crc32) {
- stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
- " expected: 0x%08x!", fpr, crc32);
+ if (stun_agent_check_fingerprint(agent, msg) == FALSE) {
return STUN_VALIDATION_BAD_REQUEST;
}