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