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 void SCHSInitCtx(MpmCtx *);
53 void SCHSInitThreadCtx(MpmCtx *, MpmThreadCtx *);
54 void SCHSDestroyCtx(MpmCtx *);
55 void SCHSDestroyThreadCtx(MpmCtx *, MpmThreadCtx *);
56 int SCHSAddPatternCI(
57  MpmCtx *, const uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t);
58 int SCHSAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
59  uint32_t, SigIntId, uint8_t);
60 int SCHSPreparePatterns(MpmConfig *mpm_conf, MpmCtx *mpm_ctx);
61 uint32_t SCHSSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
62  PrefilterRuleStore *pmq, const uint8_t *buf, const uint32_t buflen);
63 void SCHSPrintInfo(MpmCtx *mpm_ctx);
64 void SCHSPrintSearchStats(MpmThreadCtx *mpm_thread_ctx);
65 #ifdef UNITTESTS
66 static void SCHSRegisterTests(void);
67 #endif
68 
69 /* size of the hash table used to speed up pattern insertions initially */
70 #define INIT_HASH_SIZE 65536
71 
72 /* Initial size of the global database hash (used for de-duplication). */
73 #define INIT_DB_HASH_SIZE 1000
74 
75 /* Global prototype scratch, built incrementally as Hyperscan databases are
76  * built and then cloned for each thread context. Access is serialised via
77  * g_scratch_proto_mutex. */
78 static hs_scratch_t *g_scratch_proto = NULL;
79 static SCMutex g_scratch_proto_mutex = SCMUTEX_INITIALIZER;
80 
81 /* Global hash table of Hyperscan databases, used for de-duplication. Access is
82  * serialised via g_db_table_mutex. */
83 static HashTable *g_db_table = NULL;
84 static SCMutex g_db_table_mutex = SCMUTEX_INITIALIZER;
85 
86 /**
87  * \internal
88  * \brief Wraps SCMalloc (which is a macro) so that it can be passed to
89  * hs_set_allocator() for Hyperscan's use.
90  */
91 static void *SCHSMalloc(size_t size)
92 {
93  return SCMalloc(size);
94 }
95 
96 /**
97  * \internal
98  * \brief Wraps SCFree (which is a macro) so that it can be passed to
99  * hs_set_allocator() for Hyperscan's use.
100  */
101 static void SCHSFree(void *ptr)
102 {
103  SCFree(ptr);
104 }
105 
106 /** \brief Register Suricata malloc/free with Hyperscan.
107  *
108  * Requests that Hyperscan use Suricata's allocator for allocation of
109  * databases, scratch space, etc.
110  */
111 static void SCHSSetAllocators(void)
112 {
113  hs_error_t err = hs_set_allocator(SCHSMalloc, SCHSFree);
114  if (err != HS_SUCCESS) {
115  FatalError("Failed to set Hyperscan allocator.");
116  }
117 }
118 
119 /**
120  * \internal
121  * \brief Creates a hash of the pattern. We use it for the hashing process
122  * during the initial pattern insertion time, to cull duplicate sigs.
123  *
124  * \param pat Pointer to the pattern.
125  * \param patlen Pattern length.
126  *
127  * \retval hash A 32 bit unsigned hash.
128  */
129 static inline uint32_t SCHSInitHashRaw(const uint8_t *pat, uint16_t patlen)
130 {
131  uint32_t hash = patlen * pat[0];
132  if (patlen > 1)
133  hash += pat[1];
134 
135  return (hash % INIT_HASH_SIZE);
136 }
137 
138 /**
139  * \internal
140  * \brief Looks up a pattern. We use it for the hashing process during
141  * the initial pattern insertion time, to cull duplicate sigs.
142  *
143  * \param ctx Pointer to the HS ctx.
144  * \param pat Pointer to the pattern.
145  * \param patlen Pattern length.
146  * \param flags Flags. We don't need this.
147  *
148  * \retval hash A 32 bit unsigned hash.
149  */
150 static inline SCHSPattern *SCHSInitHashLookup(SCHSCtx *ctx, const uint8_t *pat, uint16_t patlen,
151  uint16_t offset, uint16_t depth, char flags, uint32_t pid)
152 {
153  uint32_t hash = SCHSInitHashRaw(pat, patlen);
154 
155  if (ctx->init_hash == NULL) {
156  return NULL;
157  }
158 
159  SCHSPattern *t = ctx->init_hash[hash];
160  for (; t != NULL; t = t->next) {
161  /* Since Hyperscan uses offset/depth, we must distinguish between
162  * patterns with the same ID but different offset/depth here. */
163  if (t->id == pid && t->offset == offset && t->depth == depth) {
164  BUG_ON(t->len != patlen);
165  BUG_ON(SCMemcmp(t->original_pat, pat, patlen) != 0);
166  return t;
167  }
168  }
169 
170  return NULL;
171 }
172 
173 /**
174  * \internal
175  * \brief Allocates a new pattern instance.
176  *
177  * \param mpm_ctx Pointer to the mpm context.
178  *
179  * \retval p Pointer to the newly created pattern.
180  */
181 static inline SCHSPattern *SCHSAllocPattern(MpmCtx *mpm_ctx)
182 {
183  SCHSPattern *p = SCCalloc(1, sizeof(SCHSPattern));
184  if (unlikely(p == NULL)) {
185  exit(EXIT_FAILURE);
186  }
187 
188  mpm_ctx->memory_cnt++;
189  mpm_ctx->memory_size += sizeof(SCHSPattern);
190 
191  return p;
192 }
193 
194 /**
195  * \internal
196  * \brief Used to free SCHSPattern instances.
197  *
198  * \param mpm_ctx Pointer to the mpm context.
199  * \param p Pointer to the SCHSPattern instance to be freed.
200  * \param free Free the above pointer or not.
201  */
202 static inline void SCHSFreePattern(MpmCtx *mpm_ctx, SCHSPattern *p)
203 {
204  if (p != NULL && p->original_pat != NULL) {
205  SCFree(p->original_pat);
206  mpm_ctx->memory_cnt--;
207  mpm_ctx->memory_size -= p->len;
208  }
209 
210  if (p != NULL && p->sids != NULL) {
211  SCFree(p->sids);
212  }
213 
214  if (p != NULL) {
215  SCFree(p);
216  mpm_ctx->memory_cnt--;
217  mpm_ctx->memory_size -= sizeof(SCHSPattern);
218  }
219 }
220 
221 static inline uint32_t SCHSInitHash(SCHSPattern *p)
222 {
223  uint32_t hash = p->len * p->original_pat[0];
224  if (p->len > 1)
225  hash += p->original_pat[1];
226 
227  return (hash % INIT_HASH_SIZE);
228 }
229 
230 static inline int SCHSInitHashAdd(SCHSCtx *ctx, SCHSPattern *p)
231 {
232  uint32_t hash = SCHSInitHash(p);
233 
234  if (ctx->init_hash == NULL) {
235  return -1;
236  }
237 
238  if (ctx->init_hash[hash] == NULL) {
239  ctx->init_hash[hash] = p;
240  return 0;
241  }
242 
243  SCHSPattern *tt = NULL;
244  SCHSPattern *t = ctx->init_hash[hash];
245 
246  /* get the list tail */
247  do {
248  tt = t;
249  t = t->next;
250  } while (t != NULL);
251 
252  tt->next = p;
253 
254  return 0;
255 }
256 
257 /**
258  * \internal
259  * \brief Add a pattern to the mpm-hs context.
260  *
261  * \param mpm_ctx Mpm context.
262  * \param pat Pointer to the pattern.
263  * \param patlen Length of the pattern.
264  * \param pid Pattern id
265  * \param sid Signature id (internal id).
266  * \param flags Pattern's MPM_PATTERN_* flags.
267  *
268  * \retval 0 On success.
269  * \retval -1 On failure.
270  */
271 static int SCHSAddPattern(MpmCtx *mpm_ctx, const uint8_t *pat, uint16_t patlen, uint16_t offset,
272  uint16_t depth, uint32_t pid, SigIntId sid, uint8_t flags)
273 {
274  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
275 
276  if (offset != 0) {
278  }
279  if (depth != 0) {
281  }
282 
283  if (patlen == 0) {
284  SCLogWarning("pattern length 0");
285  return 0;
286  }
287 
288  /* check if we have already inserted this pattern */
289  SCHSPattern *p =
290  SCHSInitHashLookup(ctx, pat, patlen, offset, depth, flags, pid);
291  if (p == NULL) {
292  SCLogDebug("Allocing new pattern");
293 
294  /* p will never be NULL */
295  p = SCHSAllocPattern(mpm_ctx);
296 
297  p->len = patlen;
298  p->flags = flags;
299  p->id = pid;
300 
301  p->offset = offset;
302  p->depth = depth;
303 
304  p->original_pat = SCMalloc(patlen);
305  if (p->original_pat == NULL)
306  goto error;
307  mpm_ctx->memory_cnt++;
308  mpm_ctx->memory_size += patlen;
309  memcpy(p->original_pat, pat, patlen);
310 
311  /* put in the pattern hash */
312  if (SCHSInitHashAdd(ctx, p) != 0)
313  goto error;
314 
315  mpm_ctx->pattern_cnt++;
316 
317  if (!(mpm_ctx->flags & MPMCTX_FLAGS_NODEPTH)) {
318  if (depth) {
319  mpm_ctx->maxdepth = MAX(mpm_ctx->maxdepth, depth);
320  SCLogDebug("%p: depth %u max %u", mpm_ctx, depth, mpm_ctx->maxdepth);
321  } else {
322  mpm_ctx->flags |= MPMCTX_FLAGS_NODEPTH;
323  mpm_ctx->maxdepth = 0;
324  SCLogDebug("%p: alas, no depth for us", mpm_ctx);
325  }
326  }
327 
328  if (mpm_ctx->maxlen < patlen)
329  mpm_ctx->maxlen = patlen;
330 
331  if (mpm_ctx->minlen == 0) {
332  mpm_ctx->minlen = patlen;
333  } else {
334  if (mpm_ctx->minlen > patlen)
335  mpm_ctx->minlen = patlen;
336  }
337 
338  p->sids_size = 1;
339  p->sids = SCMalloc(p->sids_size * sizeof(SigIntId));
340  BUG_ON(p->sids == NULL);
341  p->sids[0] = sid;
342  } else {
343  /* TODO figure out how we can be called multiple times for the same CTX with the same sid */
344 
345  int found = 0;
346  uint32_t x = 0;
347  for (x = 0; x < p->sids_size; x++) {
348  if (p->sids[x] == sid) {
349  found = 1;
350  break;
351  }
352  }
353  if (!found) {
354  SigIntId *sids = SCRealloc(p->sids, (sizeof(SigIntId) * (p->sids_size + 1)));
355  BUG_ON(sids == NULL);
356  p->sids = sids;
357  p->sids[p->sids_size] = sid;
358  p->sids_size++;
359  }
360  }
361 
362  return 0;
363 
364 error:
365  SCHSFreePattern(mpm_ctx, p);
366  return -1;
367 }
368 
369 /**
370  * \brief Pattern database information used only as input to the Hyperscan
371  * compiler.
372  */
373 typedef struct SCHSCompileData_ {
374  unsigned int *ids;
375  unsigned int *flags;
376  char **expressions;
377  hs_expr_ext_t **ext;
378  unsigned int pattern_cnt;
379 } SCHSCompileData;
380 
381 static SCHSCompileData *CompileDataAlloc(unsigned int pattern_cnt)
382 {
383  SCHSCompileData *cd = SCCalloc(pattern_cnt, sizeof(SCHSCompileData));
384  if (cd == NULL) {
385  goto error;
386  }
387 
388  cd->pattern_cnt = pattern_cnt;
389 
390  cd->ids = SCCalloc(pattern_cnt, sizeof(unsigned int));
391  if (cd->ids == NULL) {
392  goto error;
393  }
394 
395  cd->flags = SCCalloc(pattern_cnt, sizeof(unsigned int));
396  if (cd->flags == NULL) {
397  goto error;
398  }
399 
400  cd->expressions = SCCalloc(pattern_cnt, sizeof(char *));
401  if (cd->expressions == NULL) {
402  goto error;
403  }
404 
405  cd->ext = SCCalloc(pattern_cnt, sizeof(hs_expr_ext_t *));
406  if (cd->ext == NULL) {
407  goto error;
408  }
409 
410  return cd;
411 
412 error:
413  SCLogDebug("SCHSCompileData alloc failed");
414  if (cd) {
415  SCFree(cd->ids);
416  SCFree(cd->flags);
417  SCFree(cd->expressions);
418  SCFree(cd->ext);
419  SCFree(cd);
420  }
421  return NULL;
422 }
423 
424 static void CompileDataFree(SCHSCompileData *cd)
425 {
426  if (cd == NULL) {
427  return;
428  }
429 
430  SCFree(cd->ids);
431  SCFree(cd->flags);
432  if (cd->expressions) {
433  for (unsigned int i = 0; i < cd->pattern_cnt; i++) {
434  SCFree(cd->expressions[i]);
435  }
436  SCFree(cd->expressions);
437  }
438  if (cd->ext) {
439  for (unsigned int i = 0; i < cd->pattern_cnt; i++) {
440  SCFree(cd->ext[i]);
441  }
442  SCFree(cd->ext);
443  }
444  SCFree(cd);
445 }
446 
447 static uint32_t SCHSPatternHash(const SCHSPattern *p, uint32_t hash)
448 {
449  BUG_ON(p->original_pat == NULL);
450  BUG_ON(p->sids == NULL);
451 
452  hash = hashlittle_safe(&p->len, sizeof(p->len), hash);
453  hash = hashlittle_safe(&p->flags, sizeof(p->flags), hash);
454  hash = hashlittle_safe(p->original_pat, p->len, hash);
455  hash = hashlittle_safe(&p->id, sizeof(p->id), hash);
456  hash = hashlittle_safe(&p->offset, sizeof(p->offset), hash);
457  hash = hashlittle_safe(&p->depth, sizeof(p->depth), hash);
458  hash = hashlittle_safe(&p->sids_size, sizeof(p->sids_size), hash);
459  hash = hashlittle_safe(p->sids, p->sids_size * sizeof(SigIntId), hash);
460  return hash;
461 }
462 
463 static char SCHSPatternCompare(const SCHSPattern *p1, const SCHSPattern *p2)
464 {
465  if ((p1->len != p2->len) || (p1->flags != p2->flags) ||
466  (p1->id != p2->id) || (p1->offset != p2->offset) ||
467  (p1->depth != p2->depth) || (p1->sids_size != p2->sids_size)) {
468  return 0;
469  }
470 
471  if (SCMemcmp(p1->original_pat, p2->original_pat, p1->len) != 0) {
472  return 0;
473  }
474 
475  if (SCMemcmp(p1->sids, p2->sids, p1->sids_size * sizeof(p1->sids[0])) !=
476  0) {
477  return 0;
478  }
479 
480  return 1;
481 }
482 
483 static uint32_t PatternDatabaseHash(HashTable *ht, void *data, uint16_t len)
484 {
485  const PatternDatabase *pd = data;
486  uint32_t hash = 0;
487  hash = hashword(&pd->pattern_cnt, 1, hash);
488 
489  for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
490  hash = SCHSPatternHash(pd->parray[i], hash);
491  }
492 
493  hash %= ht->array_size;
494  return hash;
495 }
496 
497 static char PatternDatabaseCompare(void *data1, uint16_t len1, void *data2,
498  uint16_t len2)
499 {
500  const PatternDatabase *pd1 = data1;
501  const PatternDatabase *pd2 = data2;
502 
503  if (pd1->pattern_cnt != pd2->pattern_cnt) {
504  return 0;
505  }
506 
507  for (uint32_t i = 0; i < pd1->pattern_cnt; i++) {
508  if (SCHSPatternCompare(pd1->parray[i], pd2->parray[i]) == 0) {
509  return 0;
510  }
511  }
512 
513  return 1;
514 }
515 
516 static void PatternDatabaseFree(PatternDatabase *pd)
517 {
518  BUG_ON(pd->ref_cnt != 0);
519 
520  if (pd->parray != NULL) {
521  for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
522  SCHSPattern *p = pd->parray[i];
523  if (p != NULL) {
524  SCFree(p->original_pat);
525  SCFree(p->sids);
526  SCFree(p);
527  }
528  }
529  SCFree(pd->parray);
530  }
531 
532  hs_free_database(pd->hs_db);
533 
534  SCFree(pd);
535 }
536 
537 static void PatternDatabaseTableFree(void *data)
538 {
539  /* Stub function handed to hash table; actual freeing of PatternDatabase
540  * structures is done in MPM destruction when the ref_cnt drops to zero. */
541 }
542 
543 static PatternDatabase *PatternDatabaseAlloc(uint32_t pattern_cnt)
544 {
545  PatternDatabase *pd = SCCalloc(1, sizeof(PatternDatabase));
546  if (pd == NULL) {
547  return NULL;
548  }
549  pd->pattern_cnt = pattern_cnt;
550  pd->ref_cnt = 0;
551  pd->hs_db = NULL;
552  pd->cached = false;
553 
554  /* alloc the pattern array */
555  pd->parray = (SCHSPattern **)SCCalloc(pd->pattern_cnt, sizeof(SCHSPattern *));
556  if (pd->parray == NULL) {
557  SCFree(pd);
558  return NULL;
559  }
560 
561  return pd;
562 }
563 
564 static int HSCheckPatterns(MpmCtx *mpm_ctx, SCHSCtx *ctx)
565 {
566  if (mpm_ctx->pattern_cnt == 0 || ctx->init_hash == NULL) {
567  SCLogDebug("no patterns supplied to this mpm_ctx");
568  return 0;
569  }
570  return 1;
571 }
572 
573 static void HSPatternArrayPopulate(SCHSCtx *ctx, PatternDatabase *pd)
574 {
575  for (uint32_t i = 0, p = 0; i < INIT_HASH_SIZE; i++) {
576  SCHSPattern *node = ctx->init_hash[i];
577  SCHSPattern *nnode = NULL;
578  while (node != NULL) {
579  nnode = node->next;
580  node->next = NULL;
581  pd->parray[p++] = node;
582  node = nnode;
583  }
584  }
585 }
586 
587 static void HSPatternArrayInit(SCHSCtx *ctx, PatternDatabase *pd)
588 {
589  HSPatternArrayPopulate(ctx, pd);
590  /* we no longer need the hash, so free its memory */
591  SCFree(ctx->init_hash);
592  ctx->init_hash = NULL;
593 }
594 
595 static int HSGlobalPatternDatabaseInit(void)
596 {
597  if (g_db_table == NULL) {
598  g_db_table = HashTableInit(INIT_DB_HASH_SIZE, PatternDatabaseHash,
599  PatternDatabaseCompare,
600  PatternDatabaseTableFree);
601  if (g_db_table == NULL) {
602  return -1;
603  }
604  }
605  return 0;
606 }
607 
608 static int HSScratchAlloc(const hs_database_t *db)
609 {
610  SCMutexLock(&g_scratch_proto_mutex);
611  hs_error_t err = hs_alloc_scratch(db, &g_scratch_proto);
612  SCMutexUnlock(&g_scratch_proto_mutex);
613  if (err != HS_SUCCESS) {
614  SCLogError("failed to allocate scratch");
615  return -1;
616  }
617  return 0;
618 }
619 
620 static int PatternDatabaseGetSize(PatternDatabase *pd, size_t *db_size)
621 {
622  hs_error_t err = hs_database_size(pd->hs_db, db_size);
623  if (err != HS_SUCCESS) {
624  SCLogError("failed to query database size: %s", HSErrorToStr(err));
625  return -1;
626  }
627  return 0;
628 }
629 
630 static void SCHSCleanupOnError(PatternDatabase *pd, SCHSCompileData *cd)
631 {
632  if (pd) {
633  PatternDatabaseFree(pd);
634  }
635  if (cd) {
636  CompileDataFree(cd);
637  }
638 }
639 
640 static int CompileDataExtensionsInit(hs_expr_ext_t **ext, const SCHSPattern *p)
641 {
642  if (p->flags & (MPM_PATTERN_FLAG_OFFSET | MPM_PATTERN_FLAG_DEPTH)) {
643  *ext = SCCalloc(1, sizeof(hs_expr_ext_t));
644  if ((*ext) == NULL) {
645  return -1;
646  }
647  if (p->flags & MPM_PATTERN_FLAG_OFFSET) {
648  (*ext)->flags |= HS_EXT_FLAG_MIN_OFFSET;
649  (*ext)->min_offset = p->offset + p->len;
650  }
651  if (p->flags & MPM_PATTERN_FLAG_DEPTH) {
652  (*ext)->flags |= HS_EXT_FLAG_MAX_OFFSET;
653  (*ext)->max_offset = p->offset + p->depth;
654  }
655  }
656 
657  return 0;
658 }
659 
660 /**
661  * \brief Initialize the pattern database - try to get existing pd
662  * from the global hash table, or load it from disk if caching is enabled.
663  *
664  * \param PatternDatabase* [in/out] Pointer to the pattern database to use.
665  * \param SCHSCompileData* [in] Pointer to the compile data.
666  * \retval 0 On success, negative value on failure.
667  */
668 static int PatternDatabaseGetCached(
669  PatternDatabase **pd, SCHSCompileData *cd, const char *cache_dir_path)
670 {
671  /* Check global hash table to see if we've seen this pattern database
672  * before, and reuse the Hyperscan database if so. */
673  PatternDatabase *pd_cached = HashTableLookup(g_db_table, *pd, 1);
674  if (pd_cached != NULL) {
675  SCLogDebug("Reusing cached database %p with %" PRIu32
676  " patterns (ref_cnt=%" PRIu32 ")",
677  pd_cached->hs_db, pd_cached->pattern_cnt,
678  pd_cached->ref_cnt);
679  pd_cached->ref_cnt++;
680  PatternDatabaseFree(*pd);
681  CompileDataFree(cd);
682  *pd = pd_cached;
683  return 0;
684  } else if (cache_dir_path) {
685  pd_cached = *pd;
686  char hs_db_hash[SC_SHA256_LEN * 2 + 1]; // * 2 for hex +1 for nul terminator
687  if (HSHashDb(pd_cached, hs_db_hash, ARRAY_SIZE(hs_db_hash)) != 0) {
688  return -1;
689  }
690  if (HSLoadCache(&pd_cached->hs_db, hs_db_hash, cache_dir_path) == 0) {
691  pd_cached->ref_cnt = 1;
692  pd_cached->cached = true;
693  if (HSScratchAlloc(pd_cached->hs_db) != 0) {
694  goto recover;
695  }
696  if (HashTableAdd(g_db_table, pd_cached, 1) < 0) {
697  goto recover;
698  }
699  CompileDataFree(cd);
700  return 0;
701 
702  recover:
703  pd_cached->ref_cnt = 0;
704  pd_cached->cached = false;
705  return -1;
706  }
707  }
708 
709  return -1; // not cached
710 }
711 
712 static int PatternDatabaseCompile(PatternDatabase *pd, SCHSCompileData *cd)
713 {
714  for (uint32_t i = 0; i < pd->pattern_cnt; i++) {
715  const SCHSPattern *p = pd->parray[i];
716  cd->ids[i] = i;
717  cd->flags[i] = HS_FLAG_SINGLEMATCH;
718  if (p->flags & MPM_PATTERN_FLAG_NOCASE) {
719  cd->flags[i] |= HS_FLAG_CASELESS;
720  }
721  cd->expressions[i] = HSRenderPattern(p->original_pat, p->len);
722  if (CompileDataExtensionsInit(&cd->ext[i], p) != 0) {
723  return -1;
724  }
725  }
726 
727  hs_compile_error_t *compile_err = NULL;
728  hs_error_t err = hs_compile_ext_multi((const char *const *)cd->expressions, cd->flags, cd->ids,
729  (const hs_expr_ext_t *const *)cd->ext, cd->pattern_cnt, HS_MODE_BLOCK, NULL, &pd->hs_db,
730  &compile_err);
731  if (err != HS_SUCCESS) {
732  HSLogCompileError("multiple patterns", compile_err, err);
733  return -1;
734  }
735 
736  if (HSScratchAlloc(pd->hs_db) != 0) {
737  return -1;
738  }
739 
740  if (HashTableAdd(g_db_table, pd, 1) < 0) {
741  return -1;
742  }
743  pd->ref_cnt = 1;
744  return 0;
745 }
746 
747 /**
748  * \brief Process the patterns added to the mpm, and create the internal tables.
749  *
750  * \param mpm_conf Pointer to the generic MPM matcher configuration
751  * \param mpm_ctx Pointer to the mpm context.
752  */
753 int SCHSPreparePatterns(MpmConfig *mpm_conf, MpmCtx *mpm_ctx)
754 {
755  SCHSCtx *ctx = (SCHSCtx *)mpm_ctx->ctx;
756 
757  if (HSCheckPatterns(mpm_ctx, ctx) == 0) {
758  return 0;
759  }
760 
761  SCHSCompileData *cd = CompileDataAlloc(mpm_ctx->pattern_cnt);
762  PatternDatabase *pd = PatternDatabaseAlloc(mpm_ctx->pattern_cnt);
763  if (cd == NULL || pd == NULL) {
764  goto error;
765  }
766 
767  HSPatternArrayInit(ctx, pd);
768  pd->no_cache = !(mpm_ctx->flags & MPMCTX_FLAGS_CACHE_TO_DISK);
769  /* Serialise whole database compilation as a relatively easy way to ensure
770  * dedupe is safe. */
771  SCMutexLock(&g_db_table_mutex);
772  if (HSGlobalPatternDatabaseInit() == -1) {
773  SCMutexUnlock(&g_db_table_mutex);
774  goto error;
775  }
776 
777  const char *cache_path = pd->no_cache || !mpm_conf ? NULL : mpm_conf->cache_dir_path;
778  if (PatternDatabaseGetCached(&pd, cd, cache_path) == 0 && 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  MpmConfig *c = SCCalloc(1, sizeof(MpmConfig));
1182  return c;
1183 }
1184 
1185 static void SCHSConfigDeinit(MpmConfig **c)
1186 {
1187  if (c != NULL) {
1188  SCFree(*c);
1189  (*c) = NULL;
1190  }
1191 }
1192 
1193 static void SCHSConfigCacheDirSet(MpmConfig *c, const char *dir_path)
1194 {
1195  c->cache_dir_path = dir_path;
1196 }
1197 
1198 /************************** Mpm Registration ***************************/
1199 
1200 /**
1201  * \brief Register the Hyperscan MPM.
1202  */
1203 void MpmHSRegister(void)
1204 {
1205  mpm_table[MPM_HS].name = "hs";
1206  mpm_table[MPM_HS].InitCtx = SCHSInitCtx;
1207  mpm_table[MPM_HS].InitThreadCtx = SCHSInitThreadCtx;
1208  mpm_table[MPM_HS].DestroyCtx = SCHSDestroyCtx;
1209  mpm_table[MPM_HS].DestroyThreadCtx = SCHSDestroyThreadCtx;
1210  mpm_table[MPM_HS].ConfigInit = SCHSConfigInit;
1211  mpm_table[MPM_HS].ConfigDeinit = SCHSConfigDeinit;
1212  mpm_table[MPM_HS].ConfigCacheDirSet = SCHSConfigCacheDirSet;
1213  mpm_table[MPM_HS].AddPattern = SCHSAddPatternCS;
1214  mpm_table[MPM_HS].AddPatternNocase = SCHSAddPatternCI;
1215  mpm_table[MPM_HS].Prepare = SCHSPreparePatterns;
1216  mpm_table[MPM_HS].CacheStatsInit = SCHSCacheStatsInit;
1217  mpm_table[MPM_HS].CacheStatsPrint = SCHSCacheStatsPrint;
1218  mpm_table[MPM_HS].CacheStatsDeinit = SCHSCacheStatsDeinit;
1219  mpm_table[MPM_HS].CacheRuleset = SCHSCacheRuleset;
1220  mpm_table[MPM_HS].CachePrune = SCHSCachePrune;
1221  mpm_table[MPM_HS].Search = SCHSSearch;
1222  mpm_table[MPM_HS].PrintCtx = SCHSPrintInfo;
1223  mpm_table[MPM_HS].PrintThreadCtx = SCHSPrintSearchStats;
1224 #ifdef UNITTESTS
1225  mpm_table[MPM_HS].RegisterUnittests = SCHSRegisterTests;
1226 #endif
1228  /* Set Hyperscan memory allocators */
1229  SCHSSetAllocators();
1230 }
1231 
1232 /**
1233  * \brief Clean up global memory used by all Hyperscan MPM instances.
1234  *
1235  * Currently, this is just the global scratch prototype.
1236  */
1237 void MpmHSGlobalCleanup(void)
1238 {
1239  SCMutexLock(&g_scratch_proto_mutex);
1240  if (g_scratch_proto) {
1241  SCLogDebug("Cleaning up Hyperscan global scratch");
1242  hs_free_scratch(g_scratch_proto);
1243  g_scratch_proto = NULL;
1244  }
1245  SCMutexUnlock(&g_scratch_proto_mutex);
1246 
1247  SCMutexLock(&g_db_table_mutex);
1248  if (g_db_table != NULL) {
1249  SCLogDebug("Clearing Hyperscan database cache");
1250  HashTableFree(g_db_table);
1251  g_db_table = NULL;
1252  }
1253  SCMutexUnlock(&g_db_table_mutex);
1254 
1255  SCHSCacheDeinit();
1256 }
1257 
1258 /*************************************Unittests********************************/
1259 
1260 #ifdef UNITTESTS
1261 #include "detect-engine-alert.h"
1262 
1263 static int SCHSTest01(void)
1264 {
1265  int result = 0;
1266  MpmCtx mpm_ctx;
1267  MpmThreadCtx mpm_thread_ctx;
1268  PrefilterRuleStore pmq;
1269 
1270  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1271  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1272  MpmInitCtx(&mpm_ctx, MPM_HS);
1273 
1274  /* 1 match */
1275  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1276  PmqSetup(&pmq);
1277 
1278  SCHSPreparePatterns(NULL, &mpm_ctx);
1279  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1280 
1281  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1282 
1283  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1284  strlen(buf));
1285 
1286  if (cnt == 1)
1287  result = 1;
1288  else
1289  printf("1 != %" 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 SCHSTest02(void)
1298 {
1299  int result = 0;
1300  MpmCtx mpm_ctx;
1301  MpmThreadCtx mpm_thread_ctx;
1302  PrefilterRuleStore pmq;
1303 
1304  memset(&mpm_ctx, 0, 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 *)"abce", 4, 0, 0, 0, 0, 0);
1310  PmqSetup(&pmq);
1311 
1312  SCHSPreparePatterns(NULL, &mpm_ctx);
1313  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1314 
1315  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1316  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1317  strlen(buf));
1318 
1319  if (cnt == 0)
1320  result = 1;
1321  else
1322  printf("0 != %" PRIu32 " ", cnt);
1323 
1324  SCHSDestroyCtx(&mpm_ctx);
1325  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1326  PmqFree(&pmq);
1327  return result;
1328 }
1329 
1330 static int SCHSTest03(void)
1331 {
1332  int result = 0;
1333  MpmCtx mpm_ctx;
1334  MpmThreadCtx mpm_thread_ctx;
1335  PrefilterRuleStore pmq;
1336 
1337  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1338  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1339  MpmInitCtx(&mpm_ctx, MPM_HS);
1340 
1341  /* 1 match */
1342  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1343  /* 1 match */
1344  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0);
1345  /* 1 match */
1346  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0);
1347  PmqSetup(&pmq);
1348 
1349  SCHSPreparePatterns(NULL, &mpm_ctx);
1350  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1351 
1352  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1353  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1354  strlen(buf));
1355 
1356  if (cnt == 3)
1357  result = 1;
1358  else
1359  printf("3 != %" PRIu32 " ", cnt);
1360 
1361  SCHSDestroyCtx(&mpm_ctx);
1362  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1363  PmqFree(&pmq);
1364  return result;
1365 }
1366 
1367 static int SCHSTest04(void)
1368 {
1369  int result = 0;
1370  MpmCtx mpm_ctx;
1371  MpmThreadCtx mpm_thread_ctx;
1372  PrefilterRuleStore pmq;
1373 
1374  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1375  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1376  MpmInitCtx(&mpm_ctx, MPM_HS);
1377 
1378  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1379  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0);
1380  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0);
1381  PmqSetup(&pmq);
1382 
1383  SCHSPreparePatterns(NULL, &mpm_ctx);
1384  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1385 
1386  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1387  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1388  strlen(buf));
1389 
1390  if (cnt == 1)
1391  result = 1;
1392  else
1393  printf("1 != %" PRIu32 " ", cnt);
1394 
1395  SCHSDestroyCtx(&mpm_ctx);
1396  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1397  PmqFree(&pmq);
1398  return result;
1399 }
1400 
1401 static int SCHSTest05(void)
1402 {
1403  int result = 0;
1404  MpmCtx mpm_ctx;
1405  MpmThreadCtx mpm_thread_ctx;
1406  PrefilterRuleStore pmq;
1407 
1408  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1409  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1410  MpmInitCtx(&mpm_ctx, MPM_HS);
1411 
1412  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
1413  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
1414  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0);
1415  PmqSetup(&pmq);
1416 
1417  SCHSPreparePatterns(NULL, &mpm_ctx);
1418  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1419 
1420  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1421  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1422  strlen(buf));
1423 
1424  if (cnt == 3)
1425  result = 1;
1426  else
1427  printf("3 != %" PRIu32 " ", cnt);
1428 
1429  SCHSDestroyCtx(&mpm_ctx);
1430  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1431  PmqFree(&pmq);
1432  return result;
1433 }
1434 
1435 static int SCHSTest06(void)
1436 {
1437  int result = 0;
1438  MpmCtx mpm_ctx;
1439  MpmThreadCtx mpm_thread_ctx;
1440  PrefilterRuleStore pmq;
1441 
1442  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1443  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1444  MpmInitCtx(&mpm_ctx, MPM_HS);
1445 
1446  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1447  PmqSetup(&pmq);
1448 
1449  SCHSPreparePatterns(NULL, &mpm_ctx);
1450  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1451 
1452  const char *buf = "abcd";
1453  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1454  strlen(buf));
1455 
1456  if (cnt == 1)
1457  result = 1;
1458  else
1459  printf("1 != %" PRIu32 " ", cnt);
1460 
1461  SCHSDestroyCtx(&mpm_ctx);
1462  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1463  PmqFree(&pmq);
1464  return result;
1465 }
1466 
1467 static int SCHSTest07(void)
1468 {
1469  int result = 0;
1470  MpmCtx mpm_ctx;
1471  MpmThreadCtx mpm_thread_ctx;
1472  PrefilterRuleStore pmq;
1473 
1474  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1475  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1476  MpmInitCtx(&mpm_ctx, MPM_HS);
1477 
1478  /* should match 30 times */
1479  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0);
1480  /* should match 29 times */
1481  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0);
1482  /* should match 28 times */
1483  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0);
1484  /* 26 */
1485  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0);
1486  /* 21 */
1487  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0);
1488  /* 1 */
1489  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 30,
1490  0, 0, 5, 0, 0);
1491  PmqSetup(&pmq);
1492 
1493  SCHSPreparePatterns(NULL, &mpm_ctx);
1494  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1495 
1496  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1497  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1498  strlen(buf));
1499 
1500  if (cnt == 6)
1501  result = 1;
1502  else
1503  printf("6 != %" PRIu32 " ", cnt);
1504 
1505  SCHSDestroyCtx(&mpm_ctx);
1506  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1507  PmqFree(&pmq);
1508  return result;
1509 }
1510 
1511 static int SCHSTest08(void)
1512 {
1513  int result = 0;
1514  MpmCtx mpm_ctx;
1515  MpmThreadCtx mpm_thread_ctx;
1516  PrefilterRuleStore pmq;
1517 
1518  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1519  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1520  MpmInitCtx(&mpm_ctx, MPM_HS);
1521 
1522  /* 1 match */
1523  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1524  PmqSetup(&pmq);
1525 
1526  SCHSPreparePatterns(NULL, &mpm_ctx);
1527  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1528 
1529  uint32_t cnt =
1530  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"a", 1);
1531 
1532  if (cnt == 0)
1533  result = 1;
1534  else
1535  printf("0 != %" PRIu32 " ", cnt);
1536 
1537  SCHSDestroyCtx(&mpm_ctx);
1538  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1539  PmqFree(&pmq);
1540  return result;
1541 }
1542 
1543 static int SCHSTest09(void)
1544 {
1545  int result = 0;
1546  MpmCtx mpm_ctx;
1547  MpmThreadCtx mpm_thread_ctx;
1548  PrefilterRuleStore pmq;
1549 
1550  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1551  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1552  MpmInitCtx(&mpm_ctx, MPM_HS);
1553 
1554  /* 1 match */
1555  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0);
1556  PmqSetup(&pmq);
1557 
1558  SCHSPreparePatterns(NULL, &mpm_ctx);
1559  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1560 
1561  uint32_t cnt =
1562  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"ab", 2);
1563 
1564  if (cnt == 1)
1565  result = 1;
1566  else
1567  printf("1 != %" PRIu32 " ", cnt);
1568 
1569  SCHSDestroyCtx(&mpm_ctx);
1570  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1571  PmqFree(&pmq);
1572  return result;
1573 }
1574 
1575 static int SCHSTest10(void)
1576 {
1577  int result = 0;
1578  MpmCtx mpm_ctx;
1579  MpmThreadCtx mpm_thread_ctx;
1580  PrefilterRuleStore pmq;
1581 
1582  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1583  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1584  MpmInitCtx(&mpm_ctx, MPM_HS);
1585 
1586  /* 1 match */
1587  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0);
1588  PmqSetup(&pmq);
1589 
1590  SCHSPreparePatterns(NULL, &mpm_ctx);
1591  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1592 
1593  const char *buf = "01234567890123456789012345678901234567890123456789"
1594  "01234567890123456789012345678901234567890123456789"
1595  "abcdefgh"
1596  "01234567890123456789012345678901234567890123456789"
1597  "01234567890123456789012345678901234567890123456789";
1598  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1599  strlen(buf));
1600 
1601  if (cnt == 1)
1602  result = 1;
1603  else
1604  printf("1 != %" PRIu32 " ", cnt);
1605 
1606  SCHSDestroyCtx(&mpm_ctx);
1607  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1608  PmqFree(&pmq);
1609  return result;
1610 }
1611 
1612 static int SCHSTest11(void)
1613 {
1614  int result = 0;
1615  MpmCtx mpm_ctx;
1616  MpmThreadCtx mpm_thread_ctx;
1617  PrefilterRuleStore pmq;
1618 
1619  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1620  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1621  MpmInitCtx(&mpm_ctx, MPM_HS);
1622 
1623  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"he", 2, 0, 0, 1, 0, 0) == -1)
1624  goto end;
1625  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"she", 3, 0, 0, 2, 0, 0) == -1)
1626  goto end;
1627  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"his", 3, 0, 0, 3, 0, 0) == -1)
1628  goto end;
1629  if (MpmAddPatternCS(&mpm_ctx, (uint8_t *)"hers", 4, 0, 0, 4, 0, 0) == -1)
1630  goto end;
1631  PmqSetup(&pmq);
1632 
1633  if (SCHSPreparePatterns(NULL, &mpm_ctx) == -1)
1634  goto end;
1635 
1636  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1637 
1638  result = 1;
1639 
1640  const char *buf = "he";
1641  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1642  strlen(buf)) == 1);
1643  buf = "she";
1644  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1645  strlen(buf)) == 2);
1646  buf = "his";
1647  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1648  strlen(buf)) == 1);
1649  buf = "hers";
1650  result &= (SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1651  strlen(buf)) == 2);
1652 
1653 end:
1654  SCHSDestroyCtx(&mpm_ctx);
1655  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1656  PmqFree(&pmq);
1657  return result;
1658 }
1659 
1660 static int SCHSTest12(void)
1661 {
1662  int result = 0;
1663  MpmCtx mpm_ctx;
1664  MpmThreadCtx mpm_thread_ctx;
1665  PrefilterRuleStore pmq;
1666 
1667  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1668  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1669  MpmInitCtx(&mpm_ctx, MPM_HS);
1670 
1671  /* 1 match */
1672  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0);
1673  /* 1 match */
1674  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0);
1675  PmqSetup(&pmq);
1676 
1677  SCHSPreparePatterns(NULL, &mpm_ctx);
1678  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1679 
1680  const char *buf = "abcdefghijklmnopqrstuvwxyz";
1681  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1682  strlen(buf));
1683 
1684  if (cnt == 2)
1685  result = 1;
1686  else
1687  printf("2 != %" PRIu32 " ", cnt);
1688 
1689  SCHSDestroyCtx(&mpm_ctx);
1690  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1691  PmqFree(&pmq);
1692  return result;
1693 }
1694 
1695 static int SCHSTest13(void)
1696 {
1697  int result = 0;
1698  MpmCtx mpm_ctx;
1699  MpmThreadCtx mpm_thread_ctx;
1700  PrefilterRuleStore pmq;
1701 
1702  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1703  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1704  MpmInitCtx(&mpm_ctx, MPM_HS);
1705 
1706  /* 1 match */
1707  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCD";
1708  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1709  PmqSetup(&pmq);
1710 
1711  SCHSPreparePatterns(NULL, &mpm_ctx);
1712  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1713 
1714  const char *buf = "abcdefghijklmnopqrstuvwxyzABCD";
1715  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1716  strlen(buf));
1717 
1718  if (cnt == 1)
1719  result = 1;
1720  else
1721  printf("1 != %" PRIu32 " ", cnt);
1722 
1723  SCHSDestroyCtx(&mpm_ctx);
1724  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1725  PmqFree(&pmq);
1726  return result;
1727 }
1728 
1729 static int SCHSTest14(void)
1730 {
1731  int result = 0;
1732  MpmCtx mpm_ctx;
1733  MpmThreadCtx mpm_thread_ctx;
1734  PrefilterRuleStore pmq;
1735 
1736  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1737  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1738  MpmInitCtx(&mpm_ctx, MPM_HS);
1739 
1740  /* 1 match */
1741  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDE";
1742  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1743  PmqSetup(&pmq);
1744 
1745  SCHSPreparePatterns(NULL, &mpm_ctx);
1746  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1747 
1748  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE";
1749  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1750  strlen(buf));
1751 
1752  if (cnt == 1)
1753  result = 1;
1754  else
1755  printf("1 != %" PRIu32 " ", cnt);
1756 
1757  SCHSDestroyCtx(&mpm_ctx);
1758  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1759  PmqFree(&pmq);
1760  return result;
1761 }
1762 
1763 static int SCHSTest15(void)
1764 {
1765  int result = 0;
1766  MpmCtx mpm_ctx;
1767  MpmThreadCtx mpm_thread_ctx;
1768  PrefilterRuleStore pmq;
1769 
1770  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1771  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1772  MpmInitCtx(&mpm_ctx, MPM_HS);
1773 
1774  /* 1 match */
1775  const char pat[] = "abcdefghijklmnopqrstuvwxyzABCDEF";
1776  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1777  PmqSetup(&pmq);
1778 
1779  SCHSPreparePatterns(NULL, &mpm_ctx);
1780  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1781 
1782  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF";
1783  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1784  strlen(buf));
1785 
1786  if (cnt == 1)
1787  result = 1;
1788  else
1789  printf("1 != %" PRIu32 " ", cnt);
1790 
1791  SCHSDestroyCtx(&mpm_ctx);
1792  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1793  PmqFree(&pmq);
1794  return result;
1795 }
1796 
1797 static int SCHSTest16(void)
1798 {
1799  int result = 0;
1800  MpmCtx mpm_ctx;
1801  MpmThreadCtx mpm_thread_ctx;
1802  PrefilterRuleStore pmq;
1803 
1804  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1805  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1806  MpmInitCtx(&mpm_ctx, MPM_HS);
1807 
1808  /* 1 match */
1809  const char pat[] = "abcdefghijklmnopqrstuvwxyzABC";
1810  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1811  PmqSetup(&pmq);
1812 
1813  SCHSPreparePatterns(NULL, &mpm_ctx);
1814  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1815 
1816  const char *buf = "abcdefghijklmnopqrstuvwxyzABC";
1817  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1818  strlen(buf));
1819 
1820  if (cnt == 1)
1821  result = 1;
1822  else
1823  printf("1 != %" PRIu32 " ", cnt);
1824 
1825  SCHSDestroyCtx(&mpm_ctx);
1826  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1827  PmqFree(&pmq);
1828  return result;
1829 }
1830 
1831 static int SCHSTest17(void)
1832 {
1833  int result = 0;
1834  MpmCtx mpm_ctx;
1835  MpmThreadCtx mpm_thread_ctx;
1836  PrefilterRuleStore pmq;
1837 
1838  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1839  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1840  MpmInitCtx(&mpm_ctx, MPM_HS);
1841 
1842  /* 1 match */
1843  const char pat[] = "abcdefghijklmnopqrstuvwxyzAB";
1844  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1845  PmqSetup(&pmq);
1846 
1847  SCHSPreparePatterns(NULL, &mpm_ctx);
1848  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1849 
1850  const char *buf = "abcdefghijklmnopqrstuvwxyzAB";
1851  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1852  strlen(buf));
1853 
1854  if (cnt == 1)
1855  result = 1;
1856  else
1857  printf("1 != %" PRIu32 " ", cnt);
1858 
1859  SCHSDestroyCtx(&mpm_ctx);
1860  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1861  PmqFree(&pmq);
1862  return result;
1863 }
1864 
1865 static int SCHSTest18(void)
1866 {
1867  int result = 0;
1868  MpmCtx mpm_ctx;
1869  MpmThreadCtx mpm_thread_ctx;
1870  PrefilterRuleStore pmq;
1871 
1872  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1873  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1874  MpmInitCtx(&mpm_ctx, MPM_HS);
1875 
1876  /* 1 match */
1877  const char pat[] = "abcde"
1878  "fghij"
1879  "klmno"
1880  "pqrst"
1881  "uvwxy"
1882  "z";
1883  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1884  PmqSetup(&pmq);
1885 
1886  SCHSPreparePatterns(NULL, &mpm_ctx);
1887  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1888 
1889  const char *buf = "abcde"
1890  "fghij"
1891  "klmno"
1892  "pqrst"
1893  "uvwxy"
1894  "z";
1895  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1896  strlen(buf));
1897 
1898  if (cnt == 1)
1899  result = 1;
1900  else
1901  printf("1 != %" PRIu32 " ", cnt);
1902 
1903  SCHSDestroyCtx(&mpm_ctx);
1904  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1905  PmqFree(&pmq);
1906  return result;
1907 }
1908 
1909 static int SCHSTest19(void)
1910 {
1911  int result = 0;
1912  MpmCtx mpm_ctx;
1913  MpmThreadCtx mpm_thread_ctx;
1914  PrefilterRuleStore pmq;
1915 
1916  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1917  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1918  MpmInitCtx(&mpm_ctx, MPM_HS);
1919 
1920  /* 1 */
1921  const char pat[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1922  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1923  PmqSetup(&pmq);
1924 
1925  SCHSPreparePatterns(NULL, &mpm_ctx);
1926  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1927 
1928  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1929  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1930  strlen(buf));
1931 
1932  if (cnt == 1)
1933  result = 1;
1934  else
1935  printf("1 != %" PRIu32 " ", cnt);
1936 
1937  SCHSDestroyCtx(&mpm_ctx);
1938  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1939  PmqFree(&pmq);
1940  return result;
1941 }
1942 
1943 static int SCHSTest20(void)
1944 {
1945  int result = 0;
1946  MpmCtx mpm_ctx;
1947  MpmThreadCtx mpm_thread_ctx;
1948  PrefilterRuleStore pmq;
1949 
1950  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1951  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1952  MpmInitCtx(&mpm_ctx, MPM_HS);
1953 
1954  /* 1 */
1955  const char pat[] = "AAAAA"
1956  "AAAAA"
1957  "AAAAA"
1958  "AAAAA"
1959  "AAAAA"
1960  "AAAAA"
1961  "AA";
1962  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, sizeof(pat) - 1, 0, 0, 0, 0, 0);
1963  PmqSetup(&pmq);
1964 
1965  SCHSPreparePatterns(NULL, &mpm_ctx);
1966  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1967 
1968  const char *buf = "AAAAA"
1969  "AAAAA"
1970  "AAAAA"
1971  "AAAAA"
1972  "AAAAA"
1973  "AAAAA"
1974  "AA";
1975  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1976  strlen(buf));
1977 
1978  if (cnt == 1)
1979  result = 1;
1980  else
1981  printf("1 != %" PRIu32 " ", cnt);
1982 
1983  SCHSDestroyCtx(&mpm_ctx);
1984  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1985  PmqFree(&pmq);
1986  return result;
1987 }
1988 
1989 static int SCHSTest21(void)
1990 {
1991  int result = 0;
1992  MpmCtx mpm_ctx;
1993  MpmThreadCtx mpm_thread_ctx;
1994  PrefilterRuleStore pmq;
1995 
1996  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1997  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1998  MpmInitCtx(&mpm_ctx, MPM_HS);
1999 
2000  /* 1 */
2001  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2002  PmqSetup(&pmq);
2003 
2004  SCHSPreparePatterns(NULL, &mpm_ctx);
2005  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2006 
2007  uint32_t cnt =
2008  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"AA", 2);
2009 
2010  if (cnt == 1)
2011  result = 1;
2012  else
2013  printf("1 != %" PRIu32 " ", cnt);
2014 
2015  SCHSDestroyCtx(&mpm_ctx);
2016  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2017  PmqFree(&pmq);
2018  return result;
2019 }
2020 
2021 static int SCHSTest22(void)
2022 {
2023  int result = 0;
2024  MpmCtx mpm_ctx;
2025  MpmThreadCtx mpm_thread_ctx;
2026  PrefilterRuleStore pmq;
2027 
2028  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2029  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2030  MpmInitCtx(&mpm_ctx, MPM_HS);
2031 
2032  /* 1 match */
2033  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
2034  /* 1 match */
2035  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0);
2036  PmqSetup(&pmq);
2037 
2038  SCHSPreparePatterns(NULL, &mpm_ctx);
2039  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2040 
2041  const char *buf = "abcdefghijklmnopqrstuvwxyz";
2042  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2043  strlen(buf));
2044 
2045  if (cnt == 2)
2046  result = 1;
2047  else
2048  printf("2 != %" PRIu32 " ", cnt);
2049 
2050  SCHSDestroyCtx(&mpm_ctx);
2051  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2052  PmqFree(&pmq);
2053  return result;
2054 }
2055 
2056 static int SCHSTest23(void)
2057 {
2058  int result = 0;
2059  MpmCtx mpm_ctx;
2060  MpmThreadCtx mpm_thread_ctx;
2061  PrefilterRuleStore pmq;
2062 
2063  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2064  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2065  MpmInitCtx(&mpm_ctx, MPM_HS);
2066 
2067  /* 1 */
2068  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2069  PmqSetup(&pmq);
2070 
2071  SCHSPreparePatterns(NULL, &mpm_ctx);
2072  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2073 
2074  uint32_t cnt =
2075  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2);
2076 
2077  if (cnt == 0)
2078  result = 1;
2079  else
2080  printf("1 != %" PRIu32 " ", cnt);
2081 
2082  SCHSDestroyCtx(&mpm_ctx);
2083  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2084  PmqFree(&pmq);
2085  return result;
2086 }
2087 
2088 static int SCHSTest24(void)
2089 {
2090  int result = 0;
2091  MpmCtx mpm_ctx;
2092  MpmThreadCtx mpm_thread_ctx;
2093  PrefilterRuleStore pmq;
2094 
2095  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2096  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2097  MpmInitCtx(&mpm_ctx, MPM_HS);
2098 
2099  /* 1 */
2100  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2101  PmqSetup(&pmq);
2102 
2103  SCHSPreparePatterns(NULL, &mpm_ctx);
2104  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2105 
2106  uint32_t cnt =
2107  SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)"aa", 2);
2108 
2109  if (cnt == 1)
2110  result = 1;
2111  else
2112  printf("1 != %" PRIu32 " ", cnt);
2113 
2114  SCHSDestroyCtx(&mpm_ctx);
2115  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2116  PmqFree(&pmq);
2117  return result;
2118 }
2119 
2120 static int SCHSTest25(void)
2121 {
2122  int result = 0;
2123  MpmCtx mpm_ctx;
2124  MpmThreadCtx mpm_thread_ctx;
2125  PrefilterRuleStore pmq;
2126 
2127  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2128  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2129  MpmInitCtx(&mpm_ctx, MPM_HS);
2130 
2131  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
2132  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
2133  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0);
2134  PmqSetup(&pmq);
2135 
2136  SCHSPreparePatterns(NULL, &mpm_ctx);
2137  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2138 
2139  const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2140  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2141  strlen(buf));
2142 
2143  if (cnt == 3)
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 SCHSTest26(void)
2155 {
2156  int result = 0;
2157  MpmCtx mpm_ctx;
2158  MpmThreadCtx mpm_thread_ctx;
2159  PrefilterRuleStore pmq;
2160 
2161  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2162  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2163  MpmInitCtx(&mpm_ctx, MPM_HS);
2164 
2165  SCMpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0);
2166  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0);
2167  PmqSetup(&pmq);
2168 
2169  SCHSPreparePatterns(NULL, &mpm_ctx);
2170  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2171 
2172  const char *buf = "works";
2173  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2174  strlen(buf));
2175 
2176  if (cnt == 1)
2177  result = 1;
2178  else
2179  printf("3 != %" 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 SCHSTest27(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 SCHSTest28(void)
2221 {
2222  int result = 0;
2223  MpmCtx mpm_ctx;
2224  MpmThreadCtx mpm_thread_ctx;
2225  PrefilterRuleStore pmq;
2226 
2227  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2228  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2229  MpmInitCtx(&mpm_ctx, MPM_HS);
2230 
2231  /* 0 match */
2232  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0);
2233  PmqSetup(&pmq);
2234 
2235  SCHSPreparePatterns(NULL, &mpm_ctx);
2236  SCHSInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2237 
2238  const char *buf = "tONE";
2239  uint32_t cnt = SCHSSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
2240  strlen(buf));
2241 
2242  if (cnt == 0)
2243  result = 1;
2244  else
2245  printf("0 != %" PRIu32 " ", cnt);
2246 
2247  SCHSDestroyCtx(&mpm_ctx);
2248  SCHSDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2249  PmqFree(&pmq);
2250  return result;
2251 }
2252 
2253 static int SCHSTest29(void)
2254 {
2255  uint8_t buf[] = "onetwothreefourfivesixseveneightnine";
2256  uint16_t buflen = sizeof(buf) - 1;
2257  Packet *p = NULL;
2258  ThreadVars th_v;
2259  DetectEngineThreadCtx *det_ctx = NULL;
2260  int result = 0;
2261 
2262  memset(&th_v, 0, sizeof(th_v));
2263  StatsThreadInit(&th_v.stats);
2264  p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2265 
2267  if (de_ctx == NULL)
2268  goto end;
2270 
2271  de_ctx->flags |= DE_QUIET;
2272 
2273  de_ctx->sig_list = SigInit(
2274  de_ctx, "alert tcp any any -> any any "
2275  "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)");
2276  if (de_ctx->sig_list == NULL)
2277  goto end;
2278  de_ctx->sig_list->next =
2279  SigInit(de_ctx, "alert tcp any any -> any any "
2280  "(content:\"onetwothreefourfivesixseveneightnine\"; "
2281  "fast_pattern:3,3; sid:2;)");
2282  if (de_ctx->sig_list->next == NULL)
2283  goto end;
2284 
2286  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2287 
2288  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2289  if (PacketAlertCheck(p, 1) != 1) {
2290  printf("if (PacketAlertCheck(p, 1) != 1) failure\n");
2291  goto end;
2292  }
2293  if (PacketAlertCheck(p, 2) != 1) {
2294  printf("if (PacketAlertCheck(p, 1) != 2) failure\n");
2295  goto end;
2296  }
2297 
2298  result = 1;
2299 end:
2300  UTHFreePackets(&p, 1);
2301  if (de_ctx != NULL) {
2302  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2304  }
2305 
2306  StatsThreadCleanup(&th_v.stats);
2307  return result;
2308 }
2309 
2310 static void SCHSRegisterTests(void)
2311 {
2312  UtRegisterTest("SCHSTest01", SCHSTest01);
2313  UtRegisterTest("SCHSTest02", SCHSTest02);
2314  UtRegisterTest("SCHSTest03", SCHSTest03);
2315  UtRegisterTest("SCHSTest04", SCHSTest04);
2316  UtRegisterTest("SCHSTest05", SCHSTest05);
2317  UtRegisterTest("SCHSTest06", SCHSTest06);
2318  UtRegisterTest("SCHSTest07", SCHSTest07);
2319  UtRegisterTest("SCHSTest08", SCHSTest08);
2320  UtRegisterTest("SCHSTest09", SCHSTest09);
2321  UtRegisterTest("SCHSTest10", SCHSTest10);
2322  UtRegisterTest("SCHSTest11", SCHSTest11);
2323  UtRegisterTest("SCHSTest12", SCHSTest12);
2324  UtRegisterTest("SCHSTest13", SCHSTest13);
2325  UtRegisterTest("SCHSTest14", SCHSTest14);
2326  UtRegisterTest("SCHSTest15", SCHSTest15);
2327  UtRegisterTest("SCHSTest16", SCHSTest16);
2328  UtRegisterTest("SCHSTest17", SCHSTest17);
2329  UtRegisterTest("SCHSTest18", SCHSTest18);
2330  UtRegisterTest("SCHSTest19", SCHSTest19);
2331  UtRegisterTest("SCHSTest20", SCHSTest20);
2332  UtRegisterTest("SCHSTest21", SCHSTest21);
2333  UtRegisterTest("SCHSTest22", SCHSTest22);
2334  UtRegisterTest("SCHSTest23", SCHSTest23);
2335  UtRegisterTest("SCHSTest24", SCHSTest24);
2336  UtRegisterTest("SCHSTest25", SCHSTest25);
2337  UtRegisterTest("SCHSTest26", SCHSTest26);
2338  UtRegisterTest("SCHSTest27", SCHSTest27);
2339  UtRegisterTest("SCHSTest28", SCHSTest28);
2340  UtRegisterTest("SCHSTest29", SCHSTest29);
2341 }
2342 #endif /* UNITTESTS */
2343 #endif /* BUILD_HYPERSCAN */
MpmTableElmt_::PrintThreadCtx
void(* PrintThreadCtx)(struct MpmThreadCtx_ *)
Definition: util-mpm.h:188
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:157
MpmThreadCtx_
Definition: util-mpm.h:48
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:155
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:211
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:143
MpmThreadCtx_::memory_cnt
uint32_t memory_cnt
Definition: util-mpm.h:51
SC_SHA256_LEN
#define SC_SHA256_LEN
Definition: util-file.h:104
util-hash.h
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
MPM_FEATURE_FLAG_OFFSET
#define MPM_FEATURE_FLAG_OFFSET
Definition: util-mpm.h:151
util-memcpy.h
MpmCtx_::memory_size
uint32_t memory_size
Definition: util-mpm.h:112
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2684
MpmTableElmt_::CacheStatsPrint
void(* CacheStatsPrint)(void *data)
Definition: util-mpm.h:181
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
HashTable_
Definition: util-hash.h:35
DE_QUIET
#define DE_QUIET
Definition: detect.h:329
MpmCtx_::maxlen
uint16_t maxlen
Definition: util-mpm.h:109
MpmTableElmt_::AddPattern
int(* AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:176
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:192
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:122
MpmCtx_::maxdepth
uint16_t maxdepth
Definition: util-mpm.h:103
MAX
#define MAX(x, y)
Definition: suricata-common.h:412
MpmTableElmt_::InitCtx
void(* InitCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:156
util-unittest.h
util-unittest-helper.h
HashTableFree
void HashTableFree(HashTable *ht)
Free a HashTable and all its contents.
Definition: util-hash.c:100
MpmConfig_::cache_dir_path
const char * cache_dir_path
Definition: util-mpm.h:92
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:187
util-debug.h
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectEngineThreadCtx_
Definition: detect.h:1245
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:120
MpmThreadCtx_::memory_size
uint32_t memory_size
Definition: util-mpm.h:52
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:258
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:182
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:3414
MpmTableElmt_::CacheStatsDeinit
void(* CacheStatsDeinit)(void *data)
Definition: util-mpm.h:182
HashTableRemove
int HashTableRemove(HashTable *ht, void *data, uint16_t datalen)
Remove an item from the hash table.
Definition: util-hash.c:166
DetectEngineCtx_::mpm_matcher
uint8_t mpm_matcher
Definition: detect.h:936
MPM_PATTERN_FLAG_OFFSET
#define MPM_PATTERN_FLAG_OFFSET
Definition: util-mpm.h:144
MPM_FEATURE_FLAG_DEPTH
#define MPM_FEATURE_FLAG_DEPTH
Definition: util-mpm.h:150
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:120
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3104
MpmCtx_::minlen
uint16_t minlen
Definition: util-mpm.h:108
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
SigIntId
#define SigIntId
Definition: detect-engine-state.h:38
Packet_
Definition: decode.h:501
detect-engine-build.h
MpmTableElmt_::CacheStatsInit
void *(* CacheStatsInit)(void)
Definition: util-mpm.h:180
detect-engine-alert.h
conf.h
MpmTableElmt_::CacheRuleset
int(* CacheRuleset)(MpmConfig *)
Definition: util-mpm.h:183
MpmTableElmt_::Search
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:186
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:88
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2207
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1331
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
MPM_PATTERN_FLAG_NOCASE
#define MPM_PATTERN_FLAG_NOCASE
Definition: util-mpm.h:140
ARRAY_SIZE
#define ARRAY_SIZE(arr)
Definition: suricata-common.h:562
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:106
util-path.h
util-mpm-hs-core.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3651
MpmConfig_::cache_stats
void * cache_stats
Definition: util-mpm.h:94
MpmTableElmt_::AddPatternNocase
int(* AddPatternNocase)(struct MpmCtx_ *, const uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:177
MPM_HS
@ MPM_HS
Definition: util-mpm.h:40
FatalError
#define FatalError(...)
Definition: util-debug.h:517
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:942
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:179
MpmTableElmt_::DestroyCtx
void(* DestroyCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:158
SCFree
#define SCFree(p)
Definition: util-mem.h:61
MpmConfig_
Definition: util-mpm.h:91
detect-parse.h
MpmCtx_::memory_cnt
uint32_t memory_cnt
Definition: util-mpm.h:111
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:2645
mpm_table
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.c:47
MpmTableElmt_::ConfigDeinit
void(* ConfigDeinit)(MpmConfig **)
Definition: util-mpm.h:162
suricata.h
MpmTableElmt_::ConfigCacheDirSet
void(* ConfigCacheDirSet)(MpmConfig *, const char *dir_path)
Definition: util-mpm.h:163
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:184
MpmTableElmt_::ConfigInit
MpmConfig *(* ConfigInit)(void)
Definition: util-mpm.h:161
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:935
MpmTableElmt_::DestroyThreadCtx
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:159
MpmCtx_
Definition: util-mpm.h:97
util-mpm-hs-cache.h
MPM_PATTERN_FLAG_DEPTH
#define MPM_PATTERN_FLAG_DEPTH
Definition: util-mpm.h:142
MpmCtx_::flags
uint8_t flags
Definition: util-mpm.h:101
MPMCTX_FLAGS_CACHE_TO_DISK
#define MPMCTX_FLAGS_CACHE_TO_DISK
Definition: util-mpm.h:89
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
MpmHSRegister
void MpmHSRegister(void)
MpmCtx_::ctx
void * ctx
Definition: util-mpm.h:98
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1427
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:49
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
MpmTableElmt_::RegisterUnittests
void(* RegisterUnittests)(void)
Definition: util-mpm.h:190
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