@ -1107,6 +1107,173 @@ error:
return - 1 ;
}
static bool IsBuiltIn ( const char * n )
{
if ( strcmp ( n , " request_started " ) = = 0 | | strcmp ( n , " response_started " ) = = 0 ) {
return true ;
}
if ( strcmp ( n , " request_complete " ) = = 0 | | strcmp ( n , " response_complete " ) = = 0 ) {
return true ;
}
return false ;
}
/** \brief register app hooks as generic lists
*
* Register each hook in each app protocol as :
* < alproto > : < hook name > : generic
* These lists can be used by lua scripts to hook into .
*
* \ todo move elsewhere ? maybe a detect - engine - hook . c ?
*/
void DetectRegisterAppLayerHookLists ( void )
{
for ( AppProto a = ALPROTO_FAILED + 1 ; a < g_alproto_max ; a + + ) {
const char * alproto_name = AppProtoToString ( a ) ;
if ( strcmp ( alproto_name , " http " ) = = 0 )
alproto_name = " http1 " ;
SCLogDebug ( " alproto %u/%s " , a , alproto_name ) ;
const int max_progress_ts =
AppLayerParserGetStateProgressCompletionStatus ( a , STREAM_TOSERVER ) ;
const int max_progress_tc =
AppLayerParserGetStateProgressCompletionStatus ( a , STREAM_TOCLIENT ) ;
char ts_tx_started [ 64 ] ;
snprintf ( ts_tx_started , sizeof ( ts_tx_started ) , " %s:request_started:generic " , alproto_name ) ;
DetectAppLayerInspectEngineRegister (
ts_tx_started , a , SIG_FLAG_TOSERVER , 0 , DetectEngineInspectGenericList , NULL ) ;
SCLogDebug ( " - hook %s:%s list %s (%u) " , alproto_name , " request_name " , ts_tx_started ,
( uint32_t ) strlen ( ts_tx_started ) ) ;
char tc_tx_started [ 64 ] ;
snprintf ( tc_tx_started , sizeof ( tc_tx_started ) , " %s:response_started:generic " , alproto_name ) ;
DetectAppLayerInspectEngineRegister (
tc_tx_started , a , SIG_FLAG_TOCLIENT , 0 , DetectEngineInspectGenericList , NULL ) ;
SCLogDebug ( " - hook %s:%s list %s (%u) " , alproto_name , " response_name " , tc_tx_started ,
( uint32_t ) strlen ( tc_tx_started ) ) ;
char ts_tx_complete [ 64 ] ;
snprintf ( ts_tx_complete , sizeof ( ts_tx_complete ) , " %s:request_complete:generic " ,
alproto_name ) ;
DetectAppLayerInspectEngineRegister ( ts_tx_complete , a , SIG_FLAG_TOSERVER , max_progress_ts ,
DetectEngineInspectGenericList , NULL ) ;
SCLogDebug ( " - hook %s:%s list %s (%u) " , alproto_name , " request_name " , ts_tx_complete ,
( uint32_t ) strlen ( ts_tx_complete ) ) ;
char tc_tx_complete [ 64 ] ;
snprintf ( tc_tx_complete , sizeof ( tc_tx_complete ) , " %s:response_complete:generic " ,
alproto_name ) ;
DetectAppLayerInspectEngineRegister ( tc_tx_complete , a , SIG_FLAG_TOCLIENT , max_progress_tc ,
DetectEngineInspectGenericList , NULL ) ;
SCLogDebug ( " - hook %s:%s list %s (%u) " , alproto_name , " response_name " , tc_tx_complete ,
( uint32_t ) strlen ( tc_tx_complete ) ) ;
for ( int p = 0 ; p < = max_progress_ts ; p + + ) {
const char * name = AppLayerParserGetStateNameById (
IPPROTO_TCP /* TODO no ipproto */ , a , p , STREAM_TOSERVER ) ;
if ( name ! = NULL & & ! IsBuiltIn ( name ) ) {
char list_name [ 64 ] ;
snprintf ( list_name , sizeof ( list_name ) , " %s:%s:generic " , alproto_name , name ) ;
SCLogDebug ( " - hook %s:%s list %s (%u) " , alproto_name , name , list_name ,
( uint32_t ) strlen ( list_name ) ) ;
DetectAppLayerInspectEngineRegister (
list_name , a , SIG_FLAG_TOSERVER , p , DetectEngineInspectGenericList , NULL ) ;
}
}
for ( int p = 0 ; p < = max_progress_tc ; p + + ) {
const char * name = AppLayerParserGetStateNameById (
IPPROTO_TCP /* TODO no ipproto */ , a , p , STREAM_TOCLIENT ) ;
if ( name ! = NULL & & ! IsBuiltIn ( name ) ) {
char list_name [ 64 ] ;
snprintf ( list_name , sizeof ( list_name ) , " %s:%s:generic " , alproto_name , name ) ;
SCLogDebug ( " - hook %s:%s list %s (%u) " , alproto_name , name , list_name ,
( uint32_t ) strlen ( list_name ) ) ;
DetectAppLayerInspectEngineRegister (
list_name , a , SIG_FLAG_TOCLIENT , p , DetectEngineInspectGenericList , NULL ) ;
}
}
}
}
static const char * SignatureHookTypeToString ( enum SignatureHookType t )
{
switch ( t ) {
case SIGNATURE_HOOK_TYPE_NOT_SET :
return " not_set " ;
case SIGNATURE_HOOK_TYPE_APP :
return " app " ;
// case SIGNATURE_HOOK_TYPE_PKT:
// return "pkt";
}
return " unknown " ;
}
static SignatureHook SetAppHook ( const AppProto alproto , int progress )
{
SignatureHook h = {
. type = SIGNATURE_HOOK_TYPE_APP ,
. t . app . alproto = alproto ,
. t . app . app_progress = progress ,
} ;
return h ;
}
/**
* \ param proto_hook string of protocol and hook , e . g . dns : request_complete
*/
static int SigParseProtoHookApp ( Signature * s , const char * proto_hook , const char * p , const char * h )
{
if ( strcmp ( h , " request_started " ) = = 0 ) {
s - > flags | = SIG_FLAG_TOSERVER ;
s - > init_data - > hook =
SetAppHook ( s - > alproto , 0 ) ; // state 0 should be the starting state in each protocol.
} else if ( strcmp ( h , " response_started " ) = = 0 ) {
s - > flags | = SIG_FLAG_TOCLIENT ;
s - > init_data - > hook =
SetAppHook ( s - > alproto , 0 ) ; // state 0 should be the starting state in each protocol.
} else if ( strcmp ( h , " request_complete " ) = = 0 ) {
s - > flags | = SIG_FLAG_TOSERVER ;
s - > init_data - > hook = SetAppHook ( s - > alproto ,
AppLayerParserGetStateProgressCompletionStatus ( s - > alproto , STREAM_TOSERVER ) ) ;
} else if ( strcmp ( h , " response_complete " ) = = 0 ) {
s - > flags | = SIG_FLAG_TOCLIENT ;
s - > init_data - > hook = SetAppHook ( s - > alproto ,
AppLayerParserGetStateProgressCompletionStatus ( s - > alproto , STREAM_TOCLIENT ) ) ;
} else {
const int progress_ts = AppLayerParserGetStateIdByName (
IPPROTO_TCP /* TODO */ , s - > alproto , h , STREAM_TOSERVER ) ;
if ( progress_ts > = 0 ) {
s - > flags | = SIG_FLAG_TOSERVER ;
s - > init_data - > hook = SetAppHook ( s - > alproto , progress_ts ) ;
} else {
const int progress_tc = AppLayerParserGetStateIdByName (
IPPROTO_TCP /* TODO */ , s - > alproto , h , STREAM_TOCLIENT ) ;
if ( progress_tc < 0 ) {
return - 1 ;
}
s - > flags | = SIG_FLAG_TOCLIENT ;
s - > init_data - > hook = SetAppHook ( s - > alproto , progress_tc ) ;
}
}
char generic_hook_name [ 64 ] ;
snprintf ( generic_hook_name , sizeof ( generic_hook_name ) , " %s:generic " , proto_hook ) ;
int list = DetectBufferTypeGetByName ( generic_hook_name ) ;
if ( list < 0 ) {
SCLogError ( " no list registered as %s for hook %s " , generic_hook_name , proto_hook ) ;
return - 1 ;
}
s - > init_data - > hook . sm_list = list ;
SCLogNotice ( " protocol:%s hook:%s: type:%s alproto:%u hook:%d " , p , h ,
SignatureHookTypeToString ( s - > init_data - > hook . type ) , s - > init_data - > hook . t . app . alproto ,
s - > init_data - > hook . t . app . app_progress ) ;
return 0 ;
}
/**
* \ brief Parses the protocol supplied by the Signature .
*
@ -1122,15 +1289,41 @@ error:
static int SigParseProto ( Signature * s , const char * protostr )
{
SCEnter ( ) ;
if ( strlen ( protostr ) > 32 )
return - 1 ;
char proto [ 33 ] ;
strlcpy ( proto , protostr , 33 ) ;
const char * p = proto ;
const char * h = NULL ;
int r = DetectProtoParse ( & s - > proto , ( char * ) protostr ) ;
bool has_hook = strchr ( proto , ' : ' ) ! = NULL ;
if ( has_hook ) {
char * xsaveptr = NULL ;
p = strtok_r ( proto , " : " , & xsaveptr ) ;
h = strtok_r ( NULL , " : " , & xsaveptr ) ;
SCLogDebug ( " p: '%s' h: '%s' " , p , h ) ;
}
if ( p = = NULL ) {
SCLogError ( " invalid protocol specification '%s' " , proto ) ;
return - 1 ;
}
int r = DetectProtoParse ( & s - > proto , p ) ;
if ( r < 0 ) {
s - > alproto = AppLayerGetProtoByName ( ( char * ) protostr ) ;
s - > alproto = AppLayerGetProtoByName ( p ) ;
/* indicate that the signature is app-layer */
if ( s - > alproto ! = ALPROTO_UNKNOWN ) {
s - > flags | = SIG_FLAG_APPLAYER ;
AppLayerProtoDetectSupportedIpprotos ( s - > alproto , s - > proto . proto ) ;
if ( h ) {
if ( SigParseProtoHookApp ( s , protostr , p , h ) < 0 ) {
SCLogError ( " protocol \" %s \" does not support hook \" %s \" " , p , h ) ;
SCReturnInt ( - 1 ) ;
}
}
}
else {
SCLogError ( " protocol \" %s \" cannot be used "
@ -1138,7 +1331,7 @@ static int SigParseProto(Signature *s, const char *protostr)
" is not yet supported OR detection has been disabled for "
" protocol through the yaml option "
" app-layer.protocols.%s.detection-enabled " ,
p rotostr , p rotostr ) ;
p , p ) ;
SCReturnInt ( - 1 ) ;
}
}
@ -2186,6 +2379,7 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
DetectEngineBufferTypeGetNameById ( de_ctx , app - > sm_list ) , app - > dir ,
app - > alproto ) ;
SCLogDebug ( " b->id %d nlists %d " , b - > id , nlists ) ;
if ( b - > only_tc ) {
if ( app - > dir = = 1 )
tc_excl + + ;
@ -2196,6 +2390,22 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
bufdir [ b - > id ] . ts + = ( app - > dir = = 0 ) ;
bufdir [ b - > id ] . tc + = ( app - > dir = = 1 ) ;
}
/* only allow rules to use the hook for engines at that
* exact progress for now . */
if ( s - > init_data - > hook . type = = SIGNATURE_HOOK_TYPE_APP ) {
if ( ( s - > flags & SIG_FLAG_TOSERVER ) & & ( app - > dir = = 0 ) & &
app - > progress ! = s - > init_data - > hook . t . app . app_progress ) {
SCLogError ( " engine progress value %d doesn't match hook %u " , app - > progress ,
s - > init_data - > hook . t . app . app_progress ) ;
SCReturnInt ( 0 ) ;
}
if ( ( s - > flags & SIG_FLAG_TOCLIENT ) & & ( app - > dir = = 1 ) & &
app - > progress ! = s - > init_data - > hook . t . app . app_progress ) {
SCLogError ( " engine progress value doesn't match hook " ) ;
SCReturnInt ( 0 ) ;
}
}
}
}