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