|
|
|
|
@ -364,144 +364,144 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
|
|
|
|
|
const Signature *s, Packet *p, Flow *f, uint8_t flags,
|
|
|
|
|
AppProto alproto)
|
|
|
|
|
{
|
|
|
|
|
SCLogDebug("rule %u", s->id);
|
|
|
|
|
|
|
|
|
|
/* TX based matches (inspect engines) */
|
|
|
|
|
if (unlikely(!AppLayerParserProtocolSupportsTxs(f->proto, alproto))) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
void *alstate = FlowGetAppState(f);
|
|
|
|
|
if (unlikely(!StateIsValid(alproto, alstate))) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SigMatchData *smd = NULL;
|
|
|
|
|
uint16_t file_no_match = 0;
|
|
|
|
|
uint32_t inspect_flags = 0;
|
|
|
|
|
int alert_cnt = 0;
|
|
|
|
|
uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1;
|
|
|
|
|
int check_before_add = 0;
|
|
|
|
|
uint64_t tx_id = 0;
|
|
|
|
|
uint64_t total_txs = 0;
|
|
|
|
|
|
|
|
|
|
SCLogDebug("rule %u", s->id);
|
|
|
|
|
|
|
|
|
|
/* TX based matches (inspect engines) */
|
|
|
|
|
if (AppLayerParserProtocolSupportsTxs(f->proto, alproto)) {
|
|
|
|
|
uint8_t direction = (flags & STREAM_TOSERVER) ? 0 : 1;
|
|
|
|
|
int check_before_add = 0;
|
|
|
|
|
uint64_t tx_id = 0;
|
|
|
|
|
uint64_t total_txs = 0;
|
|
|
|
|
|
|
|
|
|
void *alstate = FlowGetAppState(f);
|
|
|
|
|
if (!StateIsValid(alproto, alstate)) {
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
/* if continue detection already inspected this rule for this tx,
|
|
|
|
|
* continue with the first not-inspected tx */
|
|
|
|
|
uint8_t offset = det_ctx->de_state_sig_array[s->num] & 0xef;
|
|
|
|
|
tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags);
|
|
|
|
|
if (offset > 0) {
|
|
|
|
|
SCLogDebug("using stored_tx_id %u instead of %u", (uint)tx_id+offset, (uint)tx_id);
|
|
|
|
|
tx_id += offset;
|
|
|
|
|
}
|
|
|
|
|
if (offset == MAX_STORED_TXID_OFFSET) {
|
|
|
|
|
check_before_add = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if continue detection already inspected this rule for this tx,
|
|
|
|
|
* continue with the first not-inspected tx */
|
|
|
|
|
uint8_t offset = det_ctx->de_state_sig_array[s->num] & 0xef;
|
|
|
|
|
tx_id = AppLayerParserGetTransactionInspectId(f->alparser, flags);
|
|
|
|
|
if (offset > 0) {
|
|
|
|
|
SCLogDebug("using stored_tx_id %u instead of %u", (uint)tx_id+offset, (uint)tx_id);
|
|
|
|
|
tx_id += offset;
|
|
|
|
|
}
|
|
|
|
|
if (offset == MAX_STORED_TXID_OFFSET) {
|
|
|
|
|
check_before_add = 1;
|
|
|
|
|
}
|
|
|
|
|
total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate);
|
|
|
|
|
SCLogDebug("total_txs %"PRIu64, total_txs);
|
|
|
|
|
|
|
|
|
|
total_txs = AppLayerParserGetTxCnt(f->proto, alproto, alstate);
|
|
|
|
|
SCLogDebug("total_txs %"PRIu64, total_txs);
|
|
|
|
|
SCLogDebug("starting: start tx %u, packet %u", (uint)tx_id, (uint)p->pcap_cnt);
|
|
|
|
|
|
|
|
|
|
SCLogDebug("starting: start tx %u, packet %u", (uint)tx_id, (uint)p->pcap_cnt);
|
|
|
|
|
for (; tx_id < total_txs; tx_id++) {
|
|
|
|
|
int total_matches = 0;
|
|
|
|
|
void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id);
|
|
|
|
|
SCLogDebug("tx %p", tx);
|
|
|
|
|
if (tx == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
det_ctx->tx_id = tx_id;
|
|
|
|
|
det_ctx->tx_id_set = 1;
|
|
|
|
|
|
|
|
|
|
for (; tx_id < total_txs; tx_id++) {
|
|
|
|
|
int total_matches = 0;
|
|
|
|
|
void *tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id);
|
|
|
|
|
SCLogDebug("tx %p", tx);
|
|
|
|
|
if (tx == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
det_ctx->tx_id = tx_id;
|
|
|
|
|
det_ctx->tx_id_set = 1;
|
|
|
|
|
|
|
|
|
|
DetectEngineAppInspectionEngine *engine = s->app_inspect;
|
|
|
|
|
DetectEngineAppInspectionEngine *engine = s->app_inspect;
|
|
|
|
|
SCLogDebug("engine %p", engine);
|
|
|
|
|
inspect_flags = 0;
|
|
|
|
|
while (engine != NULL) {
|
|
|
|
|
SCLogDebug("engine %p", engine);
|
|
|
|
|
inspect_flags = 0;
|
|
|
|
|
while (engine != NULL) {
|
|
|
|
|
SCLogDebug("engine %p", engine);
|
|
|
|
|
SCLogDebug("inspect_flags %x", inspect_flags);
|
|
|
|
|
if (direction == engine->dir) {
|
|
|
|
|
KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list);
|
|
|
|
|
int match = engine->Callback(tv, de_ctx, det_ctx,
|
|
|
|
|
s, engine->smd, f, flags, alstate, tx, tx_id);
|
|
|
|
|
SCLogDebug("engine %p match %d", engine, match);
|
|
|
|
|
if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) {
|
|
|
|
|
inspect_flags |= BIT_U32(engine->id);
|
|
|
|
|
engine = engine->next;
|
|
|
|
|
total_matches++;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) {
|
|
|
|
|
/* if the file engine matched, but indicated more
|
|
|
|
|
* files are still in progress, we don't set inspect
|
|
|
|
|
* flags as these would end inspection for this tx */
|
|
|
|
|
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 |= BIT_U32(engine->id);;
|
|
|
|
|
} else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) {
|
|
|
|
|
inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
|
|
|
|
|
inspect_flags |= BIT_U32(engine->id);
|
|
|
|
|
file_no_match++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
engine = engine->next;
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("inspect_flags %x", inspect_flags);
|
|
|
|
|
/* 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) {
|
|
|
|
|
if (!(s->flags & SIG_FLAG_NOALERT)) {
|
|
|
|
|
PacketAlertAppend(det_ctx, s, p, tx_id,
|
|
|
|
|
PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX);
|
|
|
|
|
} else {
|
|
|
|
|
DetectSignatureApplyActions(p, s);
|
|
|
|
|
if (direction == engine->dir) {
|
|
|
|
|
KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list);
|
|
|
|
|
int match = engine->Callback(tv, de_ctx, det_ctx,
|
|
|
|
|
s, engine->smd, f, flags, alstate, tx, tx_id);
|
|
|
|
|
SCLogDebug("engine %p match %d", engine, match);
|
|
|
|
|
if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) {
|
|
|
|
|
inspect_flags |= BIT_U32(engine->id);
|
|
|
|
|
engine = engine->next;
|
|
|
|
|
total_matches++;
|
|
|
|
|
continue;
|
|
|
|
|
} else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) {
|
|
|
|
|
/* if the file engine matched, but indicated more
|
|
|
|
|
* files are still in progress, we don't set inspect
|
|
|
|
|
* flags as these would end inspection for this tx */
|
|
|
|
|
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 |= BIT_U32(engine->id);
|
|
|
|
|
} else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILESTORE) {
|
|
|
|
|
inspect_flags |= DE_STATE_FLAG_SIG_CANT_MATCH;
|
|
|
|
|
inspect_flags |= BIT_U32(engine->id);
|
|
|
|
|
file_no_match++;
|
|
|
|
|
}
|
|
|
|
|
alert_cnt = 1;
|
|
|
|
|
SCLogDebug("MATCH: tx %u packet %u", (uint)tx_id, (uint)p->pcap_cnt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
engine = engine->next;
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("inspect_flags %x", inspect_flags);
|
|
|
|
|
/* 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) {
|
|
|
|
|
if (!(s->flags & SIG_FLAG_NOALERT)) {
|
|
|
|
|
PacketAlertAppend(det_ctx, s, p, tx_id,
|
|
|
|
|
PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_TX);
|
|
|
|
|
} else {
|
|
|
|
|
DetectSignatureApplyActions(p, s);
|
|
|
|
|
}
|
|
|
|
|
alert_cnt = 1;
|
|
|
|
|
SCLogDebug("MATCH: tx %u packet %u", (uint)tx_id, (uint)p->pcap_cnt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if this is the last tx in our list, and it's incomplete: then
|
|
|
|
|
* we store the state so that ContinueDetection knows about it */
|
|
|
|
|
int tx_is_done = (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) >=
|
|
|
|
|
AppLayerParserGetStateProgressCompletionStatus(alproto, flags));
|
|
|
|
|
/* see if we need to consider the next tx in our decision to add
|
|
|
|
|
* a sig to the 'no inspect array'. */
|
|
|
|
|
int next_tx_no_progress = 0;
|
|
|
|
|
if (!TxIsLast(tx_id, total_txs)) {
|
|
|
|
|
void *next_tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id+1);
|
|
|
|
|
if (next_tx != NULL) {
|
|
|
|
|
int c = AppLayerParserGetStateProgress(f->proto, alproto, next_tx, flags);
|
|
|
|
|
if (c == 0) {
|
|
|
|
|
next_tx_no_progress = 1;
|
|
|
|
|
}
|
|
|
|
|
/* if this is the last tx in our list, and it's incomplete: then
|
|
|
|
|
* we store the state so that ContinueDetection knows about it */
|
|
|
|
|
int tx_is_done = (AppLayerParserGetStateProgress(f->proto, alproto, tx, flags) >=
|
|
|
|
|
AppLayerParserGetStateProgressCompletionStatus(alproto, flags));
|
|
|
|
|
/* see if we need to consider the next tx in our decision to add
|
|
|
|
|
* a sig to the 'no inspect array'. */
|
|
|
|
|
int next_tx_no_progress = 0;
|
|
|
|
|
if (!TxIsLast(tx_id, total_txs)) {
|
|
|
|
|
void *next_tx = AppLayerParserGetTx(f->proto, alproto, alstate, tx_id+1);
|
|
|
|
|
if (next_tx != NULL) {
|
|
|
|
|
int c = AppLayerParserGetStateProgress(f->proto, alproto, next_tx, flags);
|
|
|
|
|
if (c == 0) {
|
|
|
|
|
next_tx_no_progress = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCLogDebug("tx %u, packet %u, rule %u, alert_cnt %u, last tx %d, tx_is_done %d, next_tx_no_progress %d",
|
|
|
|
|
(uint)tx_id, (uint)p->pcap_cnt, s->num, alert_cnt,
|
|
|
|
|
TxIsLast(tx_id, total_txs), tx_is_done, next_tx_no_progress);
|
|
|
|
|
|
|
|
|
|
/* if we have something to store (partial match or file store info),
|
|
|
|
|
* then we do it now. */
|
|
|
|
|
if (inspect_flags != 0) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
SCLogDebug("tx %u, packet %u, rule %u, alert_cnt %u, last tx %d, tx_is_done %d, next_tx_no_progress %d",
|
|
|
|
|
(uint)tx_id, (uint)p->pcap_cnt, s->num, alert_cnt,
|
|
|
|
|
TxIsLast(tx_id, total_txs), tx_is_done, next_tx_no_progress);
|
|
|
|
|
|
|
|
|
|
/* store */
|
|
|
|
|
StoreStateTx(det_ctx, f, flags, tx_id, tx,
|
|
|
|
|
s, smd, inspect_flags, file_no_match, check_before_add);
|
|
|
|
|
} else {
|
|
|
|
|
StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match);
|
|
|
|
|
/* if we have something to store (partial match or file store info),
|
|
|
|
|
* then we do it now. */
|
|
|
|
|
if (inspect_flags != 0) {
|
|
|
|
|
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, tx_id, tx,
|
|
|
|
|
s, smd, inspect_flags, file_no_match, check_before_add);
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug("no state to store");
|
|
|
|
|
StoreStateTxFileOnly(det_ctx, f, flags, tx_id, tx, file_no_match);
|
|
|
|
|
}
|
|
|
|
|
if (next_tx_no_progress)
|
|
|
|
|
break;
|
|
|
|
|
} /* for */
|
|
|
|
|
}
|
|
|
|
|
end:
|
|
|
|
|
} else {
|
|
|
|
|
SCLogDebug("no state to store");
|
|
|
|
|
}
|
|
|
|
|
if (next_tx_no_progress)
|
|
|
|
|
break;
|
|
|
|
|
} /* for */
|
|
|
|
|
|
|
|
|
|
det_ctx->tx_id = 0;
|
|
|
|
|
det_ctx->tx_id_set = 0;
|
|
|
|
|
return alert_cnt ? 1:0;
|
|
|
|
|
|