/* Copyright (C) 2007-2013 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 >
* \ author Anoop Saldanha < anoopsaldanha @ gmail . com >
*
* \ 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-dcepayload.h"
# include "detect-flowvar.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 "app-layer-dns-common.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
/******** static internal helpers *********/
static DeStateStore * DeStateStoreAlloc ( void )
{
DeStateStore * d = SCMalloc ( sizeof ( DeStateStore ) ) ;
if ( unlikely ( d = = NULL ) )
return NULL ;
memset ( d , 0 , sizeof ( DeStateStore ) ) ;
return d ;
}
static void DeStateSignatureAppend ( DetectEngineState * state , Signature * s ,
SigMatch * sm , uint32_t inspect_flags ,
uint8_t direction )
{
int jump = 0 ;
int i = 0 ;
DetectEngineStateDirection * dir_state = & state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] ;
DeStateStore * store = dir_state - > head ;
if ( store = = NULL ) {
store = DeStateStoreAlloc ( ) ;
if ( store ! = NULL ) {
dir_state - > head = store ;
dir_state - > tail = store ;
}
} else {
jump = dir_state - > cnt / DE_STATE_CHUNK_SIZE ;
for ( i = 0 ; i < jump ; i + + ) {
store = store - > next ;
}
if ( store = = NULL ) {
store = DeStateStoreAlloc ( ) ;
if ( store ! = NULL ) {
dir_state - > tail - > next = store ;
dir_state - > tail = store ;
}
}
}
if ( store = = NULL )
return ;
SigIntId idx = dir_state - > cnt + + % DE_STATE_CHUNK_SIZE ;
store - > store [ idx ] . sid = s - > num ;
store - > store [ idx ] . flags = inspect_flags ;
store - > store [ idx ] . nm = sm ;
return ;
}
static void DeStateStoreStateVersion ( DetectEngineState * de_state ,
uint16_t alversion , uint8_t direction )
{
de_state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . alversion = alversion ;
return ;
}
static void DeStateStoreFileNoMatchCnt ( DetectEngineState * de_state , uint16_t file_no_match , uint8_t direction )
{
de_state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . filestore_cnt + = file_no_match ;
return ;
}
static int DeStateStoreFilestoreSigsCantMatch ( SigGroupHead * sgh , DetectEngineState * de_state , uint8_t direction )
{
if ( de_state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . filestore_cnt = = sgh - > filestore_cnt )
return 1 ;
else
return 0 ;
}
static void DeStateResetFileInspection ( Flow * f , uint16_t alproto , void * alstate , uint8_t direction )
{
if ( f = = NULL | | alproto ! = ALPROTO_HTTP | | alstate = = NULL | | f - > de_state = = NULL )
return ;
FLOWLOCK_WRLOCK ( f ) ;
HtpState * htp_state = ( HtpState * ) alstate ;
if ( direction & STREAM_TOSERVER ) {
if ( htp_state - > flags & HTP_FLAG_NEW_FILE_TX_TS ) {
SCLogDebug ( " new file in the TS direction " ) ;
htp_state - > flags & = ~ HTP_FLAG_NEW_FILE_TX_TS ;
f - > de_state - > dir_state [ 0 ] . flags | = DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW ;
}
} else {
if ( htp_state - > flags & HTP_FLAG_NEW_FILE_TX_TC ) {
SCLogDebug ( " new file in the TC direction " ) ;
htp_state - > flags & = ~ HTP_FLAG_NEW_FILE_TX_TC ;
f - > de_state - > dir_state [ 1 ] . flags | = DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW ;
}
}
FLOWLOCK_UNLOCK ( f ) ;
}
DetectEngineState * DetectEngineStateAlloc ( void )
{
DetectEngineState * d = SCMalloc ( sizeof ( DetectEngineState ) ) ;
if ( unlikely ( d = = NULL ) )
return NULL ;
memset ( d , 0 , sizeof ( DetectEngineState ) ) ;
return d ;
}
void DetectEngineStateFree ( DetectEngineState * state )
{
DeStateStore * store ;
DeStateStore * store_next ;
int i = 0 ;
for ( i = 0 ; i < 2 ; i + + ) {
store = state - > dir_state [ i ] . head ;
while ( store ! = NULL ) {
store_next = store - > next ;
SCFree ( store ) ;
store = store_next ;
}
}
SCFree ( state ) ;
return ;
}
int DeStateFlowHasInspectableState ( Flow * f , uint16_t alproto , uint16_t alversion , uint8_t flags )
{
int r = 0 ;
SCMutexLock ( & f - > de_state_m ) ;
if ( f - > de_state = = NULL | | f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . cnt = = 0 ) {
if ( AppLayerAlprotoSupportsTxs ( alproto ) ) {
FLOWLOCK_RDLOCK ( f ) ;
if ( AppLayerTransactionGetInspectId ( f , flags ) > = AppLayerGetTxCnt ( alproto , f - > alstate ) )
r = 2 ;
else
r = 0 ;
FLOWLOCK_UNLOCK ( f ) ;
}
} else if ( ! ( flags & STREAM_EOF ) & &
f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . alversion = = alversion ) {
r = 2 ;
} else {
r = 1 ;
}
SCMutexUnlock ( & f - > de_state_m ) ;
return r ;
}
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 )
{
DetectEngineAppInspectionEngine * engine = NULL ;
SigMatch * sm = NULL ;
uint16_t file_no_match = 0 ;
uint32_t inspect_flags = 0 ;
HtpState * htp_state = NULL ;
SMBState * smb_state = NULL ;
void * tx = NULL ;
uint64_t tx_id = 0 ;
uint64_t total_txs = 0 ;
int match = 0 ;
int store_de_state = 0 ;
uint8_t direction = ( flags & STREAM_TOSERVER ) ? 0 : 1 ;
/* this was introduced later to allow protocols that had both app
* keywords with transaction keywords . Without this we would
* assume that we have an alert if engine = = NULL */
int total_matches = 0 ;
int alert_cnt = 0 ;
if ( alstate = = NULL )
goto end ;
if ( AppLayerAlprotoSupportsTxs ( alproto ) ) {
FLOWLOCK_WRLOCK ( f ) ;
if ( alproto = = ALPROTO_HTTP ) {
htp_state = ( HtpState * ) alstate ;
if ( htp_state - > connp = = NULL | | htp_state - > connp - > conn = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
goto end ;
}
}
tx_id = AppLayerTransactionGetInspectId ( f , flags ) ;
total_txs = AppLayerGetTxCnt ( alproto , alstate ) ;
for ( ; tx_id < total_txs ; tx_id + + ) {
total_matches = 0 ;
tx = AppLayerGetTx ( alproto , alstate , tx_id ) ;
if ( tx = = NULL )
continue ;
engine = app_inspection_engine [ alproto ] [ direction ] ;
inspect_flags = 0 ;
while ( engine ! = NULL ) {
if ( s - > sm_lists [ engine - > sm_list ] ! = NULL ) {
match = engine - > Callback ( tv , de_ctx , det_ctx , s , f ,
flags , alstate ,
tx , tx_id ) ;
if ( match = = 1 ) {
inspect_flags | = engine - > inspect_flags ;
engine = engine - > next ;
total_matches + + ;
continue ;
} else if ( match = = 2 ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
} else if ( match = = 3 ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
file_no_match + + ;
}
break ;
}
engine = engine - > next ;
}
/* all the engines seem to be exhausted at this point. If we
* didn ' t have a match in one of the engines we would have
* broken off and engine wouldn ' t be NULL . Hence the alert . */
if ( engine = = NULL & & total_matches > 0 )
alert_cnt + + ;
if ( tx_id = = ( total_txs - 1 ) ) {
void * tx = AppLayerGetTx ( alproto , alstate , tx_id ) ;
if ( tx = = NULL )
continue ;
if ( AppLayerGetAlstateProgress ( alproto , tx , direction ) <
AppLayerGetAlstateProgressCompletionStatus ( alproto , direction ) ) {
store_de_state = 1 ;
if ( engine = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH )
inspect_flags | = DE_STATE_FLAG_FULL_INSPECT ;
}
}
} /* for */
FLOWLOCK_UNLOCK ( f ) ;
} else if ( s - > sm_lists [ DETECT_SM_LIST_DMATCH ] ! = NULL & &
( alproto = = ALPROTO_DCERPC | | alproto = = ALPROTO_SMB | |
alproto = = ALPROTO_SMB2 ) )
{
if ( alproto = = ALPROTO_SMB | | alproto = = ALPROTO_SMB2 ) {
smb_state = ( SMBState * ) alstate ;
if ( smb_state - > dcerpc_present & &
DetectEngineInspectDcePayload ( de_ctx , det_ctx , s , f ,
flags , & smb_state - > dcerpc ) = = 1 ) {
alert_cnt + + ;
}
} else {
if ( DetectEngineInspectDcePayload ( de_ctx , det_ctx , s , f ,
flags , alstate ) = = 1 ) {
alert_cnt + + ;
}
}
}
sm = s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ;
for ( ; sm ! = NULL ; 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 ) {
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 ( match = = 2 )
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
}
}
if ( s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ! = NULL ) {
store_de_state = 1 ;
if ( sm = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
if ( sm = = NULL )
alert_cnt = 1 ;
inspect_flags | = DE_STATE_FLAG_FULL_INSPECT ;
}
}
if ( ! store_de_state & & file_no_match = = 0 )
goto end ;
SCMutexLock ( & f - > de_state_m ) ;
if ( f - > de_state = = NULL ) {
f - > de_state = DetectEngineStateAlloc ( ) ;
if ( f - > de_state = = NULL ) {
SCMutexUnlock ( & f - > de_state_m ) ;
goto end ;
}
}
if ( store_de_state ) {
DeStateSignatureAppend ( f - > de_state , s , sm , inspect_flags , flags ) ;
DeStateStoreStateVersion ( f - > de_state , alversion , flags ) ;
}
DeStateStoreFileNoMatchCnt ( f - > de_state , file_no_match , flags ) ;
if ( DeStateStoreFilestoreSigsCantMatch ( det_ctx - > sgh , f - > de_state , flags ) = = 1 ) {
FLOWLOCK_WRLOCK ( f ) ;
FileDisableStoringForTransaction ( f , flags & ( STREAM_TOCLIENT | STREAM_TOSERVER ) ,
det_ctx - > tx_id ) ;
FLOWLOCK_UNLOCK ( f ) ;
f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . flags | = DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED ;
}
SCMutexUnlock ( & f - > de_state_m ) ;
end :
return alert_cnt ;
}
void DeStateDetectContinueDetection ( ThreadVars * tv , DetectEngineCtx * de_ctx ,
DetectEngineThreadCtx * det_ctx ,
Packet * p , Flow * f , uint8_t flags , void * alstate ,
uint16_t alproto , uint16_t alversion )
{
SCMutexLock ( & f - > de_state_m ) ;
DetectEngineAppInspectionEngine * engine = NULL ;
SigMatch * sm = NULL ;
uint16_t file_no_match = 0 ;
uint32_t inspect_flags = 0 ;
HtpState * htp_state = NULL ;
SMBState * smb_state = NULL ;
SigIntId store_cnt = 0 ;
SigIntId state_cnt = 0 ;
int match = 0 ;
uint8_t alert = 0 ;
DetectEngineStateDirection * dir_state = & f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] ;
DeStateStore * store = dir_state - > head ;
void * inspect_tx = NULL ;
uint64_t inspect_tx_id = 0 ;
uint64_t total_txs = 0 ;
uint8_t alproto_supports_txs = 0 ;
uint8_t reset_de_state = 0 ;
/* this was introduced later to allow protocols that had both app
* keywords with transaction keywords . Without this we would
* assume that we have an alert if engine = = NULL */
uint8_t total_matches = 0 ;
uint8_t direction = ( flags & STREAM_TOSERVER ) ? 0 : 1 ;
DeStateResetFileInspection ( f , alproto , alstate , flags ) ;
if ( AppLayerAlprotoSupportsTxs ( alproto ) ) {
FLOWLOCK_RDLOCK ( f ) ;
inspect_tx_id = AppLayerTransactionGetInspectId ( f , flags ) ;
total_txs = AppLayerGetTxCnt ( alproto , alstate ) ;
inspect_tx = AppLayerGetTx ( alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
SCMutexUnlock ( & f - > de_state_m ) ;
return ;
}
if ( AppLayerGetAlstateProgress ( alproto , inspect_tx , direction ) > =
AppLayerGetAlstateProgressCompletionStatus ( alproto , direction ) ) {
reset_de_state = 1 ;
}
FLOWLOCK_UNLOCK ( f ) ;
alproto_supports_txs = 1 ;
}
for ( ; store ! = NULL ; store = store - > next ) {
for ( store_cnt = 0 ;
store_cnt < DE_STATE_CHUNK_SIZE & & state_cnt < dir_state - > cnt ;
store_cnt + + , state_cnt + + )
{
total_matches = 0 ;
DeStateStoreItem * item = & store - > store [ store_cnt ] ;
Signature * s = de_ctx - > sig_array [ item - > sid ] ;
if ( item - > flags & DE_STATE_FLAG_FULL_INSPECT ) {
if ( item - > flags & ( DE_STATE_FLAG_FILE_TC_INSPECT |
DE_STATE_FLAG_FILE_TS_INSPECT ) ) {
if ( ( flags & STREAM_TOCLIENT ) & &
( dir_state - > flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW ) )
{
item - > flags & = ~ DE_STATE_FLAG_FILE_TC_INSPECT ;
item - > flags & = ~ DE_STATE_FLAG_FULL_INSPECT ;
}
if ( ( flags & STREAM_TOSERVER ) & &
( dir_state - > flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW ) )
{
item - > flags & = ~ DE_STATE_FLAG_FILE_TS_INSPECT ;
item - > flags & = ~ DE_STATE_FLAG_FULL_INSPECT ;
}
}
if ( item - > flags & DE_STATE_FLAG_FULL_INSPECT ) {
if ( alproto_supports_txs ) {
if ( ( total_txs - inspect_tx_id ) < = 1 )
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
} else {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
continue ;
}
}
if ( item - > flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
if ( ( flags & STREAM_TOSERVER ) & &
( item - > flags & DE_STATE_FLAG_FILE_TS_INSPECT ) & &
( dir_state - > flags & DETECT_ENGINE_STATE_FLAG_FILE_TS_NEW ) )
{
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 ) & &
( dir_state - > flags & DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW ) )
{
item - > flags & = ~ DE_STATE_FLAG_FILE_TC_INSPECT ;
item - > flags & = ~ DE_STATE_FLAG_SIG_CANT_MATCH ;
} else {
if ( alproto_supports_txs ) {
if ( ( total_txs - inspect_tx_id ) < = 1 )
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
} else {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
continue ;
}
}
alert = 0 ;
inspect_flags = 0 ;
match = 0 ;
RULE_PROFILING_START ;
if ( alproto_supports_txs ) {
FLOWLOCK_WRLOCK ( f ) ;
if ( alproto = = ALPROTO_HTTP ) {
htp_state = ( HtpState * ) alstate ;
if ( htp_state - > connp = = NULL | | htp_state - > connp - > conn = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
RULE_PROFILING_END ( det_ctx , s , match ) ;
goto end ;
}
}
engine = app_inspection_engine [ alproto ] [ ( flags & STREAM_TOSERVER ) ? 0 : 1 ] ;
inspect_tx = AppLayerGetTx ( alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
RULE_PROFILING_END ( det_ctx , s , match ) ;
goto end ;
}
while ( engine ! = NULL ) {
if ( ! ( item - > flags & engine - > inspect_flags ) & &
s - > sm_lists [ engine - > sm_list ] ! = NULL )
{
match = engine - > Callback ( tv , de_ctx , det_ctx , s , f ,
flags , alstate , inspect_tx , inspect_tx_id ) ;
if ( match = = 1 ) {
inspect_flags | = engine - > inspect_flags ;
engine = engine - > next ;
total_matches + + ;
continue ;
} else if ( match = = 2 ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
} else if ( match = = 3 ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
file_no_match + + ;
}
break ;
}
engine = engine - > next ;
}
if ( total_matches > 0 & & ( engine = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH ) ) {
if ( engine = = NULL )
alert = 1 ;
inspect_flags | = DE_STATE_FLAG_FULL_INSPECT ;
}
FLOWLOCK_UNLOCK ( f ) ;
}
for ( sm = item - > nm ; sm ! = NULL ; 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 ) {
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 ( match = = 2 )
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
}
}
RULE_PROFILING_END ( det_ctx , s , match ) ;
if ( s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ! = NULL ) {
if ( sm = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
if ( sm = = NULL )
alert = 1 ;
inspect_flags | = DE_STATE_FLAG_FULL_INSPECT ;
}
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
item - > flags | = inspect_flags ;
if ( ( total_txs - inspect_tx_id ) < = 1 )
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
if ( alert ) {
SigMatchSignaturesRunPostMatch ( tv , de_ctx , det_ctx , p , s ) ;
if ( ! ( s - > flags & SIG_FLAG_NOALERT ) ) {
PacketAlertAppend ( det_ctx , s , p , 0 ) ;
} else {
PACKET_UPDATE_ACTION ( p , s - > action ) ;
}
}
DetectFlowvarProcessList ( det_ctx , f ) ;
}
}
DeStateStoreStateVersion ( f - > de_state , alversion , flags ) ;
DeStateStoreFileNoMatchCnt ( f - > de_state , file_no_match , flags ) ;
if ( ! ( dir_state - > flags & DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED ) ) {
if ( DeStateStoreFilestoreSigsCantMatch ( det_ctx - > sgh , f - > de_state , flags ) = = 1 ) {
SCLogDebug ( " disabling file storage for transaction " ) ;
FLOWLOCK_WRLOCK ( f ) ;
FileDisableStoringForTransaction ( f , flags & ( STREAM_TOCLIENT | STREAM_TOSERVER ) ,
det_ctx - > tx_id ) ;
FLOWLOCK_UNLOCK ( f ) ;
dir_state - > flags | = DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED ;
}
}
end :
if ( f - > de_state ! = NULL )
dir_state - > flags & = ~ DETECT_ENGINE_STATE_FLAG_FILE_TC_NEW ;
if ( reset_de_state )
DetectEngineStateReset ( f - > de_state , flags ) ;
SCMutexUnlock ( & f - > de_state_m ) ;
return ;
}
void DeStateUpdateInspectTransactionId ( Flow * f , uint8_t direction )
{
AppLayerTransactionUpdateInspectId ( f , direction ) ;
return ;
}
void DetectEngineStateReset ( DetectEngineState * state , uint8_t direction )
{
if ( state ! = NULL ) {
if ( direction & STREAM_TOSERVER ) {
state - > dir_state [ 0 ] . cnt = 0 ;
state - > dir_state [ 0 ] . filestore_cnt = 0 ;
state - > dir_state [ 0 ] . flags = 0 ;
}
if ( direction & STREAM_TOCLIENT ) {
state - > dir_state [ 1 ] . cnt = 0 ;
state - > dir_state [ 1 ] . filestore_cnt = 0 ;
state - > dir_state [ 1 ] . flags = 0 ;
}
}
return ;
}
/** \brief get string for match enum */
const char * DeStateMatchResultToString ( DeStateMatchResult res )
{
switch ( res ) {
CASE_CODE ( DE_STATE_MATCH_NO_NEW_STATE ) ;
CASE_CODE ( DE_STATE_MATCH_HAS_NEW_STATE ) ;
}
return NULL ;
}
/*********Unittests*********/
# 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 ) ) ;
uint8_t direction = STREAM_TOSERVER ;
s . num = 0 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 11 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 22 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 33 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 44 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 55 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 66 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 77 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 88 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 99 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 100 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 111 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 122 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 133 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 144 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 155 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 166 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head = = NULL ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > store [ 1 ] . sid ! = 11 ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > next = = NULL ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > store [ 14 ] . sid ! = 144 ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > next - > store [ 0 ] . sid ! = 155 ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . 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 ) ) ;
uint8_t direction = STREAM_TOSERVER ;
s . num = 11 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
s . num = 22 ;
DeStateSignatureAppend ( state , & s , NULL , DE_STATE_FLAG_URI_INSPECT , direction ) ;
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head = = NULL ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > store [ 0 ] . sid ! = 11 ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > store [ 0 ] . flags & DE_STATE_FLAG_URI_INSPECT ) {
goto end ;
}
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > store [ 1 ] . sid ! = 22 ) {
goto end ;
}
if ( ! ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head - > store [ 1 ] . flags & DE_STATE_FLAG_URI_INSPECT ) ) {
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 - > flags & FILE_STORE ) ) {
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 - > flags & FILE_STORE ) {
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 - > flags & FILE_NOSTORE ) ) {
printf ( " file is not set to \" no 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 - > flags & FILE_NOSTORE ) ) {
printf ( " file is not set to \" no 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 - > flags & FILE_STORE ) {
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
return ;
}
/**
* @ }
*/