summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Crête <olivier.crete@collabora.com>2017-04-04 21:27:39 -0400
committerOlivier Crête <olivier.crete@collabora.com>2017-04-11 17:50:40 -0400
commitffc7fddac42728bac6e4753a17bc52e5e610ae8b (patch)
tree8708b9dcd7206ce1c843b30a8a5b5a32016d40e4
parent1e9e28dbc98b4f6a7cf4bda0ca73b5abc2735ddc (diff)
downloadlibnice-ffc7fddac42728bac6e4753a17bc52e5e610ae8b.tar.gz
agent: Drop packets not from validated addresses
This is required by the WebRTC spec. Remove test-mainloop as it doesnt even try to do a negotiation. https://phabricator.freedesktop.org/T104 Differential Revision: https://phabricator.freedesktop.org/D1716
-rw-r--r--agent/agent-priv.h2
-rw-r--r--agent/agent.c20
-rw-r--r--agent/component.c90
-rw-r--r--agent/component.h10
-rw-r--r--agent/conncheck.c8
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/test-mainloop.c108
7 files changed, 127 insertions, 112 deletions
diff --git a/agent/agent-priv.h b/agent/agent-priv.h
index 4d8c9b8..ada3630 100644
--- a/agent/agent-priv.h
+++ b/agent/agent-priv.h
@@ -114,6 +114,8 @@ nice_input_message_iter_compare (const NiceInputMessageIter *a,
* MTU and estimated typical sizes of ICE STUN packet */
#define MAX_STUN_DATAGRAM_PAYLOAD 1300
+#define NICE_COMPONENT_MAX_VALID_CANDIDATES 50 /* maximum number of validates remote candidates to keep, the number is arbitrary but hopefully large enough */
+
struct _NiceAgent
{
GObject parent; /* gobject pointer */
diff --git a/agent/agent.c b/agent/agent.c
index 77f27e3..eff62f0 100644
--- a/agent/agent.c
+++ b/agent/agent.c
@@ -3682,8 +3682,6 @@ agent_recv_message_unlocked (
if (retval == RECV_OOB)
goto done;
- agent->media_after_tick = TRUE;
-
/* If the message’s stated length is equal to its actual length, it’s probably
* a STUN message; otherwise it’s probably data. */
if (stun_message_validate_buffer_length_fast (
@@ -3715,6 +3713,7 @@ agent_recv_message_unlocked (
nice_debug ("%s: Valid STUN packet received.", G_STRFUNC);
retval = RECV_OOB;
g_free (big_buf);
+ agent->media_after_tick = TRUE;
goto done;
}
}
@@ -3725,6 +3724,23 @@ agent_recv_message_unlocked (
g_free (big_buf);
}
+ if (!nice_component_verify_remote_candidate (component,
+ message->from, nicesock)) {
+ if (nice_debug_is_verbose ()) {
+ gchar str[INET6_ADDRSTRLEN];
+
+ nice_address_to_string (message->from, str);
+ nice_debug_verbose ("Agent %p : %d:%d DROPPING packet from unknown source"
+ " %s:%d sock-type: %d\n", agent, stream->id, component->id, str,
+ nice_address_get_port (message->from), nicesock->type);
+ }
+
+ retval = RECV_OOB;
+ goto done;
+ }
+
+ agent->media_after_tick = TRUE;
+
/* Unhandled STUN; try handling TCP data, then pass to the client. */
if (message->length > 0 && agent->reliable) {
if (!nice_socket_is_reliable (nicesock) &&
diff --git a/agent/component.c b/agent/component.c
index a679b30..ba28ffa 100644
--- a/agent/component.c
+++ b/agent/component.c
@@ -435,6 +435,8 @@ nice_component_update_selected_pair (NiceComponent *component, const CandidatePa
component->selected_pair.remote = pair->remote;
component->selected_pair.priority = pair->priority;
component->selected_pair.prflx_priority = pair->prflx_priority;
+
+ nice_component_add_valid_candidate (component, pair->remote);
}
/*
@@ -514,6 +516,11 @@ nice_component_set_selected_remote_candidate (NiceComponent *component,
component->selected_pair.remote = remote;
component->selected_pair.priority = priority;
+ /* Get into fallback mode where packets from any source is accepted once
+ * this has been called. This is the expected behavior of pre-ICE SIP.
+ */
+ component->fallback_mode = TRUE;
+
return local;
}
@@ -1107,6 +1114,9 @@ nice_component_finalize (GObject *obj)
g_warn_if_fail (cmp->remote_candidates == NULL);
g_warn_if_fail (cmp->incoming_checks == NULL);
+ g_list_free_full (cmp->valid_candidates,
+ (GDestroyNotify) nice_candidate_free);
+
g_clear_object (&cmp->tcp);
g_clear_object (&cmp->stop_cancellable);
g_clear_object (&cmp->iostream);
@@ -1421,3 +1431,83 @@ turn_server_unref (TurnServer *turn)
g_slice_free (TurnServer, turn);
}
}
+
+void
+nice_component_add_valid_candidate (NiceComponent *component,
+ const NiceCandidate *candidate)
+{
+ guint count = 0;
+ GList *item, *last = NULL;
+
+ for (item = component->valid_candidates; item; item = item->next) {
+ NiceCandidate *cand = item->data;
+
+ last = item;
+ count++;
+ if (nice_candidate_equal_target (cand, candidate))
+ return;
+ }
+
+ /* New candidate */
+
+ if (nice_debug_is_enabled ()) {
+ char str[INET6_ADDRSTRLEN];
+ nice_address_to_string (&candidate->addr, str);
+ nice_debug ("Agent %p : %d:%d Adding valid source"
+ " candidate: %s:%d trans: %d\n", component->agent,
+ candidate->stream_id, candidate->component_id, str,
+ nice_address_get_port (&candidate->addr), candidate->transport);
+ }
+
+ component->valid_candidates = g_list_prepend (
+ component->valid_candidates, nice_candidate_copy (candidate));
+
+ /* Delete the last one to make sure we don't have a list that is too long,
+ * the candidates are not freed on ICE restart as this would be more complex,
+ * we just keep the list not too long.
+ */
+ if (count > NICE_COMPONENT_MAX_VALID_CANDIDATES) {
+ NiceCandidate *cand = last->data;
+
+ component->valid_candidates = g_list_delete_link (
+ component->valid_candidates, last);
+ nice_candidate_free (cand);
+ }
+}
+
+gboolean
+nice_component_verify_remote_candidate (NiceComponent *component,
+ const NiceAddress *address, NiceSocket *nicesock)
+{
+ GList *item;
+
+ if (component->fallback_mode)
+ return TRUE;
+
+ for (item = component->valid_candidates; item; item = item->next) {
+ NiceCandidate *cand = item->data;
+
+ if (((nicesock->type == NICE_SOCKET_TYPE_TCP_BSD &&
+ (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
+ cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE ||
+ cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_SO)) ||
+ cand->transport == NICE_CANDIDATE_TRANSPORT_UDP) &&
+ nice_address_equal (address, &cand->addr)) {
+ /* fast return if it's already the first */
+ if (item == component->valid_candidates)
+ return TRUE;
+
+ /* Put the current candidate at the top so that in the normal use-case,
+ * this function becomes O(1).
+ */
+ component->valid_candidates = g_list_remove_link (
+ component->valid_candidates, item);
+ component->valid_candidates = g_list_concat (item,
+ component->valid_candidates);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/agent/component.h b/agent/component.h
index 6712794..a8a1222 100644
--- a/agent/component.h
+++ b/agent/component.h
@@ -159,12 +159,14 @@ struct _NiceComponent {
NiceComponentState state;
GSList *local_candidates; /* list of NiceCandidate objs */
GSList *remote_candidates; /* list of NiceCandidate objs */
+ GList *valid_candidates; /* list of owned remote NiceCandidates that are part of valid pairs */
GSList *socket_sources; /* list of SocketSource objs; must only grow monotonically */
guint socket_sources_age; /* incremented when socket_sources changes */
GSList *incoming_checks; /* list of IncomingCheck objs */
GList *turn_servers; /* List of TurnServer objs */
CandidatePair selected_pair; /* independent from checklists,
see ICE 11.1. "Sending Media" (ID-19) */
+ gboolean fallback_mode; /* in this case, accepts packets from all, ignore candidate validation */
NiceCandidate *restart_candidate; /* for storing active remote candidate during a restart */
NiceCandidate *turn_candidate; /* for storing active turn candidate if turn servers have been cleared */
/* I/O handling. The main context must always be non-NULL, and is used for all
@@ -301,6 +303,14 @@ turn_server_ref (TurnServer *turn);
void
turn_server_unref (TurnServer *turn);
+void
+nice_component_add_valid_candidate (NiceComponent *component,
+ const NiceCandidate *candidate);
+
+gboolean
+nice_component_verify_remote_candidate (NiceComponent *component,
+ const NiceAddress *address, NiceSocket *nicesock);
+
G_END_DECLS
diff --git a/agent/conncheck.c b/agent/conncheck.c
index 1dc13dd..7ffa3db 100644
--- a/agent/conncheck.c
+++ b/agent/conncheck.c
@@ -2627,6 +2627,7 @@ static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent *
p->state = NICE_CHECK_SUCCEEDED;
nice_debug ("Agent %p : conncheck %p SUCCEEDED.", agent, p);
priv_conn_check_unfreeze_related (agent, stream, p);
+ nice_component_add_valid_candidate (component, remote_candidate);
}
else {
if (!local_cand) {
@@ -2652,8 +2653,10 @@ static CandidateCheckPair *priv_process_response_check_for_reflexive(NiceAgent *
/* note: this is same as "adding to VALID LIST" in the spec
text */
- if (new_pair)
+ if (new_pair) {
new_pair->valid = TRUE;
+ nice_component_add_valid_candidate (component, remote_candidate);
+ }
return new_pair;
}
@@ -2739,6 +2742,7 @@ static gboolean priv_map_reply_to_conn_check_request (NiceAgent *agent, NiceStre
nice_debug ("Agent %p : Mapped address not found."
" conncheck %p SUCCEEDED.", agent, p);
priv_conn_check_unfreeze_related (agent, stream, p);
+ nice_component_add_valid_candidate (component, p->remote);
} else {
ok_pair = priv_process_response_check_for_reflexive (agent,
stream, component, p, sockptr, &sockaddr.addr,
@@ -3654,6 +3658,8 @@ gboolean conn_check_handle_inbound_stun (NiceAgent *agent, NiceStream *stream,
}
}
+ nice_component_add_valid_candidate (component, remote_candidate);
+
priv_reply_to_conn_check (agent, stream, component, local_candidate,
remote_candidate, from, nicesock, rbuf_len, &msg, use_candidate);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7bfe075..d24a2aa 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -45,7 +45,6 @@ check_PROGRAMS = \
test-send-recv \
test-socket-is-based-on \
test-priority \
- test-mainloop \
test-fullmode \
test-restart \
test-fallback \
diff --git a/tests/test-mainloop.c b/tests/test-mainloop.c
deleted file mode 100644
index 7c52daa..0000000
--- a/tests/test-mainloop.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * This file is part of the Nice GLib ICE library.
- *
- * (C) 2006, 2007 Collabora Ltd.
- * Contact: Dafydd Harries
- * (C) 2006, 2007 Nokia Corporation. All rights reserved.
- * Contact: Kai Vehmanen
- *
- * 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:
- * Dafydd Harries, Collabora Ltd.
- * Kai Vehmanen, 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 <string.h>
-
-#include <nice/nice.h>
-#include "socket/socket.h"
-
-static GMainLoop *loop = NULL;
-
-static void
-recv_cb (
- NiceAgent *agent,
- guint stream_id,
- guint component_id,
- guint len,
- gchar *buf,
- gpointer data)
-{
- g_assert (agent != NULL);
- g_assert (stream_id == 1);
- g_assert (component_id == 1);
- g_assert (len == 6);
- g_assert (0 == strncmp (buf, "\x80hello", len));
- g_assert (42 == GPOINTER_TO_UINT (data));
- g_main_loop_quit (loop);
-}
-
-int
-main (void)
-{
- NiceAgent *agent;
- NiceAddress addr;
- guint stream;
-
- nice_address_init (&addr);
-
- loop = g_main_loop_new (NULL, FALSE);
-
- agent = nice_agent_new (g_main_loop_get_context (loop), NICE_COMPATIBILITY_RFC5245);
- nice_address_set_ipv4 (&addr, 0x7f000001);
- nice_agent_add_local_address (agent, &addr);
- stream = nice_agent_add_stream (agent, 1);
- nice_agent_gather_candidates (agent, stream);
-
- // attach to default main context
- nice_agent_attach_recv (agent, stream, NICE_COMPONENT_TYPE_RTP,
- g_main_loop_get_context (loop), recv_cb, GUINT_TO_POINTER (42));
-
- {
- NiceCandidate *candidate;
- GSList *candidates, *i;
-
- candidates = nice_agent_get_local_candidates (agent, 1, 1);
- candidate = candidates->data;
-
- nice_socket_send (candidate->sockptr, &(candidate->addr), 6, "\x80hello");
- for (i = candidates; i; i = i->next)
- nice_candidate_free ((NiceCandidate *) i->data);
- g_slist_free (candidates);
- }
-
- g_main_loop_run (loop);
-
- nice_agent_remove_stream (agent, stream);
- g_object_unref (agent);
-
- return 0;
-}
-