@ -27,72 +27,72 @@
# define MOD_DATA_RESTRICTIONS "restrictions"
static pj_status_t multihomed _on_tx_message( pjsip_tx_data * tdata ) ;
static pj_bool_t multihomed _on_rx_message( pjsip_rx_data * rdata ) ;
static pj_status_t filter _on_tx_message( pjsip_tx_data * tdata ) ;
static pj_bool_t filter _on_rx_message( pjsip_rx_data * rdata ) ;
/*! \brief Outgoing message modification restrictions */
struct multihomed _message_restrictions {
struct filter _message_restrictions {
/*! \brief Disallow modification of the From domain */
unsigned int disallow_from_domain_modification ;
} ;
static pjsip_module multihomed _module = {
. name = { " M ultihomed Routing" , 18 } ,
static pjsip_module filter _module = {
. name = { " M essage Filtering" , 17 } ,
. id = - 1 ,
. priority = PJSIP_MOD_PRIORITY_T SX_LAYER - 1 ,
. on_tx_request = multihomed _on_tx_message,
. on_tx_response = multihomed _on_tx_message,
. on_rx_request = multihomed _on_rx_message,
. priority = PJSIP_MOD_PRIORITY_T RANSPORT_LAYER ,
. on_tx_request = filter _on_tx_message,
. on_tx_response = filter _on_tx_message,
. on_rx_request = filter _on_rx_message,
} ;
/*! \brief Helper function to get (or allocate if not already present) restrictions on a message */
static struct multihomed_message_restrictions * multihomed_ get_restrictions( pjsip_tx_data * tdata )
static struct filter_message_restrictions * get_restrictions( pjsip_tx_data * tdata )
{
struct multihomed _message_restrictions * restrictions ;
struct filter _message_restrictions * restrictions ;
restrictions = ast_sip_mod_data_get ( tdata - > mod_data , multihomed _module. id , MOD_DATA_RESTRICTIONS ) ;
restrictions = ast_sip_mod_data_get ( tdata - > mod_data , filter _module. id , MOD_DATA_RESTRICTIONS ) ;
if ( restrictions ) {
return restrictions ;
}
restrictions = PJ_POOL_ALLOC_T ( tdata - > pool , struct multihomed _message_restrictions) ;
ast_sip_mod_data_set ( tdata - > pool , tdata - > mod_data , multihomed _module. id , MOD_DATA_RESTRICTIONS , restrictions ) ;
restrictions = PJ_POOL_ALLOC_T ( tdata - > pool , struct filter _message_restrictions) ;
ast_sip_mod_data_set ( tdata - > pool , tdata - > mod_data , filter _module. id , MOD_DATA_RESTRICTIONS , restrictions ) ;
return restrictions ;
}
/*! \brief Callback invoked on non-session outgoing messages */
static void multihomed _outgoing_message( struct ast_sip_endpoint * endpoint , struct ast_sip_contact * contact , struct pjsip_tx_data * tdata )
static void filter _outgoing_message( struct ast_sip_endpoint * endpoint , struct ast_sip_contact * contact , struct pjsip_tx_data * tdata )
{
struct multihomed _message_restrictions * restrictions = multihomed_ get_restrictions( tdata ) ;
struct filter _message_restrictions * restrictions = get_restrictions( tdata ) ;
restrictions - > disallow_from_domain_modification = ! ast_strlen_zero ( endpoint - > fromdomain ) ;
}
/*! \brief PJSIP Supplement for tagging messages with restrictions */
static struct ast_sip_supplement multihomed _supplement = {
static struct ast_sip_supplement filter _supplement = {
. priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST ,
. outgoing_request = multihomed _outgoing_message,
. outgoing_response = multihomed _outgoing_message,
. outgoing_request = filter _outgoing_message,
. outgoing_response = filter _outgoing_message,
} ;
/*! \brief Callback invoked on session outgoing messages */
static void multihomed _session_outgoing_message( struct ast_sip_session * session , struct pjsip_tx_data * tdata )
static void filter _session_outgoing_message( struct ast_sip_session * session , struct pjsip_tx_data * tdata )
{
struct multihomed _message_restrictions * restrictions = multihomed_ get_restrictions( tdata ) ;
struct filter _message_restrictions * restrictions = get_restrictions( tdata ) ;
restrictions - > disallow_from_domain_modification = ! ast_strlen_zero ( session - > endpoint - > fromdomain ) ;
}
/*! \brief PJSIP Session Supplement for tagging messages with restrictions */
static struct ast_sip_session_supplement multihomed _session_supplement = {
static struct ast_sip_session_supplement filter _session_supplement = {
. priority = 1 ,
. outgoing_request = multihomed _session_outgoing_message,
. outgoing_response = multihomed _session_outgoing_message,
. outgoing_request = filter _session_outgoing_message,
. outgoing_response = filter _session_outgoing_message,
} ;
/*! \brief Helper function which returns a UDP transport bound to the given address and port */
static pjsip_transport * multihomed_ get_udp_transport( pj_str_t * address , int port )
static pjsip_transport * get_udp_transport( pj_str_t * address , int port )
{
struct ao2_container * transport_states = ast_sip_get_transport_states ( ) ;
struct ast_sip_transport_state * transport_state ;
@ -121,7 +121,7 @@ static pjsip_transport *multihomed_get_udp_transport(pj_str_t *address, int port
}
/*! \brief Helper function which determines if a transport is bound to any */
static int multihomed _bound_any( pjsip_transport * transport )
static int is _bound_any( pjsip_transport * transport )
{
pj_uint32_t loop6 [ 4 ] = { 0 , 0 , 0 , 0 } ;
@ -156,6 +156,19 @@ static int multihomed_rewrite_sdp(struct pjmedia_sdp_session *sdp)
# define is_sip_uri(uri) \
( PJSIP_URI_SCHEME_IS_SIP ( uri ) | | PJSIP_URI_SCHEME_IS_SIPS ( uri ) )
static void print_sanitize_debug ( char * msg , pjsip_uri_context_e context , pjsip_sip_uri * uri )
{
# ifdef AST_DEVMODE
char hdrbuf [ 512 ] ;
int hdrbuf_len ;
hdrbuf_len = pjsip_uri_print ( context , uri , hdrbuf , 512 ) ;
hdrbuf [ hdrbuf_len ] = ' \0 ' ;
ast_debug ( 2 , " %s: %s \n " , msg , hdrbuf ) ;
# endif
}
/* If in DEVMODE, prevent inlining to assist in debugging */
# ifdef AST_DEVMODE
# define FUNC_ATTRS __attribute__ ((noinline))
# else
@ -167,21 +180,12 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata)
static const pj_str_t x_name = { AST_SIP_X_AST_TXP , AST_SIP_X_AST_TXP_LEN } ;
pjsip_param * x_transport ;
pjsip_sip_uri * uri ;
pjsip_fromto_hdr * fromto ;
pjsip_contact_hdr * contact ;
pjsip_hdr * hdr ;
# ifdef AST_DEVMODE
char hdrbuf [ 512 ] ;
int hdrbuf_len ;
# endif
if ( tdata - > msg - > type = = PJSIP_REQUEST_MSG ) {
if ( is_sip_uri ( tdata - > msg - > line . req . uri ) ) {
uri = pjsip_uri_get_uri ( tdata - > msg - > line . req . uri ) ;
# ifdef AST_DEVMODE
hdrbuf_len = pjsip_uri_print ( PJSIP_URI_IN_REQ_URI , uri , hdrbuf , 512 ) ;
ast_debug ( 2 , " Sanitizing Request: %s \n " , hdrbuf ) ;
# endif
print_sanitize_debug ( " Sanitizing Request " , PJSIP_URI_IN_REQ_URI , uri ) ;
while ( ( x_transport = pjsip_param_find ( & uri - > other_param , & x_name ) ) ) {
pj_list_erase ( x_transport ) ;
}
@ -190,27 +194,17 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata)
for ( hdr = tdata - > msg - > hdr . next ; hdr ! = & tdata - > msg - > hdr ; hdr = hdr - > next ) {
if ( hdr - > type = = PJSIP_H_TO | | hdr - > type = = PJSIP_H_FROM ) {
fromto = ( pjsip_fromto_hdr * ) hdr ;
if ( is_sip_uri ( fromto - > uri ) ) {
uri = pjsip_uri_get_uri ( fromto - > uri ) ;
# ifdef AST_DEVMODE
hdrbuf_len = pjsip_uri_print ( PJSIP_URI_IN_FROMTO_HDR , uri , hdrbuf , 512 ) ;
hdrbuf [ hdrbuf_len ] = ' \0 ' ;
ast_debug ( 2 , " Sanitizing From/To: %s \n " , hdrbuf ) ;
# endif
if ( is_sip_uri ( ( ( pjsip_fromto_hdr * ) hdr ) - > uri ) ) {
uri = pjsip_uri_get_uri ( ( ( pjsip_fromto_hdr * ) hdr ) - > uri ) ;
print_sanitize_debug ( " Sanitizing From/To header " , PJSIP_URI_IN_FROMTO_HDR , uri ) ;
while ( ( x_transport = pjsip_param_find ( & uri - > other_param , & x_name ) ) ) {
pj_list_erase ( x_transport ) ;
}
}
} else if ( hdr - > type = = PJSIP_H_CONTACT ) {
contact = ( pjsip_contact_hdr * ) hdr ;
if ( is_sip_uri ( contact - > uri ) ) {
uri = pjsip_uri_get_uri ( contact - > uri ) ;
# ifdef AST_DEVMODE
hdrbuf_len = pjsip_uri_print ( PJSIP_URI_IN_CONTACT_HDR , uri , hdrbuf , 512 ) ;
hdrbuf [ hdrbuf_len ] = ' \0 ' ;
ast_debug ( 2 , " Sanitizing Contact: %s \n " , hdrbuf ) ;
# endif
if ( ! ( ( pjsip_contact_hdr * ) hdr ) - > star & & is_sip_uri ( ( ( pjsip_contact_hdr * ) hdr ) - > uri ) ) {
uri = pjsip_uri_get_uri ( ( ( pjsip_contact_hdr * ) hdr ) - > uri ) ;
print_sanitize_debug ( " Sanitizing Contact header " , PJSIP_URI_IN_CONTACT_HDR , uri ) ;
while ( ( x_transport = pjsip_param_find ( & uri - > other_param , & x_name ) ) ) {
pj_list_erase ( x_transport ) ;
}
@ -221,9 +215,9 @@ static void FUNC_ATTRS sanitize_tdata(pjsip_tx_data *tdata)
pjsip_tx_data_invalidate_msg ( tdata ) ;
}
static pj_status_t multihomed _on_tx_message( pjsip_tx_data * tdata )
static pj_status_t filter _on_tx_message( pjsip_tx_data * tdata )
{
struct multihomed _message_restrictions * restrictions = ast_sip_mod_data_get ( tdata - > mod_data , multihomed _module. id , MOD_DATA_RESTRICTIONS ) ;
struct filter _message_restrictions * restrictions = ast_sip_mod_data_get ( tdata - > mod_data , filter _module. id , MOD_DATA_RESTRICTIONS ) ;
pjsip_tpmgr_fla2_param prm ;
pjsip_cseq_hdr * cseq ;
pjsip_via_hdr * via ;
@ -256,7 +250,7 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
tdata - > tp_info . transport - > key . type = = PJSIP_TRANSPORT_UDP6 ) {
pjsip_transport * transport ;
transport = multihomed_ get_udp_transport( & prm . ret_addr , prm . ret_port ) ;
transport = get_udp_transport( & prm . ret_addr , prm . ret_port ) ;
if ( transport ) {
tdata - > tp_info . transport = transport ;
@ -264,7 +258,7 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
}
/* If the chosen transport is not bound to any we can't use the source address as it won't get back to us */
if ( ! multihomed _bound_any( tdata - > tp_info . transport ) ) {
if ( ! is _bound_any( tdata - > tp_info . transport ) ) {
pj_strassign ( & prm . ret_addr , & tdata - > tp_info . transport - > local_name . host ) ;
}
} else {
@ -345,7 +339,104 @@ static pj_status_t multihomed_on_tx_message(pjsip_tx_data *tdata)
return PJ_SUCCESS ;
}
static pj_bool_t multihomed_on_rx_message ( pjsip_rx_data * rdata )
enum uri_type {
URI_TYPE_REQUEST = - 1 ,
URI_TYPE_TO = PJSIP_H_TO ,
URI_TYPE_FROM = PJSIP_H_FROM ,
URI_TYPE_CONTACT = PJSIP_H_CONTACT ,
} ;
static void print_uri_debug ( enum uri_type ut , pjsip_rx_data * rdata , pjsip_hdr * hdr )
{
# ifdef AST_DEVMODE
pjsip_uri * local_uri = NULL ;
char hdrbuf [ 512 ] ;
int hdrbuf_len ;
char * request_uri ;
pjsip_uri_context_e context = PJSIP_URI_IN_OTHER ;
char header_name [ 32 ] ;
switch ( ut ) {
case ( URI_TYPE_REQUEST ) :
context = PJSIP_URI_IN_REQ_URI ;
strcpy ( header_name , " Request " ) ; /* Safe */
local_uri = rdata - > msg_info . msg - > line . req . uri ;
break ;
case ( PJSIP_H_FROM ) :
strcpy ( header_name , " From " ) ; /* Safe */
context = PJSIP_URI_IN_FROMTO_HDR ;
local_uri = pjsip_uri_get_uri ( ( ( pjsip_from_hdr * ) hdr ) - > uri ) ;
break ;
case ( PJSIP_H_TO ) :
strcpy ( header_name , " To " ) ; /* Safe */
context = PJSIP_URI_IN_FROMTO_HDR ;
local_uri = pjsip_uri_get_uri ( ( ( pjsip_to_hdr * ) hdr ) - > uri ) ;
break ;
case ( PJSIP_H_CONTACT ) :
strcpy ( header_name , " Contact " ) ; /* Safe */
context = PJSIP_URI_IN_CONTACT_HDR ;
local_uri = pjsip_uri_get_uri ( ( ( pjsip_contact_hdr * ) hdr ) - > uri ) ;
break ;
}
hdrbuf_len = pjsip_uri_print ( PJSIP_URI_IN_REQ_URI , rdata - > msg_info . msg - > line . req . uri , hdrbuf , 512 ) ;
hdrbuf [ hdrbuf_len ] = ' \0 ' ;
request_uri = ast_strdupa ( hdrbuf ) ;
hdrbuf_len = pjsip_uri_print ( context , local_uri , hdrbuf , 512 ) ;
hdrbuf [ hdrbuf_len ] = ' \0 ' ;
ast_debug ( 2 , " There was a non sip(s) URI scheme in %s URI '%s' for request '%*.*s %s' \n " ,
header_name , hdrbuf ,
( int ) rdata - > msg_info . msg - > line . req . method . name . slen ,
( int ) rdata - > msg_info . msg - > line . req . method . name . slen ,
rdata - > msg_info . msg - > line . req . method . name . ptr , request_uri ) ;
# endif
}
static pj_bool_t on_rx_process_uris ( pjsip_rx_data * rdata )
{
pjsip_contact_hdr * contact = NULL ;
if ( rdata - > msg_info . msg - > type ! = PJSIP_REQUEST_MSG ) {
return PJ_FALSE ;
}
if ( ! is_sip_uri ( rdata - > msg_info . msg - > line . req . uri ) ) {
print_uri_debug ( URI_TYPE_REQUEST , rdata , NULL ) ;
pjsip_endpt_respond_stateless ( ast_sip_get_pjsip_endpoint ( ) , rdata ,
PJSIP_SC_UNSUPPORTED_URI_SCHEME , NULL , NULL , NULL ) ;
return PJ_TRUE ;
}
if ( ! is_sip_uri ( rdata - > msg_info . from - > uri ) ) {
print_uri_debug ( URI_TYPE_FROM , rdata , ( pjsip_hdr * ) rdata - > msg_info . from ) ;
pjsip_endpt_respond_stateless ( ast_sip_get_pjsip_endpoint ( ) , rdata ,
PJSIP_SC_UNSUPPORTED_URI_SCHEME , NULL , NULL , NULL ) ;
return PJ_TRUE ;
}
if ( ! is_sip_uri ( rdata - > msg_info . to - > uri ) ) {
print_uri_debug ( URI_TYPE_TO , rdata , ( pjsip_hdr * ) rdata - > msg_info . to ) ;
pjsip_endpt_respond_stateless ( ast_sip_get_pjsip_endpoint ( ) , rdata ,
PJSIP_SC_UNSUPPORTED_URI_SCHEME , NULL , NULL , NULL ) ;
return PJ_TRUE ;
}
while ( ( contact =
( pjsip_contact_hdr * ) pjsip_msg_find_hdr ( rdata - > msg_info . msg , PJSIP_H_CONTACT ,
contact ? contact - > next : NULL ) ) ) {
if ( ! contact - > star & & ! is_sip_uri ( contact - > uri ) ) {
print_uri_debug ( URI_TYPE_CONTACT , rdata , ( pjsip_hdr * ) contact ) ;
pjsip_endpt_respond_stateless ( ast_sip_get_pjsip_endpoint ( ) , rdata ,
PJSIP_SC_UNSUPPORTED_URI_SCHEME , NULL , NULL , NULL ) ;
return PJ_TRUE ;
}
}
return PJ_FALSE ;
}
static pj_bool_t on_rx_process_symmetric_transport ( pjsip_rx_data * rdata )
{
pjsip_contact_hdr * contact ;
pjsip_sip_uri * uri ;
@ -388,29 +479,46 @@ static pj_bool_t multihomed_on_rx_message(pjsip_rx_data *rdata)
return PJ_FALSE ;
}
void ast_res_pjsip_cleanup_message_ip_updater ( void )
static pj_bool_t filter_on_rx_message ( pjsip_rx_data * rdata )
{
pj_bool_t rc ;
rc = on_rx_process_uris ( rdata ) ;
if ( rc = = PJ_TRUE ) {
return rc ;
}
rc = on_rx_process_symmetric_transport ( rdata ) ;
if ( rc = = PJ_TRUE ) {
return rc ;
}
return PJ_FALSE ;
}
void ast_res_pjsip_cleanup_message_filter ( void )
{
ast_sip_unregister_service ( & multihomed_module ) ;
ast_sip_unregister_supplement ( & multihomed_supplement ) ;
ast_sip_session_unregister_supplement ( & multihomed_session_supplement ) ;
ast_sip_unregister_service ( & filter _module) ;
ast_sip_unregister_supplement ( & filter _supplement) ;
ast_sip_session_unregister_supplement ( & filter _session_supplement) ;
}
int ast_res_pjsip_init_message_ip_updater ( void )
int ast_res_pjsip_init_message_ fil ter( void )
{
if ( ast_sip_session_register_supplement ( & multihomed_session_supplement ) ) {
ast_log ( LOG_ERROR , " Could not register multihomed session supplement for outgoing requests \n " ) ;
if ( ast_sip_session_register_supplement ( & filter _session_supplement) ) {
ast_log ( LOG_ERROR , " Could not register m essage filter session supplement for outgoing requests\n " ) ;
return - 1 ;
}
if ( ast_sip_register_supplement ( & multihomed_supplement ) ) {
ast_log ( LOG_ERROR , " Could not register multihomed supplement for outgoing requests \n " ) ;
ast_res_pjsip_cleanup_message_ip_updater ( ) ;
if ( ast_sip_register_supplement ( & filter _supplement) ) {
ast_log ( LOG_ERROR , " Could not register m essage filter supplement for outgoing requests\n " ) ;
ast_res_pjsip_cleanup_message_ fil ter( ) ;
return - 1 ;
}
if ( ast_sip_register_service ( & multihomed _module) ) {
ast_log ( LOG_ERROR , " Could not register m ultihomed module for incoming and outgoing requests\n " ) ;
ast_res_pjsip_cleanup_message_ ip_upda ter( ) ;
if ( ast_sip_register_service ( & filter _module) ) {
ast_log ( LOG_ERROR , " Could not register m essage filter module for incoming and outgoing requests\n " ) ;
ast_res_pjsip_cleanup_message_ fil ter( ) ;
return - 1 ;
}