/src/suricata7/src/detect-engine-siggroup.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 Victor Julien <victor@inliniac.net> |
22 | | * |
23 | | * Signature grouping part of the detection engine. |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "decode.h" |
28 | | |
29 | | #include "flow-var.h" |
30 | | |
31 | | #include "app-layer-protos.h" |
32 | | |
33 | | #include "detect.h" |
34 | | #include "detect-parse.h" |
35 | | #include "detect-engine.h" |
36 | | #include "detect-engine-build.h" |
37 | | #include "detect-engine-address.h" |
38 | | #include "detect-engine-mpm.h" |
39 | | #include "detect-engine-siggroup.h" |
40 | | #include "detect-engine-prefilter.h" |
41 | | |
42 | | #include "detect-content.h" |
43 | | #include "detect-uricontent.h" |
44 | | #include "detect-tcp-flags.h" |
45 | | |
46 | | #include "util-hash.h" |
47 | | #include "util-hashlist.h" |
48 | | |
49 | | #include "util-error.h" |
50 | | #include "util-debug.h" |
51 | | #include "util-validate.h" |
52 | | #include "util-cidr.h" |
53 | | #include "util-unittest.h" |
54 | | #include "util-unittest-helper.h" |
55 | | #include "util-memcmp.h" |
56 | | |
57 | | /* prototypes */ |
58 | | int SigGroupHeadClearSigs(SigGroupHead *); |
59 | | |
60 | | void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) |
61 | 10.6M | { |
62 | 10.6M | if (sghid->match_array != NULL) { |
63 | 226k | SCFree(sghid->match_array); |
64 | 226k | sghid->match_array = NULL; |
65 | 226k | } |
66 | 10.6M | if (sghid->sig_array != NULL) { |
67 | 10.6M | SCFreeAligned(sghid->sig_array); |
68 | 10.6M | sghid->sig_array = NULL; |
69 | 10.6M | } |
70 | 10.6M | if (sghid->app_mpms != NULL) { |
71 | 225k | SCFree(sghid->app_mpms); |
72 | 225k | } |
73 | 10.6M | if (sghid->pkt_mpms != NULL) { |
74 | 225k | SCFree(sghid->pkt_mpms); |
75 | 225k | } |
76 | 10.6M | if (sghid->frame_mpms != NULL) { |
77 | 225k | SCFree(sghid->frame_mpms); |
78 | 225k | } |
79 | | |
80 | 10.6M | PrefilterFreeEnginesList(sghid->tx_engines); |
81 | 10.6M | PrefilterFreeEnginesList(sghid->pkt_engines); |
82 | 10.6M | PrefilterFreeEnginesList(sghid->payload_engines); |
83 | 10.6M | PrefilterFreeEnginesList(sghid->frame_engines); |
84 | | |
85 | 10.6M | SCFree(sghid); |
86 | 10.6M | } |
87 | | |
88 | | static SigGroupHeadInitData *SigGroupHeadInitDataAlloc(uint32_t size) |
89 | 10.6M | { |
90 | 10.6M | SigGroupHeadInitData *sghid = SCMalloc(sizeof(SigGroupHeadInitData)); |
91 | 10.6M | if (unlikely(sghid == NULL)) |
92 | 0 | return NULL; |
93 | | |
94 | 10.6M | memset(sghid, 0x00, sizeof(SigGroupHeadInitData)); |
95 | | |
96 | | /* initialize the signature bitarray */ |
97 | 10.6M | size = sghid->sig_size = size + 16 - (size % 16); |
98 | 10.6M | void *ptr = SCMallocAligned(sghid->sig_size, 16); |
99 | 10.6M | if (ptr == NULL) |
100 | 0 | goto error; |
101 | 10.6M | memset(ptr, 0, size); |
102 | 10.6M | sghid->sig_array = ptr; |
103 | | |
104 | 10.6M | memset(sghid->sig_array, 0, sghid->sig_size); |
105 | | |
106 | 10.6M | return sghid; |
107 | 0 | error: |
108 | 0 | SigGroupHeadInitDataFree(sghid); |
109 | 0 | return NULL; |
110 | 10.6M | } |
111 | | |
112 | | void SigGroupHeadStore(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
113 | 224k | { |
114 | 224k | void *ptmp; |
115 | | //printf("de_ctx->sgh_array_cnt %u, de_ctx->sgh_array_size %u, de_ctx->sgh_array %p\n", de_ctx->sgh_array_cnt, de_ctx->sgh_array_size, de_ctx->sgh_array); |
116 | 224k | if (de_ctx->sgh_array_cnt < de_ctx->sgh_array_size) { |
117 | 173k | de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; |
118 | 173k | } else { |
119 | 51.0k | int increase = 16; |
120 | 51.0k | ptmp = SCRealloc(de_ctx->sgh_array, |
121 | 51.0k | sizeof(SigGroupHead *) * (increase + de_ctx->sgh_array_size)); |
122 | 51.0k | if (ptmp == NULL) { |
123 | 0 | SCFree(de_ctx->sgh_array); |
124 | 0 | de_ctx->sgh_array = NULL; |
125 | 0 | return; |
126 | 0 | } |
127 | 51.0k | de_ctx->sgh_array = ptmp; |
128 | | |
129 | 51.0k | de_ctx->sgh_array_size += increase; |
130 | 51.0k | de_ctx->sgh_array[de_ctx->sgh_array_cnt] = sgh; |
131 | 51.0k | } |
132 | 224k | de_ctx->sgh_array_cnt++; |
133 | 224k | } |
134 | | |
135 | | /** |
136 | | * \brief Alloc a SigGroupHead and its signature bit_array. |
137 | | * |
138 | | * \param size Size of the sig_array that has to be created for this |
139 | | * SigGroupHead. |
140 | | * |
141 | | * \retval sgh Pointer to the newly init SigGroupHead on success; or NULL in |
142 | | * case of error. |
143 | | */ |
144 | | static SigGroupHead *SigGroupHeadAlloc(const DetectEngineCtx *de_ctx, uint32_t size) |
145 | 10.6M | { |
146 | 10.6M | SigGroupHead *sgh = SCMalloc(sizeof(SigGroupHead)); |
147 | 10.6M | if (unlikely(sgh == NULL)) |
148 | 0 | return NULL; |
149 | 10.6M | memset(sgh, 0, sizeof(SigGroupHead)); |
150 | | |
151 | 10.6M | sgh->init = SigGroupHeadInitDataAlloc(size); |
152 | 10.6M | if (sgh->init == NULL) |
153 | 0 | goto error; |
154 | | |
155 | 10.6M | return sgh; |
156 | | |
157 | 0 | error: |
158 | 0 | SigGroupHeadFree(de_ctx, sgh); |
159 | 0 | return NULL; |
160 | 10.6M | } |
161 | | |
162 | | /** |
163 | | * \brief Free a SigGroupHead and its members. |
164 | | * |
165 | | * \param sgh Pointer to the SigGroupHead that has to be freed. |
166 | | */ |
167 | | void SigGroupHeadFree(const DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
168 | 5.49M | { |
169 | 5.49M | if (sgh == NULL) |
170 | 0 | return; |
171 | | |
172 | 5.49M | SCLogDebug("sgh %p", sgh); |
173 | | |
174 | 5.49M | if (sgh->non_pf_other_store_array != NULL) { |
175 | 101k | SCFree(sgh->non_pf_other_store_array); |
176 | 101k | sgh->non_pf_other_store_array = NULL; |
177 | 101k | sgh->non_pf_other_store_cnt = 0; |
178 | 101k | } |
179 | | |
180 | 5.49M | if (sgh->non_pf_syn_store_array != NULL) { |
181 | 101k | SCFree(sgh->non_pf_syn_store_array); |
182 | 101k | sgh->non_pf_syn_store_array = NULL; |
183 | 101k | sgh->non_pf_syn_store_cnt = 0; |
184 | 101k | } |
185 | | |
186 | 5.49M | if (sgh->init != NULL) { |
187 | 5.37M | SigGroupHeadInitDataFree(sgh->init); |
188 | 5.37M | sgh->init = NULL; |
189 | 5.37M | } |
190 | | |
191 | 5.49M | PrefilterCleanupRuleGroup(de_ctx, sgh); |
192 | 5.49M | SCFree(sgh); |
193 | | |
194 | 5.49M | return; |
195 | 5.49M | } |
196 | | |
197 | | /** |
198 | | * \brief The hash function to be the used by the hash table - |
199 | | * DetectEngineCtx->sgh_hash_table. |
200 | | * |
201 | | * \param ht Pointer to the hash table. |
202 | | * \param data Pointer to the SigGroupHead. |
203 | | * \param datalen Not used in our case. |
204 | | * |
205 | | * \retval hash The generated hash value. |
206 | | */ |
207 | | static uint32_t SigGroupHeadHashFunc(HashListTable *ht, void *data, uint16_t datalen) |
208 | 10.1M | { |
209 | 10.1M | SigGroupHead *sgh = (SigGroupHead *)data; |
210 | 10.1M | uint32_t hash = 0; |
211 | 10.1M | uint32_t b = 0; |
212 | | |
213 | 10.1M | SCLogDebug("hashing sgh %p", sgh); |
214 | | |
215 | 173M | for (b = 0; b < sgh->init->sig_size; b++) |
216 | 163M | hash += sgh->init->sig_array[b]; |
217 | | |
218 | 10.1M | hash %= ht->array_size; |
219 | 10.1M | SCLogDebug("hash %"PRIu32" (sig_size %"PRIu32")", hash, sgh->init->sig_size); |
220 | 10.1M | return hash; |
221 | 10.1M | } |
222 | | |
223 | | /** |
224 | | * \brief The Compare function to be used by the SigGroupHead hash table - |
225 | | * DetectEngineCtx->sgh_hash_table. |
226 | | * |
227 | | * \param data1 Pointer to the first SigGroupHead. |
228 | | * \param len1 Not used. |
229 | | * \param data2 Pointer to the second SigGroupHead. |
230 | | * \param len2 Not used. |
231 | | * |
232 | | * \retval 1 If the 2 SigGroupHeads sent as args match. |
233 | | * \retval 0 If the 2 SigGroupHeads sent as args do not match. |
234 | | */ |
235 | | static char SigGroupHeadCompareFunc(void *data1, uint16_t len1, void *data2, |
236 | | uint16_t len2) |
237 | 9.67M | { |
238 | 9.67M | SigGroupHead *sgh1 = (SigGroupHead *)data1; |
239 | 9.67M | SigGroupHead *sgh2 = (SigGroupHead *)data2; |
240 | | |
241 | 9.67M | if (data1 == NULL || data2 == NULL) |
242 | 0 | return 0; |
243 | | |
244 | 9.67M | if (sgh1->init->sig_size != sgh2->init->sig_size) |
245 | 0 | return 0; |
246 | | |
247 | 9.67M | if (SCMemcmp(sgh1->init->sig_array, sgh2->init->sig_array, sgh1->init->sig_size) != 0) |
248 | 3.13k | return 0; |
249 | | |
250 | 9.67M | return 1; |
251 | 9.67M | } |
252 | | |
253 | | /** |
254 | | * \brief Initializes the hash table in the detection engine context to hold the |
255 | | * SigGroupHeads. |
256 | | * |
257 | | * \param de_ctx Pointer to the detection engine context. |
258 | | * |
259 | | * \retval 0 On success. |
260 | | * \retval -1 On failure. |
261 | | */ |
262 | | int SigGroupHeadHashInit(DetectEngineCtx *de_ctx) |
263 | 736k | { |
264 | 736k | de_ctx->sgh_hash_table = HashListTableInit(4096, SigGroupHeadHashFunc, |
265 | 736k | SigGroupHeadCompareFunc, NULL); |
266 | 736k | if (de_ctx->sgh_hash_table == NULL) |
267 | 0 | goto error; |
268 | | |
269 | 736k | return 0; |
270 | | |
271 | 0 | error: |
272 | 0 | return -1; |
273 | 736k | } |
274 | | |
275 | | /** |
276 | | * \brief Adds a SigGroupHead to the detection engine context SigGroupHead |
277 | | * hash table. |
278 | | * |
279 | | * \param de_ctx Pointer to the detection engine context. |
280 | | * \param sgh Pointer to the SigGroupHead. |
281 | | * |
282 | | * \retval ret 0 on Successfully adding the SigGroupHead; -1 on failure. |
283 | | */ |
284 | | int SigGroupHeadHashAdd(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
285 | 224k | { |
286 | 224k | int ret = HashListTableAdd(de_ctx->sgh_hash_table, (void *)sgh, 0); |
287 | | |
288 | 224k | return ret; |
289 | 224k | } |
290 | | |
291 | | int SigGroupHeadHashRemove(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
292 | 0 | { |
293 | 0 | return HashListTableRemove(de_ctx->sgh_hash_table, (void *)sgh, 0); |
294 | 0 | } |
295 | | |
296 | | /** |
297 | | * \brief Used to lookup a SigGroupHead hash from the detection engine context |
298 | | * SigGroupHead hash table. |
299 | | * |
300 | | * \param de_ctx Pointer to the detection engine context. |
301 | | * \param sgh Pointer to the SigGroupHead. |
302 | | * |
303 | | * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is |
304 | | * found in the hash table; NULL on failure. |
305 | | */ |
306 | | SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
307 | 9.89M | { |
308 | 9.89M | SCEnter(); |
309 | | |
310 | 9.89M | SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table, |
311 | 9.89M | (void *)sgh, 0); |
312 | | |
313 | 9.89M | SCReturnPtr(rsgh, "SigGroupHead"); |
314 | 9.89M | } |
315 | | |
316 | | /** |
317 | | * \brief Frees the hash table - DetectEngineCtx->sgh_hash_table, allocated by |
318 | | * SigGroupHeadHashInit() function. |
319 | | * |
320 | | * \param de_ctx Pointer to the detection engine context. |
321 | | */ |
322 | | void SigGroupHeadHashFree(DetectEngineCtx *de_ctx) |
323 | 443k | { |
324 | 443k | if (de_ctx->sgh_hash_table == NULL) |
325 | 63.4k | return; |
326 | | |
327 | 380k | HashListTableFree(de_ctx->sgh_hash_table); |
328 | 380k | de_ctx->sgh_hash_table = NULL; |
329 | | |
330 | 380k | return; |
331 | 443k | } |
332 | | |
333 | | /** |
334 | | * \brief Add a Signature to a SigGroupHead. |
335 | | * |
336 | | * \param de_ctx Pointer to the detection engine context. |
337 | | * \param sgh Pointer to a SigGroupHead. Can be NULL also. |
338 | | * \param s Pointer to the Signature that has to be added to the |
339 | | * SigGroupHead. |
340 | | * |
341 | | * \retval 0 On success. |
342 | | * \retval -1 On failure. |
343 | | */ |
344 | | int SigGroupHeadAppendSig(const DetectEngineCtx *de_ctx, SigGroupHead **sgh, |
345 | | const Signature *s) |
346 | 17.4M | { |
347 | 17.4M | if (de_ctx == NULL) |
348 | 0 | return 0; |
349 | | |
350 | | /* see if we have a head already */ |
351 | 17.4M | if (*sgh == NULL) { |
352 | 5.08M | *sgh = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); |
353 | 5.08M | if (*sgh == NULL) |
354 | 0 | goto error; |
355 | 5.08M | } |
356 | | |
357 | | /* enable the sig in the bitarray */ |
358 | 17.4M | (*sgh)->init->sig_array[s->num / 8] |= 1 << (s->num % 8); |
359 | | |
360 | 17.4M | return 0; |
361 | | |
362 | 0 | error: |
363 | 0 | return -1; |
364 | 17.4M | } |
365 | | |
366 | | /** |
367 | | * \brief Clears the bitarray holding the sids for this SigGroupHead. |
368 | | * |
369 | | * \param sgh Pointer to the SigGroupHead. |
370 | | * |
371 | | * \retval 0 Always. |
372 | | */ |
373 | | int SigGroupHeadClearSigs(SigGroupHead *sgh) |
374 | 0 | { |
375 | 0 | if (sgh == NULL) |
376 | 0 | return 0; |
377 | | |
378 | 0 | if (sgh->init->sig_array != NULL) |
379 | 0 | memset(sgh->init->sig_array, 0, sgh->init->sig_size); |
380 | |
|
381 | 0 | sgh->init->sig_cnt = 0; |
382 | |
|
383 | 0 | return 0; |
384 | 0 | } |
385 | | |
386 | | #ifdef __SSE2__ |
387 | | #include <emmintrin.h> |
388 | | static void MergeBitarrays(const uint8_t *src, uint8_t *dst, const uint32_t size) |
389 | 1.12M | { |
390 | 2.28M | #define BYTES 16 |
391 | 1.12M | const uint8_t *srcptr = src; |
392 | 1.12M | uint8_t *dstptr = dst; |
393 | 2.26M | for (uint32_t i = 0; i < size; i += 16) { |
394 | 1.14M | __m128i s = _mm_load_si128((const __m128i *)srcptr); |
395 | 1.14M | __m128i d = _mm_load_si128((const __m128i *)dstptr); |
396 | 1.14M | d = _mm_or_si128(s, d); |
397 | 1.14M | _mm_store_si128((__m128i *)dstptr, d); |
398 | 1.14M | srcptr += BYTES; |
399 | 1.14M | dstptr += BYTES; |
400 | 1.14M | } |
401 | 1.12M | } |
402 | | #endif |
403 | | |
404 | | /** |
405 | | * \brief Copies the bitarray holding the sids from the source SigGroupHead to |
406 | | * the destination SigGroupHead. |
407 | | * |
408 | | * \param de_ctx Pointer to the detection engine context. |
409 | | * \param src Pointer to the source SigGroupHead. |
410 | | * \param dst Pointer to the destination SigGroupHead. |
411 | | * |
412 | | * \retval 0 On success. |
413 | | * \retval -1 On failure. |
414 | | */ |
415 | | int SigGroupHeadCopySigs(DetectEngineCtx *de_ctx, SigGroupHead *src, SigGroupHead **dst) |
416 | 1.00M | { |
417 | 1.00M | if (src == NULL || de_ctx == NULL) |
418 | 340k | return 0; |
419 | | |
420 | 666k | if (*dst == NULL) { |
421 | 404k | *dst = SigGroupHeadAlloc(de_ctx, DetectEngineGetMaxSigId(de_ctx) / 8 + 1); |
422 | 404k | if (*dst == NULL) |
423 | 0 | goto error; |
424 | 404k | } |
425 | 666k | DEBUG_VALIDATE_BUG_ON(src->init->sig_size != (*dst)->init->sig_size); |
426 | | |
427 | 666k | #ifdef __SSE2__ |
428 | 666k | MergeBitarrays(src->init->sig_array, (*dst)->init->sig_array, src->init->sig_size); |
429 | | #else |
430 | | /* do the copy */ |
431 | | for (uint32_t idx = 0; idx < src->init->sig_size; idx++) |
432 | | (*dst)->init->sig_array[idx] = (*dst)->init->sig_array[idx] | src->init->sig_array[idx]; |
433 | | #endif |
434 | 666k | if (src->init->whitelist) |
435 | 113k | (*dst)->init->whitelist = MAX((*dst)->init->whitelist, src->init->whitelist); |
436 | | |
437 | 666k | return 0; |
438 | | |
439 | 0 | error: |
440 | 0 | return -1; |
441 | 666k | } |
442 | | |
443 | | #ifdef HAVE_POPCNT64 |
444 | | #include <x86intrin.h> |
445 | | static uint32_t Popcnt(const uint8_t *array, const uint32_t size) |
446 | 359k | { |
447 | | /* input needs to be a multiple of 8 for u64 casts to work */ |
448 | 359k | DEBUG_VALIDATE_BUG_ON(size < 8); |
449 | 359k | DEBUG_VALIDATE_BUG_ON(size % 8); |
450 | | |
451 | 359k | uint32_t cnt = 0; |
452 | 359k | uint64_t *ptr = (uint64_t *)array; |
453 | 1.08M | for (uint64_t idx = 0; idx < size; idx += 8) { |
454 | 725k | cnt += _popcnt64(*ptr); |
455 | 725k | ptr++; |
456 | 725k | } |
457 | 359k | return cnt; |
458 | 359k | } |
459 | | #endif |
460 | | |
461 | | /** |
462 | | * \brief Updates the SigGroupHead->sig_cnt with the total count of all the |
463 | | * Signatures present in this SigGroupHead. |
464 | | * |
465 | | * \param sgh Pointer to the SigGroupHead. |
466 | | * \param max_idx Maximum sid of the all the Signatures present in this |
467 | | * SigGroupHead. |
468 | | */ |
469 | | void SigGroupHeadSetSigCnt(SigGroupHead *sgh, uint32_t max_idx) |
470 | 201k | { |
471 | 201k | #ifdef HAVE_POPCNT64 |
472 | 201k | sgh->init->sig_cnt = Popcnt(sgh->init->sig_array, sgh->init->sig_size); |
473 | | #else |
474 | | uint32_t cnt = 0; |
475 | | for (uint32_t sig = 0; sig < max_idx + 1; sig++) { |
476 | | if (sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) |
477 | | cnt++; |
478 | | } |
479 | | sgh->init->sig_cnt = cnt; |
480 | | #endif |
481 | 201k | return; |
482 | 201k | } |
483 | | |
484 | | /** |
485 | | * \brief Finds if two Signature Group Heads are the same. |
486 | | * |
487 | | * \param sgha First SGH to be compared |
488 | | * \param sghb Secornd SGH to be compared |
489 | | * |
490 | | * \return true if they're a match, false otherwise |
491 | | */ |
492 | | bool SigGroupHeadEqual(const SigGroupHead *sgha, const SigGroupHead *sghb) |
493 | 187k | { |
494 | 187k | if (sgha == NULL || sghb == NULL) |
495 | 0 | return false; |
496 | | |
497 | 187k | if (sgha->init->sig_size != sghb->init->sig_size) |
498 | 0 | return false; |
499 | | |
500 | 187k | if (SCMemcmp(sgha->init->sig_array, sghb->init->sig_array, sgha->init->sig_size) != 0) |
501 | 61.7k | return false; |
502 | | |
503 | 126k | return true; |
504 | 187k | } |
505 | | |
506 | | void SigGroupHeadSetProtoAndDirection(SigGroupHead *sgh, |
507 | | uint8_t ipproto, int dir) |
508 | 204k | { |
509 | 204k | if (sgh && sgh->init) { |
510 | 204k | SCLogDebug("setting proto %u and dir %d on sgh %p", ipproto, dir, sgh); |
511 | 204k | sgh->init->protos[ipproto] = 1; |
512 | 204k | sgh->init->direction |= dir; |
513 | 204k | } |
514 | 204k | } |
515 | | |
516 | | /** |
517 | | * \brief Helper function used to print the list of sids for the Signatures |
518 | | * present in this SigGroupHead. |
519 | | * |
520 | | * \param de_ctx Pointer to the detection engine context. |
521 | | * \param sgh Pointer to the SigGroupHead. |
522 | | */ |
523 | | void SigGroupHeadPrintSigs(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
524 | 0 | { |
525 | 0 | SCEnter(); |
526 | |
|
527 | 0 | if (sgh == NULL) { |
528 | 0 | SCReturn; |
529 | 0 | } |
530 | | |
531 | 0 | uint32_t u; |
532 | |
|
533 | 0 | SCLogDebug("The Signatures present in this SigGroupHead are: "); |
534 | 0 | for (u = 0; u < (sgh->init->sig_size * 8); u++) { |
535 | 0 | if (sgh->init->sig_array[u / 8] & (1 << (u % 8))) { |
536 | 0 | SCLogDebug("%" PRIu32, u); |
537 | 0 | printf("s->num %"PRIu32" ", u); |
538 | 0 | } |
539 | 0 | } |
540 | |
|
541 | 0 | SCReturn; |
542 | 0 | } |
543 | | |
544 | | /** |
545 | | * \brief Create an array with all the internal ids of the sigs that this |
546 | | * sig group head will check for. |
547 | | * |
548 | | * \param de_ctx Pointer to the detection engine context. |
549 | | * \param sgh Pointer to the SigGroupHead. |
550 | | * \param max_idx The maximum value of the sid in the SigGroupHead arg. |
551 | | * |
552 | | * \retval 0 success |
553 | | * \retval -1 error |
554 | | */ |
555 | | int SigGroupHeadBuildMatchArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh, |
556 | | uint32_t max_idx) |
557 | 119k | { |
558 | 119k | Signature *s = NULL; |
559 | 119k | uint32_t idx = 0; |
560 | 119k | uint32_t sig = 0; |
561 | | |
562 | 119k | if (sgh == NULL) |
563 | 0 | return 0; |
564 | | |
565 | 119k | BUG_ON(sgh->init->match_array != NULL); |
566 | | |
567 | 119k | sgh->init->match_array = SCMalloc(sgh->init->sig_cnt * sizeof(Signature *)); |
568 | 119k | if (sgh->init->match_array == NULL) |
569 | 0 | return -1; |
570 | | |
571 | 119k | memset(sgh->init->match_array, 0, sgh->init->sig_cnt * sizeof(Signature *)); |
572 | | |
573 | 1.48M | for (sig = 0; sig < max_idx + 1; sig++) { |
574 | 1.36M | if (!(sgh->init->sig_array[(sig / 8)] & (1 << (sig % 8))) ) |
575 | 615k | continue; |
576 | | |
577 | 749k | s = de_ctx->sig_array[sig]; |
578 | 749k | if (s == NULL) |
579 | 0 | continue; |
580 | | |
581 | 749k | sgh->init->match_array[idx] = s; |
582 | 749k | idx++; |
583 | 749k | } |
584 | | |
585 | 119k | return 0; |
586 | 119k | } |
587 | | |
588 | | /** |
589 | | * \brief Set the need magic flag in the sgh. |
590 | | * |
591 | | * \param de_ctx detection engine ctx for the signatures |
592 | | * \param sgh sig group head to set the flag in |
593 | | */ |
594 | | void SigGroupHeadSetFilemagicFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
595 | 119k | { |
596 | | #ifdef HAVE_MAGIC |
597 | | Signature *s = NULL; |
598 | | uint32_t sig = 0; |
599 | | |
600 | | if (sgh == NULL) |
601 | | return; |
602 | | |
603 | | for (sig = 0; sig < sgh->init->sig_cnt; sig++) { |
604 | | s = sgh->init->match_array[sig]; |
605 | | if (s == NULL) |
606 | | continue; |
607 | | |
608 | | if (SignatureIsFilemagicInspecting(s)) { |
609 | | sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMAGIC; |
610 | | break; |
611 | | } |
612 | | } |
613 | | #endif |
614 | 119k | return; |
615 | 119k | } |
616 | | |
617 | | /** |
618 | | * \brief Set the need size flag in the sgh. |
619 | | * |
620 | | * \param de_ctx detection engine ctx for the signatures |
621 | | * \param sgh sig group head to set the flag in |
622 | | */ |
623 | | void SigGroupHeadSetFilesizeFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
624 | 119k | { |
625 | 119k | Signature *s = NULL; |
626 | 119k | uint32_t sig = 0; |
627 | | |
628 | 119k | if (sgh == NULL) |
629 | 0 | return; |
630 | | |
631 | 848k | for (sig = 0; sig < sgh->init->sig_cnt; sig++) { |
632 | 729k | s = sgh->init->match_array[sig]; |
633 | 729k | if (s == NULL) |
634 | 0 | continue; |
635 | | |
636 | 729k | if (SignatureIsFilesizeInspecting(s)) { |
637 | 656 | sgh->flags |= SIG_GROUP_HEAD_HAVEFILESIZE; |
638 | 656 | break; |
639 | 656 | } |
640 | 729k | } |
641 | | |
642 | 119k | return; |
643 | 119k | } |
644 | | |
645 | | /** |
646 | | * \brief Set the need hash flag in the sgh. |
647 | | * |
648 | | * \param de_ctx detection engine ctx for the signatures |
649 | | * \param sgh sig group head to set the flag in |
650 | | */ |
651 | | void SigGroupHeadSetFileHashFlag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
652 | 119k | { |
653 | 119k | Signature *s = NULL; |
654 | 119k | uint32_t sig = 0; |
655 | | |
656 | 119k | if (sgh == NULL) |
657 | 0 | return; |
658 | | |
659 | 849k | for (sig = 0; sig < sgh->init->sig_cnt; sig++) { |
660 | 730k | s = sgh->init->match_array[sig]; |
661 | 730k | if (s == NULL) |
662 | 0 | continue; |
663 | | |
664 | 730k | if (SignatureIsFileMd5Inspecting(s)) { |
665 | 0 | sgh->flags |= SIG_GROUP_HEAD_HAVEFILEMD5; |
666 | 0 | SCLogDebug("sgh %p has filemd5", sgh); |
667 | 0 | break; |
668 | 0 | } |
669 | | |
670 | 730k | if (SignatureIsFileSha1Inspecting(s)) { |
671 | 0 | sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA1; |
672 | 0 | SCLogDebug("sgh %p has filesha1", sgh); |
673 | 0 | break; |
674 | 0 | } |
675 | | |
676 | 730k | if (SignatureIsFileSha256Inspecting(s)) { |
677 | 0 | sgh->flags |= SIG_GROUP_HEAD_HAVEFILESHA256; |
678 | 0 | SCLogDebug("sgh %p has filesha256", sgh); |
679 | 0 | break; |
680 | 0 | } |
681 | 730k | } |
682 | | |
683 | 119k | return; |
684 | 119k | } |
685 | | |
686 | | /** |
687 | | * \brief Set the filestore_cnt in the sgh. |
688 | | * |
689 | | * \param de_ctx detection engine ctx for the signatures |
690 | | * \param sgh sig group head to set the counter in |
691 | | */ |
692 | | void SigGroupHeadSetFilestoreCount(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
693 | 119k | { |
694 | 119k | Signature *s = NULL; |
695 | 119k | uint32_t sig = 0; |
696 | | |
697 | 119k | if (sgh == NULL) |
698 | 0 | return; |
699 | | |
700 | 849k | for (sig = 0; sig < sgh->init->sig_cnt; sig++) { |
701 | 730k | s = sgh->init->match_array[sig]; |
702 | 730k | if (s == NULL) |
703 | 0 | continue; |
704 | | |
705 | 730k | if (SignatureIsFilestoring(s)) { |
706 | | // should be insured by caller that we do not overflow |
707 | 29.5k | DEBUG_VALIDATE_BUG_ON(sgh->filestore_cnt == UINT16_MAX); |
708 | 29.5k | sgh->filestore_cnt++; |
709 | 29.5k | } |
710 | 730k | } |
711 | | |
712 | 119k | return; |
713 | 119k | } |
714 | | |
715 | | /** \brief build an array of rule id's for sigs with no prefilter |
716 | | * Also updated de_ctx::non_pf_store_cnt_max to track the highest cnt |
717 | | */ |
718 | | int SigGroupHeadBuildNonPrefilterArray(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
719 | 119k | { |
720 | 119k | Signature *s = NULL; |
721 | 119k | uint32_t sig = 0; |
722 | 119k | uint32_t non_pf = 0; |
723 | 119k | uint32_t non_pf_syn = 0; |
724 | | |
725 | 119k | if (sgh == NULL) |
726 | 0 | return 0; |
727 | | |
728 | 119k | BUG_ON(sgh->non_pf_other_store_array != NULL); |
729 | | |
730 | 869k | for (sig = 0; sig < sgh->init->sig_cnt; sig++) { |
731 | 749k | s = sgh->init->match_array[sig]; |
732 | 749k | if (s == NULL) |
733 | 0 | continue; |
734 | | |
735 | 749k | if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) { |
736 | 512k | if (!(DetectFlagsSignatureNeedsSynPackets(s))) { |
737 | 511k | non_pf++; |
738 | 511k | } |
739 | 512k | non_pf_syn++; |
740 | 512k | } |
741 | 749k | } |
742 | | |
743 | 119k | if (non_pf == 0 && non_pf_syn == 0) { |
744 | 17.9k | sgh->non_pf_other_store_array = NULL; |
745 | 17.9k | sgh->non_pf_syn_store_array = NULL; |
746 | 17.9k | return 0; |
747 | 17.9k | } |
748 | | |
749 | 101k | if (non_pf > 0) { |
750 | 101k | sgh->non_pf_other_store_array = SCMalloc(non_pf * sizeof(SignatureNonPrefilterStore)); |
751 | 101k | BUG_ON(sgh->non_pf_other_store_array == NULL); |
752 | 101k | memset(sgh->non_pf_other_store_array, 0, non_pf * sizeof(SignatureNonPrefilterStore)); |
753 | 101k | } |
754 | | |
755 | 101k | if (non_pf_syn > 0) { |
756 | 101k | sgh->non_pf_syn_store_array = SCMalloc(non_pf_syn * sizeof(SignatureNonPrefilterStore)); |
757 | 101k | BUG_ON(sgh->non_pf_syn_store_array == NULL); |
758 | 101k | memset(sgh->non_pf_syn_store_array, 0, non_pf_syn * sizeof(SignatureNonPrefilterStore)); |
759 | 101k | } |
760 | | |
761 | 812k | for (sig = 0; sig < sgh->init->sig_cnt; sig++) { |
762 | 710k | s = sgh->init->match_array[sig]; |
763 | 710k | if (s == NULL) |
764 | 0 | continue; |
765 | | |
766 | 710k | if (!(s->flags & SIG_FLAG_PREFILTER) || (s->flags & SIG_FLAG_MPM_NEG)) { |
767 | 512k | if (!(DetectFlagsSignatureNeedsSynPackets(s))) { |
768 | 511k | BUG_ON(sgh->non_pf_other_store_cnt >= non_pf); |
769 | 511k | BUG_ON(sgh->non_pf_other_store_array == NULL); |
770 | 511k | sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].id = s->num; |
771 | 511k | sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].mask = s->mask; |
772 | 511k | sgh->non_pf_other_store_array[sgh->non_pf_other_store_cnt].alproto = s->alproto; |
773 | 511k | sgh->non_pf_other_store_cnt++; |
774 | 511k | } |
775 | | |
776 | 512k | BUG_ON(sgh->non_pf_syn_store_cnt >= non_pf_syn); |
777 | 512k | BUG_ON(sgh->non_pf_syn_store_array == NULL); |
778 | 512k | sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].id = s->num; |
779 | 512k | sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].mask = s->mask; |
780 | 512k | sgh->non_pf_syn_store_array[sgh->non_pf_syn_store_cnt].alproto = s->alproto; |
781 | 512k | sgh->non_pf_syn_store_cnt++; |
782 | 512k | } |
783 | 710k | } |
784 | | |
785 | | /* track highest cnt for any sgh in our de_ctx */ |
786 | 101k | uint32_t max = MAX(sgh->non_pf_other_store_cnt, sgh->non_pf_syn_store_cnt); |
787 | 101k | if (max > de_ctx->non_pf_store_cnt_max) |
788 | 21.5k | de_ctx->non_pf_store_cnt_max = max; |
789 | | |
790 | 101k | return 0; |
791 | 101k | } |
792 | | |
793 | | /** |
794 | | * \brief Check if a SigGroupHead contains a Signature, whose sid is sent as an |
795 | | * argument. |
796 | | * |
797 | | * \param de_ctx Pointer to the detection engine context. |
798 | | * \param sgh Pointer to the SigGroupHead that has to be checked for the |
799 | | * presence of a Signature. |
800 | | * \param sid The Signature id(sid) that has to be checked in the SigGroupHead. |
801 | | * |
802 | | * \retval 1 On successfully finding the sid in the SigGroupHead. |
803 | | * \retval 0 If the sid is not found in the SigGroupHead |
804 | | */ |
805 | | int SigGroupHeadContainsSigId(DetectEngineCtx *de_ctx, SigGroupHead *sgh, |
806 | | uint32_t sid) |
807 | 0 | { |
808 | 0 | SCEnter(); |
809 | |
|
810 | 0 | uint32_t sig = 0; |
811 | 0 | Signature *s = NULL; |
812 | 0 | uint32_t max_sid = DetectEngineGetMaxSigId(de_ctx); |
813 | |
|
814 | 0 | if (sgh == NULL) { |
815 | 0 | SCReturnInt(0); |
816 | 0 | } |
817 | | |
818 | 0 | for (sig = 0; sig < max_sid; sig++) { |
819 | 0 | if (sgh->init->sig_array == NULL) { |
820 | 0 | SCReturnInt(0); |
821 | 0 | } |
822 | | |
823 | | /* Check if the SigGroupHead has an entry for the sid */ |
824 | 0 | if ( !(sgh->init->sig_array[sig / 8] & (1 << (sig % 8))) ) |
825 | 0 | continue; |
826 | | |
827 | | /* If we have reached here, we have an entry for sid in the SigGroupHead. |
828 | | * Retrieve the Signature from the detection engine context */ |
829 | 0 | s = de_ctx->sig_array[sig]; |
830 | 0 | if (s == NULL) |
831 | 0 | continue; |
832 | | |
833 | | /* If the retrieved Signature matches the sid arg, we have a match */ |
834 | 0 | if (s->id == sid) { |
835 | 0 | SCReturnInt(1); |
836 | 0 | } |
837 | 0 | } |
838 | | |
839 | 0 | SCReturnInt(0); |
840 | 0 | } |
841 | | |
842 | | /*----------------------------------Unittests---------------------------------*/ |
843 | | |
844 | | #ifdef UNITTESTS |
845 | | |
846 | | int SigAddressPrepareStage1(DetectEngineCtx *); |
847 | | |
848 | | /** |
849 | | * \test Check if a SigGroupHead hash table is properly allocated and |
850 | | * deallocated when calling SigGroupHeadHashInit() and |
851 | | * SigGroupHeadHashFree() respectively. |
852 | | */ |
853 | | static int SigGroupHeadTest01(void) |
854 | | { |
855 | | DetectEngineCtx de_ctx; |
856 | | |
857 | | SigGroupHeadHashInit(&de_ctx); |
858 | | FAIL_IF_NULL(de_ctx.sgh_hash_table); |
859 | | |
860 | | SigGroupHeadHashFree(&de_ctx); |
861 | | FAIL_IF_NOT_NULL(de_ctx.sgh_hash_table); |
862 | | |
863 | | PASS; |
864 | | } |
865 | | |
866 | | /** |
867 | | * \test Check if a SigGroupHeadAppendSig() correctly appends a sid to a |
868 | | * SigGroupHead() and SigGroupHeadContainsSigId() correctly indicates |
869 | | * the presence of a sid. |
870 | | */ |
871 | | static int SigGroupHeadTest02(void) |
872 | | { |
873 | | SigGroupHead *sh = NULL; |
874 | | |
875 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
876 | | FAIL_IF_NULL(de_ctx); |
877 | | |
878 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
879 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
880 | | "content:\"test2\"; content:\"test3\"; sid:1;)"); |
881 | | FAIL_IF_NULL(s); |
882 | | |
883 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
884 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
885 | | "content:\"test2\"; content:\"test3\"; sid:2;)"); |
886 | | FAIL_IF_NULL(s); |
887 | | |
888 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
889 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
890 | | "content:\"test2\"; content:\"test3\"; sid:3;)"); |
891 | | FAIL_IF_NULL(s); |
892 | | |
893 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
894 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
895 | | "content:\"test2\"; content:\"test3\"; sid:4;)"); |
896 | | FAIL_IF_NULL(s); |
897 | | |
898 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
899 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
900 | | "content:\"test2\"; content:\"test3\"; sid:5;)"); |
901 | | FAIL_IF_NULL(s); |
902 | | |
903 | | SigAddressPrepareStage1(de_ctx); |
904 | | |
905 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list); |
906 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next); |
907 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next); |
908 | | |
909 | | SigGroupHeadSetSigCnt(sh, 4); |
910 | | |
911 | | FAIL_IF_NOT(sh->init->sig_cnt == 3); |
912 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 1) == 1); |
913 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0); |
914 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 3) == 1); |
915 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0); |
916 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 5) == 1); |
917 | | |
918 | | SigGroupHeadFree(de_ctx, sh); |
919 | | |
920 | | DetectEngineCtxFree(de_ctx); |
921 | | |
922 | | PASS; |
923 | | } |
924 | | |
925 | | /** |
926 | | * \test Check if a SigGroupHeadAppendSig(), correctly appends a sid to a |
927 | | * SigGroupHead() and SigGroupHeadContainsSigId(), correctly indicates |
928 | | * the presence of a sid and SigGroupHeadClearSigs(), correctly clears |
929 | | * the SigGroupHead->sig_array and SigGroupHead->sig_cnt. |
930 | | */ |
931 | | static int SigGroupHeadTest03(void) |
932 | | { |
933 | | SigGroupHead *sh = NULL; |
934 | | |
935 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
936 | | FAIL_IF_NULL(de_ctx); |
937 | | |
938 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
939 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
940 | | "content:\"test2\"; content:\"test3\"; sid:1;)"); |
941 | | FAIL_IF_NULL(s); |
942 | | |
943 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
944 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
945 | | "content:\"test2\"; content:\"test3\"; sid:2;)"); |
946 | | FAIL_IF_NULL(s); |
947 | | |
948 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
949 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
950 | | "content:\"test2\"; content:\"test3\"; sid:3;)"); |
951 | | FAIL_IF_NULL(s); |
952 | | |
953 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
954 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
955 | | "content:\"test2\"; content:\"test3\"; sid:4;)"); |
956 | | FAIL_IF_NULL(s); |
957 | | |
958 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
959 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
960 | | "content:\"test2\"; content:\"test3\"; sid:5;)"); |
961 | | FAIL_IF_NULL(s); |
962 | | |
963 | | SigAddressPrepareStage1(de_ctx); |
964 | | |
965 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list); |
966 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next); |
967 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next); |
968 | | |
969 | | SigGroupHeadSetSigCnt(sh, 4); |
970 | | |
971 | | FAIL_IF_NOT(sh->init->sig_cnt == 3); |
972 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 1) == 1); |
973 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0); |
974 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 3) == 1); |
975 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0); |
976 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 5) == 1); |
977 | | |
978 | | SigGroupHeadClearSigs(sh); |
979 | | |
980 | | FAIL_IF_NOT(sh->init->sig_cnt == 0); |
981 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 1) == 0); |
982 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 2) == 0); |
983 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 3) == 0); |
984 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 4) == 0); |
985 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, sh, 5) == 0); |
986 | | |
987 | | SigGroupHeadFree(de_ctx, sh); |
988 | | |
989 | | DetectEngineCtxFree(de_ctx); |
990 | | |
991 | | PASS; |
992 | | } |
993 | | |
994 | | /** |
995 | | * \test Check if SigGroupHeadCopySigs(), correctly copies the sig_array from |
996 | | * the source to the destination SigGroupHead. |
997 | | */ |
998 | | static int SigGroupHeadTest04(void) |
999 | | { |
1000 | | SigGroupHead *src_sh = NULL; |
1001 | | SigGroupHead *dst_sh = NULL; |
1002 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
1003 | | |
1004 | | FAIL_IF_NULL(de_ctx); |
1005 | | |
1006 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1007 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1008 | | "content:\"test2\"; content:\"test3\"; sid:1;)"); |
1009 | | FAIL_IF_NULL(s); |
1010 | | |
1011 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1012 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1013 | | "content:\"test2\"; content:\"test3\"; sid:2;)"); |
1014 | | FAIL_IF_NULL(s); |
1015 | | |
1016 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1017 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1018 | | "content:\"test2\"; content:\"test3\"; sid:3;)"); |
1019 | | FAIL_IF_NULL(s); |
1020 | | |
1021 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1022 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1023 | | "content:\"test2\"; content:\"test3\"; sid:4;)"); |
1024 | | FAIL_IF_NULL(s); |
1025 | | |
1026 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1027 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1028 | | "content:\"test2\"; content:\"test3\"; sid:5;)"); |
1029 | | FAIL_IF_NULL(s); |
1030 | | |
1031 | | SigAddressPrepareStage1(de_ctx); |
1032 | | |
1033 | | SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list); |
1034 | | SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list->next->next); |
1035 | | SigGroupHeadAppendSig(de_ctx, &src_sh, de_ctx->sig_list->next->next->next->next); |
1036 | | |
1037 | | SigGroupHeadSetSigCnt(src_sh, 4); |
1038 | | |
1039 | | FAIL_IF_NOT(src_sh->init->sig_cnt == 3); |
1040 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 1) == 1); |
1041 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 2) == 0); |
1042 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 3) == 1); |
1043 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 4) == 0); |
1044 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, src_sh, 5) == 1); |
1045 | | |
1046 | | SigGroupHeadCopySigs(de_ctx, src_sh, &dst_sh); |
1047 | | |
1048 | | SigGroupHeadSetSigCnt(dst_sh, 4); |
1049 | | |
1050 | | FAIL_IF_NOT(dst_sh->init->sig_cnt == 3); |
1051 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 1) == 1); |
1052 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 2) == 0); |
1053 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 3) == 1); |
1054 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 4) == 0); |
1055 | | FAIL_IF_NOT(SigGroupHeadContainsSigId(de_ctx, dst_sh, 5) == 1); |
1056 | | |
1057 | | SigGroupHeadFree(de_ctx, src_sh); |
1058 | | SigGroupHeadFree(de_ctx, dst_sh); |
1059 | | |
1060 | | DetectEngineCtxFree(de_ctx); |
1061 | | |
1062 | | PASS; |
1063 | | } |
1064 | | |
1065 | | /** |
1066 | | * \test Check if SigGroupHeadBuildMatchArray(), correctly updates the |
1067 | | * match array with the sids. |
1068 | | */ |
1069 | | static int SigGroupHeadTest05(void) |
1070 | | { |
1071 | | SigGroupHead *sh = NULL; |
1072 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
1073 | | |
1074 | | FAIL_IF_NULL(de_ctx); |
1075 | | |
1076 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1077 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1078 | | "content:\"test2\"; content:\"test3\"; sid:1;)"); |
1079 | | FAIL_IF_NULL(s); |
1080 | | |
1081 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1082 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1083 | | "content:\"test2\"; content:\"test3\"; sid:2;)"); |
1084 | | FAIL_IF_NULL(s); |
1085 | | |
1086 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1087 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1088 | | "content:\"test2\"; content:\"test3\"; sid:3;)"); |
1089 | | FAIL_IF_NULL(s); |
1090 | | |
1091 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1092 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1093 | | "content:\"test2\"; content:\"test3\"; sid:4;)"); |
1094 | | FAIL_IF_NULL(s); |
1095 | | |
1096 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
1097 | | "(msg:\"SigGroupHead tests\"; content:\"test1\"; " |
1098 | | "content:\"test2\"; content:\"test3\"; sid:5;)"); |
1099 | | FAIL_IF_NULL(s); |
1100 | | |
1101 | | SigAddressPrepareStage1(de_ctx); |
1102 | | |
1103 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list); |
1104 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next); |
1105 | | SigGroupHeadAppendSig(de_ctx, &sh, de_ctx->sig_list->next->next->next->next); |
1106 | | |
1107 | | SigGroupHeadSetSigCnt(sh, 4); |
1108 | | SigGroupHeadBuildMatchArray(de_ctx, sh, 4); |
1109 | | |
1110 | | /* matching an array to a queue structure (sig_list) constructed by SigInit() |
1111 | | |
1112 | | FAIL_IF_NOT(sh->init->match_array[0] == de_ctx->sig_list); |
1113 | | FAIL_IF_NOT(sh->init->match_array[1] == de_ctx->sig_list->next->next); |
1114 | | FAIL_IF_NOT(sh->init->match_array[2] == de_ctx->sig_list->next->next->next->next); |
1115 | | */ |
1116 | | |
1117 | | // matching an array to a stack structure (sig_list) constructed by DetectEngineAppendSig() |
1118 | | FAIL_IF_NOT(sh->init->match_array[0] == de_ctx->sig_list->next->next->next->next); |
1119 | | FAIL_IF_NOT(sh->init->match_array[1] == de_ctx->sig_list->next->next); |
1120 | | FAIL_IF_NOT(sh->init->match_array[2] == de_ctx->sig_list); |
1121 | | |
1122 | | SigGroupHeadFree(de_ctx, sh); |
1123 | | |
1124 | | DetectEngineCtxFree(de_ctx); |
1125 | | |
1126 | | PASS; |
1127 | | } |
1128 | | |
1129 | | /** |
1130 | | * \test ICMP(?) sig grouping bug. |
1131 | | */ |
1132 | | static int SigGroupHeadTest06(void) |
1133 | | { |
1134 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
1135 | | DetectEngineThreadCtx *det_ctx = NULL; |
1136 | | ThreadVars th_v; |
1137 | | |
1138 | | memset(&th_v, 0, sizeof(ThreadVars)); |
1139 | | |
1140 | | Packet *p = UTHBuildPacketSrcDst(NULL, 0, IPPROTO_ICMP, "192.168.1.1", "1.2.3.4"); |
1141 | | FAIL_IF_NULL(p); |
1142 | | |
1143 | | p->icmpv4h->type = 5; |
1144 | | p->icmpv4h->code = 1; |
1145 | | |
1146 | | /* originally ip's were |
1147 | | p.src.addr_data32[0] = 0xe08102d3; |
1148 | | p.dst.addr_data32[0] = 0x3001a8c0; |
1149 | | */ |
1150 | | |
1151 | | FAIL_IF_NULL(de_ctx); |
1152 | | |
1153 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert icmp 192.168.0.0/16 any -> any any " |
1154 | | "(icode:>1; itype:11; sid:1; rev:1;)"); |
1155 | | FAIL_IF_NULL(s); |
1156 | | |
1157 | | s = DetectEngineAppendSig(de_ctx, "alert icmp any any -> 192.168.0.0/16 any " |
1158 | | "(icode:1; itype:5; sid:2; rev:1;)"); |
1159 | | FAIL_IF_NULL(s); |
1160 | | |
1161 | | SigGroupBuild(de_ctx); |
1162 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
1163 | | |
1164 | | AddressDebugPrint(&p->dst); |
1165 | | |
1166 | | const SigGroupHead *sgh = SigMatchSignaturesGetSgh(de_ctx, p); |
1167 | | FAIL_IF_NULL(sgh); |
1168 | | |
1169 | | DetectEngineCtxFree(de_ctx); |
1170 | | UTHFreePackets(&p, 1); |
1171 | | |
1172 | | PASS; |
1173 | | } |
1174 | | #endif |
1175 | | |
1176 | | void SigGroupHeadRegisterTests(void) |
1177 | 0 | { |
1178 | | #ifdef UNITTESTS |
1179 | | UtRegisterTest("SigGroupHeadTest01", SigGroupHeadTest01); |
1180 | | UtRegisterTest("SigGroupHeadTest02", SigGroupHeadTest02); |
1181 | | UtRegisterTest("SigGroupHeadTest03", SigGroupHeadTest03); |
1182 | | UtRegisterTest("SigGroupHeadTest04", SigGroupHeadTest04); |
1183 | | UtRegisterTest("SigGroupHeadTest05", SigGroupHeadTest05); |
1184 | | UtRegisterTest("SigGroupHeadTest06", SigGroupHeadTest06); |
1185 | | #endif |
1186 | 0 | } |