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