Commit ffc7fdda authored by Olivier Crête's avatar Olivier Crête

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
parent 1e9e28db
......@@ -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 */
......
......@@ -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) &&
......
......@@ -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;
}
......@@ -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
......
......@@ -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);
......
......@@ -45,7 +45,6 @@ check_PROGRAMS = \
test-send-recv \
test-socket-is-based-on \
test-priority \
test-mainloop \
test-fullmode \
test-restart \
test-fallback \
......
/*
* 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment