From c0f8196a25d1917a8c1baee7b87825e2d54304d3 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 29 Aug 2014 10:33:48 -0400 Subject: [PATCH] implement detection of duplicate packets to catch and avoid forwarding loops fixes #20 --- daemon/call.c | 27 +++++++++++++++++++++++++++ daemon/call.h | 18 ++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/daemon/call.c b/daemon/call.c index fc283890c..cbd10c23c 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -575,6 +575,7 @@ static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsi struct call_media *media; int ret = 0, update = 0, stun_ret = 0, handler_ret = 0, muxed_rtcp = 0, rtcp = 0, unk = 0; + int i; struct sockaddr_in6 sin6; struct msghdr mh; struct iovec iov; @@ -621,6 +622,32 @@ static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsi stun_ret = 0; } +#if RTP_LOOP_PROTECT + for (i = 0; i < RTP_LOOP_PACKETS; i++) { + if (stream->lp_buf[i].len != s->len) + continue; + if (memcmp(stream->lp_buf[i].buf, s->s, MIN(s->len, RTP_LOOP_PROTECT))) + continue; + + __C_DBG("packet dupe"); + if (stream->lp_count >= RTP_LOOP_MAX_COUNT) { + ilog(LOG_WARNING, "More than %d duplicate packets detected, dropping packet " + "to avoid potential loop", RTP_LOOP_MAX_COUNT); + goto done; + } + + stream->lp_count++; + goto loop_ok; + } + + /* not a dupe */ + stream->lp_count = 0; + stream->lp_buf[stream->lp_idx].len = s->len; + memcpy(stream->lp_buf[stream->lp_idx].buf, s->s, MIN(s->len, RTP_LOOP_PROTECT)); + stream->lp_idx = (stream->lp_idx + 1) % RTP_LOOP_PACKETS; +loop_ok: +#endif + mutex_unlock(&stream->in_lock); in_srtp = stream; diff --git a/daemon/call.h b/daemon/call.h index 90a869fbb..b3dfe655d 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -65,6 +65,12 @@ struct call_monologue; #define RTP_BUFFER_TAIL_ROOM 512 #define RTP_BUFFER_SIZE (MAX_RTP_PACKET_SIZE + RTP_BUFFER_HEAD_ROOM + RTP_BUFFER_TAIL_ROOM) +#ifndef RTP_LOOP_PROTECT +#define RTP_LOOP_PROTECT 16 /* number of bytes */ +#define RTP_LOOP_PACKETS 2 /* number of packets */ +#define RTP_LOOP_MAX_COUNT 30 /* number of consecutively detected dupes to trigger protection */ +#endif + #ifdef __DEBUG #define __C_DBG(x...) ilog(LOG_DEBUG, x) #else @@ -215,6 +221,11 @@ struct endpoint_map { int wildcard:1; }; +struct loop_protector { + unsigned int len; + unsigned char buf[RTP_LOOP_PROTECT]; +}; + struct packet_stream { mutex_t in_lock, out_lock; @@ -238,6 +249,13 @@ struct packet_stream { struct stats kernel_stats; /* LOCK: in_lock */ time_t last_packet; /* LOCK: in_lock */ +#if RTP_LOOP_PROTECT + /* LOCK: in_lock: */ + unsigned int lp_idx; + struct loop_protector lp_buf[RTP_LOOP_PACKETS]; + unsigned int lp_count; +#endif + X509 *dtls_cert; /* LOCK: in_lock */ /* in_lock must be held for SETTING these: */