diff --git a/src/detect-icmp-id.c b/src/detect-icmp-id.c index 34be0d7bb4..820d276cf1 100644 --- a/src/detect-icmp-id.c +++ b/src/detect-icmp-id.c @@ -29,6 +29,7 @@ #include "detect.h" #include "detect-parse.h" +#include "detect-engine-prefilter-common.h" #include "detect-icmp-id.h" @@ -46,6 +47,8 @@ int DetectIcmpIdMatch(ThreadVars *, DetectEngineThreadCtx *, Packet *, Signature static int DetectIcmpIdSetup(DetectEngineCtx *, Signature *, char *); void DetectIcmpIdRegisterTests(void); void DetectIcmpIdFree(void *); +static int PrefilterSetupIcmpId(SigGroupHead *sgh); +static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s); /** * \brief Registration function for icode: icmp_id @@ -60,28 +63,18 @@ void DetectIcmpIdRegister (void) sigmatch_table[DETECT_ICMP_ID].Free = DetectIcmpIdFree; sigmatch_table[DETECT_ICMP_ID].RegisterTests = DetectIcmpIdRegisterTests; + sigmatch_table[DETECT_ICMP_ID].SupportsPrefilter = PrefilterIcmpIdIsPrefilterable; + sigmatch_table[DETECT_ICMP_ID].SetupPrefilter = PrefilterSetupIcmpId; + DetectSetupParseRegexes(PARSE_REGEX, &parse_regex, &parse_regex_study); } -/** - * \brief This function is used to match icmp_id rule option set on a packet - * - * \param t pointer to thread vars - * \param det_ctx pointer to the pattern matcher thread - * \param p pointer to the current packet - * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData - * - * \retval 0 no match - * \retval 1 match - */ -int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +static inline _Bool GetIcmpId(Packet *p, uint16_t *id) { - uint16_t pid; - const DetectIcmpIdData *iid = (const DetectIcmpIdData *)ctx; - if (PKT_IS_PSEUDOPKT(p)) - return 0; + return FALSE; + uint16_t pid; if (PKT_IS_ICMPV4(p)) { switch (ICMPV4_GET_TYPE(p)){ case ICMP_ECHOREPLY: @@ -100,7 +93,7 @@ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, break; default: SCLogDebug("Packet has no id field"); - return 0; + return FALSE; } } else if (PKT_IS_ICMPV6(p)) { switch (ICMPV6_GET_TYPE(p)) { @@ -114,13 +107,36 @@ int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, break; default: SCLogDebug("Packet has no id field"); - return 0; + return FALSE; } } else { SCLogDebug("Packet not ICMPV4 nor ICMPV6"); - return 0; + return FALSE; } + *id = pid; + return TRUE; +} + +/** + * \brief This function is used to match icmp_id rule option set on a packet + * + * \param t pointer to thread vars + * \param det_ctx pointer to the pattern matcher thread + * \param p pointer to the current packet + * \param m pointer to the sigmatch that we will cast into DetectIcmpIdData + * + * \retval 0 no match + * \retval 1 match + */ +int DetectIcmpIdMatch (ThreadVars *t, DetectEngineThreadCtx *det_ctx, Packet *p, Signature *s, const SigMatchCtx *ctx) +{ + uint16_t pid; + + if (GetIcmpId(p, &pid) == FALSE) + return 0; + + const DetectIcmpIdData *iid = (const DetectIcmpIdData *)ctx; if (pid == iid->id) return 1; @@ -247,6 +263,60 @@ void DetectIcmpIdFree (void *ptr) SCFree(iid); } +/* prefilter code */ + +static void +PrefilterPacketIcmpIdMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + uint16_t pid; + if (GetIcmpId(p, &pid) == FALSE) + return; + + if (pid == ctx->v1.u16[0]) + { + SCLogDebug("packet matches ICMP ID %u", ctx->v1.u16[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static void +PrefilterPacketIcmpIdSet(PrefilterPacketHeaderValue *v, void *smctx) +{ + const DetectIcmpIdData *a = smctx; + v->u16[0] = a->id; +} + +static _Bool +PrefilterPacketIcmpIdCompare(PrefilterPacketHeaderValue v, void *smctx) +{ + const DetectIcmpIdData *a = smctx; + if (v.u16[0] == a->id) + return TRUE; + return FALSE; +} + +static int PrefilterSetupIcmpId(SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(sgh, DETECT_ICMP_ID, + PrefilterPacketIcmpIdSet, + PrefilterPacketIcmpIdCompare, + PrefilterPacketIcmpIdMatch); +} + +static _Bool PrefilterIcmpIdIsPrefilterable(const Signature *s) +{ + const SigMatch *sm; + for (sm = s->sm_lists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { + switch (sm->type) { + case DETECT_ICMP_ID: + return TRUE; + } + } + return FALSE; +} + #ifdef UNITTESTS #include "detect-engine.h" #include "detect-engine-mpm.h"