Package: asterisk / 1:13.14.1~dfsg-2+deb9u4

AST-2017-005-13.13.diff Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
From ae26ddb9f5cb10e565dc756c14df1da36eeff930 Mon Sep 17 00:00:00 2001
From: Joshua Colp <jcolp@digium.com>
Date: Mon, 22 May 2017 15:36:38 +0000
Subject: [PATCH] res_rtp_asterisk: Only learn a new source in learn state.

This change moves the logic which learns a new source address
for RTP so it only occurs in the learning state. The learning
state is entered on initial allocation of RTP or if we are
told that the remote address for the media has changed. While
in the learning state if we continue to receive media from
the original source we restart the learning process. It is
only once we receive a sufficient number of RTP packets from
the new source that we will switch to it. Once this is done
the closed state is entered where all packets that do not
originate from the expected source are dropped.

The learning process has also been improved to take into
account the time between received packets so a flood of them
while in the learning state does not cause media to be switched.

Finally RTCP now drops packets which are not for the learned
SSRC if strict RTP is enabled.

ASTERISK-27013

Change-Id: I56a96e993700906355e79bc880ad9d4ad3ab129c
---

diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index e6ac793..18646a5 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -213,8 +213,9 @@
 
 /*! \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 */
+	int max_seq;	 /*!< The highest sequence number received */
+	int packets;	 /*!< The number of remaining packets before the source is accepted */
+	struct timeval received; /*!< The time of the last received packet */
 };
 
 #ifdef HAVE_OPENSSL_SRTP
@@ -299,7 +300,6 @@
 	 * but these are in place to keep learning mode sequence values sealed from their normal counterparts.
 	 */
 	struct rtp_learning_info rtp_source_learn;	/* Learning mode track for the expected RTP source */
-	struct rtp_learning_info alt_source_learn;	/* Learning mode tracking for a new RTP source after one has been chosen */
 
 	struct rtp_red *red;
 
@@ -2424,6 +2424,7 @@
 {
 	info->max_seq = seq - 1;
 	info->packets = learning_min_sequential;
+	memset(&info->received, 0, sizeof(info->received));
 }
 
 /*!
@@ -2438,6 +2439,13 @@
  */
 static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t seq)
 {
+	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.
+		 */
+		return 1;
+	}
+
 	if (seq == info->max_seq + 1) {
 		/* packet is in sequence */
 		info->packets--;
@@ -2446,6 +2454,7 @@
 		info->packets = learning_min_sequential - 1;
 	}
 	info->max_seq = seq;
+	info->received = ast_tvnow();
 
 	return (info->packets == 0);
 }
@@ -2652,10 +2661,9 @@
 	/* Set default parameters on the newly created RTP structure */
 	rtp->ssrc = ast_random();
 	rtp->seqno = ast_random() & 0x7fff;
-	rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
+	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);
-		rtp_learning_seq_init(&rtp->alt_source_learn, (uint16_t)rtp->seqno);
 	}
 
 	/* Create a new socket for us to listen on and use */
@@ -4154,17 +4162,6 @@
 
 	packetwords = res / 4;
 
-	if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
-		/* Send to whoever sent to us */
-		if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) {
-			ast_sockaddr_copy(&rtp->rtcp->them, &addr);
-			if (rtpdebug) {
-				ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
-					  ast_sockaddr_stringify(&rtp->rtcp->them));
-			}
-		}
-	}
-
 	ast_debug(1, "Got RTCP report of %d bytes\n", res);
 
 	while (position < packetwords) {
@@ -4191,6 +4188,25 @@
 				ast_debug(1, "RTCP Read too short\n");
 			}
 			return &ast_null_frame;
+		}
+
+		if ((rtp->strict_rtp_state != STRICT_RTP_OPEN) && (rtcp_report->ssrc != rtp->themssrc)) {
+			/* Skip over this RTCP record as it does not contain the correct SSRC */
+			position += (length + 1);
+			ast_debug(1, "%p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u'\n",
+				rtp, ast_sockaddr_stringify(&addr), rtcp_report->ssrc, rtp->themssrc);
+			continue;
+		}
+
+		if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
+			/* Send to whoever sent to us */
+			if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) {
+				ast_sockaddr_copy(&rtp->rtcp->them, &addr);
+				if (rtpdebug) {
+					ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
+						ast_sockaddr_stringify(&rtp->rtcp->them));
+				}
+			}
 		}
 
 		if (rtcp_debug_test_addr(&addr)) {
@@ -4517,37 +4533,30 @@
 
 	/* 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) {
-		ast_debug(1, "%p -- Probation learning mode pass with source address %s\n", rtp, ast_sockaddr_stringify(&addr));
-		/* For now, we always copy the address. */
-		ast_sockaddr_copy(&rtp->strict_rtp_address, &addr);
-
-		/* Send the rtp and the seqno from header to rtp_learning_rtp_seq_update to see whether we can exit or not*/
-		if (rtp_learning_rtp_seq_update(&rtp->rtp_source_learn, seqno)) {
-			ast_debug(1, "%p -- Probation at seq %d with %d to go; discarding frame\n",
-				rtp, rtp->rtp_source_learn.max_seq, rtp->rtp_source_learn.packets);
-			return &ast_null_frame;
-		}
-
-		ast_verb(4, "%p -- Probation passed - setting RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
-		rtp->strict_rtp_state = STRICT_RTP_CLOSED;
-	}
-	if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
 		if (!ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
-			/* Always reset the alternate learning source */
-			rtp_learning_seq_init(&rtp->alt_source_learn, seqno);
+			/* 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->alt_source_learn, seqno)) {
+			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->alt_source_learn.packets);
+					rtp, ast_sockaddr_stringify(&addr), rtp->rtp_source_learn.packets);
 				return &ast_null_frame;
 			}
-			ast_verb(4, "%p -- Switching RTP source address to %s\n", rtp, ast_sockaddr_stringify(&addr));
 			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));
+			rtp->strict_rtp_state = STRICT_RTP_CLOSED;
 		}
+	} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED && ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
+		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;
 	}
 
 	/* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */
@@ -5005,7 +5014,11 @@
 
 	rtp->rxseqno = 0;
 
-	if (strictrtp && rtp->strict_rtp_state != STRICT_RTP_OPEN) {
+	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);
 	}