From e2eb9f8ede2a8b6a5ebd34b8565a4ac5f2c519c3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 25 Aug 2016 12:59:33 +0200 Subject: [PATCH] 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. --- src/detect-engine-prefilter-common.c | 54 +++++++++++++++++++++++----- src/detect-engine-prefilter-common.h | 32 +++++++++++++++++ 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/detect-engine-prefilter-common.c b/src/detect-engine-prefilter-common.c index 65c28131f9..e1bf0baa5a 100644 --- a/src/detect-engine-prefilter-common.c +++ b/src/detect-engine-prefilter-common.c @@ -22,13 +22,16 @@ typedef struct PrefilterPacketHeaderHashCtx_ { PrefilterPacketHeaderValue v1; + uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */ + uint16_t value; + uint32_t cnt; } PrefilterPacketHeaderHashCtx; static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen) { PrefilterPacketHeaderCtx *ctx = data; - uint64_t hash = ctx->v1.u64; + uint64_t hash = ctx->v1.u64 + ctx->type + ctx->value; hash %= ht->array_size; return hash; } @@ -38,7 +41,9 @@ static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1, { PrefilterPacketHeaderHashCtx *ctx1 = data1; 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) @@ -67,11 +72,29 @@ static void PrefilterPacketU8HashCtxFree(void *vctx) 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 */ static int SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, - PrefilterPacketHeaderValue v, uint32_t count, + PrefilterPacketHeaderHashCtx *hctx, _Bool (*Compare)(PrefilterPacketHeaderValue v, void *), void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)) { @@ -83,8 +106,11 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, if (ctx == NULL) return -1; - ctx->v1 = v; - ctx->sigs_cnt = count; + ctx->v1 = hctx->v1; + ctx->type = hctx->type; + ctx->value = hctx->value; + + ctx->sigs_cnt = hctx->cnt; ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId)); if (ctx->sigs_array == NULL) { SCFree(ctx); @@ -98,7 +124,13 @@ SetupEngineForPacketHeader(SigGroupHead *sgh, int sm_type, if (s->prefilter_sm == NULL || s->prefilter_sm->type != sm_type) 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); ctx->sigs_array[sig_offset] = s->num; 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, sigmatch_table[sm_type].name); return 0; @@ -228,8 +263,7 @@ static void SetupSingle(HashListTable *hash_table, PrefilterPacketHeaderHashCtx *ctx = HashListTableGetListData(hb); SetupEngineForPacketHeader(sgh, sm_type, - ctx->v1, ctx->cnt, - Compare, Match); + ctx, Compare, Match); } } @@ -321,6 +355,8 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, memset(&ctx, 0, sizeof(ctx)); Set(&ctx.v1, s->prefilter_sm->ctx); + GetExtraMatch(s, &ctx.type, &ctx.value); + PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0); if (rctx != 0) { rctx->cnt++; @@ -331,6 +367,8 @@ static int PrefilterSetupPacketHeaderCommon(SigGroupHead *sgh, int sm_type, Set(&actx->v1, s->prefilter_sm->ctx); actx->cnt = 1; + actx->type = ctx.type; + actx->value = ctx.value; int ret = HashListTableAdd(hash_table, actx, 0); if (ret != 0) { diff --git a/src/detect-engine-prefilter-common.h b/src/detect-engine-prefilter-common.h index 6867f90f32..6072b56c51 100644 --- a/src/detect-engine-prefilter-common.h +++ b/src/detect-engine-prefilter-common.h @@ -25,9 +25,17 @@ typedef union { uint64_t u64; } 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_ { PrefilterPacketHeaderValue v1; + uint16_t type; + uint16_t value; + /** rules to add when the flags are present */ uint32_t sigs_cnt; SigIntId *sigs_array; @@ -60,4 +68,28 @@ int PrefilterSetupPacketHeaderU8Hash(SigGroupHead *sgh, int sm_type, void (*Match)(DetectEngineThreadCtx *det_ctx, 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__ */