/* Copyright (C) 2007-2011 Open Information Security Foundation
*
* You can copy , redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA .
*/
/**
* \ defgroup sigstate State support
*
* It is possible to do matching on reconstructed applicative flow .
* This is done by this code . It uses the : : Flow structure to store
* the list of signatures to match on the reconstructed stream .
*
* The Flow : : de_state is a : : DetectEngineState structure . This is
* basically a containter for storage item of type : : DeStateStore .
* They contains an array of : : DeStateStoreItem which store the
* state of match for an individual signature identified by
* DeStateStoreItem : : sid .
*
* The state is constructed by DeStateDetectStartDetection ( ) which
* also starts the matching . Work is continued by
* DeStateDetectContinueDetection ( ) .
*
* Once a transaction has been analysed DeStateRestartDetection ( )
* is used to reset the structures .
*
* @ {
*/
/**
* \ file
*
* \ author Victor Julien < victor @ inliniac . net >
*
* \ brief State based signature handling
*
*/
# include "suricata-common.h"
# include "decode.h"
# include "detect.h"
# include "detect-engine.h"
# include "detect-parse.h"
# include "detect-engine-state.h"
# include "detect-engine-uri.h"
# include "detect-engine-hcbd.h"
# include "detect-engine-hsbd.h"
# include "detect-engine-hhd.h"
# include "detect-engine-hrhd.h"
# include "detect-engine-hmd.h"
# include "detect-engine-hcd.h"
# include "detect-engine-hrud.h"
# include "detect-engine-dcepayload.h"
# include "detect-engine-file.h"
# include "stream-tcp.h"
# include "stream-tcp-private.h"
# include "stream-tcp-reassemble.h"
# include "app-layer-parser.h"
# include "app-layer-protos.h"
# include "app-layer-htp.h"
# include "app-layer-smb.h"
# include "app-layer-dcerpc-common.h"
# include "app-layer-dcerpc.h"
# include "util-unittest.h"
# include "util-unittest-helper.h"
# include "util-profiling.h"
/** convert enum to string */
# define CASE_CODE(E) case E: return #E
/* prototype */
static void DeStateResetFileInspection ( Flow * f , uint16_t alproto , void * alstate ) ;
int DeStateStoreFilestoreSigsCantMatch ( SigGroupHead * sgh ,
DetectEngineState * de_state , uint8_t direction )
{
if ( direction & STREAM_TOSERVER ) {
if ( de_state - > toserver_filestore_cnt = = sgh - > filestore_cnt ) {
SCReturnInt ( 1 ) ;
}
} else if ( direction & STREAM_TOCLIENT ) {
if ( de_state - > toclient_filestore_cnt = = sgh - > filestore_cnt ) {
SCReturnInt ( 1 ) ;
}
}
SCReturnInt ( 0 ) ;
}
/** \brief get string for match enum */
const char * DeStateMatchResultToString ( DeStateMatchResult res )
{
switch ( res ) {
CASE_CODE ( DE_STATE_MATCH_NOSTATE ) ;
CASE_CODE ( DE_STATE_MATCH_FULL ) ;
CASE_CODE ( DE_STATE_MATCH_PARTIAL ) ;
CASE_CODE ( DE_STATE_MATCH_NEW ) ;
CASE_CODE ( DE_STATE_MATCH_NOMATCH ) ;
}
return NULL ;
}
/**
* \ brief Alloc a DeStateStore object
* \ retval d alloc ' d object
*/
DeStateStore * DeStateStoreAlloc ( void ) {
SCEnter ( ) ;
DeStateStore * d = SCMalloc ( sizeof ( DeStateStore ) ) ;
if ( d = = NULL ) {
SCReturnPtr ( NULL , " DeStateStore " ) ;
}
memset ( d , 0x00 , sizeof ( DeStateStore ) ) ;
SCReturnPtr ( d , " DeStateStore " ) ;
}
/**
* \ brief free a DeStateStore object ( recursively )
* \ param store DeStateStore object to free
*/
void DeStateStoreFree ( DeStateStore * store ) {
SCEnter ( ) ;
if ( store = = NULL ) {
SCReturn ;
}
if ( store - > next ! = NULL ) {
DeStateStoreFree ( store - > next ) ;
}
SCFree ( store ) ;
SCReturn ;
}
/**
* \ brief Alloc a DetectEngineState object
* \ param d alloc ' d object
*/
DetectEngineState * DetectEngineStateAlloc ( void ) {
SCEnter ( ) ;
DetectEngineState * d = SCMalloc ( sizeof ( DetectEngineState ) ) ;
if ( d = = NULL ) {
SCReturnPtr ( NULL , " DetectEngineState " ) ;
}
memset ( d , 0x00 , sizeof ( DetectEngineState ) ) ;
SCReturnPtr ( d , " DetectEngineState " ) ;
}
/**
* \ brief Free a DetectEngineState object
* You must lock the flow mutex for de_state
* ( f - > de_state_m )
* \ param state DetectEngineState object to free
*/
void DetectEngineStateFree ( DetectEngineState * state ) {
DeStateStore * iter = NULL ;
DeStateStore * aux = NULL ;
if ( state = = NULL )
return ;
iter = state - > head ;
while ( iter ! = NULL ) {
aux = iter ;
iter = iter - > next ;
SCFree ( aux ) ;
}
state - > head = NULL ;
state - > tail = NULL ;
state - > cnt = 0 ;
SCFree ( state ) ;
}
/**
* \ brief reset a DetectEngineState state
* \ param state LOCKED state
*/
void DetectEngineStateReset ( DetectEngineState * state ) {
SCEnter ( ) ;
DeStateStore * iter = NULL ;
DeStateStore * aux = NULL ;
if ( state = = NULL )
return ;
iter = state - > head ;
while ( iter ! = NULL ) {
aux = iter ;
iter = iter - > next ;
SCFree ( aux ) ;
}
state - > head = NULL ;
state - > tail = NULL ;
state - > cnt = 0 ;
SCReturn ;
}
/**
* \ brief update the transaction id
*
* \ param f unlocked flow
* \ param direction STREAM_TOCLIENT / STREAM_TOSERVER
*
* \ retval 2 current transaction done , new available
* \ retval 1 current transaction done , no new ( yet )
* \ retval 0 current transaction is not done yet
*/
int DeStateUpdateInspectTransactionId ( Flow * f , char direction ) {
SCEnter ( ) ;
int r = 0 ;
SCMutexLock ( & f - > m ) ;
r = AppLayerTransactionUpdateInspectId ( f , direction ) ;
SCMutexUnlock ( & f - > m ) ;
SCReturnInt ( r ) ;
}
/**
* \ brief Append a signature to the detect engine state
*
* \ param state the detect engine state
* \ param s signature
* \ param sm sigmatch
* \ param uri did uri already match ( if any )
* \ param dce did dce already match ( if any )
* \ param hcbd did http client body already match ( if any )
*
* \ todo Need to use an array to transfer all these args . Pushing so
* many args is slow .
*/
static void DeStateSignatureAppend ( DetectEngineState * state , Signature * s ,
SigMatch * sm , uint16_t match_flags ) {
DeStateStore * store = state - > tail ;
if ( store = = NULL ) {
store = DeStateStoreAlloc ( ) ;
if ( store ! = NULL ) {
state - > head = store ;
state - > tail = store ;
}
} else {
if ( ( state - > cnt % DE_STATE_CHUNK_SIZE ) = = 0 ) {
store = DeStateStoreAlloc ( ) ;
if ( store ! = NULL ) {
state - > tail - > next = store ;
state - > tail = store ;
}
}
}
if ( store = = NULL ) {
return ;
}
SigIntId idx = state - > cnt % DE_STATE_CHUNK_SIZE ;
store - > store [ idx ] . sid = s - > num ;
store - > store [ idx ] . flags = 0 ;
store - > store [ idx ] . flags | = match_flags ;
store - > store [ idx ] . nm = sm ;
state - > cnt + + ;
SCLogDebug ( " store %p idx % " PRIuMAX " cnt % " PRIuMAX " sig id % " PRIuMAX " " ,
store , ( uintmax_t ) idx , ( uintmax_t ) state - > cnt ,
( uintmax_t ) store - > store [ idx ] . sid ) ;
return ;
}
/*
on first detection run :
for each
( 1 ) app layer signature
( 2 a ) at least one app layer sm match OR
( 2 b ) content / uri match AND other app layer sigmatches present
Cases :
multiple app layer sm ' s
content + uricontent
content + app layer sm
uricontent + app layer sm
*/
uint16_t DeStateGetStateVersion ( DetectEngineState * de_state , uint8_t direction ) {
if ( direction & STREAM_TOSERVER ) {
SCReturnUInt ( de_state - > toserver_version ) ;
} else {
SCReturnUInt ( de_state - > toclient_version ) ;
}
}
void DeStateStoreStateVersion ( DetectEngineState * de_state , uint8_t direction ,
uint16_t alversion )
{
if ( direction & STREAM_TOSERVER ) {
SCLogDebug ( " STREAM_TOSERVER updated to % " PRIu16 , alversion ) ;
de_state - > toserver_version = alversion ;
} else {
SCLogDebug ( " STREAM_TOCLIENT updated to % " PRIu16 , alversion ) ;
de_state - > toclient_version = alversion ;
}
}
/**
* \ brief Increment de_state filestore_cnt in the proper direction .
*
* \ param de_state flow ' s locked de_state
* \ param direction flags containing direction
* \ param file_no_match number of sigs that are identified as " can't match "
* with filestore .
*/
void DeStateStoreFileNoMatch ( DetectEngineState * de_state , uint8_t direction ,
uint16_t file_no_match )
{
if ( direction & STREAM_TOSERVER ) {
SCLogDebug ( " STREAM_TOSERVER added % " PRIu16 , file_no_match ) ;
de_state - > toserver_filestore_cnt + = file_no_match ;
} else {
SCLogDebug ( " STREAM_TOCLIENT added % " PRIu16 , file_no_match ) ;
de_state - > toclient_filestore_cnt + = file_no_match ;
}
}
/**
* \ brief Check if a flow already contains a flow detect state
*
* \ retval 2 has state , but it ' s not updated
* \ retval 1 has state
* \ retval 0 has no state
*/
int DeStateFlowHasState ( Flow * f , uint8_t flags , uint16_t alversion ) {
SCEnter ( ) ;
int r = 0 ;
SCMutexLock ( & f - > de_state_m ) ;
if ( f - > de_state = = NULL | | f - > de_state - > cnt = = 0 ) {
r = 0 ;
} else if ( DeStateGetStateVersion ( f - > de_state , flags ) = = alversion )
r = 2 ;
else
r = 1 ;
SCMutexUnlock ( & f - > de_state_m ) ;
SCReturnInt ( r ) ;
}
/** \brief Match app layer sig list against state. Set up state for non matches
* and partial matches .
* \ retval 1 match
* \ retval 0 no or partial match
*/
int DeStateDetectStartDetection ( ThreadVars * tv , DetectEngineCtx * de_ctx ,
DetectEngineThreadCtx * det_ctx , Signature * s , Flow * f , uint8_t flags ,
void * alstate , uint16_t alproto , uint16_t alversion )
{
SCEnter ( ) ;
SigMatch * sm = s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ;
int match = 0 ;
int r = 0 ;
uint16_t inspect_flags = 0 ;
uint16_t match_flags = 0 ;
uint16_t file_no_match = 0 ;
if ( alstate = = NULL ) {
SCReturnInt ( 0 ) ;
}
SCLogDebug ( " s->id % " PRIu32 , s - > id ) ;
/* Check the uricontent, http client body, http header keywords here */
if ( alproto = = ALPROTO_HTTP ) {
if ( flags & STREAM_TOSERVER ) {
if ( s - > sm_lists [ DETECT_SM_LIST_UMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_URI_INSPECT ;
SCLogDebug ( " inspecting uri " ) ;
if ( DetectEngineInspectPacketUris ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 )
{
SCLogDebug ( " uri matched " ) ;
match_flags | = DE_STATE_FLAG_URI_MATCH ;
} else {
SCLogDebug ( " uri inspected but no match " ) ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCBDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HCBD_INSPECT ;
if ( DetectEngineInspectHttpClientBody ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HCBD_MATCH ;
}
SCLogDebug ( " inspecting http client body " ) ;
}
/* not inspecting in toserver direction */
if ( s - > sm_lists [ DETECT_SM_LIST_HSBDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HSBD_INSPECT ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HHDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HHD_INSPECT ;
if ( DetectEngineInspectHttpHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HHD_MATCH ;
}
SCLogDebug ( " inspecting http header " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRHDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HRHD_INSPECT ;
if ( DetectEngineInspectHttpRawHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HRHD_MATCH ;
}
SCLogDebug ( " inspecting http raw header " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HMDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HMD_INSPECT ;
if ( DetectEngineInspectHttpMethod ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HMD_MATCH ;
}
SCLogDebug ( " inspecting http method " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HCD_INSPECT ;
if ( DetectEngineInspectHttpCookie ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HCD_MATCH ;
}
SCLogDebug ( " inspecting http cookie " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRUDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HRUD_INSPECT ;
if ( DetectEngineInspectHttpRawUri ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HRUD_MATCH ;
}
SCLogDebug ( " inspecting http raw uri " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_FILEMATCH ] ! = NULL ) {
SCLogDebug ( " file inspection " ) ;
if ( match_flags = = inspect_flags ) {
SCLogDebug ( " ready to inspect files " ) ;
inspect_flags | = DE_STATE_FLAG_FILE_TS_INSPECT ;
match = DetectFileInspectHttp ( tv , det_ctx , f , s , alstate , flags ) ;
if ( match = = 1 ) {
match_flags | = DE_STATE_FLAG_FILE_TS_MATCH ;
} else if ( match = = 2 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
} else if ( match = = 3 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
file_no_match + + ;
}
} else {
SCLogDebug ( " skipping file inspection as we're not yet done with the other inspection " ) ;
}
}
} else if ( flags & STREAM_TOCLIENT ) {
/* For to client set the flags in inspect so it can't match
* if the sig requires something only the request has . The rest
* will be inspected in the opposite direction . */
if ( s - > sm_lists [ DETECT_SM_LIST_UMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_URI_INSPECT ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCBDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HCBD_INSPECT ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HSBDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HSBD_INSPECT ;
if ( DetectEngineInspectHttpServerBody ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HSBD_MATCH ;
}
SCLogDebug ( " inspecting http server body " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HHDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HHD_INSPECT ;
if ( DetectEngineInspectHttpHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HHD_MATCH ;
}
SCLogDebug ( " inspecting http header " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRHDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HRHD_INSPECT ;
if ( DetectEngineInspectHttpRawHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HRHD_MATCH ;
}
SCLogDebug ( " inspecting http raw header " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HMDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HMD_INSPECT ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HCD_INSPECT ;
if ( DetectEngineInspectHttpCookie ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HCD_MATCH ;
}
SCLogDebug ( " inspecting http cookie " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRUDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HRUD_INSPECT ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_FILEMATCH ] ! = NULL ) {
SCLogDebug ( " file inspection " ) ;
if ( match_flags = = inspect_flags ) {
SCLogDebug ( " ready to inspect files " ) ;
inspect_flags | = DE_STATE_FLAG_FILE_TC_INSPECT ;
match = DetectFileInspectHttp ( tv , det_ctx , f , s , alstate , flags ) ;
SCLogDebug ( " match %d " , match ) ;
if ( match = = 1 ) {
match_flags | = DE_STATE_FLAG_FILE_TC_MATCH ;
} else if ( match = = 2 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
} else if ( match = = 3 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
file_no_match + + ;
}
} else {
SCLogDebug ( " skipping file inspection as we're not yet done with the other inspection " ) ;
}
}
}
} else if ( alproto = = ALPROTO_DCERPC | | alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
if ( s - > sm_lists [ DETECT_SM_LIST_DMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_DCE_INSPECT ;
SCLogDebug ( " inspecting dce payload " ) ;
if ( alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
SMBState * smb_state = ( SMBState * ) alstate ;
if ( smb_state - > dcerpc_present & &
DetectEngineInspectDcePayload ( de_ctx , det_ctx , s , f ,
flags , & smb_state - > dcerpc ) = = 1 ) {
SCLogDebug ( " dce payload matched " ) ;
match_flags | = DE_STATE_FLAG_DCE_MATCH ;
} else {
SCLogDebug ( " dce payload inspected but no match " ) ;
}
} else {
if ( DetectEngineInspectDcePayload ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " dce payload matched " ) ;
match_flags | = DE_STATE_FLAG_DCE_MATCH ;
} else {
SCLogDebug ( " dce payload inspected but no match " ) ;
}
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ! = NULL ) {
for ( ; sm ! = NULL ; sm = sm - > next ) {
SCLogDebug ( " sm %p, sm->next %p " , sm , sm - > next ) ;
if ( sigmatch_table [ sm - > type ] . AppLayerMatch ! = NULL & &
( alproto = = s - > alproto | |
alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) )
{
if ( alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
SMBState * smb_state = ( SMBState * ) alstate ;
if ( smb_state - > dcerpc_present ) {
match = sigmatch_table [ sm - > type ] .
AppLayerMatch ( tv , det_ctx , f , flags , & smb_state - > dcerpc ,
s , sm ) ;
}
} else {
match = sigmatch_table [ sm - > type ] .
AppLayerMatch ( tv , det_ctx , f , flags , alstate , s , sm ) ;
}
if ( match = = 0 ) {
break ;
} else if ( sm - > next = = NULL ) {
sm = NULL ; /* set to NULL as we have a match */
if ( inspect_flags = = 0 | | ( inspect_flags = = match_flags ) ) {
r = 1 ;
}
break ;
}
}
}
} else {
if ( inspect_flags ! = 0 & & ( inspect_flags = = match_flags ) ) {
match_flags | = DE_STATE_FLAG_FULL_MATCH ;
r = 1 ;
}
}
SCLogDebug ( " detection done, store results: sm %p, inspect_flags %04X, "
" match_flags %04X " , sm , inspect_flags , match_flags ) ;
SCMutexLock ( & f - > de_state_m ) ;
/* match or no match, we store the state anyway
* " sm " here is either NULL ( complete match ) or
* the last SigMatch that didn ' t match */
if ( f - > de_state = = NULL ) {
f - > de_state = DetectEngineStateAlloc ( ) ;
}
if ( f - > de_state ! = NULL ) {
/* \todo shift to an array to transfer these match values*/
DeStateSignatureAppend ( f - > de_state , s , sm , match_flags ) ;
DeStateStoreStateVersion ( f - > de_state , flags , alversion ) ;
DeStateStoreFileNoMatch ( f - > de_state , flags , file_no_match ) ;
if ( DeStateStoreFilestoreSigsCantMatch ( det_ctx - > sgh , f - > de_state , flags ) = = 1 ) {
SCLogDebug ( " disabling file storage for transaction %u " , det_ctx - > tx_id ) ;
FileDisableStoringForTransaction ( f , flags & ( STREAM_TOCLIENT | STREAM_TOSERVER ) ,
det_ctx - > tx_id ) ;
f - > de_state - > flags | = DE_STATE_FILE_STORE_DISABLED ;
}
}
SCMutexUnlock ( & f - > de_state_m ) ;
SCReturnInt ( r ) ;
}
/** \brief Continue DeState detection of the signatures stored in the state.
*
* \ retval 0 all is good
*/
int DeStateDetectContinueDetection ( ThreadVars * tv , DetectEngineCtx * de_ctx , DetectEngineThreadCtx * det_ctx ,
Flow * f , uint8_t flags , void * alstate , uint16_t alproto , uint16_t alversion )
{
SCEnter ( ) ;
SigIntId cnt = 0 ;
SigIntId store_cnt = 0 ;
DeStateStore * store = NULL ;
uint16_t inspect_flags = 0 ;
uint16_t match_flags = 0 ;
int match = 0 ;
uint16_t file_no_match = 0 ;
if ( f = = NULL | | alstate = = NULL | | alproto = = ALPROTO_UNKNOWN ) {
return 0 ;
}
SCMutexLock ( & f - > de_state_m ) ;
if ( f - > de_state = = NULL | | f - > de_state - > cnt = = 0 )
goto end ;
DeStateResetFileInspection ( f , alproto , alstate ) ;
/* loop through the stores */
for ( store = f - > de_state - > head ; store ! = NULL ; store = store - > next )
{
/* loop through the sigs in the stores */
for ( store_cnt = 0 ;
store_cnt < DE_STATE_CHUNK_SIZE & & cnt < f - > de_state - > cnt ;
store_cnt + + , cnt + + )
{
DeStateStoreItem * item = & store - > store [ store_cnt ] ;
inspect_flags = 0 ;
match_flags = 0 ;
match = 0 ;
SCLogDebug ( " internal id of signature to inspect: % " PRIuMAX ,
( uintmax_t ) item - > sid ) ;
Signature * s = de_ctx - > sig_array [ item - > sid ] ;
SCLogDebug ( " id of signature to inspect: % " PRIuMAX ,
( uintmax_t ) s - > id ) ;
/* if we already fully matched previously, detect that here */
if ( item - > flags & DE_STATE_FLAG_FULL_MATCH ) {
if ( flags & STREAM_TOSERVER & &
item - > flags & DE_STATE_FLAG_FILE_TS_INSPECT & &
f - > de_state - > flags & DE_STATE_FILE_TS_NEW )
{
/* new file, fall through */
item - > flags & = ~ DE_STATE_FLAG_FILE_TS_INSPECT ;
} else if ( flags & STREAM_TOCLIENT & &
item - > flags & DE_STATE_FLAG_FILE_TC_INSPECT & &
f - > de_state - > flags & DE_STATE_FILE_TC_NEW )
{
/* new file, fall through */
item - > flags & = ~ DE_STATE_FLAG_FILE_TC_INSPECT ;
} else {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_FULL ;
SCLogDebug ( " full match state " ) ;
continue ;
}
}
/* if we know for sure we can't ever match, detect that here */
if ( item - > flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
if ( flags & STREAM_TOSERVER & &
item - > flags & DE_STATE_FLAG_FILE_TS_INSPECT & &
f - > de_state - > flags & DE_STATE_FILE_TS_NEW ) {
/* new file, fall through */
item - > flags & = ~ DE_STATE_FLAG_FILE_TS_INSPECT ;
item - > flags & = ~ DE_STATE_FLAG_SIG_CANT_MATCH ;
} else if ( flags & STREAM_TOCLIENT & &
item - > flags & DE_STATE_FLAG_FILE_TC_INSPECT & &
f - > de_state - > flags & DE_STATE_FILE_TC_NEW ) {
/* new file, fall through */
item - > flags & = ~ DE_STATE_FLAG_FILE_TC_INSPECT ;
item - > flags & = ~ DE_STATE_FLAG_SIG_CANT_MATCH ;
} else {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NOMATCH ;
continue ;
}
}
RULE_PROFILING_START ;
/* let's continue detection */
/* first, check uricontent */
if ( alproto = = ALPROTO_HTTP & & ( flags & STREAM_TOSERVER ) ) {
if ( s - > sm_lists [ DETECT_SM_LIST_UMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_URI_MATCH ) ) {
SCLogDebug ( " inspecting uri " ) ;
inspect_flags | = DE_STATE_FLAG_URI_INSPECT ;
if ( DetectEngineInspectPacketUris ( de_ctx , det_ctx , s ,
f , flags , alstate ) = = 1 )
{
SCLogDebug ( " uri matched " ) ;
match_flags | = DE_STATE_FLAG_URI_MATCH ;
} else {
SCLogDebug ( " uri inspected but no match " ) ;
}
} else {
SCLogDebug ( " uri already inspected " ) ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCBDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HCBD_MATCH ) ) {
SCLogDebug ( " inspecting http client body data " ) ;
inspect_flags | = DE_STATE_FLAG_HCBD_INSPECT ;
if ( DetectEngineInspectHttpClientBody ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http client body matched " ) ;
match_flags | = DE_STATE_FLAG_HCBD_MATCH ;
}
}
}
/* not inspecting in toserver direction */
if ( s - > sm_lists [ DETECT_SM_LIST_HSBDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HSBD_MATCH ) ) {
inspect_flags | = DE_STATE_FLAG_HSBD_INSPECT ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HHDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HHD_MATCH ) ) {
SCLogDebug ( " inspecting http header data " ) ;
inspect_flags | = DE_STATE_FLAG_HHD_INSPECT ;
if ( DetectEngineInspectHttpHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http header matched " ) ;
match_flags | = DE_STATE_FLAG_HHD_MATCH ;
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRHDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HRHD_MATCH ) ) {
SCLogDebug ( " inspecting http raw header data " ) ;
inspect_flags | = DE_STATE_FLAG_HRHD_INSPECT ;
if ( DetectEngineInspectHttpRawHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http raw header matched " ) ;
match_flags | = DE_STATE_FLAG_HRHD_MATCH ;
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HMDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HMD_MATCH ) ) {
SCLogDebug ( " inspecting http method data " ) ;
inspect_flags | = DE_STATE_FLAG_HMD_INSPECT ;
if ( DetectEngineInspectHttpMethod ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http method matched " ) ;
match_flags | = DE_STATE_FLAG_HMD_MATCH ;
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HCD_MATCH ) ) {
SCLogDebug ( " inspecting http cookie data " ) ;
inspect_flags | = DE_STATE_FLAG_HCD_INSPECT ;
if ( DetectEngineInspectHttpCookie ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http cookie matched " ) ;
match_flags | = DE_STATE_FLAG_HCD_MATCH ;
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRUDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HRUD_MATCH ) ) {
SCLogDebug ( " inspecting http raw uri data " ) ;
inspect_flags | = DE_STATE_FLAG_HRUD_INSPECT ;
if ( DetectEngineInspectHttpRawUri ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http raw uri matched " ) ;
match_flags | = DE_STATE_FLAG_HRUD_MATCH ;
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_FILEMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_FILE_TS_MATCH ) ) {
SCLogDebug ( " file inspection " ) ;
if ( match_flags = = inspect_flags ) {
SCLogDebug ( " ready to inspect files " ) ;
inspect_flags | = DE_STATE_FLAG_FILE_TS_INSPECT ;
match = DetectFileInspectHttp ( tv , det_ctx , f , s , alstate , flags ) ;
if ( match = = 1 ) {
match_flags | = DE_STATE_FLAG_FILE_TS_MATCH ;
} else if ( match = = 2 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
} else if ( match = = 3 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
file_no_match + + ;
}
} else {
SCLogDebug ( " skipping file inspection as we're not yet done with the other inspection " ) ;
}
}
}
} else if ( alproto = = ALPROTO_HTTP & & ( flags & STREAM_TOCLIENT ) ) {
/* For to client set the flags in inspect so it can't match
* if the sig requires something only the request has . The rest
* will be inspected in the opposite direction . */
if ( s - > sm_lists [ DETECT_SM_LIST_UMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_URI_MATCH ) ) {
inspect_flags | = DE_STATE_FLAG_URI_INSPECT ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCBDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HCBD_MATCH ) ) {
inspect_flags | = DE_STATE_FLAG_HCBD_INSPECT ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HSBDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HSBD_MATCH ) ) {
SCLogDebug ( " inspecting http server body data " ) ;
inspect_flags | = DE_STATE_FLAG_HSBD_INSPECT ;
if ( DetectEngineInspectHttpServerBody ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " http server body matched " ) ;
match_flags | = DE_STATE_FLAG_HSBD_MATCH ;
}
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HHDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HHD_INSPECT ;
if ( DetectEngineInspectHttpHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HHD_MATCH ;
}
SCLogDebug ( " inspecting http header " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRHDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HRHD_INSPECT ;
if ( DetectEngineInspectHttpRawHeader ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HRHD_MATCH ;
}
SCLogDebug ( " inspecting http raw header " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HMDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HMD_MATCH ) ) {
inspect_flags | = DE_STATE_FLAG_HMD_INSPECT ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_HCDMATCH ] ! = NULL ) {
inspect_flags | = DE_STATE_FLAG_HCD_INSPECT ;
if ( DetectEngineInspectHttpCookie ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
match_flags | = DE_STATE_FLAG_HCD_MATCH ;
}
SCLogDebug ( " inspecting http cookie " ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_HRUDMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_HRUD_MATCH ) ) {
inspect_flags | = DE_STATE_FLAG_HRUD_INSPECT ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_FILEMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_FILE_TC_MATCH ) ) {
SCLogDebug ( " file inspection " ) ;
if ( match_flags = = inspect_flags ) {
SCLogDebug ( " ready to inspect files " ) ;
inspect_flags | = DE_STATE_FLAG_FILE_TC_INSPECT ;
match = DetectFileInspectHttp ( tv , det_ctx , f , s , alstate , flags ) ;
if ( match = = 1 ) {
match_flags | = DE_STATE_FLAG_FILE_TC_MATCH ;
} else if ( match = = 2 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
} else if ( match = = 3 ) {
match_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
file_no_match + + ;
}
} else {
SCLogDebug ( " skipping file inspection as we're not yet done with the other inspection " ) ;
}
}
}
} else if ( alproto = = ALPROTO_DCERPC | | alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
if ( s - > sm_lists [ DETECT_SM_LIST_DMATCH ] ! = NULL ) {
if ( ! ( item - > flags & DE_STATE_FLAG_DCE_MATCH ) ) {
SCLogDebug ( " inspecting dce payload " ) ;
inspect_flags | = DE_STATE_FLAG_DCE_INSPECT ;
if ( alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
SMBState * smb_state = ( SMBState * ) alstate ;
//DCERPCState dcerpc_state;
//dcerpc_state.dcerpc = smb_state->dcerpc;
if ( smb_state - > dcerpc_present & &
DetectEngineInspectDcePayload ( de_ctx , det_ctx , s , f ,
flags , & smb_state - > dcerpc ) = = 1 ) {
SCLogDebug ( " dce payload matched " ) ;
match_flags | = DE_STATE_FLAG_DCE_MATCH ;
} else {
SCLogDebug ( " dce payload inspected but no match " ) ;
}
} else {
if ( DetectEngineInspectDcePayload ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
SCLogDebug ( " dce payload matched " ) ;
match_flags | = DE_STATE_FLAG_DCE_MATCH ;
} else {
SCLogDebug ( " dce payload inspected but no match " ) ;
}
}
} else {
SCLogDebug ( " dce payload already inspected " ) ;
}
}
}
/* next, check the other sig matches */
if ( item - > nm ! = NULL ) {
SigMatch * sm ;
for ( sm = item - > nm ; sm ! = NULL ; sm = sm - > next ) {
if ( alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
SMBState * smb_state = ( SMBState * ) alstate ;
//DCERPCState dcerpc_state;
//dcerpc_state.dcerpc = smb_state->dcerpc;
if ( smb_state - > dcerpc_present ) {
match = sigmatch_table [ sm - > type ] .
AppLayerMatch ( tv , det_ctx , f , flags , & smb_state - > dcerpc ,
s , sm ) ;
}
} else {
match = sigmatch_table [ sm - > type ] .
AppLayerMatch ( tv , det_ctx , f , flags , alstate ,
s , sm ) ;
}
/* no match, break out */
if ( match = = 0 ) {
item - > nm = sm ;
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_PARTIAL ;
SCLogDebug ( " state set to %s " , DeStateMatchResultToString ( DE_STATE_MATCH_PARTIAL ) ) ;
break ;
/* match, and no more sm's */
} else if ( sm - > next = = NULL ) {
/* mark the sig as matched */
item - > nm = NULL ;
SCLogDebug ( " inspect_flags %04x match_flags %04x " , inspect_flags , match_flags ) ;
if ( inspect_flags = = 0 | | ( inspect_flags = = match_flags ) ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NEW ;
SCLogDebug ( " state set to %s " , DeStateMatchResultToString ( DE_STATE_MATCH_NEW ) ) ;
match_flags | = DE_STATE_FLAG_FULL_MATCH ;
} else {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_PARTIAL ;
SCLogDebug ( " state set to %s " , DeStateMatchResultToString ( DE_STATE_MATCH_PARTIAL ) ) ;
}
}
}
} else {
SCLogDebug ( " inspect_flags %04x match_flags %04x " , inspect_flags , match_flags ) ;
if ( inspect_flags ! = 0 & & ( inspect_flags = = match_flags ) ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NEW ;
SCLogDebug ( " state set to %s " , DeStateMatchResultToString ( DE_STATE_MATCH_NEW ) ) ;
match_flags | = DE_STATE_FLAG_FULL_MATCH ;
} else {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_PARTIAL ;
SCLogDebug ( " state set to %s " , DeStateMatchResultToString ( DE_STATE_MATCH_PARTIAL ) ) ;
}
}
item - > flags | = match_flags ;
SCLogDebug ( " signature % " PRIu32 " match state %s " ,
s - > id , DeStateMatchResultToString ( det_ctx - > de_state_sig_array [ item - > sid ] ) ) ;
RULE_PROFILING_END ( s , match ) ;
}
}
DeStateStoreStateVersion ( f - > de_state , flags , alversion ) ;
DeStateStoreFileNoMatch ( f - > de_state , flags , file_no_match ) ;
if ( ! ( f - > de_state - > flags & DE_STATE_FILE_STORE_DISABLED ) ) {
if ( DeStateStoreFilestoreSigsCantMatch ( det_ctx - > sgh , f - > de_state , flags ) = = 1 ) {
SCLogDebug ( " disabling file storage for transaction " ) ;
FileDisableStoringForTransaction ( f , flags & ( STREAM_TOCLIENT | STREAM_TOSERVER ) ,
det_ctx - > tx_id ) ;
f - > de_state - > flags | = DE_STATE_FILE_STORE_DISABLED ;
}
}
end :
if ( flags & STREAM_TOCLIENT )
f - > de_state - > flags & = ~ DE_STATE_FILE_TC_NEW ;
else
f - > de_state - > flags & = ~ DE_STATE_FILE_TS_NEW ;
SCMutexUnlock ( & f - > de_state_m ) ;
SCReturnInt ( 0 ) ;
}
/**
* \ brief Restart detection as we ' re going to inspect a new transaction
*/
int DeStateRestartDetection ( ThreadVars * tv , DetectEngineCtx * de_ctx , DetectEngineThreadCtx * det_ctx ,
Flow * f , uint8_t flags , void * alstate , uint16_t alproto )
{
SCEnter ( ) ;
/* first clear the existing state as it belongs
* to the previous transaction */
SCMutexLock ( & f - > de_state_m ) ;
if ( f - > de_state ! = NULL ) {
DetectEngineStateReset ( f - > de_state ) ;
}
SCMutexUnlock ( & f - > de_state_m ) ;
SCReturnInt ( 0 ) ;
}
/**
* \ brief Act on HTTP new file in same tx flag .
*
* \ param f flow with * LOCKED * de_state
*/
static void DeStateResetFileInspection ( Flow * f , uint16_t alproto , void * alstate ) {
if ( f = = NULL | | alproto ! = ALPROTO_HTTP | | alstate = = NULL | | f - > de_state = = NULL ) {
SCReturn ;
}
SCMutexLock ( & f - > m ) ;
HtpState * htp_state = ( HtpState * ) alstate ;
if ( htp_state - > flags & HTP_FLAG_NEW_FILE_TX_TC ) {
htp_state - > flags & = ~ HTP_FLAG_NEW_FILE_TX_TC ;
f - > de_state - > flags | = DE_STATE_FILE_TC_NEW ;
} else if ( htp_state - > flags & HTP_FLAG_NEW_FILE_TX_TS ) {
htp_state - > flags & = ~ HTP_FLAG_NEW_FILE_TX_TS ;
f - > de_state - > flags | = DE_STATE_FILE_TS_NEW ;
}
SCMutexUnlock ( & f - > m ) ;
}
# ifdef UNITTESTS
# include "flow-util.h"
static int DeStateTest01 ( void ) {
SCLogDebug ( " sizeof(DetectEngineState) \t \t % " PRIuMAX ,
( uintmax_t ) sizeof ( DetectEngineState ) ) ;
SCLogDebug ( " sizeof(DeStateStore) \t \t \t % " PRIuMAX ,
( uintmax_t ) sizeof ( DeStateStore ) ) ;
SCLogDebug ( " sizeof(DeStateStoreItem) \t \t % " PRIuMAX " " ,
( uintmax_t ) sizeof ( DeStateStoreItem ) ) ;
return 1 ;
}
static int DeStateTest02 ( void ) {
int result = 0 ;
DetectEngineState * state = DetectEngineStateAlloc ( ) ;
if ( state = = NULL ) {
printf ( " d == NULL: " ) ;
goto end ;
}
Signature s ;
memset ( & s , 0x00 , sizeof ( s ) ) ;
s . num = 0 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 11 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 22 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 33 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 44 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 55 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 66 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 77 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 88 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 99 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 100 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 111 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 122 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 133 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 144 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 155 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 166 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
if ( state - > head = = NULL ) {
goto end ;
}
if ( state - > head - > store [ 1 ] . sid ! = 11 ) {
goto end ;
}
if ( state - > head - > next = = NULL ) {
goto end ;
}
if ( state - > head - > store [ 14 ] . sid ! = 144 ) {
goto end ;
}
if ( state - > head - > next - > store [ 0 ] . sid ! = 155 ) {
goto end ;
}
if ( state - > head - > next - > store [ 1 ] . sid ! = 166 ) {
goto end ;
}
result = 1 ;
end :
if ( state ! = NULL ) {
DetectEngineStateFree ( state ) ;
}
return result ;
}
static int DeStateTest03 ( void ) {
int result = 0 ;
DetectEngineState * state = DetectEngineStateAlloc ( ) ;
if ( state = = NULL ) {
printf ( " d == NULL: " ) ;
goto end ;
}
Signature s ;
memset ( & s , 0x00 , sizeof ( s ) ) ;
s . num = 11 ;
DeStateSignatureAppend ( state , & s , NULL , 0 ) ;
s . num = 22 ;
DeStateSignatureAppend ( state , & s , NULL , DE_STATE_FLAG_URI_MATCH ) ;
if ( state - > head = = NULL ) {
goto end ;
}
if ( state - > head - > store [ 0 ] . sid ! = 11 ) {
goto end ;
}
if ( state - > head - > store [ 0 ] . flags & DE_STATE_FLAG_URI_MATCH ) {
goto end ;
}
if ( state - > head - > store [ 1 ] . sid ! = 22 ) {
goto end ;
}
if ( ! ( state - > head - > store [ 1 ] . flags & DE_STATE_FLAG_URI_MATCH ) ) {
goto end ;
}
result = 1 ;
end :
if ( state ! = NULL ) {
DetectEngineStateFree ( state ) ;
}
return result ;
}
static int DeStateSigTest01 ( void ) {
int result = 0 ;
Signature * s = NULL ;
DetectEngineThreadCtx * det_ctx = NULL ;
ThreadVars th_v ;
Flow f ;
TcpSession ssn ;
Packet * p = NULL ;
uint8_t httpbuf1 [ ] = " POST / HTTP/1.0 \r \n " ;
uint8_t httpbuf2 [ ] = " User-Agent: Mozilla/1.0 \r \n " ;
uint8_t httpbuf3 [ ] = " Cookie: dummy \r \n Content-Length: 10 \r \n \r \n " ;
uint8_t httpbuf4 [ ] = " Http Body! " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
uint32_t httplen2 = sizeof ( httpbuf2 ) - 1 ; /* minus the \0 */
uint32_t httplen3 = sizeof ( httpbuf3 ) - 1 ; /* minus the \0 */
uint32_t httplen4 = sizeof ( httpbuf4 ) - 1 ; /* minus the \0 */
HtpState * http_state = NULL ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & f , 0 , sizeof ( f ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
FLOW_INITIALIZE ( & f ) ;
f . protoctx = ( void * ) & ssn ;
f . flags | = FLOW_IPV4 ;
p - > flow = & f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
f . alproto = ALPROTO_HTTP ;
StreamTcpInitConfig ( TRUE ) ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
s = de_ctx - > sig_list = SigInit ( de_ctx , " alert tcp any any -> any any (content: \" POST \" ; http_method; content: \" dummy \" ; http_cookie; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
int r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf2 , httplen2 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 2 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted (2): " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf3 , httplen3 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 3 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( ! ( PacketAlertCheck ( p , 1 ) ) ) {
printf ( " sig 1 didn't alert: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf4 , httplen4 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 4 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " signature matched, but shouldn't have: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
result = 1 ;
end :
if ( http_state ! = NULL ) {
HTPStateFree ( http_state ) ;
}
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
FLOW_DESTROY ( & f ) ;
UTHFreePacket ( p ) ;
return result ;
}
/** \test multiple pipelined http transactions */
static int DeStateSigTest02 ( void ) {
int result = 0 ;
Signature * s = NULL ;
DetectEngineThreadCtx * det_ctx = NULL ;
ThreadVars th_v ;
Flow f ;
TcpSession ssn ;
Packet * p = NULL ;
uint8_t httpbuf1 [ ] = " POST / HTTP/1.1 \r \n " ;
uint8_t httpbuf2 [ ] = " User-Agent: Mozilla/1.0 \r \n Content-Length: 10 \r \n " ;
uint8_t httpbuf3 [ ] = " Cookie: dummy \r \n \r \n " ;
uint8_t httpbuf4 [ ] = " Http Body! " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
uint32_t httplen2 = sizeof ( httpbuf2 ) - 1 ; /* minus the \0 */
uint32_t httplen3 = sizeof ( httpbuf3 ) - 1 ; /* minus the \0 */
uint32_t httplen4 = sizeof ( httpbuf4 ) - 1 ; /* minus the \0 */
uint8_t httpbuf5 [ ] = " GET /?var=val HTTP/1.1 \r \n " ;
uint8_t httpbuf6 [ ] = " User-Agent: Firefox/1.0 \r \n " ;
uint8_t httpbuf7 [ ] = " Cookie: dummy2 \r \n Content-Length: 10 \r \n \r \n Http Body! " ;
uint32_t httplen5 = sizeof ( httpbuf5 ) - 1 ; /* minus the \0 */
uint32_t httplen6 = sizeof ( httpbuf6 ) - 1 ; /* minus the \0 */
uint32_t httplen7 = sizeof ( httpbuf7 ) - 1 ; /* minus the \0 */
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & f , 0 , sizeof ( f ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
FLOW_INITIALIZE ( & f ) ;
f . protoctx = ( void * ) & ssn ;
f . proto = IPPROTO_TCP ;
f . flags | = FLOW_IPV4 ;
p - > flow = & f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
f . alproto = ALPROTO_HTTP ;
StreamTcpInitConfig ( TRUE ) ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
s = DetectEngineAppendSig ( de_ctx , " alert tcp any any -> any any (content: \" POST \" ; http_method; content: \" Mozilla \" ; http_header; content: \" dummy \" ; http_cookie; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
s = DetectEngineAppendSig ( de_ctx , " alert tcp any any -> any any (content: \" GET \" ; http_method; content: \" Firefox \" ; http_header; content: \" dummy2 \" ; http_cookie; sid:2; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig2 parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
int r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf2 , httplen2 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 2 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted (2): " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf3 , httplen3 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 3 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( ! ( PacketAlertCheck ( p , 1 ) ) ) {
printf ( " sig 1 didn't alert: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf4 , httplen4 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 4 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " signature matched, but shouldn't have: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf5 , httplen5 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 5 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted (5): " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf6 , httplen6 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 6 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( ( PacketAlertCheck ( p , 1 ) ) | | ( PacketAlertCheck ( p , 2 ) ) ) {
printf ( " sig 1 alerted (request 2, chunk 6): " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
SCLogDebug ( " sending data chunk 7 " ) ;
r = AppLayerParse ( NULL , & f , ALPROTO_HTTP , STREAM_TOSERVER , httpbuf7 , httplen7 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 7 returned % " PRId32 " , expected 0: " , r ) ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( ! ( PacketAlertCheck ( p , 2 ) ) ) {
printf ( " signature 2 didn't match, but should have: " ) ;
goto end ;
}
p - > alerts . cnt = 0 ;
result = 1 ;
end :
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
FLOW_DESTROY ( & f ) ;
UTHFreePacket ( p ) ;
return result ;
}
static int DeStateSigTest03 ( void ) {
uint8_t httpbuf1 [ ] = " POST /upload.cgi HTTP/1.1 \r \n "
" Host: www.server.lan \r \n "
" Content-Type: multipart/form-data; boundary=---------------------------277531038314945 \r \n "
" Content-Length: 215 \r \n "
" \r \n "
" -----------------------------277531038314945 \r \n "
" Content-Disposition: form-data; name= \" uploadfile_0 \" ; filename= \" somepicture1.jpg \" \r \n "
" Content-Type: image/jpeg \r \n "
" \r \n "
" filecontent \r \n "
" -----------------------------277531038314945-- " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
ThreadVars th_v ;
TcpSession ssn ;
int result = 0 ;
Flow * f = NULL ;
Packet * p = NULL ;
HtpState * http_state = NULL ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
DetectEngineThreadCtx * det_ctx = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
Signature * s = DetectEngineAppendSig ( de_ctx , " alert http any any -> any any (content: \" POST \" ; http_method; content: \" upload.cgi \" ; http_uri; filestore; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
f = UTHBuildFlow ( AF_INET , " 1.2.3.4 " , " 1.2.3.5 " , 1024 , 80 ) ;
if ( f = = NULL )
goto end ;
f - > protoctx = & ssn ;
f - > alproto = ALPROTO_HTTP ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
if ( p = = NULL )
goto end ;
p - > flow = f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
StreamTcpInitConfig ( TRUE ) ;
int r = AppLayerParse ( NULL , f , ALPROTO_HTTP , STREAM_TOSERVER | STREAM_START | STREAM_EOF , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( ! ( PacketAlertCheck ( p , 1 ) ) ) {
printf ( " sig 1 didn't alert: " ) ;
goto end ;
}
http_state = f - > alstate ;
if ( http_state = = NULL ) {
printf ( " no http state: " ) ;
result = 0 ;
goto end ;
}
if ( http_state - > files_ts = = NULL ) {
printf ( " no files in state: " ) ;
goto end ;
}
FileContainer * files = AppLayerGetFilesFromFlow ( p - > flow , STREAM_TOSERVER ) ;
if ( files = = NULL ) {
printf ( " no stored files: " ) ;
goto end ;
}
File * file = files - > head ;
if ( file = = NULL ) {
printf ( " no file: " ) ;
goto end ;
}
if ( file - > store ! = 1 ) {
printf ( " file is set to store, but sig didn't match: " ) ;
goto end ;
}
result = 1 ;
end :
UTHFreeFlow ( f ) ;
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
return result ;
}
static int DeStateSigTest04 ( void ) {
uint8_t httpbuf1 [ ] = " POST /upload.cgi HTTP/1.1 \r \n "
" Host: www.server.lan \r \n "
" Content-Type: multipart/form-data; boundary=---------------------------277531038314945 \r \n "
" Content-Length: 215 \r \n "
" \r \n "
" -----------------------------277531038314945 \r \n "
" Content-Disposition: form-data; name= \" uploadfile_0 \" ; filename= \" somepicture1.jpg \" \r \n "
" Content-Type: image/jpeg \r \n "
" \r \n "
" filecontent \r \n "
" -----------------------------277531038314945-- " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
ThreadVars th_v ;
TcpSession ssn ;
int result = 0 ;
Flow * f = NULL ;
Packet * p = NULL ;
HtpState * http_state = NULL ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
DetectEngineThreadCtx * det_ctx = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
Signature * s = DetectEngineAppendSig ( de_ctx , " alert http any any -> any any (content: \" GET \" ; http_method; content: \" upload.cgi \" ; http_uri; filestore; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
f = UTHBuildFlow ( AF_INET , " 1.2.3.4 " , " 1.2.3.5 " , 1024 , 80 ) ;
if ( f = = NULL )
goto end ;
f - > protoctx = & ssn ;
f - > alproto = ALPROTO_HTTP ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
if ( p = = NULL )
goto end ;
p - > flow = f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
StreamTcpInitConfig ( TRUE ) ;
int r = AppLayerParse ( NULL , f , ALPROTO_HTTP , STREAM_TOSERVER | STREAM_START | STREAM_EOF , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
http_state = f - > alstate ;
if ( http_state = = NULL ) {
printf ( " no http state: " ) ;
result = 0 ;
goto end ;
}
if ( http_state - > files_ts = = NULL ) {
printf ( " no files in state: " ) ;
goto end ;
}
FileContainer * files = AppLayerGetFilesFromFlow ( p - > flow , STREAM_TOSERVER ) ;
if ( files = = NULL ) {
printf ( " no stored files: " ) ;
goto end ;
}
File * file = files - > head ;
if ( file = = NULL ) {
printf ( " no file: " ) ;
goto end ;
}
if ( file - > store = = 1 ) {
printf ( " file is set to store, but sig didn't match: " ) ;
goto end ;
}
result = 1 ;
end :
UTHFreeFlow ( f ) ;
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
return result ;
}
static int DeStateSigTest05 ( void ) {
uint8_t httpbuf1 [ ] = " POST /upload.cgi HTTP/1.1 \r \n "
" Host: www.server.lan \r \n "
" Content-Type: multipart/form-data; boundary=---------------------------277531038314945 \r \n "
" Content-Length: 215 \r \n "
" \r \n "
" -----------------------------277531038314945 \r \n "
" Content-Disposition: form-data; name= \" uploadfile_0 \" ; filename= \" somepicture1.jpg \" \r \n "
" Content-Type: image/jpeg \r \n "
" \r \n "
" filecontent \r \n "
" -----------------------------277531038314945-- " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
ThreadVars th_v ;
TcpSession ssn ;
int result = 0 ;
Flow * f = NULL ;
Packet * p = NULL ;
HtpState * http_state = NULL ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
DetectEngineThreadCtx * det_ctx = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
Signature * s = DetectEngineAppendSig ( de_ctx , " alert http any any -> any any (content: \" GET \" ; http_method; content: \" upload.cgi \" ; http_uri; filename: \" nomatch \" ; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
f = UTHBuildFlow ( AF_INET , " 1.2.3.4 " , " 1.2.3.5 " , 1024 , 80 ) ;
if ( f = = NULL )
goto end ;
f - > protoctx = & ssn ;
f - > alproto = ALPROTO_HTTP ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
if ( p = = NULL )
goto end ;
p - > flow = f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
StreamTcpInitConfig ( TRUE ) ;
int r = AppLayerParse ( NULL , f , ALPROTO_HTTP , STREAM_TOSERVER | STREAM_START | STREAM_EOF , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
http_state = f - > alstate ;
if ( http_state = = NULL ) {
printf ( " no http state: " ) ;
result = 0 ;
goto end ;
}
if ( http_state - > files_ts = = NULL ) {
printf ( " no files in state: " ) ;
goto end ;
}
FileContainer * files = AppLayerGetFilesFromFlow ( p - > flow , STREAM_TOSERVER ) ;
if ( files = = NULL ) {
printf ( " no stored files: " ) ;
goto end ;
}
File * file = files - > head ;
if ( file = = NULL ) {
printf ( " no file: " ) ;
goto end ;
}
if ( file - > store ! = - 1 ) {
printf ( " file is not set to \" no store \" , but %d: " , file - > store ) ;
goto end ;
}
result = 1 ;
end :
UTHFreeFlow ( f ) ;
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
return result ;
}
static int DeStateSigTest06 ( void ) {
uint8_t httpbuf1 [ ] = " POST /upload.cgi HTTP/1.1 \r \n "
" Host: www.server.lan \r \n "
" Content-Type: multipart/form-data; boundary=---------------------------277531038314945 \r \n "
" Content-Length: 215 \r \n "
" \r \n "
" -----------------------------277531038314945 \r \n "
" Content-Disposition: form-data; name= \" uploadfile_0 \" ; filename= \" somepicture1.jpg \" \r \n "
" Content-Type: image/jpeg \r \n "
" \r \n "
" filecontent \r \n "
" -----------------------------277531038314945-- " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
ThreadVars th_v ;
TcpSession ssn ;
int result = 0 ;
Flow * f = NULL ;
Packet * p = NULL ;
HtpState * http_state = NULL ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
DetectEngineThreadCtx * det_ctx = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
Signature * s = DetectEngineAppendSig ( de_ctx , " alert http any any -> any any (content: \" POST \" ; http_method; content: \" upload.cgi \" ; http_uri; filename: \" nomatch \" ; filestore; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
f = UTHBuildFlow ( AF_INET , " 1.2.3.4 " , " 1.2.3.5 " , 1024 , 80 ) ;
if ( f = = NULL )
goto end ;
f - > protoctx = & ssn ;
f - > alproto = ALPROTO_HTTP ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
if ( p = = NULL )
goto end ;
p - > flow = f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
StreamTcpInitConfig ( TRUE ) ;
int r = AppLayerParse ( NULL , f , ALPROTO_HTTP , STREAM_TOSERVER | STREAM_START | STREAM_EOF , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
http_state = f - > alstate ;
if ( http_state = = NULL ) {
printf ( " no http state: " ) ;
result = 0 ;
goto end ;
}
if ( http_state - > files_ts = = NULL ) {
printf ( " no files in state: " ) ;
goto end ;
}
FileContainer * files = AppLayerGetFilesFromFlow ( p - > flow , STREAM_TOSERVER ) ;
if ( files = = NULL ) {
printf ( " no stored files: " ) ;
goto end ;
}
File * file = files - > head ;
if ( file = = NULL ) {
printf ( " no file: " ) ;
goto end ;
}
if ( file - > store ! = - 1 ) {
printf ( " file is not set to \" no store \" , but %d: " , file - > store ) ;
goto end ;
}
result = 1 ;
end :
UTHFreeFlow ( f ) ;
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
return result ;
}
static int DeStateSigTest07 ( void ) {
uint8_t httpbuf1 [ ] = " POST /upload.cgi HTTP/1.1 \r \n "
" Host: www.server.lan \r \n "
" Content-Type: multipart/form-data; boundary=---------------------------277531038314945 \r \n "
" Content-Length: 215 \r \n "
" \r \n "
" -----------------------------277531038314945 \r \n "
" Content-Disposition: form-data; name= \" uploadfile_0 \" ; filename= \" somepicture1.jpg \" \r \n "
" Content-Type: image/jpeg \r \n "
" \r \n " ;
uint32_t httplen1 = sizeof ( httpbuf1 ) - 1 ; /* minus the \0 */
uint8_t httpbuf2 [ ] = " filecontent \r \n "
" -----------------------------277531038314945-- " ;
uint32_t httplen2 = sizeof ( httpbuf2 ) - 1 ; /* minus the \0 */
ThreadVars th_v ;
TcpSession ssn ;
int result = 0 ;
Flow * f = NULL ;
Packet * p = NULL ;
HtpState * http_state = NULL ;
memset ( & th_v , 0 , sizeof ( th_v ) ) ;
memset ( & ssn , 0 , sizeof ( ssn ) ) ;
DetectEngineThreadCtx * det_ctx = NULL ;
DetectEngineCtx * de_ctx = DetectEngineCtxInit ( ) ;
if ( de_ctx = = NULL ) {
goto end ;
}
de_ctx - > flags | = DE_QUIET ;
Signature * s = DetectEngineAppendSig ( de_ctx , " alert http any any -> any any (content: \" GET \" ; http_method; content: \" upload.cgi \" ; http_uri; filestore; sid:1; rev:1;) " ) ;
if ( s = = NULL ) {
printf ( " sig parse failed: " ) ;
goto end ;
}
SigGroupBuild ( de_ctx ) ;
DetectEngineThreadCtxInit ( & th_v , ( void * ) de_ctx , ( void * ) & det_ctx ) ;
f = UTHBuildFlow ( AF_INET , " 1.2.3.4 " , " 1.2.3.5 " , 1024 , 80 ) ;
if ( f = = NULL )
goto end ;
f - > protoctx = & ssn ;
f - > alproto = ALPROTO_HTTP ;
p = UTHBuildPacket ( NULL , 0 , IPPROTO_TCP ) ;
if ( p = = NULL )
goto end ;
p - > flow = f ;
p - > flags | = PKT_HAS_FLOW | PKT_STREAM_EST ;
p - > flowflags | = FLOW_PKT_TOSERVER ;
p - > flowflags | = FLOW_PKT_ESTABLISHED ;
StreamTcpInitConfig ( TRUE ) ;
SCLogDebug ( " \n >>>> processing chunk 1 <<<< \n " ) ;
int r = AppLayerParse ( NULL , f , ALPROTO_HTTP , STREAM_TOSERVER | STREAM_START , httpbuf1 , httplen1 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 1 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
/* do detect */
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
SCLogDebug ( " \n >>>> processing chunk 2 size %u <<<< \n " , httplen2 ) ;
r = AppLayerParse ( NULL , f , ALPROTO_HTTP , STREAM_TOSERVER | STREAM_EOF , httpbuf2 , httplen2 ) ;
if ( r ! = 0 ) {
printf ( " toserver chunk 2 returned % " PRId32 " , expected 0: " , r ) ;
result = 0 ;
goto end ;
}
SigMatchSignatures ( & th_v , de_ctx , det_ctx , p ) ;
if ( PacketAlertCheck ( p , 1 ) ) {
printf ( " sig 1 alerted: " ) ;
goto end ;
}
http_state = f - > alstate ;
if ( http_state = = NULL ) {
printf ( " no http state: " ) ;
result = 0 ;
goto end ;
}
if ( http_state - > files_ts = = NULL ) {
printf ( " no files in state: " ) ;
goto end ;
}
FileContainer * files = AppLayerGetFilesFromFlow ( p - > flow , STREAM_TOSERVER ) ;
if ( files = = NULL ) {
printf ( " no stored files: " ) ;
goto end ;
}
File * file = files - > head ;
if ( file = = NULL ) {
printf ( " no file: " ) ;
goto end ;
}
if ( file - > store = = 1 ) {
printf ( " file is set to store, but sig didn't match: " ) ;
goto end ;
}
result = 1 ;
end :
UTHFreeFlow ( f ) ;
if ( det_ctx ! = NULL ) {
DetectEngineThreadCtxDeinit ( & th_v , ( void * ) det_ctx ) ;
}
if ( de_ctx ! = NULL ) {
SigGroupCleanup ( de_ctx ) ;
DetectEngineCtxFree ( de_ctx ) ;
}
StreamTcpFreeConfig ( TRUE ) ;
return result ;
}
# endif
void DeStateRegisterTests ( void ) {
# ifdef UNITTESTS
UtRegisterTest ( " DeStateTest01 " , DeStateTest01 , 1 ) ;
UtRegisterTest ( " DeStateTest02 " , DeStateTest02 , 1 ) ;
UtRegisterTest ( " DeStateTest03 " , DeStateTest03 , 1 ) ;
UtRegisterTest ( " DeStateSigTest01 " , DeStateSigTest01 , 1 ) ;
UtRegisterTest ( " DeStateSigTest02 " , DeStateSigTest02 , 1 ) ;
UtRegisterTest ( " DeStateSigTest03 " , DeStateSigTest03 , 1 ) ;
UtRegisterTest ( " DeStateSigTest04 " , DeStateSigTest04 , 1 ) ;
UtRegisterTest ( " DeStateSigTest05 " , DeStateSigTest05 , 1 ) ;
UtRegisterTest ( " DeStateSigTest06 " , DeStateSigTest06 , 1 ) ;
UtRegisterTest ( " DeStateSigTest07 " , DeStateSigTest07 , 1 ) ;
# endif
}
/**
* @ }
*/