mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1159 lines
44 KiB
C
1159 lines
44 KiB
C
/* 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 ret = 0, res = 0;
|
|
size_t pcre2len;
|
|
char arg_substr[128] = "";
|
|
DetectContentData *cd = 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. */
|
|
ret = DetectParsePcreExec(&parse_regex, 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(
|
|
parse_regex.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(
|
|
parse_regex.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;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
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
|