summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
Diffstat (limited to 'res')
-rw-r--r--res/res_rtp_asterisk.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index 62d314446..1cd68736e 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -80,6 +80,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define ZFONE_PROFILE_ID 0x505a
+#define DEFAULT_LEARNING_MIN_SEQUENTIAL 4
+
extern struct ast_srtp_res *res_srtp;
static int dtmftimeout = DEFAULT_DTMF_TIMEOUT;
@@ -96,7 +98,8 @@ static int rtcpdebugport; /*< Debug only RTCP packets from IP or IP+Port if por
#ifdef SO_NO_CHECK
static int nochecksums;
#endif
-static int strictrtp;
+static int strictrtp; /*< Only accept RTP frames from a defined source. If we receive an indication of a changing source, enter learning mode. */
+static int learning_min_sequential; /*< Number of sequential RTP frames needed from a single source during learning mode to accept new source. */
enum strict_rtp_state {
STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
@@ -176,6 +179,13 @@ struct ast_rtp {
struct ast_sockaddr strict_rtp_address; /*!< Remote address information for strict RTP purposes */
struct ast_sockaddr alt_rtp_address; /*!<Alternate remote address information */
+ /*
+ * Learning mode values based on pjmedia's probation mode. Many of these values are redundant to the above,
+ * but these are in place to keep learning mode sequence values sealed from their normal counterparts.
+ */
+ uint16_t learning_max_seq; /*!< Highest sequence number heard */
+ int learning_probation; /*!< Sequential packets untill source is valid */
+
struct rtp_red *red;
};
@@ -460,6 +470,52 @@ static int create_new_socket(const char *type, int af)
return sock;
}
+/*!
+ * \internal
+ * \brief Initializes sequence values and probation for learning mode.
+ * \note This is an adaptation of pjmedia's pjmedia_rtp_seq_init function.
+ *
+ * \param rtp pointer to rtp struct used with the received rtp packet.
+ * \param seq sequence number read from the rtp header
+ */
+static void rtp_learning_seq_init(struct ast_rtp *rtp, uint16_t seq)
+{
+ rtp->learning_max_seq = seq - 1;
+ rtp->learning_probation = learning_min_sequential;
+}
+
+/*!
+ * \internal
+ * \brief Updates sequence information for learning mode and determines if probation/learning mode should remain in effect.
+ * \note This function was adapted from pjmedia's pjmedia_rtp_seq_update function.
+ *
+ * \param rtp pointer to rtp struct used with the received rtp packet.
+ * \param seq sequence number read from the rtp header
+ * \return boolean value indicating if probation mode is active at the end of the function
+ */
+static int rtp_learning_rtp_seq_update(struct ast_rtp *rtp, uint16_t seq)
+{
+ int probation = 0;
+
+ ast_debug(1, "%p -- probation = %d, seq = %d\n", rtp, rtp->learning_probation, seq);
+
+ probation = 1;
+
+ if (seq == rtp->learning_max_seq + 1) {
+ /* packet is in sequence */
+ rtp->learning_probation--;
+ rtp->learning_max_seq = seq;
+ if (rtp->learning_probation == 0) {
+ probation = 0;
+ }
+ } else {
+ rtp->learning_probation = learning_min_sequential - 1;
+ rtp->learning_max_seq = seq;
+ }
+
+ return probation;
+}
+
static int ast_rtp_new(struct ast_rtp_instance *instance,
struct ast_sched_context *sched, struct ast_sockaddr *addr,
void *data)
@@ -476,6 +532,9 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
rtp->ssrc = ast_random();
rtp->seqno = ast_random() & 0xffff;
rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
+ if (strictrtp) {
+ rtp_learning_seq_init(rtp, (uint16_t)rtp->seqno);
+ }
/* Create a new socket for us to listen on and use */
if ((rtp->s =
@@ -2082,7 +2141,17 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
/* 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 -- start learning mode pass with addr = %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, ntohl(rtpheader[0]))) {
+ ast_debug(1, "%p -- Condition for learning hasn't exited, so reject the frame.\n", rtp);
+ return &ast_null_frame;
+ }
+
+ ast_debug(1, "%p -- Probation Ended. Set strict_rtp_state to STRICT_RTP_CLOSED with address %s\n", rtp, ast_sockaddr_stringify(&addr));
rtp->strict_rtp_state = STRICT_RTP_CLOSED;
} else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
if (ast_sockaddr_cmp(&rtp->strict_rtp_address, &addr)) {
@@ -2497,6 +2566,7 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
if (strictrtp) {
rtp->strict_rtp_state = STRICT_RTP_LEARN;
+ rtp_learning_seq_init(rtp, rtp->seqno);
}
return;
@@ -2884,6 +2954,7 @@ static int rtp_reload(int reload)
rtpend = DEFAULT_RTP_END;
dtmftimeout = DEFAULT_DTMF_TIMEOUT;
strictrtp = STRICT_RTP_CLOSED;
+ learning_min_sequential = DEFAULT_LEARNING_MIN_SEQUENTIAL;
if (cfg) {
if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
rtpstart = atoi(s);
@@ -2927,6 +2998,12 @@ static int rtp_reload(int reload)
if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
strictrtp = ast_true(s);
}
+ if ((s = ast_variable_retrieve(cfg, "general", "probation"))) {
+ if ((sscanf(s, "%d", &learning_min_sequential) <= 0) || learning_min_sequential <= 0) {
+ ast_log(LOG_WARNING, "Value for 'probation' could not be read, using default of '%d' instead\n",
+ DEFAULT_LEARNING_MIN_SEQUENTIAL);
+ }
+ }
ast_config_destroy(cfg);
}
if (rtpstart >= rtpend) {