@ -83,6 +83,28 @@
/******** static internal helpers *********/
static inline int StateIsValid ( uint16_t alproto , void * alstate )
{
if ( alstate ! = NULL ) {
if ( alproto = = ALPROTO_HTTP ) {
HtpState * htp_state = ( HtpState * ) alstate ;
if ( htp_state - > conn ! = NULL ) {
return 1 ;
}
} else {
return 1 ;
}
}
return 0 ;
}
static inline int TxIsLast ( uint64_t tx_id , uint64_t total_txs )
{
if ( total_txs - tx_id < = 1 )
return 1 ;
return 0 ;
}
static DeStateStore * DeStateStoreAlloc ( void )
{
DeStateStore * d = SCMalloc ( sizeof ( DeStateStore ) ) ;
@ -92,10 +114,17 @@ static DeStateStore *DeStateStoreAlloc(void)
return d ;
}
static DeStateStoreFlowRules * DeStateStoreFlowRulesAlloc ( void )
{
DeStateStoreFlowRules * d = SCMalloc ( sizeof ( DeStateStoreFlowRules ) ) ;
if ( unlikely ( d = = NULL ) )
return NULL ;
memset ( d , 0 , sizeof ( DeStateStoreFlowRules ) ) ;
static void DeStateSignatureAppend ( DetectEngineState * state , Signature * s ,
SigMatch * sm , uint32_t inspect_flags ,
uint8_t direction )
return d ;
}
static void DeStateSignatureAppend ( DetectEngineState * state , Signature * s , uint32_t inspect_flags , uint8_t direction )
{
int jump = 0 ;
int i = 0 ;
@ -128,19 +157,56 @@ static void DeStateSignatureAppend(DetectEngineState *state, Signature *s,
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 )
static void DeStateFlowRuleAppend ( DetectEngineStateFlow * state , Signature * s ,
SigMatch * sm , uint32_t inspect_flags ,
uint8_t direction )
{
de_state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . alversion = alversion ;
int jump = 0 ;
int i = 0 ;
DetectEngineStateDirectionFlow * dir_state = & state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] ;
DeStateStoreFlowRules * store = dir_state - > head ;
if ( store = = NULL ) {
store = DeStateStoreFlowRulesAlloc ( ) ;
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 = DeStateStoreFlowRulesAlloc ( ) ;
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 ( Flow * f ,
uint16_t alversion , uint8_t direction )
{
f - > detect_alversion [ direction & STREAM_TOSERVER ? 0 : 1 ] = alversion ;
}
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 ;
@ -166,6 +232,16 @@ DetectEngineState *DetectEngineStateAlloc(void)
return d ;
}
DetectEngineStateFlow * DetectEngineStateFlowAlloc ( void )
{
DetectEngineStateFlow * d = SCMalloc ( sizeof ( DetectEngineStateFlow ) ) ;
if ( unlikely ( d = = NULL ) )
return NULL ;
memset ( d , 0 , sizeof ( DetectEngineStateFlow ) ) ;
return d ;
}
void DetectEngineStateFree ( DetectEngineState * state )
{
DeStateStore * store ;
@ -185,7 +261,65 @@ void DetectEngineStateFree(DetectEngineState *state)
return ;
}
/**
void DetectEngineStateFlowFree ( DetectEngineStateFlow * state )
{
DeStateStoreFlowRules * store ;
DeStateStoreFlowRules * 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 ;
}
static int HasStoredSigs ( Flow * f , uint8_t flags )
{
if ( f - > de_state ! = NULL & & f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . cnt ! = 0 ) {
SCLogDebug ( " global sigs present " ) ;
return 1 ;
}
if ( AppLayerParserProtocolSupportsTxs ( f - > proto , f - > alproto ) ) {
AppProto alproto = f - > alproto ;
void * alstate = FlowGetAppState ( f ) ;
if ( ! StateIsValid ( f - > alproto , alstate ) ) {
return 0 ;
}
uint64_t inspect_tx_id = AppLayerParserGetTransactionInspectId ( f - > alparser , flags ) ;
uint64_t total_txs = AppLayerParserGetTxCnt ( f - > proto , alproto , alstate ) ;
for ( ; inspect_tx_id < total_txs ; inspect_tx_id + + ) {
void * inspect_tx = AppLayerParserGetTx ( f - > proto , alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx ! = NULL ) {
DetectEngineState * tx_de_state = AppLayerParserGetTxDetectState ( f - > proto , alproto , inspect_tx ) ;
if ( tx_de_state = = NULL ) {
continue ;
}
if ( tx_de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . cnt ! = 0 ) {
SCLogDebug ( " tx %u has sigs present " , ( uint ) inspect_tx_id ) ;
return 1 ;
}
}
}
}
return 0 ;
}
/** \brief Check if we need to inspect this state
*
* State needs to be inspected if :
* 1. state has been updated
* 2. we already have de_state in progress
*
* \ retval 0 no inspectable state
* \ retval 1 inspectable state
* \ retval 2 inspectable state , but no update
@ -194,49 +328,97 @@ int DeStateFlowHasInspectableState(Flow *f, AppProto alproto, uint16_t alversion
{
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 ( AppLayerParserProtocolSupportsTxs ( f - > proto , alproto ) ) {
FLOWLOCK_RDLOCK ( f ) ;
if ( f - > alparser ! = NULL & & f - > alstate ! = NULL ) {
if ( AppLayerParserGetTransactionInspectId ( f - > alparser , flags ) > =
AppLayerParserGetTxCnt ( f - > proto , alproto , f - > alstate ) ) {
r = 2 ;
}
}
FLOWLOCK_UNLOCK ( f ) ;
}
} else if ( ! ( flags & STREAM_EOF ) & &
f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . alversion = = alversion ) {
FLOWLOCK_WRLOCK ( f ) ;
if ( ! ( flags & STREAM_EOF ) & & f - > de_state & &
f - > detect_alversion [ flags & STREAM_TOSERVER ? 0 : 1 ] = = alversion ) {
SCLogDebug ( " unchanged state " ) ;
r = 2 ;
} else {
} else if ( HasStoredSigs ( f , flags ) ) {
r = 1 ;
} else {
r = 0 ;
}
SCMutexUnlock ( & f - > de_state_m ) ;
FLOWLOCK_UNLOCK ( f ) ;
return r ;
}
static inline int StateIsValid ( uint16_t alproto , void * alstate )
static int StoreState ( DetectEngineThreadCtx * det_ctx ,
Flow * f , const uint8_t flags , const uint16_t alversion ,
Signature * s , SigMatch * sm , const uint32_t inspect_flags ,
const uint16_t file_no_match )
{
if ( alstate ! = NULL ) {
if ( alproto = = ALPROTO_HTTP ) {
HtpState * htp_state = ( HtpState * ) alstate ;
if ( htp_state - > conn ! = NULL ) {
return 1 ;
if ( f - > de_state = = NULL ) {
f - > de_state = DetectEngineStateFlowAlloc ( ) ;
if ( f - > de_state = = NULL ) {
return 0 ;
}
}
DeStateFlowRuleAppend ( f - > de_state , s , sm , inspect_flags , flags ) ;
DeStateStoreStateVersion ( f , alversion , flags ) ;
return 1 ;
}
static void StoreStateTxHandleFiles ( DetectEngineThreadCtx * det_ctx , Flow * f ,
DetectEngineState * destate , const uint8_t flags ,
const uint64_t tx_id , const uint16_t file_no_match )
{
DeStateStoreFileNoMatchCnt ( destate , file_no_match , flags ) ;
if ( DeStateStoreFilestoreSigsCantMatch ( det_ctx - > sgh , destate , flags ) = = 1 ) {
FileDisableStoringForTransaction ( f , flags & ( STREAM_TOCLIENT | STREAM_TOSERVER ) , tx_id ) ;
destate - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] . flags | = DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED ;
}
}
static void StoreStateTxFileOnly ( DetectEngineThreadCtx * det_ctx ,
Flow * f , const uint8_t flags , const uint64_t tx_id , void * tx ,
const uint16_t file_no_match )
{
if ( AppLayerParserSupportsTxDetectState ( f - > proto , f - > alproto ) ) {
DetectEngineState * destate = AppLayerParserGetTxDetectState ( f - > proto , f - > alproto , tx ) ;
if ( destate = = NULL ) {
destate = DetectEngineStateAlloc ( ) ;
if ( destate = = NULL )
return ;
if ( AppLayerParserSetTxDetectState ( f - > proto , f - > alproto , tx , destate ) < 0 ) {
DetectEngineStateFree ( destate ) ;
BUG_ON ( 1 ) ;
return ;
}
} else {
return 1 ;
SCLogDebug ( " destate created for % " PRIu64 , tx_id ) ;
}
StoreStateTxHandleFiles ( det_ctx , f , destate , flags , tx_id , file_no_match ) ;
}
return 0 ;
}
static inline int TxIsLast ( uint64_t tx_id , uint64_t total_txs )
static void StoreStateTx ( DetectEngineThreadCtx * det_ctx ,
Flow * f , const uint8_t flags , const uint16_t alversion ,
const uint64_t tx_id , void * tx ,
Signature * s , SigMatch * sm ,
const uint32_t inspect_flags , const uint16_t file_no_match )
{
if ( total_txs - tx_id < = 1 )
return 1 ;
return 0 ;
if ( AppLayerParserSupportsTxDetectState ( f - > proto , f - > alproto ) ) {
DetectEngineState * destate = AppLayerParserGetTxDetectState ( f - > proto , f - > alproto , tx ) ;
if ( destate = = NULL ) {
destate = DetectEngineStateAlloc ( ) ;
if ( destate = = NULL )
return ;
if ( AppLayerParserSetTxDetectState ( f - > proto , f - > alproto , tx , destate ) < 0 ) {
DetectEngineStateFree ( destate ) ;
BUG_ON ( 1 ) ;
return ;
}
SCLogDebug ( " destate created for % " PRIu64 , tx_id ) ;
}
DeStateSignatureAppend ( destate , s , inspect_flags , flags ) ;
DeStateStoreStateVersion ( f , alversion , flags ) ;
StoreStateTxHandleFiles ( det_ctx , f , destate , flags , tx_id , file_no_match ) ;
}
SCLogDebug ( " Stored for TX % " PRIu64 , tx_id ) ;
}
int DeStateDetectStartDetection ( ThreadVars * tv , DetectEngineCtx * de_ctx ,
@ -247,23 +429,21 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
SigMatch * sm = NULL ;
uint16_t file_no_match = 0 ;
uint32_t inspect_flags = 0 ;
int store_de_state = 0 ;
uint8_t direction = ( flags & STREAM_TOSERVER ) ? 0 : 1 ;
int alert_cnt = 0 ;
FLOWLOCK_WRLOCK ( f ) ;
/* TX based matches (inspect engines) */
if ( AppLayerParserProtocolSupportsTxs ( f - > proto , alproto ) ) {
uint64_t tx_id = 0 ;
uint64_t total_txs = 0 ;
FLOWLOCK_WRLOCK ( f ) ;
void * alstate = FlowGetAppState ( f ) ;
if ( ! StateIsValid ( alproto , alstate ) ) {
FLOWLOCK_UNLOCK ( f ) ;
goto end ;
}
tx_id = AppLayerParserGetTransactionInspectId ( f - > alparser , flags ) ;
SCLogDebug ( " tx_id % " PRIu64 , tx_id ) ;
total_txs = AppLayerParserGetTxCnt ( f - > proto , alproto , alstate ) ;
SCLogDebug ( " total_txs % " PRIu64 , total_txs ) ;
@ -314,26 +494,31 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
/* if this is the last tx in our list, and it's incomplete: then
* we store the state so that ContinueDetection knows about it */
if ( TxIsLast ( tx_id , total_txs ) ) {
if ( AppLayerParserGetStateProgress ( f - > proto , alproto , tx , flags ) <
AppLayerParserGetStateProgressCompletionStatus ( f - > proto , alproto , flags ) ) {
store_de_state = 1 ;
if ( engine = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH )
int tx_is_done = ( AppLayerParserGetStateProgress ( f - > proto , alproto , tx , flags ) > =
AppLayerParserGetStateProgressCompletionStatus ( f - > proto , alproto , flags ) ) ;
if ( ( engine = = NULL & & total_matches > 0 ) | | ( inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH ) ) {
if ( ! ( TxIsLast ( tx_id , total_txs ) ) | | ! tx_is_done ) {
if ( engine = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
inspect_flags | = DE_STATE_FLAG_FULL_INSPECT ;
}
/* store */
StoreStateTx ( det_ctx , f , flags , alversion , tx_id , tx ,
s , sm , inspect_flags , file_no_match ) ;
} else {
StoreStateTxFileOnly ( det_ctx , f , flags , tx_id , tx , file_no_match ) ;
}
}
} /* for */
FLOWLOCK_UNLOCK ( f ) ;
/* DCERPC matches */
} else if ( s - > sm_lists [ DETECT_SM_LIST_DMATCH ] ! = NULL & &
( alproto = = ALPROTO_DCERPC | | alproto = = ALPROTO_SMB | |
alproto = = ALPROTO_SMB2 ) )
{
FLOWLOCK_WRLOCK ( f ) ;
void * alstate = FlowGetAppState ( f ) ;
if ( alstate = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
goto end ;
}
@ -363,18 +548,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
alert_cnt = 1 ;
}
}
FLOWLOCK_UNLOCK ( f ) ;
}
/* flow based matches */
KEYWORD_PROFILING_SET_LIST ( det_ctx , DETECT_SM_LIST_AMATCH ) ;
sm = s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ;
if ( sm ! = NULL ) {
/* RDLOCK would be nicer, but at least tlsstore needs
* write lock currently . */
FLOWLOCK_WRLOCK ( f ) ;
void * alstate = FlowGetAppState ( f ) ;
if ( alstate = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
goto end ;
}
@ -405,9 +586,7 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
}
}
}
FLOWLOCK_UNLOCK ( f ) ;
store_de_state = 1 ;
if ( sm = = NULL | | inspect_flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
if ( match = = 1 ) {
if ( ! ( s - > flags & SIG_FLAG_NOALERT ) ) {
@ -420,34 +599,14 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
}
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 ;
}
StoreState ( det_ctx , f , flags , alversion ,
s , sm , inspect_flags , file_no_match ) ;
}
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 :
FLOWLOCK_UNLOCK ( f ) ;
det_ctx - > tx_id = 0 ;
det_ctx - > tx_id_set = 0 ;
return alert_cnt ? 1 : 0 ;
@ -455,12 +614,12 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
static int DoInspectItem ( ThreadVars * tv ,
DetectEngineCtx * de_ctx , DetectEngineThreadCtx * det_ctx ,
const int alproto_supports_txs ,
DeStateStoreItem * item , const uint8_t dir_state_flags ,
Packet * p , Flow * f , AppProto alproto , uint8_t flags ,
const uint64_t inspect_tx_id , const uint64_t total_txs ,
uint16_t * file_no_match )
uint16_t * file_no_match , int inprogress , // is current tx in progress?
const int next_tx_no_progress ) // tx after current is still dormant
{
Signature * s = de_ctx - > sig_array [ item - > sid ] ;
@ -484,11 +643,7 @@ static int DoInspectItem(ThreadVars *tv,
}
if ( item - > flags & DE_STATE_FLAG_FULL_INSPECT ) {
if ( alproto_supports_txs ) {
if ( TxIsLast ( inspect_tx_id , total_txs ) ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
} else {
if ( TxIsLast ( inspect_tx_id , total_txs ) | | inprogress | | next_tx_no_progress ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
return 0 ;
@ -511,11 +666,7 @@ static int DoInspectItem(ThreadVars *tv,
item - > flags & = ~ DE_STATE_FLAG_FILE_TC_INSPECT ;
item - > flags & = ~ DE_STATE_FLAG_SIG_CANT_MATCH ;
} else {
if ( alproto_supports_txs ) {
if ( TxIsLast ( inspect_tx_id , total_txs ) ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
} else {
if ( TxIsLast ( inspect_tx_id , total_txs ) | | inprogress | | next_tx_no_progress ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
}
return 0 ;
@ -528,70 +679,105 @@ static int DoInspectItem(ThreadVars *tv,
RULE_PROFILING_START ( p ) ;
if ( alproto_supports_txs ) {
FLOWLOCK_WRLOCK ( f ) ;
void * alstate = FlowGetAppState ( f ) ;
if ( ! StateIsValid ( alproto , alstate ) ) {
FLOWLOCK_UNLOCK ( f ) ;
RULE_PROFILING_END ( det_ctx , s , 0 , p ) ;
return - 1 ;
}
void * alstate = FlowGetAppState ( f ) ;
if ( ! StateIsValid ( alproto , alstate ) ) {
RULE_PROFILING_END ( det_ctx , s , 0 , p ) ;
return - 1 ;
}
det_ctx - > tx_id = inspect_tx_id ;
det_ctx - > tx_id_set = 1 ;
DetectEngineAppInspectionEngine * engine = app_inspection_engine [ FlowGetProtoMapping ( f - > proto ) ] [ alproto ] [ ( flags & STREAM_TOSERVER ) ? 0 : 1 ] ;
void * inspect_tx = AppLayerParserGetTx ( f - > proto , alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
RULE_PROFILING_END ( det_ctx , s , 0 , p ) ;
return - 1 ;
}
det_ctx - > tx_id = inspect_tx_id ;
det_ctx - > tx_id_set = 1 ;
DetectEngineAppInspectionEngine * engine = app_inspection_engine [ FlowGetProtoMapping ( f - > proto ) ] [ alproto ] [ ( flags & STREAM_TOSERVER ) ? 0 : 1 ] ;
void * inspect_tx = AppLayerParserGetTx ( f - > proto , alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx = = NULL ) {
RULE_PROFILING_END ( det_ctx , s , 0 , p ) ;
return - 1 ;
}
while ( engine ! = NULL ) {
if ( ! ( item - > flags & engine - > inspect_flags ) & &
s - > sm_lists [ engine - > sm_list ] ! = NULL )
{
KEYWORD_PROFILING_SET_LIST ( det_ctx , engine - > sm_list ) ;
int match = engine - > Callback ( tv , de_ctx , det_ctx , s , f ,
flags , alstate , inspect_tx , inspect_tx_id ) ;
if ( match = = DETECT_ENGINE_INSPECT_SIG_MATCH ) {
inspect_flags | = engine - > inspect_flags ;
engine = engine - > next ;
total_matches + + ;
continue ;
} else if ( match = = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
} else if ( match = = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
( * file_no_match ) + + ;
}
break ;
while ( engine ! = NULL ) {
if ( ! ( item - > flags & engine - > inspect_flags ) & &
s - > sm_lists [ engine - > sm_list ] ! = NULL )
{
KEYWORD_PROFILING_SET_LIST ( det_ctx , engine - > sm_list ) ;
int match = engine - > Callback ( tv , de_ctx , det_ctx , s , f ,
flags , alstate , inspect_tx , inspect_tx_id ) ;
if ( match = = DETECT_ENGINE_INSPECT_SIG_MATCH ) {
inspect_flags | = engine - > inspect_flags ;
engine = engine - > next ;
total_matches + + ;
continue ;
} else if ( match = = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
} else if ( match = = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE ) {
inspect_flags | = DE_STATE_FLAG_SIG_CANT_MATCH ;
inspect_flags | = engine - > inspect_flags ;
( * file_no_match ) + + ;
}
engine = engine - > next ;
break ;
}
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 ;
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 ;
}
item - > flags | = inspect_flags ;
if ( TxIsLast ( inspect_tx_id , total_txs ) ) {
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 , inspect_tx_id ,
PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_TX ) ;
} else {
PACKET_UPDATE_ACTION ( p , s - > action ) ;
}
}
FLOWLOCK_UNLOCK ( f ) ;
DetectFlowvarProcessList ( det_ctx , f ) ;
return 1 ;
}
/** \internal
* \ brief Continue Detection for a single " flow " rule ( AMATCH )
*/
static int DoInspectFlowRule ( ThreadVars * tv ,
DetectEngineCtx * de_ctx , DetectEngineThreadCtx * det_ctx ,
DeStateStoreFlowRule * item , const uint8_t dir_state_flags ,
Packet * p , Flow * f , AppProto alproto , uint8_t flags )
{
if ( item - > flags & DE_STATE_FLAG_FULL_INSPECT ) {
if ( item - > flags & DE_STATE_FLAG_FULL_INSPECT ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
return 0 ;
}
}
/* check if a sig in state 'cant match' needs to be reconsidered
* as the result of a new file in the existing tx */
if ( item - > flags & DE_STATE_FLAG_SIG_CANT_MATCH ) {
det_ctx - > de_state_sig_array [ item - > sid ] = DE_STATE_MATCH_NO_NEW_STATE ;
return 0 ;
}
/* count AMATCH matches */
total_matches = 0 ;
uint8_t alert = 0 ;
uint32_t inspect_flags = 0 ;
int total_matches = 0 ;
SigMatch * sm = NULL ;
Signature * s = de_ctx - > sig_array [ item - > sid ] ;
RULE_PROFILING_START ( p ) ;
KEYWORD_PROFILING_SET_LIST ( det_ctx , DETECT_SM_LIST_AMATCH ) ;
if ( item - > nm ! = NULL ) {
/* RDLOCK would be nicer, but at least tlsstore needs
* write lock currently . */
FLOWLOCK_WRLOCK ( f ) ;
void * alstate = FlowGetAppState ( f ) ;
if ( alstate = = NULL ) {
FLOWLOCK_UNLOCK ( f ) ;
RULE_PROFILING_END ( det_ctx , s , 0 /* no match */ , p ) ;
return - 1 ;
}
@ -623,7 +809,6 @@ static int DoInspectItem(ThreadVars *tv,
total_matches + + ;
}
}
FLOWLOCK_UNLOCK ( f ) ;
}
if ( s - > sm_lists [ DETECT_SM_LIST_AMATCH ] ! = NULL ) {
@ -638,20 +823,13 @@ static int DoInspectItem(ThreadVars *tv,
item - > flags | = inspect_flags ;
item - > nm = sm ;
if ( TxIsLast ( inspect_tx_id , total_txs ) ) {
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 ) ) {
if ( alproto_supports_txs )
PacketAlertAppend ( det_ctx , s , p , inspect_tx_id ,
PACKET_ALERT_FLAG_STATE_MATCH | PACKET_ALERT_FLAG_TX ) ;
else
PacketAlertAppend ( det_ctx , s , p , 0 ,
PACKET_ALERT_FLAG_STATE_MATCH ) ;
PacketAlertAppend ( det_ctx , s , p , 0 ,
PACKET_ALERT_FLAG_STATE_MATCH ) ;
} else {
DetectSignatureApplyActions ( p , s ) ;
}
@ -671,83 +849,111 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
SigIntId state_cnt = 0 ;
uint64_t inspect_tx_id = 0 ;
uint64_t total_txs = 0 ;
uint8_t alproto_supports_txs = 0 ;
uint8_t reset_de_state = 0 ;
SCMutexLock( & f - > de_state_m ) ;
DetectEngineStateDirection * dir_state = & f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] ;
DeStateStore * store = dir_state - > head ;
FLOWLOCK_WRLOCK ( f ) ;
SCLogDebug ( " starting continue detection for packet % " PRIu64 , p - > pcap_cnt ) ;
if ( AppLayerParserProtocolSupportsTxs ( f - > proto , alproto ) ) {
FLOWLOCK_RDLOCK ( f ) ;
void * alstate = FlowGetAppState ( f ) ;
if ( ! StateIsValid ( alproto , alstate ) ) {
FLOWLOCK_UNLOCK ( f ) ;
SCMutexUnlock ( & f - > de_state_m ) ;
return ;
}
inspect_tx_id = AppLayerParserGetTransactionInspectId ( f - > alparser , flags ) ;
total_txs = AppLayerParserGetTxCnt ( f - > proto , alproto , alstate ) ;
void * inspect_tx = AppLayerParserGetTx ( f - > proto , alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx ! = NULL ) {
if ( AppLayerParserGetStateProgress ( f - > proto , alproto , inspect_tx , flags ) > =
AppLayerParserGetStateProgressCompletionStatus ( f - > proto , alproto , flags ) ) {
reset_de_state = 1 ;
}
}
FLOWLOCK_UNLOCK ( f ) ;
alproto_supports_txs = 1 ;
}
/* Loop through stored 'items' (stateful rules) and inspect them */
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 + + )
{
DeStateStoreItem * item = & store - > store [ store_cnt ] ;
int r = DoInspectItem ( tv , de_ctx , det_ctx , alproto_supports_txs ,
item , dir_state - > flags ,
p , f , alproto , flags ,
inspect_tx_id , total_txs ,
& file_no_match ) ;
if ( r < 0 ) {
goto end ;
for ( ; inspect_tx_id < total_txs ; inspect_tx_id + + ) {
int inspect_tx_inprogress = 0 ;
int next_tx_no_progress = 0 ;
void * inspect_tx = AppLayerParserGetTx ( f - > proto , alproto , alstate , inspect_tx_id ) ;
if ( inspect_tx ! = NULL ) {
int a = AppLayerParserGetStateProgress ( f - > proto , alproto , inspect_tx , flags ) ;
int b = AppLayerParserGetStateProgressCompletionStatus ( f - > proto , alproto , flags ) ;
if ( a < b ) {
inspect_tx_inprogress = 1 ;
}
SCLogDebug ( " tx % " PRIu64 " (% " PRIu64 " ) => %s " , inspect_tx_id , total_txs ,
inspect_tx_inprogress ? " in progress " : " done " ) ;
DetectEngineState * tx_de_state = AppLayerParserGetTxDetectState ( f - > proto , alproto , inspect_tx ) ;
if ( tx_de_state = = NULL ) {
SCLogDebug ( " NO STATE tx % " PRIu64 " (% " PRIu64 " ) " , inspect_tx_id , total_txs ) ;
continue ;
}
DetectEngineStateDirection * tx_dir_state = & tx_de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] ;
DeStateStore * tx_store = tx_dir_state - > head ;
/* see if we need to consider the next tx in our decision to add
* a sig to the ' no inspect array ' . */
if ( ! TxIsLast ( inspect_tx_id , total_txs ) ) {
void * next_inspect_tx = AppLayerParserGetTx ( f - > proto , alproto , alstate , inspect_tx_id + 1 ) ;
if ( next_inspect_tx ! = NULL ) {
int c = AppLayerParserGetStateProgress ( f - > proto , alproto , next_inspect_tx , flags ) ;
if ( c = = 0 ) {
next_tx_no_progress = 1 ;
}
}
}
/* Loop through stored 'items' (stateful rules) and inspect them */
state_cnt = 0 ;
for ( ; tx_store ! = NULL ; tx_store = tx_store - > next ) {
SCLogDebug ( " tx_store %p " , tx_store ) ;
for ( store_cnt = 0 ;
store_cnt < DE_STATE_CHUNK_SIZE & & state_cnt < tx_dir_state - > cnt ;
store_cnt + + , state_cnt + + )
{
DeStateStoreItem * item = & tx_store - > store [ store_cnt ] ;
int r = DoInspectItem ( tv , de_ctx , det_ctx ,
item , tx_dir_state - > flags ,
p , f , alproto , flags ,
inspect_tx_id , total_txs ,
& file_no_match , inspect_tx_inprogress , next_tx_no_progress ) ;
if ( r < 0 ) {
SCLogDebug ( " failed " ) ;
goto end ;
}
}
}
}
if ( inspect_tx_inprogress ) {
SCLogDebug ( " break out " ) ;
break ;
}
}
}
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 ) ;
/* continue on flow based state rules (AMATCH) */
if ( f - > de_state ! = NULL ) {
DetectEngineStateDirectionFlow * dir_state = & f - > de_state - > dir_state [ flags & STREAM_TOSERVER ? 0 : 1 ] ;
DeStateStoreFlowRules * store = dir_state - > head ;
/* Loop through stored 'items' (stateful rules) and inspect them */
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 + + )
{
DeStateStoreFlowRule * rule = & store - > store [ store_cnt ] ;
dir_state - > flags | = DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED ;
int r = DoInspectFlowRule ( tv , de_ctx , det_ctx ,
rule , dir_state - > flags ,
p , f , alproto , flags ) ;
if ( r < 0 ) {
goto end ;
}
}
}
DeStateStoreStateVersion ( f , alversion , flags ) ;
}
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 ) ;
FLOWLOCK_UNLOCK ( f ) ;
det_ctx - > tx_id = 0 ;
det_ctx - > tx_id_set = 0 ;
return ;
}
/** \brief update flow's inspection id's
*
* \ note it is possible that f - > alstate , f - > alparser are NULL */
@ -762,18 +968,15 @@ void DeStateUpdateInspectTransactionId(Flow *f, uint8_t direction)
return ;
}
void DetectEngineStateReset ( DetectEngineState * state , uint8_t direction )
void DetectEngineStateReset ( DetectEngineStateFlow * 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 ;
}
}
@ -825,39 +1028,39 @@ static int DeStateTest02(void)
uint8_t direction = STREAM_TOSERVER ;
s . num = 0 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 11 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 22 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 33 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 44 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 55 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 66 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 77 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 88 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 99 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 100 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 111 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 122 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 133 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 144 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 155 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 166 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head = = NULL ) {
goto end ;
@ -907,9 +1110,9 @@ static int DeStateTest03(void)
uint8_t direction = STREAM_TOSERVER ;
s . num = 11 ;
DeStateSignatureAppend ( state , & s , NULL , 0 , direction ) ;
DeStateSignatureAppend ( state , & s , 0 , direction ) ;
s . num = 22 ;
DeStateSignatureAppend ( state , & s , NULL , DE_STATE_FLAG_URI_INSPECT , direction ) ;
DeStateSignatureAppend ( state , & s , DE_STATE_FLAG_URI_INSPECT , direction ) ;
if ( state - > dir_state [ direction & STREAM_TOSERVER ? 0 : 1 ] . head = = NULL ) {
goto end ;