@ -31,26 +31,27 @@
# include <fnmatch.h>
const char * FilterType2String ( FilterType ft ) {
switch ( ft ) {
case Transparent : return " transparent " ;
case Whitelist : return " whitelist " ;
case Blacklist : return " blacklist " ;
default : return " unknown " ;
switch ( ft )
{
case Transparent : return " transparent " ;
case Whitelist : return " whitelist " ;
case Blacklist : return " blacklist " ;
default : return " unknown " ;
} ;
}
FilterType String2FilterType ( const char * ft ) {
if ( ! ft )
return Undefined ;
return Undefined ;
if ( ! strcasecmp ( ft , " transparent " ) )
return Transparent ;
return Transparent ;
if ( ! strcasecmp ( ft , " whitelist " ) )
return Whitelist ;
return Whitelist ;
if ( ! strcasecmp ( ft , " blacklist " ) )
return Blacklist ;
return Blacklist ;
return Undefined ;
}
@ -61,178 +62,187 @@ bool isActiveFilter(FilterType ft) {
/** @return whether successful */
bool readFilter ( AmConfigReader & cfg , const char * cfg_key_filter , const char * cfg_key_list ,
vector < FilterEntry > & filter_list , bool keep_transparent_entry ) {
vector < FilterEntry > & filter_list , bool keep_transparent_entry ) {
string filter = cfg . getParameter ( cfg_key_filter ) ;
if ( filter . empty ( ) )
return true ;
return true ;
FilterEntry hf ;
hf . filter_type = String2FilterType ( filter . c_str ( ) ) ;
if ( Undefined = = hf . filter_type ) {
ERROR ( " invalid %s mode '%s' \n " , cfg_key_filter , filter . c_str ( ) ) ;
return false ;
ERROR ( " invalid %s mode '%s' \n " , cfg_key_filter , filter . c_str ( ) ) ;
return false ;
}
// no transparent filter
/* no transparent filter */
if ( ! keep_transparent_entry & & hf . filter_type = = Transparent )
return true ;
return true ;
vector < string > elems = explode ( cfg . getParameter ( cfg_key_list ) , " , " ) ;
for ( vector < string > : : iterator it = elems . begin ( ) ; it ! = elems . end ( ) ; it + + ) {
string c = * it ;
std : : transform ( c . begin ( ) , c . end ( ) , c . begin ( ) , : : tolower ) ;
hf . filter_list . insert ( c ) ;
string c = * it ;
std : : transform ( c . begin ( ) , c . end ( ) , c . begin ( ) , : : tolower ) ;
hf . filter_list . insert ( c ) ;
}
filter_list . push_back ( hf ) ;
return true ;
}
int skip_header ( const std : : string & hdr , size_t start_pos ,
size_t & name_end , size_t & val_begin ,
size_t & val_end , size_t & hdr_end ) {
// adapted from sip/parse_header.cpp
int skip_header ( const std : : string & hdr , size_t start_pos ,
size_t & name_end , size_t & val_begin ,
size_t & val_end , size_t & hdr_end ) {
/* adapted from sip/parse_header.cpp */
name_end = val_begin = val_end = start_pos ;
hdr_end = hdr . length ( ) ;
//
// Header states
//
/*
* Header states
*/
enum {
H_NAME = 0 ,
H_HCOLON ,
H_VALUE_SWS ,
H_VALUE ,
H_NAME = 0 ,
H_HCOLON ,
H_VALUE_SWS ,
H_VALUE ,
} ;
int st = H_NAME ;
int saved_st = 0 ;
size_t p = start_pos ;
for ( ; p < hdr . length ( ) & & st ! = ST_LF & & st ! = ST_CRLF ; p + + ) {
switch ( st ) {
case H_NAME :
switch ( hdr [ p ] ) {
case_CR_LF ;
case HCOLON :
st = H_VALUE_SWS ;
name_end = p ;
break ;
case SP :
case HTAB :
st = H_HCOLON ;
name_end = p ;
break ;
}
break ;
case H_VALUE_SWS :
switch ( hdr [ p ] ) {
case_CR_LF ;
case SP :
case HTAB :
break ;
default :
st = H_VALUE ;
val_begin = p ;
break ;
} ;
break ;
case H_VALUE :
switch ( hdr [ p ] ) {
case_CR_LF ;
} ;
if ( st = = ST_CR | | st = = ST_LF )
val_end = p ;
break ;
case H_HCOLON :
switch ( hdr [ p ] ) {
case HCOLON :
st = H_VALUE_SWS ;
val_begin = p ;
break ;
case SP :
case HTAB :
break ;
default :
DBG ( " Missing ':' after header name \n " ) ;
return MALFORMED_SIP_MSG ;
}
break ;
case_ST_CR ( hdr [ p ] ) ;
st = saved_st ;
hdr_end = p ;
break ;
}
for ( ; p < hdr . length ( ) & & st ! = ST_LF & & st ! = ST_CRLF ; p + + )
{
switch ( st )
{
case H_NAME :
switch ( hdr [ p ] )
{
case_CR_LF ;
case HCOLON :
st = H_VALUE_SWS ;
name_end = p ;
break ;
case SP :
case HTAB :
st = H_HCOLON ;
name_end = p ;
break ;
}
break ;
case H_VALUE_SWS :
switch ( hdr [ p ] )
{
case_CR_LF ;
case SP :
case HTAB :
break ;
default :
st = H_VALUE ;
val_begin = p ;
break ;
} ;
break ;
case H_VALUE :
switch ( hdr [ p ] )
{
case_CR_LF ;
} ;
if ( st = = ST_CR | | st = = ST_LF )
val_end = p ;
break ;
case H_HCOLON :
switch ( hdr [ p ] )
{
case HCOLON :
st = H_VALUE_SWS ;
val_begin = p ;
break ;
case SP :
case HTAB :
break ;
default :
DBG ( " Missing ':' after header name \n " ) ;
return MALFORMED_SIP_MSG ;
}
break ;
case_ST_CR ( hdr [ p ] ) ;
st = saved_st ;
hdr_end = p ;
break ;
}
}
hdr_end = p ;
if ( p = = hdr . length ( ) & & st = = H_VALUE ) {
val_end = p ;
val_end = p ;
}
return 0 ;
}
int inplaceHeaderFilter ( string & hdrs , const vector < FilterEntry > & filter_list ) {
if ( ! hdrs . length ( ) | | ! filter_list . size ( ) )
return 0 ;
return 0 ;
DBG ( " applying %zd header filters \n " , filter_list . size ( ) ) ;
for ( vector < FilterEntry > : : const_iterator fe =
filter_list . begin ( ) ; fe ! = filter_list . end ( ) ; fe + + ) {
const set < string > & headerfilter_list = fe - > filter_list ;
const FilterType & f_type = fe - > filter_type ;
if ( ! isActiveFilter ( f_type ) )
continue ;
// todo: multi-line header support
size_t start_pos = 0 ;
while ( start_pos < hdrs . length ( ) ) {
size_t name_end , val_begin , val_end , hdr_end ;
int res ;
if ( ( res = skip_header ( hdrs , start_pos , name_end , val_begin ,
val_end , hdr_end ) ) ! = 0 ) {
return res ;
}
string hdr_name = hdrs . substr ( start_pos , name_end - start_pos ) ;
std : : transform ( hdr_name . begin ( ) , hdr_name . end ( ) , hdr_name . begin ( ) , : : tolower ) ;
bool erase = ( f_type = = Whitelist ) ;
for ( set < string > : : iterator it = headerfilter_list . begin ( ) ;
it ! = headerfilter_list . end ( ) ; + + it ) {
if ( fnmatch ( it - > c_str ( ) , hdr_name . c_str ( ) , 0 ) = = 0 ) {
erase = ( f_type ! = Whitelist ) ;
break ;
}
}
if ( erase ) {
DBG ( " erasing header '%s' by %s \n " , hdr_name . c_str ( ) , FilterType2String ( f_type ) ) ;
hdrs . erase ( start_pos , hdr_end - start_pos ) ;
} else {
start_pos = hdr_end ;
}
}
for ( vector < FilterEntry > : : const_iterator fe = filter_list . begin ( ) ;
fe ! = filter_list . end ( ) ; fe + + )
{
const set < string > & headerfilter_list = fe - > filter_list ;
const FilterType & f_type = fe - > filter_type ;
if ( ! isActiveFilter ( f_type ) )
continue ;
/* todo: multi-line header support */
size_t start_pos = 0 ;
while ( start_pos < hdrs . length ( ) )
{
size_t name_end , val_begin , val_end , hdr_end ;
int res ;
if ( ( res = skip_header ( hdrs , start_pos , name_end , val_begin ,
val_end , hdr_end ) ) ! = 0 ) {
return res ;
}
string hdr_name = hdrs . substr ( start_pos , name_end - start_pos ) ;
std : : transform ( hdr_name . begin ( ) , hdr_name . end ( ) , hdr_name . begin ( ) , : : tolower ) ;
bool erase = ( f_type = = Whitelist ) ;
for ( set < string > : : iterator it = headerfilter_list . begin ( ) ;
it ! = headerfilter_list . end ( ) ; + + it )
{
if ( fnmatch ( it - > c_str ( ) , hdr_name . c_str ( ) , 0 ) = = 0 ) {
erase = ( f_type ! = Whitelist ) ;
break ;
}
}
if ( erase ) {
DBG ( " erasing header '%s' by %s \n " , hdr_name . c_str ( ) , FilterType2String ( f_type ) ) ;
hdrs . erase ( start_pos , hdr_end - start_pos ) ;
} else {
start_pos = hdr_end ;
}
}
}
return 0 ;