/src/suricata8/src/detect-fast-pattern.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2021 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 | | * Implements the fast_pattern keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "detect.h" |
28 | | #include "flow.h" |
29 | | #include "detect-content.h" |
30 | | #include "detect-parse.h" |
31 | | #include "detect-engine.h" |
32 | | #include "detect-engine-mpm.h" |
33 | | #include "detect-engine-build.h" |
34 | | #include "detect-fast-pattern.h" |
35 | | |
36 | | #include "util-error.h" |
37 | | #include "util-byte.h" |
38 | | #include "util-debug.h" |
39 | | #include "util-unittest.h" |
40 | | #include "util-unittest-helper.h" |
41 | | |
42 | 79 | #define PARSE_REGEX "^(\\s*only\\s*)|\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*$" |
43 | | |
44 | | static DetectParseRegex parse_regex; |
45 | | |
46 | | static int DetectFastPatternSetup(DetectEngineCtx *, Signature *, const char *); |
47 | | #ifdef UNITTESTS |
48 | | static void DetectFastPatternRegisterTests(void); |
49 | | #endif |
50 | | |
51 | | /* holds the list of sm match lists that need to be searched for a keyword |
52 | | * that has fp support */ |
53 | | static SCFPSupportSMList *g_fp_support_smlist_list = NULL; |
54 | | |
55 | | /** |
56 | | * \brief Checks if a particular buffer is in the list |
57 | | * of lists that need to be searched for a keyword that has fp support. |
58 | | * |
59 | | * \param list_id The list id. |
60 | | * |
61 | | * \retval 1 If supported. |
62 | | * \retval 0 If not. |
63 | | */ |
64 | | int FastPatternSupportEnabledForSigMatchList(const DetectEngineCtx *de_ctx, |
65 | | const int list_id) |
66 | 773k | { |
67 | 773k | if (de_ctx->fp_support_smlist_list == NULL) { |
68 | 0 | return 0; |
69 | 0 | } |
70 | | |
71 | 773k | if (list_id == DETECT_SM_LIST_PMATCH) |
72 | 178k | return 1; |
73 | | |
74 | 594k | return DetectEngineBufferTypeSupportsMpmGetById(de_ctx, list_id); |
75 | 773k | } |
76 | | |
77 | | static void Add(SCFPSupportSMList **list, const int list_id, const int priority) |
78 | 456k | { |
79 | 456k | SCFPSupportSMList *ip = NULL; |
80 | | /* insertion point - ip */ |
81 | 133M | for (SCFPSupportSMList *tmp = *list; tmp != NULL; tmp = tmp->next) { |
82 | 133M | if (list_id == tmp->list_id) { |
83 | 366k | SCLogDebug("SM list already registered."); |
84 | 366k | return; |
85 | 366k | } |
86 | | |
87 | | /* We need a strict check to be sure that the current list |
88 | | * was not already registered |
89 | | * and other lists with the same priority hide it. |
90 | | */ |
91 | 132M | if (priority < tmp->priority) |
92 | 89.5k | break; |
93 | | |
94 | 132M | ip = tmp; |
95 | 132M | } |
96 | | |
97 | 90.0k | if (*list == NULL) { |
98 | 79 | SCFPSupportSMList *new = SCCalloc(1, sizeof(SCFPSupportSMList)); |
99 | 79 | if (unlikely(new == NULL)) |
100 | 0 | exit(EXIT_FAILURE); |
101 | 79 | new->list_id = list_id; |
102 | 79 | new->priority = priority; |
103 | | |
104 | 79 | *list = new; |
105 | 79 | return; |
106 | 79 | } |
107 | | |
108 | 89.9k | SCFPSupportSMList *new = SCCalloc(1, sizeof(SCFPSupportSMList)); |
109 | 89.9k | if (unlikely(new == NULL)) |
110 | 0 | exit(EXIT_FAILURE); |
111 | 89.9k | new->list_id = list_id; |
112 | 89.9k | new->priority = priority; |
113 | 89.9k | if (ip == NULL) { |
114 | 195 | new->next = *list; |
115 | 195 | *list = new; |
116 | 89.7k | } else { |
117 | 89.7k | new->next = ip->next; |
118 | 89.7k | ip->next = new; |
119 | 89.7k | } |
120 | 89.9k | } |
121 | | |
122 | | /** |
123 | | * \brief Lets one add a sm list id to be searched for potential fp supported |
124 | | * keywords later. |
125 | | * |
126 | | * \param list_id SM list id. |
127 | | * \param priority Priority for this list. |
128 | | */ |
129 | | void SupportFastPatternForSigMatchList(int list_id, int priority) |
130 | 28.0k | { |
131 | 28.0k | Add(&g_fp_support_smlist_list, list_id, priority); |
132 | 28.0k | } |
133 | | |
134 | | void DetectEngineRegisterFastPatternForId(DetectEngineCtx *de_ctx, int list_id, int priority) |
135 | 428k | { |
136 | 428k | Add(&de_ctx->fp_support_smlist_list, list_id, priority); |
137 | 428k | } |
138 | | |
139 | | /** |
140 | | * \brief Registers the keywords(SMs) that should be given fp support. |
141 | | */ |
142 | | void SupportFastPatternForSigMatchTypes(void) |
143 | 77 | { |
144 | 77 | SupportFastPatternForSigMatchList(DETECT_SM_LIST_PMATCH, 3); |
145 | | |
146 | | /* other types are handled by DetectMpmAppLayerRegister() */ |
147 | 77 | } |
148 | | |
149 | | void DetectEngineInitializeFastPatternList(DetectEngineCtx *de_ctx) |
150 | 114k | { |
151 | 114k | SCFPSupportSMList *last = NULL; |
152 | 20.2M | for (SCFPSupportSMList *tmp = g_fp_support_smlist_list; tmp != NULL; tmp = tmp->next) { |
153 | 20.0M | SCFPSupportSMList *n = SCCalloc(1, sizeof(*n)); |
154 | 20.0M | if (n == NULL) { |
155 | 0 | FatalError("out of memory: %s", strerror(errno)); |
156 | 0 | } |
157 | 20.0M | n->list_id = tmp->list_id; |
158 | 20.0M | n->priority = tmp->priority; |
159 | | |
160 | | // append |
161 | 20.0M | if (de_ctx->fp_support_smlist_list == NULL) { |
162 | 114k | last = de_ctx->fp_support_smlist_list = n; |
163 | 19.9M | } else { |
164 | 19.9M | BUG_ON(last == NULL); |
165 | 19.9M | last->next = n; |
166 | 19.9M | last = n; |
167 | 19.9M | } |
168 | 20.0M | } |
169 | 114k | } |
170 | | |
171 | | void DetectEngineFreeFastPatternList(DetectEngineCtx *de_ctx) |
172 | 114k | { |
173 | 20.2M | for (SCFPSupportSMList *tmp = de_ctx->fp_support_smlist_list; tmp != NULL;) { |
174 | 20.1M | SCFPSupportSMList *next = tmp->next; |
175 | 20.1M | SCFree(tmp); |
176 | 20.1M | tmp = next; |
177 | 20.1M | } |
178 | 114k | de_ctx->fp_support_smlist_list = NULL; |
179 | 114k | } |
180 | | |
181 | | /** |
182 | | * \brief Registration function for fast_pattern keyword |
183 | | */ |
184 | | void DetectFastPatternRegister(void) |
185 | 79 | { |
186 | 79 | sigmatch_table[DETECT_FAST_PATTERN].name = "fast_pattern"; |
187 | 79 | sigmatch_table[DETECT_FAST_PATTERN].desc = "force using preceding content in the multi pattern matcher"; |
188 | 79 | sigmatch_table[DETECT_FAST_PATTERN].url = "/rules/prefilter-keywords.html#fast-pattern"; |
189 | 79 | sigmatch_table[DETECT_FAST_PATTERN].Match = NULL; |
190 | 79 | sigmatch_table[DETECT_FAST_PATTERN].Setup = DetectFastPatternSetup; |
191 | 79 | sigmatch_table[DETECT_FAST_PATTERN].Free = NULL; |
192 | | #ifdef UNITTESTS |
193 | | sigmatch_table[DETECT_FAST_PATTERN].RegisterTests = DetectFastPatternRegisterTests; |
194 | | #endif |
195 | 79 | sigmatch_table[DETECT_FAST_PATTERN].flags |= SIGMATCH_OPTIONAL_OPT; |
196 | | |
197 | 79 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
198 | 79 | } |
199 | | |
200 | | /** |
201 | | * \brief Configures the previous content context for a fast_pattern modifier |
202 | | * keyword used in the rule. |
203 | | * |
204 | | * \param de_ctx Pointer to the Detection Engine Context. |
205 | | * \param s Pointer to the Signature to which the current keyword belongs. |
206 | | * \param arg May hold an argument |
207 | | * |
208 | | * \retval 0 On success. |
209 | | * \retval -1 On failure. |
210 | | */ |
211 | | static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg) |
212 | 36.7k | { |
213 | 36.7k | int res = 0; |
214 | 36.7k | size_t pcre2len; |
215 | 36.7k | char arg_substr[128] = ""; |
216 | 36.7k | DetectContentData *cd = NULL; |
217 | 36.7k | pcre2_match_data *match = NULL; |
218 | | |
219 | 36.7k | SigMatch *pm1 = DetectGetLastSMFromMpmLists(de_ctx, s); |
220 | 36.7k | SigMatch *pm2 = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); |
221 | 36.7k | if (pm1 == NULL && pm2 == NULL) { |
222 | 544 | SCLogError("fast_pattern found inside " |
223 | 544 | "the rule, without a content context. Please use a " |
224 | 544 | "content based keyword before using fast_pattern"); |
225 | 544 | return -1; |
226 | 544 | } |
227 | | |
228 | 36.1k | SigMatch *pm = NULL; |
229 | 36.1k | if (pm1 && pm2) { |
230 | 32.4k | if (pm1->idx > pm2->idx) |
231 | 158 | pm = pm1; |
232 | 32.3k | else |
233 | 32.3k | pm = pm2; |
234 | 32.4k | } else if (pm1 && !pm2) { |
235 | 615 | pm = pm1; |
236 | 3.08k | } else { |
237 | 3.08k | pm = pm2; |
238 | 3.08k | } |
239 | | |
240 | 36.1k | if (s->flags & SIG_FLAG_TXBOTHDIR && s->init_data->curbuf != NULL) { |
241 | 3.38k | if (DetectBufferToClient(de_ctx, s->init_data->curbuf->id, s->alproto)) { |
242 | 1.66k | if (s->init_data->init_flags & SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER) { |
243 | 0 | SCLogError("fast_pattern cannot be used on to_client keyword for " |
244 | 0 | "transactional rule with a streaming buffer to server %u", |
245 | 0 | s->id); |
246 | 0 | goto error; |
247 | 0 | } |
248 | 1.66k | s->init_data->init_flags |= SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT; |
249 | 1.66k | } |
250 | 3.38k | } |
251 | | |
252 | 36.1k | cd = (DetectContentData *)pm->ctx; |
253 | 36.1k | if ((cd->flags & DETECT_CONTENT_NEGATED) && |
254 | 610 | ((cd->flags & DETECT_CONTENT_DISTANCE) || |
255 | 609 | (cd->flags & DETECT_CONTENT_WITHIN) || |
256 | 608 | (cd->flags & DETECT_CONTENT_OFFSET) || |
257 | 607 | (cd->flags & DETECT_CONTENT_DEPTH))) { |
258 | | |
259 | | /* we can't have any of these if we are having "only" */ |
260 | 66 | SCLogError("fast_pattern; cannot be " |
261 | 66 | "used with negated content, along with relative modifiers"); |
262 | 66 | goto error; |
263 | 66 | } |
264 | | |
265 | 36.1k | if (arg == NULL|| strcmp(arg, "") == 0) { |
266 | 29.4k | if (cd->flags & DETECT_CONTENT_FAST_PATTERN) { |
267 | 238 | SCLogError("can't use multiple fast_pattern " |
268 | 238 | "options for the same content"); |
269 | 238 | goto error; |
270 | 238 | } |
271 | 29.1k | else { /*allow only one content to have fast_pattern modifier*/ |
272 | 233k | for (uint32_t list_id = 0; list_id < DETECT_SM_LIST_MAX; list_id++) { |
273 | 204k | SigMatch *sm = NULL; |
274 | 236k | for (sm = s->init_data->smlists[list_id]; sm != NULL; sm = sm->next) { |
275 | 31.9k | if (sm->type == DETECT_CONTENT) { |
276 | 3.12k | DetectContentData *tmp_cd = (DetectContentData *)sm->ctx; |
277 | 3.12k | if (tmp_cd->flags & DETECT_CONTENT_FAST_PATTERN) { |
278 | 15 | SCLogError("fast_pattern " |
279 | 15 | "can be used on only one content in a rule"); |
280 | 15 | goto error; |
281 | 15 | } |
282 | 3.12k | } |
283 | 31.9k | } |
284 | 204k | } |
285 | 29.1k | } |
286 | 29.1k | if (SigMatchListSMBelongsTo(s, pm) == DETECT_SM_LIST_BASE64_DATA) { |
287 | 5 | SCLogError("fast_pattern cannot be used with base64_data"); |
288 | 5 | goto error; |
289 | 5 | } |
290 | 29.1k | cd->flags |= DETECT_CONTENT_FAST_PATTERN; |
291 | 29.1k | return 0; |
292 | 29.1k | } |
293 | | |
294 | | /* Execute the regex and populate args with captures. */ |
295 | 6.67k | int ret = DetectParsePcreExec(&parse_regex, &match, arg, 0, 0); |
296 | | /* fast pattern only */ |
297 | 6.67k | if (ret == 2) { |
298 | 6.35k | if ((cd->flags & DETECT_CONTENT_NEGATED) || |
299 | 6.35k | (cd->flags & DETECT_CONTENT_DISTANCE) || |
300 | 6.35k | (cd->flags & DETECT_CONTENT_WITHIN) || |
301 | 6.35k | (cd->flags & DETECT_CONTENT_OFFSET) || |
302 | 6.35k | (cd->flags & DETECT_CONTENT_DEPTH)) { |
303 | | |
304 | | /* we can't have any of these if we are having "only" */ |
305 | 104 | SCLogError("fast_pattern: only; cannot be " |
306 | 104 | "used with negated content or with any of the relative " |
307 | 104 | "modifiers like distance, within, offset, depth"); |
308 | 104 | goto error; |
309 | 104 | } |
310 | 6.25k | cd->flags |= DETECT_CONTENT_FAST_PATTERN_ONLY; |
311 | | |
312 | | /* fast pattern chop */ |
313 | 6.25k | } else if (ret == 4) { |
314 | 126 | pcre2len = sizeof(arg_substr); |
315 | 126 | res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg_substr, &pcre2len); |
316 | 126 | if (res < 0) { |
317 | 1 | SCLogError("pcre2_substring_copy_bynumber failed " |
318 | 1 | "for fast_pattern offset"); |
319 | 1 | goto error; |
320 | 1 | } |
321 | 125 | uint16_t offset; |
322 | 125 | if (StringParseUint16(&offset, 10, 0, (const char *)arg_substr) <= 0) { |
323 | 1 | SCLogError("Invalid fast pattern offset:" |
324 | 1 | " \"%s\"", |
325 | 1 | arg_substr); |
326 | 1 | goto error; |
327 | 1 | } |
328 | | |
329 | 124 | pcre2len = sizeof(arg_substr); |
330 | 124 | res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)arg_substr, &pcre2len); |
331 | 124 | if (res < 0) { |
332 | 1 | SCLogError("pcre2_substring_copy_bynumber failed " |
333 | 1 | "for fast_pattern offset"); |
334 | 1 | goto error; |
335 | 1 | } |
336 | 123 | uint16_t length; |
337 | 123 | if (StringParseUint16(&length, 10, 0, (const char *)arg_substr) <= 0) { |
338 | 2 | SCLogError("Invalid value for fast " |
339 | 2 | "pattern: \"%s\"", |
340 | 2 | arg_substr); |
341 | 2 | goto error; |
342 | 2 | } |
343 | | |
344 | | // Avoiding integer overflow |
345 | 121 | if (offset > (65535 - length)) { |
346 | 1 | SCLogError("Fast pattern (length + offset) " |
347 | 1 | "exceeds limit pattern length limit"); |
348 | 1 | goto error; |
349 | 1 | } |
350 | | |
351 | 120 | if (offset + length > cd->content_len) { |
352 | 2 | SCLogError("Fast pattern (length + " |
353 | 2 | "offset (%u)) exceeds pattern length (%u)", |
354 | 2 | offset + length, cd->content_len); |
355 | 2 | goto error; |
356 | 2 | } |
357 | | |
358 | 118 | cd->fp_chop_offset = offset; |
359 | 118 | cd->fp_chop_len = length; |
360 | 118 | cd->flags |= DETECT_CONTENT_FAST_PATTERN_CHOP; |
361 | | |
362 | 189 | } else { |
363 | 189 | SCLogError("parse error, ret %" PRId32 ", string %s", ret, arg); |
364 | 189 | goto error; |
365 | 189 | } |
366 | | |
367 | 6.37k | cd->flags |= DETECT_CONTENT_FAST_PATTERN; |
368 | | |
369 | 6.37k | pcre2_match_data_free(match); |
370 | 6.37k | return 0; |
371 | | |
372 | 625 | error: |
373 | 625 | if (match) { |
374 | | pcre2_match_data_free(match); |
375 | 301 | } |
376 | 625 | return -1; |
377 | 6.67k | } |
378 | | |
379 | | /*----------------------------------Unittests---------------------------------*/ |
380 | | |
381 | | #ifdef UNITTESTS |
382 | | #include "detect-engine-alert.h" |
383 | | #include "detect-engine-buffer.h" |
384 | | static SigMatch *GetMatches(Signature *s, const int list) |
385 | | { |
386 | | SigMatch *sm = DetectBufferGetFirstSigMatch(s, list); |
387 | | if (sm == NULL && list < DETECT_SM_LIST_MAX) { |
388 | | sm = s->init_data->smlists[list]; |
389 | | } |
390 | | return sm; |
391 | | } |
392 | | |
393 | | static int DetectFastPatternStickySingle(const char *sticky, const int list) |
394 | | { |
395 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
396 | | FAIL_IF_NULL(de_ctx); |
397 | | char string[1024]; |
398 | | snprintf(string, sizeof(string), |
399 | | "alert tcp any any -> any any " |
400 | | "(%s%scontent:\"one\"; fast_pattern; sid:1;)", |
401 | | sticky ? sticky : "", sticky ? "; " : " "); |
402 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
403 | | FAIL_IF_NULL(s); |
404 | | SigMatch *sm = GetMatches(s, list); |
405 | | FAIL_IF_NULL(sm); |
406 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
407 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
408 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
409 | | FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN); |
410 | | DetectEngineCtxFree(de_ctx); |
411 | | PASS; |
412 | | } |
413 | | |
414 | | static int DetectFastPatternModifierSingle(const char *sticky, const int list) |
415 | | { |
416 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
417 | | FAIL_IF_NULL(de_ctx); |
418 | | char string[1024]; |
419 | | snprintf(string, sizeof(string), |
420 | | "alert tcp any any -> any any " |
421 | | "(content:\"one\"; %s%sfast_pattern; sid:1;)", |
422 | | sticky ? sticky : "", sticky ? "; " : " "); |
423 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
424 | | FAIL_IF_NULL(s); |
425 | | SigMatch *sm = GetMatches(s, list); |
426 | | FAIL_IF_NULL(sm); |
427 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
428 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
429 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
430 | | FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN); |
431 | | DetectEngineCtxFree(de_ctx); |
432 | | PASS; |
433 | | } |
434 | | |
435 | | static int DetectFastPatternStickySingleNoFP(const char *sticky, const int list) |
436 | | { |
437 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
438 | | FAIL_IF_NULL(de_ctx); |
439 | | char string[1024]; |
440 | | snprintf(string, sizeof(string), |
441 | | "alert tcp any any -> any any " |
442 | | "(%s%scontent:\"one\"; sid:1;)", |
443 | | sticky ? sticky : "", sticky ? "; " : " "); |
444 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
445 | | FAIL_IF_NULL(s); |
446 | | SigMatch *sm = GetMatches(s, list); |
447 | | FAIL_IF_NULL(sm); |
448 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
449 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
450 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
451 | | FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == 0); |
452 | | DetectEngineCtxFree(de_ctx); |
453 | | PASS; |
454 | | } |
455 | | |
456 | | static int DetectFastPatternModifierSingleNoFP(const char *sticky, const int list) |
457 | | { |
458 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
459 | | FAIL_IF_NULL(de_ctx); |
460 | | char string[1024]; |
461 | | snprintf(string, sizeof(string), |
462 | | "alert tcp any any -> any any " |
463 | | "(content:\"one\"; %s%ssid:1;)", |
464 | | sticky ? sticky : "", sticky ? "; " : " "); |
465 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
466 | | FAIL_IF_NULL(s); |
467 | | SigMatch *sm = GetMatches(s, list); |
468 | | FAIL_IF_NULL(sm); |
469 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
470 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
471 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
472 | | FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == 0); |
473 | | DetectEngineCtxFree(de_ctx); |
474 | | PASS; |
475 | | } |
476 | | |
477 | | static int DetectFastPatternStickySingleBadArg(const char *sticky) |
478 | | { |
479 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
480 | | FAIL_IF_NULL(de_ctx); |
481 | | char string[1024]; |
482 | | /* bogus argument to fast_pattern */ |
483 | | snprintf(string, sizeof(string), |
484 | | "alert tcp any any -> any any " |
485 | | "(%s%scontent:\"one\"; fast_pattern:boo; sid:1;)", |
486 | | sticky ? sticky : "", sticky ? "; " : " "); |
487 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
488 | | FAIL_IF_NOT_NULL(s); |
489 | | /* fast_pattern only with distance */ |
490 | | snprintf(string, sizeof(string), |
491 | | "alert tcp any any -> any any " |
492 | | "(%s%scontent:\"one\"; fast_pattern:only; content:\"two\"; distance:10; sid:1;)", |
493 | | sticky ? sticky : "", sticky ? "; " : " "); |
494 | | s = DetectEngineAppendSig(de_ctx, string); |
495 | | FAIL_IF_NOT_NULL(s); |
496 | | /* fast_pattern only with distance */ |
497 | | snprintf(string, sizeof(string), |
498 | | "alert tcp any any -> any any " |
499 | | "(%s%scontent:\"one\"; content:\"two\"; fast_pattern:only; distance:10; sid:1;)", |
500 | | sticky ? sticky : "", sticky ? "; " : " "); |
501 | | s = DetectEngineAppendSig(de_ctx, string); |
502 | | FAIL_IF_NOT_NULL(s); |
503 | | /* fast_pattern only with distance */ |
504 | | snprintf(string, sizeof(string), |
505 | | "alert tcp any any -> any any " |
506 | | "(%s%scontent:\"one\"; content:\"two\"; distance:10; fast_pattern:only; sid:1;)", |
507 | | sticky ? sticky : "", sticky ? "; " : " "); |
508 | | s = DetectEngineAppendSig(de_ctx, string); |
509 | | FAIL_IF_NOT_NULL(s); |
510 | | /* fast_pattern chop with invalid values */ |
511 | | snprintf(string, sizeof(string), |
512 | | "alert tcp any any -> any any " |
513 | | "(%s%scontent:\"one\"; fast_pattern:5,6; sid:1;)", |
514 | | sticky ? sticky : "", sticky ? "; " : " "); |
515 | | s = DetectEngineAppendSig(de_ctx, string); |
516 | | FAIL_IF_NOT_NULL(s); |
517 | | DetectEngineCtxFree(de_ctx); |
518 | | PASS; |
519 | | } |
520 | | |
521 | | static int DetectFastPatternModifierBadRules(const char *sticky) |
522 | | { |
523 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
524 | | FAIL_IF_NULL(de_ctx); |
525 | | char string[1024]; |
526 | | /* bogus argument to fast_pattern */ |
527 | | snprintf(string, sizeof(string), |
528 | | "alert tcp any any -> any any " |
529 | | "(content:\"one\"; %s%sfast_pattern:boo; sid:1;)", |
530 | | sticky ? sticky : "", sticky ? "; " : " "); |
531 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
532 | | FAIL_IF_NOT_NULL(s); |
533 | | /* fast_pattern only with distance */ |
534 | | snprintf(string, sizeof(string), |
535 | | "alert tcp any any -> any any " |
536 | | "(content:\"one\"; %s%sfast_pattern:only; content:\"two\"; %s%sdistance:10; sid:1;)", |
537 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
538 | | s = DetectEngineAppendSig(de_ctx, string); |
539 | | FAIL_IF_NOT_NULL(s); |
540 | | #if 0 // TODO bug? |
541 | | /* fast_pattern only with distance */ |
542 | | snprintf(string, sizeof(string), "alert tcp any any -> any any " |
543 | | "(content:\"one\"; %s%s content:\"two\"; %s%sdistance:10; fast_pattern:only; sid:1;)", |
544 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
545 | | s = DetectEngineAppendSig(de_ctx, string); |
546 | | FAIL_IF_NOT_NULL(s); |
547 | | #endif |
548 | | /* fast_pattern only with within */ |
549 | | snprintf(string, sizeof(string), |
550 | | "alert tcp any any -> any any " |
551 | | "(content:\"one\"; %s%sfast_pattern:only; content:\"two\"; %s%swithin:10; sid:1;)", |
552 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
553 | | s = DetectEngineAppendSig(de_ctx, string); |
554 | | FAIL_IF_NOT_NULL(s); |
555 | | /* fast_pattern only with within */ |
556 | | snprintf(string, sizeof(string), |
557 | | "alert tcp any any -> any any " |
558 | | "(content:\"one\"; %s%s content:\"two\"; %s%swithin:10; fast_pattern:only; sid:1;)", |
559 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
560 | | s = DetectEngineAppendSig(de_ctx, string); |
561 | | FAIL_IF_NOT_NULL(s); |
562 | | /* fast_pattern only with offset */ |
563 | | snprintf(string, sizeof(string), |
564 | | "alert tcp any any -> any any " |
565 | | "(content:\"one\"; %s%sfast_pattern:only; offset:10; sid:1;)", |
566 | | sticky ? sticky : "", sticky ? "; " : " "); |
567 | | s = DetectEngineAppendSig(de_ctx, string); |
568 | | FAIL_IF_NOT_NULL(s); |
569 | | /* fast_pattern only with offset */ |
570 | | snprintf(string, sizeof(string), |
571 | | "alert tcp any any -> any any " |
572 | | "(content:\"one\"; %s%s offset:10; fast_pattern:only; sid:1;)", |
573 | | sticky ? sticky : "", sticky ? "; " : " "); |
574 | | s = DetectEngineAppendSig(de_ctx, string); |
575 | | FAIL_IF_NOT_NULL(s); |
576 | | /* fast_pattern only with depth */ |
577 | | snprintf(string, sizeof(string), |
578 | | "alert tcp any any -> any any " |
579 | | "(content:\"one\"; %s%sfast_pattern:only; depth:10; sid:1;)", |
580 | | sticky ? sticky : "", sticky ? "; " : " "); |
581 | | s = DetectEngineAppendSig(de_ctx, string); |
582 | | FAIL_IF_NOT_NULL(s); |
583 | | /* fast_pattern only with depth */ |
584 | | snprintf(string, sizeof(string), |
585 | | "alert tcp any any -> any any " |
586 | | "(content:\"one\"; %s%s depth:10; fast_pattern:only; sid:1;)", |
587 | | sticky ? sticky : "", sticky ? "; " : " "); |
588 | | s = DetectEngineAppendSig(de_ctx, string); |
589 | | FAIL_IF_NOT_NULL(s); |
590 | | /* fast_pattern only negate */ |
591 | | snprintf(string, sizeof(string), |
592 | | "alert tcp any any -> any any " |
593 | | "(content:\"one\"; %s%s content:!\"two\"; %s%sfast_pattern:only; sid:1;)", |
594 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
595 | | s = DetectEngineAppendSig(de_ctx, string); |
596 | | FAIL_IF_NOT_NULL(s); |
597 | | /* fast_pattern chop with invalid values */ |
598 | | snprintf(string, sizeof(string), |
599 | | "alert tcp any any -> any any " |
600 | | "(content:\"one\"; %s%sfast_pattern:5,6; sid:1;)", |
601 | | sticky ? sticky : "", sticky ? "; " : " "); |
602 | | s = DetectEngineAppendSig(de_ctx, string); |
603 | | FAIL_IF_NOT_NULL(s); |
604 | | /* fast_pattern chop with invalid values */ |
605 | | snprintf(string, sizeof(string), |
606 | | "alert tcp any any -> any any " |
607 | | "(content:\"one\"; %s%sfast_pattern:65977,2; sid:1;)", |
608 | | sticky ? sticky : "", sticky ? "; " : " "); |
609 | | s = DetectEngineAppendSig(de_ctx, string); |
610 | | FAIL_IF_NOT_NULL(s); |
611 | | /* fast_pattern chop with invalid values */ |
612 | | snprintf(string, sizeof(string), |
613 | | "alert tcp any any -> any any " |
614 | | "(content:\"one\"; %s%sfast_pattern:2,65977; sid:1;)", |
615 | | sticky ? sticky : "", sticky ? "; " : " "); |
616 | | s = DetectEngineAppendSig(de_ctx, string); |
617 | | FAIL_IF_NOT_NULL(s); |
618 | | /* fast_pattern chop with invalid values */ |
619 | | snprintf(string, sizeof(string), |
620 | | "alert tcp any any -> any any " |
621 | | "(content:\"one\"; %s%sfast_pattern:2,65534; sid:1;)", |
622 | | sticky ? sticky : "", sticky ? "; " : " "); |
623 | | s = DetectEngineAppendSig(de_ctx, string); |
624 | | FAIL_IF_NOT_NULL(s); |
625 | | /* fast_pattern chop with invalid values */ |
626 | | snprintf(string, sizeof(string), |
627 | | "alert tcp any any -> any any " |
628 | | "(content:\"one\"; %s%sfast_pattern:65534,2; sid:1;)", |
629 | | sticky ? sticky : "", sticky ? "; " : " "); |
630 | | s = DetectEngineAppendSig(de_ctx, string); |
631 | | FAIL_IF_NOT_NULL(s); |
632 | | /* negated fast_pattern with distance */ |
633 | | snprintf(string, sizeof(string), |
634 | | "alert tcp any any -> any any " |
635 | | "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%sdistance:10; sid:1;)", |
636 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
637 | | s = DetectEngineAppendSig(de_ctx, string); |
638 | | FAIL_IF_NOT_NULL(s); |
639 | | /* negated fast_pattern with within */ |
640 | | snprintf(string, sizeof(string), |
641 | | "alert tcp any any -> any any " |
642 | | "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%swithin:10; sid:1;)", |
643 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
644 | | s = DetectEngineAppendSig(de_ctx, string); |
645 | | FAIL_IF_NOT_NULL(s); |
646 | | /* negated fast_pattern with depth */ |
647 | | snprintf(string, sizeof(string), |
648 | | "alert tcp any any -> any any " |
649 | | "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%sdepth:10; sid:1;)", |
650 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
651 | | s = DetectEngineAppendSig(de_ctx, string); |
652 | | FAIL_IF_NOT_NULL(s); |
653 | | /* negated fast_pattern with offset */ |
654 | | snprintf(string, sizeof(string), |
655 | | "alert tcp any any -> any any " |
656 | | "(content:\"one\"; %s%scontent:!\"two\"; fast_pattern:1,2; %s%soffset:10; sid:1;)", |
657 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
658 | | s = DetectEngineAppendSig(de_ctx, string); |
659 | | FAIL_IF_NOT_NULL(s); |
660 | | DetectEngineCtxFree(de_ctx); |
661 | | PASS; |
662 | | } |
663 | | |
664 | | static int DetectFastPatternStickySingleFPOnly(const char *sticky, const int list) |
665 | | { |
666 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
667 | | FAIL_IF_NULL(de_ctx); |
668 | | char string[1024]; |
669 | | snprintf(string, sizeof(string), |
670 | | "alert tcp any any -> any any " |
671 | | "(%s%scontent:\"one\"; fast_pattern:only; sid:1;)", |
672 | | sticky ? sticky : "", sticky ? "; " : " "); |
673 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
674 | | FAIL_IF_NULL(s); |
675 | | SigMatch *sm = GetMatches(s, list); |
676 | | FAIL_IF_NULL(sm); |
677 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
678 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
679 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
680 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
681 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
682 | | DetectEngineCtxFree(de_ctx); |
683 | | PASS; |
684 | | } |
685 | | |
686 | | static int DetectFastPatternModifierFPOnly(const char *sticky, const int list) |
687 | | { |
688 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
689 | | FAIL_IF_NULL(de_ctx); |
690 | | char string[1024]; |
691 | | snprintf(string, sizeof(string), |
692 | | "alert tcp any any -> any any " |
693 | | "(content:\"one\"; %s%sfast_pattern:only; sid:1;)", |
694 | | sticky ? sticky : "", sticky ? "; " : " "); |
695 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
696 | | FAIL_IF_NULL(s); |
697 | | SigMatch *sm = GetMatches(s, list); |
698 | | FAIL_IF_NULL(sm); |
699 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
700 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
701 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
702 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
703 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
704 | | |
705 | | snprintf(string, sizeof(string), |
706 | | "alert tcp any any -> any any " |
707 | | "(content:\"one\"; %s%scontent:\"two\"; %s%sfast_pattern:only; sid:2;)", |
708 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
709 | | s = DetectEngineAppendSig(de_ctx, string); |
710 | | FAIL_IF_NULL(s); |
711 | | sm = GetMatches(s, list); |
712 | | FAIL_IF_NULL(sm); |
713 | | FAIL_IF_NULL(sm->next); |
714 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
715 | | cd = (DetectContentData *)sm->ctx; |
716 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
717 | | FAIL_IF_NOT( |
718 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
719 | | sm = sm->next; |
720 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
721 | | cd = (DetectContentData *)sm->ctx; |
722 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
723 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
724 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
725 | | |
726 | | snprintf(string, sizeof(string), |
727 | | "alert tcp any any -> any any " |
728 | | "(content:\"one\"; %s%scontent:\"two\"; distance:10; %s%scontent:\"three\"; " |
729 | | "%s%sfast_pattern:only; sid:3;)", |
730 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", |
731 | | sticky ? sticky : "", sticky ? "; " : " "); |
732 | | s = DetectEngineAppendSig(de_ctx, string); |
733 | | FAIL_IF_NULL(s); |
734 | | sm = GetMatches(s, list); |
735 | | FAIL_IF_NULL(sm); |
736 | | FAIL_IF_NULL(sm->next); |
737 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
738 | | cd = (DetectContentData *)sm->ctx; |
739 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
740 | | FAIL_IF_NOT( |
741 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
742 | | sm = sm->next; |
743 | | FAIL_IF_NULL(sm->next); |
744 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
745 | | cd = (DetectContentData *)sm->ctx; |
746 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
747 | | FAIL_IF_NOT( |
748 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
749 | | sm = sm->next; |
750 | | FAIL_IF_NOT_NULL(sm->next); |
751 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
752 | | cd = (DetectContentData *)sm->ctx; |
753 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
754 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
755 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
756 | | |
757 | | snprintf(string, sizeof(string), |
758 | | "alert tcp any any -> any any " |
759 | | "(content:\"one\"; %s%scontent:\"two\"; within:10; %s%scontent:\"three\"; " |
760 | | "%s%sfast_pattern:only; sid:4;)", |
761 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", |
762 | | sticky ? sticky : "", sticky ? "; " : " "); |
763 | | s = DetectEngineAppendSig(de_ctx, string); |
764 | | FAIL_IF_NULL(s); |
765 | | sm = GetMatches(s, list); |
766 | | FAIL_IF_NULL(sm); |
767 | | FAIL_IF_NULL(sm->next); |
768 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
769 | | cd = (DetectContentData *)sm->ctx; |
770 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
771 | | FAIL_IF_NOT( |
772 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
773 | | sm = sm->next; |
774 | | FAIL_IF_NULL(sm->next); |
775 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
776 | | cd = (DetectContentData *)sm->ctx; |
777 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
778 | | FAIL_IF_NOT( |
779 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
780 | | sm = sm->next; |
781 | | FAIL_IF_NOT_NULL(sm->next); |
782 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
783 | | cd = (DetectContentData *)sm->ctx; |
784 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
785 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
786 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
787 | | |
788 | | snprintf(string, sizeof(string), |
789 | | "alert tcp any any -> any any " |
790 | | "(content:\"one\"; %s%scontent:\"two\"; offset:10; %s%scontent:\"three\"; " |
791 | | "%s%sfast_pattern:only; sid:5;)", |
792 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", |
793 | | sticky ? sticky : "", sticky ? "; " : " "); |
794 | | s = DetectEngineAppendSig(de_ctx, string); |
795 | | FAIL_IF_NULL(s); |
796 | | sm = GetMatches(s, list); |
797 | | FAIL_IF_NULL(sm); |
798 | | FAIL_IF_NULL(sm->next); |
799 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
800 | | cd = (DetectContentData *)sm->ctx; |
801 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
802 | | FAIL_IF_NOT( |
803 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
804 | | sm = sm->next; |
805 | | FAIL_IF_NULL(sm->next); |
806 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
807 | | cd = (DetectContentData *)sm->ctx; |
808 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
809 | | FAIL_IF_NOT( |
810 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
811 | | sm = sm->next; |
812 | | FAIL_IF_NOT_NULL(sm->next); |
813 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
814 | | cd = (DetectContentData *)sm->ctx; |
815 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
816 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
817 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
818 | | |
819 | | snprintf(string, sizeof(string), |
820 | | "alert tcp any any -> any any " |
821 | | "(content:\"one\"; %s%scontent:\"two\"; depth:10; %s%scontent:\"three\"; " |
822 | | "%s%sfast_pattern:only; sid:6;)", |
823 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " ", |
824 | | sticky ? sticky : "", sticky ? "; " : " "); |
825 | | s = DetectEngineAppendSig(de_ctx, string); |
826 | | FAIL_IF_NULL(s); |
827 | | sm = GetMatches(s, list); |
828 | | FAIL_IF_NULL(sm); |
829 | | FAIL_IF_NULL(sm->next); |
830 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
831 | | cd = (DetectContentData *)sm->ctx; |
832 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
833 | | FAIL_IF_NOT( |
834 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
835 | | sm = sm->next; |
836 | | FAIL_IF_NULL(sm->next); |
837 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
838 | | cd = (DetectContentData *)sm->ctx; |
839 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
840 | | FAIL_IF_NOT( |
841 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
842 | | sm = sm->next; |
843 | | FAIL_IF_NOT_NULL(sm->next); |
844 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
845 | | cd = (DetectContentData *)sm->ctx; |
846 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
847 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
848 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)); |
849 | | |
850 | | snprintf(string, sizeof(string), |
851 | | "alert tcp any any -> any any " |
852 | | "(content:!\"one\"; %s%sfast_pattern; content:\"two\"; depth:10; %s%ssid:7;)", |
853 | | sticky ? sticky : "", sticky ? "; " : " ", sticky ? sticky : "", sticky ? "; " : " "); |
854 | | s = DetectEngineAppendSig(de_ctx, string); |
855 | | FAIL_IF_NULL(s); |
856 | | sm = GetMatches(s, list); |
857 | | FAIL_IF_NULL(sm); |
858 | | FAIL_IF_NULL(sm->next); |
859 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
860 | | cd = (DetectContentData *)sm->ctx; |
861 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
862 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY | |
863 | | DETECT_CONTENT_NEGATED)) == |
864 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_NEGATED)); |
865 | | sm = sm->next; |
866 | | FAIL_IF_NOT_NULL(sm->next); |
867 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
868 | | cd = (DetectContentData *)sm->ctx; |
869 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
870 | | FAIL_IF_NOT( |
871 | | (cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_ONLY)) == 0); |
872 | | |
873 | | DetectEngineCtxFree(de_ctx); |
874 | | PASS; |
875 | | } |
876 | | |
877 | | static int DetectFastPatternStickyFPChop(const char *sticky, const int list) |
878 | | { |
879 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
880 | | FAIL_IF_NULL(de_ctx); |
881 | | char string[1024]; |
882 | | snprintf(string, sizeof(string), |
883 | | "alert tcp any any -> any any " |
884 | | "(%s%scontent:\"onetwothree\"; fast_pattern:3,4; sid:1;)", |
885 | | sticky ? sticky : "", sticky ? "; " : " "); |
886 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
887 | | FAIL_IF_NULL(s); |
888 | | SigMatch *sm = GetMatches(s, list); |
889 | | FAIL_IF_NULL(sm); |
890 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
891 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
892 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
893 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | |
894 | | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
895 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); |
896 | | FAIL_IF_NOT(cd->fp_chop_offset == 3); |
897 | | FAIL_IF_NOT(cd->fp_chop_len == 4); |
898 | | |
899 | | snprintf(string, sizeof(string), |
900 | | "alert tcp any any -> any any " |
901 | | "(%s%scontent:\"onetwothree\"; fast_pattern:3,4; content:\"xyz\"; distance:10; sid:2;)", |
902 | | sticky ? sticky : "", sticky ? "; " : " "); |
903 | | s = DetectEngineAppendSig(de_ctx, string); |
904 | | FAIL_IF_NULL(s); |
905 | | sm = GetMatches(s, list); |
906 | | FAIL_IF_NULL(sm); |
907 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
908 | | cd = (DetectContentData *)sm->ctx; |
909 | | FAIL_IF(DETECT_CONTENT_IS_SINGLE(cd)); |
910 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | |
911 | | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
912 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); |
913 | | FAIL_IF_NOT(cd->fp_chop_offset == 3); |
914 | | FAIL_IF_NOT(cd->fp_chop_len == 4); |
915 | | |
916 | | DetectEngineCtxFree(de_ctx); |
917 | | PASS; |
918 | | } |
919 | | |
920 | | static int DetectFastPatternModifierFPChop(const char *sticky, const int list) |
921 | | { |
922 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
923 | | FAIL_IF_NULL(de_ctx); |
924 | | char string[1024]; |
925 | | snprintf(string, sizeof(string), |
926 | | "alert tcp any any -> any any " |
927 | | "(content:\"onetwothree\"; %s%sfast_pattern:3,4; sid:1;)", |
928 | | sticky ? sticky : "", sticky ? "; " : " "); |
929 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
930 | | FAIL_IF_NULL(s); |
931 | | SigMatch *sm = GetMatches(s, list); |
932 | | FAIL_IF_NULL(sm); |
933 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
934 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
935 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
936 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP | |
937 | | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
938 | | (DETECT_CONTENT_FAST_PATTERN | DETECT_CONTENT_FAST_PATTERN_CHOP)); |
939 | | FAIL_IF_NOT(cd->fp_chop_offset == 3); |
940 | | FAIL_IF_NOT(cd->fp_chop_len == 4); |
941 | | |
942 | | snprintf(string, sizeof(string), |
943 | | "alert tcp any any -> any any " |
944 | | "(content:!\"onetwothree\"; %s%sfast_pattern:3,4; sid:2;)", |
945 | | sticky ? sticky : "", sticky ? "; " : " "); |
946 | | s = DetectEngineAppendSig(de_ctx, string); |
947 | | FAIL_IF_NULL(s); |
948 | | sm = GetMatches(s, list); |
949 | | FAIL_IF_NULL(sm); |
950 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
951 | | cd = (DetectContentData *)sm->ctx; |
952 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
953 | | FAIL_IF_NOT((cd->flags & (DETECT_CONTENT_NEGATED | DETECT_CONTENT_FAST_PATTERN | |
954 | | DETECT_CONTENT_FAST_PATTERN_CHOP | |
955 | | DETECT_CONTENT_FAST_PATTERN_ONLY)) == |
956 | | (DETECT_CONTENT_NEGATED | DETECT_CONTENT_FAST_PATTERN | |
957 | | DETECT_CONTENT_FAST_PATTERN_CHOP)); |
958 | | FAIL_IF_NOT(cd->fp_chop_offset == 3); |
959 | | FAIL_IF_NOT(cd->fp_chop_len == 4); |
960 | | |
961 | | DetectEngineCtxFree(de_ctx); |
962 | | PASS; |
963 | | } |
964 | | |
965 | | /** |
966 | | * \test Checks if a fast_pattern is registered in a Signature |
967 | | */ |
968 | | static int DetectFastPatternTest01(void) |
969 | | { |
970 | | FAIL_IF_NOT(DetectFastPatternStickySingle(NULL, DETECT_SM_LIST_PMATCH)); |
971 | | FAIL_IF_NOT(DetectFastPatternModifierSingle(NULL, DETECT_SM_LIST_PMATCH)); |
972 | | FAIL_IF_NOT(DetectFastPatternStickySingleNoFP(NULL, DETECT_SM_LIST_PMATCH)); |
973 | | FAIL_IF_NOT(DetectFastPatternModifierSingleNoFP(NULL, DETECT_SM_LIST_PMATCH)); |
974 | | FAIL_IF_NOT(DetectFastPatternStickySingleBadArg(NULL)); |
975 | | FAIL_IF_NOT(DetectFastPatternModifierBadRules(NULL)); |
976 | | FAIL_IF_NOT(DetectFastPatternStickySingleFPOnly(NULL, DETECT_SM_LIST_PMATCH)); |
977 | | FAIL_IF_NOT(DetectFastPatternModifierFPOnly(NULL, DETECT_SM_LIST_PMATCH)); |
978 | | FAIL_IF_NOT(DetectFastPatternStickyFPChop(NULL, DETECT_SM_LIST_PMATCH)); |
979 | | FAIL_IF_NOT(DetectFastPatternModifierFPChop(NULL, DETECT_SM_LIST_PMATCH)); |
980 | | |
981 | | struct { |
982 | | const char *buffer_name; |
983 | | const char *sb_name; |
984 | | const char *mod_name; |
985 | | } keywords[] = { |
986 | | { "file_data", "file.data", NULL }, |
987 | | { "http_uri", "http.uri", "http_uri" }, |
988 | | { "http_raw_uri", "http.uri.raw", "http_raw_uri" }, |
989 | | { "http_user_agent", "http.user_agent", "http_user_agent" }, |
990 | | { "http_header", "http.header", "http_header" }, |
991 | | // http_raw_header requires sigs to have a direction |
992 | | //{ "http_raw_header", "http.header.raw", "http_raw_header" }, |
993 | | { "http_method", "http.method", "http_method" }, |
994 | | { "http_cookie", "http.cookie", "http_cookie" }, |
995 | | { "http_host", "http.host", "http_host" }, |
996 | | { "http_raw_host", "http.host.raw", "http_raw_host" }, |
997 | | { "http_stat_code", "http.stat_code", "http_stat_code" }, |
998 | | { "http_stat_msg", "http.stat_msg", "http_stat_msg" }, |
999 | | { "http_client_body", "http.request_body", "http_client_body" }, |
1000 | | { NULL, NULL, NULL }, |
1001 | | }; |
1002 | | |
1003 | | for (int i = 0; keywords[i].buffer_name != NULL; i++) { |
1004 | | const int list_id = DetectBufferTypeGetByName(keywords[i].buffer_name); |
1005 | | FAIL_IF(list_id == -1); |
1006 | | |
1007 | | const char *k = keywords[i].sb_name; |
1008 | | if (k) { |
1009 | | FAIL_IF_NOT(DetectFastPatternStickySingle(k, list_id)); |
1010 | | FAIL_IF_NOT(DetectFastPatternStickySingleNoFP(k, list_id)); |
1011 | | FAIL_IF_NOT(DetectFastPatternStickySingleBadArg(k)); |
1012 | | FAIL_IF_NOT(DetectFastPatternStickySingleFPOnly(k, list_id)); |
1013 | | FAIL_IF_NOT(DetectFastPatternStickyFPChop(k, list_id)); |
1014 | | } |
1015 | | k = keywords[i].mod_name; |
1016 | | if (k) { |
1017 | | FAIL_IF_NOT(DetectFastPatternModifierSingle(k, list_id)); |
1018 | | FAIL_IF_NOT(DetectFastPatternModifierSingleNoFP(k, list_id)); |
1019 | | FAIL_IF_NOT(DetectFastPatternModifierBadRules(k)); |
1020 | | FAIL_IF_NOT(DetectFastPatternModifierFPOnly(k, list_id)); |
1021 | | FAIL_IF_NOT(DetectFastPatternModifierFPChop(k, list_id)); |
1022 | | } |
1023 | | } |
1024 | | |
1025 | | PASS; |
1026 | | } |
1027 | | |
1028 | | /** |
1029 | | * \test Checks to make sure that other sigs work that should when fast_pattern is inspecting on the |
1030 | | * same payload |
1031 | | * |
1032 | | */ |
1033 | | static int DetectFastPatternTest14(void) |
1034 | | { |
1035 | | uint8_t *buf = (uint8_t *)"Dummy is our name. Oh yes. From right here " |
1036 | | "right now, all the way to hangover. right. strings5_imp now here " |
1037 | | "comes our dark knight strings_string5. Yes here is our dark knight"; |
1038 | | uint16_t buflen = strlen((char *)buf); |
1039 | | ThreadVars th_v; |
1040 | | DetectEngineThreadCtx *det_ctx = NULL; |
1041 | | |
1042 | | memset(&th_v, 0, sizeof(th_v)); |
1043 | | Packet *p = UTHBuildPacket(buf, buflen, IPPROTO_TCP); |
1044 | | FAIL_IF_NULL(p); |
1045 | | |
1046 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
1047 | | FAIL_IF_NULL(de_ctx); |
1048 | | de_ctx->flags |= DE_QUIET; |
1049 | | |
1050 | | FlowInitConfig(FLOW_QUIET); |
1051 | | |
1052 | | Signature *s = DetectEngineAppendSig(de_ctx, |
1053 | | "alert tcp any any -> any any " |
1054 | | "(msg:\"fast_pattern test\"; content:\"strings_string5\"; content:\"knight\"; " |
1055 | | "fast_pattern; sid:1;)"); |
1056 | | FAIL_IF_NULL(s); |
1057 | | |
1058 | | s = DetectEngineAppendSig(de_ctx, |
1059 | | "alert tcp any any -> any any " |
1060 | | "(msg:\"test different content\"; content:\"Dummy is our name\"; sid:2;)"); |
1061 | | FAIL_IF_NULL(s); |
1062 | | |
1063 | | SigGroupBuild(de_ctx); |
1064 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
1065 | | |
1066 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
1067 | | FAIL_IF_NOT(PacketAlertCheck(p, 1)); |
1068 | | FAIL_IF_NOT(PacketAlertCheck(p, 2)); |
1069 | | |
1070 | | UTHFreePackets(&p, 1); |
1071 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
1072 | | DetectEngineCtxFree(de_ctx); |
1073 | | FlowShutdown(); |
1074 | | PASS; |
1075 | | } |
1076 | | |
1077 | | /** |
1078 | | * Unittest to check |
1079 | | * - if we assign different content_ids to duplicate patterns, but one of the |
1080 | | * patterns has a fast_pattern chop set. |
1081 | | * - if 2 unique patterns get unique ids. |
1082 | | * - if 2 duplicate patterns, with no chop set get unique ids. |
1083 | | */ |
1084 | | static int DetectFastPatternTest671(void) |
1085 | | { |
1086 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
1087 | | FAIL_IF_NULL(de_ctx); |
1088 | | de_ctx->flags |= DE_QUIET; |
1089 | | |
1090 | | Signature *s[6]; |
1091 | | s[0] = DetectEngineAppendSig( |
1092 | | de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; sid:1;)"); |
1093 | | FAIL_IF_NULL(s[0]); |
1094 | | s[1] = DetectEngineAppendSig( |
1095 | | de_ctx, "alert tcp any any -> any any (content:\"onetwothreefour\"; sid:2;)"); |
1096 | | FAIL_IF_NULL(s[1]); |
1097 | | s[2] = DetectEngineAppendSig( |
1098 | | de_ctx, "alert tcp any any -> any any (content:\"uniquepattern\"; sid:3;)"); |
1099 | | FAIL_IF_NULL(s[2]); |
1100 | | s[3] = DetectEngineAppendSig(de_ctx, |
1101 | | "alert tcp any any -> any any (content:\"onetwothreefour\"; fast_pattern:3,5; sid:4;)"); |
1102 | | FAIL_IF_NULL(s[3]); |
1103 | | s[4] = DetectEngineAppendSig( |
1104 | | de_ctx, "alert tcp any any -> any any (content:\"twoth\"; sid:5;)"); |
1105 | | FAIL_IF_NULL(s[4]); |
1106 | | s[5] = DetectEngineAppendSig(de_ctx, |
1107 | | "alert tcp any any -> any any (content:\"onetwothreefour\"; fast_pattern:0,15; " |
1108 | | "sid:6;)"); |
1109 | | FAIL_IF_NULL(s[5]); |
1110 | | |
1111 | | SigGroupBuild(de_ctx); |
1112 | | |
1113 | | SigMatchData *smd = s[0]->sm_arrays[DETECT_SM_LIST_PMATCH]; |
1114 | | DetectContentData *cd = (DetectContentData *)smd->ctx; |
1115 | | FAIL_IF(cd->id != 0); |
1116 | | |
1117 | | smd = s[1]->sm_arrays[DETECT_SM_LIST_PMATCH]; |
1118 | | cd = (DetectContentData *)smd->ctx; |
1119 | | FAIL_IF(cd->id != 0); |
1120 | | |
1121 | | smd = s[2]->sm_arrays[DETECT_SM_LIST_PMATCH]; |
1122 | | cd = (DetectContentData *)smd->ctx; |
1123 | | FAIL_IF(cd->id != 2); |
1124 | | |
1125 | | smd = s[3]->sm_arrays[DETECT_SM_LIST_PMATCH]; |
1126 | | cd = (DetectContentData *)smd->ctx; |
1127 | | FAIL_IF(cd->id != 1); |
1128 | | |
1129 | | smd = s[4]->sm_arrays[DETECT_SM_LIST_PMATCH]; |
1130 | | cd = (DetectContentData *)smd->ctx; |
1131 | | FAIL_IF(cd->id != 1); |
1132 | | |
1133 | | smd = s[5]->sm_arrays[DETECT_SM_LIST_PMATCH]; |
1134 | | cd = (DetectContentData *)smd->ctx; |
1135 | | FAIL_IF(cd->id != 0); |
1136 | | |
1137 | | DetectEngineCtxFree(de_ctx); |
1138 | | PASS; |
1139 | | } |
1140 | | |
1141 | | static int DetectFastPatternPrefilter(void) |
1142 | | { |
1143 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
1144 | | FAIL_IF_NULL(de_ctx); |
1145 | | const char *string = "alert tcp any any -> any any " |
1146 | | "(content:\"one\"; prefilter; sid:1;)"; |
1147 | | Signature *s = DetectEngineAppendSig(de_ctx, string); |
1148 | | FAIL_IF_NULL(s); |
1149 | | SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; |
1150 | | FAIL_IF_NULL(sm); |
1151 | | FAIL_IF_NOT(sm->type == DETECT_CONTENT); |
1152 | | DetectContentData *cd = (DetectContentData *)sm->ctx; |
1153 | | FAIL_IF_NOT(DETECT_CONTENT_IS_SINGLE(cd)); |
1154 | | FAIL_IF_NOT((cd->flags & DETECT_CONTENT_FAST_PATTERN) == DETECT_CONTENT_FAST_PATTERN); |
1155 | | DetectEngineCtxFree(de_ctx); |
1156 | | PASS; |
1157 | | } |
1158 | | |
1159 | | static void DetectFastPatternRegisterTests(void) |
1160 | | { |
1161 | | UtRegisterTest("DetectFastPatternTest01", DetectFastPatternTest01); |
1162 | | UtRegisterTest("DetectFastPatternTest14", DetectFastPatternTest14); |
1163 | | /* Unittest to check |
1164 | | * - if we assign different content_ids to duplicate patterns, but one of the |
1165 | | * patterns has a fast_pattern chop set. |
1166 | | * - if 2 unique patterns get unique ids. |
1167 | | * - if 2 duplicate patterns, with no chop set get unique ids. |
1168 | | */ |
1169 | | UtRegisterTest("DetectFastPatternTest671", DetectFastPatternTest671); |
1170 | | |
1171 | | UtRegisterTest("DetectFastPatternPrefilter", DetectFastPatternPrefilter); |
1172 | | } |
1173 | | #endif |