[Asterisk-code-review] res rtp asterisk.c: Make strict RTP learning more flexible. (asterisk[13])

Richard Mudgett asteriskteam at digium.com
Tue Sep 5 14:59:42 CDT 2017


Richard Mudgett has uploaded this change for review. ( https://gerrit.asterisk.org/6410


Change subject: res_rtp_asterisk.c: Make strict RTP learning more flexible.
......................................................................

res_rtp_asterisk.c: Make strict RTP learning more flexible.

Direct media can cause strict RTP to attempt to learn a remote address
again before it has had a chance to learn the remote address the first
time.  Because of the rapid relearn requests, strict RTP could latch onto
the first remote address and fail to latch onto the direct media remote
address.  As a result, you have one way audio until the call is placed on
and off hold.

The new algorythm learns remote addresses for a set time (1.5 seconds)
before locking the remote address.  In addition, we must see a configured
number of remote packets from the same address in a row before switching.

* Fixed strict RTP learning from always accepting the first new address
packet as the new stream.

* Fixed strict RTP to initialize the expected sequence number with the
last received sequence number instead of the last transmitted sequence
number.

* Fixed the predicted next sequence number calculation in
rtp_learning_rtp_seq_update() to handle overflow.

ASTERISK-27252

Change-Id: Ia2d3aa6e0f22906c25971e74f10027d96525f31c
---
M res/res_rtp_asterisk.c
1 file changed, 91 insertions(+), 41 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/10/6410/1

diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 77027aa..b1f6b56 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -117,7 +117,9 @@
 	STRICT_RTP_CLOSED,   /*! Drop all RTP packets not coming from source that was learned */
 };
 
-#define DEFAULT_STRICT_RTP STRICT_RTP_CLOSED
+#define STRICT_RTP_LEARN_TIMEOUT	1500	/*!< milliseconds */
+
+#define DEFAULT_STRICT_RTP -1	/*!< Enabled */
 #define DEFAULT_ICESUPPORT 1
 
 extern struct ast_srtp_res *res_srtp;
@@ -218,9 +220,11 @@
 
 /*! \brief RTP learning mode tracking information */
 struct rtp_learning_info {
-	int max_seq;	 /*!< The highest sequence number received */
-	int packets;	 /*!< The number of remaining packets before the source is accepted */
+	struct ast_sockaddr proposed_address;	/*!< Proposed remote address for strict RTP */
+	struct timeval start;	/*!< The time learning mode was started */
 	struct timeval received; /*!< The time of the last received packet */
+	int max_seq;	/*!< The highest sequence number received */
+	int packets;	/*!< The number of remaining packets before the source is accepted */
 };
 
 #ifdef HAVE_OPENSSL_SRTP
@@ -1984,7 +1988,7 @@
 #endif
 
 #ifdef HAVE_PJPROJECT
-static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq);
+static void rtp_learning_start(struct ast_rtp *rtp);
 
 /* PJPROJECT ICE callback */
 static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
@@ -2023,8 +2027,8 @@
 		return;
 	}
 
-	rtp->strict_rtp_state = STRICT_RTP_LEARN;
-	rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
+	ast_verb(4, "%p -- Strict RTP learning after ICE completion\n", rtp);
+	rtp_learning_start(rtp);
 	ao2_unlock(instance);
 }
 
@@ -2753,7 +2757,7 @@
  */
 static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq)
 {
-	info->max_seq = seq - 1;
+	info->max_seq = seq;
 	info->packets = learning_min_sequential;
 	memset(&info->received, 0, sizeof(info->received));
 }
@@ -2770,14 +2774,17 @@
  */
 static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq)
 {
+	/*
+	 * During the learning mode the minimum amount of media we'll accept is
+	 * 10ms so give a reasonable 5ms buffer just in case we get it sporadically.
+	 */
 	if (!ast_tvzero(info->received) && ast_tvdiff_ms(ast_tvnow(), info->received) < 5) {
-		/* During the probation period the minimum amount of media we'll accept is
-		 * 10ms so give a reasonable 5ms buffer just in case we get it sporadically.
+		/*
+		 * Reject a flood of packets as acceptable for learning.
+		 * Reset the needed packets.
 		 */
-		return 1;
-	}
-
-	if (seq == info->max_seq + 1) {
+		info->packets = learning_min_sequential - 1;
+	} else if (seq == (uint16_t) (info->max_seq + 1)) {
 		/* packet is in sequence */
 		info->packets--;
 	} else {
@@ -2787,7 +2794,24 @@
 	info->max_seq = seq;
 	info->received = ast_tvnow();
 
-	return (info->packets == 0);
+	return info->packets;
+}
+
+/*!
+ * \brief Start the strictrtp learning mode.
+ * \since 13.18.0
+ *
+ * \param rtp RTP session description
+ *
+ * \return Nothing
+ */
+static void rtp_learning_start(struct ast_rtp *rtp)
+{
+	rtp->strict_rtp_state = STRICT_RTP_LEARN;
+	memset(&rtp->rtp_source_learn.proposed_address, 0,
+		sizeof(rtp->rtp_source_learn.proposed_address));
+	rtp->rtp_source_learn.start = ast_tvnow();
+	rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t) rtp->lastrxseqno);
 }
 
 #ifdef HAVE_PJPROJECT
