diff options
Diffstat (limited to 'res')
-rw-r--r-- | res/res_rtp_asterisk.c | 79 |
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) { |