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