@@ -3061,9 +3085,6 @@
 	rtp->ssrc = ast_random();
 	rtp->seqno = ast_random() & 0x7fff;
 	rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_CLOSED : STRICT_RTP_OPEN);
-	if (strictrtp) {
-		rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
-	}
 
 	/* Create a new socket for us to listen on and use */
 	if ((rtp->s =
@@ -5076,31 +5097,59 @@
 	}
 
 	/* If strict RTP protection is enabled see if we need to learn the remote address or if we need to drop the packet */
-	if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
-		if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
-			/* We are learning a new address but have received traffic from the existing address,
-			 * accept it but reset the current learning for the new source so it only takes over
-			 * once sufficient traffic has been received. */
-			rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
-		} else {
-			/* Start trying to learn from the new address. If we pass a probationary period with
-			 * it, that means we've stopped getting RTP from the original source and we should
-			 * switch to it.
-			 */
-			if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
-				ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",
-					rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
-				return &ast_null_frame;
-			}
-			ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
-
-			ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
+	switch (rtp->strict_rtp_state) {
+	case STRICT_RTP_LEARN:
+		if (!ast_sockaddr_isnull(&rtp->strict_rtp_address)
+			&& STRICT_RTP_LEARN_TIMEOUT < ast_tvdiff_ms(ast_tvnow(), rtp->rtp_source_learn.start)) {
+			ast_verb(4, "%p -- Strict RTP learning complete - Locking on source address %s\n",
+				rtp, ast_sockaddr_stringify(&rtp->strict_rtp_address));
 			rtp->strict_rtp_state = STRICT_RTP_CLOSED;
+		} else {
+			if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+				/*
+				 * We are learning a new address but have received traffic from the existing address,
+				 * accept it but reset the current learning for the new source so it only takes over
+				 * once sufficient traffic has been received.
+				 */
+				rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+				break;
+			}
+			/*
+			 * Trying to learn a new address.  If we pass a probationary period with
+			 * it, that means we've stopped getting RTP from the original source and
+			 * we should switch to it.
+			 */
+			if (!ast_sockaddr_cmp(&rtp->rtp_source_learn.proposed_address, &addr)) {
+				if (!rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
+					/* Accept the new RTP stream */
+					ast_verb(4, "%p -- Strict RTP switching source address to %s\n",
+						rtp, ast_sockaddr_stringify(&addr));
+					ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
+					break;
+				}
+				/* Not ready to accept the RTP stream candidate */
+			} else {
+				/*
+				 * This is either an attacking stream or
+				 * the start of the expected new stream.
+				 */
+				ast_sockaddr_copy(&rtp->rtp_source_learn.proposed_address, &addr);
+				rtp_learning_seq_init(&rtp->rtp_source_learn, seqno);
+			}
+			ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets\n",
+				rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
+			return &ast_null_frame;
 		}
-	} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+		/* Fall through */
+	case STRICT_RTP_CLOSED:
+		if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+			break;
+		}
 		ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n",
 			rtp, ast_sockaddr_stringify(&addr));
 		return &ast_null_frame;
+	case STRICT_RTP_OPEN:
+		break;
 	}
 
 	/* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */
@@ -5618,13 +5667,14 @@
 
 	rtp->rxseqno = 0;
 
-	if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN && !ast_sockaddr_isnull(addr) &&
-		ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) {
+	if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN
+		&& !ast_sockaddr_isnull(addr) && ast_sockaddr_cmp(addr, &rtp->strict_rtp_address)) {
 		/* We only need to learn a new strict source address if we've been told the source is
 		 * changing to something different.
 		 */
-		rtp->strict_rtp_state = STRICT_RTP_LEARN;
-		rtp_learning_seq_init(&rtp->rtp_source_learn, rtp->seqno);
+		ast_verb(4, "%p -- Strict RTP learning after remote address set to: %s\n",
+			rtp, ast_sockaddr_stringify(addr));
+		rtp_learning_start(rtp);
 	}
 }
 

-- 
To view, visit https://gerrit.asterisk.org/6410
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia2d3aa6e0f22906c25971e74f10027d96525f31c
Gerrit-Change-Number: 6410
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Mudgett <rmudgett at digium.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20170905/7a68bd35/attachment-0001.html>


More information about the asterisk-code-review mailing list