summaryrefslogtreecommitdiffstats
path: root/src/detect-fast-pattern.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:39:49 +0000
commita0aa2307322cd47bbf416810ac0292925e03be87 (patch)
tree37076262a026c4b48c8a0e84f44ff9187556ca35 /src/detect-fast-pattern.c
parentInitial commit. (diff)
downloadsuricata-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.c1161
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