@ -115,7 +115,9 @@ enum strict_rtp_state {
STRICT_RTP_CLOSED , /*! Drop all RTP packets not coming from source that was learned */
} ;
# define DEFAULT_STRICT_RTP STRICT_RTP_CLOSED
# define STRICT_RTP_LEARN_TIMEOUT 1500 /*!< milliseconds */
# define DEFAULT_STRICT_RTP -1 /*!< Enabled */
# define DEFAULT_ICESUPPORT 1
extern struct ast_srtp_res * res_srtp ;
@ -199,9 +201,11 @@ static AST_LIST_HEAD_STATIC(ioqueues, ast_rtp_ioqueue_thread);
/*! \brief RTP learning mode tracking information */
struct rtp_learning_info {
struct ast_sockaddr proposed_address ; /*!< Proposed remote address for strict RTP */
struct timeval start ; /*!< The time learning mode was started */
struct timeval received ; /*!< The time of the last received packet */
int max_seq ; /*!< The highest sequence number received */
int packets ; /*!< The number of remaining packets before the source is accepted */
struct timeval received ; /*!< The time of the last received packet */
} ;
# ifdef HAVE_OPENSSL_SRTP
@ -223,7 +227,7 @@ struct ast_rtp {
unsigned char rawdata [ 8192 + AST_FRIENDLY_OFFSET ] ;
unsigned int ssrc ; /*!< Synchronization source, RFC 3550, page 10. */
unsigned int themssrc ; /*!< Their SSRC */
unsigned int rxssrc;
unsigned int themssrc_valid; /*!< True if their SSRC is available. */
unsigned int lastts ;
unsigned int lastrxts ;
unsigned int lastividtimestamp ;
@ -1655,8 +1659,6 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
# endif
} ;
static void rtp_learning_seq_init ( struct rtp_learning_info * info , uint16_t seq ) ;
# ifdef HAVE_OPENSSL_SRTP
static void dtls_perform_handshake ( struct ast_rtp_instance * instance , struct dtls_details * dtls , int rtcp )
{
@ -1685,6 +1687,8 @@ static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtl
# endif
# ifdef USE_PJPROJECT
static void rtp_learning_start ( struct ast_rtp * rtp ) ;
static void ast_rtp_on_ice_complete ( pj_ice_sess * ice , pj_status_t status )
{
struct ast_rtp_instance * instance = ice - > user_data ;
@ -1721,8 +1725,8 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
return ;
}
rtp - > strict_rtp_state = STRICT_RTP_LEARN ;
rtp_learning_s eq_init( & rtp - > rtp_source_learn , ( uint16_t ) rtp - > seqno ) ;
ast_verb ( 4 , " %p -- Strict RTP learning after ICE completion \n " , rtp ) ;
rtp_learning_s tart( rtp ) ;
}
static void ast_rtp_on_ice_rx_data ( pj_ice_sess * ice , unsigned comp_id , unsigned transport_id , void * pkt , pj_size_t size , const pj_sockaddr_t * src_addr , unsigned src_addr_len )
@ -2355,7 +2359,7 @@ static int create_new_socket(const char *type, int af)
*/
static void rtp_learning_seq_init ( struct rtp_learning_info * info , uint16_t seq )
{
info - > max_seq = seq - 1 ;
info - > max_seq = seq ;
info - > packets = learning_min_sequential ;
memset ( & info - > received , 0 , sizeof ( info - > received ) ) ;
}
@ -2372,14 +2376,17 @@ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq)
*/
static int rtp_learning_rtp_seq_update ( struct rtp_learning_info * info , uint16_t seq )
{
/*
* During the learning mode the minimum amount of media we ' ll accept is
* 10 ms so give a reasonable 5 ms buffer just in case we get it sporadically .
*/
if ( ! ast_tvzero ( info - > received ) & & ast_tvdiff_ms ( ast_tvnow ( ) , info - > received ) < 5 ) {
/* During the probation period the minimum amount of media we'll accept is
* 10 ms so give a reasonable 5 ms buffer just in case we get it sporadically .
/*
* Reject a flood of packets as acceptable for learning .
* Reset the needed packets .
*/
return 1 ;
}
if ( seq = = info - > max_seq + 1 ) {
info - > packets = learning_min_sequential - 1 ;
} else if ( seq = = ( uint16_t ) ( info - > max_seq + 1 ) ) {
/* packet is in sequence */
info - > packets - - ;
} else {
@ -2389,7 +2396,23 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t
info - > max_seq = seq ;
info - > received = ast_tvnow ( ) ;
return ( info - > packets = = 0 ) ;
return info - > packets ;
}
/*!
* \ brief Start the strictrtp learning mode .
*
* \ param rtp RTP session description
*
* \ return Nothing
*/
static void rtp_learning_start ( struct ast_rtp * rtp )
{
rtp - > strict_rtp_state = STRICT_RTP_LEARN ;
memset ( & rtp - > rtp_source_learn . proposed_address , 0 ,
sizeof ( rtp - > rtp_source_learn . proposed_address ) ) ;
rtp - > rtp_source_learn . start = ast_tvnow ( ) ;
rtp_learning_seq_init ( & rtp - > rtp_source_learn , ( uint16_t ) rtp - > lastrxseqno ) ;
}
# ifdef USE_PJPROJECT
@ -2546,10 +2569,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
/* Set default parameters on the newly created RTP structure */
rtp - > ssrc = ast_random ( ) ;
rtp - > seqno = ast_random ( ) & 0x7fff ;
rtp - > strict_rtp_state = ( strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN ) ;
if ( strictrtp ) {
rtp_learning_seq_init ( & rtp - > rtp_source_learn , ( uint16_t ) rtp - > seqno ) ;
}
rtp - > strict_rtp_state = ( strictrtp ? STRICT_RTP_CLOSED : STRICT_RTP_OPEN ) ;
/* Create a new socket for us to listen on and use */
if ( ( rtp - > s =
@ -3867,13 +3887,86 @@ static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, u
return & rtp - > f ;
}
static const char * rtcp_payload_type2str ( unsigned int pt )
{
const char * str ;
switch ( pt ) {
case RTCP_PT_SR :
str = " Sender Report " ;
break ;
case RTCP_PT_RR :
str = " Receiver Report " ;
break ;
case RTCP_PT_FUR :
/* Full INTRA-frame Request / Fast Update Request */
str = " H.261 FUR " ;
break ;
case RTCP_PT_SDES :
str = " Source Description " ;
break ;
case RTCP_PT_BYE :
str = " BYE " ;
break ;
default :
str = " Unknown " ;
break ;
}
return str ;
}
/*
* Unshifted RTCP header bit field masks
*/
# define RTCP_LENGTH_MASK 0xFFFF
# define RTCP_PAYLOAD_TYPE_MASK 0xFF
# define RTCP_REPORT_COUNT_MASK 0x1F
# define RTCP_PADDING_MASK 0x01
# define RTCP_VERSION_MASK 0x03
/*
* RTCP header bit field shift offsets
*/
# define RTCP_LENGTH_SHIFT 0
# define RTCP_PAYLOAD_TYPE_SHIFT 16
# define RTCP_REPORT_COUNT_SHIFT 24
# define RTCP_PADDING_SHIFT 29
# define RTCP_VERSION_SHIFT 30
# define RTCP_VERSION 2U
# define RTCP_VERSION_SHIFTED (RTCP_VERSION << RTCP_VERSION_SHIFT)
# define RTCP_VERSION_MASK_SHIFTED (RTCP_VERSION_MASK << RTCP_VERSION_SHIFT)
/*
* RTCP first packet record validity header mask and value .
*
* RFC3550 intentionally defines the encoding of RTCP_PT_SR and RTCP_PT_RR
* such that they differ in the least significant bit . Either of these two
* payload types MUST be the first RTCP packet record in a compound packet .
*
* RFC3550 checks the padding bit in the algorithm they use to check the
* RTCP packet for validity . However , we aren ' t masking the padding bit
* to check since we don ' t know if it is a compound RTCP packet or not .
*/
# define RTCP_VALID_MASK (RTCP_VERSION_MASK_SHIFTED | (((RTCP_PAYLOAD_TYPE_MASK & ~0x1)) << RTCP_PAYLOAD_TYPE_SHIFT))
# define RTCP_VALID_VALUE (RTCP_VERSION_SHIFTED | (RTCP_PT_SR << RTCP_PAYLOAD_TYPE_SHIFT))
# define RTCP_SR_BLOCK_WORD_LENGTH 5
# define RTCP_RR_BLOCK_WORD_LENGTH 6
# define RTCP_HEADER_SSRC_LENGTH 2
static struct ast_frame * ast_rtcp_read ( struct ast_rtp_instance * instance )
{
struct ast_rtp * rtp = ast_rtp_instance_get_data ( instance ) ;
struct ast_sockaddr addr ;
unsigned char rtcpdata [ 8192 + AST_FRIENDLY_OFFSET ] ;
unsigned int * rtcpheader = ( unsigned int * ) ( rtcpdata + AST_FRIENDLY_OFFSET ) ;
int res , packetwords , position = 0 ;
int res ;
unsigned int packetwords ;
unsigned int position ;
unsigned int first_word ;
/*! True if we have seen an acceptable SSRC to learn the remote RTCP address */
unsigned int ssrc_seen ;
struct ast_frame * f = & ast_null_frame ;
/* Read in RTCP data from the socket */
@ -3918,56 +4011,170 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
packetwords = res / 4 ;
ast_debug ( 1 , " Got RTCP report of %d bytes \n " , res ) ;
ast_debug ( 1 , " Got RTCP report of %d bytes from %s \n " ,
res , ast_sockaddr_stringify ( & addr ) ) ;
/*
* Validate the RTCP packet according to an adapted and slightly
* modified RFC3550 validation algorithm .
*/
if ( packetwords < RTCP_HEADER_SSRC_LENGTH ) {
ast_debug ( 1 , " %p -- RTCP from %s: Frame size (%u words) is too short \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , packetwords ) ;
return & ast_null_frame ;
}
position = 0 ;
first_word = ntohl ( rtcpheader [ position ] ) ;
if ( ( first_word & RTCP_VALID_MASK ) ! = RTCP_VALID_VALUE ) {
ast_debug ( 1 , " %p -- RTCP from %s: Failed first packet validity check \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
return & ast_null_frame ;
}
do {
position + = ( ( first_word > > RTCP_LENGTH_SHIFT ) & RTCP_LENGTH_MASK ) + 1 ;
if ( packetwords < = position ) {
break ;
}
first_word = ntohl ( rtcpheader [ position ] ) ;
} while ( ( first_word & RTCP_VERSION_MASK_SHIFTED ) = = RTCP_VERSION_SHIFTED ) ;
if ( position ! = packetwords ) {
ast_debug ( 1 , " %p -- RTCP from %s: Failed packet version or length check \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
return & ast_null_frame ;
}
/*
* Note : RFC3605 points out that true NAT ( vs NAPT ) can cause RTCP
* to have a different IP address and port than RTP . Otherwise , when
* strictrtp is enabled we could reject RTCP packets not coming from
* the learned RTP IP address if it is available .
*/
/*
* strictrtp safety needs SSRC to match before we use the
* sender ' s address for symmetrical RTP to send our RTCP
* reports .
*
* If strictrtp is not enabled then claim to have already seen
* a matching SSRC so we ' ll accept this packet ' s address for
* symmetrical RTP .
*/
ssrc_seen = rtp - > strict_rtp_state = = STRICT_RTP_OPEN ;
position = 0 ;
while ( position < packetwords ) {
int i , pt , rc ;
unsigned int length , dlsr , lsr , msw , lsw , comp ;
unsigned int i ;
unsigned int pt ;
unsigned int rc ;
unsigned int ssrc ;
/*! True if the ssrc value we have is valid and not garbage because it doesn't exist. */
unsigned int ssrc_valid ;
unsigned int length ;
unsigned int min_length ;
unsigned int dlsr , lsr , msw , lsw , comp ;
struct timeval now ;
double rttsec , reported_jitter , reported_normdev_jitter_current , normdevrtt_current , reported_lost , reported_normdev_lost_current ;
uint64_t rtt = 0 ;
i = position ;
length = ntohl ( rtcpheader [ i ] ) ;
pt = ( length & 0xff0000 ) > > 16 ;
rc = ( length & 0x1f000000 ) > > 24 ;
length & = 0xffff ;
if ( ( i + length ) > packetwords ) {
if ( rtpdebug )
ast_debug ( 1 , " RTCP Read too short \n " ) ;
first_word = ntohl ( rtcpheader [ i ] ) ;
pt = ( first_word > > RTCP_PAYLOAD_TYPE_SHIFT ) & RTCP_PAYLOAD_TYPE_MASK ;
rc = ( first_word > > RTCP_REPORT_COUNT_SHIFT ) & RTCP_REPORT_COUNT_MASK ;
/* RFC3550 says 'length' is the number of words in the packet - 1 */
length = ( ( first_word > > RTCP_LENGTH_SHIFT ) & RTCP_LENGTH_MASK ) + 1 ;
/* Check expected RTCP packet record length */
min_length = RTCP_HEADER_SSRC_LENGTH ;
switch ( pt ) {
case RTCP_PT_SR :
min_length + = RTCP_SR_BLOCK_WORD_LENGTH ;
/* fall through */
case RTCP_PT_RR :
min_length + = ( rc * RTCP_RR_BLOCK_WORD_LENGTH ) ;
break ;
case RTCP_PT_FUR :
break ;
case RTCP_PT_SDES :
case RTCP_PT_BYE :
/*
* There may not be a SSRC / CSRC present . The packet is
* useless but still valid if it isn ' t present .
*
* We don ' t know what min_length should be so disable the check
*/
min_length = length ;
break ;
default :
ast_debug ( 1 , " %p -- RTCP from %s: %u(%s) skipping record \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , pt , rtcp_payload_type2str ( pt ) ) ;
if ( rtcp_debug_test_addr ( & addr ) ) {
ast_verbose ( " \n " ) ;
ast_verbose ( " RTCP from %s: %u(%s) skipping record \n " ,
ast_sockaddr_stringify ( & addr ) , pt , rtcp_payload_type2str ( pt ) ) ;
}
position + = length ;
continue ;
}
if ( length < min_length ) {
ast_debug ( 1 , " %p -- RTCP from %s: %u(%s) length field less than expected minimum. Min:%u Got:%u \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , pt , rtcp_payload_type2str ( pt ) ,
min_length - 1 , length - 1 ) ;
return & ast_null_frame ;
}
if ( ( rtp - > strict_rtp_state ! = STRICT_RTP_OPEN ) & & ( ntohl ( rtcpheader [ i + 1 ] ) ! = rtp - > themssrc ) ) {
/* Skip over this RTCP record as it does not contain the correct SSRC */
position + = ( length + 1 ) ;
ast_debug ( 1 , " %p -- Received RTCP report from %s, dropping due to strict RTP protection. Received SSRC '%u' but expected '%u' \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , ntohl ( rtcpheader [ i + 1 ] ) , rtp - > themssrc ) ;
continue ;
/* Get the RTCP record SSRC if defined for the record */
ssrc_valid = 1 ;
switch ( pt ) {
case RTCP_PT_SR :
case RTCP_PT_RR :
case RTCP_PT_FUR :
ssrc = ntohl ( rtcpheader [ i + 1 ] ) ;
break ;
case RTCP_PT_SDES :
case RTCP_PT_BYE :
default :
ssrc = 0 ;
ssrc_valid = 0 ;
break ;
}
if ( ast_rtp_instance_get_prop ( instance , AST_RTP_PROPERTY_NAT ) ) {
if ( rtcp_debug_test_addr ( & addr ) ) {
ast_verbose ( " \n " ) ;
ast_verbose ( " RTCP from %s \n " , ast_sockaddr_stringify ( & addr ) ) ;
ast_verbose ( " PT: %u(%s) \n " , pt , rtcp_payload_type2str ( pt ) ) ;
ast_verbose ( " Reception reports: %u \n " , rc ) ;
ast_verbose ( " SSRC of sender: %u \n " , ssrc ) ;
}
if ( ssrc_valid & & rtp - > themssrc_valid ) {
if ( ssrc ! = rtp - > themssrc ) {
/*
* Skip over this RTCP record as it does not contain the
* correct SSRC . We should not act upon RTCP records
* for a different stream .
*/
position + = length ;
ast_debug ( 1 , " %p -- RTCP from %s: Skipping record, received SSRC '%u' != expected '%u' \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , ssrc , rtp - > themssrc ) ;
continue ;
}
ssrc_seen = 1 ;
}
if ( ssrc_seen & & ast_rtp_instance_get_prop ( instance , AST_RTP_PROPERTY_NAT ) ) {
/* Send to whoever sent to us */
if ( ast_sockaddr_cmp ( & rtp - > rtcp - > them , & addr ) ) {
ast_sockaddr_copy ( & rtp - > rtcp - > them , & addr ) ;
if ( rtpdebug )
if ( rtpdebug ) {
ast_debug ( 0 , " RTCP NAT: Got RTCP from other end. Now sending to address %s \n " ,
ast_sockaddr_stringify ( & rtp - > rtcp - > them ) ) ;
ast_sockaddr_stringify ( & addr ) ) ;
}
}
}
if ( rtcp_debug_test_addr ( & addr ) ) {
ast_verbose ( " \n \n Got RTCP from %s \n " ,
ast_sockaddr_stringify ( & addr ) ) ;
ast_verbose ( " PT: %d(%s) \n " , pt , ( pt = = 200 ) ? " Sender Report " : ( pt = = 201 ) ? " Receiver Report " : ( pt = = 192 ) ? " H.261 FUR " : " Unknown " ) ;
ast_verbose ( " Reception reports: %d \n " , rc ) ;
ast_verbose ( " SSRC of sender: %u \n " , rtcpheader [ i + 1 ] ) ;
}
i + = 2 ; /* Advance past header and ssrc */
i + = RTCP_HEADER_SSRC_LENGTH ; /* Advance past header and ssrc */
if ( rc = = 0 & & pt = = RTCP_PT_RR ) { /* We're receiving a receiver report with no reports, which is ok */
position + = ( length + 1 ) ;
position + = length ;
continue ;
}
@ -3983,7 +4190,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
ast_verbose ( " RTP timestamp: %lu \n " , ( unsigned long ) ntohl ( rtcpheader [ i + 2 ] ) ) ;
ast_verbose ( " SPC: %lu \t SOC: %lu \n " , ( unsigned long ) ntohl ( rtcpheader [ i + 3 ] ) , ( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) ) ;
}
i + = 5 ;
i + = RTCP_SR_BLOCK_WORD_LENGTH ;
if ( rc < 1 )
break ;
/* Intentional fall through */
@ -4153,21 +4360,18 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
case RTCP_PT_SDES :
if ( rtcp_debug_test_addr ( & addr ) )
ast_verbose ( " Received an SDES from %s \n " ,
ast_sockaddr_stringify ( & rtp- > rtcp - > them ) ) ;
ast_sockaddr_stringify ( & add r) ) ;
break ;
case RTCP_PT_BYE :
if ( rtcp_debug_test_addr ( & addr ) )
ast_verbose ( " Received a BYE from %s \n " ,
ast_sockaddr_stringify ( & rtp- > rtcp - > them ) ) ;
ast_sockaddr_stringify ( & add r) ) ;
break ;
default :
ast_debug ( 1 , " Unknown RTCP packet (pt=%d) received from %s \n " ,
pt , ast_sockaddr_stringify ( & rtp - > rtcp - > them ) ) ;
break ;
}
position + = ( length + 1 ) ;
position + = length ;
}
rtp - > rtcp - > rtcp_info = 1 ;
return f ;
@ -4344,39 +4548,156 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
return & ast_null_frame ;
}
/* If the version is not what we expected by this point then just drop the packet */
if ( version ! = 2 ) {
return & ast_null_frame ;
}
/* 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 ) {
if ( ! ast_sockaddr_cmp ( & rtp - > strict_rtp_address , & addr ) ) {
/* We are learning a new address but have received traffic from the existing address,
* accept it but reset the current learning for the new source so it only takes over
* once sufficient traffic has been received . */
rtp_learning_seq_init ( & rtp - > rtp_source_learn , seqno ) ;
switch ( rtp - > strict_rtp_state ) {
case STRICT_RTP_LEARN :
/*
* Scenario setup :
* PartyA - - Ast1 - - Ast2 - - PartyB
*
* The learning timeout is necessary for Ast1 to handle the above
* setup where PartyA calls PartyB and Ast2 initiates direct media
* between Ast1 and PartyB . Ast1 may lock onto the Ast2 stream and
* never learn the PartyB stream when it starts . The timeout makes
* Ast1 stay in the learning state long enough to see and learn the
* RTP stream from PartyB .
*
* To mitigate against attack , the learning state cannot switch
* streams while there are competing streams . The competing streams
* interfere with each other ' s qualification . Once we accept a
* stream and reach the timeout , an attacker cannot interfere
* anymore .
*
* Here are a few scenarios and each one assumes that the streams
* are continuous :
*
* 1 ) We already have a known stream source address and the known
* stream wants to change to a new source address . An attacking
* stream will block learning the new stream source . After the
* timeout we re - lock onto the original stream source address which
* likely went away . The result is one way audio .
*
* 2 ) We already have a known stream source address and the known
* stream doesn ' t want to change source addresses . An attacking
* stream will not be able to replace the known stream . After the
* timeout we re - lock onto the known stream . The call is not
* affected .
*
* 3 ) We don ' t have a known stream source address . This presumably
* is the start of a call . Competing streams will result in staying
* in learning mode until a stream becomes the victor and we reach
* the timeout . We cannot exit learning if we have no known stream
* to lock onto . The result is one way audio until there is a victor .
*
* If we learn a stream source address before the timeout we will be
* in scenario 1 ) or 2 ) when a competing stream starts .
*/
if ( ! ast_sockaddr_isnull ( & rtp - > strict_rtp_address )
& & 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 ) ) ;
rtp - > strict_rtp_state = STRICT_RTP_CLOSED ;
/*
* Clear the alternate remote address after learning .
*
* We should not leave this address laying around .
* It gets set only on a chan_sip reINVITE glare .
* We don ' t want a stale address interfering with
* the next learning time .
*/
ast_sockaddr_setnull ( & rtp - > alt_rtp_address ) ;
} else {
/* Hmm, not the strict address. Perhaps we're getting audio from the alternate? */
if ( ! ast_sockaddr_cmp ( & rtp - > alt_rtp_address , & addr ) ) {
/* ooh, we did! You're now the new expected address, son! */
ast_sockaddr_copy ( & rtp - > strict_rtp_address ,
& addr ) ;
} else {
/* Start trying to learn from the new address. If we pass a probationary period with
* it , that means we ' ve stopped getting RTP from the original source and we should
* switch to it .
if ( ! ast_sockaddr_cmp ( & rtp - > strict_rtp_address , & addr ) ) {
/*
* We are open to learning a new address but have received
* traffic from the current address , accept it and reset
* the learning counts for a new source . When no more
* current source packets arrive a new source can take over
* once sufficient traffic is received .
*/
if ( rtp_learning_rtp_seq_update ( & rtp - > rtp_source_learn , seqno ) ) {
ast_debug ( 1 , " %p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , rtp - > rtp_source_learn . packets ) ;
return & ast_null_frame ;
}
rtp_learning_seq_init ( & rtp - > rtp_source_learn , seqno ) ;
break ;
}
/*
* We give preferential treatment to the requested remote address
* ( negotiated SDP address ) where we are to send our RTP . However ,
* the other end has no obligation to send from that address even
* though it is practically a requirement when NAT is involved .
*/
if ( ! ast_sockaddr_cmp ( & remote_address , & addr ) ) {
/* Accept the negotiated remote RTP stream as the source */
ast_verb ( 4 , " %p -- Strict RTP switching to RTP remote address %s as source \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
ast_sockaddr_copy ( & rtp - > strict_rtp_address , & addr ) ;
rtp_learning_seq_init ( & rtp - > rtp_source_learn , seqno ) ;
break ;
}
/* Treat the alternate remote address as another negotiated SDP address. */
if ( ! ast_sockaddr_isnull ( & rtp - > alt_rtp_address )
& & ! ast_sockaddr_cmp ( & rtp - > alt_rtp_address , & addr ) ) {
/* ooh, we did! You're now the new expected address, son! */
ast_verb ( 4 , " %p -- Strict RTP switching to RTP alt remote address %s as source \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
ast_sockaddr_copy ( & rtp - > strict_rtp_address , & addr ) ;
rtp_learning_seq_init ( & rtp - > rtp_source_learn , seqno ) ;
break ;
}
ast_verb ( 4 , " %p -- Probation passed - setting RTP source address to %s \n " , rtp , ast_sockaddr_stringify ( & addr ) ) ;
rtp - > strict_rtp_state = STRICT_RTP_CLOSED ;
/*
* Trying to learn a new address . If we pass a probationary period
* with it , that means we ' ve stopped getting RTP from the original
* source and we should switch to it .
*/
if ( ! ast_sockaddr_cmp ( & rtp - > rtp_source_learn . proposed_address , & addr ) ) {
if ( ! rtp_learning_rtp_seq_update ( & rtp - > rtp_source_learn , seqno ) ) {
/* Accept the new RTP stream */
ast_verb ( 4 , " %p -- Strict RTP switching source address to %s \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
ast_sockaddr_copy ( & rtp - > strict_rtp_address , & addr ) ;
rtp_learning_seq_init ( & rtp - > rtp_source_learn , seqno ) ;
break ;
}
/* Not ready to accept the RTP stream candidate */
ast_debug ( 1 , " %p -- Received RTP packet from %s, dropping due to strict RTP protection. Will switch to it in %d packets. \n " ,
rtp , ast_sockaddr_stringify ( & addr ) , rtp - > rtp_source_learn . packets ) ;
} else {
/*
* This is either an attacking stream or
* the start of the expected new stream .
*/
ast_sockaddr_copy ( & rtp - > rtp_source_learn . proposed_address , & addr ) ;
rtp_learning_seq_init ( & rtp - > rtp_source_learn , seqno ) ;
ast_debug ( 1 , " %p -- Received RTP packet from %s, dropping due to strict RTP protection. Qualifying new stream. \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
}
return & ast_null_frame ;
}
/* Fall through */
case STRICT_RTP_CLOSED :
/*
* We should not allow a stream address change if the SSRC matches
* once strictrtp learning is closed . Any kind of address change
* like this should have happened while we were in the learning
* state . We do not want to allow the possibility of an attacker
* interfering with the RTP stream after the learning period .
* An attacker could manage to get an RTCP packet redirected to
* them which can contain the SSRC value .
*/
if ( ! ast_sockaddr_cmp ( & rtp - > strict_rtp_address , & addr ) ) {
break ;
}
} else if ( rtp - > strict_rtp_state = = STRICT_RTP_CLOSED & & ast_sockaddr_cmp ( & rtp - > strict_rtp_address , & addr ) ) {
ast_debug ( 1 , " %p -- Received RTP packet from %s, dropping due to strict RTP protection. \n " ,
rtp , ast_sockaddr_stringify ( & addr ) ) ;
return & ast_null_frame ;
case STRICT_RTP_OPEN :
break ;
}
/* If symmetric RTP is enabled see if the remote side is not what we expected and change where we are sending audio */
@ -4401,11 +4722,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
return & ast_null_frame ;
}
/* If the version is not what we expected by this point then just drop the packet */
if ( version ! = 2 ) {
return & ast_null_frame ;
}
/* Pull out the various other fields we will need */
payloadtype = ( seqno & 0x7f0000 ) > > 16 ;
padding = seqno & ( 1 < < 29 ) ;
@ -4418,7 +4734,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
AST_LIST_HEAD_INIT_NOLOCK ( & frames ) ;
/* Force a marker bit and change SSRC if the SSRC changes */
if ( rtp - > rxssrc & & rtp - > rx ssrc ! = ssrc ) {
if ( rtp - > themssrc_valid & & rtp - > them ssrc ! = ssrc ) {
struct ast_frame * f , srcupdate = {
AST_FRAME_CONTROL ,
. subclass . integer = AST_CONTROL_SRCCHANGE ,
@ -4445,8 +4761,8 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
rtp - > rtcp - > received_prior = 0 ;
}
}
rtp - > rxssrc = ssrc ;
rtp - > themssrc = ssrc ; /* Record their SSRC to put in future RR */
rtp - > themssrc_valid = 1 ;
/* Remove any padding bytes that may be present */
if ( padding ) {
@ -4499,10 +4815,6 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
prev_seqno = rtp - > lastrxseqno ;
rtp - > lastrxseqno = seqno ;
if ( ! rtp - > themssrc ) {
rtp - > themssrc = ntohl ( rtpheader [ 2 ] ) ; /* Record their SSRC to put in future RR */
}
if ( rtp_debug_test_addr ( & addr ) ) {
ast_verbose ( " Got RTP packet from %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6d) \n " ,
ast_sockaddr_stringify ( & addr ) ,
@ -4771,13 +5083,14 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
rtp - > rxseqno = 0 ;
if ( strictrtp & & rtp - > strict_rtp_state ! = STRICT_RTP_OPEN & & ! ast_sockaddr_isnull ( addr ) & &
ast_sockaddr_cmp ( addr , & rtp - > strict_rtp_address ) ) {
if ( strictrtp & & rtp - > strict_rtp_state ! = STRICT_RTP_OPEN
& & ! ast_sockaddr_isnull ( addr ) & & ast_sockaddr_cmp ( addr , & rtp - > strict_rtp_address ) ) {
/* We only need to learn a new strict source address if we've been told the source is
* changing to something different .
*/
rtp - > strict_rtp_state = STRICT_RTP_LEARN ;
rtp_learning_seq_init ( & rtp - > rtp_source_learn , rtp - > seqno ) ;
ast_verb ( 4 , " %p -- Strict RTP learning after remote address set to: %s \n " ,
rtp , ast_sockaddr_stringify ( addr ) ) ;
rtp_learning_start ( rtp ) ;
}
# ifdef HAVE_OPENSSL_SRTP
@ -4805,7 +5118,23 @@ static void ast_rtp_alt_remote_address_set(struct ast_rtp_instance *instance, st
*/
ast_sockaddr_copy ( & rtp - > alt_rtp_address , addr ) ;
return ;
if ( strictrtp & & rtp - > strict_rtp_state ! = STRICT_RTP_OPEN
& & ! ast_sockaddr_isnull ( addr ) & & ast_sockaddr_cmp ( addr , & rtp - > strict_rtp_address ) ) {
/*
* We only need to learn a new strict source address if we ' ve been told the
* source may be changing to something different .
*
* XXX NOTE : The alternate source address is only set because of a reINVITE
* glare in chan_sip . A reINVITE glare is supposed to be retried after a
* backoff delay so it shouldn ' t be needed at all . However , I found this
* as the best description of why it was added :
* http : //lists.digium.com/pipermail/asterisk-dev/2009-May/038348.html
* https : //reviewboard.asterisk.org/r/252/
*/
ast_verb ( 4 , " %p -- Strict RTP learning after alternate remote address set to: %s \n " ,
rtp , ast_sockaddr_stringify ( addr ) ) ;
rtp_learning_start ( rtp ) ;
}
}
/*! \brief Write t140 redundacy frame