suricata
util-mpm-hs.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Jim Xu <jim.xu@windriver.com>
22  * \author Justin Viiret <justin.viiret@intel.com>
23  *
24  * MPM pattern matcher that calls the Hyperscan regex matcher.
25  */
26 
27 #include "suricata-common.h"
28 #include "suricata.h"
29 
30 #include "detect.h"
31 #include "detect-parse.h"
32 #include "detect-engine.h"
33 #include "detect-engine-build.h"
34 
35 #include "conf.h"
36 #include "util-conf.h"
37 #include "util-debug.h"
38 #include "util-unittest.h"
39 #include "util-unittest-helper.h"
40 #include "util-memcmp.h"
41 #include "util-mpm-hs.h"
42 #include "util-mpm-hs-cache.h"
43 #include "util-mpm-hs-core.h"
44 #include "util-memcpy.h"
45 #include "util-hash.h"
46 #include "util-hash-lookup3.h"
47 #include "util-hyperscan.h"
48 #include "util-path.h"
49 
50 #ifdef BUILD_HYPERSCAN
51 
52 #include <hs.h>
53 
54 void SCHSInitCtx(MpmCtx *);
55 void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *);
56 void SCHSDestroyCtx(MpmCtx *);
57 void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *);
58 int SCHSAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
59  uint32_t, SigIntId, uint8_t);
60 int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
61  uint32_t, SigIntId, uint8_t);
62 int SCHSPreparePatterns(MpmConfig *mpm_conf, MpmCtx *mpm_ctx);
63 uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
64  PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen);
65 void SCHSPrintInfo(MpmCtx *mpm_ctx);
66 void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx);
67 #ifdef UNITTESTS
68 static void SCHSRegisterTests(void);
69 #endif
70 
71 /* size of the hash table used to speed up pattern insertions initially */
72 #define INIT_HASH_SIZE 65536
73 
74 /* Initial size of the global database hash (used for de-duplication). */
75 #define INIT_DB_HASH_SIZE 1000
76 
77 /* Global prototype scratch, built incrementally as Hyperscan databases are
78  * built and then cloned for each thread context. Access is serialised via
79  * g_scratch_proto_mutex. */
80 static hs_scratch_t *g_scratch_proto = NULL;
81 static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER;
82 
83 /* Global hash table of Hyperscan databases, used for de-duplication. Access is
84  * serialised via g_db_table_mutex. */
85 static HashTable *g_db_table = NULL;
86 static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER;
87 
88 /**
89  * \internal
90  * \brief Wraps SCMalloc (which is a macro) so that it can be passed to
91  * hs_set_allocator() for Hyperscan's use.
92  */
93 static void *SCHSMalloc(size_t size)
94 {
95  return SCMalloc(size);
96 }
97 
98 /**
99  * \internal
100  * \brief Wraps SCFree (which is a macro) so that it can be passed to
101  * hs_set_allocator() for Hyperscan's use.
102  */
103 static void SCHSFree(void *ptr)
104 {
105  SCFree(ptr);
106 }
107 
108 /** \brief Register Suricata malloc/free with Hyperscan.
109  *
110  * Requests that Hyperscan use Suricata's allocator for allocation of
111  * databases, scratch space, etc.
112  */
113 static void SCHSSetAllocators(void)
114 {
115  hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree);
116  if (err != HS_SUCCESS) {
117  FatalError("Failed to set Hyperscan allocator.");
118  }
119 }
120 
121 /**
122  * \internal
123  * \brief Creates a hash of the pattern. We use it for the hashing process
124  * during the initial pattern insertion time, to cull duplicate sigs.
125  *
126  * \param pat Pointer to the pattern.
127  * \param patlen Pattern length.
128  *
129  * \retval hash A 32 bit unsigned hash.
130  */
131 static inline uint32_t SCHSInitHashRaw(uint8_t *pat, uint16_t patlen)
132 {
133  uint32_t hash = patlen * pat[0];
134  if (patlen > 1)
135  hash += pat[1];
136 
137  return (hash % INIT_HASH_SIZE);
138 }
139 
140 /**
141  * \internal
142  * \brief Looks up a pattern. We use it for the hashing process during
143  * the initial pattern insertion time, to cull duplicate sigs.
144  *
145  * \param ctx Pointer to the HS ctx.
146  * \param pat Pointer to the pattern.
147  * \param patlen Pattern length.
148  * \param flags Flags. We don't need this.
149  *
150  * \retval hash A 32 bit unsigned hash.
151  */
152 static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, uint8_t *pat,
153  uint16_t patlen, uint16_t offset,
154  uint16_t depth, char flags,
155  uint32_t pid)
156 {
157  uint32_t hash = SCHSInitHashRaw(pat, patlen);
158 
159  if (ctx->init_hash == NULL) {
160  return NULL;
161  }
162 
163  SCHSPattern *t = ctx->init_hash[hash];
164  for (; t != NULL; t = t->next) {
165  /* Since Hyperscan uses offset/depth, we must distinguish between
166  * patterns with the same ID but different offset/depth here. */
167  if (t->id == pid && t->offset == offset && t->depth == depth) {
168  BUG_ON(t->len != patlen);
169  BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0);
170  return t;
171  }
172  }
173 
174  return NULL;
175 }
176 
177 /**
178  * \internal
179  * \brief Allocates a new pattern instance.
180  *
181  * \param mpm_ctx Pointer to the mpm context.
182  *
183  * \retval p Pointer to the newly created pattern.
184  */
185 static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx)
186 {
187  SCHSPattern *p = SCCalloc(1, sizeof(SCHSPattern));
188  if (unlikely(p == NULL)) {
189  exit(EXIT_FAILURE);
190  }
191 
192  mpm_ctx->memory_cnt++;
193  mpm_ctx->memory_size += sizeof(SCHSPattern);
194 
195  return p;
196 }
197 
198 /**
199  * \internal
200  * \brief Used to free SCHSPattern instances.
201  *
202  * \param mpm_ctx Pointer to the mpm context.
203  * \param p Pointer to the SCHSPattern instance to be freed.
204  * \param free Free the above pointer or not.
205  */
206 static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p)
207 {
208  if (p != NULL && p->original_pat != NULL) {
209  SCFree(p->original_pat);
210  mpm_ctx->memory_cnt--;
211  mpm_ctx->memory_size -= p->len;
212  }
213 
214  if (p != NULL && p->sids != NULL) {
215  SCFree(p->sids);
216  }
217 
218  if (p != NULL) {
219  SCFree(p);
220  mpm_ctx->memory_cnt--;
221  mpm_ctx->memory_size -= sizeof(SCHSPattern);
222  }
223 }
224 
225 static inline uint32_t SCHSInitHash(SCHSPattern *p)
226 {
227  uint32_t hash = p->len * p->original_pat[0];
228  if (p->len > 1)
229  hash += p->original_pat[1];
230 
231  return (hash % INIT_HASH_SIZE);
232 }
233 
234 static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p)
235 {
236  uint32_t hash = SCHSInitHash(p);
237 
238  if (ctx->init_hash == NULL) {
239  return -1;
240  }
241 
242  if (ctx->init_hash[hash] == NULL) {
243  ctx->init_hash[hash] = p;
244  return 0;
245  }
246 
247  SCHSPattern *tt = NULL;
248  SCHSPattern *t = ctx->init_hash[hash];
249 
250  /* get the list tail */
251  do {
252  tt = t;
253  t = t->next;
254  } while (t != NULL);
255 
256  tt->next = p;
257 
258  return 0;
259 }
260 
261 /**
262  * \internal
263  * \brief Add a pattern to the mpm-hs context.
264  *
265  * \param mpm_ctx Mpm context.
266  * \param pat Pointer to the pattern.
267  * \param patlen Length of the pattern.
268  * \param pid Pattern id
269  * \param sid Signature id (internal id).
270  * \param flags Pattern's MPM_PATTERN_* flags.
271  *
272  * \retval 0 On success.
273  * \retval -1 On failure.
274  */
275 static int SCHSAddPattern(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
276  uint16_t offset, uint16_t depth, uint32_t pid,
277  SigIntId sid, uint8_t flags)
278 {
279  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
280 
281  if (offset != 0) {
283  }
284  if (depth != 0) {
286  }
287 
288  if (patlen == 0) {
289  SCLogWarning("pattern length 0");
290  return 0;
291  }
292 
293  /* check if we have already inserted this pattern */
294  SCHSPattern *p =
295  SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid);
296  if (p == NULL) {
297  SCLogDebug("Allocing new pattern");
298 
299  /* p will never be NULL */
300  p = SCHSAllocPattern(mpm_ctx);
301 
302  p->len = patlen;
303  p->flags = flags;
304  p->id = pid;
305 
306  p->offset = offset;
307  p->depth = depth;
308 
309  p->original_pat = SCMalloc(patlen);
310  if (p->original_pat == NULL)
311  goto error;
312  mpm_ctx->memory_cnt++;
313  mpm_ctx->memory_size += patlen;
314  memcpy(p->original_pat, pat, patlen);
315 
316  /* put in the pattern hash */
317  if (SCHSInitHashAdd(ctx, p) != 0)
318  goto error;
319 
320  mpm_ctx->pattern_cnt++;
321 
322  if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) {
323  if (depth) {
324  mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth);
325  SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth);
326  } else {
327  mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH;
328  mpm_ctx->maxdepth = 0;
329  SCLogDebug("%p: alas, no depth for us", mpm_ctx);
330  }
331  }
332 
333  if (mpm_ctx->maxlen < patlen)
334  mpm_ctx->maxlen = patlen;
335 
336  if (mpm_ctx->minlen == 0) {
337  mpm_ctx->minlen = patlen;
338  } else {
339  if (mpm_ctx->minlen > patlen)
340  mpm_ctx->minlen = patlen;
341  }
342 
343  p->sids_size = 1;
344  p->sids = SCMalloc(p->sids_size * sizeof(SigIntId));
345  BUG_ON(p->sids == NULL);
346  p->sids[0] = sid;
347  } else {
348  /* TODO figure out how we can be called multiple times for the same CTX with the same sid */
349 
350  int found = 0;
351  uint32_t x = 0;
352  for (x = 0; x < p->sids_size; x++) {
353  if (p->sids[x] == sid) {
354  found = 1;
355  break;
356  }
357  }
358  if (!found) {
359  SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1)));
360  BUG_ON(sids == NULL);
361  p->sids = sids;
362  p->sids[p->sids_size] = sid;
363  p->sids_size++;
364  }
365  }
366 
367  return 0;
368 
369 error:
370  SCHSFreePattern(mpm_ctx, p);
371  return -1;
372 }
373 
374 /**
375  * \brief Pattern database information used only as input to the Hyperscan
376  * compiler.
377  */
378 typedef struct SCHSCompileData_ {
379  unsigned int *ids;
380  unsigned int *flags;
381  char **expressions;
382  hs_expr_ext_t **ext;
383  unsigned int pattern_cnt;
384 } SCHSCompileData;
385 
386 static SCHSCompileData *CompileDataAlloc(unsigned int pattern_cnt)
387 {
388  SCHSCompileData *cd = SCCalloc(pattern_cnt, sizeof(SCHSCompileData));
389  if (cd == NULL) {
390  goto error;
391  }
392 
393  cd->pattern_cnt = pattern_cnt;
394 
395  cd->ids = SCCalloc(pattern_cnt, sizeof(unsigned int));
396  if (cd->ids == NULL) {
397  goto error;
398  }
399 
400  cd->flags = SCCalloc(pattern_cnt, sizeof(unsigned int));
401  if (cd->flags == NULL) {
402  goto error;
403  }
404 
405  cd->expressions = SCCalloc(pattern_cnt, sizeof(char *));
406  if (cd->expressions == NULL) {
407  goto error;
408  }
409 
410  cd->ext = SCCalloc(pattern_cnt, sizeof(hs_expr_ext_t *));
411  if (cd->ext == NULL) {
412  goto error;
413  }
414 
415  return cd;
416 
417 error:
418  SCLogDebug("SCHSCompileData alloc failed");
419  if (cd) {
420  SCFree(cd->ids);
421  SCFree(cd->flags);
422  SCFree(cd->expressions);
423  SCFree(cd->ext);
424  SCFree(cd);
425  }
426  return NULL;
427 }
428 
429 static void CompileDataFree(SCHSCompileData *cd)
430 {
431  if (cd == NULL) {
432  return;
433  }
434 
435  SCFree(cd->ids);
436  SCFree(cd->flags);
437  if (cd->expressions) {
438  for (unsigned int i = 0; i < cd->pattern_cnt; i++) {
439  SCFree(cd->expressions[i]);
440  }
441  SCFree(cd->expressions);
442  }
443  if (cd->ext) {
444  for (unsigned int i = 0; i < cd->pattern_cnt; i++) {
445  SCFree(cd->ext[i]);
446  }
447  SCFree(cd->ext);
448  }
449  SCFree(cd);
450 }
451 
452 static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash)
453 {
454  BUG_ON(p->original_pat == NULL);
455  BUG_ON(p->sids == NULL);
456 
457  hash = hashlittle_safe(&p->len, sizeof(p->len), hash);
458  hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash);
459  hash = hashlittle_safe(p->original_pat, p->len, hash);
460  hash = hashlittle_safe(&p->id, sizeof(p->id), hash);
461  hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash);
462  hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash);
463  hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash);
464  hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash);
465  return hash;
466 }
467 
468 static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2)
469 {
470  if ((p1->len != p2->len) || (p1->flags != p2->flags) ||
471  (p1->id != p2->id) || (p1->offset != p2->offset) ||
472  (p1->depth != p2->depth) || (p1->sids_size != p2->sids_size)) {
473  return 0;
474  }
475 
476  if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) {
477  return 0;
478  }
479 
480  if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) !=
481  0) {
482  return 0;
483  }
484 
485  return 1;
486 }
487 
488 static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len)
489 {
490  const PatternDatabase *pd = data;
491  uint32_t hash = 0;
492  hash = hashword(&pd->pattern_cnt, 1, hash);
493 
494  for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
495  hash = SCHSPatternHash(pd->parray[i], hash);
496  }
497 
498  hash %= ht->array_size;
499  return hash;
500 }
501 
502 static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2,
503  uint16_t len2)
504 {
505  const PatternDatabase *pd1 = data1;
506  const PatternDatabase *pd2 = data2;
507 
508  if (pd1->pattern_cnt != pd2->pattern_cnt) {
509  return 0;
510  }
511 
512  for (uint32_t i = 0; i < pd1->pattern_cnt; i++) {
513  if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) {
514  return 0;
515  }
516  }
517 
518  return 1;
519 }
520 
521 static void PatternDatabaseFree(PatternDatabase *pd)
522 {
523  BUG_ON(pd->ref_cnt != 0);
524 
525  if (pd->parray != NULL) {
526  for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
527  SCHSPattern *p = pd->parray[i];
528  if (p != NULL) {
529  SCFree(p->original_pat);
530  SCFree(p->sids);
531  SCFree(p);
532  }
533  }
534  SCFree(pd->parray);
535  }
536 
537  hs_free_database(pd->hs_db);
538 
539  SCFree(pd);
540 }
541 
542 static void PatternDatabaseTableFree(void *data)
543 {
544  /* Stub function handed to hash table; actual freeing of PatternDatabase
545  * structures is done in MPM destruction when the ref_cnt drops to zero. */
546 }
547 
548 static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt)
549 {
550  PatternDatabase *pd = SCCalloc(1, sizeof(PatternDatabase));
551  if (pd == NULL) {
552  return NULL;
553  }
554  pd->pattern_cnt = pattern_cnt;
555  pd->ref_cnt = 0;
556  pd->hs_db = NULL;
557  pd->cached = false;
558 
559  /* alloc the pattern array */
560  pd->parray = (SCHSPattern **)SCCalloc(pd->pattern_cnt, sizeof(SCHSPattern *));
561  if (pd->parray == NULL) {
562  SCFree(pd);
563  return NULL;
564  }
565 
566  return pd;
567 }
568 
569 static int HSCheckPatterns(MpmCtx *mpm_ctx, SCHSCtx *ctx)
570 {
571  if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) {
572  SCLogDebug("no patterns supplied to this mpm_ctx");
573  return 0;
574  }
575  return 1;
576 }
577 
578 static void HSPatternArrayPopulate(SCHSCtx *ctx, PatternDatabase *pd)
579 {
580  for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) {
581  SCHSPattern *node = ctx->init_hash[i];
582  SCHSPattern *nnode = NULL;
583  while (node != NULL) {
584  nnode = node->next;
585  node->next = NULL;
586  pd->parray[p++] = node;
587  node = nnode;
588  }
589  }
590 }
591 
592 static void HSPatternArrayInit(SCHSCtx *ctx, PatternDatabase *pd)
593 {
594  HSPatternArrayPopulate(ctx, pd);
595  /* we no longer need the hash, so free its memory */
596  SCFree(ctx->init_hash);
597  ctx->init_hash = NULL;
598 }
599 
600 static int HSGlobalPatternDatabaseInit(void)
601 {
602  if (g_db_table == NULL) {
603  g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash,
604  PatternDatabaseCompare,
605  PatternDatabaseTableFree);
606  if (g_db_table == NULL) {
607  return -1;
608  }
609  }
610  return 0;
611 }
612 
613 static void HSLogCompileError(hs_compile_error_t *compile_err)
614 {
615  SCLogError("failed to compile hyperscan database");
616  if (compile_err) {
617  SCLogError("compile error: %s", compile_err->message);
618  hs_free_compile_error(compile_err);
619  }
620 }
621 
622 static int HSScratchAlloc(const hs_database_t *db)
623 {
624  SCMutexLock(&g_scratch_proto_mutex);
625  hs_error_t err = hs_alloc_scratch(db, &g_scratch_proto);
626  SCMutexUnlock(&g_scratch_proto_mutex);
627  if (err != HS_SUCCESS) {
628  SCLogError("failed to allocate scratch");
629  return -1;
630  }
631  return 0;
632 }
633 
634 static int PatternDatabaseGetSize(PatternDatabase *pd, size_t *db_size)
635 {
636  hs_error_t err = hs_database_size(pd->hs_db, db_size);
637  if (err != HS_SUCCESS) {
638  SCLogError("failed to query database size: %s", HSErrorToStr(err));
639  return -1;
640  }
641  return 0;
642 }
643 
644 static void SCHSCleanupOnError(PatternDatabase *pd, SCHSCompileData *cd)
645 {
646  if (pd) {
647  PatternDatabaseFree(pd);
648  }
649  if (cd) {
650  CompileDataFree(cd);
651  }
652 }
653 
654 static int CompileDataExtensionsInit(hs_expr_ext_t **ext, const SCHSPattern *p)
655 {
656  if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) {
657  *ext = SCCalloc(1, sizeof(hs_expr_ext_t));
658  if ((*ext) == NULL) {
659  return -1;
660  }
661  if (p->flags & MPM_PATTERN_FLAG_OFFSET) {
662  (*ext)->flags |= HS_EXT_FLAG_MIN_OFFSET;
663  (*ext)->min_offset = p->offset + p->len;
664  }
665  if (p->flags & MPM_PATTERN_FLAG_DEPTH) {
666  (*ext)->flags |= HS_EXT_FLAG_MAX_OFFSET;
667  (*ext)->max_offset = p->offset + p->depth;
668  }
669  }
670 
671  return 0;
672 }
673 
674 /**
675  * \brief Initialize the pattern database - try to get existing pd
676  * from the global hash table, or load it from disk if caching is enabled.
677  *
678  * \param PatternDatabase* [in/out] Pointer to the pattern database to use.
679  * \param SCHSCompileData* [in] Pointer to the compile data.
680  * \retval 0 On success, negative value on failure.
681  */
682 static int PatternDatabaseGetCached(
683  PatternDatabase **pd, SCHSCompileData *cd, const char *cache_dir_path)
684 {
685  /* Check global hash table to see if we've seen this pattern database
686  * before, and reuse the Hyperscan database if so. */
687  PatternDatabase *pd_cached = HashTableLookup(g_db_table, *pd, 1);
688  if (pd_cached != NULL) {
689  SCLogDebug("Reusing cached database %p with %" PRIu32
690  " patterns (ref_cnt=%" PRIu32 ")",
691  pd_cached->hs_db, pd_cached->pattern_cnt,
692  pd_cached->ref_cnt);
693  pd_cached->ref_cnt++;
694  PatternDatabaseFree(*pd);
695  CompileDataFree(cd);
696  *pd = pd_cached;
697  return 0;
698  } else if (cache_dir_path) {
699  pd_cached = *pd;
700  uint64_t db_lookup_hash = HSHashDb(pd_cached);
701  if (HSLoadCache(&pd_cached->hs_db, db_lookup_hash, cache_dir_path) == 0) {
702  pd_cached->ref_cnt = 1;
703  pd_cached->cached = true;
704  if (HSScratchAlloc(pd_cached->hs_db) != 0) {
705  goto recover;
706  }
707  if (HashTableAdd(g_db_table, pd_cached, 1) < 0) {
708  goto recover;
709  }
710  CompileDataFree(cd);
711  return 0;
712 
713  recover:
714  pd_cached->ref_cnt = 0;
715  pd_cached->cached = false;
716  return -1;
717  }
718  }
719 
720  return -1; // not cached
721 }
722 
723 static int PatternDatabaseCompile(PatternDatabase *pd, SCHSCompileData *cd)
724 {
725  for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
726  const SCHSPattern *p = pd->parray[i];
727  cd->ids[i] = i;
728  cd->flags[i] = HS_FLAG_SINGLEMATCH;
729  if (p->flags & MPM_PATTERN_FLAG_NOCASE) {
730  cd->flags[i] |= HS_FLAG_CASELESS;
731  }
732  cd->expressions[i] = HSRenderPattern(p->original_pat, p->len);
733  if (CompileDataExtensionsInit(&cd->ext[i], p) != 0) {
734  return -1;
735  }
736  }
737 
738  hs_compile_error_t *compile_err = NULL;
739  hs_error_t err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags, cd->ids,
740  (const hs_expr_ext_t *const *)cd->ext, cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db,
741  &compile_err);
742  if (err != HS_SUCCESS) {
743  HSLogCompileError(compile_err);
744  return -1;
745  }
746 
747  if (HSScratchAlloc(pd->hs_db) != 0) {
748  return -1;
749  }
750 
751  if (HashTableAdd(g_db_table, pd, 1) < 0) {
752  return -1;
753  }
754  pd->ref_cnt = 1;
755  return 0;
756 }
757 
758 /**
759  * \brief Process the patterns added to the mpm, and create the internal tables.
760  *
761  * \param mpm_conf Pointer to the generic MPM matcher configuration
762  * \param mpm_ctx Pointer to the mpm context.
763  */
764 int SCHSPreparePatterns(MpmConfig *mpm_conf, MpmCtx *mpm_ctx)
765 {
766  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
767 
768  if (HSCheckPatterns(mpm_ctx, ctx) == 0) {
769  return 0;
770  }
771 
772  SCHSCompileData *cd = CompileDataAlloc(mpm_ctx->pattern_cnt);
773  PatternDatabase *pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt);
774  if (cd == NULL || pd == NULL) {
775  goto error;
776  }
777 
778  HSPatternArrayInit(ctx, pd);
779  pd->no_cache = !(mpm_ctx->flags & MPMCTX_FLAGS_CACHE_TO_DISK);
780  /* Serialise whole database compilation as a relatively easy way to ensure
781  * dedupe is safe. */
782  SCMutexLock(&g_db_table_mutex);
783  if (HSGlobalPatternDatabaseInit() == -1) {
784  SCMutexUnlock(&g_db_table_mutex);
785  goto error;
786  }
787 
788  const char *cache_path = pd->no_cache || !mpm_conf ? NULL : mpm_conf->cache_dir_path;
789  if (PatternDatabaseGetCached(&pd, cd, cache_path) == 0 && pd != NULL) {
790  ctx->pattern_db = pd;
791  if (PatternDatabaseGetSize(pd, &ctx->hs_db_size) != 0) {
792  SCMutexUnlock(&g_db_table_mutex);
793  goto error;
794  }
795 
796  if (pd->ref_cnt == 1) {
797  // freshly allocated
798  mpm_ctx->memory_cnt++;
799  mpm_ctx->memory_size += ctx->hs_db_size;
800  }
801  SCMutexUnlock(&g_db_table_mutex);
802  return 0;
803  }
804 
805  BUG_ON(ctx->pattern_db != NULL); /* already built? */
806  BUG_ON(mpm_ctx->pattern_cnt == 0);
807 
808  if (PatternDatabaseCompile(pd, cd) != 0) {
809  SCMutexUnlock(&g_db_table_mutex);
810  goto error;
811  }
812 
813  ctx->pattern_db = pd;
814  if (PatternDatabaseGetSize(pd, &ctx->hs_db_size) != 0) {
815  SCMutexUnlock(&g_db_table_mutex);
816  goto error;
817  }
818 
819  mpm_ctx->memory_cnt++;
820  mpm_ctx->memory_size += ctx->hs_db_size;
821 
822  SCMutexUnlock(&g_db_table_mutex);
823  CompileDataFree(cd);
824  return 0;
825 
826 error:
827  SCHSCleanupOnError(pd, cd);
828  return -1;
829 }
830 
831 /**
832  * \brief Cache the initialized and compiled ruleset
833  */
834 static int SCHSCacheRuleset(MpmConfig *mpm_conf)
835 {
836  if (!mpm_conf || !mpm_conf->cache_dir_path) {
837  return -1;
838  }
839 
840  SCLogDebug("Caching the loaded ruleset to %s", mpm_conf->cache_dir_path);
841  if (SCCreateDirectoryTree(mpm_conf->cache_dir_path, true) != 0) {
842  SCLogWarning("Failed to create Hyperscan cache folder, make sure "
843  "the parent folder is writeable "
844  "or adjust sgh-mpm-caching-path setting (%s)",
845  mpm_conf->cache_dir_path);
846  return -1;
847  }
848  PatternDatabaseCache pd_stats = { 0 };
849  struct HsIteratorData iter_data = { .pd_stats = &pd_stats,
850  .cache_path = mpm_conf->cache_dir_path };
851  SCMutexLock(&g_db_table_mutex);
852  HashTableIterate(g_db_table, HSSaveCacheIterator, &iter_data);
853  SCMutexUnlock(&g_db_table_mutex);
854  SCLogNotice("Rule group caching - loaded: %u newly cached: %u total cacheable: %u",
855  pd_stats.hs_dbs_cache_loaded_cnt, pd_stats.hs_dbs_cache_saved_cnt,
856  pd_stats.hs_cacheable_dbs_cnt);
857  return 0;
858 }
859 
860 /**
861  * \brief Init the mpm thread context.
862  *
863  * \param mpm_ctx Pointer to the mpm context.
864  * \param mpm_thread_ctx Pointer to the mpm thread context.
865  */
866 void SCHSInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
867 {
868  memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
869 
870  SCHSThreadCtx *ctx = SCCalloc(1, sizeof(SCHSThreadCtx));
871  if (ctx == NULL) {
872  exit(EXIT_FAILURE);
873  }
874  mpm_thread_ctx->ctx = ctx;
875 
876  mpm_thread_ctx->memory_cnt++;
877  mpm_thread_ctx->memory_size += sizeof(SCHSThreadCtx);
878 
879  ctx->scratch = NULL;
880  ctx->scratch_size = 0;
881 
882  SCMutexLock(&g_scratch_proto_mutex);
883 
884  if (g_scratch_proto == NULL) {
885  /* There is no scratch prototype: this means that we have not compiled
886  * any Hyperscan databases. */
887  SCMutexUnlock(&g_scratch_proto_mutex);
888  SCLogDebug("No scratch space prototype");
889  return;
890  }
891 
892  hs_error_t err = hs_clone_scratch(g_scratch_proto,
893  (hs_scratch_t **)&ctx->scratch);
894 
895  SCMutexUnlock(&g_scratch_proto_mutex);
896 
897  if (err != HS_SUCCESS) {
898  FatalError("Unable to clone scratch prototype");
899  }
900 
901  err = hs_scratch_size(ctx->scratch, &ctx->scratch_size);
902  if (err != HS_SUCCESS) {
903  FatalError("Unable to query scratch size");
904  }
905 
906  mpm_thread_ctx->memory_cnt++;
907  mpm_thread_ctx->memory_size += ctx->scratch_size;
908 }
909 
910 /**
911  * \brief Initialize the HS context.
912  *
913  * \param mpm_ctx Mpm context.
914  */
915 void SCHSInitCtx(MpmCtx *mpm_ctx)
916 {
917  if (mpm_ctx->ctx != NULL)
918  return;
919 
920  mpm_ctx->ctx = SCCalloc(1, sizeof(SCHSCtx));
921  if (mpm_ctx->ctx == NULL) {
922  exit(EXIT_FAILURE);
923  }
924 
925  mpm_ctx->memory_cnt++;
926  mpm_ctx->memory_size += sizeof(SCHSCtx);
927 
928  /* initialize the hash we use to speed up pattern insertions */
929  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
930  ctx->init_hash = SCCalloc(INIT_HASH_SIZE, sizeof(SCHSPattern *));
931  if (ctx->init_hash == NULL) {
932  exit(EXIT_FAILURE);
933  }
934 }
935 
936 /**
937  * \brief Destroy the mpm thread context.
938  *
939  * \param mpm_ctx Pointer to the mpm context.
940  * \param mpm_thread_ctx Pointer to the mpm thread context.
941  */
942 void SCHSDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
943 {
944  SCHSPrintSearchStats(mpm_thread_ctx);
945 
946  if (mpm_thread_ctx->ctx != NULL) {
947  SCHSThreadCtx *thr_ctx = (SCHSThreadCtx *)mpm_thread_ctx->ctx;
948 
949  if (thr_ctx->scratch != NULL) {
950  hs_free_scratch(thr_ctx->scratch);
951  mpm_thread_ctx->memory_cnt--;
952  mpm_thread_ctx->memory_size -= thr_ctx->scratch_size;
953  }
954 
955  SCFree(mpm_thread_ctx->ctx);
956  mpm_thread_ctx->ctx = NULL;
957  mpm_thread_ctx->memory_cnt--;
958  mpm_thread_ctx->memory_size -= sizeof(SCHSThreadCtx);
959  }
960 }
961 
962 /**
963  * \brief Destroy the mpm context.
964  *
965  * \param mpm_ctx Pointer to the mpm context.
966  */
967 void SCHSDestroyCtx(MpmCtx *mpm_ctx)
968 {
969  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
970  if (ctx == NULL)
971  return;
972 
973  if (ctx->init_hash != NULL) {
974  SCFree(ctx->init_hash);
975  ctx->init_hash = NULL;
976  mpm_ctx->memory_cnt--;
977  mpm_ctx->memory_size -= (INIT_HASH_SIZE * sizeof(SCHSPattern *));
978  }
979 
980  /* Decrement pattern database ref count, and delete it entirely if the
981  * count has dropped to zero. */
982  SCMutexLock(&g_db_table_mutex);
983  PatternDatabase *pd = ctx->pattern_db;
984  if (pd) {
985  BUG_ON(pd->ref_cnt == 0);
986  pd->ref_cnt--;
987  if (pd->ref_cnt == 0) {
988  HashTableRemove(g_db_table, pd, 1);
989  PatternDatabaseFree(pd);
990  }
991  }
992  SCMutexUnlock(&g_db_table_mutex);
993 
994  SCFree(mpm_ctx->ctx);
995  mpm_ctx->ctx = NULL;
996  mpm_ctx->memory_cnt--;
997  mpm_ctx->memory_size -= sizeof(SCHSCtx);
998 }
999 
1000 typedef struct SCHSCallbackCtx_ {
1001  SCHSCtx *ctx;
1002  void *pmq;
1003  uint32_t match_count;
1004 } SCHSCallbackCtx;
1005 
1006 /* Hyperscan MPM match event handler */
1007 static int SCHSMatchEvent(unsigned int id, unsigned long long from,
1008  unsigned long long to, unsigned int flags,
1009  void *ctx)
1010 {
1011  SCHSCallbackCtx *cctx = ctx;
1012  PrefilterRuleStore *pmq = cctx->pmq;
1013  const PatternDatabase *pd = cctx->ctx->pattern_db;
1014  const SCHSPattern *pat = pd->parray[id];
1015 
1016  SCLogDebug("Hyperscan Match %" PRIu32 ": id=%" PRIu32 " @ %" PRIuMAX
1017  " (pat id=%" PRIu32 ")",
1018  cctx->match_count, (uint32_t)id, (uintmax_t)to, pat->id);
1019 
1020  PrefilterAddSids(pmq, pat->sids, pat->sids_size);
1021 
1022  cctx->match_count++;
1023  return 0;
1024 }
1025 
1026 /**
1027  * \brief The Hyperscan search function.
1028  *
1029  * \param mpm_ctx Pointer to the mpm context.
1030  * \param mpm_thread_ctx Pointer to the mpm thread context.
1031  * \param pmq Pointer to the Pattern Matcher Queue to hold
1032  * search matches.
1033  * \param buf Buffer to be searched.
1034  * \param buflen Buffer length.
1035  *
1036  * \retval matches Match count.
1037  */
1038 uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
1039  PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen)
1040 {
1041  uint32_t ret = 0;
1042  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
1043  SCHSThreadCtx *hs_thread_ctx = (SCHSThreadCtx *)(mpm_thread_ctx->ctx);
1044  const PatternDatabase *pd = ctx->pattern_db;
1045 
1046  if (unlikely(buflen == 0)) {
1047  return 0;
1048  }
1049 
1050  SCHSCallbackCtx cctx = {.ctx = ctx, .pmq = pmq, .match_count = 0};
1051 
1052  /* scratch should have been cloned from g_scratch_proto at thread init. */
1053  hs_scratch_t *scratch = hs_thread_ctx->scratch;
1054  BUG_ON(pd->hs_db == NULL);
1055  BUG_ON(scratch == NULL);
1056 
1057  hs_error_t err = hs_scan(pd->hs_db, (const char *)buf, buflen, 0, scratch,
1058  SCHSMatchEvent, &cctx);
1059  if (err != HS_SUCCESS) {
1060  /* An error value (other than HS_SCAN_TERMINATED) from hs_scan()
1061  * indicates that it was passed an invalid database or scratch region,
1062  * which is not something we can recover from at scan time. */
1063  SCLogError("Hyperscan returned error %d", err);
1064  exit(EXIT_FAILURE);
1065  } else {
1066  ret = cctx.match_count;
1067  }
1068 
1069  return ret;
1070 }
1071 
1072 /**
1073  * \brief Add a case insensitive pattern. Although we have different calls for
1074  * adding case sensitive and insensitive patterns, we make a single call
1075  * for either case. No special treatment for either case.
1076  *
1077  * \param mpm_ctx Pointer to the mpm context.
1078  * \param pat The pattern to add.
1079  * \param patlen The pattern length.
1080  * \param offset The pattern offset.
1081  * \param depth The pattern depth.
1082  * \param pid The pattern id.
1083  * \param sid The pattern signature id.
1084  * \param flags Flags associated with this pattern.
1085  *
1086  * \retval 0 On success.
1087  * \retval -1 On failure.
1088  */
1089 int SCHSAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
1090  uint16_t offset, uint16_t depth, uint32_t pid,
1091  SigIntId sid, uint8_t flags)
1092 {
1094  return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
1095 }
1096 
1097 /**
1098  * \brief Add a case sensitive pattern. Although we have different calls for
1099  * adding case sensitive and insensitive patterns, we make a single call
1100  * for either case. No special treatment for either case.
1101  *
1102  * \param mpm_ctx Pointer to the mpm context.
1103  * \param pat The pattern to add.
1104  * \param patlen The pattern length.
1105  * \param offset The pattern offset.
1106  * \param depth The pattern depth.
1107  * \param pid The pattern id.
1108  * \param sid The pattern signature id.
1109  * \param flags Flags associated with this pattern.
1110  *
1111  * \retval 0 On success.
1112  * \retval -1 On failure.
1113  */
1114 int SCHSAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
1115  uint16_t offset, uint16_t depth, uint32_t pid,
1116  SigIntId sid, uint8_t flags)
1117 {
1118  return SCHSAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
1119 }
1120 
1121 void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx)
1122 {
1123 }
1124 
1125 void SCHSPrintInfo(MpmCtx *mpm_ctx)
1126 {
1127  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
1128 
1129  printf("MPM HS Information:\n");
1130  printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt);
1131  printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size);
1132  printf(" Sizeof:\n");
1133  printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx));
1134  printf(" SCHSCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSCtx));
1135  printf(" SCHSPattern %" PRIuMAX "\n", (uintmax_t)sizeof(SCHSPattern));
1136  printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt);
1137  printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen);
1138  printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen);
1139  printf("\n");
1140 
1141  if (ctx) {
1142  PatternDatabase *pd = ctx->pattern_db;
1143  char *db_info = NULL;
1144  if (hs_database_info(pd->hs_db, &db_info) == HS_SUCCESS) {
1145  printf("HS Database Info: %s\n", db_info);
1146  SCFree(db_info);
1147  }
1148  printf("HS Database Size: %" PRIuMAX " bytes\n",
1149  (uintmax_t)ctx->hs_db_size);
1150  }
1151 
1152  printf("\n");
1153 }
1154 
1155 static MpmConfig *SCHSConfigInit(void)
1156 {
1157  MpmConfig *c = SCCalloc(1, sizeof(MpmConfig));
1158  return c;
1159 }
1160 
1161 static void SCHSConfigDeinit(MpmConfig **c)
1162 {
1163  if (c != NULL) {
1164  SCFree(*c);
1165  (*c) = NULL;
1166  }
1167 }
1168 
1169 static void SCHSConfigCacheDirSet(MpmConfig *c, const char *dir_path)
1170 {
1171  c->cache_dir_path = dir_path;
1172 }
1173 
1174 /************************** Mpm Registration ***************************/
1175 
1176 /**
1177  * \brief Register the Hyperscan MPM.
1178  */
1179 void MpmHSRegister(void)
1180 {
1181  mpm_table[MPM_HS].name = "hs";
1182  mpm_table[MPM_HS].InitCtx = SCHSInitCtx;
1183  mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx;
1184  mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx;
1185  mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx;
1186  mpm_table[MPM_HS].ConfigInit = SCHSConfigInit;
1187  mpm_table[MPM_HS].ConfigDeinit = SCHSConfigDeinit;
1188  mpm_table[MPM_HS].ConfigCacheDirSet = SCHSConfigCacheDirSet;
1189  mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS;
1190  mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI;
1191  mpm_table[MPM_HS].Prepare = SCHSPreparePatterns;
1192  mpm_table[MPM_HS].CacheRuleset = SCHSCacheRuleset;
1193  mpm_table[MPM_HS].Search = SCHSSearch;
1194  mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo;
1195  mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats;
1196 #ifdef UNITTESTS
1197  mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests;
1198 #endif
1200  /* Set Hyperscan memory allocators */
1201  SCHSSetAllocators();
1202 }
1203 
1204 /**
1205  * \brief Clean up global memory used by all Hyperscan MPM instances.
1206  *
1207  * Currently, this is just the global scratch prototype.
1208  */
1209 void MpmHSGlobalCleanup(void)
1210 {
1211  SCMutexLock(&g_scratch_proto_mutex);
1212  if (g_scratch_proto) {
1213  SCLogDebug("Cleaning up Hyperscan global scratch");
1214  hs_free_scratch(g_scratch_proto);
1215  g_scratch_proto = NULL;
1216  }
1217  SCMutexUnlock(&g_scratch_proto_mutex);
1218 
1219  SCMutexLock(&g_db_table_mutex);
1220  if (g_db_table != NULL) {
1221  SCLogDebug("Clearing Hyperscan database cache");
1222  HashTableFree(g_db_table);
1223  g_db_table = NULL;
1224  }
1225  SCMutexUnlock(&g_db_table_mutex);
1226 }
1227 
1228 /*************************************Unittests********************************/
1229 
1230 #ifdef UNITTESTS
1231 #include "detect-engine-alert.h"
1232 
1233 static int SCHSTest01(void)
1234 {
1235  int result = 0;
1236  MpmCtx mpm_ctx;
1237  MpmThreadCtx mpm_thread_ctx;
1238  PrefilterRuleStore pmq;
1239 
1240  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1241  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1242  MpmInitCtx(&mpm_ctx, MPM_HS);
1243 
1244  /* 1 match */
1245  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1246  PmqSetup(&pmq);
1247 
1248  SCHSPreparePatterns(NULL, &mpm_ctx);
1249  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1250 
1251  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1252 
1253  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1254  strlen(buf));
1255 
1256  if (cnt == 1)
1257  result = 1;
1258  else
1259  printf("1 != %" PRIu32 " ", cnt);
1260 
1261  SCHSDestroyCtx(&mpm_ctx);
1262  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1263  PmqFree(&pmq);
1264  return result;
1265 }
1266 
1267 static int SCHSTest02(void)
1268 {
1269  int result = 0;
1270  MpmCtx mpm_ctx;
1271  MpmThreadCtx mpm_thread_ctx;
1272  PrefilterRuleStore pmq;
1273 
1274  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1275  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1276  MpmInitCtx(&mpm_ctx, MPM_HS);
1277 
1278  /* 1 match */
1279  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0);
1280  PmqSetup(&pmq);
1281 
1282  SCHSPreparePatterns(NULL, &mpm_ctx);
1283  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1284 
1285  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1286  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1287  strlen(buf));
1288 
1289  if (cnt == 0)
1290  result = 1;
1291  else
1292  printf("0 != %" PRIu32 " ", cnt);
1293 
1294  SCHSDestroyCtx(&mpm_ctx);
1295  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1296  PmqFree(&pmq);
1297  return result;
1298 }
1299 
1300 static int SCHSTest03(void)
1301 {
1302  int result = 0;
1303  MpmCtx mpm_ctx;
1304  MpmThreadCtx mpm_thread_ctx;
1305  PrefilterRuleStore pmq;
1306 
1307  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1308  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1309  MpmInitCtx(&mpm_ctx, MPM_HS);
1310 
1311  /* 1 match */
1312  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1313  /* 1 match */
1314  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0);
1315  /* 1 match */
1316  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0);
1317  PmqSetup(&pmq);
1318 
1319  SCHSPreparePatterns(NULL, &mpm_ctx);
1320  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1321 
1322  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1323  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1324  strlen(buf));
1325 
1326  if (cnt == 3)
1327  result = 1;
1328  else
1329  printf("3 != %" PRIu32 " ", cnt);
1330 
1331  SCHSDestroyCtx(&mpm_ctx);
1332  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1333  PmqFree(&pmq);
1334  return result;
1335 }
1336 
1337 static int SCHSTest04(void)
1338 {
1339  int result = 0;
1340  MpmCtx mpm_ctx;
1341  MpmThreadCtx mpm_thread_ctx;
1342  PrefilterRuleStore pmq;
1343 
1344  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1345  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1346  MpmInitCtx(&mpm_ctx, MPM_HS);
1347 
1348  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1349  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0);
1350  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0);
1351  PmqSetup(&pmq);
1352 
1353  SCHSPreparePatterns(NULL, &mpm_ctx);
1354  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1355 
1356  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1357  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1358  strlen(buf));
1359 
1360  if (cnt == 1)
1361  result = 1;
1362  else
1363  printf("1 != %" PRIu32 " ", cnt);
1364 
1365  SCHSDestroyCtx(&mpm_ctx);
1366  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1367  PmqFree(&pmq);
1368  return result;
1369 }
1370 
1371 static int SCHSTest05(void)
1372 {
1373  int result = 0;
1374  MpmCtx mpm_ctx;
1375  MpmThreadCtx mpm_thread_ctx;
1376  PrefilterRuleStore pmq;
1377 
1378  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1379  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1380  MpmInitCtx(&mpm_ctx, MPM_HS);
1381 
1382  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
1383  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
1384  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0);
1385  PmqSetup(&pmq);
1386 
1387  SCHSPreparePatterns(NULL, &mpm_ctx);
1388  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1389 
1390  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1391  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1392  strlen(buf));
1393 
1394  if (cnt == 3)
1395  result = 1;
1396  else
1397  printf("3 != %" PRIu32 " ", cnt);
1398 
1399  SCHSDestroyCtx(&mpm_ctx);
1400  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1401  PmqFree(&pmq);
1402  return result;
1403 }
1404 
1405 static int SCHSTest06(void)
1406 {
1407  int result = 0;
1408  MpmCtx mpm_ctx;
1409  MpmThreadCtx mpm_thread_ctx;
1410  PrefilterRuleStore pmq;
1411 
1412  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1413  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1414  MpmInitCtx(&mpm_ctx, MPM_HS);
1415 
1416  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1417  PmqSetup(&pmq);
1418 
1419  SCHSPreparePatterns(NULL, &mpm_ctx);
1420  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1421 
1422  const char *buf = "abcd";
1423  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1424  strlen(buf));
1425 
1426  if (cnt == 1)
1427  result = 1;
1428  else
1429  printf("1 != %" PRIu32 " ", cnt);
1430 
1431  SCHSDestroyCtx(&mpm_ctx);
1432  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1433  PmqFree(&pmq);
1434  return result;
1435 }
1436 
1437 static int SCHSTest07(void)
1438 {
1439  int result = 0;
1440  MpmCtx mpm_ctx;
1441  MpmThreadCtx mpm_thread_ctx;
1442  PrefilterRuleStore pmq;
1443 
1444  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1445  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1446  MpmInitCtx(&mpm_ctx, MPM_HS);
1447 
1448  /* should match 30 times */
1449  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0);
1450  /* should match 29 times */
1451  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0);
1452  /* should match 28 times */
1453  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0);
1454  /* 26 */
1455  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0);
1456  /* 21 */
1457  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0);
1458  /* 1 */
1459  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30,
1460  0, 0, 5, 0, 0);
1461  PmqSetup(&pmq);
1462 
1463  SCHSPreparePatterns(NULL, &mpm_ctx);
1464  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1465 
1466  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1467  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1468  strlen(buf));
1469 
1470  if (cnt == 6)
1471  result = 1;
1472  else
1473  printf("6 != %" PRIu32 " ", cnt);
1474 
1475  SCHSDestroyCtx(&mpm_ctx);
1476  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1477  PmqFree(&pmq);
1478  return result;
1479 }
1480 
1481 static int SCHSTest08(void)
1482 {
1483  int result = 0;
1484  MpmCtx mpm_ctx;
1485  MpmThreadCtx mpm_thread_ctx;
1486  PrefilterRuleStore pmq;
1487 
1488  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1489  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1490  MpmInitCtx(&mpm_ctx, MPM_HS);
1491 
1492  /* 1 match */
1493  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1494  PmqSetup(&pmq);
1495 
1496  SCHSPreparePatterns(NULL, &mpm_ctx);
1497  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1498 
1499  uint32_t cnt =
1500  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1);
1501 
1502  if (cnt == 0)
1503  result = 1;
1504  else
1505  printf("0 != %" PRIu32 " ", cnt);
1506 
1507  SCHSDestroyCtx(&mpm_ctx);
1508  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1509  PmqFree(&pmq);
1510  return result;
1511 }
1512 
1513 static int SCHSTest09(void)
1514 {
1515  int result = 0;
1516  MpmCtx mpm_ctx;
1517  MpmThreadCtx mpm_thread_ctx;
1518  PrefilterRuleStore pmq;
1519 
1520  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1521  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1522  MpmInitCtx(&mpm_ctx, MPM_HS);
1523 
1524  /* 1 match */
1525  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0);
1526  PmqSetup(&pmq);
1527 
1528  SCHSPreparePatterns(NULL, &mpm_ctx);
1529  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1530 
1531  uint32_t cnt =
1532  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2);
1533 
1534  if (cnt == 1)
1535  result = 1;
1536  else
1537  printf("1 != %" PRIu32 " ", cnt);
1538 
1539  SCHSDestroyCtx(&mpm_ctx);
1540  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1541  PmqFree(&pmq);
1542  return result;
1543 }
1544 
1545 static int SCHSTest10(void)
1546 {
1547  int result = 0;
1548  MpmCtx mpm_ctx;
1549  MpmThreadCtx mpm_thread_ctx;
1550  PrefilterRuleStore pmq;
1551 
1552  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1553  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1554  MpmInitCtx(&mpm_ctx, MPM_HS);
1555 
1556  /* 1 match */
1557  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0);
1558  PmqSetup(&pmq);
1559 
1560  SCHSPreparePatterns(NULL, &mpm_ctx);
1561  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1562 
1563  const char *buf = "01234567890123456789012345678901234567890123456789"
1564  "01234567890123456789012345678901234567890123456789"
1565  "abcdefgh"
1566  "01234567890123456789012345678901234567890123456789"
1567  "01234567890123456789012345678901234567890123456789";
1568  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1569  strlen(buf));
1570 
1571  if (cnt == 1)
1572  result = 1;
1573  else
1574  printf("1 != %" PRIu32 " ", cnt);
1575 
1576  SCHSDestroyCtx(&mpm_ctx);
1577  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1578  PmqFree(&pmq);
1579  return result;
1580 }
1581 
1582 static int SCHSTest11(void)
1583 {
1584  int result = 0;
1585  MpmCtx mpm_ctx;
1586  MpmThreadCtx mpm_thread_ctx;
1587  PrefilterRuleStore pmq;
1588 
1589  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1590  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1591  MpmInitCtx(&mpm_ctx, MPM_HS);
1592 
1593  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1)
1594  goto end;
1595  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1)
1596  goto end;
1597  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1)
1598  goto end;
1599  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1)
1600  goto end;
1601  PmqSetup(&pmq);
1602 
1603  if (SCHSPreparePatterns(NULL, &mpm_ctx) == -1)
1604  goto end;
1605 
1606  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1607 
1608  result = 1;
1609 
1610  const char *buf = "he";
1611  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1612  strlen(buf)) == 1);
1613  buf = "she";
1614  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1615  strlen(buf)) == 2);
1616  buf = "his";
1617  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1618  strlen(buf)) == 1);
1619  buf = "hers";
1620  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1621  strlen(buf)) == 2);
1622 
1623 end:
1624  SCHSDestroyCtx(&mpm_ctx);
1625  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1626  PmqFree(&pmq);
1627  return result;
1628 }
1629 
1630 static int SCHSTest12(void)
1631 {
1632  int result = 0;
1633  MpmCtx mpm_ctx;
1634  MpmThreadCtx mpm_thread_ctx;
1635  PrefilterRuleStore pmq;
1636 
1637  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1638  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1639  MpmInitCtx(&mpm_ctx, MPM_HS);
1640 
1641  /* 1 match */
1642  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0);
1643  /* 1 match */
1644  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0);
1645  PmqSetup(&pmq);
1646 
1647  SCHSPreparePatterns(NULL, &mpm_ctx);
1648  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1649 
1650  const char *buf = "abcdefghijklmnopqrstuvwxyz";
1651  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1652  strlen(buf));
1653 
1654  if (cnt == 2)
1655  result = 1;
1656  else
1657  printf("2 != %" PRIu32 " ", cnt);
1658 
1659  SCHSDestroyCtx(&mpm_ctx);
1660  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1661  PmqFree(&pmq);
1662  return result;
1663 }
1664 
1665 static int SCHSTest13(void)
1666 {
1667  int result = 0;
1668  MpmCtx mpm_ctx;
1669  MpmThreadCtx mpm_thread_ctx;
1670  PrefilterRuleStore pmq;
1671 
1672  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1673  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1674  MpmInitCtx(&mpm_ctx, MPM_HS);
1675 
1676  /* 1 match */
1677  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD";
1678  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1679  PmqSetup(&pmq);
1680 
1681  SCHSPreparePatterns(NULL, &mpm_ctx);
1682  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1683 
1684  const char *buf = "abcdefghijklmnopqrstuvwxyzABCD";
1685  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1686  strlen(buf));
1687 
1688  if (cnt == 1)
1689  result = 1;
1690  else
1691  printf("1 != %" PRIu32 " ", cnt);
1692 
1693  SCHSDestroyCtx(&mpm_ctx);
1694  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1695  PmqFree(&pmq);
1696  return result;
1697 }
1698 
1699 static int SCHSTest14(void)
1700 {
1701  int result = 0;
1702  MpmCtx mpm_ctx;
1703  MpmThreadCtx mpm_thread_ctx;
1704  PrefilterRuleStore pmq;
1705 
1706  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1707  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1708  MpmInitCtx(&mpm_ctx, MPM_HS);
1709 
1710  /* 1 match */
1711  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE";
1712  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1713  PmqSetup(&pmq);
1714 
1715  SCHSPreparePatterns(NULL, &mpm_ctx);
1716  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1717 
1718  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE";
1719  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1720  strlen(buf));
1721 
1722  if (cnt == 1)
1723  result = 1;
1724  else
1725  printf("1 != %" PRIu32 " ", cnt);
1726 
1727  SCHSDestroyCtx(&mpm_ctx);
1728  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1729  PmqFree(&pmq);
1730  return result;
1731 }
1732 
1733 static int SCHSTest15(void)
1734 {
1735  int result = 0;
1736  MpmCtx mpm_ctx;
1737  MpmThreadCtx mpm_thread_ctx;
1738  PrefilterRuleStore pmq;
1739 
1740  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1741  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1742  MpmInitCtx(&mpm_ctx, MPM_HS);
1743 
1744  /* 1 match */
1745  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF";
1746  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1747  PmqSetup(&pmq);
1748 
1749  SCHSPreparePatterns(NULL, &mpm_ctx);
1750  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1751 
1752  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF";
1753  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1754  strlen(buf));
1755 
1756  if (cnt == 1)
1757  result = 1;
1758  else
1759  printf("1 != %" PRIu32 " ", cnt);
1760 
1761  SCHSDestroyCtx(&mpm_ctx);
1762  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1763  PmqFree(&pmq);
1764  return result;
1765 }
1766 
1767 static int SCHSTest16(void)
1768 {
1769  int result = 0;
1770  MpmCtx mpm_ctx;
1771  MpmThreadCtx mpm_thread_ctx;
1772  PrefilterRuleStore pmq;
1773 
1774  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1775  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1776  MpmInitCtx(&mpm_ctx, MPM_HS);
1777 
1778  /* 1 match */
1779  const char pat[] = "abcdefghijklmnopqrstuvwxyzABC";
1780  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1781  PmqSetup(&pmq);
1782 
1783  SCHSPreparePatterns(NULL, &mpm_ctx);
1784  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1785 
1786  const char *buf = "abcdefghijklmnopqrstuvwxyzABC";
1787  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1788  strlen(buf));
1789 
1790  if (cnt == 1)
1791  result = 1;
1792  else
1793  printf("1 != %" PRIu32 " ", cnt);
1794 
1795  SCHSDestroyCtx(&mpm_ctx);
1796  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1797  PmqFree(&pmq);
1798  return result;
1799 }
1800 
1801 static int SCHSTest17(void)
1802 {
1803  int result = 0;
1804  MpmCtx mpm_ctx;
1805  MpmThreadCtx mpm_thread_ctx;
1806  PrefilterRuleStore pmq;
1807 
1808  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1809  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1810  MpmInitCtx(&mpm_ctx, MPM_HS);
1811 
1812  /* 1 match */
1813  const char pat[] = "abcdefghijklmnopqrstuvwxyzAB";
1814  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1815  PmqSetup(&pmq);
1816 
1817  SCHSPreparePatterns(NULL, &mpm_ctx);
1818  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1819 
1820  const char *buf = "abcdefghijklmnopqrstuvwxyzAB";
1821  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1822  strlen(buf));
1823 
1824  if (cnt == 1)
1825  result = 1;
1826  else
1827  printf("1 != %" PRIu32 " ", cnt);
1828 
1829  SCHSDestroyCtx(&mpm_ctx);
1830  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1831  PmqFree(&pmq);
1832  return result;
1833 }
1834 
1835 static int SCHSTest18(void)
1836 {
1837  int result = 0;
1838  MpmCtx mpm_ctx;
1839  MpmThreadCtx mpm_thread_ctx;
1840  PrefilterRuleStore pmq;
1841 
1842  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1843  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1844  MpmInitCtx(&mpm_ctx, MPM_HS);
1845 
1846  /* 1 match */
1847  const char pat[] = "abcde"
1848  "fghij"
1849  "klmno"
1850  "pqrst"
1851  "uvwxy"
1852  "z";
1853  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1854  PmqSetup(&pmq);
1855 
1856  SCHSPreparePatterns(NULL, &mpm_ctx);
1857  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1858 
1859  const char *buf = "abcde"
1860  "fghij"
1861  "klmno"
1862  "pqrst"
1863  "uvwxy"
1864  "z";
1865  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1866  strlen(buf));
1867 
1868  if (cnt == 1)
1869  result = 1;
1870  else
1871  printf("1 != %" PRIu32 " ", cnt);
1872 
1873  SCHSDestroyCtx(&mpm_ctx);
1874  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1875  PmqFree(&pmq);
1876  return result;
1877 }
1878 
1879 static int SCHSTest19(void)
1880 {
1881  int result = 0;
1882  MpmCtx mpm_ctx;
1883  MpmThreadCtx mpm_thread_ctx;
1884  PrefilterRuleStore pmq;
1885 
1886  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1887  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1888  MpmInitCtx(&mpm_ctx, MPM_HS);
1889 
1890  /* 1 */
1891  const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1892  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1893  PmqSetup(&pmq);
1894 
1895  SCHSPreparePatterns(NULL, &mpm_ctx);
1896  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1897 
1898  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1899  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1900  strlen(buf));
1901 
1902  if (cnt == 1)
1903  result = 1;
1904  else
1905  printf("1 != %" PRIu32 " ", cnt);
1906 
1907  SCHSDestroyCtx(&mpm_ctx);
1908  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1909  PmqFree(&pmq);
1910  return result;
1911 }
1912 
1913 static int SCHSTest20(void)
1914 {
1915  int result = 0;
1916  MpmCtx mpm_ctx;
1917  MpmThreadCtx mpm_thread_ctx;
1918  PrefilterRuleStore pmq;
1919 
1920  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1921  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1922  MpmInitCtx(&mpm_ctx, MPM_HS);
1923 
1924  /* 1 */
1925  const char pat[] = "AAAAA"
1926  "AAAAA"
1927  "AAAAA"
1928  "AAAAA"
1929  "AAAAA"
1930  "AAAAA"
1931  "AA";
1932  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1933  PmqSetup(&pmq);
1934 
1935  SCHSPreparePatterns(NULL, &mpm_ctx);
1936  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1937 
1938  const char *buf = "AAAAA"
1939  "AAAAA"
1940  "AAAAA"
1941  "AAAAA"
1942  "AAAAA"
1943  "AAAAA"
1944  "AA";
1945  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1946  strlen(buf));
1947 
1948  if (cnt == 1)
1949  result = 1;
1950  else
1951  printf("1 != %" PRIu32 " ", cnt);
1952 
1953  SCHSDestroyCtx(&mpm_ctx);
1954  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1955  PmqFree(&pmq);
1956  return result;
1957 }
1958 
1959 static int SCHSTest21(void)
1960 {
1961  int result = 0;
1962  MpmCtx mpm_ctx;
1963  MpmThreadCtx mpm_thread_ctx;
1964  PrefilterRuleStore pmq;
1965 
1966  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1967  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1968  MpmInitCtx(&mpm_ctx, MPM_HS);
1969 
1970  /* 1 */
1971  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
1972  PmqSetup(&pmq);
1973 
1974  SCHSPreparePatterns(NULL, &mpm_ctx);
1975  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1976 
1977  uint32_t cnt =
1978  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2);
1979 
1980  if (cnt == 1)
1981  result = 1;
1982  else
1983  printf("1 != %" PRIu32 " ", cnt);
1984 
1985  SCHSDestroyCtx(&mpm_ctx);
1986  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1987  PmqFree(&pmq);
1988  return result;
1989 }
1990 
1991 static int SCHSTest22(void)
1992 {
1993  int result = 0;
1994  MpmCtx mpm_ctx;
1995  MpmThreadCtx mpm_thread_ctx;
1996  PrefilterRuleStore pmq;
1997 
1998  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1999  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2000  MpmInitCtx(&mpm_ctx, MPM_HS);
2001 
2002  /* 1 match */
2003  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
2004  /* 1 match */
2005  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0);
2006  PmqSetup(&pmq);
2007 
2008  SCHSPreparePatterns(NULL, &mpm_ctx);
2009  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2010 
2011  const char *buf = "abcdefghijklmnopqrstuvwxyz";
2012  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2013  strlen(buf));
2014 
2015  if (cnt == 2)
2016  result = 1;
2017  else
2018  printf("2 != %" PRIu32 " ", cnt);
2019 
2020  SCHSDestroyCtx(&mpm_ctx);
2021  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2022  PmqFree(&pmq);
2023  return result;
2024 }
2025 
2026 static int SCHSTest23(void)
2027 {
2028  int result = 0;
2029  MpmCtx mpm_ctx;
2030  MpmThreadCtx mpm_thread_ctx;
2031  PrefilterRuleStore pmq;
2032 
2033  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2034  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2035  MpmInitCtx(&mpm_ctx, MPM_HS);
2036 
2037  /* 1 */
2038  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2039  PmqSetup(&pmq);
2040 
2041  SCHSPreparePatterns(NULL, &mpm_ctx);
2042  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2043 
2044  uint32_t cnt =
2045  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2);
2046 
2047  if (cnt == 0)
2048  result = 1;
2049  else
2050  printf("1 != %" PRIu32 " ", cnt);
2051 
2052  SCHSDestroyCtx(&mpm_ctx);
2053  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2054  PmqFree(&pmq);
2055  return result;
2056 }
2057 
2058 static int SCHSTest24(void)
2059 {
2060  int result = 0;
2061  MpmCtx mpm_ctx;
2062  MpmThreadCtx mpm_thread_ctx;
2063  PrefilterRuleStore pmq;
2064 
2065  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2066  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2067  MpmInitCtx(&mpm_ctx, MPM_HS);
2068 
2069  /* 1 */
2070  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2071  PmqSetup(&pmq);
2072 
2073  SCHSPreparePatterns(NULL, &mpm_ctx);
2074  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2075 
2076  uint32_t cnt =
2077  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2);
2078 
2079  if (cnt == 1)
2080  result = 1;
2081  else
2082  printf("1 != %" PRIu32 " ", cnt);
2083 
2084  SCHSDestroyCtx(&mpm_ctx);
2085  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2086  PmqFree(&pmq);
2087  return result;
2088 }
2089 
2090 static int SCHSTest25(void)
2091 {
2092  int result = 0;
2093  MpmCtx mpm_ctx;
2094  MpmThreadCtx mpm_thread_ctx;
2095  PrefilterRuleStore pmq;
2096 
2097  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2098  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2099  MpmInitCtx(&mpm_ctx, MPM_HS);
2100 
2101  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
2102  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
2103  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0);
2104  PmqSetup(&pmq);
2105 
2106  SCHSPreparePatterns(NULL, &mpm_ctx);
2107  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2108 
2109  const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2110  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2111  strlen(buf));
2112 
2113  if (cnt == 3)
2114  result = 1;
2115  else
2116  printf("3 != %" PRIu32 " ", cnt);
2117 
2118  SCHSDestroyCtx(&mpm_ctx);
2119  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2120  PmqFree(&pmq);
2121  return result;
2122 }
2123 
2124 static int SCHSTest26(void)
2125 {
2126  int result = 0;
2127  MpmCtx mpm_ctx;
2128  MpmThreadCtx mpm_thread_ctx;
2129  PrefilterRuleStore pmq;
2130 
2131  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2132  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2133  MpmInitCtx(&mpm_ctx, MPM_HS);
2134 
2135  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0);
2136  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0);
2137  PmqSetup(&pmq);
2138 
2139  SCHSPreparePatterns(NULL, &mpm_ctx);
2140  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2141 
2142  const char *buf = "works";
2143  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2144  strlen(buf));
2145 
2146  if (cnt == 1)
2147  result = 1;
2148  else
2149  printf("3 != %" PRIu32 " ", cnt);
2150 
2151  SCHSDestroyCtx(&mpm_ctx);
2152  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2153  PmqFree(&pmq);
2154  return result;
2155 }
2156 
2157 static int SCHSTest27(void)
2158 {
2159  int result = 0;
2160  MpmCtx mpm_ctx;
2161  MpmThreadCtx mpm_thread_ctx;
2162  PrefilterRuleStore pmq;
2163 
2164  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2165  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2166  MpmInitCtx(&mpm_ctx, MPM_HS);
2167 
2168  /* 0 match */
2169  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0);
2170  PmqSetup(&pmq);
2171 
2172  SCHSPreparePatterns(NULL, &mpm_ctx);
2173  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2174 
2175  const char *buf = "tone";
2176  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2177  strlen(buf));
2178 
2179  if (cnt == 0)
2180  result = 1;
2181  else
2182  printf("0 != %" PRIu32 " ", cnt);
2183 
2184  SCHSDestroyCtx(&mpm_ctx);
2185  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2186  PmqFree(&pmq);
2187  return result;
2188 }
2189 
2190 static int SCHSTest28(void)
2191 {
2192  int result = 0;
2193  MpmCtx mpm_ctx;
2194  MpmThreadCtx mpm_thread_ctx;
2195  PrefilterRuleStore pmq;
2196 
2197  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2198  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2199  MpmInitCtx(&mpm_ctx, MPM_HS);
2200 
2201  /* 0 match */
2202  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0);
2203  PmqSetup(&pmq);
2204 
2205  SCHSPreparePatterns(NULL, &mpm_ctx);
2206  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2207 
2208  const char *buf = "tONE";
2209  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2210  strlen(buf));
2211 
2212  if (cnt == 0)
2213  result = 1;
2214  else
2215  printf("0 != %" PRIu32 " ", cnt);
2216 
2217  SCHSDestroyCtx(&mpm_ctx);
2218  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2219  PmqFree(&pmq);
2220  return result;
2221 }
2222 
2223 static int SCHSTest29(void)
2224 {
2225  uint8_t buf[] = "onetwothreefourfivesixseveneightnine";
2226  uint16_t buflen = sizeof(buf) - 1;
2227  Packet *p = NULL;
2228  ThreadVars th_v;
2229  DetectEngineThreadCtx *det_ctx = NULL;
2230  int result = 0;
2231 
2232  memset(&th_v, 0, sizeof(th_v));
2233  p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2234 
2236  if (de_ctx == NULL)
2237  goto end;
2239 
2240  de_ctx->flags |= DE_QUIET;
2241 
2242  de_ctx->sig_list = SigInit(
2243  de_ctx, "alert tcp any any -> any any "
2244  "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)");
2245  if (de_ctx->sig_list == NULL)
2246  goto end;
2247  de_ctx->sig_list->next =
2248  SigInit(de_ctx, "alert tcp any any -> any any "
2249  "(content:\"onetwothreefourfivesixseveneightnine\"; "
2250  "fast_pattern:3,3; sid:2;)");
2251  if (de_ctx->sig_list->next == NULL)
2252  goto end;
2253 
2255  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2256 
2257  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2258  if (PacketAlertCheck(p, 1) != 1) {
2259  printf("if (PacketAlertCheck(p, 1) != 1) failure\n");
2260  goto end;
2261  }
2262  if (PacketAlertCheck(p, 2) != 1) {
2263  printf("if (PacketAlertCheck(p, 1) != 2) failure\n");
2264  goto end;
2265  }
2266 
2267  result = 1;
2268 end:
2269  if (de_ctx != NULL) {
2272 
2273  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2275  }
2276 
2277  UTHFreePackets(&p, 1);
2278  return result;
2279 }
2280 
2281 static void SCHSRegisterTests(void)
2282 {
2283  UtRegisterTest("SCHSTest01", SCHSTest01);
2284  UtRegisterTest("SCHSTest02", SCHSTest02);
2285  UtRegisterTest("SCHSTest03", SCHSTest03);
2286  UtRegisterTest("SCHSTest04", SCHSTest04);
2287  UtRegisterTest("SCHSTest05", SCHSTest05);
2288  UtRegisterTest("SCHSTest06", SCHSTest06);
2289  UtRegisterTest("SCHSTest07", SCHSTest07);
2290  UtRegisterTest("SCHSTest08", SCHSTest08);
2291  UtRegisterTest("SCHSTest09", SCHSTest09);
2292  UtRegisterTest("SCHSTest10", SCHSTest10);
2293  UtRegisterTest("SCHSTest11", SCHSTest11);
2294  UtRegisterTest("SCHSTest12", SCHSTest12);
2295  UtRegisterTest("SCHSTest13", SCHSTest13);
2296  UtRegisterTest("SCHSTest14", SCHSTest14);
2297  UtRegisterTest("SCHSTest15", SCHSTest15);
2298  UtRegisterTest("SCHSTest16", SCHSTest16);
2299  UtRegisterTest("SCHSTest17", SCHSTest17);
2300  UtRegisterTest("SCHSTest18", SCHSTest18);
2301  UtRegisterTest("SCHSTest19", SCHSTest19);
2302  UtRegisterTest("SCHSTest20", SCHSTest20);
2303  UtRegisterTest("SCHSTest21", SCHSTest21);
2304  UtRegisterTest("SCHSTest22", SCHSTest22);
2305  UtRegisterTest("SCHSTest23", SCHSTest23);
2306  UtRegisterTest("SCHSTest24", SCHSTest24);
2307  UtRegisterTest("SCHSTest25", SCHSTest25);
2308  UtRegisterTest("SCHSTest26", SCHSTest26);
2309  UtRegisterTest("SCHSTest27", SCHSTest27);
2310  UtRegisterTest("SCHSTest28", SCHSTest28);
2311  UtRegisterTest("SCHSTest29", SCHSTest29);
2312 }
2313 #endif /* UNITTESTS */
2314 #endif /* BUILD_HYPERSCAN */
MpmTableElmt_::PrintThreadCtx
void(* PrintThreadCtx)(struct MpmThreadCtx_ *)
Definition: util-mpm.h:179
len
uint8_t len
Definition: app-layer-dnp3.h:2
detect-engine.h
hashword
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:172
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
MpmTableElmt_::InitThreadCtx
void(* InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:153
MpmThreadCtx_
Definition: util-mpm.h:46
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
MpmTableElmt_::name
const char * name
Definition: util-mpm.h:151
PrefilterRuleStore_
structure for storing potential rule matches
Definition: util-prefilter.h:34
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
HashTableIterate
void HashTableIterate(HashTable *ht, void(*CallbackFn)(void *, void *), void *aux)
Definition: util-hash.c:212
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:141
MpmThreadCtx_::memory_cnt
uint32_t memory_cnt
Definition: util-mpm.h:49
util-hash.h
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:860
MPM_FEATURE_FLAG_OFFSET
#define MPM_FEATURE_FLAG_OFFSET
Definition: util-mpm.h:147
util-memcpy.h
MpmCtx_::memory_size
uint32_t memory_size
Definition: util-mpm.h:108
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2742
MpmTableElmt_::AddPatternNocase
int(* AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:173
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
HashTable_
Definition: util-hash.h:35
DE_QUIET
#define DE_QUIET
Definition: detect.h:324
MpmCtx_::maxlen
uint16_t maxlen
Definition: util-mpm.h:105
MpmTableElmt_::AddPattern
int(* AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:172
UTHBuildPacket
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.
Definition: util-unittest-helper.c:359
MpmTableElmt_::feature_flags
uint8_t feature_flags
Definition: util-mpm.h:183
util-hyperscan.h
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1963
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:55
MpmCtx_::maxdepth
uint16_t maxdepth
Definition: util-mpm.h:99
MAX
#define MAX(x, y)
Definition: suricata-common.h:404
MpmTableElmt_::InitCtx
void(* InitCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:152
util-unittest.h
util-unittest-helper.h
HashTableFree
void HashTableFree(HashTable *ht)
Definition: util-hash.c:78
MpmConfig_::cache_dir_path
const char * cache_dir_path
Definition: util-mpm.h:90
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
util-memcmp.h
MpmInitCtx
void MpmInitCtx(MpmCtx *mpm_ctx, uint8_t matcher)
Definition: util-mpm.c:209
Signature_::next
struct Signature_ * next
Definition: detect.h:691
MpmTableElmt_::PrintCtx
void(* PrintCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:178
MPM_HS
@ MPM_HS
Definition: util-mpm.h:38
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1116
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
MpmThreadCtx_::memory_size
uint32_t memory_size
Definition: util-mpm.h:50
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:183
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3475
HashTableRemove
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:142
DetectEngineCtx_::mpm_matcher
uint8_t mpm_matcher
Definition: detect.h:863
MPM_PATTERN_FLAG_OFFSET
#define MPM_PATTERN_FLAG_OFFSET
Definition: util-mpm.h:140
MPM_FEATURE_FLAG_DEPTH
#define MPM_FEATURE_FLAG_DEPTH
Definition: util-mpm.h:146
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:104
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2520
MpmCtx_::minlen
uint16_t minlen
Definition: util-mpm.h:104
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:309
hashlittle_safe
uint32_t hashlittle_safe(const void *key, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:482
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2180
Packet_
Definition: decode.h:476
detect-engine-build.h
detect-engine-alert.h
conf.h
MpmTableElmt_::CacheRuleset
int(* CacheRuleset)(MpmConfig *)
Definition: util-mpm.h:175
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:177
MpmAddPatternCS
int MpmAddPatternCS(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:249
MPMCTX_FLAGS_NODEPTH
#define MPMCTX_FLAGS_NODEPTH
Definition: util-mpm.h:86
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2113
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
MPM_PATTERN_FLAG_NOCASE
#define MPM_PATTERN_FLAG_NOCASE
Definition: util-mpm.h:136
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
util-conf.h
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
MpmCtx_::pattern_cnt
uint32_t pattern_cnt
Definition: util-mpm.h:102
util-path.h
util-mpm-hs-core.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3702
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:869
util-hash-lookup3.h
HSRenderPattern
char * HSRenderPattern(const uint8_t *pat, uint16_t pat_len)
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
MpmTableElmt_::Prepare
int(* Prepare)(MpmConfig *, struct MpmCtx_ *)
Definition: util-mpm.h:174
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:154
SCFree
#define SCFree(p)
Definition: util-mem.h:61
MpmConfig_
Definition: util-mpm.h:89
detect-parse.h
MpmCtx_::memory_cnt
uint32_t memory_cnt
Definition: util-mpm.h:107
HashTableInit
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hash.c:35
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2703
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:47
MpmTableElmt_::ConfigDeinit
void(* ConfigDeinit)(MpmConfig **)
Definition: util-mpm.h:158
suricata.h
MpmTableElmt_::ConfigCacheDirSet
void(* ConfigCacheDirSet)(MpmConfig *, const char *dir_path)
Definition: util-mpm.h:159
util-mpm-hs.h
PmqFree
void PmqFree(PrefilterRuleStore *pmq)
Cleanup and free a Pmq.
Definition: util-prefilter.c:126
MpmTableElmt_::ConfigInit
MpmConfig *(* ConfigInit)(void)
Definition: util-mpm.h:157
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:862
MpmTableElmt_::DestroyThreadCtx
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:155
MpmCtx_
Definition: util-mpm.h:93
util-mpm-hs-cache.h
MPM_PATTERN_FLAG_DEPTH
#define MPM_PATTERN_FLAG_DEPTH
Definition: util-mpm.h:138
SigIntId
#define SigIntId
Definition: suricata-common.h:324
MpmCtx_::flags
uint8_t flags
Definition: util-mpm.h:97
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
MPMCTX_FLAGS_CACHE_TO_DISK
#define MPMCTX_FLAGS_CACHE_TO_DISK
Definition: util-mpm.h:87
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
MpmHSRegister
void MpmHSRegister(void)
MpmCtx_::ctx
void * ctx
Definition: util-mpm.h:94
MpmAddPatternCI
int MpmAddPatternCI(struct MpmCtx_ *mpm_ctx, uint8_t *pat, uint16_t patlen, uint16_t offset, uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
Definition: util-mpm.c:258
SCMemcmp
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:290
SCMutex
#define SCMutex
Definition: threads-debug.h:114
MpmThreadCtx_::ctx
void * ctx
Definition: util-mpm.h:47
MpmTableElmt_::RegisterUnittests
void(* RegisterUnittests)(void)
Definition: util-mpm.h:181
PmqSetup
int PmqSetup(PrefilterRuleStore *pmq)
Setup a pmq.
Definition: util-prefilter.c:37
MpmHSGlobalCleanup
void MpmHSGlobalCleanup(void)
SCCreateDirectoryTree
int SCCreateDirectoryTree(const char *path, const bool final)
Recursively create a directory.
Definition: util-path.c:137
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:450