diff options
author | Johan Sternerup <johast@axis.com> | 2022-01-20 15:47:11 +0100 |
---|---|---|
committer | Johan Sternerup <johast@axis.com> | 2022-04-06 08:40:23 +0200 |
commit | 526eec8beaf9068b66caab6e1f941ec574e3b82a (patch) | |
tree | dd979631aa81f69e550fd350037253aa75422d8b | |
parent | 642714943a554898645921eb39aa28d26da3f65c (diff) | |
download | libnice-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.c | 31 | ||||
-rw-r--r-- | agent/address.h | 13 | ||||
-rw-r--r-- | agent/agent.c | 3 | ||||
-rw-r--r-- | agent/conncheck.c | 12 | ||||
-rw-r--r-- | docs/reference/libnice/libnice-sections.txt | 1 | ||||
-rw-r--r-- | tests/test-address.c | 34 |
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 |