summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Sternerup <johast@axis.com>2022-01-20 15:47:11 +0100
committerJohan Sternerup <johast@axis.com>2022-04-06 08:40:23 +0200
commit526eec8beaf9068b66caab6e1f941ec574e3b82a (patch)
treedd979631aa81f69e550fd350037253aa75422d8b
parent642714943a554898645921eb39aa28d26da3f65c (diff)
downloadlibnice-526eec8beaf9068b66caab6e1f941ec574e3b82a.tar.gz
Don't try to use link-local addresses outside local network
If we have gathered a host IP-address that is link-local we should never try to use it for anything else than trying to match it with another link-local address. Some routers seem to have problems with traffic from link-local addresses destined at external IP-addresses. By definition link-local addresses should stay local so there's no reason to access STUN/TURN from it or try to form a candidate with another address that is not link-local.
-rw-r--r--agent/address.c31
-rw-r--r--agent/address.h13
-rw-r--r--agent/agent.c3
-rw-r--r--agent/conncheck.c12
-rw-r--r--docs/reference/libnice/libnice-sections.txt1
-rw-r--r--tests/test-address.c34
6 files changed, 91 insertions, 3 deletions
diff --git a/agent/address.c b/agent/address.c
index 08092a4..5dad589 100644
--- a/agent/address.c
+++ b/agent/address.c
@@ -356,6 +356,37 @@ nice_address_is_private (const NiceAddress *a)
}
+static gboolean
+ipv4_address_is_linklocal (guint32 addr)
+{
+ addr = ntohl (addr);
+
+ return (addr & 0xffff0000) == 0xa9fe0000;
+}
+
+
+static gboolean
+ipv6_address_is_linklocal (const guchar *addr)
+{
+ return (addr[0] == 0xfe) && ((addr[1] & 0xc0) == 0x80);
+}
+
+
+NICEAPI_EXPORT gboolean
+nice_address_is_linklocal (const NiceAddress *a)
+{
+ switch (a->s.addr.sa_family)
+ {
+ case AF_INET:
+ return ipv4_address_is_linklocal (a->s.ip4.sin_addr.s_addr);
+ case AF_INET6:
+ return ipv6_address_is_linklocal (a->s.ip6.sin6_addr.s6_addr);
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+}
+
+
NICEAPI_EXPORT gboolean
nice_address_is_valid (const NiceAddress *a)
{
diff --git a/agent/address.h b/agent/address.h
index fa555b2..afd798a 100644
--- a/agent/address.h
+++ b/agent/address.h
@@ -278,6 +278,19 @@ gboolean
nice_address_is_private (const NiceAddress *addr);
/**
+ * nice_address_is_linklocal:
+ * @addr: The #NiceAddress to query
+ *
+ * Verifies if the address in @addr is a link-local address or not
+ *
+ * Returns: %TRUE if @addr is a link-local address, %FALSE otherwise
+ *
+ * Since: 0.1.19
+ */
+gboolean
+nice_address_is_linklocal (const NiceAddress *addr);
+
+/**
* nice_address_is_valid:
* @addr: The #NiceAddress to query
*
diff --git a/agent/agent.c b/agent/agent.c
index b96b8e0..0765ad9 100644
--- a/agent/agent.c
+++ b/agent/agent.c
@@ -3455,6 +3455,7 @@ nice_agent_gather_candidates (
/* TODO: Add server-reflexive support for TCP candidates */
if (agent->full_mode && agent->stun_server_ip && !agent->force_relay &&
+ !nice_address_is_linklocal (addr) &&
transport == NICE_CANDIDATE_TRANSPORT_UDP) {
NiceAddress stun_server;
if (nice_address_set_from_string (&stun_server, agent->stun_server_ip)) {
@@ -3470,7 +3471,7 @@ nice_agent_gather_candidates (
}
}
- if (agent->full_mode && component &&
+ if (agent->full_mode && component && !nice_address_is_linklocal (addr) &&
transport != NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE) {
GList *item;
int host_ip_version = nice_address_ip_version (&host_candidate->c.addr);
diff --git a/agent/conncheck.c b/agent/conncheck.c
index d99f948..9f1374a 100644
--- a/agent/conncheck.c
+++ b/agent/conncheck.c
@@ -2432,6 +2432,12 @@ static CandidateCheckPair *priv_conn_check_add_for_candidate_pair_matched (
return pair;
}
+static gboolean
+_is_linklocal_to_non_linklocal (NiceAddress *laddr, NiceAddress *raddr)
+{
+ return nice_address_is_linklocal (laddr) != nice_address_is_linklocal (raddr);
+}
+
gboolean conn_check_add_for_candidate_pair (NiceAgent *agent,
guint stream_id, NiceComponent *component, NiceCandidate *local,
NiceCandidate *remote)
@@ -2458,9 +2464,11 @@ gboolean conn_check_add_for_candidate_pair (NiceAgent *agent,
return FALSE;
}
- /* note: match pairs only if transport and address family are the same */
+ /* note: match pairs only if transport and address family are the same
+ * and make sure link-local stay link-local */
if (local->transport == conn_check_match_transport (remote->transport) &&
- local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family) {
+ local->addr.s.addr.sa_family == remote->addr.s.addr.sa_family &&
+ !_is_linklocal_to_non_linklocal (&local->addr, &remote->addr)) {
if (priv_conn_check_add_for_candidate_pair_matched (agent, stream_id,
component, local, remote, NICE_CHECK_FROZEN))
ret = TRUE;
diff --git a/docs/reference/libnice/libnice-sections.txt b/docs/reference/libnice/libnice-sections.txt
index 5c13bce..a26d596 100644
--- a/docs/reference/libnice/libnice-sections.txt
+++ b/docs/reference/libnice/libnice-sections.txt
@@ -143,6 +143,7 @@ nice_address_equal
nice_address_equal_no_port
nice_address_to_string
nice_address_is_private
+nice_address_is_linklocal
nice_address_is_valid
nice_address_ip_version
</SECTION>
diff --git a/tests/test-address.c b/tests/test-address.c
index 4b874c8..7ad8cb8 100644
--- a/tests/test-address.c
+++ b/tests/test-address.c
@@ -151,6 +151,40 @@ test_ipv4 (void)
nice_address_free (heap_addr);
}
+
+ /* test link-local address check */
+ {
+ NiceAddress *heap_addr = nice_address_new ();
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "169.253.255.255"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == FALSE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "169.254.0.0"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == TRUE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "169.254.255.255"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == TRUE);
+
+ g_assert_true (nice_address_set_from_string (heap_addr, "127.0.0.1"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == FALSE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "172.31.255.255"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == FALSE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "192.168.15.69"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == FALSE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "fe70::0"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == FALSE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "fe80::0"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == TRUE);
+
+ g_assert_true (nice_address_set_from_string(heap_addr, "fe81::0"));
+ g_assert_true (nice_address_is_linklocal (heap_addr) == TRUE);
+
+ nice_address_free (heap_addr);
+ }
}
static void