suricata
util-mpm-ac.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2014 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 Anoop Saldanha <anoopsaldanha@gmail.com>
22  *
23  * First iteration of aho-corasick MPM from -
24  *
25  * Efficient String Matching: An Aid to Bibliographic Search
26  * Alfred V. Aho and Margaret J. Corasick
27  *
28  * - Uses the delta table for calculating transitions, instead of having
29  * separate goto and failure transitions.
30  * - If we cross 2 ** 16 states, we use 4 bytes in the transition table
31  * to hold each state, otherwise we use 2 bytes.
32  * - This version of the MPM is heavy on memory, but it performs well.
33  * If you can fit the ruleset with this mpm on your box without hitting
34  * swap, this is the MPM to go for.
35  *
36  * \todo - Do a proper analyis of our existing MPMs and suggest a good one based
37  * on the pattern distribution and the expected traffic(say http).
38  * - Tried out loop unrolling without any perf increase. Need to dig deeper.
39  * - Irrespective of whether we cross 2 ** 16 states or not,shift to using
40  * uint32_t for state type, so that we can integrate it's status as a
41  * final state or not in the topmost byte. We are already doing it if
42  * state_count is > 2 ** 16.
43  * - Test case-senstive patterns if they have any ascii chars. If they
44  * don't treat them as nocase.
45  * - Carry out other optimizations we are working on. hashes, compression.
46  */
47 
48 #include "suricata-common.h"
49 #include "suricata.h"
50 
51 #include "detect.h"
52 #include "detect-parse.h"
53 #include "detect-engine.h"
54 
55 #include "conf.h"
56 #include "util-debug.h"
57 #include "util-unittest.h"
58 #include "util-unittest-helper.h"
59 #include "util-memcmp.h"
60 #include "util-mpm-ac.h"
61 #include "util-memcpy.h"
62 
63 void SCACInitCtx(MpmCtx *);
65 void SCACDestroyCtx(MpmCtx *);
67 int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
68  uint32_t, SigIntId, uint8_t);
69 int SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t,
70  uint32_t, SigIntId, uint8_t);
71 int SCACPreparePatterns(MpmCtx *mpm_ctx);
72 uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
73  PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen);
74 void SCACPrintInfo(MpmCtx *mpm_ctx);
75 void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx);
76 void SCACRegisterTests(void);
77 
78 /* a placeholder to denote a failure transition in the goto table */
79 #define SC_AC_FAIL (-1)
80 
81 #define STATE_QUEUE_CONTAINER_SIZE 65536
82 
83 #define AC_CASE_MASK 0x80000000
84 #define AC_PID_MASK 0x7FFFFFFF
85 #define AC_CASE_BIT 31
86 
87 static int construct_both_16_and_32_state_tables = 0;
88 
89 /**
90  * \brief Helper structure used by AC during state table creation
91  */
92 typedef struct StateQueue_ {
94  int top;
95  int bot;
96 } StateQueue;
97 
98 /**
99  * \internal
100  * \brief Initialize the AC context with user specified conf parameters. We
101  * aren't retrieving anything for AC conf now, but we will certainly
102  * need it, when we customize AC.
103  */
104 static void SCACGetConfig(void)
105 {
106  //ConfNode *ac_conf;
107  //const char *hash_val = NULL;
108 
109  //ConfNode *pm = ConfGetNode("pattern-matcher");
110 
111  return;
112 }
113 
114 /**
115  * \internal
116  * \brief Check if size_t multiplication would overflow and perform operation
117  * if safe. In case of an overflow we exit().
118  *
119  * \param a First size_t value to multiplicate.
120  * \param b Second size_t value to multiplicate.
121  *
122  * \retval The product of a and b, guaranteed to not overflow.
123  */
124 static inline size_t SCACCheckSafeSizetMult(size_t a, size_t b)
125 {
126  /* check for safety of multiplication operation */
127  if (b > 0 && a > SIZE_MAX / b) {
128  SCLogError(SC_ERR_MEM_ALLOC, "%"PRIuMAX" * %"PRIuMAX" > %"
129  PRIuMAX" would overflow size_t calculating buffer size",
130  (uintmax_t) a, (uintmax_t) b, (uintmax_t) SIZE_MAX);
131  exit(EXIT_FAILURE);
132  }
133  return a * b;
134 }
135 
136 /**
137  * \internal
138  * \brief Initialize a new state in the goto and output tables.
139  *
140  * \param mpm_ctx Pointer to the mpm context.
141  *
142  * \retval The state id, of the newly created state.
143  */
144 static inline int SCACReallocState(SCACCtx *ctx, uint32_t cnt)
145 {
146  void *ptmp = NULL;
147  size_t size = 0;
148 
149  /* reallocate space in the goto table to include a new state */
150  size = SCACCheckSafeSizetMult((size_t) cnt, (size_t) ctx->single_state_size);
151  if (size > 0)
152  ptmp = SCRealloc(ctx->goto_table, size);
153  if (ptmp == NULL) {
154  SCFree(ctx->goto_table);
155  ctx->goto_table = NULL;
156  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
157  exit(EXIT_FAILURE);
158  }
159  ctx->goto_table = ptmp;
160 
161  /* reallocate space in the output table for the new state */
162  size_t oldsize = SCACCheckSafeSizetMult((size_t) ctx->state_count,
163  sizeof(SCACOutputTable));
164  size = SCACCheckSafeSizetMult((size_t) cnt, sizeof(SCACOutputTable));
165  SCLogDebug("oldsize %"PRIuMAX" size %"PRIuMAX" cnt %d ctx->state_count %u",
166  (uintmax_t) oldsize, (uintmax_t) size, cnt, ctx->state_count);
167 
168  ptmp = NULL;
169  if (size > 0)
170  ptmp = SCRealloc(ctx->output_table, size);
171  if (ptmp == NULL) {
172  SCFree(ctx->output_table);
173  ctx->output_table = NULL;
174  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
175  exit(EXIT_FAILURE);
176  }
177  ctx->output_table = ptmp;
178 
179  memset(((uint8_t *)ctx->output_table + oldsize), 0, (size - oldsize));
180 
181  /* \todo using it temporarily now during dev, since I have restricted
182  * state var in SCACCtx->state_table to uint16_t. */
183  //if (ctx->state_count > 65536) {
184  // printf("state count exceeded\n");
185  // exit(EXIT_FAILURE);
186  //}
187 
188  return 0;//ctx->state_count++;
189 }
190 
191 /** \internal
192  * \brief Shrink state after setup is done
193  *
194  * Shrinks only the output table, goto table is freed after calling this
195  */
196 static void SCACShrinkState(SCACCtx *ctx)
197 {
198  /* reallocate space in the output table for the new state */
199 #ifdef DEBUG
200  int oldsize = ctx->allocated_state_count * sizeof(SCACOutputTable);
201 #endif
202  int newsize = ctx->state_count * sizeof(SCACOutputTable);
203 
204  SCLogDebug("oldsize %d newsize %d ctx->allocated_state_count %u "
205  "ctx->state_count %u: shrink by %d bytes", oldsize,
206  newsize, ctx->allocated_state_count, ctx->state_count,
207  oldsize - newsize);
208 
209  void *ptmp = SCRealloc(ctx->output_table, newsize);
210  if (ptmp == NULL) {
211  SCFree(ctx->output_table);
212  ctx->output_table = NULL;
213  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
214  exit(EXIT_FAILURE);
215  }
216  ctx->output_table = ptmp;
217 }
218 
219 static inline int SCACInitNewState(MpmCtx *mpm_ctx)
220 {
221  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;;
222 
223  /* Exponentially increase the allocated space when needed. */
224  if (ctx->allocated_state_count < ctx->state_count + 1) {
225  if (ctx->allocated_state_count == 0)
226  ctx->allocated_state_count = 256;
227  else
228  ctx->allocated_state_count *= 2;
229 
230  SCACReallocState(ctx, ctx->allocated_state_count);
231 
232  }
233 #if 0
234  if (ctx->allocated_state_count > 260) {
235  SCACOutputTable *output_state = &ctx->output_table[260];
236  SCLogInfo("output_state %p %p %u", output_state, output_state->pids, output_state->no_of_entries);
237  }
238 #endif
239  int ascii_code = 0;
240  /* set all transitions for the newly assigned state as FAIL transitions */
241  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
242  ctx->goto_table[ctx->state_count][ascii_code] = SC_AC_FAIL;
243  }
244 
245  return ctx->state_count++;
246 }
247 
248 /**
249  * \internal
250  * \brief Adds a pid to the output table for a state.
251  *
252  * \param state The state to whose output table we should add the pid.
253  * \param pid The pattern id to add.
254  * \param mpm_ctx Pointer to the mpm context.
255  */
256 static void SCACSetOutputState(int32_t state, uint32_t pid, MpmCtx *mpm_ctx)
257 {
258  void *ptmp;
259  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
260  SCACOutputTable *output_state = &ctx->output_table[state];
261  uint32_t i = 0;
262 
263  for (i = 0; i < output_state->no_of_entries; i++) {
264  if (output_state->pids[i] == pid)
265  return;
266  }
267 
268  output_state->no_of_entries++;
269  ptmp = SCRealloc(output_state->pids,
270  output_state->no_of_entries * sizeof(uint32_t));
271  if (ptmp == NULL) {
272  SCFree(output_state->pids);
273  output_state->pids = NULL;
274  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
275  exit(EXIT_FAILURE);
276  }
277  output_state->pids = ptmp;
278 
279  output_state->pids[output_state->no_of_entries - 1] = pid;
280 
281  return;
282 }
283 
284 /**
285  * \brief Helper function used by SCACCreateGotoTable. Adds a pattern to the
286  * goto table.
287  *
288  * \param pattern Pointer to the pattern.
289  * \param pattern_len Pattern length.
290  * \param pid The pattern id, that corresponds to this pattern. We
291  * need it to updated the output table for this pattern.
292  * \param mpm_ctx Pointer to the mpm context.
293  */
294 static inline void SCACEnter(uint8_t *pattern, uint16_t pattern_len, uint32_t pid,
295  MpmCtx *mpm_ctx)
296 {
297  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
298  int32_t state = 0;
299  int32_t newstate = 0;
300  int i = 0;
301  int p = 0;
302 
303  /* walk down the trie till we have a match for the pattern prefix */
304  state = 0;
305  for (i = 0; i < pattern_len; i++) {
306  if (ctx->goto_table[state][pattern[i]] != SC_AC_FAIL) {
307  state = ctx->goto_table[state][pattern[i]];
308  } else {
309  break;
310  }
311  }
312 
313  /* add the non-matching pattern suffix to the trie, from the last state
314  * we left off */
315  for (p = i; p < pattern_len; p++) {
316  newstate = SCACInitNewState(mpm_ctx);
317  ctx->goto_table[state][pattern[p]] = newstate;
318  state = newstate;
319  }
320 
321  /* add this pattern id, to the output table of the last state, where the
322  * pattern ends in the trie */
323  SCACSetOutputState(state, pid, mpm_ctx);
324 
325  return;
326 }
327 
328 /**
329  * \internal
330  * \brief Create the goto table.
331  *
332  * \param mpm_ctx Pointer to the mpm context.
333  */
334 static inline void SCACCreateGotoTable(MpmCtx *mpm_ctx)
335 {
336  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
337  uint32_t i = 0;
338 
339  /* add each pattern to create the goto table */
340  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
341  SCACEnter(ctx->parray[i]->ci, ctx->parray[i]->len,
342  ctx->parray[i]->id, mpm_ctx);
343  }
344 
345  int ascii_code = 0;
346  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
347  if (ctx->goto_table[0][ascii_code] == SC_AC_FAIL) {
348  ctx->goto_table[0][ascii_code] = 0;
349  }
350  }
351 
352  return;
353 }
354 
355 static inline void SCACDetermineLevel1Gap(MpmCtx *mpm_ctx)
356 {
357  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
358  uint32_t u = 0;
359 
360  int map[256];
361  memset(map, 0, sizeof(map));
362 
363  for (u = 0; u < mpm_ctx->pattern_cnt; u++)
364  map[ctx->parray[u]->ci[0]] = 1;
365 
366  for (u = 0; u < 256; u++) {
367  if (map[u] == 0)
368  continue;
369  int32_t newstate = SCACInitNewState(mpm_ctx);
370  ctx->goto_table[0][u] = newstate;
371  }
372 
373  return;
374 }
375 
376 static inline int SCACStateQueueIsEmpty(StateQueue *q)
377 {
378  if (q->top == q->bot)
379  return 1;
380  else
381  return 0;
382 }
383 
384 static inline void SCACEnqueue(StateQueue *q, int32_t state)
385 {
386  int i = 0;
387 
388  /*if we already have this */
389  for (i = q->bot; i < q->top; i++) {
390  if (q->store[i] == state)
391  return;
392  }
393 
394  q->store[q->top++] = state;
395 
397  q->top = 0;
398 
399  if (q->top == q->bot) {
400  SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. "
401  "Fatal Error. Exiting. Please file a bug report on this");
402  exit(EXIT_FAILURE);
403  }
404 
405  return;
406 }
407 
408 static inline int32_t SCACDequeue(StateQueue *q)
409 {
411  q->bot = 0;
412 
413  if (q->bot == q->top) {
414  SCLogCritical(SC_ERR_AHO_CORASICK, "StateQueue behaving weirdly. "
415  "Fatal Error. Exiting. Please file a bug report on this");
416  exit(EXIT_FAILURE);
417  }
418 
419  return q->store[q->bot++];
420 }
421 
422 /*
423 #define SCACStateQueueIsEmpty(q) (((q)->top == (q)->bot) ? 1 : 0)
424 
425 #define SCACEnqueue(q, state) do { \
426  int i = 0; \
427  \
428  for (i = (q)->bot; i < (q)->top; i++) { \
429  if ((q)->store[i] == state) \
430  return; \
431  } \
432  \
433  (q)->store[(q)->top++] = state; \
434  \
435  if ((q)->top == STATE_QUEUE_CONTAINER_SIZE) \
436  (q)->top = 0; \
437  \
438  if ((q)->top == (q)->bot) { \
439  SCLogCritical(SC_ERR_AHO_CORASICK, "Just ran out of space in the queue. " \
440  "Fatal Error. Exiting. Please file a bug report on this"); \
441  exit(EXIT_FAILURE); \
442  } \
443  } while (0)
444 
445 #define SCACDequeue(q) ( (((q)->bot == STATE_QUEUE_CONTAINER_SIZE)? ((q)->bot = 0): 0), \
446  (((q)->bot == (q)->top) ? \
447  (printf("StateQueue behaving " \
448  "weirdly. Fatal Error. Exiting. Please " \
449  "file a bug report on this"), \
450  exit(EXIT_FAILURE)) : 0), \
451  (q)->store[(q)->bot++]) \
452 */
453 
454 /**
455  * \internal
456  * \brief Club the output data from 2 states and store it in the 1st state.
457  * dst_state_data = {dst_state_data} UNION {src_state_data}
458  *
459  * \param dst_state First state(also the destination) for the union operation.
460  * \param src_state Second state for the union operation.
461  * \param mpm_ctx Pointer to the mpm context.
462  */
463 static inline void SCACClubOutputStates(int32_t dst_state, int32_t src_state,
464  MpmCtx *mpm_ctx)
465 {
466  void *ptmp;
467  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
468  uint32_t i = 0;
469  uint32_t j = 0;
470 
471  SCACOutputTable *output_dst_state = &ctx->output_table[dst_state];
472  SCACOutputTable *output_src_state = &ctx->output_table[src_state];
473 
474  for (i = 0; i < output_src_state->no_of_entries; i++) {
475  for (j = 0; j < output_dst_state->no_of_entries; j++) {
476  if (output_src_state->pids[i] == output_dst_state->pids[j]) {
477  break;
478  }
479  }
480  if (j == output_dst_state->no_of_entries) {
481  output_dst_state->no_of_entries++;
482 
483  ptmp = SCRealloc(output_dst_state->pids,
484  (output_dst_state->no_of_entries * sizeof(uint32_t)));
485  if (ptmp == NULL) {
486  SCFree(output_dst_state->pids);
487  output_dst_state->pids = NULL;
488  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
489  exit(EXIT_FAILURE);
490  }
491  output_dst_state->pids = ptmp;
492 
493  output_dst_state->pids[output_dst_state->no_of_entries - 1] =
494  output_src_state->pids[i];
495  }
496  }
497 
498  return;
499 }
500 
501 /**
502  * \internal
503  * \brief Create the failure table.
504  *
505  * \param mpm_ctx Pointer to the mpm context.
506  */
507 static inline void SCACCreateFailureTable(MpmCtx *mpm_ctx)
508 {
509  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
510  int ascii_code = 0;
511  int32_t state = 0;
512  int32_t r_state = 0;
513 
514  StateQueue q;
515  memset(&q, 0, sizeof(StateQueue));
516 
517  /* allot space for the failure table. A failure entry in the table for
518  * every state(SCACCtx->state_count) */
519  ctx->failure_table = SCMalloc(ctx->state_count * sizeof(int32_t));
520  if (ctx->failure_table == NULL) {
521  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
522  exit(EXIT_FAILURE);
523  }
524  memset(ctx->failure_table, 0, ctx->state_count * sizeof(int32_t));
525 
526  /* add the failure transitions for the 0th state, and add every non-fail
527  * transition from the 0th state to the queue for further processing
528  * of failure states */
529  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
530  int32_t temp_state = ctx->goto_table[0][ascii_code];
531  if (temp_state != 0) {
532  SCACEnqueue(&q, temp_state);
533  ctx->failure_table[temp_state] = 0;
534  }
535  }
536 
537  while (!SCACStateQueueIsEmpty(&q)) {
538  /* pick up every state from the queue and add failure transitions */
539  r_state = SCACDequeue(&q);
540  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
541  int32_t temp_state = ctx->goto_table[r_state][ascii_code];
542  if (temp_state == SC_AC_FAIL)
543  continue;
544  SCACEnqueue(&q, temp_state);
545  state = ctx->failure_table[r_state];
546 
547  while(ctx->goto_table[state][ascii_code] == SC_AC_FAIL)
548  state = ctx->failure_table[state];
549  ctx->failure_table[temp_state] = ctx->goto_table[state][ascii_code];
550  SCACClubOutputStates(temp_state, ctx->failure_table[temp_state],
551  mpm_ctx);
552  }
553  }
554 
555  return;
556 }
557 
558 /**
559  * \internal
560  * \brief Create the delta table.
561  *
562  * \param mpm_ctx Pointer to the mpm context.
563  */
564 static inline void SCACCreateDeltaTable(MpmCtx *mpm_ctx)
565 {
566  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
567  int ascii_code = 0;
568  int32_t r_state = 0;
569 
570  if ((ctx->state_count < 32767) || construct_both_16_and_32_state_tables) {
571  ctx->state_table_u16 = SCMalloc(ctx->state_count *
572  sizeof(SC_AC_STATE_TYPE_U16) * 256);
573  if (ctx->state_table_u16 == NULL) {
574  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
575  exit(EXIT_FAILURE);
576  }
577  memset(ctx->state_table_u16, 0,
578  ctx->state_count * sizeof(SC_AC_STATE_TYPE_U16) * 256);
579 
580  mpm_ctx->memory_cnt++;
581  mpm_ctx->memory_size += (ctx->state_count *
582  sizeof(SC_AC_STATE_TYPE_U16) * 256);
583 
584  StateQueue q;
585  memset(&q, 0, sizeof(StateQueue));
586 
587  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
588  SC_AC_STATE_TYPE_U16 temp_state = ctx->goto_table[0][ascii_code];
589  ctx->state_table_u16[0][ascii_code] = temp_state;
590  if (temp_state != 0)
591  SCACEnqueue(&q, temp_state);
592  }
593 
594  while (!SCACStateQueueIsEmpty(&q)) {
595  r_state = SCACDequeue(&q);
596 
597  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
598  int32_t temp_state = ctx->goto_table[r_state][ascii_code];
599  if (temp_state != SC_AC_FAIL) {
600  SCACEnqueue(&q, temp_state);
601  ctx->state_table_u16[r_state][ascii_code] = temp_state;
602  } else {
603  ctx->state_table_u16[r_state][ascii_code] =
604  ctx->state_table_u16[ctx->failure_table[r_state]][ascii_code];
605  }
606  }
607  }
608  }
609 
610  if (!(ctx->state_count < 32767) || construct_both_16_and_32_state_tables) {
611  /* create space for the state table. We could have used the existing goto
612  * table, but since we have it set to hold 32 bit state values, we will create
613  * a new state table here of type SC_AC_STATE_TYPE(current set to uint16_t) */
614  ctx->state_table_u32 = SCMalloc(ctx->state_count *
615  sizeof(SC_AC_STATE_TYPE_U32) * 256);
616  if (ctx->state_table_u32 == NULL) {
617  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
618  exit(EXIT_FAILURE);
619  }
620  memset(ctx->state_table_u32, 0,
621  ctx->state_count * sizeof(SC_AC_STATE_TYPE_U32) * 256);
622 
623  mpm_ctx->memory_cnt++;
624  mpm_ctx->memory_size += (ctx->state_count *
625  sizeof(SC_AC_STATE_TYPE_U32) * 256);
626 
627  StateQueue q;
628  memset(&q, 0, sizeof(StateQueue));
629 
630  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
631  SC_AC_STATE_TYPE_U32 temp_state = ctx->goto_table[0][ascii_code];
632  ctx->state_table_u32[0][ascii_code] = temp_state;
633  if (temp_state != 0)
634  SCACEnqueue(&q, temp_state);
635  }
636 
637  while (!SCACStateQueueIsEmpty(&q)) {
638  r_state = SCACDequeue(&q);
639 
640  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
641  int32_t temp_state = ctx->goto_table[r_state][ascii_code];
642  if (temp_state != SC_AC_FAIL) {
643  SCACEnqueue(&q, temp_state);
644  ctx->state_table_u32[r_state][ascii_code] = temp_state;
645  } else {
646  ctx->state_table_u32[r_state][ascii_code] =
647  ctx->state_table_u32[ctx->failure_table[r_state]][ascii_code];
648  }
649  }
650  }
651  }
652 
653  return;
654 }
655 
656 static inline void SCACClubOutputStatePresenceWithDeltaTable(MpmCtx *mpm_ctx)
657 {
658  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
659  int ascii_code = 0;
660  uint32_t state = 0;
661  uint32_t temp_state = 0;
662 
663  if ((ctx->state_count < 32767) || construct_both_16_and_32_state_tables) {
664  for (state = 0; state < ctx->state_count; state++) {
665  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
666  temp_state = ctx->state_table_u16[state & 0x7FFF][ascii_code];
667  if (ctx->output_table[temp_state & 0x7FFF].no_of_entries != 0)
668  ctx->state_table_u16[state & 0x7FFF][ascii_code] |= (1 << 15);
669  }
670  }
671  }
672 
673  if (!(ctx->state_count < 32767) || construct_both_16_and_32_state_tables) {
674  for (state = 0; state < ctx->state_count; state++) {
675  for (ascii_code = 0; ascii_code < 256; ascii_code++) {
676  temp_state = ctx->state_table_u32[state & 0x00FFFFFF][ascii_code];
677  if (ctx->output_table[temp_state & 0x00FFFFFF].no_of_entries != 0)
678  ctx->state_table_u32[state & 0x00FFFFFF][ascii_code] |= (1 << 24);
679  }
680  }
681  }
682 
683  return;
684 }
685 
686 static inline void SCACInsertCaseSensitiveEntriesForPatterns(MpmCtx *mpm_ctx)
687 {
688  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
689  uint32_t state = 0;
690  uint32_t k = 0;
691 
692  for (state = 0; state < ctx->state_count; state++) {
693  if (ctx->output_table[state].no_of_entries == 0)
694  continue;
695 
696  for (k = 0; k < ctx->output_table[state].no_of_entries; k++) {
697  if (ctx->pid_pat_list[ctx->output_table[state].pids[k]].cs != NULL) {
698  ctx->output_table[state].pids[k] &= AC_PID_MASK;
699  ctx->output_table[state].pids[k] |= ((uint32_t)1 << AC_CASE_BIT);
700  }
701  }
702  }
703 
704  return;
705 }
706 
707 #if 0
708 static void SCACPrintDeltaTable(MpmCtx *mpm_ctx)
709 {
710  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
711  int i = 0, j = 0;
712 
713  printf("##############Delta Table##############\n");
714  for (i = 0; i < ctx->state_count; i++) {
715  printf("%d: \n", i);
716  for (j = 0; j < 256; j++) {
717  if (SCACGetDelta(i, j, mpm_ctx) != 0) {
718  printf(" %c -> %d\n", j, SCACGetDelta(i, j, mpm_ctx));
719  }
720  }
721  }
722 
723  return;
724 }
725 #endif
726 
727 /**
728  * \brief Process the patterns and prepare the state table.
729  *
730  * \param mpm_ctx Pointer to the mpm context.
731  */
732 static void SCACPrepareStateTable(MpmCtx *mpm_ctx)
733 {
734  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
735 
736  /* create the 0th state in the goto table and output_table */
737  SCACInitNewState(mpm_ctx);
738 
739  SCACDetermineLevel1Gap(mpm_ctx);
740 
741  /* create the goto table */
742  SCACCreateGotoTable(mpm_ctx);
743  /* create the failure table */
744  SCACCreateFailureTable(mpm_ctx);
745  /* create the final state(delta) table */
746  SCACCreateDeltaTable(mpm_ctx);
747  /* club the output state presence with delta transition entries */
748  SCACClubOutputStatePresenceWithDeltaTable(mpm_ctx);
749 
750  /* club nocase entries */
751  SCACInsertCaseSensitiveEntriesForPatterns(mpm_ctx);
752 
753  /* shrink the memory */
754  SCACShrinkState(ctx);
755 
756 #if 0
757  SCACPrintDeltaTable(mpm_ctx);
758 #endif
759 
760  /* we don't need these anymore */
761  SCFree(ctx->goto_table);
762  ctx->goto_table = NULL;
763  SCFree(ctx->failure_table);
764  ctx->failure_table = NULL;
765 
766  return;
767 }
768 
769 /**
770  * \brief Process the patterns added to the mpm, and create the internal tables.
771  *
772  * \param mpm_ctx Pointer to the mpm context.
773  */
775 {
776  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
777 
778  if (mpm_ctx->pattern_cnt == 0 || mpm_ctx->init_hash == NULL) {
779  SCLogDebug("no patterns supplied to this mpm_ctx");
780  return 0;
781  }
782 
783  /* alloc the pattern array */
784  ctx->parray = (MpmPattern **)SCMalloc(mpm_ctx->pattern_cnt *
785  sizeof(MpmPattern *));
786  if (ctx->parray == NULL)
787  goto error;
788  memset(ctx->parray, 0, mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
789  mpm_ctx->memory_cnt++;
790  mpm_ctx->memory_size += (mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
791 
792  /* populate it with the patterns in the hash */
793  uint32_t i = 0, p = 0;
794  for (i = 0; i < MPM_INIT_HASH_SIZE; i++) {
795  MpmPattern *node = mpm_ctx->init_hash[i], *nnode = NULL;
796  while(node != NULL) {
797  nnode = node->next;
798  node->next = NULL;
799  ctx->parray[p++] = node;
800  node = nnode;
801  }
802  }
803 
804  /* we no longer need the hash, so free it's memory */
805  SCFree(mpm_ctx->init_hash);
806  mpm_ctx->init_hash = NULL;
807 
808  /* the memory consumed by a single state in our goto table */
809  ctx->single_state_size = sizeof(int32_t) * 256;
810 
811  /* handle no case patterns */
812  ctx->pid_pat_list = SCMalloc((mpm_ctx->max_pat_id + 1)* sizeof(SCACPatternList));
813  if (ctx->pid_pat_list == NULL) {
814  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
815  exit(EXIT_FAILURE);
816  }
817  memset(ctx->pid_pat_list, 0, (mpm_ctx->max_pat_id + 1) * sizeof(SCACPatternList));
818 
819  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
820  if (!(ctx->parray[i]->flags & MPM_PATTERN_FLAG_NOCASE)) {
821  ctx->pid_pat_list[ctx->parray[i]->id].cs = SCMalloc(ctx->parray[i]->len);
822  if (ctx->pid_pat_list[ctx->parray[i]->id].cs == NULL) {
823  SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
824  exit(EXIT_FAILURE);
825  }
826  memcpy(ctx->pid_pat_list[ctx->parray[i]->id].cs,
827  ctx->parray[i]->original_pat, ctx->parray[i]->len);
828  ctx->pid_pat_list[ctx->parray[i]->id].patlen = ctx->parray[i]->len;
829  }
830  ctx->pid_pat_list[ctx->parray[i]->id].offset = ctx->parray[i]->offset;
831  ctx->pid_pat_list[ctx->parray[i]->id].depth = ctx->parray[i]->depth;
832 
833  /* ACPatternList now owns this memory */
834  //SCLogInfo("ctx->parray[i]->sids_size %u", ctx->parray[i]->sids_size);
835  ctx->pid_pat_list[ctx->parray[i]->id].sids_size = ctx->parray[i]->sids_size;
836  ctx->pid_pat_list[ctx->parray[i]->id].sids = ctx->parray[i]->sids;
837 
838  ctx->parray[i]->sids_size = 0;
839  ctx->parray[i]->sids = NULL;
840  }
841 
842  /* prepare the state table required by AC */
843  SCACPrepareStateTable(mpm_ctx);
844 
845  /* free all the stored patterns. Should save us a good 100-200 mbs */
846  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
847  if (ctx->parray[i] != NULL) {
848  MpmFreePattern(mpm_ctx, ctx->parray[i]);
849  }
850  }
851  SCFree(ctx->parray);
852  ctx->parray = NULL;
853  mpm_ctx->memory_cnt--;
854  mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
855 
856  ctx->pattern_id_bitarray_size = (mpm_ctx->max_pat_id / 8) + 1;
857  SCLogDebug("ctx->pattern_id_bitarray_size %u", ctx->pattern_id_bitarray_size);
858 
859  return 0;
860 
861 error:
862  return -1;
863 }
864 
865 /**
866  * \brief Init the mpm thread context.
867  *
868  * \param mpm_ctx Pointer to the mpm context.
869  * \param mpm_thread_ctx Pointer to the mpm thread context.
870  * \param matchsize We don't need this.
871  */
872 void SCACInitThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
873 {
874  memset(mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
875 
876  mpm_thread_ctx->ctx = SCMalloc(sizeof(SCACThreadCtx));
877  if (mpm_thread_ctx->ctx == NULL) {
878  exit(EXIT_FAILURE);
879  }
880  memset(mpm_thread_ctx->ctx, 0, sizeof(SCACThreadCtx));
881  mpm_thread_ctx->memory_cnt++;
882  mpm_thread_ctx->memory_size += sizeof(SCACThreadCtx);
883 
884  return;
885 }
886 
887 /**
888  * \brief Initialize the AC context.
889  *
890  * \param mpm_ctx Mpm context.
891  */
892 void SCACInitCtx(MpmCtx *mpm_ctx)
893 {
894  if (mpm_ctx->ctx != NULL)
895  return;
896 
897  mpm_ctx->ctx = SCMalloc(sizeof(SCACCtx));
898  if (mpm_ctx->ctx == NULL) {
899  exit(EXIT_FAILURE);
900  }
901  memset(mpm_ctx->ctx, 0, sizeof(SCACCtx));
902 
903  mpm_ctx->memory_cnt++;
904  mpm_ctx->memory_size += sizeof(SCACCtx);
905 
906  /* initialize the hash we use to speed up pattern insertions */
907  mpm_ctx->init_hash = SCMalloc(sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE);
908  if (mpm_ctx->init_hash == NULL) {
909  exit(EXIT_FAILURE);
910  }
911  memset(mpm_ctx->init_hash, 0, sizeof(MpmPattern *) * MPM_INIT_HASH_SIZE);
912 
913  /* get conf values for AC from our yaml file. We have no conf values for
914  * now. We will certainly need this, as we develop the algo */
915  SCACGetConfig();
916 
917  SCReturn;
918 }
919 
920 /**
921  * \brief Destroy the mpm thread context.
922  *
923  * \param mpm_ctx Pointer to the mpm context.
924  * \param mpm_thread_ctx Pointer to the mpm thread context.
925  */
926 void SCACDestroyThreadCtx(MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx)
927 {
928  SCACPrintSearchStats(mpm_thread_ctx);
929 
930  if (mpm_thread_ctx->ctx != NULL) {
931  SCFree(mpm_thread_ctx->ctx);
932  mpm_thread_ctx->ctx = NULL;
933  mpm_thread_ctx->memory_cnt--;
934  mpm_thread_ctx->memory_size -= sizeof(SCACThreadCtx);
935  }
936 
937  return;
938 }
939 
940 /**
941  * \brief Destroy the mpm context.
942  *
943  * \param mpm_ctx Pointer to the mpm context.
944  */
945 void SCACDestroyCtx(MpmCtx *mpm_ctx)
946 {
947  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
948  if (ctx == NULL)
949  return;
950 
951  if (mpm_ctx->init_hash != NULL) {
952  SCFree(mpm_ctx->init_hash);
953  mpm_ctx->init_hash = NULL;
954  mpm_ctx->memory_cnt--;
955  mpm_ctx->memory_size -= (MPM_INIT_HASH_SIZE * sizeof(MpmPattern *));
956  }
957 
958  if (ctx->parray != NULL) {
959  uint32_t i;
960  for (i = 0; i < mpm_ctx->pattern_cnt; i++) {
961  if (ctx->parray[i] != NULL) {
962  MpmFreePattern(mpm_ctx, ctx->parray[i]);
963  }
964  }
965 
966  SCFree(ctx->parray);
967  ctx->parray = NULL;
968  mpm_ctx->memory_cnt--;
969  mpm_ctx->memory_size -= (mpm_ctx->pattern_cnt * sizeof(MpmPattern *));
970  }
971 
972  if (ctx->state_table_u16 != NULL) {
973  SCFree(ctx->state_table_u16);
974  ctx->state_table_u16 = NULL;
975 
976  mpm_ctx->memory_cnt++;
977  mpm_ctx->memory_size -= (ctx->state_count *
978  sizeof(SC_AC_STATE_TYPE_U16) * 256);
979  }
980  if (ctx->state_table_u32 != NULL) {
981  SCFree(ctx->state_table_u32);
982  ctx->state_table_u32 = NULL;
983 
984  mpm_ctx->memory_cnt++;
985  mpm_ctx->memory_size -= (ctx->state_count *
986  sizeof(SC_AC_STATE_TYPE_U32) * 256);
987  }
988 
989  if (ctx->output_table != NULL) {
990  uint32_t state_count;
991  for (state_count = 0; state_count < ctx->state_count; state_count++) {
992  if (ctx->output_table[state_count].pids != NULL) {
993  SCFree(ctx->output_table[state_count].pids);
994  }
995  }
996  SCFree(ctx->output_table);
997  }
998 
999  if (ctx->pid_pat_list != NULL) {
1000  uint32_t i;
1001  for (i = 0; i < (mpm_ctx->max_pat_id + 1); i++) {
1002  if (ctx->pid_pat_list[i].cs != NULL)
1003  SCFree(ctx->pid_pat_list[i].cs);
1004  if (ctx->pid_pat_list[i].sids != NULL)
1005  SCFree(ctx->pid_pat_list[i].sids);
1006  }
1007  SCFree(ctx->pid_pat_list);
1008  }
1009 
1010  SCFree(mpm_ctx->ctx);
1011  mpm_ctx->memory_cnt--;
1012  mpm_ctx->memory_size -= sizeof(SCACCtx);
1013 
1014  return;
1015 }
1016 
1017 /**
1018  * \brief The aho corasick search function.
1019  *
1020  * \param mpm_ctx Pointer to the mpm context.
1021  * \param mpm_thread_ctx Pointer to the mpm thread context.
1022  * \param pmq Pointer to the Pattern Matcher Queue to hold
1023  * search matches.
1024  * \param buf Buffer to be searched.
1025  * \param buflen Buffer length.
1026  *
1027  * \retval matches Match count.
1028  */
1029 uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx,
1030  PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen)
1031 {
1032  const SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
1033  uint32_t i = 0;
1034  int matches = 0;
1035 
1036  /* \todo tried loop unrolling with register var, with no perf increase. Need
1037  * to dig deeper */
1038  /* \todo Change it for stateful MPM. Supply the state using mpm_thread_ctx */
1039  const SCACPatternList *pid_pat_list = ctx->pid_pat_list;
1040 
1041  uint8_t bitarray[ctx->pattern_id_bitarray_size];
1042  memset(bitarray, 0, ctx->pattern_id_bitarray_size);
1043 
1044  if (ctx->state_count < 32767) {
1045  register SC_AC_STATE_TYPE_U16 state = 0;
1046  SC_AC_STATE_TYPE_U16 (*state_table_u16)[256] = ctx->state_table_u16;
1047  for (i = 0; i < buflen; i++) {
1048  state = state_table_u16[state & 0x7FFF][u8_tolower(buf[i])];
1049  if (state & 0x8000) {
1050  uint32_t no_of_entries = ctx->output_table[state & 0x7FFF].no_of_entries;
1051  uint32_t *pids = ctx->output_table[state & 0x7FFF].pids;
1052  uint32_t k;
1053  for (k = 0; k < no_of_entries; k++) {
1054  if (pids[k] & AC_CASE_MASK) {
1055  uint32_t lower_pid = pids[k] & AC_PID_MASK;
1056  const SCACPatternList *pat = &pid_pat_list[lower_pid];
1057  const int offset = i - pat->patlen + 1;
1058 
1059  if (offset < (int)pat->offset || (pat->depth && i > pat->depth))
1060  continue;
1061 
1062  if (SCMemcmp(pat->cs, buf + offset, pat->patlen) != 0)
1063  {
1064  /* inside loop */
1065  continue;
1066  }
1067  if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) {
1068  ;
1069  } else {
1070  bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8));
1071  PrefilterAddSids(pmq, pat->sids, pat->sids_size);
1072  }
1073  matches++;
1074  } else {
1075  const SCACPatternList *pat = &pid_pat_list[pids[k]];
1076  const int offset = i - pat->patlen + 1;
1077 
1078  if (offset < (int)pat->offset || (pat->depth && i > pat->depth))
1079  continue;
1080 
1081  if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) {
1082  ;
1083  } else {
1084  bitarray[pids[k] / 8] |= (1 << (pids[k] % 8));
1085  PrefilterAddSids(pmq, pat->sids, pat->sids_size);
1086  }
1087  matches++;
1088  }
1089  //loop1:
1090  //;
1091  }
1092  }
1093  } /* for (i = 0; i < buflen; i++) */
1094 
1095  } else {
1096  register SC_AC_STATE_TYPE_U32 state = 0;
1097  SC_AC_STATE_TYPE_U32 (*state_table_u32)[256] = ctx->state_table_u32;
1098  for (i = 0; i < buflen; i++) {
1099  state = state_table_u32[state & 0x00FFFFFF][u8_tolower(buf[i])];
1100  if (state & 0xFF000000) {
1101  uint32_t no_of_entries = ctx->output_table[state & 0x00FFFFFF].no_of_entries;
1102  uint32_t *pids = ctx->output_table[state & 0x00FFFFFF].pids;
1103  uint32_t k;
1104  for (k = 0; k < no_of_entries; k++) {
1105  if (pids[k] & AC_CASE_MASK) {
1106  uint32_t lower_pid = pids[k] & 0x0000FFFF;
1107  const SCACPatternList *pat = &pid_pat_list[lower_pid];
1108  const int offset = i - pat->patlen + 1;
1109 
1110  if (offset < (int)pat->offset || (pat->depth && i > pat->depth))
1111  continue;
1112 
1113  if (SCMemcmp(pat->cs, buf + offset,
1114  pat->patlen) != 0) {
1115  /* inside loop */
1116  continue;
1117  }
1118  if (bitarray[(lower_pid) / 8] & (1 << ((lower_pid) % 8))) {
1119  ;
1120  } else {
1121  bitarray[(lower_pid) / 8] |= (1 << ((lower_pid) % 8));
1122  PrefilterAddSids(pmq, pat->sids, pat->sids_size);
1123  }
1124  matches++;
1125  } else {
1126  const SCACPatternList *pat = &pid_pat_list[pids[k]];
1127  const int offset = i - pat->patlen + 1;
1128 
1129  if (offset < (int)pat->offset || (pat->depth && i > pat->depth))
1130  continue;
1131 
1132  if (bitarray[pids[k] / 8] & (1 << (pids[k] % 8))) {
1133  ;
1134  } else {
1135  bitarray[pids[k] / 8] |= (1 << (pids[k] % 8));
1136  PrefilterAddSids(pmq, pat->sids, pat->sids_size);
1137  }
1138  matches++;
1139  }
1140  //loop1:
1141  //;
1142  }
1143  }
1144  } /* for (i = 0; i < buflen; i++) */
1145  }
1146 
1147  return matches;
1148 }
1149 
1150 /**
1151  * \brief Add a case insensitive pattern. Although we have different calls for
1152  * adding case sensitive and insensitive patterns, we make a single call
1153  * for either case. No special treatment for either case.
1154  *
1155  * \param mpm_ctx Pointer to the mpm context.
1156  * \param pat The pattern to add.
1157  * \param patnen The pattern length.
1158  * \param offset Ignored.
1159  * \param depth Ignored.
1160  * \param pid The pattern id.
1161  * \param sid Ignored.
1162  * \param flags Flags associated with this pattern.
1163  *
1164  * \retval 0 On success.
1165  * \retval -1 On failure.
1166  */
1167 int SCACAddPatternCI(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
1168  uint16_t offset, uint16_t depth, uint32_t pid,
1169  SigIntId sid, uint8_t flags)
1170 {
1171  flags |= MPM_PATTERN_FLAG_NOCASE;
1172  return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
1173 }
1174 
1175 /**
1176  * \brief Add a case sensitive pattern. Although we have different calls for
1177  * adding case sensitive and insensitive patterns, we make a single call
1178  * for either case. No special treatment for either case.
1179  *
1180  * \param mpm_ctx Pointer to the mpm context.
1181  * \param pat The pattern to add.
1182  * \param patnen The pattern length.
1183  * \param offset Ignored.
1184  * \param depth Ignored.
1185  * \param pid The pattern id.
1186  * \param sid Ignored.
1187  * \param flags Flags associated with this pattern.
1188  *
1189  * \retval 0 On success.
1190  * \retval -1 On failure.
1191  */
1192 int SCACAddPatternCS(MpmCtx *mpm_ctx, uint8_t *pat, uint16_t patlen,
1193  uint16_t offset, uint16_t depth, uint32_t pid,
1194  SigIntId sid, uint8_t flags)
1195 {
1196  return MpmAddPattern(mpm_ctx, pat, patlen, offset, depth, pid, sid, flags);
1197 }
1198 
1199 void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx)
1200 {
1201 
1202 #ifdef SC_AC_COUNTERS
1203  SCACThreadCtx *ctx = (SCACThreadCtx *)mpm_thread_ctx->ctx;
1204  printf("AC Thread Search stats (ctx %p)\n", ctx);
1205  printf("Total calls: %" PRIu32 "\n", ctx->total_calls);
1206  printf("Total matches: %" PRIu64 "\n", ctx->total_matches);
1207 #endif /* SC_AC_COUNTERS */
1208 
1209  return;
1210 }
1211 
1212 void SCACPrintInfo(MpmCtx *mpm_ctx)
1213 {
1214  SCACCtx *ctx = (SCACCtx *)mpm_ctx->ctx;
1215 
1216  printf("MPM AC Information:\n");
1217  printf("Memory allocs: %" PRIu32 "\n", mpm_ctx->memory_cnt);
1218  printf("Memory alloced: %" PRIu32 "\n", mpm_ctx->memory_size);
1219  printf(" Sizeof:\n");
1220  printf(" MpmCtx %" PRIuMAX "\n", (uintmax_t)sizeof(MpmCtx));
1221  printf(" SCACCtx: %" PRIuMAX "\n", (uintmax_t)sizeof(SCACCtx));
1222  printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern));
1223  printf(" MpmPattern %" PRIuMAX "\n", (uintmax_t)sizeof(MpmPattern));
1224  printf("Unique Patterns: %" PRIu32 "\n", mpm_ctx->pattern_cnt);
1225  printf("Smallest: %" PRIu32 "\n", mpm_ctx->minlen);
1226  printf("Largest: %" PRIu32 "\n", mpm_ctx->maxlen);
1227  printf("Total states in the state table: %" PRIu32 "\n", ctx->state_count);
1228  printf("\n");
1229 
1230  return;
1231 }
1232 
1233 
1234 /************************** Mpm Registration ***************************/
1235 
1236 /**
1237  * \brief Register the aho-corasick mpm.
1238  */
1239 void MpmACRegister(void)
1240 {
1241  mpm_table[MPM_AC].name = "ac";
1253 
1254  return;
1255 }
1256 
1257 /*************************************Unittests********************************/
1258 
1259 #ifdef UNITTESTS
1260 
1261 static int SCACTest01(void)
1262 {
1263  int result = 0;
1264  MpmCtx mpm_ctx;
1265  MpmThreadCtx mpm_thread_ctx;
1266  PrefilterRuleStore pmq;
1267 
1268  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1269  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1270  MpmInitCtx(&mpm_ctx, MPM_AC);
1271  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1272 
1273  /* 1 match */
1274  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1275  PmqSetup(&pmq);
1276 
1277  SCACPreparePatterns(&mpm_ctx);
1278 
1279  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1280 
1281  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1282  (uint8_t *)buf, strlen(buf));
1283 
1284  if (cnt == 1)
1285  result = 1;
1286  else
1287  printf("1 != %" PRIu32 " ",cnt);
1288 
1289  SCACDestroyCtx(&mpm_ctx);
1290  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1291  PmqFree(&pmq);
1292  return result;
1293 }
1294 
1295 static int SCACTest02(void)
1296 {
1297  int result = 0;
1298  MpmCtx mpm_ctx;
1299  MpmThreadCtx mpm_thread_ctx;
1300  PrefilterRuleStore pmq;
1301 
1302  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1303  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1304  MpmInitCtx(&mpm_ctx, MPM_AC);
1305  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1306 
1307  /* 1 match */
1308  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abce", 4, 0, 0, 0, 0, 0);
1309  PmqSetup(&pmq);
1310 
1311  SCACPreparePatterns(&mpm_ctx);
1312 
1313  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1314  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1315  (uint8_t *)buf, strlen(buf));
1316 
1317  if (cnt == 0)
1318  result = 1;
1319  else
1320  printf("0 != %" PRIu32 " ",cnt);
1321 
1322  SCACDestroyCtx(&mpm_ctx);
1323  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1324  PmqFree(&pmq);
1325  return result;
1326 }
1327 
1328 static int SCACTest03(void)
1329 {
1330  int result = 0;
1331  MpmCtx mpm_ctx;
1332  MpmThreadCtx mpm_thread_ctx;
1333  PrefilterRuleStore pmq;
1334 
1335  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1336  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1337  MpmInitCtx(&mpm_ctx, MPM_AC);
1338  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1339 
1340  /* 1 match */
1341  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1342  /* 1 match */
1343  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcde", 4, 0, 0, 1, 0, 0);
1344  /* 1 match */
1345  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghj", 4, 0, 0, 2, 0, 0);
1346  PmqSetup(&pmq);
1347 
1348  SCACPreparePatterns(&mpm_ctx);
1349 
1350  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1351  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1352  (uint8_t *)buf, strlen(buf));
1353 
1354  if (cnt == 3)
1355  result = 1;
1356  else
1357  printf("3 != %" PRIu32 " ",cnt);
1358 
1359  SCACDestroyCtx(&mpm_ctx);
1360  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1361  PmqFree(&pmq);
1362  return result;
1363 }
1364 
1365 static int SCACTest04(void)
1366 {
1367  int result = 0;
1368  MpmCtx mpm_ctx;
1369  MpmThreadCtx mpm_thread_ctx;
1370  PrefilterRuleStore pmq;
1371 
1372  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1373  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1374  MpmInitCtx(&mpm_ctx, MPM_AC);
1375  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1376 
1377  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1378  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"bcdegh", 6, 0, 0, 1, 0, 0);
1379  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"fghjxyz", 7, 0, 0, 2, 0, 0);
1380  PmqSetup(&pmq);
1381 
1382  SCACPreparePatterns(&mpm_ctx);
1383 
1384  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1385  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1386  (uint8_t *)buf, strlen(buf));
1387 
1388  if (cnt == 1)
1389  result = 1;
1390  else
1391  printf("1 != %" PRIu32 " ",cnt);
1392 
1393  SCACDestroyCtx(&mpm_ctx);
1394  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1395  PmqFree(&pmq);
1396  return result;
1397 }
1398 
1399 static int SCACTest05(void)
1400 {
1401  int result = 0;
1402  MpmCtx mpm_ctx;
1403  MpmThreadCtx mpm_thread_ctx;
1404  PrefilterRuleStore pmq;
1405 
1406  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1407  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1408  MpmInitCtx(&mpm_ctx, MPM_AC);
1409  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1410 
1411  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
1412  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
1413  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghJikl", 7, 0, 0, 2, 0, 0);
1414  PmqSetup(&pmq);
1415 
1416  SCACPreparePatterns(&mpm_ctx);
1417 
1418  const char *buf = "abcdefghjiklmnopqrstuvwxyz";
1419  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1420  (uint8_t *)buf, strlen(buf));
1421 
1422  if (cnt == 3)
1423  result = 1;
1424  else
1425  printf("3 != %" PRIu32 " ",cnt);
1426 
1427  SCACDestroyCtx(&mpm_ctx);
1428  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1429  PmqFree(&pmq);
1430  return result;
1431 }
1432 
1433 static int SCACTest06(void)
1434 {
1435  int result = 0;
1436  MpmCtx mpm_ctx;
1437  MpmThreadCtx mpm_thread_ctx;
1438  PrefilterRuleStore pmq;
1439 
1440  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1441  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1442  MpmInitCtx(&mpm_ctx, MPM_AC);
1443  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1444 
1445  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1446  PmqSetup(&pmq);
1447 
1448  SCACPreparePatterns(&mpm_ctx);
1449 
1450  const char *buf = "abcd";
1451  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1452  (uint8_t *)buf, strlen(buf));
1453 
1454  if (cnt == 1)
1455  result = 1;
1456  else
1457  printf("1 != %" PRIu32 " ",cnt);
1458 
1459  SCACDestroyCtx(&mpm_ctx);
1460  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1461  PmqFree(&pmq);
1462  return result;
1463 }
1464 
1465 static int SCACTest07(void)
1466 {
1467  int result = 0;
1468  MpmCtx mpm_ctx;
1469  MpmThreadCtx mpm_thread_ctx;
1470  PrefilterRuleStore pmq;
1471 
1472  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1473  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1474  MpmInitCtx(&mpm_ctx, MPM_AC);
1475  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1476 
1477  /* should match 30 times */
1478  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"A", 1, 0, 0, 0, 0, 0);
1479  /* should match 29 times */
1480  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 1, 0, 0);
1481  /* should match 28 times */
1482  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAA", 3, 0, 0, 2, 0, 0);
1483  /* 26 */
1484  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAA", 5, 0, 0, 3, 0, 0);
1485  /* 21 */
1486  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAA", 10, 0, 0, 4, 0, 0);
1487  /* 1 */
1488  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
1489  30, 0, 0, 5, 0, 0);
1490  PmqSetup(&pmq);
1491  /* total matches: 135 */
1492 
1493  SCACPreparePatterns(&mpm_ctx);
1494 
1495  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1496  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1497  (uint8_t *)buf, strlen(buf));
1498 
1499  if (cnt == 135)
1500  result = 1;
1501  else
1502  printf("135 != %" PRIu32 " ",cnt);
1503 
1504  SCACDestroyCtx(&mpm_ctx);
1505  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1506  PmqFree(&pmq);
1507  return result;
1508 }
1509 
1510 static int SCACTest08(void)
1511 {
1512  int result = 0;
1513  MpmCtx mpm_ctx;
1514  MpmThreadCtx mpm_thread_ctx;
1515  PrefilterRuleStore pmq;
1516 
1517  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1518  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1519  MpmInitCtx(&mpm_ctx, MPM_AC);
1520  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1521 
1522  /* 1 match */
1523  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
1524  PmqSetup(&pmq);
1525 
1526  SCACPreparePatterns(&mpm_ctx);
1527 
1528  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1529  (uint8_t *)"a", 1);
1530 
1531  if (cnt == 0)
1532  result = 1;
1533  else
1534  printf("0 != %" PRIu32 " ",cnt);
1535 
1536  SCACDestroyCtx(&mpm_ctx);
1537  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1538  PmqFree(&pmq);
1539  return result;
1540 }
1541 
1542 static int SCACTest09(void)
1543 {
1544  int result = 0;
1545  MpmCtx mpm_ctx;
1546  MpmThreadCtx mpm_thread_ctx;
1547  PrefilterRuleStore pmq;
1548 
1549  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1550  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1551  MpmInitCtx(&mpm_ctx, MPM_AC);
1552  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1553 
1554  /* 1 match */
1555  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ab", 2, 0, 0, 0, 0, 0);
1556  PmqSetup(&pmq);
1557 
1558  SCACPreparePatterns(&mpm_ctx);
1559 
1560  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1561  (uint8_t *)"ab", 2);
1562 
1563  if (cnt == 1)
1564  result = 1;
1565  else
1566  printf("1 != %" PRIu32 " ",cnt);
1567 
1568  SCACDestroyCtx(&mpm_ctx);
1569  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1570  PmqFree(&pmq);
1571  return result;
1572 }
1573 
1574 static int SCACTest10(void)
1575 {
1576  int result = 0;
1577  MpmCtx mpm_ctx;
1578  MpmThreadCtx mpm_thread_ctx;
1579  PrefilterRuleStore pmq;
1580 
1581  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1582  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1583  MpmInitCtx(&mpm_ctx, MPM_AC);
1584  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1585 
1586  /* 1 match */
1587  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcdefgh", 8, 0, 0, 0, 0, 0);
1588  PmqSetup(&pmq);
1589 
1590  SCACPreparePatterns(&mpm_ctx);
1591 
1592  const char *buf = "01234567890123456789012345678901234567890123456789"
1593  "01234567890123456789012345678901234567890123456789"
1594  "abcdefgh"
1595  "01234567890123456789012345678901234567890123456789"
1596  "01234567890123456789012345678901234567890123456789";
1597  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1598  (uint8_t *)buf, strlen(buf));
1599 
1600  if (cnt == 1)
1601  result = 1;
1602  else
1603  printf("1 != %" PRIu32 " ",cnt);
1604 
1605  SCACDestroyCtx(&mpm_ctx);
1606  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1607  PmqFree(&pmq);
1608  return result;
1609 }
1610 
1611 static int SCACTest11(void)
1612 {
1613  int result = 0;
1614  MpmCtx mpm_ctx;
1615  MpmThreadCtx mpm_thread_ctx;
1616  PrefilterRuleStore pmq;
1617 
1618  memset(&mpm_ctx, 0, sizeof(MpmCtx));
1619  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1620  MpmInitCtx(&mpm_ctx, MPM_AC);
1621  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
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 (SCACPreparePatterns(&mpm_ctx) == -1)
1634  goto end;
1635 
1636  result = 1;
1637 
1638  const char *buf = "he";
1639  result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1640  strlen(buf)) == 1);
1641  buf = "she";
1642  result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1643  strlen(buf)) == 2);
1644  buf = "his";
1645  result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1646  strlen(buf)) == 1);
1647  buf = "hers";
1648  result &= (SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq, (uint8_t *)buf,
1649  strlen(buf)) == 2);
1650 
1651  end:
1652  SCACDestroyCtx(&mpm_ctx);
1653  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1654  PmqFree(&pmq);
1655  return result;
1656 }
1657 
1658 static int SCACTest12(void)
1659 {
1660  int result = 0;
1661  MpmCtx mpm_ctx;
1662  MpmThreadCtx mpm_thread_ctx;
1663  PrefilterRuleStore pmq;
1664 
1665  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1666  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1667  MpmInitCtx(&mpm_ctx, MPM_AC);
1668  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1669 
1670  /* 1 match */
1671  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"wxyz", 4, 0, 0, 0, 0, 0);
1672  /* 1 match */
1673  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"vwxyz", 5, 0, 0, 1, 0, 0);
1674  PmqSetup(&pmq);
1675 
1676  SCACPreparePatterns(&mpm_ctx);
1677 
1678  const char *buf = "abcdefghijklmnopqrstuvwxyz";
1679  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1680  (uint8_t *)buf, strlen(buf));
1681 
1682  if (cnt == 2)
1683  result = 1;
1684  else
1685  printf("2 != %" PRIu32 " ",cnt);
1686 
1687  SCACDestroyCtx(&mpm_ctx);
1688  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1689  PmqFree(&pmq);
1690  return result;
1691 }
1692 
1693 static int SCACTest13(void)
1694 {
1695  int result = 0;
1696  MpmCtx mpm_ctx;
1697  MpmThreadCtx mpm_thread_ctx;
1698  PrefilterRuleStore pmq;
1699 
1700  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1701  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1702  MpmInitCtx(&mpm_ctx, MPM_AC);
1703  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1704 
1705  /* 1 match */
1706  const char *pat = "abcdefghijklmnopqrstuvwxyzABCD";
1707  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1708  PmqSetup(&pmq);
1709 
1710  SCACPreparePatterns(&mpm_ctx);
1711 
1712  const char *buf = "abcdefghijklmnopqrstuvwxyzABCD";
1713  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1714  (uint8_t *)buf, strlen(buf));
1715 
1716  if (cnt == 1)
1717  result = 1;
1718  else
1719  printf("1 != %" PRIu32 " ",cnt);
1720 
1721  SCACDestroyCtx(&mpm_ctx);
1722  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1723  PmqFree(&pmq);
1724  return result;
1725 }
1726 
1727 static int SCACTest14(void)
1728 {
1729  int result = 0;
1730  MpmCtx mpm_ctx;
1731  MpmThreadCtx mpm_thread_ctx;
1732  PrefilterRuleStore pmq;
1733 
1734  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1735  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1736  MpmInitCtx(&mpm_ctx, MPM_AC);
1737  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1738 
1739  /* 1 match */
1740  const char *pat = "abcdefghijklmnopqrstuvwxyzABCDE";
1741  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1742  PmqSetup(&pmq);
1743 
1744  SCACPreparePatterns(&mpm_ctx);
1745 
1746  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDE";
1747  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1748  (uint8_t *)buf, strlen(buf));
1749 
1750  if (cnt == 1)
1751  result = 1;
1752  else
1753  printf("1 != %" PRIu32 " ",cnt);
1754 
1755  SCACDestroyCtx(&mpm_ctx);
1756  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1757  PmqFree(&pmq);
1758  return result;
1759 }
1760 
1761 static int SCACTest15(void)
1762 {
1763  int result = 0;
1764  MpmCtx mpm_ctx;
1765  MpmThreadCtx mpm_thread_ctx;
1766  PrefilterRuleStore pmq;
1767 
1768  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1769  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1770  MpmInitCtx(&mpm_ctx, MPM_AC);
1771  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1772 
1773  /* 1 match */
1774  const char *pat = "abcdefghijklmnopqrstuvwxyzABCDEF";
1775  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1776  PmqSetup(&pmq);
1777 
1778  SCACPreparePatterns(&mpm_ctx);
1779 
1780  const char *buf = "abcdefghijklmnopqrstuvwxyzABCDEF";
1781  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1782  (uint8_t *)buf, strlen(buf));
1783 
1784  if (cnt == 1)
1785  result = 1;
1786  else
1787  printf("1 != %" PRIu32 " ",cnt);
1788 
1789  SCACDestroyCtx(&mpm_ctx);
1790  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1791  PmqFree(&pmq);
1792  return result;
1793 }
1794 
1795 static int SCACTest16(void)
1796 {
1797  int result = 0;
1798  MpmCtx mpm_ctx;
1799  MpmThreadCtx mpm_thread_ctx;
1800  PrefilterRuleStore pmq;
1801 
1802  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1803  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1804  MpmInitCtx(&mpm_ctx, MPM_AC);
1805  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1806 
1807  /* 1 match */
1808  const char *pat = "abcdefghijklmnopqrstuvwxyzABC";
1809  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1810  PmqSetup(&pmq);
1811 
1812  SCACPreparePatterns(&mpm_ctx);
1813 
1814  const char *buf = "abcdefghijklmnopqrstuvwxyzABC";
1815  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1816  (uint8_t *)buf, strlen(buf));
1817 
1818  if (cnt == 1)
1819  result = 1;
1820  else
1821  printf("1 != %" PRIu32 " ",cnt);
1822 
1823  SCACDestroyCtx(&mpm_ctx);
1824  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1825  PmqFree(&pmq);
1826  return result;
1827 }
1828 
1829 static int SCACTest17(void)
1830 {
1831  int result = 0;
1832  MpmCtx mpm_ctx;
1833  MpmThreadCtx mpm_thread_ctx;
1834  PrefilterRuleStore pmq;
1835 
1836  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1837  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1838  MpmInitCtx(&mpm_ctx, MPM_AC);
1839  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1840 
1841  /* 1 match */
1842  const char *pat = "abcdefghijklmnopqrstuvwxyzAB";
1843  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1844  PmqSetup(&pmq);
1845 
1846  SCACPreparePatterns(&mpm_ctx);
1847 
1848  const char *buf = "abcdefghijklmnopqrstuvwxyzAB";
1849  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1850  (uint8_t *)buf, strlen(buf));
1851 
1852  if (cnt == 1)
1853  result = 1;
1854  else
1855  printf("1 != %" PRIu32 " ",cnt);
1856 
1857  SCACDestroyCtx(&mpm_ctx);
1858  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1859  PmqFree(&pmq);
1860  return result;
1861 }
1862 
1863 static int SCACTest18(void)
1864 {
1865  int result = 0;
1866  MpmCtx mpm_ctx;
1867  MpmThreadCtx mpm_thread_ctx;
1868  PrefilterRuleStore pmq;
1869 
1870  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1871  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1872  MpmInitCtx(&mpm_ctx, MPM_AC);
1873  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1874 
1875  /* 1 match */
1876  const char *pat = "abcde""fghij""klmno""pqrst""uvwxy""z";
1877  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1878  PmqSetup(&pmq);
1879 
1880  SCACPreparePatterns(&mpm_ctx);
1881 
1882  const char *buf = "abcde""fghij""klmno""pqrst""uvwxy""z";
1883  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1884  (uint8_t *)buf, strlen(buf));
1885 
1886  if (cnt == 1)
1887  result = 1;
1888  else
1889  printf("1 != %" PRIu32 " ",cnt);
1890 
1891  SCACDestroyCtx(&mpm_ctx);
1892  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1893  PmqFree(&pmq);
1894  return result;
1895 }
1896 
1897 static int SCACTest19(void)
1898 {
1899  int result = 0;
1900  MpmCtx mpm_ctx;
1901  MpmThreadCtx mpm_thread_ctx;
1902  PrefilterRuleStore pmq;
1903 
1904  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1905  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1906  MpmInitCtx(&mpm_ctx, MPM_AC);
1907  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1908 
1909  /* 1 */
1910  const char *pat = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1911  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1912  PmqSetup(&pmq);
1913 
1914  SCACPreparePatterns(&mpm_ctx);
1915 
1916  const char *buf = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1917  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1918  (uint8_t *)buf, strlen(buf));
1919 
1920  if (cnt == 1)
1921  result = 1;
1922  else
1923  printf("1 != %" PRIu32 " ",cnt);
1924 
1925  SCACDestroyCtx(&mpm_ctx);
1926  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1927  PmqFree(&pmq);
1928  return result;
1929 }
1930 
1931 static int SCACTest20(void)
1932 {
1933  int result = 0;
1934  MpmCtx mpm_ctx;
1935  MpmThreadCtx mpm_thread_ctx;
1936  PrefilterRuleStore pmq;
1937 
1938  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1939  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1940  MpmInitCtx(&mpm_ctx, MPM_AC);
1941  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1942 
1943  /* 1 */
1944  const char *pat = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA";
1945  MpmAddPatternCS(&mpm_ctx, (uint8_t *)pat, strlen(pat), 0, 0, 0, 0, 0);
1946  PmqSetup(&pmq);
1947 
1948  SCACPreparePatterns(&mpm_ctx);
1949 
1950  const char *buf = "AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AAAAA""AA";
1951  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1952  (uint8_t *)buf, strlen(buf));
1953 
1954  if (cnt == 1)
1955  result = 1;
1956  else
1957  printf("1 != %" PRIu32 " ",cnt);
1958 
1959  SCACDestroyCtx(&mpm_ctx);
1960  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1961  PmqFree(&pmq);
1962  return result;
1963 }
1964 
1965 static int SCACTest21(void)
1966 {
1967  int result = 0;
1968  MpmCtx mpm_ctx;
1969  MpmThreadCtx mpm_thread_ctx;
1970  PrefilterRuleStore pmq;
1971 
1972  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
1973  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
1974  MpmInitCtx(&mpm_ctx, MPM_AC);
1975  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1976 
1977  /* 1 */
1978  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
1979  PmqSetup(&pmq);
1980 
1981  SCACPreparePatterns(&mpm_ctx);
1982 
1983  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
1984  (uint8_t *)"AA", 2);
1985 
1986  if (cnt == 1)
1987  result = 1;
1988  else
1989  printf("1 != %" PRIu32 " ",cnt);
1990 
1991  SCACDestroyCtx(&mpm_ctx);
1992  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
1993  PmqFree(&pmq);
1994  return result;
1995 }
1996 
1997 static int SCACTest22(void)
1998 {
1999  int result = 0;
2000  MpmCtx mpm_ctx;
2001  MpmThreadCtx mpm_thread_ctx;
2002  PrefilterRuleStore pmq;
2003 
2004  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2005  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2006  MpmInitCtx(&mpm_ctx, MPM_AC);
2007  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2008 
2009  /* 1 match */
2010  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcd", 4, 0, 0, 0, 0, 0);
2011  /* 1 match */
2012  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"abcde", 5, 0, 0, 1, 0, 0);
2013  PmqSetup(&pmq);
2014 
2015  SCACPreparePatterns(&mpm_ctx);
2016 
2017  const char *buf = "abcdefghijklmnopqrstuvwxyz";
2018  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2019  (uint8_t *)buf, strlen(buf));
2020 
2021  if (cnt == 2)
2022  result = 1;
2023  else
2024  printf("2 != %" PRIu32 " ",cnt);
2025 
2026  SCACDestroyCtx(&mpm_ctx);
2027  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2028  PmqFree(&pmq);
2029  return result;
2030 }
2031 
2032 static int SCACTest23(void)
2033 {
2034  int result = 0;
2035  MpmCtx mpm_ctx;
2036  MpmThreadCtx mpm_thread_ctx;
2037  PrefilterRuleStore pmq;
2038 
2039  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2040  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2041  MpmInitCtx(&mpm_ctx, MPM_AC);
2042  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2043 
2044  /* 1 */
2045  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2046  PmqSetup(&pmq);
2047 
2048  SCACPreparePatterns(&mpm_ctx);
2049 
2050  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2051  (uint8_t *)"aa", 2);
2052 
2053  if (cnt == 0)
2054  result = 1;
2055  else
2056  printf("1 != %" PRIu32 " ",cnt);
2057 
2058  SCACDestroyCtx(&mpm_ctx);
2059  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2060  PmqFree(&pmq);
2061  return result;
2062 }
2063 
2064 static int SCACTest24(void)
2065 {
2066  int result = 0;
2067  MpmCtx mpm_ctx;
2068  MpmThreadCtx mpm_thread_ctx;
2069  PrefilterRuleStore pmq;
2070 
2071  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2072  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2073  MpmInitCtx(&mpm_ctx, MPM_AC);
2074  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2075 
2076  /* 1 */
2077  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"AA", 2, 0, 0, 0, 0, 0);
2078  PmqSetup(&pmq);
2079 
2080  SCACPreparePatterns(&mpm_ctx);
2081 
2082  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2083  (uint8_t *)"aa", 2);
2084 
2085  if (cnt == 1)
2086  result = 1;
2087  else
2088  printf("1 != %" PRIu32 " ",cnt);
2089 
2090  SCACDestroyCtx(&mpm_ctx);
2091  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2092  PmqFree(&pmq);
2093  return result;
2094 }
2095 
2096 static int SCACTest25(void)
2097 {
2098  int result = 0;
2099  MpmCtx mpm_ctx;
2100  MpmThreadCtx mpm_thread_ctx;
2101  PrefilterRuleStore pmq;
2102 
2103  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2104  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2105  MpmInitCtx(&mpm_ctx, MPM_AC);
2106  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2107 
2108  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"ABCD", 4, 0, 0, 0, 0, 0);
2109  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"bCdEfG", 6, 0, 0, 1, 0, 0);
2110  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"fghiJkl", 7, 0, 0, 2, 0, 0);
2111  PmqSetup(&pmq);
2112 
2113  SCACPreparePatterns(&mpm_ctx);
2114 
2115  const char *buf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
2116  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2117  (uint8_t *)buf, strlen(buf));
2118 
2119  if (cnt == 3)
2120  result = 1;
2121  else
2122  printf("3 != %" PRIu32 " ",cnt);
2123 
2124  SCACDestroyCtx(&mpm_ctx);
2125  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2126  PmqFree(&pmq);
2127  return result;
2128 }
2129 
2130 static int SCACTest26(void)
2131 {
2132  int result = 0;
2133  MpmCtx mpm_ctx;
2134  MpmThreadCtx mpm_thread_ctx;
2135  PrefilterRuleStore pmq;
2136 
2137  memset(&mpm_ctx, 0x00, sizeof(MpmCtx));
2138  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2139  MpmInitCtx(&mpm_ctx, MPM_AC);
2140  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2141 
2142  MpmAddPatternCI(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 0, 0, 0);
2143  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"Works", 5, 0, 0, 1, 0, 0);
2144  PmqSetup(&pmq);
2145 
2146  SCACPreparePatterns(&mpm_ctx);
2147 
2148  const char *buf = "works";
2149  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2150  (uint8_t *)buf, strlen(buf));
2151 
2152  if (cnt == 1)
2153  result = 1;
2154  else
2155  printf("3 != %" PRIu32 " ",cnt);
2156 
2157  SCACDestroyCtx(&mpm_ctx);
2158  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2159  PmqFree(&pmq);
2160  return result;
2161 }
2162 
2163 static int SCACTest27(void)
2164 {
2165  int result = 0;
2166  MpmCtx mpm_ctx;
2167  MpmThreadCtx mpm_thread_ctx;
2168  PrefilterRuleStore pmq;
2169 
2170  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2171  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2172  MpmInitCtx(&mpm_ctx, MPM_AC);
2173  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2174 
2175  /* 0 match */
2176  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"ONE", 3, 0, 0, 0, 0, 0);
2177  PmqSetup(&pmq);
2178 
2179  SCACPreparePatterns(&mpm_ctx);
2180 
2181  const char *buf = "tone";
2182  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2183  (uint8_t *)buf, strlen(buf));
2184 
2185  if (cnt == 0)
2186  result = 1;
2187  else
2188  printf("0 != %" PRIu32 " ",cnt);
2189 
2190  SCACDestroyCtx(&mpm_ctx);
2191  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2192  PmqFree(&pmq);
2193  return result;
2194 }
2195 
2196 static int SCACTest28(void)
2197 {
2198  int result = 0;
2199  MpmCtx mpm_ctx;
2200  MpmThreadCtx mpm_thread_ctx;
2201  PrefilterRuleStore pmq;
2202 
2203  memset(&mpm_ctx, 0, sizeof(MpmCtx));
2204  memset(&mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
2205  MpmInitCtx(&mpm_ctx, MPM_AC);
2206  SCACInitThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2207 
2208  /* 0 match */
2209  MpmAddPatternCS(&mpm_ctx, (uint8_t *)"one", 3, 0, 0, 0, 0, 0);
2210  PmqSetup(&pmq);
2211 
2212  SCACPreparePatterns(&mpm_ctx);
2213 
2214  const char *buf = "tONE";
2215  uint32_t cnt = SCACSearch(&mpm_ctx, &mpm_thread_ctx, &pmq,
2216  (uint8_t *)buf, strlen(buf));
2217 
2218  if (cnt == 0)
2219  result = 1;
2220  else
2221  printf("0 != %" PRIu32 " ",cnt);
2222 
2223  SCACDestroyCtx(&mpm_ctx);
2224  SCACDestroyThreadCtx(&mpm_ctx, &mpm_thread_ctx);
2225  PmqFree(&pmq);
2226  return result;
2227 }
2228 
2229 static int SCACTest29(void)
2230 {
2231  uint8_t *buf = (uint8_t *)"onetwothreefourfivesixseveneightnine";
2232  uint16_t buflen = strlen((char *)buf);
2233  Packet *p = NULL;
2234  ThreadVars th_v;
2235  DetectEngineThreadCtx *det_ctx = NULL;
2236  int result = 0;
2237 
2238  memset(&th_v, 0, sizeof(th_v));
2239  p = UTHBuildPacket(buf, buflen, IPPROTO_TCP);
2240 
2242  if (de_ctx == NULL)
2243  goto end;
2244 
2245  de_ctx->flags |= DE_QUIET;
2246 
2247  de_ctx->sig_list = SigInit(de_ctx, "alert tcp any any -> any any "
2248  "(content:\"onetwothreefourfivesixseveneightnine\"; sid:1;)");
2249  if (de_ctx->sig_list == NULL)
2250  goto end;
2251  de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any any "
2252  "(content:\"onetwothreefourfivesixseveneightnine\"; fast_pattern:3,3; sid:2;)");
2253  if (de_ctx->sig_list->next == NULL)
2254  goto end;
2255 
2256  SigGroupBuild(de_ctx);
2257  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
2258 
2259  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
2260  if (PacketAlertCheck(p, 1) != 1) {
2261  printf("if (PacketAlertCheck(p, 1) != 1) failure\n");
2262  goto end;
2263  }
2264  if (PacketAlertCheck(p, 2) != 1) {
2265  printf("if (PacketAlertCheck(p, 1) != 2) failure\n");
2266  goto end;
2267  }
2268 
2269  result = 1;
2270 end:
2271  if (de_ctx != NULL) {
2272  SigGroupCleanup(de_ctx);
2273  SigCleanSignatures(de_ctx);
2274 
2275  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
2276  DetectEngineCtxFree(de_ctx);
2277  }
2278 
2279  UTHFreePackets(&p, 1);
2280  return result;
2281 }
2282 
2283 #endif /* UNITTESTS */
2284 
2286 {
2287 
2288 #ifdef UNITTESTS
2289  UtRegisterTest("SCACTest01", SCACTest01);
2290  UtRegisterTest("SCACTest02", SCACTest02);
2291  UtRegisterTest("SCACTest03", SCACTest03);
2292  UtRegisterTest("SCACTest04", SCACTest04);
2293  UtRegisterTest("SCACTest05", SCACTest05);
2294  UtRegisterTest("SCACTest06", SCACTest06);
2295  UtRegisterTest("SCACTest07", SCACTest07);
2296  UtRegisterTest("SCACTest08", SCACTest08);
2297  UtRegisterTest("SCACTest09", SCACTest09);
2298  UtRegisterTest("SCACTest10", SCACTest10);
2299  UtRegisterTest("SCACTest11", SCACTest11);
2300  UtRegisterTest("SCACTest12", SCACTest12);
2301  UtRegisterTest("SCACTest13", SCACTest13);
2302  UtRegisterTest("SCACTest14", SCACTest14);
2303  UtRegisterTest("SCACTest15", SCACTest15);
2304  UtRegisterTest("SCACTest16", SCACTest16);
2305  UtRegisterTest("SCACTest17", SCACTest17);
2306  UtRegisterTest("SCACTest18", SCACTest18);
2307  UtRegisterTest("SCACTest19", SCACTest19);
2308  UtRegisterTest("SCACTest20", SCACTest20);
2309  UtRegisterTest("SCACTest21", SCACTest21);
2310  UtRegisterTest("SCACTest22", SCACTest22);
2311  UtRegisterTest("SCACTest23", SCACTest23);
2312  UtRegisterTest("SCACTest24", SCACTest24);
2313  UtRegisterTest("SCACTest25", SCACTest25);
2314  UtRegisterTest("SCACTest26", SCACTest26);
2315  UtRegisterTest("SCACTest27", SCACTest27);
2316  UtRegisterTest("SCACTest28", SCACTest28);
2317  UtRegisterTest("SCACTest29", SCACTest29);
2318 #endif
2319 
2320  return;
2321 }
SCACOutputTable * output_table
Definition: util-mpm-ac.h:68
uint16_t flags
#define SCMemcmp(a, b, c)
Definition: util-memcmp.h:369
#define SCLogDebug(...)
Definition: util-debug.h:335
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
struct StateQueue_ StateQueue
Helper structure used by AC during state table creation.
uint16_t minlen
Definition: util-mpm.h:99
#define SC_AC_FAIL
Definition: util-mpm-ac.c:79
struct SCACThreadCtx_ SCACThreadCtx
void(* PrintCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:163
uint32_t total_calls
Definition: util-mpm-ac.h:80
uint32_t SCACSearch(const MpmCtx *mpm_ctx, MpmThreadCtx *mpm_thread_ctx, PrefilterRuleStore *pmq, const uint8_t *buf, uint32_t buflen)
The aho corasick search function.
Definition: util-mpm-ac.c:1029
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
uint32_t pattern_cnt
Definition: util-mpm.h:97
void MpmFreePattern(MpmCtx *mpm_ctx, MpmPattern *p)
Definition: util-mpm.c:410
int PmqSetup(PrefilterRuleStore *)
Setup a pmq.
uint8_t * cs
Definition: util-mpm-ac.h:32
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
uint32_t pattern_id_bitarray_size
Definition: util-mpm-ac.h:57
uint16_t patlen
Definition: util-mpm-ac.h:33
#define MPM_PATTERN_FLAG_NOCASE
Definition: util-mpm.h:128
void(* InitCtx)(struct MpmCtx_ *)
Definition: util-mpm.h:143
struct SCACCtx_ SCACCtx
#define AC_CASE_MASK
Definition: util-mpm-ac.c:83
void(* RegisterUnittests)(void)
Definition: util-mpm.h:165
Signature * sig_list
Definition: detect.h:730
uint64_t offset
void SCACDestroyThreadCtx(MpmCtx *, MpmThreadCtx *)
Destroy the mpm thread context.
Definition: util-mpm-ac.c:926
void SCACPrintSearchStats(MpmThreadCtx *mpm_thread_ctx)
Definition: util-mpm-ac.c:1199
void SigCleanSignatures(DetectEngineCtx *de_ctx)
void(* DestroyThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:146
uint32_t memory_cnt
Definition: util-mpm.h:102
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
uint32_t memory_size
Definition: util-mpm.h:50
#define SC_AC_STATE_TYPE_U16
Definition: util-mpm-ac.h:28
SC_AC_STATE_TYPE_U16(* state_table_u16)[256]
Definition: util-mpm-ac.h:60
struct MpmPattern_ * next
Definition: util-mpm.h:79
#define STATE_QUEUE_CONTAINER_SIZE
Definition: util-mpm-ac.c:81
main detection engine ctx
Definition: detect.h:724
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
void PmqFree(PrefilterRuleStore *)
Cleanup and free a Pmq.
void MpmACRegister(void)
Register the aho-corasick mpm.
Definition: util-mpm-ac.c:1239
#define DE_QUIET
Definition: detect.h:296
int(* Prepare)(struct MpmCtx_ *)
Definition: util-mpm.h:161
void(* PrintThreadCtx)(struct MpmThreadCtx_ *)
Definition: util-mpm.h:164
SigIntId * sids
Definition: util-mpm.h:77
#define u8_tolower(c)
Definition: suricata.h:180
#define AC_PID_MASK
Definition: util-mpm-ac.c:84
uint16_t depth
Definition: util-mpm.h:64
int SCACPreparePatterns(MpmCtx *mpm_ctx)
Process the patterns added to the mpm, and create the internal tables.
Definition: util-mpm-ac.c:774
SC_AC_STATE_TYPE_U32(* state_table_u32)[256]
Definition: util-mpm-ac.h:62
uint32_t single_state_size
Definition: util-mpm-ac.h:72
int32_t(* goto_table)[256]
Definition: util-mpm-ac.h:66
uint8_t flags
Definition: detect.h:725
int MpmAddPattern(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:488
void SCACRegisterTests(void)
Definition: util-mpm-ac.c:2285
#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.
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:1742
uint32_t no_of_entries
Definition: util-mpm-ac.h:47
void SCACPrintInfo(MpmCtx *mpm_ctx)
Definition: util-mpm-ac.c:1212
SigIntId * sids
Definition: util-mpm-ac.h:40
struct SCACOutputTable_ SCACOutputTable
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 SCACAddPatternCS(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Add a case sensitive pattern. Although we have different calls for adding case sensitive and insensit...
Definition: util-mpm-ac.c:1192
uint16_t depth
Definition: util-mpm-ac.h:36
int SigGroupCleanup(DetectEngineCtx *de_ctx)
struct Signature_ * next
Definition: detect.h:567
int SCACAddPatternCI(MpmCtx *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Add a case insensitive pattern. Although we have different calls for adding case sensitive and insens...
Definition: util-mpm-ac.c:1167
SCACPatternList * pid_pat_list
Definition: util-mpm-ac.h:69
uint32_t id
Definition: util-mpm.h:73
uint16_t offset
Definition: util-mpm.h:61
#define SCRealloc(x, a)
Definition: util-mem.h:182
#define SC_AC_STATE_TYPE_U32
Definition: util-mpm-ac.h:29
uint32_t * pids
Definition: util-mpm-ac.h:45
uint16_t offset
Definition: util-mpm-ac.h:35
uint32_t memory_size
Definition: util-mpm.h:103
uint32_t memory_cnt
Definition: util-mpm.h:49
uint32_t allocated_state_count
Definition: util-mpm-ac.h:74
Helper structure used by AC during state table creation.
#define MPM_INIT_HASH_SIZE
Definition: util-mpm.h:29
#define SCMalloc(a)
Definition: util-mem.h:166
void(* InitThreadCtx)(struct MpmCtx_ *, struct MpmThreadCtx_ *)
Definition: util-mpm.h:144
uint16_t maxlen
Definition: util-mpm.h:100
MpmPattern ** parray
Definition: util-mpm-ac.h:52
void MpmInitCtx(MpmCtx *mpm_ctx, uint16_t matcher)
Definition: util-mpm.c:261
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
MpmTableElmt mpm_table[MPM_TABLE_SIZE]
Definition: util-mpm.h:169
uint32_t state_count
Definition: util-mpm-ac.h:55
#define SCFree(a)
Definition: util-mem.h:228
void SCACInitThreadCtx(MpmCtx *, MpmThreadCtx *)
Init the mpm thread context.
Definition: util-mpm-ac.c:872
int32_t store[STATE_QUEUE_CONTAINER_SIZE]
MpmPattern ** init_hash
Definition: util-mpm.h:108
structure for storing potential rule matches
void SCACDestroyCtx(MpmCtx *)
Destroy the mpm context.
Definition: util-mpm-ac.c:945
uint64_t total_matches
Definition: util-mpm-ac.h:82
uint32_t sids_size
Definition: util-mpm.h:76
uint8_t flags
Definition: util-mpm.h:58
int32_t * failure_table
Definition: util-mpm-ac.h:67
uint32_t max_pat_id
Definition: util-mpm.h:105
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
uint32_t(* Search)(const struct MpmCtx_ *, struct MpmThreadCtx_ *, PrefilterRuleStore *, const uint8_t *, uint32_t)
Definition: util-mpm.h:162
#define SCReturn
Definition: util-debug.h:339
Per thread variable structure.
Definition: threadvars.h:57
const char * name
Definition: util-mpm.h:142
#define AC_CASE_BIT
Definition: util-mpm-ac.c:85
void * ctx
Definition: util-mpm.h:89
uint32_t sids_size
Definition: util-mpm-ac.h:39
uint8_t * ci
Definition: util-mpm.h:71
uint16_t len
Definition: util-mpm.h:56
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...
#define SCLogCritical(err_code,...)
Macro used to log CRITICAL messages.
Definition: util-debug.h:307
int(* AddPatternNocase)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:160
#define SigIntId
int(* AddPattern)(struct MpmCtx_ *, uint8_t *, uint16_t, uint16_t, uint16_t, uint32_t, SigIntId, uint8_t)
Definition: util-mpm.h:159
uint8_t * original_pat
Definition: util-mpm.h:67
DetectEngineCtx * DetectEngineCtxInit(void)
void SCACInitCtx(MpmCtx *)
Initialize the AC context.
Definition: util-mpm-ac.c:892
void * ctx
Definition: util-mpm.h:47