@ -51,6 +51,13 @@
mask with a slash ( ' / ' )
mask with a slash ( ' / ' )
< / para > < / description >
< / para > < / description >
< / configOption >
< / configOption >
< configOption name = " srv_lookups " default = " yes " >
< synopsis > Perform SRV lookups for provided hostnames . < / synopsis >
< description > < para > When enabled , < replaceable > srv_lookups < / replaceable > will
perform SRV lookups for _sip . _udp , _sip . _tcp , and _sips . _tcp of the given
hostnames to determine additional addresses that traffic may originate from .
< / para > < / description >
< / configOption >
< configOption name = " type " >
< configOption name = " type " >
< synopsis > Must be of type ' identify ' . < / synopsis >
< synopsis > Must be of type ' identify ' . < / synopsis >
< / configOption >
< / configOption >
@ -70,6 +77,8 @@ struct ip_identify_match {
) ;
) ;
/*! \brief Networks or addresses that should match this */
/*! \brief Networks or addresses that should match this */
struct ast_ha * matches ;
struct ast_ha * matches ;
/*! \brief Perform SRV resolution of hostnames */
unsigned int srv_lookups ;
} ;
} ;
/*! \brief Destructor function for a matching object */
/*! \brief Destructor function for a matching object */
@ -153,6 +162,72 @@ static struct ast_sip_endpoint_identifier ip_identifier = {
. identify_endpoint = ip_identify ,
. identify_endpoint = ip_identify ,
} ;
} ;
/*! \brief Helper function which performs a host lookup and adds result to identify match */
static int ip_identify_match_host_lookup ( struct ip_identify_match * identify , const char * host )
{
struct ast_sockaddr * addrs ;
int num_addrs = 0 , error = 0 , i ;
int results = 0 ;
num_addrs = ast_sockaddr_resolve ( & addrs , host , PARSE_PORT_FORBID , AST_AF_UNSPEC ) ;
if ( ! num_addrs ) {
return - 1 ;
}
for ( i = 0 ; i < num_addrs ; + + i ) {
/* Check if the address is already in the list, if so don't bother adding it again */
if ( identify - > matches & & ( ast_apply_ha ( identify - > matches , & addrs [ i ] ) ! = AST_SENSE_ALLOW ) ) {
continue ;
}
/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
identify - > matches = ast_append_ha ( " d " , ast_sockaddr_stringify_addr ( & addrs [ i ] ) , identify - > matches , & error ) ;
if ( ! identify - > matches | | error ) {
results = - 1 ;
break ;
}
results + = 1 ;
}
ast_free ( addrs ) ;
return results ;
}
/*! \brief Helper function which performs an SRV lookup and then resolves the hostname */
static int ip_identify_match_srv_lookup ( struct ip_identify_match * identify , const char * prefix , const char * host )
{
char service [ NI_MAXHOST ] ;
struct srv_context * context = NULL ;
int srv_ret ;
const char * srvhost ;
unsigned short srvport ;
int results = 0 ;
snprintf ( service , sizeof ( service ) , " %s.%s " , prefix , host ) ;
while ( ! ( srv_ret = ast_srv_lookup ( & context , service , & srvhost , & srvport ) ) ) {
int hosts ;
/* In the case of the SRV lookup we don't care if it fails, we will output a log message
* when we fallback to a normal lookup .
*/
hosts = ip_identify_match_host_lookup ( identify , srvhost ) ;
if ( hosts = = - 1 ) {
results = - 1 ;
break ;
} else {
results + = hosts ;
}
}
ast_srv_cleanup ( & context ) ;
return results ;
}
/*! \brief Custom handler for match field */
/*! \brief Custom handler for match field */
static int ip_identify_match_handler ( const struct aco_option * opt , struct ast_variable * var , void * obj )
static int ip_identify_match_handler ( const struct aco_option * opt , struct ast_variable * var , void * obj )
{
{
@ -165,9 +240,9 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
}
}
while ( ( current_string = ast_strip ( strsep ( & input_string , " , " ) ) ) ) {
while ( ( current_string = ast_strip ( strsep ( & input_string , " , " ) ) ) ) {
struct ast_sockaddr * addrs ;
int num_addrs = 0 , error = 0 , i ;
char * mask = strrchr ( current_string , ' / ' ) ;
char * mask = strrchr ( current_string , ' / ' ) ;
struct ast_sockaddr address ;
int error , results = 0 ;
if ( ast_strlen_zero ( current_string ) ) {
if ( ast_strlen_zero ( current_string ) ) {
continue ;
continue ;
@ -185,28 +260,28 @@ static int ip_identify_match_handler(const struct aco_option *opt, struct ast_va
continue ;
continue ;
}
}
num_addrs = ast_sockaddr_resolve ( & addrs , current_string , PARSE_PORT_FORBID , AST_AF_UNSPEC ) ;
/* If the provided string is not an IP address perform SRV resolution on it */
if ( ! num_addrs ) {
if ( identify - > srv_lookups & & ! ast_sockaddr_parse ( & address , current_string , 0 ) ) {
ast_log ( LOG_ERROR , " Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address \n " ,
results = ip_identify_match_srv_lookup ( identify , " _sip._udp " , current_string ) ;
var - > value , ast_sorcery_object_get_id ( obj ) ) ;
if ( results ! = - 1 ) {
return - 1 ;
results + = ip_identify_match_srv_lookup ( identify , " _sip._tcp " , current_string ) ;
}
}
if ( results ! = - 1 ) {
for ( i = 0 ; i < num_addrs ; + + i ) {
results + = ip_identify_match_srv_lookup ( identify , " _sips._tcp " , current_string ) ;
/* We deny what we actually want to match because there is an implicit permit all rule for ACLs */
identify - > matches = ast_append_ha ( " d " , ast_sockaddr_stringify_addr ( & addrs [ i ] ) , identify - > matches , & error ) ;
if ( ! identify - > matches | | error ) {
ast_log ( LOG_ERROR , " Failed to add address '%s' to ip endpoint identifier '%s' \n " ,
ast_sockaddr_stringify_addr ( & addrs [ i ] ) , ast_sorcery_object_get_id ( obj ) ) ;
error = - 1 ;
break ;
}
}
}
}
ast_free ( addrs ) ;
/* If SRV falls fall back to a normal lookup on the host itself */
if ( ! results ) {
results = ip_identify_match_host_lookup ( identify , current_string ) ;
}
if ( error ) {
if ( results = = 0 ) {
ast_log ( LOG_ERROR , " Address '%s' provided on ip endpoint identifier '%s' did not resolve to any address \n " ,
current_string , ast_sorcery_object_get_id ( obj ) ) ;
} else if ( results = = - 1 ) {
ast_log ( LOG_ERROR , " An error occurred when adding resolution results of '%s' on '%s' \n " ,
current_string , ast_sorcery_object_get_id ( obj ) ) ;
return - 1 ;
return - 1 ;
}
}
}
}
@ -469,6 +544,7 @@ static int load_module(void)
ast_sorcery_object_field_register ( ast_sip_get_sorcery ( ) , " identify " , " type " , " " , OPT_NOOP_T , 0 , 0 ) ;
ast_sorcery_object_field_register ( ast_sip_get_sorcery ( ) , " identify " , " type " , " " , OPT_NOOP_T , 0 , 0 ) ;
ast_sorcery_object_field_register ( ast_sip_get_sorcery ( ) , " identify " , " endpoint " , " " , OPT_STRINGFIELD_T , 0 , STRFLDSET ( struct ip_identify_match , endpoint_name ) ) ;
ast_sorcery_object_field_register ( ast_sip_get_sorcery ( ) , " identify " , " endpoint " , " " , OPT_STRINGFIELD_T , 0 , STRFLDSET ( struct ip_identify_match , endpoint_name ) ) ;
ast_sorcery_object_field_register_custom ( ast_sip_get_sorcery ( ) , " identify " , " match " , " " , ip_identify_match_handler , match_to_str , match_to_var_list , 0 , 0 ) ;
ast_sorcery_object_field_register_custom ( ast_sip_get_sorcery ( ) , " identify " , " match " , " " , ip_identify_match_handler , match_to_str , match_to_var_list , 0 , 0 ) ;
ast_sorcery_object_field_register ( ast_sip_get_sorcery ( ) , " identify " , " srv_lookups " , " yes " , OPT_BOOL_T , 1 , FLDSET ( struct ip_identify_match , srv_lookups ) ) ;
ast_sorcery_load_object ( ast_sip_get_sorcery ( ) , " identify " ) ;
ast_sorcery_load_object ( ast_sip_get_sorcery ( ) , " identify " ) ;
ast_sip_register_endpoint_identifier_with_name ( & ip_identifier , " ip " ) ;
ast_sip_register_endpoint_identifier_with_name ( & ip_identifier , " ip " ) ;