/* Copyright (C) 2007-2021 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ /** * \file * * \author Anoop Saldanha * * Implements the fast_pattern keyword */ #include "suricata-common.h" #include "detect.h" #include "flow.h" #include "detect-content.h" #include "detect-parse.h" #include "detect-engine.h" #include "detect-engine-mpm.h" #include "detect-engine-build.h" #include "detect-fast-pattern.h" #include "util-error.h" #include "util-byte.h" #include "util-debug.h" #include "util-unittest.h" #include "util-unittest-helper.h" #define PARSE_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" static DetectParseRegex parse_regex; static int DetectFastPatternSetup(DetectEngineCtx *, Signature *, const char *); #ifdef UNITTESTS static void DetectFastPatternRegisterTests(void); #endif /* holds the list of sm match lists that need to be searched for a keyword * that has fp support */ static SCFPSupportSMList *g_fp_support_smlist_list = NULL; /** * \brief Checks if a particular buffer is in the list * of lists that need to be searched for a keyword that has fp support. * * \param list_id The list id. * * \retval 1 If supported. * \retval 0 If not. */ int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, const int list_id) { if (de_ctx->fp_support_smlist_list == NULL) { return 0; } if (list_id == DETECT_SM_LIST_PMATCH) return 1; return DetectEngineBufferTypeSupportsMpmGetById(de_ctx, list_id); } static void Add(SCFPSupportSMList **list, const int list_id, const int priority) { SCFPSupportSMList *ip = NULL; /* insertion point - ip */ for (SCFPSupportSMList *tmp = *list; tmp != NULL; tmp = tmp->next) { if (list_id == tmp->list_id) { SCLogDebug("SM list already registered."); return; } /* We need a strict check to be sure that the current list * was not already registered * and other lists with the same priority hide it. */ if (priority < tmp->priority) break; ip = tmp; } if (*list == NULL) { SCFPSupportSMList *new = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new == NULL)) exit(EXIT_FAILURE); memset(new, 0, sizeof(SCFPSupportSMList)); new->list_id = list_id; new->priority = priority; *list = new; return; } SCFPSupportSMList *new = SCMalloc(sizeof(SCFPSupportSMList)); if (unlikely(new == NULL)) exit(EXIT_FAILURE); memset(new, 0, sizeof(SCFPSupportSMList)); new->list_id = list_id; new->priority = priority; if (ip == NULL) { new->next = *list; *list = new; } else { new->next = ip->next; ip->next = new; } return; } /** * \brief Lets one add a sm list id to be searched for potential fp supported * keywords later. * * \param list_id SM list id. * \param priority Priority for this list. */ void SupportFastPatternForSigMatchList(int list_id, int priority) { Add(&g_fp_support_smlist_list, list_id, priority); } void DetectEngineRegisterFastPatternForId(DetectEngineCtx *de_ctx, int list_id, int priority) { Add(&de_ctx->fp_support_smlist_list, list_id, priority); } /** * \brief Registers the keywords(SMs) that should be given fp support. */ void SupportFastPatternForSigMatchTypes(void) { SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH, 3); /* other types are handled by DetectMpmAppLayerRegister() */ } void DetectEngineInitializeFastPatternList(DetectEngineCtx *de_ctx) { SCFPSupportSMList *last = NULL; for (SCFPSupportSMList *tmp = g_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) { SCFPSupportSMList *n = SCCalloc(1, sizeof(*n)); if (n == NULL) { FatalError("out of memory: %s", strerror(errno)); } n->list_id = tmp->list_id; n->priority = tmp->priority; // append if (de_ctx->fp_support_smlist_list == NULL) { last = de_ctx->fp_support_smlist_list = n; } else { BUG_ON(last == NULL); last->next = n; last = n; } } } void DetectEngineFreeFastPatternList(DetectEngineCtx *de_ctx) { for (SCFPSupportSMList *tmp = de_ctx->fp_support_smlist_list; tmp != NULL;) { SCFPSupportSMList *next = tmp->next; SCFree(tmp); tmp = next; } de_ctx->fp_support_smlist_list = NULL; } /** * \brief Registration function for fast_pattern keyword */ void DetectFastPatternRegister(void) { sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern"; sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher"; sigmatch_table[DETECT_FAST_PATTERN].url = "/rules/prefilter-keywords.html#fast-pattern"; sigmatch_table[DETECT_FAST_PATTERN].Match = NULL; sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup; sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; #ifdef UNITTESTS sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; #endif sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_OPTIONAL_OPT; DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); } /** * \brief Configures the previous content context for a fast_pattern modifier * keyword used in the rule. * * \param de_ctx Pointer to the Detection Engine Context. * \param s Pointer to the Signature to which the current keyword belongs. * \param arg May hold an argument * * \retval 0 On success. * \retval -1 On failure. */ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) { int res = 0; size_t pcre2len; char arg_substr[128] = ""; DetectContentData *cd = NULL; pcre2_match_data *match = NULL; SigMatch *pm1 = DetectGetLastSMFromMpmLists(de_ctx, s); SigMatch *pm2 = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); if (pm1 == NULL && pm2 == NULL) { SCLogError("fast_pattern found inside " "the rule, without a content context. Please use a " "content based keyword before using fast_pattern"); return -1; } SigMatch *pm = NULL; if (pm1 && pm2) { if (pm1->idx > pm2->idx) pm = pm1; else pm = pm2; } else if (pm1 && !pm2) { pm = pm1; } else { pm = pm2; } cd = (DetectContentData *)pm->ctx; if ((cd->flags & DETECT_CONTENT_NEGATED) && ((cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_OFFSET) || (cd->flags & DETECT_CONTENT_DEPTH))) { /* we can't have any of these if we are having "only" */ SCLogError("fast_pattern; cannot be " "used with negated content, along with relative modifiers"); goto error; } if (arg == NULL|| strcmp(arg, "") == 0) { if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError("can't use multiple fast_pattern " "options for the same content"); goto error; } else { /*allow only one content to have fast_pattern modifier*/ for (uint32_t list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { SigMatch *sm = NULL; for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { if (sm->type == DETECT_CONTENT) { DetectContentData *tmp_cd = (DetectContentData *)sm->ctx; if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { SCLogError("fast_pattern " "can be used on only one content in a rule"); goto error; } } } } } cd->flags |= DETECT_CONTENT_FAST_PATTERN; return 0; } /* Execute the regex and populate args with captures. */ int ret = DetectParsePcreExec(&parse_regex, &match, arg, 0, 0); /* fast pattern only */ if (ret == 2) { if ((cd->flags & DETECT_CONTENT_NEGATED) || (cd->flags & DETECT_CONTENT_DISTANCE) || (cd->flags & DETECT_CONTENT_WITHIN) || (cd->flags & DETECT_CONTENT_OFFSET) || (cd->flags & DETECT_CONTENT_DEPTH)) { /* we can't have any of these if we are having "only" */ SCLogError("fast_pattern: only; cannot be " "used with negated content or with any of the relative " "modifiers like distance, within, offset, depth"); goto error; } cd->flags |= DETECT_CONTENT_FAST_PATTERN_ONLY; /* fast pattern chop */ } else if (ret == 4) { pcre2len = sizeof(arg_substr); res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg_substr, &pcre2len); if (res < 0) { SCLogError("pcre2_substring_copy_bynumber failed " "for fast_pattern offset"); goto error; } uint16_t offset; if (StringParseUint16(&offset, 10, 0, (const char *)arg_substr) < 0) { SCLogError("Invalid fast pattern offset:" " \"%s\"", arg_substr); goto error; } pcre2len = sizeof(arg_substr); res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)arg_substr, &pcre2len); if (res < 0) { SCLogError("pcre2_substring_copy_bynumber failed " "for fast_pattern offset"); goto error; } uint16_t length; if (StringParseUint16(&length, 10, 0, (const char *)arg_substr) < 0) { SCLogError("Invalid value for fast " "pattern: \"%s\"", arg_substr); goto error; } // Avoiding integer overflow if (offset > (65535 - length)) { SCLogError("Fast pattern (length + offset) " "exceeds limit pattern length limit"); goto error; } if (offset + length > cd->content_len) { SCLogError("Fast pattern (length + " "offset (%u)) exceeds pattern length (%u)", offset + length, cd->content_len); goto error; } cd->fp_chop_offset = offset; cd->fp_chop_len = length; cd->flags |= DETECT_CONTENT_FAST_PATTERN_CHOP; } else { SCLogError("parse error, ret %" PRId32 ", string %s", ret, arg); goto error; } cd->flags |= DETECT_CONTENT_FAST_PATTERN; pcre2_match_data_free(match); return 0; error: if (match) { pcre2_match_data_free(match); } return -1; } /*----------------------------------Unittests---------------------------------*/ #ifdef UNITTESTS #include "detect-engine-alert.h" static SigMatch *GetMatches(Signature *s, const int list) { SigMatch *sm = DetectBufferGetFirstSigMatch(s, list); if (sm == NULL && list < DETECT_SM_LIST_MAX) { sm = s->init_data->smlists[list]; } return sm; } static int DetectFastPatternStickySingle(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; fast_pattern; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternModifierSingle(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternStickySingleNoFP(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == 0); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternModifierSingleNoFP(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%ssid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == 0); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternStickySingleBadArg(const char *sticky) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; /* bogus argument to fast_pattern */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; fast_pattern:boo; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with distance */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; fast_pattern:only; content:\"two\"; distance:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with distance */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; content:\"two\"; fast_pattern:only; distance:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with distance */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; content:\"two\"; distance:10; fast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern chop with invalid values */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; fast_pattern:5,6; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternModifierBadRules(const char *sticky) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; /* bogus argument to fast_pattern */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:boo; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with distance */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:only; content:\"two\"; %s%sdistance:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); #if 0 // TODO bug? /* fast_pattern only with distance */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%s content:\"two\"; %s%sdistance:10; fast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); #endif /* fast_pattern only with within */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:only; content:\"two\"; %s%swithin:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with within */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%s content:\"two\"; %s%swithin:10; fast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with offset */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:only; offset:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with offset */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%s offset:10; fast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with depth */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:only; depth:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only with depth */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%s depth:10; fast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern only negate */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%s content:!\"two\"; %s%sfast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern chop with invalid values */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:5,6; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern chop with invalid values */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:65977,2; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern chop with invalid values */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:2,65977; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern chop with invalid values */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:2,65534; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* fast_pattern chop with invalid values */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:65534,2; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* negated fast_pattern with distance */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%sdistance:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* negated fast_pattern with within */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%swithin:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* negated fast_pattern with depth */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%sdepth:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); /* negated fast_pattern with offset */ snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%soffset:10; sid:1;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NOT_NULL(s); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternStickySingleFPOnly(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"one\"; fast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternModifierFPOnly(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%sfast_pattern:only; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:\"two\"; %s%sfast_pattern:only; sid:2;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:\"two\"; distance:10; %s%scontent:\"three\"; " "%s%sfast_pattern:only; sid:3;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NOT_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:\"two\"; within:10; %s%scontent:\"three\"; " "%s%sfast_pattern:only; sid:4;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NOT_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:\"two\"; offset:10; %s%scontent:\"three\"; " "%s%sfast_pattern:only; sid:5;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NOT_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"one\"; %s%scontent:\"two\"; depth:10; %s%scontent:\"three\"; " "%s%sfast_pattern:only; sid:6;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); sm = sm->next; FAIL_IF_NOT_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:!\"one\"; %s%sfast_pattern; content:\"two\"; depth:10; %s%ssid:7;)", sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY | DETECT_CONTENT_NEGATED)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_NEGATED)); sm = sm->next; FAIL_IF_NOT_NULL(sm->next); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT( (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternStickyFPChop(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"onetwothree\"; fast_pattern:3,4; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); FAIL_IF_NOT(cd->fp_chop_offset == 3); FAIL_IF_NOT(cd->fp_chop_len == 4); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(%s%scontent:\"onetwothree\"; fast_pattern:3,4; content:\"xyz\"; distance:10; sid:2;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); FAIL_IF_NOT(cd->fp_chop_offset == 3); FAIL_IF_NOT(cd->fp_chop_len == 4); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternModifierFPChop(const char *sticky, const int list) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); char string[1024]; snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:\"onetwothree\"; %s%sfast_pattern:3,4; sid:1;)", sticky ? sticky : "", sticky ? "; " : " "); Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); FAIL_IF_NOT(cd->fp_chop_offset == 3); FAIL_IF_NOT(cd->fp_chop_len == 4); snprintf(string, sizeof(string), "alert tcp any any -> any any " "(content:!\"onetwothree\"; %s%sfast_pattern:3,4; sid:2;)", sticky ? sticky : "", sticky ? "; " : " "); s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); sm = GetMatches(s, list); FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_NEGATED | DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | DETECT_CONTENT_FAST_PATTERN_ONLY)) == (DETECT_CONTENT_NEGATED | DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); FAIL_IF_NOT(cd->fp_chop_offset == 3); FAIL_IF_NOT(cd->fp_chop_len == 4); DetectEngineCtxFree(de_ctx); PASS; } /** * \test Checks if a fast_pattern is registered in a Signature */ static int DetectFastPatternTest01(void) { FAIL_IF_NOT(DetectFastPatternStickySingle(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternModifierSingle(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternStickySingleNoFP(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternModifierSingleNoFP(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternStickySingleBadArg(NULL)); FAIL_IF_NOT(DetectFastPatternModifierBadRules(NULL)); FAIL_IF_NOT(DetectFastPatternStickySingleFPOnly(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternModifierFPOnly(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternStickyFPChop(NULL, DETECT_SM_LIST_PMATCH)); FAIL_IF_NOT(DetectFastPatternModifierFPChop(NULL, DETECT_SM_LIST_PMATCH)); struct { const char *buffer_name; const char *sb_name; const char *mod_name; } keywords[] = { { "file_data", "file.data", NULL }, { "http_uri", "http.uri", "http_uri" }, { "http_raw_uri", "http.uri.raw", "http_raw_uri" }, { "http_user_agent", "http.user_agent", "http_user_agent" }, { "http_header", "http.header", "http_header" }, // http_raw_header requires sigs to have a direction //{ "http_raw_header", "http.header.raw", "http_raw_header" }, { "http_method", "http.method", "http_method" }, { "http_cookie", "http.cookie", "http_cookie" }, { "http_host", "http.host", "http_host" }, { "http_raw_host", "http.host.raw", "http_raw_host" }, { "http_stat_code", "http.stat_code", "http_stat_code" }, { "http_stat_msg", "http.stat_msg", "http_stat_msg" }, { "http_client_body", "http.request_body", "http_client_body" }, { NULL, NULL, NULL }, }; for (int i = 0; keywords[i].buffer_name != NULL; i++) { const int list_id = DetectBufferTypeGetByName(keywords[i].buffer_name); FAIL_IF(list_id == -1); const char *k = keywords[i].sb_name; if (k) { FAIL_IF_NOT(DetectFastPatternStickySingle(k, list_id)); FAIL_IF_NOT(DetectFastPatternStickySingleNoFP(k, list_id)); FAIL_IF_NOT(DetectFastPatternStickySingleBadArg(k)); FAIL_IF_NOT(DetectFastPatternStickySingleFPOnly(k, list_id)); FAIL_IF_NOT(DetectFastPatternStickyFPChop(k, list_id)); } k = keywords[i].mod_name; if (k) { FAIL_IF_NOT(DetectFastPatternModifierSingle(k, list_id)); FAIL_IF_NOT(DetectFastPatternModifierSingleNoFP(k, list_id)); FAIL_IF_NOT(DetectFastPatternModifierBadRules(k)); FAIL_IF_NOT(DetectFastPatternModifierFPOnly(k, list_id)); FAIL_IF_NOT(DetectFastPatternModifierFPChop(k, list_id)); } } PASS; } /** * \test Checks to make sure that other sigs work that should when fast_pattern is inspecting on the * same payload * */ static int DetectFastPatternTest14(void) { uint8_t *buf = (uint8_t *)"Dummy is our name. Oh yes. From right here " "right now, all the way to hangover. right. strings5_imp now here " "comes our dark knight strings_string5. Yes here is our dark knight"; uint16_t buflen = strlen((char *)buf); ThreadVars th_v; DetectEngineThreadCtx *det_ctx = NULL; memset(&th_v, 0, sizeof(th_v)); Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); FAIL_IF_NULL(p); DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; FlowInitConfig(FLOW_QUIET); Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"fast_pattern test\"; content:\"strings_string5\"; content:\"knight\"; " "fast_pattern; sid:1;)"); FAIL_IF_NULL(s); s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " "(msg:\"test different content\"; content:\"Dummy is our name\"; sid:2;)"); FAIL_IF_NULL(s); SigGroupBuild(de_ctx); DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); SigMatchSignatures(&th_v, de_ctx, det_ctx, p); FAIL_IF_NOT(PacketAlertCheck(p, 1)); FAIL_IF_NOT(PacketAlertCheck(p, 2)); UTHFreePackets(&p, 1); DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); DetectEngineCtxFree(de_ctx); FlowShutdown(); PASS; } /** * Unittest to check * - if we assign different content_ids to duplicate patterns, but one of the * patterns has a fast_pattern chop set. * - if 2 unique patterns get unique ids. * - if 2 duplicate patterns, with no chop set get unique ids. */ static int DetectFastPatternTest671(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); de_ctx->flags |= DE_QUIET; Signature *s[6]; s[0] = DetectEngineAppendSig( de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; sid:1;)"); FAIL_IF_NULL(s[0]); s[1] = DetectEngineAppendSig( de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; sid:2;)"); FAIL_IF_NULL(s[1]); s[2] = DetectEngineAppendSig( de_ctx, "alert tcp any any -> any any (content:\"uniquepattern\"; sid:3;)"); FAIL_IF_NULL(s[2]); s[3] = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; fast_pattern:3,5; sid:4;)"); FAIL_IF_NULL(s[3]); s[4] = DetectEngineAppendSig( de_ctx, "alert tcp any any -> any any (content:\"twoth\"; sid:5;)"); FAIL_IF_NULL(s[4]); s[5] = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; fast_pattern:0,15; " "sid:6;)"); FAIL_IF_NULL(s[5]); SigGroupBuild(de_ctx); SigMatchData *smd = s[0]->sm_arrays[DETECT_SM_LIST_PMATCH]; DetectContentData *cd = (DetectContentData *)smd->ctx; FAIL_IF(cd->id != 0); smd = s[1]->sm_arrays[DETECT_SM_LIST_PMATCH]; cd = (DetectContentData *)smd->ctx; FAIL_IF(cd->id != 0); smd = s[2]->sm_arrays[DETECT_SM_LIST_PMATCH]; cd = (DetectContentData *)smd->ctx; FAIL_IF(cd->id != 2); smd = s[3]->sm_arrays[DETECT_SM_LIST_PMATCH]; cd = (DetectContentData *)smd->ctx; FAIL_IF(cd->id != 1); smd = s[4]->sm_arrays[DETECT_SM_LIST_PMATCH]; cd = (DetectContentData *)smd->ctx; FAIL_IF(cd->id != 1); smd = s[5]->sm_arrays[DETECT_SM_LIST_PMATCH]; cd = (DetectContentData *)smd->ctx; FAIL_IF(cd->id != 0); DetectEngineCtxFree(de_ctx); PASS; } static int DetectFastPatternPrefilter(void) { DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); const char *string = "alert tcp any any -> any any " "(content:\"one\"; prefilter; sid:1;)"; Signature *s = DetectEngineAppendSig(de_ctx, string); FAIL_IF_NULL(s); SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; FAIL_IF_NULL(sm); FAIL_IF_NOT(sm->type == DETECT_CONTENT); DetectContentData *cd = (DetectContentData *)sm->ctx; FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN); DetectEngineCtxFree(de_ctx); PASS; } static void DetectFastPatternRegisterTests(void) { UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14); /* Unittest to check * - if we assign different content_ids to duplicate patterns, but one of the * patterns has a fast_pattern chop set. * - if 2 unique patterns get unique ids. * - if 2 duplicate patterns, with no chop set get unique ids. */ UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671); UtRegisterTest("DetectFastPatternPrefilter", DetectFastPatternPrefilter); } #endif