res_rtp_asterisk: Add ice_blacklist option

Introduces ice_blacklist configuration in rtp.conf. Subnets listed in the
form ice_blacklist = <subnet spec>, e.g. ice_blacklist =
192.168.1.0/255.255.255.0, are excluded from ICE host, srflx and relay
discovery. This is useful for optimizing the ICE process where a system
has multiple host address ranges and/or physical interfaces and certain
of them are not expected to be used for RTP. Multiple ice_blacklist
configuration lines may be used. If left unconfigured, all discovered
host addresses are used, as per previous behavior.

Documention in rtp.conf.sample.

ASTERISK-26418 #close

Change-Id: Ibee88f80d7693874fda1cceaef94a03bd86012c9
changes/63/4063/5
Michael Walton 9 years ago committed by Joshua Colp
parent 193a94a60f
commit 3e96d491d0

@ -97,6 +97,11 @@ res_pjsip
Note: The caller-id and redirecting number strings obtained from incoming Note: The caller-id and redirecting number strings obtained from incoming
SIP URI user fields are now always truncated at the first semicolon. SIP URI user fields are now always truncated at the first semicolon.
res_rtp_asterisk
------------------
* An option, ice_blacklist, has been added which allows certain subnets to be
excluded from local ICE candidates.
app_confbridge app_confbridge
------------------ ------------------
* Some sounds played into the bridge are played asynchronously. This, for * Some sounds played into the bridge are played asynchronously. This, for

@ -59,6 +59,18 @@ rtpend=20000
; Password used to authenticate with TURN relay server. ; Password used to authenticate with TURN relay server.
; turnpassword= ; turnpassword=
; ;
; Subnets to exclude from ICE host, srflx and relay discovery. This is useful
; to optimize the ICE process where a system has multiple host address ranges
; and/or physical interfaces and certain of them are not expected to be used
; for RTP. For example, VPNs and local interconnections may not be suitable or
; necessary for ICE. Multiple subnets may be listed. If left unconfigured,
; all discovered host addresses are used.
;
; e.g. ice_blacklist = 192.168.1.0/255.255.255.0
; ice_blacklist = 10.32.77.0/255.255.255.0
;
; ice_blacklist =
;
[ice_host_candidates] [ice_host_candidates]
; ;
; When Asterisk is behind a static one-to-one NAT and ICE is in use, ICE will ; When Asterisk is behind a static one-to-one NAT and ICE is in use, ICE will

@ -51,6 +51,7 @@ ASTERISK_REGISTER_FILE()
#include <pjlib.h> #include <pjlib.h>
#include <pjlib-util.h> #include <pjlib-util.h>
#include <pjnath.h> #include <pjnath.h>
#include <ifaddrs.h>
#endif #endif
#include "asterisk/stun.h" #include "asterisk/stun.h"
@ -145,6 +146,9 @@ static pj_str_t turnaddr;
static int turnport = DEFAULT_TURN_PORT; static int turnport = DEFAULT_TURN_PORT;
static pj_str_t turnusername; static pj_str_t turnusername;
static pj_str_t turnpassword; 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. */ /*! \brief Pool factory used by pjlib to allocate memory. */
static pj_caching_pool cachingpool; 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 #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, 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) int transport)
{ {
pj_sockaddr address[16]; pj_sockaddr address[16];
unsigned int count = PJ_ARRAY_SIZE(address), pos = 0; unsigned int count = PJ_ARRAY_SIZE(address), pos = 0;
int basepos = -1;
/* Add all the local interface IP addresses */ /* Add all the local interface IP addresses */
if (ast_sockaddr_is_ipv4(addr)) { if (ast_sockaddr_is_ipv4(addr)) {
@ -2464,10 +2495,19 @@ static void rtp_add_candidates_to_ice(struct ast_rtp_instance *instance, struct
host_candidate_overrides_apply(count, address); host_candidate_overrides_apply(count, address);
for (pos = 0; pos < count; pos++) { for (pos = 0; pos < count; pos++) {
if (!rtp_address_is_ice_blacklisted(&address[pos])) {
if (basepos == -1) {
basepos = pos;
}
pj_sockaddr_set_port(&address[pos], port); 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, 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])); 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 */ /* If configured to use a STUN server to get our external mapped address do so */
if (stunaddr.sin_addr.s_addr && ast_sockaddr_is_ipv4(addr) && count) { if (stunaddr.sin_addr.s_addr && ast_sockaddr_is_ipv4(addr) && count) {
@ -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)) { if (!ast_stun_request(component == AST_RTP_ICE_COMPONENT_RTCP ? rtp->rtcp->s : rtp->s, &stunaddr, NULL, &answer)) {
pj_sockaddr base; pj_sockaddr base;
pj_sockaddr ext;
pj_str_t mapped = pj_str(ast_strdupa(ast_inet_ntoa(answer.sin_addr))); 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 */ /* 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(), &address[0], &mapped, ntohs(answer.sin_port)); pj_sockaddr_init(pj_AF_INET(), &ext, &mapped, ntohs(answer.sin_port));
ast_rtp_ice_add_cand(rtp, component, transport, PJ_ICE_CAND_TYPE_SRFLX, 65535, &address[0], &base, /* If the returned address is the same as one of our host candidates, don't send the srflx */
&base, pj_sockaddr_get_len(&address[0])); for (pos = 0; pos < count; pos++) {
if ((pj_sockaddr_cmp(&address[pos], &ext) == 0) && !rtp_address_is_ice_blacklisted(&address[pos])) {
srflx = 0;
break;
}
}
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); turnusername = pj_str(NULL);
turnpassword = pj_str(NULL); turnpassword = pj_str(NULL);
host_candidate_overrides_clear(); 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 #endif
if (cfg) { if (cfg) {
@ -5502,6 +5558,25 @@ static int rtp_reload(int reload)
AST_RWLIST_INSERT_TAIL(&host_candidates, candidate, next); AST_RWLIST_INSERT_TAIL(&host_candidates, candidate, next);
} }
AST_RWLIST_UNLOCK(&host_candidates); 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 #endif
ast_config_destroy(cfg); ast_config_destroy(cfg);
} }

Loading…
Cancel
Save