prefilter: add 'extra match' logic to packet engines

Many of the packet engines are very generic. Rules are generally more
limited.

A rule like 'alert tcp any any -> any 888 (flags:S; sid:1;)' would still
be inspected against every SYN packet in most cases (it depends a bit on
rule grouping though).

This extra match logic adds an additional check to these packet engines.
It can add a check based on alproto, source port and dest port. It uses
only one of these 3. Priority order is src port > alproto > dst port.

For the ports only 'single' ports are used at this time.
pull/2310/head
Victor Julien 9 years ago
parent 9187c20782
commit e2eb9f8ede

@ -22,13 +22,16 @@
typedef struct PrefilterPacketHeaderHashCtx_ { typedef struct PrefilterPacketHeaderHashCtx_ {
PrefilterPacketHeaderValue v1; PrefilterPacketHeaderValue v1;
uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */
uint16_t value;
uint32_t cnt; uint32_t cnt;
} PrefilterPacketHeaderHashCtx; } PrefilterPacketHeaderHashCtx;
static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen) static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen)
{ {
PrefilterPacketHeaderCtx *ctx = data; PrefilterPacketHeaderCtx *ctx = data;
uint64_t hash = ctx->v1.u64; uint64_t hash = ctx->v1.u64 + ctx->type + ctx->value;
hash %= ht->array_size; hash %= ht->array_size;
return hash; return hash;
} }
@ -38,7 +41,9 @@ static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1,
{ {
PrefilterPacketHeaderHashCtx *ctx1 = data1; PrefilterPacketHeaderHashCtx *ctx1 = data1;
PrefilterPacketHeaderHashCtx *ctx2 = data2; PrefilterPacketHeaderHashCtx *ctx2 = data2;
return (ctx1->v1.u64 == ctx2->v1.u64); return (ctx1->v1.u64 == ctx2->v1.u64 &&
ctx1->type == ctx2->type &&
ctx1->value == ctx2->value);
} }
static void PrefilterPacketHeaderFreeFunc(void *ptr) static void PrefilterPacketHeaderFreeFunc(void *ptr)
@ -67,11 +72,29 @@ static void PrefilterPacketU8HashCtxFree(void *vctx)
SCFree(ctx); SCFree(ctx);
} }
static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value)
{
if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 &&
!(s->sp->flags & PORT_FLAG_NOT))
{
*type = PREFILTER_EXTRA_MATCH_SRCPORT;
*value = s->sp->port;
} else if (s->alproto != ALPROTO_UNKNOWN) {
*type = PREFILTER_EXTRA_MATCH_ALPROTO;
*value = s->alproto;
} else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 &&
!(s->dp->flags & PORT_FLAG_NOT))
{
*type = PREFILTER_EXTRA_MATCH_DSTPORT;
*value = s->dp->port;
}
}
/** \internal /** \internal
*/ */
static int static int
SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type,
PrefilterPacketHeaderValue v, uint32_t count, PrefilterPacketHeaderHashCtx *hctx,
_Bool (*Compare)(PrefilterPacketHeaderValue v, void *), _Bool (*Compare)(PrefilterPacketHeaderValue v, void *),
void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
{ {
@ -83,8 +106,11 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type,
if (ctx == NULL) if (ctx == NULL)
return -1; return -1;
ctx->v1 = v; ctx->v1 = hctx->v1;
ctx->sigs_cnt = count; ctx->type = hctx->type;
ctx->value = hctx->value;
ctx->sigs_cnt = hctx->cnt;
ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId)); ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId));
if (ctx->sigs_array == NULL) { if (ctx->sigs_array == NULL) {
SCFree(ctx); SCFree(ctx);
@ -98,7 +124,13 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type,
if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type)
continue; continue;
if (Compare(v, s->prefilter_sm->ctx)) { uint16_t type = 0;
uint16_t value = 0;
GetExtraMatch(s, &type, &value);
if (Compare(ctx->v1, s->prefilter_sm->ctx) &&
ctx->type == type && ctx->value == value)
{
SCLogDebug("appending sid %u on %u", s->id, sig_offset); SCLogDebug("appending sid %u on %u", s->id, sig_offset);
ctx->sigs_array[sig_offset] = s->num; ctx->sigs_array[sig_offset] = s->num;
sig_offset++; sig_offset++;
@ -107,6 +139,9 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type,
} }
} }
SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u",
sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value,
ctx->sigs_cnt);
PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree, PrefilterAppendEngine(sgh, Match, ctx, PrefilterPacketHeaderFree,
sigmatch_table[sm_type].name); sigmatch_table[sm_type].name);
return 0; return 0;
@ -228,8 +263,7 @@ static void SetupSingle(HashListTable *hash_table,
PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb);
SetupEngineForPacketHeader(sgh, sm_type, SetupEngineForPacketHeader(sgh, sm_type,
ctx->v1, ctx->cnt, ctx, Compare, Match);
Compare, Match);
} }
} }
@ -321,6 +355,8 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type,
memset(&ctx, 0, sizeof(ctx)); memset(&ctx, 0, sizeof(ctx));
Set(&ctx.v1, s->prefilter_sm->ctx); Set(&ctx.v1, s->prefilter_sm->ctx);
GetExtraMatch(s, &ctx.type, &ctx.value);
PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0); PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0);
if (rctx != 0) { if (rctx != 0) {
rctx->cnt++; rctx->cnt++;
@ -331,6 +367,8 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type,
Set(&actx->v1, s->prefilter_sm->ctx); Set(&actx->v1, s->prefilter_sm->ctx);
actx->cnt = 1; actx->cnt = 1;
actx->type = ctx.type;
actx->value = ctx.value;
int ret = HashListTableAdd(hash_table, actx, 0); int ret = HashListTableAdd(hash_table, actx, 0);
if (ret != 0) { if (ret != 0) {

@ -25,9 +25,17 @@ typedef union {
uint64_t u64; uint64_t u64;
} PrefilterPacketHeaderValue; } PrefilterPacketHeaderValue;
#define PREFILTER_EXTRA_MATCH_UNUSED 0
#define PREFILTER_EXTRA_MATCH_ALPROTO 1
#define PREFILTER_EXTRA_MATCH_SRCPORT 2
#define PREFILTER_EXTRA_MATCH_DSTPORT 3
typedef struct PrefilterPacketHeaderCtx_ { typedef struct PrefilterPacketHeaderCtx_ {
PrefilterPacketHeaderValue v1; PrefilterPacketHeaderValue v1;
uint16_t type;
uint16_t value;
/** rules to add when the flags are present */ /** rules to add when the flags are present */
uint32_t sigs_cnt; uint32_t sigs_cnt;
SigIntId *sigs_array; SigIntId *sigs_array;
@ -60,4 +68,28 @@ int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type,
void (*Match)(DetectEngineThreadCtx *det_ctx, void (*Match)(DetectEngineThreadCtx *det_ctx,
Packet *p, const void *pectx)); Packet *p, const void *pectx));
static inline _Bool
PrefilterPacketHeaderExtraMatch(const PrefilterPacketHeaderCtx *ctx,
const Packet *p)
{
switch (ctx->type)
{
case PREFILTER_EXTRA_MATCH_UNUSED:
break;
case PREFILTER_EXTRA_MATCH_ALPROTO:
if (p->flow == NULL || p->flow->alproto != ctx->value)
return FALSE;
break;
case PREFILTER_EXTRA_MATCH_SRCPORT:
if (p->sp != ctx->value)
return FALSE;
break;
case PREFILTER_EXTRA_MATCH_DSTPORT:
if (p->dp != ctx->value)
return FALSE;
break;
}
return TRUE;
}
#endif /* __DETECT_ENGINE_PREFILTER_COMMON_H__ */ #endif /* __DETECT_ENGINE_PREFILTER_COMMON_H__ */

Loading…
Cancel
Save