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
pull/11/head
Ben Ford 7 years ago committed by Benjamin Keith Ford
parent aa10d6d5eb
commit b11a6643cf

@ -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 --------------------
------------------------------------------------------------------------------

@ -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
;

@ -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) {

Loading…
Cancel
Save