@ -51,6 +51,7 @@ ASTERISK_REGISTER_FILE()
# include <pjlib.h>
# include <pjlib-util.h>
# include <pjnath.h>
# include <ifaddrs.h>
# endif
# include "asterisk/stun.h"
@ -145,6 +146,9 @@ static pj_str_t turnaddr;
static int turnport = DEFAULT_TURN_PORT ;
static pj_str_t turnusername ;
static pj_str_t turnpassword ;
static struct ast_ha * ice_blacklist = NULL ; /*!< Blacklisted ICE networks */
static ast_rwlock_t ice_blacklist_lock = AST_RWLOCK_INIT_VALUE ;
/*! \brief Pool factory used by pjlib to allocate memory. */
static pj_caching_pool cachingpool ;
@ -2446,11 +2450,38 @@ static int rtp_learning_rtp_seq_update(struct rtp_learning_info *info, uint16_t
}
# ifdef HAVE_PJPROJECT
/*!
* \ internal
* \ brief Checks an address against the ICE blacklist
* \ note If there is no ice_blacklist list , always returns 0
*
* \ param address The address to consider
* \ retval 0 if address is not ICE blacklisted
* \ retval 1 if address is ICE blacklisted
*/
static int rtp_address_is_ice_blacklisted ( const pj_sockaddr_t * address )
{
char buf [ PJ_INET6_ADDRSTRLEN ] ;
struct ast_sockaddr saddr ;
int result = 1 ;
ast_sockaddr_parse ( & saddr , pj_sockaddr_print ( address , buf , sizeof ( buf ) , 0 ) , 0 ) ;
ast_rwlock_rdlock ( & ice_blacklist_lock ) ;
if ( ! ice_blacklist | | ( ast_apply_ha ( ice_blacklist , & saddr ) = = AST_SENSE_ALLOW ) ) {
result = 0 ;
}
ast_rwlock_unlock ( & ice_blacklist_lock ) ;
return result ;
}
static void rtp_add_candidates_to_ice ( struct ast_rtp_instance * instance , struct ast_rtp * rtp , struct ast_sockaddr * addr , int port , int component ,
int transport )
{
pj_sockaddr address [ 16 ] ;
unsigned int count = PJ_ARRAY_SIZE ( address ) , pos = 0 ;
int basepos = - 1 ;
/* Add all the local interface IP addresses */
if ( ast_sockaddr_is_ipv4 ( addr ) ) {
@ -2464,9 +2495,18 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
host_candidate_overrides_apply ( count , address ) ;
for ( pos = 0 ; pos < count ; pos + + ) {
pj_sockaddr_set_port ( & address [ pos ] , port ) ;
ast_rtp_ice_add_cand ( rtp , component , transport , PJ_ICE_CAND_TYPE_HOST , 65535 , & address [ pos ] , & address [ pos ] , NULL ,
if ( ! rtp_address_is_ice_blacklisted ( & address [ pos ] ) ) {
if ( basepos = = - 1 ) {
basepos = pos ;
}
pj_sockaddr_set_port ( & address [ pos ] , port ) ;
ast_rtp_ice_add_cand ( rtp , component , transport , PJ_ICE_CAND_TYPE_HOST , 65535 , & address [ pos ] , & address [ pos ] , NULL ,
pj_sockaddr_get_len ( & address [ pos ] ) ) ;
}
}
if ( basepos = = - 1 ) {
/* start with first address unless excluded above */
basepos = 0 ;
}
/* If configured to use a STUN server to get our external mapped address do so */
@ -2475,15 +2515,27 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
if ( ! ast_stun_request ( component = = AST_RTP_ICE_COMPONENT_RTCP ? rtp - > rtcp - > s : rtp - > s , & stunaddr , NULL , & answer ) ) {
pj_sockaddr base ;
pj_sockaddr ext ;
pj_str_t mapped = pj_str ( ast_strdupa ( ast_inet_ntoa ( answer . sin_addr ) ) ) ;
int srflx = 1 ;
/* Use the first local host candidate as the base */
pj_sockaddr_cp ( & base , & address [ 0 ] ) ;
pj_sockaddr_cp ( & base , & address [ basepos ] ) ;
pj_sockaddr_init ( pj_AF_INET ( ) , & ext , & mapped , ntohs ( answer . sin_port ) ) ;
pj_sockaddr_init ( pj_AF_INET ( ) , & address [ 0 ] , & mapped , ntohs ( answer . sin_port ) ) ;
/* If the returned address is the same as one of our host candidates, don't send the srflx */
for ( pos = 0 ; pos < count ; pos + + ) {
if ( ( pj_sockaddr_cmp ( & address [ pos ] , & ext ) = = 0 ) & & ! rtp_address_is_ice_blacklisted ( & address [ pos ] ) ) {
srflx = 0 ;
break ;
}
}
ast_rtp_ice_add_cand ( rtp , component , transport , PJ_ICE_CAND_TYPE_SRFLX , 65535 , & address [ 0 ] , & base ,
& base , pj_sockaddr_get_len ( & address [ 0 ] ) ) ;
if ( srflx ) {
ast_rtp_ice_add_cand ( rtp , component , transport , PJ_ICE_CAND_TYPE_SRFLX , 65535 , & ext , & base ,
& base , pj_sockaddr_get_len ( & ext ) ) ;
}
}
}
@ -5393,6 +5445,10 @@ static int rtp_reload(int reload)
turnusername = pj_str ( NULL ) ;
turnpassword = pj_str ( NULL ) ;
host_candidate_overrides_clear ( ) ;
ast_rwlock_wrlock ( & ice_blacklist_lock ) ;
ast_free_ha ( ice_blacklist ) ;
ice_blacklist = NULL ;
ast_rwlock_unlock ( & ice_blacklist_lock ) ;
# endif
if ( cfg ) {
@ -5502,6 +5558,25 @@ static int rtp_reload(int reload)
AST_RWLIST_INSERT_TAIL ( & host_candidates , candidate , next ) ;
}
AST_RWLIST_UNLOCK ( & host_candidates ) ;
/* Read ICE blacklist configuration lines */
ast_rwlock_wrlock ( & ice_blacklist_lock ) ;
for ( var = ast_variable_browse ( cfg , " general " ) ; var ; var = var - > next ) {
if ( ! strcasecmp ( var - > name , " ice_blacklist " ) ) {
struct ast_ha * na ;
int ha_error = 0 ;
if ( ! ( na = ast_append_ha ( " d " , var - > value , ice_blacklist , & ha_error ) ) ) {
ast_log ( LOG_WARNING , " Invalid ice_blacklist value: %s \n " , var - > value ) ;
} else {
ice_blacklist = na ;
}
if ( ha_error ) {
ast_log ( LOG_ERROR , " Bad ice_blacklist configuration value line %d : %s \n " , var - > lineno , var - > value ) ;
}
}
}
ast_rwlock_unlock ( & ice_blacklist_lock ) ;
# endif
ast_config_destroy ( cfg ) ;
}