detect: pkt inspect engines

Instead of hard coded calls to the inspection logic for
payload inspection and 'MATCH'-list inspection use a callback
approach. This will register a callback per 'sm_list' much like
how app-layer inspect engines are registered.

This will allow for adding more types later without adding
runtime overhead.

Implement the callback for the PMATCH and MATCH logic.
pull/3963/head
Victor Julien 7 years ago
parent 2a778e439a
commit 0965afd661

@ -1845,6 +1845,9 @@ static int SigMatchPrepare(DetectEngineCtx *de_ctx)
SigMatch *sm = s->init_data->smlists[type];
s->sm_arrays[type] = SigMatchList2DataArray(sm);
}
/* set up the pkt inspection engines */
DetectEnginePktInspectionSetup(s);
if (rule_engine_analysis_set) {
#ifdef HAVE_LIBJANSSON
EngineAnalysisRules2(de_ctx, s);

@ -1116,6 +1116,148 @@ int DetectBufferTypeGetByIdTransforms(DetectEngineCtx *de_ctx, const int id,
return map->id;
}
/* returns false if no match, true if match */
static bool DetectEngineInspectRulePacketMatches(
ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
const Signature *s, const SigMatchData *sm_data,
Flow *f, Packet *p,
uint8_t *alert_flags)
{
SCEnter();
BUG_ON(sm_data != s->sm_arrays[DETECT_SM_LIST_MATCH]);
/* run the packet match functions */
KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
const SigMatchData *smd = sm_data;
SCLogDebug("running match functions, sm %p", smd);
while (1) {
KEYWORD_PROFILING_START;
if (sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx) <= 0) {
KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
SCLogDebug("no match");
return false;
}
KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
if (smd->is_last) {
SCLogDebug("match and is_last");
break;
}
smd++;
}
return true;
}
static bool DetectEngineInspectRulePayloadMatches(
ThreadVars *tv, DetectEngineThreadCtx *det_ctx,
const Signature *s, const SigMatchData *sm_data,
Flow *f, Packet *p,
uint8_t *alert_flags)
{
SCEnter();
BUG_ON(alert_flags == NULL);
DetectEngineCtx *de_ctx = det_ctx->de_ctx;
KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH);
/* if we have stream msgs, inspect against those first,
* but not for a "dsize" signature */
if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
int pmatch = 0;
if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, f, p);
if (pmatch) {
det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH;
/* Tell the engine that this reassembled stream can drop the
* rest of the pkts with no further inspection */
if (s->action & ACTION_DROP)
*alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
*alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH;
}
}
/* no match? then inspect packet payload */
if (pmatch == 0) {
SCLogDebug("no match in stream, fall back to packet payload");
/* skip if we don't have to inspect the packet and segment was
* added to stream */
if (!(s->flags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) {
return false;
}
if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, f, p) != 1) {
return false;
}
}
} else {
if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, f, p) != 1) {
return false;
}
}
return true;
}
bool DetectEnginePktInspectionRun(ThreadVars *tv,
DetectEngineThreadCtx *det_ctx, const Signature *s,
Flow *f, Packet *p,
uint8_t *alert_flags)
{
SCEnter();
for (DetectEnginePktInspectionEngine *e = s->pkt_inspect; e != NULL; e = e->next) {
if (e->Callback(tv, det_ctx, s, e->sm_data, f, p, alert_flags) == false) {
SCLogDebug("sid %u: e %p Callback returned false", s->id, e);
return false;
}
SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
}
SCLogDebug("sid %u: returning true", s->id);
return true;
}
static int DetectEnginePktInspectionAppend(Signature *s,
DetectEnginePktInspectionFunc Callback,
SigMatchData *data)
{
DetectEnginePktInspectionEngine *e = SCCalloc(1, sizeof(*e));
if (e == NULL)
return -1;
e->Callback = Callback;
e->sm_data = data;
if (s->pkt_inspect == NULL) {
s->pkt_inspect = e;
} else {
DetectEnginePktInspectionEngine *a = s->pkt_inspect;
while (a->next != NULL) {
a = a->next;
}
a->next = e;
}
return 0;
}
int DetectEnginePktInspectionSetup(Signature *s)
{
/* only handle PMATCH here if we're not an app inspect rule */
if (s->sm_arrays[DETECT_SM_LIST_PMATCH] && (s->init_data->init_flags & SIG_FLAG_INIT_STATE_MATCH) == 0) {
if (DetectEnginePktInspectionAppend(s, DetectEngineInspectRulePayloadMatches,
s->sm_arrays[DETECT_SM_LIST_PMATCH]) < 0)
return -1;
SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id);
}
if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
if (DetectEnginePktInspectionAppend(s, DetectEngineInspectRulePacketMatches,
s->sm_arrays[DETECT_SM_LIST_MATCH]) < 0)
return -1;
SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id);
}
return 0;
}
/* code to control the main thread to do a reload */
enum DetectEngineSyncState {

@ -145,6 +145,12 @@ void DetectAppLayerInspectEngineRegister2(const char *name,
int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature *s);
void DetectEngineAppInspectionEngineSignatureFree(Signature *s);
bool DetectEnginePktInspectionRun(ThreadVars *tv,
DetectEngineThreadCtx *det_ctx, const Signature *s,
Flow *f, Packet *p,
uint8_t *alert_flags);
int DetectEnginePktInspectionSetup(Signature *s);
void DetectEngineSetParseMetadata(void);
void DetectEngineUnsetParseMetadata(void);
int DetectEngineMustParseMetadata(void);

@ -1369,6 +1369,15 @@ void SigFree(Signature *s)
DetectEngineAppInspectionEngineSignatureFree(s);
if (s->pkt_inspect) {
DetectEnginePktInspectionEngine *e = s->pkt_inspect;
while (e) {
DetectEnginePktInspectionEngine *next = e->next;
SCFree(e);
e = next;
}
}
SCFree(s);
}

