res_rtp_asterisk.c: Add "seqno" strictrtp option
authorBen Ford <bford@digium.com>
Mon, 10 Sep 2018 16:28:09 +0000 (11:28 -0500)
committerBenjamin Keith Ford <bford@digium.com>
Wed, 26 Sep 2018 18:27:03 +0000 (13:27 -0500)
When networks experience disruptions, there can be large gaps of time
between receiving packets. When strictrtp is enabled, this created
issues where a flood of packets could come in and be seen as an attack.
Another option - seqno - has been added to the strictrtp option that
ignores the time interval and goes strictly by sequence number for
validity.

Change-Id: I8a42b8d193673899c8fc22fe7f98ea87df89be71

CHANGES
configs/samples/rtp.conf.sample
res/res_rtp_asterisk.c

diff --git a/CHANGES b/CHANGES
index 26748f7..fef7212 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,17 @@
 ==============================================================================
 
 ------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 16.0.0 to Asterisk 16.1.0 ------------
+------------------------------------------------------------------------------
+
+res_rtp_asterisk
+------------------
+ * The existing strictrtp option in rtp.conf has a new choice availabe, called
+   'seqno', which behaves the same way as setting strictrtp to 'yes', but will
+   ignore the time interval during learning so that bursts of packets can still
+   trigger learning our source.
+
+------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 15 to Asterisk 16 --------------------
 ------------------------------------------------------------------------------
 
index de9d590..26a70d2 100644 (file)
@@ -31,6 +31,10 @@ rtpend=20000
 ; seconds after starting learning mode.  Once learning mode completes the
 ; current stream is locked in and cannot change until the next
 ; renegotiation.
+; Valid options are "no" to disable strictrtp, "yes" to enable strictrtp,
+; and "seqno", which does the same thing as strictrtp=yes, but only checks
+; to make sure the sequence number is correct rather than checking the time
+; interval as well.
 ; This option is enabled by default.
 ; strictrtp=yes
 ;
index 192840c..5f7cd9f 100644 (file)
@@ -157,6 +157,12 @@ enum strict_rtp_state {
        STRICT_RTP_CLOSED,   /*! Drop all RTP packets not coming from source that was learned */
 };
 
+enum strict_rtp_mode {
+       STRICT_RTP_NO = 0,      /*! Don't adhere to any strict RTP rules */
+       STRICT_RTP_YES,         /*! Strict RTP that restricts packets based on time and sequence number */
+       STRICT_RTP_SEQNO,       /*! Strict RTP that restricts packets based on sequence number */
+};
+
 /*!
  * \brief Strict RTP learning timeout time in milliseconds
  *
@@ -166,7 +172,7 @@ enum strict_rtp_state {
  */
 #define STRICT_RTP_LEARN_TIMEOUT       5000
 
-#define DEFAULT_STRICT_RTP -1  /*!< Enabled */
+#define DEFAULT_STRICT_RTP STRICT_RTP_YES      /*!< Enabled by default */
 #define DEFAULT_ICESUPPORT 1
 
 extern struct ast_srtp_res *res_srtp;
@@ -3154,28 +3160,31 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t
                info->received = ast_tvnow();
        }
 
-       switch (info->stream_type) {
-       case AST_MEDIA_TYPE_UNKNOWN:
-       case AST_MEDIA_TYPE_AUDIO:
-               /*
-                * Protect against packet floods by checking that we
-                * received the packet sequence in at least the minimum
-                * allowed time.
-                */
-               if (ast_tvzero(info->received)) {
-                       info->received = ast_tvnow();
-               } else if (!info->packets
-                       && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) {
-                       /* Packet flood; reset */
-                       info->packets = learning_min_sequential - 1;
-                       info->received = ast_tvnow();
+       /* Only check time if strictrtp is set to yes. Otherwise, we only needed to check seqno */
+       if (strictrtp == STRICT_RTP_YES) {
+               switch (info->stream_type) {
+               case AST_MEDIA_TYPE_UNKNOWN:
+               case AST_MEDIA_TYPE_AUDIO:
+                       /*
+                        * Protect against packet floods by checking that we
+                        * received the packet sequence in at least the minimum
+                        * allowed time.
+                        */
+                       if (ast_tvzero(info->received)) {
+                               info->received = ast_tvnow();
+                       } else if (!info->packets
+                               && ast_tvdiff_ms(ast_tvnow(), info->received) < learning_min_duration) {
+                               /* Packet flood; reset */
+                               info->packets = learning_min_sequential - 1;
+                               info->received = ast_tvnow();
+                       }
+                       break;
+               case AST_MEDIA_TYPE_VIDEO:
+               case AST_MEDIA_TYPE_IMAGE:
+               case AST_MEDIA_TYPE_TEXT:
+               case AST_MEDIA_TYPE_END:
+                       break;
                }
-               break;
-       case AST_MEDIA_TYPE_VIDEO:
-       case AST_MEDIA_TYPE_IMAGE:
-       case AST_MEDIA_TYPE_TEXT:
-       case AST_MEDIA_TYPE_END:
-               break;
        }
 
        info->max_seq = seq;
@@ -6736,6 +6745,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                        && 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));
+                       ast_test_suite_event_notify("STRICT_RTP_LEARN", "Source: %s",
+                               ast_sockaddr_stringify(&rtp->strict_rtp_address));
                        rtp->strict_rtp_state = STRICT_RTP_CLOSED;
                } else {
                        struct ast_sockaddr target_address;
@@ -6822,6 +6833,16 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
                }
                ast_debug(1, "%p -- Received RTP packet from %s, dropping due to strict RTP protection.\n",
                        rtp, ast_sockaddr_stringify(&addr));
+#ifdef TEST_FRAMEWORK
+       {
+               static int strict_rtp_test_event = 1;
+               if (strict_rtp_test_event) {
+                       ast_test_suite_event_notify("STRICT_RTP_CLOSED", "Source: %s",
+                               ast_sockaddr_stringify(&addr));
+                       strict_rtp_test_event = 0; /* Only run this event once to prevent possible spam */
+               }
+       }
+#endif
                return &ast_null_frame;
        case STRICT_RTP_OPEN:
                break;
@@ -8110,7 +8131,13 @@ static int rtp_reload(int reload)
                };
        }
        if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
-               strictrtp = ast_true(s);
+               if (ast_true(s)) {
+                       strictrtp = STRICT_RTP_YES;
+               } else if (!strcasecmp(s, "seqno")) {
+                       strictrtp = STRICT_RTP_SEQNO;
+               } else {
+                       strictrtp = STRICT_RTP_NO;
+               }
        }
        if ((s = ast_variable_retrieve(cfg, "general", "probation"))) {
                if ((sscanf(s, "%d", &learning_min_sequential) != 1) || learning_min_sequential <= 1) {