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.
suricata/src/util-mpm-hs.c

2185 lines
60 KiB
C

/* Copyright (C) 2007-2016 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 Jim Xu <jim.xu@windriver.com>
* \author Justin Viiret <justin.viiret@intel.com>
*
* MPM pattern matcher that calls the Hyperscan regex matcher.
*/
#include "suricata-common.h"
#include "suricata.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "conf.h"
#include "util-debug.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "util-memcmp.h"
#include "util-mpm-hs.h"
#include "util-memcpy.h"
#include "util-hash.h"
#include "util-hash-lookup3.h"
#include "util-hyperscan.h"
#ifdef BUILD_HYPERSCAN
#include <hs.h>
void SCHSInitCtx(MpmCtx *);
void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *);
void SCHSDestroyCtx(MpmCtx *);
void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *);
int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
uint32_t, SigIntId, uint8_t);
int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
uint32_t, SigIntId, uint8_t);
int SCHSPreparePatterns(MpmCtx *mpm_ctx);
uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen);
void SCHSPrintInfo(MpmCtx *mpm_ctx);
void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx);
void SCHSRegisterTests(void);
/* size of the hash table used to speed up pattern insertions initially */
#define INIT_HASH_SIZE 65536
/* Initial size of the global database hash (used for de-duplication). */
#define INIT_DB_HASH_SIZE 1000
/* Global prototype scratch, built incrementally as Hyperscan databases are
* built and then cloned for each thread context. Access is serialised via
* g_scratch_proto_mutex. */
static hs_scratch_t *g_scratch_proto = NULL;
static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER;
/* Global hash table of Hyperscan databases, used for de-duplication. Access is
* serialised via g_db_table_mutex. */
static HashTable *g_db_table = NULL;
static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER;
/**
* \internal
* \brief Wraps SCMalloc (which is a macro) so that it can be passed to
* hs_set_allocator() for Hyperscan's use.
*/
static void *SCHSMalloc(size_t size)
{
return SCMalloc(size);
}
/**
* \internal
* \brief Wraps SCFree (which is a macro) so that it can be passed to
* hs_set_allocator() for Hyperscan's use.
*/
static void SCHSFree(void *ptr)
{
SCFree(ptr);
}
/** \brief Register Suricata malloc/free with Hyperscan.
*
* Requests that Hyperscan use Suricata's allocator for allocation of
* databases, scratch space, etc.
*/
static void SCHSSetAllocators(void)
{
hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree);
if (err != HS_SUCCESS) {
FatalError(SC_ERR_FATAL, "Failed to set Hyperscan allocator.");
}
}
/**
* \internal
* \brief Creates a hash of the pattern. We use it for the hashing process
* during the initial pattern insertion time, to cull duplicate sigs.
*
* \param pat Pointer to the pattern.
* \param patlen Pattern length.
*
* \retval hash A 32 bit unsigned hash.
*/
static inline uint32_t SCHSInitHashRaw(uint8_t *pat, uint16_t patlen)
{
uint32_t hash = patlen * pat[0];
if (patlen > 1)
hash += pat[1];
return (hash % INIT_HASH_SIZE);
}
/**
* \internal
* \brief Looks up a pattern. We use it for the hashing process during
* the initial pattern insertion time, to cull duplicate sigs.
*
* \param ctx Pointer to the HS ctx.
* \param pat Pointer to the pattern.
* \param patlen Pattern length.
* \param flags Flags. We don't need this.
*
* \retval hash A 32 bit unsigned hash.
*/
static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, uint8_t *pat,
uint16_t patlen, uint16_t offset,
uint16_t depth, char flags,
uint32_t pid)
{
uint32_t hash = SCHSInitHashRaw(pat, patlen);
if (ctx->init_hash == NULL) {
return NULL;
}
SCHSPattern *t = ctx->init_hash[hash];
for (; t != NULL; t = t->next) {
/* Since Hyperscan uses offset/depth, we must distinguish between
* patterns with the same ID but different offset/depth here. */
if (t->id == pid && t->offset == offset && t->depth == depth) {
BUG_ON(t->len != patlen);
BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0);
return t;
}
}
return NULL;
}
/**
* \internal
* \brief Allocates a new pattern instance.
*
* \param mpm_ctx Pointer to the mpm context.
*
* \retval p Pointer to the newly created pattern.
*/
static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx)
{
SCHSPattern *p = SCMalloc(sizeof(SCHSPattern));
if (unlikely(p == NULL)) {
exit(EXIT_FAILURE);
}
memset(p, 0, sizeof(SCHSPattern));
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += sizeof(SCHSPattern);
return p;
}
/**
* \internal
* \brief Used to free SCHSPattern instances.
*
* \param mpm_ctx Pointer to the mpm context.
* \param p Pointer to the SCHSPattern instance to be freed.
* \param free Free the above pointer or not.
*/
static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p)
{
if (p != NULL && p->original_pat != NULL) {
SCFree(p->original_pat);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= p->len;
}
if (p != NULL && p->sids != NULL) {
SCFree(p->sids);
}
if (p != NULL) {
SCFree(p);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= sizeof(SCHSPattern);
}
}
static inline uint32_t SCHSInitHash(SCHSPattern *p)
{
uint32_t hash = p->len * p->original_pat[0];
if (p->len > 1)
hash += p->original_pat[1];
return (hash % INIT_HASH_SIZE);
}
static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p)
{
uint32_t hash = SCHSInitHash(p);
if (ctx->init_hash == NULL) {
return 0;
}
if (ctx->init_hash[hash] == NULL) {
ctx->init_hash[hash] = p;
return 0;
}
SCHSPattern *tt = NULL;
SCHSPattern *t = ctx->init_hash[hash];
/* get the list tail */
do {
tt = t;
t = t->next;
} while (t != NULL);
tt->next = p;
return 0;
}
/**
* \internal
* \brief Add a pattern to the mpm-hs context.
*
* \param mpm_ctx Mpm context.
* \param pat Pointer to the pattern.
* \param patlen Length of the pattern.
* \param pid Pattern id
* \param sid Signature id (internal id).
* \param flags Pattern's MPM_PATTERN_* flags.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
static int SCHSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
uint16_t offset, uint16_t depth, uint32_t pid,
SigIntId sid, uint8_t flags)
{
SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
if (offset != 0) {
flags |= MPM_PATTERN_FLAG_OFFSET;
}
if (depth != 0) {
flags |= MPM_PATTERN_FLAG_DEPTH;
}
if (patlen == 0) {
SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "pattern length 0");
return 0;
}
/* check if we have already inserted this pattern */
SCHSPattern *p =
SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid);
if (p == NULL) {
SCLogDebug("Allocing new pattern");
/* p will never be NULL */
p = SCHSAllocPattern(mpm_ctx);
p->len = patlen;
p->flags = flags;
p->id = pid;
p->offset = offset;
p->depth = depth;
p->original_pat = SCMalloc(patlen);
if (p->original_pat == NULL)
goto error;
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += patlen;
memcpy(p->original_pat, pat, patlen);
/* put in the pattern hash */
SCHSInitHashAdd(ctx, p);
mpm_ctx->pattern_cnt++;
if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) {
if (depth) {
mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth);
SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth);
} else {
mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH;
mpm_ctx->maxdepth = 0;
SCLogDebug("%p: alas, no depth for us", mpm_ctx);
}
}
if (mpm_ctx->maxlen < patlen)
mpm_ctx->maxlen = patlen;
if (mpm_ctx->minlen == 0) {
mpm_ctx->minlen = patlen;
} else {
if (mpm_ctx->minlen > patlen)
mpm_ctx->minlen = patlen;
}
p->sids_size = 1;
p->sids = SCMalloc(p->sids_size * sizeof(SigIntId));
BUG_ON(p->sids == NULL);
p->sids[0] = sid;
} else {
/* TODO figure out how we can be called multiple times for the same CTX with the same sid */
int found = 0;
uint32_t x = 0;
for (x = 0; x < p->sids_size; x++) {
if (p->sids[x] == sid) {
found = 1;
break;
}
}
if (!found) {
SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1)));
BUG_ON(sids == NULL);
p->sids = sids;
p->sids[p->sids_size] = sid;
p->sids_size++;
}
}
return 0;
error:
SCHSFreePattern(mpm_ctx, p);
return -1;
}
/**
* \brief Pattern database information used only as input to the Hyperscan
* compiler.
*/
typedef struct SCHSCompileData_ {
unsigned int *ids;
unsigned int *flags;
char **expressions;
hs_expr_ext_t **ext;
unsigned int pattern_cnt;
} SCHSCompileData;
static SCHSCompileData *SCHSAllocCompileData(unsigned int pattern_cnt)
{
SCHSCompileData *cd = SCMalloc(pattern_cnt * sizeof(SCHSCompileData));
if (cd == NULL) {
goto error;
}
memset(cd, 0, pattern_cnt * sizeof(SCHSCompileData));
cd->pattern_cnt = pattern_cnt;
cd->ids = SCMalloc(pattern_cnt * sizeof(unsigned int));
if (cd->ids == NULL) {
goto error;
}
memset(cd->ids, 0, pattern_cnt * sizeof(unsigned int));
cd->flags = SCMalloc(pattern_cnt * sizeof(unsigned int));
if (cd->flags == NULL) {
goto error;
}
memset(cd->flags, 0, pattern_cnt * sizeof(unsigned int));
cd->expressions = SCMalloc(pattern_cnt * sizeof(char *));
if (cd->expressions == NULL) {
goto error;
}
memset(cd->expressions, 0, pattern_cnt * sizeof(char *));
cd->ext = SCMalloc(pattern_cnt * sizeof(hs_expr_ext_t *));
if (cd->ext == NULL) {
goto error;
}
memset(cd->ext, 0, pattern_cnt * sizeof(hs_expr_ext_t *));
return cd;
error:
SCLogDebug("SCHSCompileData alloc failed");
if (cd) {
SCFree(cd->ids);
SCFree(cd->flags);
SCFree(cd->expressions);
SCFree(cd->ext);
SCFree(cd);
}
return NULL;
}
static void SCHSFreeCompileData(SCHSCompileData *cd)
{
if (cd == NULL) {
return;
}
SCFree(cd->ids);
SCFree(cd->flags);
if (cd->expressions) {
for (unsigned int i = 0; i < cd->pattern_cnt; i++) {
SCFree(cd->expressions[i]);
}
SCFree(cd->expressions);
}
if (cd->ext) {
for (unsigned int i = 0; i < cd->pattern_cnt; i++) {
SCFree(cd->ext[i]);
}
SCFree(cd->ext);
}
SCFree(cd);
}
typedef struct PatternDatabase_ {
SCHSPattern **parray;
hs_database_t *hs_db;
uint32_t pattern_cnt;
/* Reference count: number of MPM contexts using this pattern database. */
uint32_t ref_cnt;
} PatternDatabase;
static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash)
{
BUG_ON(p->original_pat == NULL);
BUG_ON(p->sids == NULL);
hash = hashlittle_safe(&p->len, sizeof(p->len), hash);
hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash);
hash = hashlittle_safe(p->original_pat, p->len, hash);
hash = hashlittle_safe(&p->id, sizeof(p->id), hash);
hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash);
hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash);
hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash);
hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash);
return hash;
}
static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2)
{
if ((p1->len != p2->len) || (p1->flags != p2->flags) ||
(p1->id != p2->id) || (p1->offset != p2->offset) ||
(p1->depth != p2->depth) || (p1->sids_size != p2->sids_size)) {
return 0;
}
if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) {
return 0;
}
if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) !=
0) {
return 0;
}
return 1;
}
static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len)
{
const PatternDatabase *pd = data;
uint32_t hash = 0;
hash = hashword(&pd->pattern_cnt, 1, hash);
for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
hash = SCHSPatternHash(pd->parray[i], hash);
}
hash %= ht->array_size;
return hash;
}
static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2,
uint16_t len2)
{
const PatternDatabase *pd1 = data1;
const PatternDatabase *pd2 = data2;
if (pd1->pattern_cnt != pd2->pattern_cnt) {
return 0;
}
for (uint32_t i = 0; i < pd1->pattern_cnt; i++) {
if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) {
return 0;
}
}
return 1;
}
static void PatternDatabaseFree(PatternDatabase *pd)
{
BUG_ON(pd->ref_cnt != 0);
if (pd->parray != NULL) {
for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
SCHSPattern *p = pd->parray[i];
if (p != NULL) {
SCFree(p->original_pat);
SCFree(p->sids);
SCFree(p);
}
}
SCFree(pd->parray);
}
hs_free_database(pd->hs_db);
SCFree(pd);
}
static void PatternDatabaseTableFree(void *data)
{
/* Stub function handed to hash table; actual freeing of PatternDatabase
* structures is done in MPM destruction when the ref_cnt drops to zero. */
}
static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt)
{
PatternDatabase *pd = SCMalloc(sizeof(PatternDatabase));
if (pd == NULL) {
return NULL;
}
memset(pd, 0, sizeof(PatternDatabase));
pd->pattern_cnt = pattern_cnt;
pd->ref_cnt = 0;
pd->hs_db = NULL;
/* alloc the pattern array */
pd->parray =
(SCHSPattern **)SCMalloc(pd->pattern_cnt * sizeof(SCHSPattern *));
if (pd->parray == NULL) {
SCFree(pd);
return NULL;
}
memset(pd->parray, 0, pd->pattern_cnt * sizeof(SCHSPattern *));
return pd;
}
/**
* \brief Process the patterns added to the mpm, and create the internal tables.
*
* \param mpm_ctx Pointer to the mpm context.
*/
int SCHSPreparePatterns(MpmCtx *mpm_ctx)
{
SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) {
SCLogDebug("no patterns supplied to this mpm_ctx");
return 0;
}
hs_error_t err;
hs_compile_error_t *compile_err = NULL;
SCHSCompileData *cd = NULL;
PatternDatabase *pd = NULL;
cd = SCHSAllocCompileData(mpm_ctx->pattern_cnt);
if (cd == NULL) {
goto error;
}
pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt);
if (pd == NULL) {
goto error;
}
/* populate the pattern array with the patterns in the hash */
for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) {
SCHSPattern *node = ctx->init_hash[i], *nnode = NULL;
while (node != NULL) {
nnode = node->next;
node->next = NULL;
pd->parray[p++] = node;
node = nnode;
}
}
/* we no longer need the hash, so free its memory */
SCFree(ctx->init_hash);
ctx->init_hash = NULL;
/* Serialise whole database compilation as a relatively easy way to ensure
* dedupe is safe. */
SCMutexLock(&g_db_table_mutex);
/* Init global pattern database hash if necessary. */
if (g_db_table == NULL) {
g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash,
PatternDatabaseCompare,
PatternDatabaseTableFree);
if (g_db_table == NULL) {
SCMutexUnlock(&g_db_table_mutex);
goto error;
}
}
/* Check global hash table to see if we've seen this pattern database
* before, and reuse the Hyperscan database if so. */
PatternDatabase *pd_cached = HashTableLookup(g_db_table, pd, 1);
if (pd_cached != NULL) {
SCLogDebug("Reusing cached database %p with %" PRIu32
" patterns (ref_cnt=%" PRIu32 ")",
pd_cached->hs_db, pd_cached->pattern_cnt,
pd_cached->ref_cnt);
pd_cached->ref_cnt++;
ctx->pattern_db = pd_cached;
SCMutexUnlock(&g_db_table_mutex);
PatternDatabaseFree(pd);
SCHSFreeCompileData(cd);
return 0;
}
BUG_ON(ctx->pattern_db != NULL); /* already built? */
for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
const SCHSPattern *p = pd->parray[i];
cd->ids[i] = i;
cd->flags[i] = HS_FLAG_SINGLEMATCH;
if (p->flags & MPM_PATTERN_FLAG_NOCASE) {
cd->flags[i] |= HS_FLAG_CASELESS;
}
cd->expressions[i] = HSRenderPattern(p->original_pat, p->len);
if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) {
cd->ext[i] = SCMalloc(sizeof(hs_expr_ext_t));
if (cd->ext[i] == NULL) {
SCMutexUnlock(&g_db_table_mutex);
goto error;
}
memset(cd->ext[i], 0, sizeof(hs_expr_ext_t));
if (p->flags & MPM_PATTERN_FLAG_OFFSET) {
cd->ext[i]->flags |= HS_EXT_FLAG_MIN_OFFSET;
cd->ext[i]->min_offset = p->offset + p->len;
}
if (p->flags & MPM_PATTERN_FLAG_DEPTH) {
cd->ext[i]->flags |= HS_EXT_FLAG_MAX_OFFSET;
cd->ext[i]->max_offset = p->offset + p->depth;
}
}
}
BUG_ON(mpm_ctx->pattern_cnt == 0);
err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags,
cd->ids, (const hs_expr_ext_t *const *)cd->ext,
cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db,
&compile_err);
if (err != HS_SUCCESS) {
SCLogError(SC_ERR_FATAL, "failed to compile hyperscan database");
if (compile_err) {
SCLogError(SC_ERR_FATAL, "compile error: %s", compile_err->message);
}
hs_free_compile_error(compile_err);
SCMutexUnlock(&g_db_table_mutex);
goto error;
}
ctx->pattern_db = pd;
SCMutexLock(&g_scratch_proto_mutex);
err = hs_alloc_scratch(pd->hs_db, &g_scratch_proto);
SCMutexUnlock(&g_scratch_proto_mutex);
if (err != HS_SUCCESS) {
SCLogError(SC_ERR_FATAL, "failed to allocate scratch");
SCMutexUnlock(&g_db_table_mutex);
goto error;
}
err = hs_database_size(pd->hs_db, &ctx->hs_db_size);
if (err != HS_SUCCESS) {
SCLogError(SC_ERR_FATAL, "failed to query database size");
SCMutexUnlock(&g_db_table_mutex);
goto error;
}
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += ctx->hs_db_size;
SCLogDebug("Built %" PRIu32 " patterns into a database of size %" PRIuMAX
" bytes", mpm_ctx->pattern_cnt, (uintmax_t)ctx->hs_db_size);
/* Cache this database globally for later. */
pd->ref_cnt = 1;
int r = HashTableAdd(g_db_table, pd, 1);
SCMutexUnlock(&g_db_table_mutex);
if (r < 0)
goto error;
SCHSFreeCompileData(cd);
return 0;
error:
if (pd) {
PatternDatabaseFree(pd);
}
if (cd) {
SCHSFreeCompileData(cd);
}
return -1;
}
/**
* \brief Init the mpm thread context.
*
* \param mpm_ctx Pointer to the mpm context.
* \param mpm_thread_ctx Pointer to the mpm thread context.
*/
void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
{
memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
SCHSThreadCtx *ctx = SCMalloc(sizeof(SCHSThreadCtx));
if (ctx == NULL) {
exit(EXIT_FAILURE);
}
mpm_thread_ctx->ctx = ctx;
memset(ctx, 0, sizeof(SCHSThreadCtx));
mpm_thread_ctx->memory_cnt++;
mpm_thread_ctx->memory_size += sizeof(SCHSThreadCtx);
ctx->scratch = NULL;
ctx->scratch_size = 0;
SCMutexLock(&g_scratch_proto_mutex);
if (g_scratch_proto == NULL) {
/* There is no scratch prototype: this means that we have not compiled
* any Hyperscan databases. */
SCMutexUnlock(&g_scratch_proto_mutex);
SCLogDebug("No scratch space prototype");
return;
}
hs_error_t err = hs_clone_scratch(g_scratch_proto,
(hs_scratch_t **)&ctx->scratch);
SCMutexUnlock(&g_scratch_proto_mutex);
if (err != HS_SUCCESS) {
FatalError(SC_ERR_FATAL, "Unable to clone scratch prototype");
}
err = hs_scratch_size(ctx->scratch, &ctx->scratch_size);
if (err != HS_SUCCESS) {
FatalError(SC_ERR_FATAL, "Unable to query scratch size");
}
mpm_thread_ctx->memory_cnt++;
mpm_thread_ctx->memory_size += ctx->scratch_size;
}
/**
* \brief Initialize the HS context.
*
* \param mpm_ctx Mpm context.
*/
void SCHSInitCtx(MpmCtx *mpm_ctx)
{
if (mpm_ctx->ctx != NULL)
return;
mpm_ctx->ctx = SCMalloc(sizeof(SCHSCtx));
if (mpm_ctx->ctx == NULL) {
exit(EXIT_FAILURE);
}
memset(mpm_ctx->ctx, 0, sizeof(SCHSCtx));
mpm_ctx->memory_cnt++;
mpm_ctx->memory_size += sizeof(SCHSCtx);
/* initialize the hash we use to speed up pattern insertions */
SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
ctx->init_hash = SCMalloc(sizeof(SCHSPattern *) * INIT_HASH_SIZE);
if (ctx->init_hash == NULL) {
exit(EXIT_FAILURE);
}
memset(ctx->init_hash, 0, sizeof(SCHSPattern *) * INIT_HASH_SIZE);
}
/**
* \brief Destroy the mpm thread context.
*
* \param mpm_ctx Pointer to the mpm context.
* \param mpm_thread_ctx Pointer to the mpm thread context.
*/
void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
{
SCHSPrintSearchStats(mpm_thread_ctx);
if (mpm_thread_ctx->ctx != NULL) {
SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx;
if (thr_ctx->scratch != NULL) {
hs_free_scratch(thr_ctx->scratch);
mpm_thread_ctx->memory_cnt--;
mpm_thread_ctx->memory_size -= thr_ctx->scratch_size;
}
SCFree(mpm_thread_ctx->ctx);
mpm_thread_ctx->ctx = NULL;
mpm_thread_ctx->memory_cnt--;
mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx);
}
}
/**
* \brief Destroy the mpm context.
*
* \param mpm_ctx Pointer to the mpm context.
*/
void SCHSDestroyCtx(MpmCtx *mpm_ctx)
{
SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
if (ctx == NULL)
return;
if (ctx->init_hash != NULL) {
SCFree(ctx->init_hash);
ctx->init_hash = NULL;
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCHSPattern *));
}
/* Decrement pattern database ref count, and delete it entirely if the
* count has dropped to zero. */
SCMutexLock(&g_db_table_mutex);
PatternDatabase *pd = ctx->pattern_db;
if (pd) {
BUG_ON(pd->ref_cnt == 0);
pd->ref_cnt--;
if (pd->ref_cnt == 0) {
HashTableRemove(g_db_table, pd, 1);
PatternDatabaseFree(pd);
}
}
SCMutexUnlock(&g_db_table_mutex);
SCFree(mpm_ctx->ctx);
mpm_ctx->memory_cnt--;
mpm_ctx->memory_size -= sizeof(SCHSCtx);
}
typedef struct SCHSCallbackCtx_ {
SCHSCtx *ctx;
void *pmq;
uint32_t match_count;
} SCHSCallbackCtx;
/* Hyperscan MPM match event handler */
static int SCHSMatchEvent(unsigned int id, unsigned long long from,
unsigned long long to, unsigned int flags,
void *ctx)
{
SCHSCallbackCtx *cctx = ctx;
PrefilterRuleStore *pmq = cctx->pmq;
const PatternDatabase *pd = cctx->ctx->pattern_db;
const SCHSPattern *pat = pd->parray[id];
SCLogDebug("Hyperscan Match %" PRIu32 ": id=%" PRIu32 " @ %" PRIuMAX
" (pat id=%" PRIu32 ")",
cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id);
PrefilterAddSids(pmq, pat->sids, pat->sids_size);
cctx->match_count++;
return 0;
}
/**
* \brief The Hyperscan search function.
*
* \param mpm_ctx Pointer to the mpm context.
* \param mpm_thread_ctx Pointer to the mpm thread context.
* \param pmq Pointer to the Pattern Matcher Queue to hold
* search matches.
* \param buf Buffer to be searched.
* \param buflen Buffer length.
*
* \retval matches Match count.
*/
uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen)
{
uint32_t ret = 0;
SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx);
const PatternDatabase *pd = ctx->pattern_db;
if (unlikely(buflen == 0)) {
return 0;
}
SCHSCallbackCtx cctx = {.ctx = ctx, .pmq = pmq, .match_count = 0};
/* scratch should have been cloned from g_scratch_proto at thread init. */
hs_scratch_t *scratch = hs_thread_ctx->scratch;
BUG_ON(pd->hs_db == NULL);
BUG_ON(scratch == NULL);
hs_error_t err = hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch,
SCHSMatchEvent, &cctx);
if (err != HS_SUCCESS) {
/* An error value (other than HS_SCAN_TERMINATED) from hs_scan()
* indicates that it was passed an invalid database or scratch region,
* which is not something we can recover from at scan time. */
SCLogError(SC_ERR_FATAL, "Hyperscan returned error %d", err);
exit(EXIT_FAILURE);
} else {
ret = cctx.match_count;
}
return ret;
}
/**
* \brief Add a case insensitive pattern. Although we have different calls for
* adding case sensitive and insensitive patterns, we make a single call
* for either case. No special treatment for either case.
*
* \param mpm_ctx Pointer to the mpm context.
* \param pat The pattern to add.
* \param patlen The pattern length.
* \param offset The pattern offset.
* \param depth The pattern depth.
* \param pid The pattern id.
* \param sid The pattern signature id.
* \param flags Flags associated with this pattern.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
int SCHSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
uint16_t offset, uint16_t depth, uint32_t pid,
SigIntId sid, uint8_t flags)
{
flags |= MPM_PATTERN_FLAG_NOCASE;
return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
}
/**
* \brief Add a case sensitive pattern. Although we have different calls for
* adding case sensitive and insensitive patterns, we make a single call
* for either case. No special treatment for either case.
*
* \param mpm_ctx Pointer to the mpm context.
* \param pat The pattern to add.
* \param patlen The pattern length.
* \param offset The pattern offset.
* \param depth The pattern depth.
* \param pid The pattern id.
* \param sid The pattern signature id.
* \param flags Flags associated with this pattern.
*
* \retval 0 On success.
* \retval -1 On failure.
*/
int SCHSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
uint16_t offset, uint16_t depth, uint32_t pid,
SigIntId sid, uint8_t flags)
{
return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
}
void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx)
{
return;
}
void SCHSPrintInfo(MpmCtx *mpm_ctx)
{
SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
printf("MPM HS Information:\n");
printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt);
printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size);
printf(" Sizeof:\n");
printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx));
printf(" SCHSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSCtx));
printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern));
printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt);
printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen);
printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen);
printf("\n");
if (ctx) {
PatternDatabase *pd = ctx->pattern_db;
char *db_info = NULL;
if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) {
printf("HS Database Info: %s\n", db_info);
SCFree(db_info);
}
printf("HS Database Size: %" PRIuMAX " bytes\n",
(uintmax_t)ctx->hs_db_size);
}
printf("\n");
}
/************************** Mpm Registration ***************************/
/**
* \brief Register the Hyperscan MPM.
*/
void MpmHSRegister(void)
{
mpm_table[MPM_HS].name = "hs";
mpm_table[MPM_HS].InitCtx = SCHSInitCtx;
mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx;
mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx;
mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx;
mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS;
mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI;
mpm_table[MPM_HS].Prepare = SCHSPreparePatterns;
mpm_table[MPM_HS].Search = SCHSSearch;
mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo;
mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats;
mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests;
/* Set Hyperscan memory allocators */
SCHSSetAllocators();
}
/**
* \brief Clean up global memory used by all Hyperscan MPM instances.
*
* Currently, this is just the global scratch prototype.
*/
void MpmHSGlobalCleanup(void)
{
SCMutexLock(&g_scratch_proto_mutex);
if (g_scratch_proto) {
SCLogPerf("Cleaning up Hyperscan global scratch");
hs_free_scratch(g_scratch_proto);
g_scratch_proto = NULL;
}
SCMutexUnlock(&g_scratch_proto_mutex);
SCMutexLock(&g_db_table_mutex);
if (g_db_table != NULL) {
SCLogPerf("Clearing Hyperscan database cache");
HashTableFree(g_db_table);
g_db_table = NULL;
}
SCMutexUnlock(&g_db_table_mutex);
}
/*************************************Unittests********************************/
#ifdef UNITTESTS
static int SCHSTest01(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghjiklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest02(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghjiklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 0)
result = 1;
else
printf("0 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest03(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghjiklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 3)
result = 1;
else
printf("3 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest04(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0);
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghjiklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest05(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghjiklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 3)
result = 1;
else
printf("3 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest06(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcd";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest07(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* should match 30 times */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0);
/* should match 29 times */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0);
/* should match 28 times */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0);
/* 26 */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0);
/* 21 */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0);
/* 1 */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30,
0, 0, 5, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 6)
result = 1;
else
printf("6 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest08(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
uint32_t cnt =
SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1);
if (cnt == 0)
result = 1;
else
printf("0 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest09(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
uint32_t cnt =
SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2);
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest10(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789"
"abcdefgh"
"01234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest11(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1)
goto end;
if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1)
goto end;
if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1)
goto end;
if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1)
goto end;
PmqSetup(&pmq);
if (SCHSPreparePatterns(&mpm_ctx) == -1)
goto end;
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
result = 1;
const char *buf = "he";
result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf)) == 1);
buf = "she";
result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf)) == 2);
buf = "his";
result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf)) == 1);
buf = "hers";
result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf)) == 2);
end:
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest12(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 2)
result = 1;
else
printf("2 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest13(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyzABCD";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest14(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest15(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest16(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
const char pat[] = "abcdefghijklmnopqrstuvwxyzABC";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyzABC";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest17(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
const char pat[] = "abcdefghijklmnopqrstuvwxyzAB";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyzAB";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest18(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
const char pat[] = "abcde"
"fghij"
"klmno"
"pqrst"
"uvwxy"
"z";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcde"
"fghij"
"klmno"
"pqrst"
"uvwxy"
"z";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest19(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 */
const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest20(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 */
const char pat[] = "AAAAA"
"AAAAA"
"AAAAA"
"AAAAA"
"AAAAA"
"AAAAA"
"AA";
MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "AAAAA"
"AAAAA"
"AAAAA"
"AAAAA"
"AAAAA"
"AAAAA"
"AA";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest21(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
uint32_t cnt =
SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2);
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest22(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
/* 1 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "abcdefghijklmnopqrstuvwxyz";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 2)
result = 1;
else
printf("2 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest23(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
uint32_t cnt =
SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2);
if (cnt == 0)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest24(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 1 */
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
uint32_t cnt =
SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2);
if (cnt == 1)
result = 1;
else
printf("1 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest25(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 3)
result = 1;
else
printf("3 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest26(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0);
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "works";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 1)
result = 1;
else
printf("3 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest27(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 0 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "tone";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 0)
result = 1;
else
printf("0 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest28(void)
{
int result = 0;
MpmCtx mpm_ctx;
MpmThreadCtx mpm_thread_ctx;
PrefilterRuleStore pmq;
memset(&mpm_ctx, 0, sizeof(MpmCtx));
memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
MpmInitCtx(&mpm_ctx, MPM_HS);
/* 0 match */
MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0);
PmqSetup(&pmq);
SCHSPreparePatterns(&mpm_ctx);
SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
const char *buf = "tONE";
uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
strlen(buf));
if (cnt == 0)
result = 1;
else
printf("0 != %" PRIu32 " ", cnt);
SCHSDestroyCtx(&mpm_ctx);
SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
PmqFree(&pmq);
return result;
}
static int SCHSTest29(void)
{
uint8_t buf[] = "onetwothreefourfivesixseveneightnine";
uint16_t buflen = sizeof(buf) - 1;
Packet *p = NULL;
ThreadVars th_v;
DetectEngineThreadCtx *det_ctx = NULL;
int result = 0;
memset(&th_v, 0, sizeof(th_v));
p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL)
goto end;
de_ctx->mpm_matcher = MPM_HS;
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(
de_ctx, "alert tcp any any -> any any "
"(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)");
if (de_ctx->sig_list == NULL)
goto end;
de_ctx->sig_list->next =
SigInit(de_ctx, "alert tcp any any -> any any "
"(content:\"onetwothreefourfivesixseveneightnine\"; "
"fast_pattern:3,3; sid:2;)");
if (de_ctx->sig_list->next == NULL)
goto end;
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1) != 1) {
printf("if (PacketAlertCheck(p, 1) != 1) failure\n");
goto end;
}
if (PacketAlertCheck(p, 2) != 1) {
printf("if (PacketAlertCheck(p, 1) != 2) failure\n");
goto end;
}
result = 1;
end:
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
}
UTHFreePackets(&p, 1);
return result;
}
#endif /* UNITTESTS */
void SCHSRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("SCHSTest01", SCHSTest01);
UtRegisterTest("SCHSTest02", SCHSTest02);
UtRegisterTest("SCHSTest03", SCHSTest03);
UtRegisterTest("SCHSTest04", SCHSTest04);
UtRegisterTest("SCHSTest05", SCHSTest05);
UtRegisterTest("SCHSTest06", SCHSTest06);
UtRegisterTest("SCHSTest07", SCHSTest07);
UtRegisterTest("SCHSTest08", SCHSTest08);
UtRegisterTest("SCHSTest09", SCHSTest09);
UtRegisterTest("SCHSTest10", SCHSTest10);
UtRegisterTest("SCHSTest11", SCHSTest11);
UtRegisterTest("SCHSTest12", SCHSTest12);
UtRegisterTest("SCHSTest13", SCHSTest13);
UtRegisterTest("SCHSTest14", SCHSTest14);
UtRegisterTest("SCHSTest15", SCHSTest15);
UtRegisterTest("SCHSTest16", SCHSTest16);
UtRegisterTest("SCHSTest17", SCHSTest17);
UtRegisterTest("SCHSTest18", SCHSTest18);
UtRegisterTest("SCHSTest19", SCHSTest19);
UtRegisterTest("SCHSTest20", SCHSTest20);
UtRegisterTest("SCHSTest21", SCHSTest21);
UtRegisterTest("SCHSTest22", SCHSTest22);
UtRegisterTest("SCHSTest23", SCHSTest23);
UtRegisterTest("SCHSTest24", SCHSTest24);
UtRegisterTest("SCHSTest25", SCHSTest25);
UtRegisterTest("SCHSTest26", SCHSTest26);
UtRegisterTest("SCHSTest27", SCHSTest27);
UtRegisterTest("SCHSTest28", SCHSTest28);
UtRegisterTest("SCHSTest29", SCHSTest29);
#endif
return;
}
#endif /* BUILD_HYPERSCAN */