@ -658,38 +658,6 @@ static inline int DetectRunInspectRuleHeader(
return 1;
}
/* returns 0 if no match, 1 if match */
static inline int DetectRunInspectRulePacketMatches(
ThreadVars *tv,
DetectEngineThreadCtx *det_ctx,
Packet *p,
const Flow *f,
const Signature *s)
{
/* run the packet match functions */
if (s->sm_arrays[DETECT_SM_LIST_MATCH] != NULL) {
KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_MATCH);
SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
SCLogDebug("running match functions, sm %p", smd);
while (1) {
KEYWORD_PROFILING_START;
if (sigmatch_table[smd->type].Match(tv, det_ctx, p, s, smd->ctx) <= 0) {
KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
SCLogDebug("no match");
return 0;
}
KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
if (smd->is_last) {
SCLogDebug("match and is_last");
break;
}
smd++;
}
}
return 1;
}
/** \internal
* \brief run packet/stream prefilter engines
*/
@ -827,49 +795,9 @@ static inline void DetectRulePacketRules(
goto next;
}
/* Check the payload keywords. If we are a MPM sig and we've made
* to here, we've had at least one of the patterns match */
if (s->sm_arrays[DETECT_SM_LIST_PMATCH] != NULL) {
KEYWORD_PROFILING_SET_LIST(det_ctx, DETECT_SM_LIST_PMATCH);
/* if we have stream msgs, inspect against those first,
* but not for a "dsize" signature */
if (sflags & SIG_FLAG_REQUIRE_STREAM) {
int pmatch = 0;
if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, pflow, p);
if (pmatch) {
det_ctx->flags |= DETECT_ENGINE_THREAD_CTX_STREAM_CONTENT_MATCH;
/* Tell the engine that this reassembled stream can drop the
* rest of the pkts with no further inspection */
if (s->action & ACTION_DROP)
alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH;
}
}
/* no match? then inspect packet payload */
if (pmatch == 0) {
SCLogDebug("no match in stream, fall back to packet payload");
/* skip if we don't have to inspect the packet and segment was
* added to stream */
if (!(sflags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) {
goto next;
}
if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) {
goto next;
}
}
} else {
if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, pflow, p) != 1) {
goto next;
}
}
}
if (DetectRunInspectRulePacketMatches(tv, det_ctx, p, pflow, s) == 0)
if (DetectEnginePktInspectionRun(tv, det_ctx, s, pflow, p, &alert_flags) == false) {
goto next;
}
#ifdef PROFILING
smatch = true;
@ -1154,8 +1082,8 @@ static bool DetectRunTxInspectRule(ThreadVars *tv,
TRACE_SID_TXS(s->id, tx, "DetectRunInspectRuleHeader() no match");
return false;
}
if (DetectRunInspectRulePacketMatches(tv, det_ctx, p, f, s) == 0) {
TRACE_SID_TXS(s->id, tx, "DetectRunInspectRulePacketMatches no match");
if (DetectEnginePktInspectionRun(tv, det_ctx, s, f, p, NULL) == false) {
TRACE_SID_TXS(s->id, tx, "DetectEnginePktInspectionRun no match");
return false;
}
/* stream mpm and negated mpm sigs can end up here with wrong proto */

@ -438,6 +438,23 @@ typedef struct DetectBufferType_ {
DetectEngineTransforms transforms;
} DetectBufferType;
/* Function pointer for the pkt inspect engines. Goal for this
* function will be to process the complete list of conditions
* passed to it through 'sm_data'. */
typedef bool (*DetectEnginePktInspectionFunc)(ThreadVars *,
struct DetectEngineThreadCtx_ *,
const struct Signature_ *s,
const struct SigMatchData_ *sm_data,
Flow *f,
Packet *p,
uint8_t *alert_flags);
typedef struct DetectEnginePktInspectionEngine {
DetectEnginePktInspectionFunc Callback;
SigMatchData *sm_data;
struct DetectEnginePktInspectionEngine *next;
} DetectEnginePktInspectionEngine;
#ifdef UNITTESTS
#define sm_lists init_data->smlists
#define sm_lists_tail init_data->smlists_tail
@ -542,6 +559,7 @@ typedef struct Signature_ {
IPOnlyCIDRItem *CidrSrc, *CidrDst;
DetectEngineAppInspectionEngine *app_inspect;
DetectEnginePktInspectionEngine *pkt_inspect;
/* Matching structures for the built-ins. The others are in
* their inspect engines. */

Loading…
Cancel
Save