From 99f9179372baf7d25bed3961c24a28fc519d269e Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Nov 2023 09:52:15 +0100 Subject: [PATCH 1/6] mpm: cleanup pattern free function Avoid redundant pointer checks; instead check once. --- src/util-mpm.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/util-mpm.c b/src/util-mpm.c index 0638a8876c53..0910c7407263 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -358,30 +358,30 @@ static inline MpmPattern *MpmAllocPattern(MpmCtx *mpm_ctx) */ void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p) { - if (p != NULL && p->cs != NULL && p->cs != p->ci) { + if (p == NULL) + return; + + if (p->cs != NULL && p->cs != p->ci) { SCFree(p->cs); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } - if (p != NULL && p->ci != NULL) { + if (p->ci != NULL) { SCFree(p->ci); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } - if (p != NULL && p->original_pat != NULL) { + if (p->original_pat != NULL) { SCFree(p->original_pat); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= p->len; } - if (p != NULL) { - SCFree(p); - mpm_ctx->memory_cnt--; - mpm_ctx->memory_size -= sizeof(MpmPattern); - } - return; + SCFree(p); + mpm_ctx->memory_cnt--; + mpm_ctx->memory_size -= sizeof(MpmPattern); } static inline uint32_t MpmInitHash(MpmPattern *p) From c2e4527fd65495ba1970ea4cca531fe5520efe8c Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Nov 2023 10:05:55 +0100 Subject: [PATCH 2/6] mpm: free sids in MpmFreePattern as well --- src/util-mpm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util-mpm.c b/src/util-mpm.c index 0910c7407263..3fb10c0e8bff 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -379,6 +379,10 @@ void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p) mpm_ctx->memory_size -= p->len; } + if (p->sids != NULL) { + SCFree(p->sids); + } + SCFree(p); mpm_ctx->memory_cnt--; mpm_ctx->memory_size -= sizeof(MpmPattern); From 1fca02d106264a2aa186f7e0b12df6dce72fbdce Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Nov 2023 13:18:42 +0100 Subject: [PATCH 3/6] ac/bs: reset sids pointer after xfer --- src/util-mpm-ac-bs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util-mpm-ac-bs.c b/src/util-mpm-ac-bs.c index 72d2065ca7c1..db010d7f6fbd 100644 --- a/src/util-mpm-ac-bs.c +++ b/src/util-mpm-ac-bs.c @@ -906,6 +906,8 @@ int SCACBSPreparePatterns(MpmCtx *mpm_ctx) /* ACPatternList now owns this memory */ ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size; ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids; + ctx->parray[i]->sids = NULL; + ctx->parray[i]->sids_size = 0; } /* prepare the state table required by AC */ From 47f2bc384dfa175de9656f020c93ee7540bb2df0 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Nov 2023 11:41:58 +0100 Subject: [PATCH 4/6] util/prefilter: constify sids --- src/util-prefilter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-prefilter.h b/src/util-prefilter.h index b956143114ab..67c24d6c9de7 100644 --- a/src/util-prefilter.h +++ b/src/util-prefilter.h @@ -58,8 +58,8 @@ int PrefilterAddSidsResize(PrefilterRuleStore *pmq, uint32_t new_size); * \param sids_size number of Signature IDs in sids array. * */ -static inline void -PrefilterAddSids(PrefilterRuleStore *pmq, SigIntId *sids, uint32_t sids_size) +static inline void PrefilterAddSids( + PrefilterRuleStore *pmq, const SigIntId *sids, uint32_t sids_size) { if (sids_size == 0) return; From fbd0919792e218710c232e9067d2514fa3f1943a Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 26 Nov 2023 07:12:12 +0100 Subject: [PATCH 5/6] mpm/ac-rs: AC matcher based on aho-corasick crate Count uniq matches only, like the Hyperscan implementation. Ticket: #3847. --- rust/Cargo.toml.in | 1 + rust/src/common.rs | 157 ++++++ src/Makefile.am | 2 + src/util-mpm-ac-rs.c | 1210 ++++++++++++++++++++++++++++++++++++++++++ src/util-mpm-ac-rs.h | 30 ++ src/util-mpm.c | 2 + src/util-mpm.h | 1 + 7 files changed, 1403 insertions(+) create mode 100644 src/util-mpm-ac-rs.c create mode 100644 src/util-mpm-ac-rs.h diff --git a/rust/Cargo.toml.in b/rust/Cargo.toml.in index 0bac7e159e0a..b97279c7048f 100644 --- a/rust/Cargo.toml.in +++ b/rust/Cargo.toml.in @@ -38,6 +38,7 @@ brotli = "~3.4.0" hkdf = "~0.12.3" aes = "~0.7.5" aes-gcm = "~0.9.4" +aho-corasick = "1.1.2" der-parser = "~8.2.0" kerberos-parser = { version = "~0.7.1", default_features = false } diff --git a/rust/src/common.rs b/rust/src/common.rs index 1d10bbe443d0..e4268bef0247 100644 --- a/rust/src/common.rs +++ b/rust/src/common.rs @@ -152,3 +152,160 @@ pub unsafe extern "C" fn rs_to_hex_sep( // overwrites last separator with final null char oslice[3 * islice.len() - 1] = 0; } + +use aho_corasick::AhoCorasick; +use std::collections::HashMap; + +#[derive(Debug,Clone)] +struct AhoCorasickPatternData { + pat: Vec, + sids: Vec, + ci: bool, + offset: u16, + depth: u16, +} + +impl AhoCorasickPatternData { + fn new(pat: Vec, ci: bool, sids: Vec, offset: u16, depth: u16) -> Self { + Self { pat, ci, sids, offset, depth } + } +} + +#[derive(Default)] +pub struct AhoCorasickStateBuilder { + /// vector of patterns. The final pattern id will depend on the position in this + /// vector, starting at 0. + patterns: Vec>, + pattern_id: u32, + /// Hash of patterns with their settings. Will be copied to AhoCorasickStateBuilder + /// in the prepare step. + pattern_data: HashMap, + /// track if we have case insensitive patterns. If so, we need to tell AC and + /// do a bit more work in validation. + has_ci: bool, +} + +impl AhoCorasickStateBuilder { + fn new() -> Self { + Self { ..Default::default() } + } + fn add_pattern(&mut self, pat: Vec, ci: bool, sids: Vec, offset: u16, depth: u16) { + self.patterns.push(pat.clone()); + if ci { + self.has_ci = true; + } + let pattern_id = self.pattern_id; + self.pattern_id += 1; + + self.pattern_data.insert(pattern_id, AhoCorasickPatternData::new(pat.clone(), ci, sids, offset, depth)); + } +} + +#[no_mangle] +pub extern "C" fn rs_mpm_acrs_new_builder() -> *mut std::os::raw::c_void { + let state = AhoCorasickStateBuilder::new(); + let boxed = Box::new(state); + return Box::into_raw(boxed) as *mut _; +} + +#[no_mangle] +pub extern "C" fn rs_mpm_acrs_free_builder(state: *mut std::os::raw::c_void) { + let mut _state = unsafe { Box::from_raw(state as *mut AhoCorasickStateBuilder) }; +} + +#[no_mangle] +pub unsafe extern "C" fn rs_mpm_acrs_add_pattern(state: &mut AhoCorasickStateBuilder, + pat: *mut u8, pat_len: u16, sids: *mut u32, sids_len: u32, ci: bool, offset: u16, depth: u16) -> i32 { + let p = unsafe { build_slice!(pat, pat_len as usize) }; + let s = unsafe { build_slice!(sids, sids_len as usize) }; + state.add_pattern(p.to_vec(), ci, s.to_vec(), offset, depth); + return 0; +} + +pub struct AhoCorasickState { + pattern_cnt: u32, + pattern_data: HashMap, + has_ci: bool, + ac: AhoCorasick, +} + +impl AhoCorasickState { + /// build the AC state from the builder + fn prepare(builder: &AhoCorasickStateBuilder) -> Self { + let ac = AhoCorasick::builder() + .ascii_case_insensitive(builder.has_ci) + .build(&builder.patterns) + .unwrap(); + Self { ac, has_ci: builder.has_ci, pattern_cnt: builder.pattern_id, pattern_data: builder.pattern_data.clone() } + } + + /// Search for the patterns. Returns number of matches. + /// Per pattern found sids are only appended once. + /// TODO review match_cnt logic. In general it's tuned to the unittests now, but it leads to + /// some inefficienty. Could make sense to check the bool array first instead of doing the + /// hash map lookup. + fn search(&self, haystack: &[u8], sids: &mut Vec) -> u32 { + SCLogDebug!("haystack {:?}: looking for {} patterns. Has CI {}", haystack, self.pattern_cnt, self.has_ci); + let mut match_cnt = 0; + // array of bools for patterns we found + let mut matches = vec![false; self.pattern_cnt as usize]; + for mat in self.ac.find_overlapping_iter(haystack) { + let pat_id = mat.pattern(); + /* bail if we found this pattern before */ + if matches[pat_id] { + SCLogDebug!("pattern {:?} already found", pat_id); + continue; + } + + let pattern = self.pattern_data.get(&pat_id.as_u32()).unwrap(); + if self.has_ci && !pattern.ci { + let found = &haystack[mat.start()..mat.end()]; + if found != pattern.pat { + SCLogDebug!("pattern {:?} failed: not an exact match", pat_id); + continue; + } + } + + /* enforce offset and depth */ + if pattern.offset as usize > mat.start() { + SCLogDebug!("pattern {:?} failed: found before offset", pat_id); + continue; + } + if pattern.depth != 0 && mat.end() > pattern.depth as usize { + SCLogDebug!("pattern {:?} failed: after depth", pat_id); + continue; + } + matches[pat_id] = true; + SCLogDebug!("match! {:?}: {:?}", pat_id, pattern); + sids.append(&mut pattern.sids.clone()); + match_cnt += 1; + } + return match_cnt; + } +} + +#[no_mangle] +pub extern "C" fn rs_mpm_acrs_prepare_builder(builder: &AhoCorasickStateBuilder) -> *mut std::os::raw::c_void { + let state = AhoCorasickState::prepare(builder); + let boxed = Box::new(state); + return Box::into_raw(boxed) as *mut _; +} +#[no_mangle] +pub extern "C" fn rs_mpm_acrs_state_free(state: *mut std::os::raw::c_void) { + let mut _state = unsafe { Box::from_raw(state as *mut AhoCorasickState) }; +} + +#[no_mangle] +pub unsafe extern "C" fn rs_mpm_acrs_search(state: &AhoCorasickState, data: *const u8, data_len: u32, + cb: unsafe extern "C" fn(*mut std::os::raw::c_void, *const u32, u32), + cbdata: *mut std::os::raw::c_void) -> u32 +{ + let mut sids: Vec = Vec::new(); + let data = unsafe { build_slice!(data, data_len as usize) }; + let matches = state.search(data, &mut sids); + if !sids.is_empty() { + let sids_s = sids.as_ptr(); + unsafe { cb(cbdata, sids_s, sids.len() as u32); }; + } + matches +} diff --git a/src/Makefile.am b/src/Makefile.am index 21e1dfe5fbeb..63d74a3feb5f 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -581,6 +581,7 @@ noinst_HEADERS = \ util-mpm-ac-bs.h \ util-mpm-ac.h \ util-mpm-ac-ks.h \ + util-mpm-ac-rs.h \ util-mpm.h \ util-mpm-hs.h \ util-napatech.h \ @@ -1181,6 +1182,7 @@ libsuricata_c_a_SOURCES = \ util-mpm-ac.c \ util-mpm-ac-ks.c \ util-mpm-ac-ks-small.c \ + util-mpm-ac-rs.c \ util-mpm.c \ util-mpm-hs.c \ util-napatech.c \ diff --git a/src/util-mpm-ac-rs.c b/src/util-mpm-ac-rs.c new file mode 100644 index 000000000000..4e4b8b913f12 --- /dev/null +++ b/src/util-mpm-ac-rs.c @@ -0,0 +1,1210 @@ +/* Copyright (C) 2007-2023 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 + * + * Wrapper around "aho-corasick" Rust crate. + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "rust.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-build.h" + +#include "conf.h" +#include "util-debug.h" +#include "util-unittest.h" +#include "util-unittest-helper.h" +#include "util-memcmp.h" +#include "util-mpm-ac-rs.h" +#include "util-memcpy.h" +#include "util-validate.h" + +/** + * \brief Process the patterns added to the mpm, and create the internal tables. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static int SCACRSPreparePatterns(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) { + SCLogDebug("no patterns supplied to this mpm_ctx"); + return 0; + } + + AhoCorasickStateBuilder *builder = rs_mpm_acrs_new_builder(); + if (builder == NULL) + return -1; + + /* populate it with the patterns in the hash */ + for (uint32_t i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL; + while (node != NULL) { + nnode = node->next; + + if (node->cs) { + rs_mpm_acrs_add_pattern(builder, node->cs, node->len, node->sids, node->sids_size, + (node->flags & MPM_PATTERN_FLAG_NOCASE) != 0, node->offset, node->depth); + } else { + rs_mpm_acrs_add_pattern(builder, node->ci, node->len, node->sids, node->sids_size, + (node->flags & MPM_PATTERN_FLAG_NOCASE) != 0, node->offset, node->depth); + } + + MpmFreePattern(mpm_ctx, node); + + node = nnode; + } + } + /* we no longer need the hash, so free it's memory */ + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; + + mpm_ctx->ctx = rs_mpm_acrs_prepare_builder(builder); + rs_mpm_acrs_free_builder(builder); + SCLogDebug("mpm_ctx->ctx %p", mpm_ctx->ctx); + return 0; +} + +/** + * \brief Initialize the AC context. + * + * \param mpm_ctx Mpm context. + * \todo it seems we can be called multiple times, probably due to MpmCtx::ctx not + * getting initialized yet until "Prepare". + */ +static void SCACRSInitCtx(MpmCtx *mpm_ctx) +{ + /* initialize the hash we use to speed up pattern insertions */ + if (mpm_ctx->init_hash == NULL) { + mpm_ctx->init_hash = SCCalloc(MPM_INIT_HASH_SIZE, sizeof(MpmPattern *)); + if (mpm_ctx->init_hash == NULL) { + FatalError("calloc mpm_ctx->init_hash failed"); + } + } +} + +/** + * \brief Destroy the mpm context. + * + * \param mpm_ctx Pointer to the mpm context. + */ +static void SCACRSDestroyCtx(MpmCtx *mpm_ctx) +{ + if (mpm_ctx->init_hash != NULL) { + for (uint32_t i = 0; i < MPM_INIT_HASH_SIZE; i++) { + MpmPattern *node = mpm_ctx->init_hash[i]; + while (node != NULL) { + MpmPattern *next = node->next; + MpmFreePattern(mpm_ctx, node); + node = next; + } + } + SCFree(mpm_ctx->init_hash); + mpm_ctx->init_hash = NULL; + } + if (mpm_ctx->ctx) { + rs_mpm_acrs_state_free(mpm_ctx->ctx); + mpm_ctx->ctx = NULL; + } +} + +static void SCACRSSearchAddSids(void *pmqv, const uint32_t *sids, uint32_t size) +{ + PrefilterAddSids(pmqv, sids, size); +} + +/** + * \brief The aho corasick 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. + */ +static uint32_t SCACRSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, + PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen) +{ + uint32_t r = rs_mpm_acrs_search(mpm_ctx->ctx, buf, buflen, SCACRSSearchAddSids, pmq); + return r; +} + +/** + * \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 patnen The pattern length. + * \param offset Ignored. + * \param depth Ignored. + * \param pid The pattern id. + * \param sid Ignored. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int SCACRSAddPatternCI(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 MpmAddPattern(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 patnen The pattern length. + * \param offset Ignored. + * \param depth Ignored. + * \param pid The pattern id. + * \param sid Ignored. + * \param flags Flags associated with this pattern. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +static int SCACRSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, + uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags) +{ + return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags); +} + +static void SCACRSPrintInfo(MpmCtx *mpm_ctx) +{ + printf("MPM AC 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(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern)); + 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"); + + return; +} + +/************************** Mpm Registration ***************************/ + +#ifdef UNITTESTS +static void SCACRSRegisterTests(void); +#endif + +/** + * \brief Register the aho-corasick mpm. + */ +void MpmACRSRegister(void) +{ + mpm_table[MPM_AC_RS].name = "ac-rs"; + mpm_table[MPM_AC_RS].InitCtx = SCACRSInitCtx; + mpm_table[MPM_AC_RS].DestroyCtx = SCACRSDestroyCtx; + mpm_table[MPM_AC_RS].AddPattern = SCACRSAddPatternCS; + mpm_table[MPM_AC_RS].AddPatternNocase = SCACRSAddPatternCI; + mpm_table[MPM_AC_RS].Prepare = SCACRSPreparePatterns; + mpm_table[MPM_AC_RS].Search = SCACRSSearch; + mpm_table[MPM_AC_RS].PrintCtx = SCACRSPrintInfo; +#ifdef UNITTESTS + mpm_table[MPM_AC_RS].RegisterUnittests = SCACRSRegisterTests; +#endif +} + +/*************************************Unittests********************************/ + +#ifdef UNITTESTS +#include "detect-engine-alert.h" + +static int SCACRSTest01(void) +{ + 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_AC_RS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 1); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACRSTest02(void) +{ + 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_AC_RS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 0); + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACRSTest03(void) +{ + 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_AC_RS); + + /* 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 3); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACRSTest04(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_AC_RS); + + 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest05(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_AC_RS); + + 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghjiklmnopqrstuvwxyz"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest06(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_AC_RS); + + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcd"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest07(void) +{ + 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_AC_RS); + + /* 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); + /* total matches: 135 -> however we count only 1 per pattern */ + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 6); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACRSTest08(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_AC_RS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest09(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_AC_RS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest10(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_AC_RS); + + /* 1 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "abcdefgh" + "01234567890123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest11(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_AC_RS); + + 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 (SCACRSPreparePatterns(&mpm_ctx) == -1) + goto end; + + result = 1; + + const char *buf = "he"; + result &= (SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "she"; + result &= (SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + buf = "his"; + result &= (SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 1); + buf = "hers"; + result &= (SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)) == 2); + +end: + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest12(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_AC_RS); + + /* 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest13(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_AC_RS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCD"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest14(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_AC_RS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest15(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_AC_RS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest16(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_AC_RS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzABC"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzABC"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest17(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_AC_RS); + + /* 1 match */ + const char pat[] = "abcdefghijklmnopqrstuvwxyzAB"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyzAB"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest18(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_AC_RS); + + /* 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest19(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_AC_RS); + + /* 1 */ + const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest20(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_AC_RS); + + /* 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AAAAA" + "AA"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest21(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_AC_RS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest22(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_AC_RS); + + /* 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "abcdefghijklmnopqrstuvwxyz"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 2) + result = 1; + else + printf("2 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest23(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_AC_RS); + + /* 1 */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 0) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest24(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_AC_RS); + + /* 1 */ + MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2); + + if (cnt == 1) + result = 1; + else + printf("1 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest25(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_AC_RS); + + 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 3) + result = 1; + else + printf("3 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest26(void) +{ + 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_AC_RS); + + 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); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "works"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + FAIL_IF_NOT(cnt == 1); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + PASS; +} + +static int SCACRSTest27(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_AC_RS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "tone"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest28(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_AC_RS); + + /* 0 match */ + MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0); + PmqSetup(&pmq); + + SCACRSPreparePatterns(&mpm_ctx); + + const char *buf = "tONE"; + uint32_t cnt = SCACRSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf, strlen(buf)); + + if (cnt == 0) + result = 1; + else + printf("0 != %" PRIu32 " ", cnt); + + SCACRSDestroyCtx(&mpm_ctx); + PmqFree(&pmq); + return result; +} + +static int SCACRSTest29(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->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; +} + +static void SCACRSRegisterTests(void) +{ + UtRegisterTest("SCACRSTest01", SCACRSTest01); + UtRegisterTest("SCACRSTest02", SCACRSTest02); + UtRegisterTest("SCACRSTest03", SCACRSTest03); + UtRegisterTest("SCACRSTest04", SCACRSTest04); + UtRegisterTest("SCACRSTest05", SCACRSTest05); + UtRegisterTest("SCACRSTest06", SCACRSTest06); + UtRegisterTest("SCACRSTest07", SCACRSTest07); + UtRegisterTest("SCACRSTest08", SCACRSTest08); + UtRegisterTest("SCACRSTest09", SCACRSTest09); + UtRegisterTest("SCACRSTest10", SCACRSTest10); + UtRegisterTest("SCACRSTest11", SCACRSTest11); + UtRegisterTest("SCACRSTest12", SCACRSTest12); + UtRegisterTest("SCACRSTest13", SCACRSTest13); + UtRegisterTest("SCACRSTest14", SCACRSTest14); + UtRegisterTest("SCACRSTest15", SCACRSTest15); + UtRegisterTest("SCACRSTest16", SCACRSTest16); + UtRegisterTest("SCACRSTest17", SCACRSTest17); + UtRegisterTest("SCACRSTest18", SCACRSTest18); + UtRegisterTest("SCACRSTest19", SCACRSTest19); + UtRegisterTest("SCACRSTest20", SCACRSTest20); + UtRegisterTest("SCACRSTest21", SCACRSTest21); + UtRegisterTest("SCACRSTest22", SCACRSTest22); + UtRegisterTest("SCACRSTest23", SCACRSTest23); + UtRegisterTest("SCACRSTest24", SCACRSTest24); + UtRegisterTest("SCACRSTest25", SCACRSTest25); + UtRegisterTest("SCACRSTest26", SCACRSTest26); + UtRegisterTest("SCACRSTest27", SCACRSTest27); + UtRegisterTest("SCACRSTest28", SCACRSTest28); + UtRegisterTest("SCACRSTest29", SCACRSTest29); +} +#endif diff --git a/src/util-mpm-ac-rs.h b/src/util-mpm-ac-rs.h new file mode 100644 index 000000000000..6a3cfb5762bb --- /dev/null +++ b/src/util-mpm-ac-rs.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2007-2023 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 + * + */ + +#ifndef __UTIL_MPM_AC_RS_H__ +#define __UTIL_MPM_AC_RS_H__ + +#include "util-mpm.h" + +void MpmACRSRegister(void); + +#endif /* __UTIL_MPM_AC_RS_H__ */ diff --git a/src/util-mpm.c b/src/util-mpm.c index 3fb10c0e8bff..ca5d5ccddc95 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -31,6 +31,7 @@ #include "util-mpm-ac.h" #include "util-mpm-ac-bs.h" #include "util-mpm-ac-ks.h" +#include "util-mpm-ac-rs.h" #include "util-mpm-hs.h" #include "util-hashlist.h" @@ -231,6 +232,7 @@ void MpmTableSetup(void) MpmACRegister(); MpmACBSRegister(); MpmACTileRegister(); + MpmACRSRegister(); #ifdef BUILD_HYPERSCAN #ifdef HAVE_HS_VALID_PLATFORM /* Enable runtime check for SSSE3. Do not use Hyperscan MPM matcher if diff --git a/src/util-mpm.h b/src/util-mpm.h index 87eec5e793a9..defe29461da7 100644 --- a/src/util-mpm.h +++ b/src/util-mpm.h @@ -37,6 +37,7 @@ enum { MPM_AC_BS, MPM_AC_KS, MPM_HS, + MPM_AC_RS, /* table size */ MPM_TABLE_SIZE, }; From c5811c734a1e4afb05d9de416983df99f2e12b94 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Mon, 27 Nov 2023 12:52:16 +0100 Subject: [PATCH 6/6] TEST default to mpm-algo=ac-rs for testing purposes --- src/util-mpm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util-mpm.c b/src/util-mpm.c index ca5d5ccddc95..62fc47425bef 100644 --- a/src/util-mpm.c +++ b/src/util-mpm.c @@ -218,10 +218,10 @@ void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher) /* MPM matcher to use by default, i.e. when "mpm-algo" is set to "auto". * If Hyperscan is available, use it. Otherwise, use AC. */ #ifdef BUILD_HYPERSCAN -# define DEFAULT_MPM MPM_HS -# define DEFAULT_MPM_AC MPM_AC +#define DEFAULT_MPM MPM_AC_RS +#define DEFAULT_MPM_AC MPM_AC_RS #else -# define DEFAULT_MPM MPM_AC +#define DEFAULT_MPM MPM_AC_RS #endif void MpmTableSetup(void)