/* Simple content match part of the detection engine.
*
* Copyright ( C ) 2008 by Victor Julien < victor @ inliniac . net > */
# include "suricata-common.h"
# include "decode.h"
# include "detect.h"
# include "detect-content.h"
# include "detect-uricontent.h"
# include "detect-engine-mpm.h"
# include "detect-engine.h"
# include "detect-parse.h"
# include "util-mpm.h"
# include "flow.h"
# include "flow-var.h"
# include "detect-flow.h"
# include "util-unittest.h"
# include "util-print.h"
# include "util-debug.h"
# include "threads.h"
int DetectContentMatch ( ThreadVars * , DetectEngineThreadCtx * , Packet * , Signature * , SigMatch * ) ;
static int DetectContentSetup ( DetectEngineCtx * , Signature * , char * ) ;
void DetectContentRegisterTests ( void ) ;
void DetectContentRegister ( void ) {
sigmatch_table [ DETECT_CONTENT ] . name = " content " ;
sigmatch_table [ DETECT_CONTENT ] . Match = NULL ;
sigmatch_table [ DETECT_CONTENT ] . Setup = DetectContentSetup ;
sigmatch_table [ DETECT_CONTENT ] . Free = DetectContentFree ;
sigmatch_table [ DETECT_CONTENT ] . RegisterTests = DetectContentRegisterTests ;
sigmatch_table [ DETECT_CONTENT ] . flags | = SIGMATCH_PAYLOAD ;
}
/* pass on the content_max_id */
uint32_t DetectContentMaxId ( DetectEngineCtx * de_ctx ) {
//SCLogDebug("DetectContentMaxId: %" PRIu32 "", de_ctx->content_max_id);
return de_ctx - > content_max_id ;
}
DetectContentData * DetectContentParse ( char * contentstr )
{
DetectContentData * cd = NULL ;
char * str = NULL ;
char * temp = NULL ;
uint16_t len ;
uint16_t pos = 0 ;
uint16_t slen = 0 ;
if ( ( temp = SCStrdup ( contentstr ) ) = = NULL ) {
SCLogError ( SC_ERR_MEM_ALLOC , " Error allocating memory " ) ;
goto error ;
}
if ( strlen ( temp ) = = 0 ) {
SCFree ( temp ) ;
return NULL ;
}
cd = SCMalloc ( sizeof ( DetectContentData ) ) ;
if ( cd = = NULL ) {
SCLogError ( SC_ERR_MEM_ALLOC , " SCMalloc failed " ) ;
goto error ;
}
memset ( cd , 0 , sizeof ( DetectContentData ) ) ;
/* skip the first spaces */
slen = strlen ( temp ) ;
while ( pos < slen & & isspace ( temp [ pos ] ) ) {
pos + + ;
} ;
if ( temp [ pos ] = = ' ! ' ) {
SCFree ( temp ) ;
if ( ( temp = SCStrdup ( contentstr + pos + 1 ) ) = = NULL )
goto error ;
cd - > negated = 1 ;
}
if ( temp [ pos ] = = ' \" ' & & temp [ strlen ( temp ) - 1 ] = = ' \" ' ) {
if ( ( str = SCStrdup ( temp + pos + 1 ) ) = = NULL )
goto error ;
str [ strlen ( temp ) - pos - 2 ] = ' \0 ' ;
} else {
if ( ( str = SCStrdup ( temp + pos ) ) = = NULL )
goto error ;
}
SCFree ( temp ) ;
Memory leak cleanup in detectors
Hello,
I ran the code through an analysis program and found several leaks that
should be cleaned up.
*In src/detect-engine-address-ipv4.c at line 472, the test for ag == NULL
will never be true since that is the loop entry test.
*In src/detect-engine-port.c at line 1133, the test for p == NULL will
never be true since that is the loop entry test.
*In src/detect-engine-mpm.c at line 263 is a return without freeing
fast_pattern
*In src/detect-ack.c at line 80 and 85, data catches the return from malloc.
One of them should be deleted.
*In src/detect-seq.c at line 81 and 86, data catches the return from malloc.
One of them should be deleted.
*In src/detect-content.c at line 749, many of the paths that lead to the error
exit still has temp pointing to allocated memory. To clean this up, temp
should be set to NULL if not immediately assigning and new value.
*In src/detect-uricontent.c at line 319, both cd and str needto be freed. At
lines 344, str needs to be freed. And at line 347 str and temp need to be
freed.
*In src/detect-flowbits.c at line 231 and 235, str was not being freed. cd was
not being freed at line 235.
*In src/detect-flowvar.c at line 127, str was not being freed. At line 194, cd
and str were not being freed.
*In src/detect-flowint.c at line 277, sfd was not being freed. At line 315, str
was not being freed.
*In src/detect-pktvar.c at line 121, str was not being freed. At line 188, str
and cd was not being freed.
*In src/detect-pcre.c at line 389, there is an extra free of "re" that should
be deleted.
*In src/detect-depth.c at line 42 & 48, str has not been freed.
*In src/detect-distance.c at line 49 and 55, str has not been freed
*In src/detect-offset.c at line 45, str has not been freed.
The patch below fixes these issues.
-Steve
16 years ago
temp = NULL ;
/*This was submitted as a patch for bug #11. But this impliments incorrect behavior as !
* inside of quotes should be treated as normal match . */
//if (str[0] == '!') {
// if (cd->negated == 1) {
// SCLogDebug("Invalid negated content. \"!\" located twice at the "
// "start of the contet string: %s", contentstr);
// goto error;
// } else {
// temp = str;
// if ( (str = SCStrdup(temp + 1)) == NULL)
// goto error;
// cd->negated = 1;
// SCFree(temp);
// temp = NULL;
// }
//}
len = strlen ( str ) ;
if ( len = = 0 )
goto error ;
//SCLogDebug("DetectContentParse: \"%s\", len %" PRIu32 "", str, len);
char converted = 0 ;
{
uint16_t i , x ;
uint8_t bin = 0 ;
uint8_t escape = 0 ;
uint8_t binstr [ 3 ] = " " ;
uint8_t binpos = 0 ;
for ( i = 0 , x = 0 ; i < len ; i + + ) {
// SCLogDebug("str[%02u]: %c", i, str[i]);
if ( str [ i ] = = ' | ' ) {
if ( bin ) {
bin = 0 ;
} else {
bin = 1 ;
}
} else if ( ! escape & & str [ i ] = = ' \\ ' ) {
escape = 1 ;
} else {
if ( bin ) {
if ( isdigit ( str [ i ] ) | |
str [ i ] = = ' A ' | | str [ i ] = = ' a ' | |
str [ i ] = = ' B ' | | str [ i ] = = ' b ' | |
str [ i ] = = ' C ' | | str [ i ] = = ' c ' | |
str [ i ] = = ' D ' | | str [ i ] = = ' d ' | |
str [ i ] = = ' E ' | | str [ i ] = = ' e ' | |
str [ i ] = = ' F ' | | str [ i ] = = ' f ' )
{
// SCLogDebug("part of binary: %c", str[i]);
binstr [ binpos ] = ( char ) str [ i ] ;
binpos + + ;
if ( binpos = = 2 ) {
uint8_t c = strtol ( ( char * ) binstr , ( char * * ) NULL , 16 ) & 0xFF ;
binpos = 0 ;
str [ x ] = c ;
x + + ;
converted = 1 ;
}
} else if ( str [ i ] = = ' ' ) {
// SCLogDebug("space as part of binary string");
}
} else if ( escape ) {
if ( str [ i ] = = ' : ' | |
str [ i ] = = ' ; ' | |
str [ i ] = = ' \\ ' | |
str [ i ] = = ' \" ' )
{
str [ x ] = str [ i ] ;
x + + ;
} else {
//SCLogDebug("Can't escape %c", str[i]);
goto error ;
}
escape = 0 ;
converted = 1 ;
} else {
str [ x ] = str [ i ] ;
x + + ;
}
}
}
#if 0 //def DEBUG
if ( SCLogDebugEnabled ( ) ) {
for ( i = 0 ; i < x ; i + + ) {
if ( isprint ( str [ i ] ) ) SCLogDebug ( " %c " , str [ i ] ) ;
else SCLogDebug ( " \\ x%02u " , str [ i ] ) ;
}
SCLogDebug ( " " ) ;
}
# endif
if ( converted ) {
len = x ;
}
}
cd - > content = SCMalloc ( len ) ;
if ( cd - > content = = NULL )
goto error ;
memcpy ( cd - > content , str , len ) ;
cd - > content_len = len ;
cd - > depth = 0 ;
cd - > offset = 0 ;
cd - > within = 0 ;
cd - > distance = 0 ;
cd - > flags = 0 ;
SCFree ( str ) ;
return cd ;
error :
SCFree ( str ) ;
SCFree ( temp ) ;
if ( cd ! = NULL ) {
if ( cd - > content ! = NULL )
SCFree ( cd - > content ) ;
SCFree ( cd ) ;
}
return NULL ;
}
/**
* \ brief Helper function to print a DetectContentData
*/
void DetectContentPrint ( DetectContentData * cd )
{
int i = 0 ;
if ( cd = = NULL ) {
SCLogDebug ( " DetectContentData \" cd \" is NULL " ) ;
return ;
}
char * tmpstr = SCMalloc ( sizeof ( char ) * cd - > content_len + 1 ) ;
if ( tmpstr ! = NULL ) {
for ( i = 0 ; i < cd - > content_len ; i + + ) {
if ( isprint ( cd - > content [ i ] ) )
tmpstr [ i ] = cd - > content [ i ] ;
else
tmpstr [ i ] = ' . ' ;
}
tmpstr [ i ] = ' \0 ' ;
SCLogDebug ( " Content: \" %s \" " , tmpstr ) ;
SCFree ( tmpstr ) ;
} else {
SCLogDebug ( " Content: " ) ;
for ( i = 0 ; i < cd - > content_len ; i + + )
SCLogDebug ( " %c " , cd - > content [ i ] ) ;
}
SCLogDebug ( " Content_id: %u " , cd - > id ) ;
SCLogDebug ( " Content_len: %u " , cd - > content_len ) ;
SCLogDebug ( " Depth: %u " , cd - > depth ) ;
SCLogDebug ( " Offset: %u " , cd - > offset ) ;
SCLogDebug ( " Within: %u " , cd - > within ) ;
SCLogDebug ( " Distance: %u " , cd - > distance ) ;
SCLogDebug ( " Isdataat: %u " , cd - > isdataat ) ;
SCLogDebug ( " flags: %u " , cd - > flags ) ;
SCLogDebug ( " negated %u " , cd - > negated ) ;
SCLogDebug ( " within next: %s " , cd - > flags & DETECT_CONTENT_WITHIN_NEXT ? " true " : " false " ) ;
SCLogDebug ( " distance next: %s " , cd - > flags & DETECT_CONTENT_DISTANCE_NEXT ? " true " : " false " ) ;
/** If it's a chunk, print the data related */
if ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) {
SCLogDebug ( " * Is_Chunk: is set " ) ;
SCLogDebug ( " chunk_group_id: %u " , cd - > chunk_group_id ) ;
SCLogDebug ( " chunk_id: %u " , cd - > chunk_id ) ;
} else {
SCLogDebug ( " Is_Chunk: is not set " ) ;
}
SCLogDebug ( " ----------- " ) ;
}
/**
* \ brief Function that return chunks of a original DetectContentData
* that need to be split
* \ param origcd pointer to the real DetectContentData
* \ param remaining_content_length to the real DetectContentData
*
* \ retval NULL if something goes wrong
* \ retval DetectContentData pointer to the new chunk
*/
DetectContentData * DetectContentSplitChunk ( DetectContentData * origcd ,
uint8_t remaining_content_len ,
uint8_t index , int32_t mpl )
{
DetectContentData * cd = SCMalloc ( sizeof ( DetectContentData ) ) ;
if ( cd = = NULL ) {
SCLogError ( SC_ERR_MEM_ALLOC , " DetectContentData SCMalloc failed " ) ;
goto error ;
}
memset ( cd , 0 , sizeof ( DetectContentData ) ) ;
/* Get the length for this chunk */
if ( remaining_content_len < mpl )
cd - > content_len = remaining_content_len ;
else
cd - > content_len = mpl ;
if ( cd - > content_len < = 0 )
goto error ;
cd - > content = ( uint8_t * ) SCMalloc ( sizeof ( uint8_t ) * cd - > content_len ) ;
if ( cd - > content = = NULL ) {
SCLogError ( SC_ERR_MEM_ALLOC , " string for content SCMalloc failed " ) ;
goto error ;
}
memcpy ( cd - > content , origcd - > content + index * sizeof ( uint8_t ) , cd - > content_len ) ;
return cd ;
error :
if ( cd ! = NULL ) {
if ( cd - > content ! = NULL )
SCFree ( cd - > content ) ;
SCFree ( cd ) ;
}
return NULL ;
}
/**
* \ brief Search the next applicable DETECT_CONTENT SigMatch
( includes the current sm )
*
* \ param sm pointer to the current SigMatch of a parsing process
*
* \ retval null if no applicable DetectContent was found
* \ retval pointer to the SigMatch next DETECT_CONTENT SigMatch
*/
SigMatch * DetectContentFindNextApplicableSM ( SigMatch * sm )
{
if ( sm = = NULL )
return NULL ;
while ( sm ! = NULL & & sm - > type ! = DETECT_CONTENT )
sm = sm - > next ;
return sm ;
}
/**
* \ brief Helper function to determine if there are patterns before this one ,
* this is used before installing a new within or distance modifier
* because if this return NULL , it will never match !
*
* \ param sm pointer to the current SigMatch of a parsing process
*
* \ retval null if no applicable SigMatch pattern was found
* \ retval pointer to the SigMatch that has the previous SigMatch
* of type DetectContent , ( and is the first chunk if
* the pattern was splitted )
*
* \ todo : should we add here DETECT_PCRE , DETECT_URI_CONTENT , etc ?
*/
SigMatch * DetectContentHasPrevSMPattern ( SigMatch * sm )
{
if ( sm = = NULL )
return NULL ;
/* the current SM doesn't apply */
sm = sm - > prev ;
while ( sm ! = NULL & & sm - > type ! = DETECT_CONTENT )
sm = sm - > prev ;
return sm ;
}
/**
* \ brief Search the first DETECT_CONTENT chunk of the last group in the
* previous SigMatches or the first DETECT_CONTENT not chunked
* \ retval pointer to the SigMatch holding the DetectContent
* \ param sm pointer to the current SigMatch of a parsing process
* \ retval null if no applicable DetectContent was found
* \ retval pointer to the SigMatch that has the previous SigMatch
* of type DetectContent , ( and is the first chunk if
* the pattern was splitted )
*/
SigMatch * DetectContentFindPrevApplicableSM ( SigMatch * sm )
{
if ( sm = = NULL )
return NULL ;
while ( sm ! = NULL & & sm - > type ! = DETECT_CONTENT )
sm = sm - > prev ;
if ( sm = = NULL )
return NULL ;
DetectContentData * cd = ( DetectContentData * ) sm - > ctx ;
if ( cd = = NULL )
return NULL ;
/** It's not a chunk, so its the only DetectContent for this pattern */
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) )
return sm ;
/** Else search for the first chunk in this group of chunks */
uint8_t chunk_group_id = cd - > chunk_group_id ;
while ( sm ! = NULL & & sm - > type = = DETECT_CONTENT )
{
cd = ( DetectContentData * ) sm - > ctx ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) )
return NULL ;
/** Weird case, this means that the chunk are not consecutive
* or not likned correctly */
if ( cd - > chunk_group_id ! = chunk_group_id )
return NULL ;
/** If we get the first one, return the SimMatch */
if ( cd - > chunk_id = = 0 )
return sm ;
sm = sm - > prev ;
}
/* We should not be here */
return NULL ;
}
/** \brief get the last pattern sigmatch, content or uricontent
*
* \ param s signature
*
* \ retval sm sigmatch of either content or uricontent that is the last
* or NULL if none was found
*/
SigMatch * SigMatchGetLastPattern ( Signature * s ) {
SCEnter ( ) ;
BUG_ON ( s = = NULL ) ;
SigMatch * co_sm = DetectContentFindPrevApplicableSM ( s - > pmatch_tail ) ;
SigMatch * ur_sm = SigMatchGetLastSM ( s - > match , DETECT_URICONTENT ) ;
SigMatch * sm = NULL ;
if ( co_sm ! = NULL & & ur_sm ! = NULL ) {
BUG_ON ( co_sm - > idx = = ur_sm - > idx ) ;
if ( co_sm - > idx > ur_sm - > idx )
sm = co_sm ;
else
sm = ur_sm ;
} else if ( co_sm ! = NULL ) {
sm = co_sm ;
} else if ( ur_sm ! = NULL ) {
sm = ur_sm ;
}
SCReturnPtr ( sm , " SigMatch " ) ;
}
/**
* \ brief Count the number of chunks of a specified chunk group
* \ param sm pointer to a SigMatch that belong to this chunk group
* \ param chunk_group_id id of the group of chunks ( to ensure )
* \ retval - 1 if something fail
* \ retval count of the chunks of this group
*/
int DetectContentCountChunksInGroup ( SigMatch * sm , uint8_t chunk_group_id )
{
int count = 0 ;
if ( sm = = NULL | | sm - > type ! = DETECT_CONTENT )
return - 1 ;
DetectContentData * cd = NULL ;
SigMatch * first_sm = DetectContentFindPrevApplicableSM ( sm ) ;
for ( ; first_sm ! = NULL & &
first_sm - > type = = DETECT_CONTENT & &
first_sm - > ctx ! = NULL & &
( cd = ( DetectContentData * ) first_sm - > ctx ) & &
( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & &
cd - > chunk_group_id = = chunk_group_id
; first_sm = first_sm - > next , count + + ) ;
return count ;
}
/**
* \ brief Get the remaining legth of a splitted pattern
* ( current content not included ! )
* \ param first_sm pointer to a SigMatch that belong to this chunk group
* \ retval pointer to the SigMatch holding the DetectContent
* \ retval - 1 if fail
* \ retval length if every thing was ok
*/
int DetectContentChunksGetRemainingLength ( SigMatch * first_sm )
{
int length = 0 ;
if ( first_sm = = NULL )
return - 1 ;
if ( first_sm - > type ! = DETECT_CONTENT | | first_sm - > ctx = = NULL )
return - 1 ;
DetectContentData * cd = ( DetectContentData * ) first_sm - > ctx ;
uint8_t chunk_group_id = cd - > chunk_group_id ;
/** Skip the current content (not included) */
first_sm = first_sm - > next ;
/** sum the content_len's */
for ( ; first_sm ! = NULL & &
first_sm - > type = = DETECT_CONTENT & &
first_sm - > ctx ! = NULL & &
( cd = ( DetectContentData * ) first_sm - > ctx ) & &
( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & &
cd - > chunk_group_id = = chunk_group_id
; first_sm = first_sm - > next , length + = cd - > content_len ) ;
return length ;
}
/**
* \ brief Get the previous legth of a splitted pattern ( current content not included ! )
* \ param first_sm pointer to a SigMatch that belong to this chunk group
* \ retval pointer to the SigMatch holding the DetectContent
* \ retval length if every thing was ok
* \ retval - 1 if fail
*/
int DetectContentChunksGetPreviousLength ( SigMatch * sm )
{
int length = 0 ;
if ( sm = = NULL )
return - 1 ;
if ( sm - > type ! = DETECT_CONTENT | | sm - > ctx = = NULL )
return - 1 ;
DetectContentData * cd = ( DetectContentData * ) sm - > ctx ;
uint8_t chunk_group_id = cd - > chunk_group_id ;
uint8_t chunk_id = cd - > chunk_id ;
SigMatch * first_sm = DetectContentFindPrevApplicableSM ( sm ) ;
for ( ; first_sm ! = NULL & &
first_sm - > type = = DETECT_CONTENT & &
first_sm - > ctx ! = NULL & &
( cd = ( DetectContentData * ) first_sm - > ctx ) & &
( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & &
cd - > chunk_group_id = = chunk_group_id & &
cd - > chunk_id ! = chunk_id
; first_sm = first_sm - > next , length + = cd - > content_len ) ;
if ( cd ! = NULL & & cd - > chunk_id = = chunk_id )
return length ;
return 0 ;
}
/**
* \ brief Get the total legth of a splitted pattern
* \ param first_sm pointer to a SigMatch that belong to this chunk group
* \ retval pointer to the SigMatch holding the DetectContent
* \ retval length if every thing was ok
* \ retval - 1 if fail
*/
int DetectContentChunksGetTotalLength ( SigMatch * sm )
{
int length = 0 ;
if ( sm = = NULL )
return - 1 ;
if ( sm - > type ! = DETECT_CONTENT | | sm - > ctx = = NULL )
return - 1 ;
DetectContentData * cd = ( DetectContentData * ) sm - > ctx ;
uint8_t chunk_group_id = cd - > chunk_group_id ;
/** Go to the first SigMatch of this Chunk group */
SigMatch * first_sm = DetectContentFindPrevApplicableSM ( sm ) ;
for ( ; first_sm ! = NULL & &
first_sm - > type = = DETECT_CONTENT & &
first_sm - > ctx ! = NULL & &
( cd = ( DetectContentData * ) first_sm - > ctx ) & &
( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & &
cd - > chunk_group_id = = chunk_group_id
; first_sm = first_sm - > next , length + = cd - > content_len ) ;
return length ;
}
/**
* \ brief Print list of DETECT_CONTENT SigMatch ' s allocated in a
* SigMatch list , from the current sm to the end
* \ param sm pointer to the current SigMatch to start printing from
*/
void DetectContentPrintAll ( SigMatch * sm )
{
# ifdef DEBUG
int i = 0 ;
if ( SCLogDebugEnabled ( ) ) {
if ( sm = = NULL )
return ;
/** Go to the first SigMatch of this Chunk group */
SigMatch * first_sm = sm ;
/* Print all of them */
for ( ; first_sm ! = NULL ; first_sm = first_sm - > next ) {
if ( first_sm - > type = = DETECT_CONTENT ) {
SCLogDebug ( " Printing SigMatch DETECT_CONTENT %d " , + + i ) ;
DetectContentPrint ( first_sm - > ctx ) ;
}
}
}
# endif /* DEBUG */
}
/**
* \ brief Function to update modifiers of a chunk group after setting depth
* \ param first_sm pointer to the head of this group of chunks to update
* \ retval - 1 if error
* \ retval 1 if all was ok
*/
int DetectContentPropagateDepth ( SigMatch * first_sm )
{
int res = - 1 ;
DetectContentData * cd = first_sm - > ctx ;
if ( first_sm = = NULL | | first_sm - > ctx = = NULL )
return - 1 ;
if ( cd - > chunk_flags & CHUNK_UPDATED_DEPTH )
{
SCLogDebug ( " Depth already set for this pattern!! " ) ;
return res ;
}
res = DetectContentPropagateModifiers ( first_sm ) ;
if ( res = = 1 ) {
cd - > chunk_flags | = CHUNK_UPDATED_DEPTH ;
}
return res ;
}
/**
* \ brief Function to update modifiers of a chunk group after setting isdataat
* \ param first_sm pointer to the head of this group of chunks to update
* \ retval - 1 if error
* \ retval 1 if all was ok
*/
int DetectContentPropagateIsdataat ( SigMatch * first_sm )
{
int res = - 1 ;
DetectContentData * cd = first_sm - > ctx ;
if ( first_sm = = NULL | | first_sm - > ctx = = NULL )
return - 1 ;
if ( cd - > chunk_flags & CHUNK_UPDATED_ISDATAAT )
{
SCLogDebug ( " Depth already set for this pattern!! " ) ;
return res ;
}
res = DetectContentPropagateModifiers ( first_sm ) ;
if ( res = = 1 ) {
cd - > chunk_flags | = CHUNK_UPDATED_ISDATAAT ;
}
return res ;
}
/**
* \ brief Function to update modifiers of a chunk group after setting within
* \ param first_sm pointer to the head of this group of chunks to update
* \ retval - 1 if error
* \ retval 1 if all was ok
*/
int DetectContentPropagateWithin ( SigMatch * first_sm )
{
int res = - 1 ;
DetectContentData * cd = first_sm - > ctx ;
if ( first_sm = = NULL | | first_sm - > ctx = = NULL )
return - 1 ;
if ( cd - > chunk_flags & CHUNK_UPDATED_WITHIN )
{
SCLogDebug ( " Depth already set for this pattern!! " ) ;
return res ;
}
res = DetectContentPropagateModifiers ( first_sm ) ;
if ( res = = 1 ) {
cd - > chunk_flags | = CHUNK_UPDATED_WITHIN ;
}
return res ;
}
/**
* \ brief Function to update modifiers of a chunk group after setting distance
* \ param first_sm pointer to the head of this group of chunks to update
* \ retval - 1 if error
* \ retval 1 if all was ok
*/
int DetectContentPropagateDistance ( SigMatch * first_sm )
{
int res = - 1 ;
DetectContentData * cd = first_sm - > ctx ;
if ( first_sm = = NULL | | first_sm - > ctx = = NULL )
return - 1 ;
if ( cd - > chunk_flags & CHUNK_UPDATED_DISTANCE )
{
SCLogDebug ( " Depth already set for this pattern!! " ) ;
return res ;
}
res = DetectContentPropagateModifiers ( first_sm ) ;
if ( res = = 1 ) {
cd - > chunk_flags | = CHUNK_UPDATED_DISTANCE ;
}
return res ;
}
/**
* \ brief Function to update modifiers of a chunk group after setting Offset
* \ param first_sm pointer to the head of this group of chunks to update
* \ retval - 1 if error
* \ retval 1 if all was ok
*/
int DetectContentPropagateOffset ( SigMatch * first_sm )
{
int res = - 1 ;
DetectContentData * cd = first_sm - > ctx ;
if ( first_sm = = NULL | | first_sm - > ctx = = NULL )
return - 1 ;
if ( cd - > chunk_flags & CHUNK_UPDATED_OFFSET )
{
SCLogDebug ( " Depth already set for this pattern!! " ) ;
return res ;
}
res = DetectContentPropagateModifiers ( first_sm ) ;
if ( res = = 1 ) {
cd - > chunk_flags | = CHUNK_UPDATED_OFFSET ;
}
return res ;
}
/**
* \ brief Function to update modifiers of a chunk group after setting a modifier
* This function should not be called directly from outside detect - content . c !
*
* \ param first_sm pointer to the head of this group of chunks to update
* \ retval - 1 if error
* \ retval 1 if all was ok
*/
int DetectContentPropagateModifiers ( SigMatch * first_sm )
{
SCEnter ( ) ;
if ( first_sm = = NULL )
goto error ;
/** Rewind the pointer to the start of the chunk if we have a chunk group */
first_sm = DetectContentFindPrevApplicableSM ( first_sm ) ;
if ( first_sm - > ctx = = NULL )
goto error ;
DetectContentData * first_chunk = ( DetectContentData * ) first_sm - > ctx ;
if ( first_chunk = = NULL )
goto error ;
if ( ! ( first_chunk - > flags & DETECT_CONTENT_IS_CHUNK ) ) {
/** No modifiers to update */
SCReturnInt ( 1 ) ;
}
uint8_t chunk_group_id = first_chunk - > chunk_group_id ;
uint8_t num_chunks = DetectContentCountChunksInGroup ( first_sm , chunk_group_id ) ;
int16_t total_len = DetectContentChunksGetTotalLength ( first_sm ) ;
if ( num_chunks < 1 | | total_len < 1 )
goto error ;
DetectContentData * cur_chunk = NULL ;
DetectContentData * last_chunk = first_chunk ;
SigMatch * cur_sm = NULL ;
/** The first chunk has the real modifiers that we want to propagate */
for ( cur_sm = first_sm ;
cur_sm ! = NULL & &
cur_sm - > type = = DETECT_CONTENT & &
( cur_chunk = ( DetectContentData * ) cur_sm - > ctx ) ! = NULL & &
cur_chunk - > chunk_group_id = = chunk_group_id ;
cur_sm = cur_sm - > next ) {
//SCLogDebug("Cur: %u %s Last: %u %s", cur_chunk->offset, cur_chunk->content, last_chunk->offset, last_chunk->content);
int16_t remaining_len = DetectContentChunksGetRemainingLength ( cur_sm ) ;
int16_t previous_len = DetectContentChunksGetRemainingLength ( cur_sm ) ;
if ( previous_len < 0 | | remaining_len < 0 )
goto error ;
/** If we are in the first chunk */
if ( cur_chunk - > chunk_id = = 0 ) {
SCLogDebug ( " handling first chunk " ) ;
/** Reset the first depth removing the length of the remaining chunks
*/
SCLogDebug ( " CUR depth = %u remain_len %d " , cur_chunk - > depth , remaining_len ) ;
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_DEPTH ) & & cur_chunk - > depth > 0 )
cur_chunk - > depth - = remaining_len ;
/** Reset the first within removing the length of the remaining chunks
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_WITHIN ) & & cur_chunk - > within > 0 )
cur_chunk - > within - = remaining_len ;
/** Reset the first isdataat adding the length of the remaining chunks
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_ISDATAAT ) & & cur_chunk - > isdataat > 0 )
cur_chunk - > isdataat + = remaining_len ;
/**
* The offseth for the first chunk is the real offset ,
* so no need to update it here
* The same is applicable here to offset and distance
*/
/** If it's not the first chunk we need to propagate the changes */
} else {
SCLogDebug ( " handling first chunk id % " PRIu8 " , last_chunk %p " , cur_chunk - > chunk_id , last_chunk ) ;
/** Propagate the flags */
cur_chunk - > flags = last_chunk - > flags ;
/** Update the depth adding the content_len of the current chunk
* to the previous chunk depth
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_DEPTH ) & & last_chunk - > depth > 0 )
cur_chunk - > depth = last_chunk - > depth + cur_chunk - > content_len ;
/** Update the offset adding the content_len of the last chunk
* to the previous chunk offset
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_OFFSET ) & & last_chunk - > offset > 0 )
cur_chunk - > offset = last_chunk - > offset + last_chunk - > content_len ;
/** We are iterating in the chunks after the first one, so within is
* relative to the previous chunks and should be exactly the size of
* its content_len since they are consecutive
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_WITHIN ) ) {
/** Even if they don't specify a within option,
* we set the flag , since they are relative to the chunks
* of the same pattern
*/
cur_chunk - > flags | = DETECT_CONTENT_WITHIN ;
cur_chunk - > within = cur_chunk - > content_len ;
/* set the within next flag on the previous chunk */
if ( last_chunk ! = NULL ) {
SCLogDebug ( " within next flag set to prev chunk " ) ;
last_chunk - > flags | = DETECT_CONTENT_WITHIN_NEXT ;
}
}
/** We are iterating in the chunks after the first one, so distance
* must be 0 between the chunks , since they are consecutive
* splitted chunks
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_DISTANCE ) ) {
/** Even if they don't specify a within option,
* we set the flag , since they are relative to the chunks
* of the same pattern
*/
cur_chunk - > flags | = DETECT_CONTENT_DISTANCE ;
cur_chunk - > distance = 0 ;
/* set the distance next flag on the previous chunk */
if ( last_chunk ! = NULL )
last_chunk - > flags | = DETECT_CONTENT_DISTANCE_NEXT ;
}
/** The isdataat (relative) is updated to the
* last_chunk isdataat - the content_len of the current
* chunk content_len
*/
if ( ! ( cur_chunk - > chunk_flags & CHUNK_UPDATED_ISDATAAT ) & & last_chunk - > isdataat > 0 )
cur_chunk - > isdataat = last_chunk - > isdataat - cur_chunk - > content_len ;
}
last_chunk = cur_chunk ;
}
SCReturnInt ( 1 ) ;
error :
SCReturnInt ( - 1 ) ;
}
/**
* \ brief Function to setup a content pattern . Patterns that doesn ' t fit the
* current max_pattern_length , are splitted into multiple chunks in independent
* DetectContentData structures with it ' s own modifiers . Each modifier must be
* recalculated for each chunk from the modifiers of the head of the chunk
* group , and will act as independent patterns
*
* \ param de_ctx pointer to the current detection_engine
* \ param s pointer to the current Signature
* \ param m pointer to the last parsed SigMatch
* \ param contentstr pointer to the current keyword content string
* \ retval - 1 if error
* \ retval 0 if all was ok
*/
static int DetectContentSetup ( DetectEngineCtx * de_ctx , Signature * s , char * contentstr )
{
DetectContentData * cd = NULL ;
SigMatch * sm = NULL ;
/* max_pattern_length */
int32_t mpltmp = - 1 ;
uint8_t mpl = 0 ;
uint8_t index = 0 ;
cd = DetectContentParse ( contentstr ) ;
if ( cd = = NULL ) goto error ;
mpltmp = MpmMatcherGetMaxPatternLength ( de_ctx - > mpm_matcher ) ;
if ( mpltmp < 0 )
{
SCLogDebug ( " Unknown Matcher type. Exiting... " ) ;
exit ( EXIT_FAILURE ) ;
}
mpl = mpltmp ;
SCLogDebug ( " Matcher type: % " PRIu16 " max_pattern_length: % " PRIu32 " " , de_ctx - > mpm_matcher , mpl ) ;
/** We are going to assign a chunk group to all the DetectContents, even
* if it ' s not splitted . This will give us the number of loaded patterns
* in this signature */
if ( s ! = NULL ) {
s - > nchunk_groups + + ;
}
/** Check if we need to split the content into chunks */
if ( mpl > 0 & & cd - > content_len > mpl ) {
DetectContentData * aux = NULL ;
SigMatch * first = NULL ;
uint8_t chunk_id = 0 ;
/** Split it from DetectContentSplitChunk() */
for ( index = 0 ; index < cd - > content_len ; index + = mpl )
{
aux = DetectContentSplitChunk ( cd , ( uint8_t ) ( cd - > content_len - index ) , index , mpl ) ;
if ( aux = = NULL ) {
SCLogDebug ( " Couldn't split pattern chunks. Exiting... " ) ;
exit ( EXIT_FAILURE ) ;
}
aux - > flags | = DETECT_CONTENT_IS_CHUNK ;
/** If we load a signature, assing the internal
* chunk_group_id of the sig
*/
if ( s ! = NULL )
{
/** each group of chunks has it's own internal id in the sig */
aux - > chunk_group_id = s - > nchunk_groups ;
/**
* The first chunk will have id = 0
* we need to search for applying the content modifiers
*/
aux - > chunk_id = chunk_id + + ;
}
/** Allocate it as a normal SigMatch */
sm = SigMatchAlloc ( ) ;
if ( sm = = NULL )
goto error ;
sm - > type = DETECT_CONTENT ;
sm - > ctx = ( void * ) aux ;
SigMatchAppendPayload ( s , sm ) ;
aux - > id = DetectContentGetId ( de_ctx , aux ) ;
/** We need to setup the modifiers for the chunks respect
* the last chunk installed inmediatelly before
* so do the propagation from the first one
* The function DetectContentPropagate * Modifier * ( ) should
* be called when a new content modifier is
* parsed / installed
*/
if ( aux - > chunk_id = = 0 )
first = sm ;
DetectContentPropagateModifiers ( first ) ;
DetectContentPrint ( aux ) ;
}
/** Free the original pattern */
DetectContentFree ( cd ) ;
/**
* If we dont need to split it is because the matcher has no length limit
* or the payload fit in the current max pattern length , so no chunks here
*/
} else {
sm = SigMatchAlloc ( ) ;
if ( sm = = NULL )
goto error ;
sm - > type = DETECT_CONTENT ;
sm - > ctx = ( void * ) cd ;
SigMatchAppendPayload ( s , sm ) ;
if ( s ! = NULL ) {
/** each group of chunks has it's own internal id in the sig,
* if the content is not splitted we will assign a chunk group id
* anyway , so we know the real number of detect_content
* patterns loaded */
cd - > chunk_group_id = s - > nchunk_groups ;
}
cd - > id = DetectContentGetId ( de_ctx , cd ) ;
DetectContentPrint ( cd ) ;
}
return 0 ;
error :
if ( cd ! = NULL ) DetectContentFree ( cd ) ;
if ( sm ! = NULL ) SCFree ( sm ) ;
return - 1 ;
}
/**
* \ brief this function will SCFree memory associated with DetectContentData
*
* \ param cd pointer to DetectCotentData
*/
void DetectContentFree ( void * ptr ) {
DetectContentData * cd = ( DetectContentData * ) ptr ;
if ( cd = = NULL )
return ;
if ( cd - > content ! = NULL )
SCFree ( cd - > content ) ;
SCFree ( cd ) ;
}
/* content hash
* A per detection engine hash to make sure each pattern has a unique global id
* but pattern that are the same share id ' s .
*/
typedef struct DetectContentTableElmt_ {
uint8_t * pattern ; /**< ptr to the pattern */
uint16_t pattern_len ; /**< pattern len */
uint32_t id ; /**< pattern id */
} DetectContentTableElmt ;
static char DetectContentTableCompare ( void * p1 , uint16_t len1 , void * p2 , uint16_t len2 ) {
SCEnter ( ) ;
BUG_ON ( len1 < sizeof ( DetectContentTableElmt ) ) ;
BUG_ON ( len2 < sizeof ( DetectContentTableElmt ) ) ;
DetectContentTableElmt * e1 = ( DetectContentTableElmt * ) p1 ;
DetectContentTableElmt * e2 = ( DetectContentTableElmt * ) p2 ;
if ( e1 - > pattern_len ! = e2 - > pattern_len ) {
SCReturnInt ( 0 ) ;
}
if ( memcmp ( e1 - > pattern , e2 - > pattern , e1 - > pattern_len ) ! = 0 ) {
SCReturnInt ( 0 ) ;
}
SCReturnInt ( 1 ) ;
}
static uint32_t DetectContentTableHash ( HashTable * ht , void * p , uint16_t len ) {
SCEnter ( ) ;
BUG_ON ( len < sizeof ( DetectContentTableElmt ) ) ;
DetectContentTableElmt * e = ( DetectContentTableElmt * ) p ;
uint32_t hash = e - > pattern_len ;
uint16_t u = 0 ;
for ( u = 0 ; u < e - > pattern_len ; u + + ) {
hash + = e - > pattern [ u ] ;
}
SCReturnUInt ( hash % ht - > array_size ) ;
}
static void DetectContentTableElmtFree ( void * e ) {
free ( e ) ;
}
int DetectContentTableInitHash ( DetectEngineCtx * de_ctx ) {
SCEnter ( ) ;
BUG_ON ( de_ctx = = NULL ) ;
de_ctx - > content_hash = HashTableInit ( 65536 , DetectContentTableHash , DetectContentTableCompare , DetectContentTableElmtFree ) ;
BUG_ON ( de_ctx - > content_hash = = NULL ) ;
SCReturnInt ( 0 ) ;
}
void DetectContentTableFreeHash ( DetectEngineCtx * de_ctx ) {
SCEnter ( ) ;
if ( de_ctx = = NULL | | de_ctx - > content_hash = = NULL ) {
SCReturn ;
}
HashTableFree ( de_ctx - > content_hash ) ;
SCReturn ;
}
uint32_t DetectContentGetId ( DetectEngineCtx * de_ctx , DetectContentData * co ) {
SCEnter ( ) ;
BUG_ON ( de_ctx = = NULL | | de_ctx - > content_hash = = NULL ) ;
DetectContentTableElmt * e = NULL ;
DetectContentTableElmt * r = NULL ;
uint32_t id = 0 ;
e = malloc ( sizeof ( DetectContentTableElmt ) ) ;
BUG_ON ( e = = NULL ) ;
e - > pattern = co - > content ;
e - > pattern_len = co - > content_len ;
e - > id = 0 ;
r = HashTableLookup ( de_ctx - > content_hash , ( void * ) e , sizeof ( DetectContentTableElmt ) ) ;
if ( r = = NULL ) {
e - > id = de_ctx - > content_max_id ;
de_ctx - > content_max_id + + ;
id = e - > id ;
int ret = HashTableAdd ( de_ctx - > content_hash , e , sizeof ( DetectContentTableElmt ) ) ;
BUG_ON ( ret ! = 0 ) ;
e = NULL ;
de_ctx - > content_hash_unique + + ;
} else {
id = r - > id ;
de_ctx - > content_hash_shared + + ;
}
if ( e ! = NULL )
free ( e ) ;
SCReturnUInt ( id ) ;
}
# ifdef UNITTESTS /* UNITTESTS */
/**
* \ test DetectCotentParseTest01 this is a test to make sure we can deal with escaped colons
*/
int DetectContentParseTest01 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" abc \\ :def \" " ;
char * teststringparsed = " abc:def " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
if ( memcmp ( cd - > content , teststringparsed , strlen ( teststringparsed ) ) ! = 0 ) {
SCLogDebug ( " expected %s got " , teststringparsed ) ;
PrintRawUriFp ( stdout , cd - > content , cd - > content_len ) ;
SCLogDebug ( " : " ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
} else {
SCLogDebug ( " expected %s got NULL: " , teststringparsed ) ;
result = 0 ;
}
return result ;
}
/**
* \ test DetectCotentParseTest02 this is a test to make sure we can deal with escaped semi - colons
*/
int DetectContentParseTest02 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" abc \\ ;def \" " ;
char * teststringparsed = " abc;def " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
if ( memcmp ( cd - > content , teststringparsed , strlen ( teststringparsed ) ) ! = 0 ) {
SCLogDebug ( " expected %s got " , teststringparsed ) ;
PrintRawUriFp ( stdout , cd - > content , cd - > content_len ) ;
SCLogDebug ( " : " ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
} else {
SCLogDebug ( " expected %s got NULL: " , teststringparsed ) ;
result = 0 ;
}
return result ;
}
/**
* \ test DetectCotentParseTest03 this is a test to make sure we can deal with escaped double - quotes
*/
int DetectContentParseTest03 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" abc \\ \" def \" " ;
char * teststringparsed = " abc \" def " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
if ( memcmp ( cd - > content , teststringparsed , strlen ( teststringparsed ) ) ! = 0 ) {
SCLogDebug ( " expected %s got " , teststringparsed ) ;
PrintRawUriFp ( stdout , cd - > content , cd - > content_len ) ;
SCLogDebug ( " : " ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
} else {
SCLogDebug ( " expected %s got NULL: " , teststringparsed ) ;
result = 0 ;
}
return result ;
}
/**
* \ test DetectCotentParseTest04 this is a test to make sure we can deal with escaped backslashes
*/
int DetectContentParseTest04 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" abc \\ \\ def \" " ;
char * teststringparsed = " abc \\ def " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
uint16_t len = ( cd - > content_len > strlen ( teststringparsed ) ) ;
if ( memcmp ( cd - > content , teststringparsed , len ) ! = 0 ) {
SCLogDebug ( " expected %s got " , teststringparsed ) ;
PrintRawUriFp ( stdout , cd - > content , cd - > content_len ) ;
SCLogDebug ( " : " ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
} else {
SCLogDebug ( " expected %s got NULL: " , teststringparsed ) ;
result = 0 ;
}
return result ;
}
/**
* \ test DetectCotentParseTest05 test illegal escape
*/
int DetectContentParseTest05 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" abc \\ def \" " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
SCLogDebug ( " expected NULL got " ) ;
PrintRawUriFp ( stdout , cd - > content , cd - > content_len ) ;
SCLogDebug ( " : " ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
return result ;
}
/**
* \ test DetectCotentParseTest06 test a binary content
*/
int DetectContentParseTest06 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" a|42|c|44|e|46| \" " ;
char * teststringparsed = " abcdef " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
uint16_t len = ( cd - > content_len > strlen ( teststringparsed ) ) ;
if ( memcmp ( cd - > content , teststringparsed , len ) ! = 0 ) {
SCLogDebug ( " expected %s got " , teststringparsed ) ;
PrintRawUriFp ( stdout , cd - > content , cd - > content_len ) ;
SCLogDebug ( " : " ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
} else {
SCLogDebug ( " expected %s got NULL: " , teststringparsed ) ;
result = 0 ;
}
return result ;
}
/**
* \ test DetectCotentParseTest07 test an empty content
*/
int DetectContentParseTest07 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " \" \" " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
SCLogDebug ( " expected NULL got %p: " , cd ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
return result ;
}
/**
* \ test DetectCotentParseTest08 test an empty content
*/
int DetectContentParseTest08 ( void ) {
int result = 1 ;
DetectContentData * cd = NULL ;
char * teststring = " " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
SCLogDebug ( " expected NULL got %p: " , cd ) ;
result = 0 ;
DetectContentFree ( cd ) ;
}
return result ;
}
/**
* \ test DetectCotentParseChunksTest01B2G test split process
*/
int DetectContentChunkTestB2G01 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
/** MPM_B2G is currently 32 bytes word, so the number of chunks
* created should be 0 , since the pattern is 32 bytes and fit in a word */
de_ctx - > mpm_matcher = MPM_B2G ;
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly "
" 32 bytes lentgh \" ; content: \" 12345678901234567890123456789012 \" ; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
if ( de_ctx - > sig_list - > pmatch = = NULL ) {
printf ( " no match in pmatch list: " ) ;
goto end ;
}
m = de_ctx - > sig_list - > pmatch ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & & m - > next = = NULL )
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectCotentParseChunksTest01B3G test split process
*/
int DetectContentChunkTestB3G01 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
/** MPM_B3G is currently 32 bytes word, so the number of chunks
* created should be 0 , since the pattern is 32 bytes and fit in a word */
de_ctx - > mpm_matcher = MPM_B3G ;
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly "
" 32 bytes lentgh \" ; content: \" 12345678901234567890123456789012 \" ; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
if ( de_ctx - > sig_list - > pmatch = = NULL ) {
printf ( " no match in pmatch list: " ) ;
goto end ;
}
m = de_ctx - > sig_list - > pmatch ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & & m - > next = = NULL )
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectCotentParseChunksTestB2G02 test split process
*/
int DetectContentChunkTestB2G02 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
/** MPM_B2G is currently 33 bytes word, so the number of chunks
* created should be 2 , since the pattern is 33 bytes and
* wont fit in a word */
de_ctx - > mpm_matcher = MPM_B2G ;
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly 33 bytes length, so it should be splitted \" ; content: \" 123456789012345678901234567890123 \" ; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
if ( de_ctx - > sig_list - > pmatch = = NULL ) {
printf ( " no match in pmatch list: " ) ;
goto end ;
}
m = de_ctx - > sig_list - > pmatch ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next ! = NULL & & cd - > content_len = = 32 & & cd - > chunk_id = = 0 ) )
goto end ;
m = m - > next ;
if ( m ! = NULL & & m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
if ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next = = NULL & & cd - > content_len = = 1 & & cd - > chunk_id = = 1 )
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectCotentParseChunksTestB3G02 test split proccess
*/
int DetectContentChunkTestB3G02 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
/** MPM_B3G is currently 33 bytes word, so the number of chunks
* created should be 2 , since the pattern is 33 bytes and
* wont fit in a word */
de_ctx - > mpm_matcher = MPM_B3G ;
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly 33 bytes length, so it should be splitted \" ; content: \" 123456789012345678901234567890123 \" ; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL ) {
goto end ;
}
if ( de_ctx - > sig_list - > pmatch = = NULL ) {
goto end ;
}
m = de_ctx - > sig_list - > pmatch ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next ! = NULL & & cd - > content_len = = 32 & & cd - > chunk_id = = 0 ) )
goto end ;
m = m - > next ;
if ( m ! = NULL & & m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
if ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next = = NULL & & cd - > content_len = = 1 & & cd - > chunk_id = = 1 )
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectCotentParseChunksTestB2G03 test split proccess
*/
int DetectContentChunkTestB2G03 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
de_ctx - > mpm_matcher = MPM_B2G ;
/** content_len = 100, so 3 chunks of 32 and the last chunk length == 4 */
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly 100 bytes length, so it should be splitted \" ; content: \" 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 \" ; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL )
goto end ;
if ( de_ctx - > sig_list - > pmatch = = NULL )
goto end ;
m = de_ctx - > sig_list - > pmatch ;
uint8_t chunk_id = 0 ;
do {
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next ! = NULL & & cd - > content_len = = 32 & & cd - > chunk_id = = chunk_id + + ) )
goto end ;
} while ( ( m = m - > next ) & & m ! = NULL & & m - > next ! = NULL ) ;
/** Now let's see if the last Chunk hast the content_len of 4 */
if ( m = = NULL | | m - > next ! = NULL )
goto end ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( cd - > content_len ! = 4 | | cd - > chunk_id ! = chunk_id )
goto end ;
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectCotentParseChunksTestB3G03 test split proccess
*/
int DetectContentChunkTestB3G03 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
de_ctx - > mpm_matcher = MPM_B3G ;
/** content_len = 100, so 3 chunks of 32 and the last chunk length == 4 */
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly 100 bytes length, so it should be splitted \" ; content: \" 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 \" ; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL )
goto end ;
if ( de_ctx - > sig_list - > pmatch = = NULL )
goto end ;
m = de_ctx - > sig_list - > pmatch ;
uint8_t chunk_id = 0 ;
do {
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next ! = NULL & & cd - > content_len = = 32 & & cd - > chunk_id = = chunk_id + + ) )
goto end ;
} while ( ( m = m - > next ) & & m ! = NULL & & m - > next ! = NULL ) ;
/** Now let's see if the last Chunk hast the content_len of 4 */
if ( m = = NULL | | m - > next ! = NULL )
goto end ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( cd - > content_len ! = 4 | | cd - > chunk_id ! = chunk_id )
goto end ;
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectContentChunkTestModifiers01 test modifiers propagation
* given a signature with just one pattern
*/
int DetectContentChunkModifiersTest01 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
de_ctx - > mpm_matcher = MPM_B2G ;
/** content_len = 43, so 1 chunk of length 32 and another chunk of length == 11 */
char * sigstr = " alert tcp any any -> any any (msg: \" This content is exactly 43 bytes length, so it should be splitted \" ; content: \" 1234567890123456789012345678901234567890123 \" ; depth:50; offset:10; isdataat:10, relative; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL )
goto end ;
if ( de_ctx - > sig_list - > pmatch = = NULL )
goto end ;
m = de_ctx - > sig_list - > pmatch ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
SCLogDebug ( " ---DetectContentChunkModifiersTest01--- " ) ;
DetectContentPrintAll ( m ) ;
uint8_t chunk_id = 0 ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next ! = NULL & &
cd - > content_len = = 32 & & cd - > chunk_id = = chunk_id + + ) )
goto end ;
/** Check modifiers for the first chunk */
if ( cd - > offset ! = 10 | | cd - > depth ! = 42 | | cd - > isdataat ! = 21 | |
cd - > within ! = 0 | | cd - > distance ! = 0 ) {
SCLogDebug ( " First Chunk has bad modifiers " ) ;
goto end ;
}
/** Check specified flags (offset and depth have no flags) */
if ( ! ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE ) )
goto end ;
/** Check not specified flags (should not be set
* automatically set for the first chunk ) */
if ( ( cd - > flags & DETECT_CONTENT_WITHIN ) | |
( cd - > flags & DETECT_CONTENT_DISTANCE ) )
goto end ;
/** Now let's see if the last Chunk of this first group has
* the content_len of 11 and the modifiers correctly set */
m = m - > next ;
if ( m = = NULL )
goto end ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) )
goto end ;
if ( cd - > content_len ! = 11 | | cd - > chunk_id ! = chunk_id )
goto end ;
/** Check modifiers for the second chunk */
if ( cd - > offset ! = 42 | | cd - > depth ! = 53 | | cd - > isdataat ! = 10 | |
cd - > within ! = 11 | | cd - > distance ! = 0 ) {
SCLogDebug ( " Second Chunk has bad modifiers " ) ;
goto end ;
}
/** Check specified flags */
if ( ! ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE ) )
goto end ;
/** Check flags, the second chunk should have a distance and depth
* relative to the first chunk , so flags should be automatically set */
if ( ! ( cd - > flags & DETECT_CONTENT_DISTANCE ) | |
! ( cd - > flags & DETECT_CONTENT_WITHIN ) )
goto end ;
/* Great! */
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test DetectContentChunkTestModifiers01 test modifiers propagation
* mixing splitted patterns with non splitted
*/
int DetectContentChunkModifiersTest02 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
Signature * s = NULL ;
SigMatch * m = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
de_ctx - > mpm_matcher = MPM_B2G ;
/** content 1: content_len = 3, so not splitted
* content 2 : content_len = 43 , so 1 chunk of length 32 and another chunk of length = = 11
* content 3 : content_len = 4 , so not splitted
* content 4 : content_len = 43 , so 1 chunk of length 32 and another chunk of length = = 11
*/
char * sigstr = " alert tcp any any -> any any (msg: \" Lot of contents \" ; content: \" GET \" ; depth:3; offset:0; isdataat:43,relative ; content: \" 1234567890123456789012345678901234567890123 \" ; distance: 1; within: 50; depth:50; offset:10; isdataat:10, relative; content: \" HTTP \" ; distance:10; within:20; content: \" 1234567890123456789012345678901234567890123 \" ; distance: 10; within: 50; depth:1000; offset:50; isdataat:20, relative; sid:1;) " ;
s = de_ctx - > sig_list = SigInit ( de_ctx , sigstr ) ;
if ( s = = NULL )
goto end ;
if ( de_ctx - > sig_list - > pmatch = = NULL )
goto end ;
m = de_ctx - > sig_list - > pmatch ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
SCLogDebug ( " ---DetectContentChunkModifiersTest02--- " ) ;
DetectContentPrintAll ( m ) ;
//uint8_t num_chunks = DetectContentCountChunksInGroup(first_sm, chunk_group_id);
/** The first DetectContent should not be splitted */
if ( ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) | | m - > next = = NULL | |
cd - > depth ! = 3 | | cd - > isdataat ! = 43 | | cd - > offset ! = 0 | |
cd - > within ! = 0 | | cd - > distance ! = 0 | | cd - > content_len ! = 3 )
goto end ;
/** First detect content ok, now let's see the first group of chunks */
m = m - > next ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK & & m - > next ! = NULL & &
cd - > content_len = = 32 & & cd - > chunk_id = = 0 ) )
goto end ;
/** Check modifiers for the first chunk */
if ( cd - > offset ! = 10 | | cd - > depth ! = 42 | | cd - > isdataat ! = 21 | |
cd - > within ! = 39 | | cd - > distance ! = 1 ) {
SCLogDebug ( " First Chunk has bad modifiers " ) ;
goto end ;
}
/** Check specified flags (offset and depth have no flags) */
if ( ! ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE ) )
goto end ;
/** Check specified flags relative to the previous DetectContent
* are correctly set for the first chunk ) */
if ( ! ( cd - > flags & DETECT_CONTENT_WITHIN ) | |
! ( cd - > flags & DETECT_CONTENT_DISTANCE ) )
goto end ;
/** Now let's see if the last Chunk of this first group has
* the content_len of 11 and the modifiers correctly set */
m = m - > next ;
if ( m = = NULL )
goto end ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) )
goto end ;
if ( cd - > content_len ! = 11 | | cd - > chunk_id ! = 1 )
goto end ;
/** Check modifiers for the second chunk */
if ( cd - > offset ! = 42 | | cd - > depth ! = 53 | | cd - > isdataat ! = 10 | |
cd - > within ! = 11 | | cd - > distance ! = 0 ) {
SCLogDebug ( " Second Chunk has bad modifiers " ) ;
goto end ;
}
/** Check specified flags */
if ( ! ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE ) )
goto end ;
/** Check flags, the second chunk should have a distance and depth
* relative to the first chunk , so flags should be automatically set */
if ( ! ( cd - > flags & DETECT_CONTENT_DISTANCE ) | |
! ( cd - > flags & DETECT_CONTENT_WITHIN ) )
goto end ;
/** The next DetectContent should not be splitted (pattern "HTTP") */
m = m - > next ;
if ( m = = NULL )
goto end ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
/** Should not be a chunk */
if ( cd - > flags & DETECT_CONTENT_IS_CHUNK )
goto end ;
if ( cd - > content_len ! = 4 )
goto end ;
/** Check modifiers for the second chunk */
if ( cd - > offset ! = 0 | | cd - > depth ! = 0 | | cd - > isdataat ! = 0 | |
cd - > within ! = 20 | | cd - > distance ! = 10 ) {
SCLogDebug ( " Second Chunk has bad modifiers " ) ;
goto end ;
}
/** Check not specified flags */
if ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE )
goto end ;
/** Check specified flags */
if ( ! ( cd - > flags & DETECT_CONTENT_DISTANCE ) | |
! ( cd - > flags & DETECT_CONTENT_WITHIN ) )
goto end ;
/** Ok, now the last group of chunks */
m = m - > next ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) & & m - > next ! = NULL & &
cd - > content_len = = 32 & & cd - > chunk_id = = 0 & &
cd - > chunk_group_id = = 4 ) )
goto end ;
/** Check modifiers for the first chunk */
if ( cd - > offset ! = 50 | | cd - > depth ! = 989 | | cd - > isdataat ! = 31 | |
cd - > within ! = 39 | | cd - > distance ! = 10 ) {
SCLogDebug ( " First Chunk of last group has bad modifiers " ) ;
goto end ;
}
/** Check specified flags (offset and depth have no flags) */
if ( ! ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE ) )
goto end ;
/** Check specified flags relative to the previous DetectContent
* are correctly set for the first chunk ) */
if ( ! ( cd - > flags & DETECT_CONTENT_WITHIN ) | |
! ( cd - > flags & DETECT_CONTENT_DISTANCE ) )
goto end ;
/** Now let's see if the last Chunk of this last group has
* the content_len of 11 and the modifiers correctly set */
m = m - > next ;
if ( m = = NULL )
goto end ;
if ( m - > type = = DETECT_CONTENT & & m - > ctx ! = NULL )
cd = m - > ctx ;
else
goto end ;
if ( ! ( cd - > flags & DETECT_CONTENT_IS_CHUNK ) )
goto end ;
if ( cd - > content_len ! = 11 | | cd - > chunk_id ! = 1 | | cd - > chunk_group_id ! = 4 )
goto end ;
/** Check modifiers for the second chunk */
if ( cd - > offset ! = 82 | | cd - > depth ! = 1000 | | cd - > isdataat ! = 20 | |
cd - > within ! = 11 | | cd - > distance ! = 0 ) {
SCLogDebug ( " Second Chunk of last group has bad modifiers " ) ;
goto end ;
}
/** Check specified flags */
if ( ! ( cd - > flags & DETECT_CONTENT_ISDATAAT_RELATIVE ) )
goto end ;
/** Check flags, the second chunk should have a distance and depth
* relative to the first chunk , so flags should be automatically set */
if ( ! ( cd - > flags & DETECT_CONTENT_DISTANCE ) | |
! ( cd - > flags & DETECT_CONTENT_WITHIN ) )
goto end ;
/** Great!!! */
result = 1 ;
end :
SigCleanSignatures ( de_ctx ) ;
if ( de_ctx ! = NULL )
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
/**
* \ test Test packet Matches
* \ param raw_eth_pkt pointer to the ethernet packet
* \ param pktsize size of the packet
* \ param sig pointer to the signature to test
* \ param sid sid number of the signature
* \ retval return 1 if match
* \ retval return 0 if not
*/
int DetectContentChunkMatchTest ( uint8_t * raw_eth_pkt , uint16_t pktsize , char * sig ,
uint32_t sid )
{
int result = 1 ;
Packet p ;
DecodeThreadVars dtv ;
ThreadVars th_v ;
DetectEngineThreadCtx * det_ctx = NULL ;
memset ( & p , 0 , sizeof ( Packet ) ) ;
memset ( & dtv , 0 , sizeof ( DecodeThreadVars ) ) ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
FlowInitConfig ( FLOW_QUIET ) ;
DecodeEthernet ( & th_v , & dtv , & p , raw_eth_pkt , pktsize , NULL ) ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
result = 0 ;
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
de_ctx - > sig_list = SigInit ( de_ctx , sig ) ;
if ( de_ctx - > sig_list = = NULL ) {
result = 0 ;
goto end ;
}
de_ctx - > sig_list - > next = NULL ;
SCLogDebug ( " ---DetectContentChunkMatchTest--- " ) ;
DetectContentPrintAll ( de_ctx - > sig_list - > match ) ;
SigGroupBuild ( de_ctx ) ;
//PatternMatchPrepare(mpm_ctx, MPM_B2G);
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
SigMatchSignatures ( & th_v , de_ctx , det_ctx , & p ) ;
if ( PacketAlertCheck ( & p , sid ) ! = 1 ) {
result = 0 ;
goto end ;
}
end :
if ( de_ctx ! = NULL )
{
//PatternMatchDestroy(mpm_ctx);
SigGroupCleanup ( de_ctx ) ;
SigCleanSignatures ( de_ctx ) ;
if ( det_ctx ! = NULL )
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
FlowShutdown ( ) ;
return result ;
}
/**
* \ brief Wrapper for DetectContentChunkMatchTest
*/
int DetectContentChunkMatchTestWrp ( char * sig , uint32_t sid ) {
/** Real packet with the following tcp data:
* " Hi, this is a big test to check content matches of splitted "
* " patterns between multiple chunks! "
* ( without quotes ! : ) )
*/
uint8_t raw_eth_pkt [ ] = {
0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x08 , 0x00 , 0x45 , 0x00 ,
0x00 , 0x85 , 0x00 , 0x01 , 0x00 , 0x00 , 0x40 , 0x06 ,
0x7c , 0x70 , 0x7f , 0x00 , 0x00 , 0x01 , 0x7f , 0x00 ,
0x00 , 0x01 , 0x00 , 0x14 , 0x00 , 0x50 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x50 , 0x02 ,
0x20 , 0x00 , 0xc9 , 0xad , 0x00 , 0x00 , 0x48 , 0x69 ,
0x2c , 0x20 , 0x74 , 0x68 , 0x69 , 0x73 , 0x20 , 0x69 ,
0x73 , 0x20 , 0x61 , 0x20 , 0x62 , 0x69 , 0x67 , 0x20 ,
0x74 , 0x65 , 0x73 , 0x74 , 0x20 , 0x74 , 0x6f , 0x20 ,
0x63 , 0x68 , 0x65 , 0x63 , 0x6b , 0x20 , 0x63 , 0x6f ,
0x6e , 0x74 , 0x65 , 0x6e , 0x74 , 0x20 , 0x6d , 0x61 ,
0x74 , 0x63 , 0x68 , 0x65 , 0x73 , 0x20 , 0x6f , 0x66 ,
0x20 , 0x73 , 0x70 , 0x6c , 0x69 , 0x74 , 0x74 , 0x65 ,
0x64 , 0x20 , 0x70 , 0x61 , 0x74 , 0x74 , 0x65 , 0x72 ,
0x6e , 0x73 , 0x20 , 0x62 , 0x65 , 0x74 , 0x77 , 0x65 ,
0x65 , 0x6e , 0x20 , 0x6d , 0x75 , 0x6c , 0x74 , 0x69 ,
0x70 , 0x6c , 0x65 , 0x20 , 0x63 , 0x68 , 0x75 , 0x6e ,
0x6b , 0x73 , 0x21 } ; /* end raw_eth_pkt */
return DetectContentChunkMatchTest ( raw_eth_pkt , ( uint16_t ) sizeof ( raw_eth_pkt ) ,
sig , sid ) ;
}
/**
* \ test Check if we match a normal pattern ( not splitted )
*/
int DetectContentChunkMatchTest01 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is a big test \" ; sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check if we match a splitted pattern
*/
int DetectContentChunkMatchTest02 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is a big test to check content matches of "
" splitted patterns between multiple chunks! \" ; sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check that we don ' t match the signature if one of the splitted
* chunks doesn ' t match the packet
*/
int DetectContentChunkMatchTest03 ( )
{
/** The last chunk of the content should not match */
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is a big test to check content matches of "
" splitted patterns between multiple splitted chunks! \" ; sid:1;) " ;
return ( DetectContentChunkMatchTestWrp ( sig , 1 ) = = 0 ) ? 1 : 0 ;
}
/**
* \ test Check if we match multiple content ( not splitted )
*/
int DetectContentChunkMatchTest04 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is \" ; depth:15 ;content: \" a big test \" ; "
" within:15; content: \" to check content matches of \" ; "
" within:30; content: \" splitted patterns \" ; distance:1; "
" within:30; depth:400; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check that we match packets with multiple chunks and not chunks
* Here we should specify only contents that fit in 32 bytes
* Each of them with their modifier values
*/
int DetectContentChunkMatchTest05 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is a big \" ; depth:17; "
" isdataat:30, relative; "
" content: \" test \" ; within: 5; distance:1; depth:22; "
" isdataat:15, relative; offset:18; "
" content: \" of splitted \" ; within:37; distance:15; "
" depth:60; isdataat:20,relative; offset: 48; "
" content: \" patterns \" ; within:9; distance:1; depth:69; "
" isdataat:10, relative; offset:60; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check that we match packets with multiple chunks and not chunks
* Here we should specify contents that fit and contents that must be splitted
* Each of them with their modifier values
*/
int DetectContentChunkMatchTest06 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is a big test to check cont \" ; depth:36; "
" content: \" ent matches \" ; within:11; distance:0; "
" content: \" of splitted patterns between multiple \" ; "
" within:38; distance:1; offset:47; depth:85; "
" content: \" chunks! \" ; within: 8; distance:1; "
" depth:94; offset: 50; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check if we match contents that are in the payload
* but not in the same order as specified in the signature
*/
int DetectContentChunkMatchTest07 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" chunks! \" ; "
" content: \" content matches \" ; offset:32; depth:47; "
" content: \" of splitted patterns between multiple \" ; "
" content: \" Hi, this is a big \" ; offset:0; depth:17; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check if we match contents that are in the payload
* but not in the same order as specified in the signature
*/
int DetectContentChunkMatchTest08 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" ent matches \" ; "
" content: \" of splitted patterns between multiple \" ; "
" within:38; distance:1; offset:47; depth:85; "
" content: \" chunks! \" ; within: 8; distance:1; "
" depth:94; offset: 50; "
" content: \" Hi, this is a big test to check cont \" ; depth:36; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check if we match contents that are in the payload
* but not in the same order as specified in the signature
*/
int DetectContentChunkMatchTest09 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" ent matches \" ; "
" content: \" of splitted patterns between multiple \" ; "
" within:38; distance:1; offset:47; depth:85; "
" content: \" chunks! \" ; within: 8; distance:1; "
" depth:94; offset: 50; "
" content: \" Hi, this is a big test to chec \" ; depth:36; "
" content: \" k cont \" ; distance:0; within:6; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check if we match two consecutive simple contents
*/
int DetectContentChunkMatchTest10 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" Hi, this is a big test to check \" ; "
" content: \" con \" ; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
/**
* \ test Check if we match two contents of length 1
*/
int DetectContentChunkMatchTest11 ( )
{
char * sig = " alert tcp any any -> any any (msg: \" Nothing.. \" ; "
" content: \" H \" ; "
" content: \" i \" ; "
" sid:1;) " ;
return DetectContentChunkMatchTestWrp ( sig , 1 ) ;
}
int DetectContentParseTest09 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " !boo " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 1 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseTest10 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " ! \" boo \" " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 1 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseNegTest11 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " boo " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 0 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseNegTest12 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " \" boo \" " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 0 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseNegTest13 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " ! \" boo \" " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 1 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseNegTest14 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " \" !boo \" " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 0 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseNegTest15 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " !boo " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > negated = = 1 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
int DetectContentParseNegTest16 ( void ) {
int result = 0 ;
DetectContentData * cd = NULL ;
char * teststring = " boo " ;
cd = DetectContentParse ( teststring ) ;
if ( cd ! = NULL ) {
result = ( cd - > content_len = = 3 & & memcmp ( cd - > content , " boo " , 3 ) = = 0 ) ;
DetectContentFree ( cd ) ;
}
return result ;
}
static int SigTestPositiveTestContent ( char * rule , uint8_t * buf )
{
uint16_t buflen = strlen ( ( char * ) buf ) ;
Packet p ;
ThreadVars th_v ;
DetectEngineThreadCtx * det_ctx ;
int result = 0 ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & p , 0 , sizeof ( p ) ) ;
p . src . family = AF_INET ;
p . dst . family = AF_INET ;
p . payload = buf ;
p . payload_len = buflen ;
p . proto = IPPROTO_TCP ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
de_ctx - > flags | = DE_QUIET ;
de_ctx - > sig_list = SigInit ( de_ctx , rule ) ;
if ( de_ctx - > sig_list = = NULL ) {
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
SigMatchSignatures ( & th_v , de_ctx , det_ctx , & p ) ;
if ( PacketAlertCheck ( & p , 1 ) ! = 1 ) {
goto end ;
}
result = 1 ;
end :
SigGroupCleanup ( de_ctx ) ;
SigCleanSignatures ( de_ctx ) ;
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
return result ;
}
static int SigTestNegativeTestContent ( char * rule , uint8_t * buf )
{
uint16_t buflen = strlen ( ( char * ) buf ) ;
Packet p ;
ThreadVars th_v ;
DetectEngineThreadCtx * det_ctx = NULL ;
int result = 0 ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & p , 0 , sizeof ( p ) ) ;
p . src . family = AF_INET ;
p . dst . family = AF_INET ;
p . payload = buf ;
p . payload_len = buflen ;
p . proto = IPPROTO_TCP ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL )
goto end ;
de_ctx - > flags | = DE_QUIET ;
de_ctx - > sig_list = SigInit ( de_ctx , rule ) ;
if ( de_ctx - > sig_list = = NULL ) {
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
SigMatchSignatures ( & th_v , de_ctx , det_ctx , & p ) ;
if ( PacketAlertCheck ( & p , 1 ) ! = 0 ) {
goto end ;
}
result = 1 ;
end :
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
SigCleanSignatures ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
return result ;
}
/**
* \ test A positive test that checks that the content string doesn ' t contain
* the negated content
*/
static int SigTest41TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:!GES; sid:1;) " , ( uint8_t * ) " GET /one/ HTTP/1.1 \r \n Host: one.example.org \r \n \r \n \r \n GET /two/ HTTP/1.1 \r \n Host: two.example.org \r \n \r \n \r \n " ) ;
}
/**
* \ test A positive test that checks that the content string doesn ' t contain
* the negated content within the specified depth
*/
static int SigTest42TestNegatedContent ( void )
{ // 01 5 10 15 20 24
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:!twentythree; depth:22; offset:35; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that checks that the content string doesn ' t contain
* the negated content within the specified depth , and also after the
* specified offset . Since the content is there , the match fails .
*
* Match is at offset : 23 , depth : 34
*/
static int SigTest43TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:!twentythree; depth:34; offset:23; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that checks that the content string doesn ' t contain
* the negated content after the specified offset and within the specified
* depth .
*/
static int SigTest44TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:!twentythree; offset:40; depth:35; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A positive test that uses a combination of content string with negated
* content string
*/
static int SigTest45TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; depth:5; content:!twentythree; depth:23; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that uses a combination of content string with negated
* content string , with we receiving a failure for ' onee ' itself .
*/
static int SigTest46TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:onee; content:!twentythree; depth:23; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that uses a combination of content string with negated
* content string , with we receiving a failure of first content ' s offset
* condition
*/
static int SigTest47TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; offset:5; content:!twentythree; depth:23; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A positive test that checks that we don ' t have a negated content within
* the specified length from the previous content match .
*/
static int SigTest48TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:GET; content:!GES; within:26; sid:1;) " , ( uint8_t * ) " GET /one/ HTTP/1.1 \r \n Host: one.example.org \r \n \r \n \r \n GET /two/ HTTP/1.1 \r \n Host: two.example.org \r \n \r \n \r \n " ) ;
}
/**
* \ test A negative test that checks the combined use of content and negated
* content with the use of within
*/
static int SigTest49TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:GET; content:!Host; within:26; sid:1;) " , ( uint8_t * ) " GET /one/ HTTP/1.1 \r \n Host: one.example.org \r \n \r \n \r \n GET /two/ HTTP/1.1 \r \n Host: two.example.org \r \n \r \n \r \n " ) ;
}
/**
* \ test A positive test that checks the combined use of content and negated
* content with the use of distance
*/
static int SigTest50TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:GET; content:!GES; distance:25; sid:1;) " , ( uint8_t * ) " GET /one/ HTTP/1.1 \r \n Host: one.example.org \r \n \r \n \r \n GET /two/ HTTP/1.1 \r \n Host: two.example.org \r \n \r \n \r \n " ) ;
}
/**
* \ test A negative test that checks the combined use of content and negated
* content with the use of distance
*/
static int SigTest51TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:GET; content:!Host; distance:18; sid:1;) " , ( uint8_t * ) " GET /one/ HTTP/1.1 \r \n Host: one.example.org \r \n \r \n \r \n GET /two/ HTTP/1.1 \r \n Host: two.example.org \r \n \r \n \r \n " ) ;
}
/**
* \ test A negative test that checks the combined use of content and negated
* content , with the content not being present
*/
static int SigTest52TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:GES; content:!BOO; sid:1;) " , ( uint8_t * ) " GET /one/ HTTP/1.1 \r \n Host: one.example.org \r \n \r \n \r \n GET /two/ HTTP/1.1 \r \n Host: two.example.org \r \n \r \n \r \n " ) ;
}
/**
* \ test A negative test that checks the combined use of content and negated
* content , in the presence of within
*/
static int SigTest53TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; content:!fourty; within:56; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A positive test that checks the combined use of content and negated
* content , in the presence of within
*/
static int SigTest54TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; content:!fourty; within:20; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that checks the use of negated content along with
* the presence of depth
*/
static int SigTest55TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:!one; depth:5; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A positive test that checks the combined use of 2 contents in the
* presence of within
*/
static int SigTest56TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; content:fourty; within:56; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that checks the combined use of content and negated
* content , in the presence of within
*/
static int SigTest57TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; content:!fourty; within:56; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A positive test that checks the combined use of content and negated
* content , in the presence of distance
*/
static int SigTest58TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; content:!fourty; distance:57; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/**
* \ test A negative test that checks the combined use of content and negated
* content , in the presence of distance
*/
static int SigTest59TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; content:!fourty; distance:30; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest60TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:!one; content:fourty; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest61TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:!fourty; within:30; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/** \test Test negation in combination with within and depth
*
* Match of " one " at offset : 0 , depth : 3
* Match of " fourty " at offset : 46 , depth : 52
*
* This signature should not match for the test to pass .
*/
static int SigTest62TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:!fourty; within:49; depth:52; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest63TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; depth:10; content:!fourty; within:56; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest64TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:!fourty; within:30; depth:30; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/** \test Test negation in combination with within and depth
*
* Match of " one " at offset : 0 , depth : 3
* Match of " fourty " at offset : 46 , depth : 52
*
* This signature should not match for the test to pass .
*/
static int SigTest65TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:!fourty; distance:0; within:49; offset:46; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest66TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:!fourty; within:30; offset:56; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest67TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:!four; within:56; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest68TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:nine; offset:8; content:!fourty; within:28; content:fiftysix; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest69TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; depth:10; content:nine; offset:8; content:!fourty; within:48; content:fiftysix; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest70TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; content:!fourty; within:52; distance:45 sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
/** \test within and distance */
static int SigTest71TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; content:!fourty; within:40; distance:43; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest72TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (content:one; content:!fourty; within:49; distance:43; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest73TestNegatedContent ( void )
{
return SigTestNegativeTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content:one; depth:5; content:!twentythree; depth:35; sid:1;) " , ( uint8_t * ) " one four nine fourteen twentythree thirtyfive fourtysix fiftysix " ) ;
}
static int SigTest74TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content: \" USER \" ; content:! \" PASS \" ; sid:1;) " , ( uint8_t * ) " USER apple " ) ;
}
static int SigTest75TestNegatedContent ( void )
{
return SigTestPositiveTestContent ( " alert tcp any any -> any any (msg: \" HTTP URI cap \" ; content: \" USER \" ; content: \" !PASS \" ; sid:1;) " , ( uint8_t * ) " USER !PASS " ) ;
}
# endif /* UNITTESTS */
/**
* \ brief this function registers unit tests for DetectContent
*/
void DetectContentRegisterTests ( void )
{
# ifdef UNITTESTS /* UNITTESTS */
UtRegisterTest ( " DetectContentParseTest01 " , DetectContentParseTest01 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest02 " , DetectContentParseTest02 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest03 " , DetectContentParseTest03 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest04 " , DetectContentParseTest04 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest05 " , DetectContentParseTest05 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest06 " , DetectContentParseTest06 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest07 " , DetectContentParseTest07 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest08 " , DetectContentParseTest08 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest09 " , DetectContentParseTest09 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest10 " , DetectContentParseTest10 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest11 " , DetectContentParseNegTest11 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest12 " , DetectContentParseNegTest12 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest13 " , DetectContentParseNegTest13 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest14 " , DetectContentParseNegTest14 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest15 " , DetectContentParseNegTest15 , 1 ) ;
UtRegisterTest ( " DetectContentParseTest16 " , DetectContentParseNegTest16 , 1 ) ;
UtRegisterTest ( " DetectContentChunkTestB2G01 l=32 " , DetectContentChunkTestB2G01 , 1 ) ;
UtRegisterTest ( " DetectContentChunkTestB3G01 l=32 " , DetectContentChunkTestB3G01 , 1 ) ;
UtRegisterTest ( " DetectContentChunkTestB2G02 l=33 " , DetectContentChunkTestB2G02 , 1 ) ;
UtRegisterTest ( " DetectContentChunkTestB3G02 l=33 " , DetectContentChunkTestB3G02 , 1 ) ;
UtRegisterTest ( " DetectContentChunkTestB2G03 l=100 " , DetectContentChunkTestB2G03 , 1 ) ;
UtRegisterTest ( " DetectContentChunkTestB3G03 l=100 " , DetectContentChunkTestB3G03 , 1 ) ;
UtRegisterTest ( " DetectContentChunkModifiersTest01 " , DetectContentChunkModifiersTest01 , 1 ) ;
UtRegisterTest ( " DetectContentChunkModifiersTest02 " , DetectContentChunkModifiersTest02 , 1 ) ;
/* The reals */
UtRegisterTest ( " DetectContentChunkMatchTest01 " , DetectContentChunkMatchTest01 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest02 " , DetectContentChunkMatchTest02 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest03 " , DetectContentChunkMatchTest03 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest04 " , DetectContentChunkMatchTest04 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest05 " , DetectContentChunkMatchTest05 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest06 " , DetectContentChunkMatchTest06 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest07 " , DetectContentChunkMatchTest07 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest08 " , DetectContentChunkMatchTest08 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest09 " , DetectContentChunkMatchTest09 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest10 " , DetectContentChunkMatchTest10 , 1 ) ;
UtRegisterTest ( " DetectContentChunkMatchTest11 " , DetectContentChunkMatchTest11 , 1 ) ;
/* Negated content tests */
UtRegisterTest ( " SigTest41TestNegatedContent " , SigTest41TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest42TestNegatedContent " , SigTest42TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest43TestNegatedContent " , SigTest43TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest44TestNegatedContent " , SigTest44TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest45TestNegatedContent " , SigTest45TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest46TestNegatedContent " , SigTest46TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest47TestNegatedContent " , SigTest47TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest48TestNegatedContent " , SigTest48TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest49TestNegatedContent " , SigTest49TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest50TestNegatedContent " , SigTest50TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest51TestNegatedContent " , SigTest51TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest52TestNegatedContent " , SigTest52TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest53TestNegatedContent " , SigTest53TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest54TestNegatedContent " , SigTest54TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest55TestNegatedContent " , SigTest55TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest56TestNegatedContent " , SigTest56TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest57TestNegatedContent " , SigTest57TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest58TestNegatedContent " , SigTest58TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest59TestNegatedContent " , SigTest59TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest60TestNegatedContent " , SigTest60TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest61TestNegatedContent " , SigTest61TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest62TestNegatedContent " , SigTest62TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest63TestNegatedContent " , SigTest63TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest64TestNegatedContent " , SigTest64TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest65TestNegatedContent " , SigTest65TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest66TestNegatedContent " , SigTest66TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest67TestNegatedContent " , SigTest67TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest68TestNegatedContent " , SigTest68TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest69TestNegatedContent " , SigTest69TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest70TestNegatedContent " , SigTest70TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest71TestNegatedContent " , SigTest71TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest72TestNegatedContent " , SigTest72TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest73TestNegatedContent " , SigTest73TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest74TestNegatedContent " , SigTest74TestNegatedContent , 1 ) ;
UtRegisterTest ( " SigTest75TestNegatedContent " , SigTest75TestNegatedContent , 1 ) ;
# endif /* UNITTESTS */
}