From b11a6643cf9eaf62c26fb6c30eaf75e023515e48 Mon Sep 17 00:00:00 2001 From: Ben Ford <bford@digium.com> Date: Mon, 10 Sep 2018 11:28:09 -0500 Subject: [PATCH] res_rtp_asterisk.c: Add "seqno" strictrtp option 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 | 11 +++++ configs/samples/rtp.conf.sample | 4 ++ res/res_rtp_asterisk.c | 73 ++++++++++++++++++++++----------- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/CHANGES b/CHANGES index 26748f776e..fef72124b3 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,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 -------------------- ------------------------------------------------------------------------------ diff --git a/configs/samples/rtp.conf.sample b/configs/samples/rtp.conf.sample index de9d59007c..26a70d2e16 100644 --- a/configs/samples/rtp.conf.sample +++ b/configs/samples/rtp.conf.sample @@ -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 ; diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 192840ca38..5f7cd9f957 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -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) { -- GitLab