@ -677,11 +677,15 @@ static void DumpMatches(RuleAnalyzer *ctx, JsonBuilder *js, const SigMatchData *
jb_close ( js ) ;
}
static void EngineAnalysisRulePatterns ( const DetectEngineCtx * de_ctx , const Signature * s ) ;
SCMutex g_rules_analyzer_write_m = SCMUTEX_INITIALIZER ;
void EngineAnalysisRules2 ( const DetectEngineCtx * de_ctx , const Signature * s )
{
SCEnter ( ) ;
EngineAnalysisRulePatterns ( de_ctx , s ) ;
RuleAnalyzer ctx = { NULL , NULL , NULL } ;
ctx . js = jb_new_object ( ) ;
@ -956,6 +960,331 @@ void EngineAnalysisRules2(const DetectEngineCtx *de_ctx, const Signature *s)
SCReturn ;
}
struct PatternItem {
const DetectContentData * cd ;
int sm_list ;
uint32_t cnt ;
uint32_t mpm ;
} ;
static inline uint32_t ContentFlagsForHash ( const DetectContentData * cd )
{
return cd - > flags & ( DETECT_CONTENT_NOCASE | DETECT_CONTENT_OFFSET | DETECT_CONTENT_DEPTH |
DETECT_CONTENT_NEGATED | DETECT_CONTENT_ENDS_WITH ) ;
}
/** \internal
* \ brief The hash function for Pattern
*
* \ param ht Pointer to the hash table .
* \ param data Pointer to the Pattern .
* \ param datalen Not used in our case .
*
* \ retval hash The generated hash value .
*/
static uint32_t PatternHashFunc ( HashListTable * ht , void * data , uint16_t datalen )
{
struct PatternItem * p = ( struct PatternItem * ) data ;
uint32_t hash = p - > sm_list + ContentFlagsForHash ( p - > cd ) ;
for ( uint32_t b = 0 ; b < p - > cd - > content_len ; b + + )
hash + = p - > cd - > content [ b ] ;
return hash % ht - > array_size ;
}
/**
* \ brief The Compare function for Pattern
*
* \ param data1 Pointer to the first Pattern .
* \ param len1 Not used .
* \ param data2 Pointer to the second Pattern .
* \ param len2 Not used .
*
* \ retval 1 If the 2 Patterns sent as args match .
* \ retval 0 If the 2 Patterns sent as args do not match .
*/
static char PatternCompareFunc ( void * data1 , uint16_t len1 , void * data2 , uint16_t len2 )
{
const struct PatternItem * p1 = ( struct PatternItem * ) data1 ;
const struct PatternItem * p2 = ( struct PatternItem * ) data2 ;
if ( p1 - > sm_list ! = p2 - > sm_list )
return 0 ;
if ( ContentFlagsForHash ( p1 - > cd ) ! = ContentFlagsForHash ( p2 - > cd ) )
return 0 ;
if ( p1 - > cd - > content_len ! = p2 - > cd - > content_len )
return 0 ;
if ( memcmp ( p1 - > cd - > content , p2 - > cd - > content , p1 - > cd - > content_len ) ! = 0 ) {
return 0 ;
}
return 1 ;
}
static void PatternFreeFunc ( void * ptr )
{
SCFree ( ptr ) ;
}
/**
* \ brief Initializes the Pattern mpm hash table to be used by the detection
* engine context .
*
* \ param de_ctx Pointer to the detection engine context .
*
* \ retval 0 On success .
* \ retval - 1 On failure .
*/
static int PatternInit ( DetectEngineCtx * de_ctx )
{
de_ctx - > pattern_hash_table =
HashListTableInit ( 4096 , PatternHashFunc , PatternCompareFunc , PatternFreeFunc ) ;
if ( de_ctx - > pattern_hash_table = = NULL )
goto error ;
return 0 ;
error :
return - 1 ;
}
static inline bool NeedsAsHex ( uint8_t c )
{
if ( ! isprint ( c ) )
return true ;
switch ( c ) {
case ' / ' :
case ' ; ' :
case ' : ' :
case ' \\ ' :
case ' ' :
case ' | ' :
case ' " ' :
case ' ` ' :
case ' \' ' :
return true ;
}
return false ;
}
static void PatternPrettyPrint ( const DetectContentData * cd , char * str , size_t str_len )
{
bool hex = false ;
for ( uint16_t i = 0 ; i < cd - > content_len ; i + + ) {
if ( NeedsAsHex ( cd - > content [ i ] ) ) {
char hex_str [ 4 ] ;
snprintf ( hex_str , sizeof ( hex_str ) , " %s%02X " , ! hex ? " | " : " " , cd - > content [ i ] ) ;
strlcat ( str , hex_str , str_len ) ;
hex = true ;
} else {
char p_str [ 3 ] ;
snprintf ( p_str , sizeof ( p_str ) , " %s%c " , hex ? " | " : " " , cd - > content [ i ] ) ;
strlcat ( str , p_str , str_len ) ;
hex = false ;
}
}
if ( hex ) {
strlcat ( str , " | " , str_len ) ;
}
}
void DumpPatterns ( DetectEngineCtx * de_ctx )
{
if ( de_ctx - > buffer_type_map_elements = = 0 | | de_ctx - > pattern_hash_table = = NULL )
return ;
JsonBuilder * root_jb = jb_new_object ( ) ;
JsonBuilder * arrays [ de_ctx - > buffer_type_map_elements ] ;
memset ( & arrays , 0 , sizeof ( JsonBuilder * ) * de_ctx - > buffer_type_map_elements ) ;
jb_open_array ( root_jb , " buffers " ) ;
for ( HashListTableBucket * htb = HashListTableGetListHead ( de_ctx - > pattern_hash_table ) ;
htb ! = NULL ; htb = HashListTableGetListNext ( htb ) ) {
char str [ 1024 ] = " " ;
struct PatternItem * p = HashListTableGetListData ( htb ) ;
PatternPrettyPrint ( p - > cd , str , sizeof ( str ) ) ;
JsonBuilder * jb = arrays [ p - > sm_list ] ;
if ( arrays [ p - > sm_list ] = = NULL ) {
jb = arrays [ p - > sm_list ] = jb_new_object ( ) ;
const char * name ;
if ( p - > sm_list < DETECT_SM_LIST_DYNAMIC_START )
name = DetectListToHumanString ( p - > sm_list ) ;
else
name = DetectBufferTypeGetNameById ( de_ctx , p - > sm_list ) ;
jb_set_string ( jb , " name " , name ) ;
jb_set_uint ( jb , " list_id " , p - > sm_list ) ;
jb_open_array ( jb , " patterns " ) ;
}
jb_start_object ( jb ) ;
jb_set_string ( jb , " pattern " , str ) ;
jb_set_uint ( jb , " patlen " , p - > cd - > content_len ) ;
jb_set_uint ( jb , " cnt " , p - > cnt ) ;
jb_set_uint ( jb , " mpm " , p - > mpm ) ;
jb_open_object ( jb , " flags " ) ;
jb_set_bool ( jb , " nocase " , p - > cd - > flags & DETECT_CONTENT_NOCASE ) ;
jb_set_bool ( jb , " negated " , p - > cd - > flags & DETECT_CONTENT_NEGATED ) ;
jb_set_bool ( jb , " depth " , p - > cd - > flags & DETECT_CONTENT_DEPTH ) ;
jb_set_bool ( jb , " offset " , p - > cd - > flags & DETECT_CONTENT_OFFSET ) ;
jb_set_bool ( jb , " endswith " , p - > cd - > flags & DETECT_CONTENT_ENDS_WITH ) ;
jb_close ( jb ) ;
jb_close ( jb ) ;
}
for ( uint32_t i = 0 ; i < de_ctx - > buffer_type_map_elements ; i + + ) {
JsonBuilder * jb = arrays [ i ] ;
if ( jb = = NULL )
continue ;
jb_close ( jb ) ; // array
jb_close ( jb ) ; // object
jb_append_object ( root_jb , jb ) ;
jb_free ( jb ) ;
}
jb_close ( root_jb ) ;
jb_close ( root_jb ) ;
const char * filename = " patterns.json " ;
const char * log_dir = ConfigGetLogDirectory ( ) ;
char json_path [ PATH_MAX ] = " " ;
snprintf ( json_path , sizeof ( json_path ) , " %s/%s " , log_dir , filename ) ;
SCMutexLock ( & g_rules_analyzer_write_m ) ;
FILE * fp = fopen ( json_path , " a " ) ;
if ( fp ! = NULL ) {
fwrite ( jb_ptr ( root_jb ) , jb_len ( root_jb ) , 1 , fp ) ;
fprintf ( fp , " \n " ) ;
fclose ( fp ) ;
}
SCMutexUnlock ( & g_rules_analyzer_write_m ) ;
jb_free ( root_jb ) ;
HashListTableFree ( de_ctx - > pattern_hash_table ) ;
de_ctx - > pattern_hash_table = NULL ;
}
static void EngineAnalysisRulePatterns ( const DetectEngineCtx * de_ctx , const Signature * s )
{
SCEnter ( ) ;
if ( de_ctx - > pattern_hash_table = = NULL )
PatternInit ( ( DetectEngineCtx * ) de_ctx ) ; // TODO hack const
if ( s - > sm_arrays [ DETECT_SM_LIST_PMATCH ] ) {
SigMatchData * smd = s - > sm_arrays [ DETECT_SM_LIST_PMATCH ] ;
do {
switch ( smd - > type ) {
case DETECT_CONTENT : {
const DetectContentData * cd = ( const DetectContentData * ) smd - > ctx ;
struct PatternItem lookup = {
. cd = cd , . sm_list = DETECT_SM_LIST_PMATCH , . cnt = 0 , . mpm = 0
} ;
struct PatternItem * res =
HashListTableLookup ( de_ctx - > pattern_hash_table , & lookup , 0 ) ;
if ( res ) {
res - > cnt + + ;
res - > mpm + = ( ( cd - > flags & DETECT_CONTENT_MPM ) ! = 0 ) ;
} else {
struct PatternItem * add = SCCalloc ( 1 , sizeof ( * add ) ) ;
BUG_ON ( add = = NULL ) ;
add - > cd = cd ;
add - > sm_list = DETECT_SM_LIST_PMATCH ;
add - > cnt = 1 ;
add - > mpm = ( ( cd - > flags & DETECT_CONTENT_MPM ) ! = 0 ) ;
HashListTableAdd ( de_ctx - > pattern_hash_table , ( void * ) add , 0 ) ;
}
break ;
}
}
if ( smd - > is_last )
break ;
smd + + ;
} while ( 1 ) ;
}
const DetectEngineAppInspectionEngine * app = s - > app_inspect ;
for ( ; app ! = NULL ; app = app - > next ) {
SigMatchData * smd = app - > smd ;
do {
switch ( smd - > type ) {
case DETECT_CONTENT : {
const DetectContentData * cd = ( const DetectContentData * ) smd - > ctx ;
struct PatternItem lookup = {
. cd = cd , . sm_list = app - > sm_list , . cnt = 0 , . mpm = 0
} ;
struct PatternItem * res =
HashListTableLookup ( de_ctx - > pattern_hash_table , & lookup , 0 ) ;
if ( res ) {
res - > cnt + + ;
res - > mpm + = ( ( cd - > flags & DETECT_CONTENT_MPM ) ! = 0 ) ;
} else {
struct PatternItem * add = SCCalloc ( 1 , sizeof ( * add ) ) ;
BUG_ON ( add = = NULL ) ;
add - > cd = cd ;
add - > sm_list = app - > sm_list ;
add - > cnt = 1 ;
add - > mpm = ( ( cd - > flags & DETECT_CONTENT_MPM ) ! = 0 ) ;
HashListTableAdd ( de_ctx - > pattern_hash_table , ( void * ) add , 0 ) ;
}
break ;
}
}
if ( smd - > is_last )
break ;
smd + + ;
} while ( 1 ) ;
}
const DetectEnginePktInspectionEngine * pkt = s - > pkt_inspect ;
for ( ; pkt ! = NULL ; pkt = pkt - > next ) {
SigMatchData * smd = pkt - > smd ;
do {
if ( smd = = NULL ) {
BUG_ON ( ! ( pkt - > sm_list < DETECT_SM_LIST_DYNAMIC_START ) ) ;
smd = s - > sm_arrays [ pkt - > sm_list ] ;
}
switch ( smd - > type ) {
case DETECT_CONTENT : {
const DetectContentData * cd = ( const DetectContentData * ) smd - > ctx ;
struct PatternItem lookup = {
. cd = cd , . sm_list = pkt - > sm_list , . cnt = 0 , . mpm = 0
} ;
struct PatternItem * res =
HashListTableLookup ( de_ctx - > pattern_hash_table , & lookup , 0 ) ;
if ( res ) {
res - > cnt + + ;
res - > mpm + = ( ( cd - > flags & DETECT_CONTENT_MPM ) ! = 0 ) ;
} else {
struct PatternItem * add = SCCalloc ( 1 , sizeof ( * add ) ) ;
BUG_ON ( add = = NULL ) ;
add - > cd = cd ;
add - > sm_list = pkt - > sm_list ;
add - > cnt = 1 ;
add - > mpm = ( ( cd - > flags & DETECT_CONTENT_MPM ) ! = 0 ) ;
HashListTableAdd ( de_ctx - > pattern_hash_table , ( void * ) add , 0 ) ;
}
break ;
}
}
if ( smd - > is_last )
break ;
smd + + ;
} while ( 1 ) ;
}
SCReturn ;
}
static void EngineAnalysisItemsReset ( void )
{
for ( size_t i = 0 ; i < ARRAY_SIZE ( analyzer_items ) ; i + + ) {