diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
commit | a0aa2307322cd47bbf416810ac0292925e03be87 (patch) | |
tree | 37076262a026c4b48c8a0e84f44ff9187556ca35 /src/detect-fast-pattern.c | |
parent | Initial commit. (diff) | |
download | suricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip |
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/detect-fast-pattern.c')
-rw-r--r-- | src/detect-fast-pattern.c | 1161 |
1 files changed, 1161 insertions, 0 deletions
diff --git a/src/detect-fast-pattern.c b/src/detect-fast-pattern.c new file mode 100644 index 0000000..b82f327 --- /dev/null +++ b/src/detect-fast-pattern.c @@ -0,0 +1,1161 @@ +/* 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 <anoopsaldanha@gmail.com> + * + * 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 |