/src/suricata7/src/detect-dsize.c
Line | Count | Source |
1 | | /* Copyright (C) 2007-2022 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 | | * Implements the dsize keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "decode.h" |
28 | | |
29 | | #include "detect.h" |
30 | | #include "detect-parse.h" |
31 | | #include "detect-engine-prefilter-common.h" |
32 | | #include "detect-engine-build.h" |
33 | | |
34 | | #include "flow-var.h" |
35 | | |
36 | | #include "detect-content.h" |
37 | | #include "detect-dsize.h" |
38 | | |
39 | | #include "util-unittest.h" |
40 | | #include "util-debug.h" |
41 | | #include "util-byte.h" |
42 | | |
43 | | #include "pkt-var.h" |
44 | | #include "host.h" |
45 | | #include "util-profiling.h" |
46 | | |
47 | | static int DetectDsizeMatch (DetectEngineThreadCtx *, Packet *, |
48 | | const Signature *, const SigMatchCtx *); |
49 | | static int DetectDsizeSetup (DetectEngineCtx *, Signature *s, const char *str); |
50 | | #ifdef UNITTESTS |
51 | | static void DsizeRegisterTests(void); |
52 | | #endif |
53 | | static void DetectDsizeFree(DetectEngineCtx *, void *); |
54 | | |
55 | | static int PrefilterSetupDsize(DetectEngineCtx *de_ctx, SigGroupHead *sgh); |
56 | | static bool PrefilterDsizeIsPrefilterable(const Signature *s); |
57 | | |
58 | | /** |
59 | | * \brief Registration function for dsize: keyword |
60 | | */ |
61 | | void DetectDsizeRegister (void) |
62 | 75 | { |
63 | 75 | sigmatch_table[DETECT_DSIZE].name = "dsize"; |
64 | 75 | sigmatch_table[DETECT_DSIZE].desc = "match on the size of the packet payload"; |
65 | 75 | sigmatch_table[DETECT_DSIZE].url = "/rules/payload-keywords.html#dsize"; |
66 | 75 | sigmatch_table[DETECT_DSIZE].Match = DetectDsizeMatch; |
67 | 75 | sigmatch_table[DETECT_DSIZE].Setup = DetectDsizeSetup; |
68 | 75 | sigmatch_table[DETECT_DSIZE].Free = DetectDsizeFree; |
69 | | #ifdef UNITTESTS |
70 | | sigmatch_table[DETECT_DSIZE].RegisterTests = DsizeRegisterTests; |
71 | | #endif |
72 | 75 | sigmatch_table[DETECT_DSIZE].SupportsPrefilter = PrefilterDsizeIsPrefilterable; |
73 | 75 | sigmatch_table[DETECT_DSIZE].SetupPrefilter = PrefilterSetupDsize; |
74 | 75 | } |
75 | | |
76 | | /** |
77 | | * \internal |
78 | | * \brief This function is used to match flags on a packet with those passed via dsize: |
79 | | * |
80 | | * \param t pointer to thread vars |
81 | | * \param det_ctx pointer to the pattern matcher thread |
82 | | * \param p pointer to the current packet |
83 | | * \param s pointer to the Signature |
84 | | * \param m pointer to the sigmatch |
85 | | * |
86 | | * \retval 0 no match |
87 | | * \retval 1 match |
88 | | */ |
89 | | static int DetectDsizeMatch (DetectEngineThreadCtx *det_ctx, Packet *p, |
90 | | const Signature *s, const SigMatchCtx *ctx) |
91 | 5.36k | { |
92 | 5.36k | SCEnter(); |
93 | 5.36k | int ret = 0; |
94 | | |
95 | 5.36k | if (PKT_IS_PSEUDOPKT(p)) { |
96 | 128 | SCReturnInt(0); |
97 | 128 | } |
98 | | |
99 | 5.23k | const DetectU16Data *dd = (const DetectU16Data *)ctx; |
100 | | |
101 | 5.23k | SCLogDebug("p->payload_len %"PRIu16"", p->payload_len); |
102 | | |
103 | 5.23k | ret = DetectU16Match(p->payload_len, dd); |
104 | | |
105 | 5.23k | SCReturnInt(ret); |
106 | 5.36k | } |
107 | | |
108 | | /** |
109 | | * \internal |
110 | | * \brief this function is used to add the parsed dsize into the current signature |
111 | | * |
112 | | * \param de_ctx pointer to the Detection Engine Context |
113 | | * \param s pointer to the Current Signature |
114 | | * \param rawstr pointer to the user provided flags options |
115 | | * |
116 | | * \retval 0 on Success |
117 | | * \retval -1 on Failure |
118 | | */ |
119 | | static int DetectDsizeSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) |
120 | 46.1k | { |
121 | 46.1k | DetectU16Data *dd = NULL; |
122 | 46.1k | SigMatch *sm = NULL; |
123 | | |
124 | 46.1k | if (DetectGetLastSMFromLists(s, DETECT_DSIZE, -1)) { |
125 | 543 | SCLogError("Can't use 2 or more dsizes in " |
126 | 543 | "the same sig. Invalidating signature."); |
127 | 543 | return -1; |
128 | 543 | } |
129 | | |
130 | 45.6k | SCLogDebug("\'%s\'", rawstr); |
131 | | |
132 | 45.6k | dd = DetectU16Parse(rawstr); |
133 | 45.6k | if (dd == NULL) { |
134 | 3.21k | SCLogError("Parsing \'%s\' failed", rawstr); |
135 | 3.21k | return -1; |
136 | 3.21k | } |
137 | | |
138 | | /* Okay so far so good, lets get this into a SigMatch |
139 | | * and put it in the Signature. */ |
140 | 42.3k | sm = SigMatchAlloc(); |
141 | 42.3k | if (sm == NULL){ |
142 | 0 | SCLogError("Failed to allocate memory for SigMatch"); |
143 | 0 | rs_detect_u16_free(dd); |
144 | 0 | return -1; |
145 | 0 | } |
146 | | |
147 | 42.3k | sm->type = DETECT_DSIZE; |
148 | 42.3k | sm->ctx = (SigMatchCtx *)dd; |
149 | | |
150 | 42.3k | SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); |
151 | | |
152 | 42.3k | SCLogDebug("dd->arg1 %" PRIu16 ", dd->arg2 %" PRIu16 ", dd->mode %" PRIu8 "", dd->arg1, |
153 | 42.3k | dd->arg2, dd->mode); |
154 | | /* tell the sig it has a dsize to speed up engine init */ |
155 | 42.3k | s->flags |= SIG_FLAG_REQUIRE_PACKET; |
156 | 42.3k | s->flags |= SIG_FLAG_DSIZE; |
157 | | |
158 | 42.3k | if (s->init_data->dsize_sm == NULL) { |
159 | 38.9k | s->init_data->dsize_sm = sm; |
160 | 38.9k | } |
161 | | |
162 | 42.3k | return 0; |
163 | 42.3k | } |
164 | | |
165 | | /** |
166 | | * \internal |
167 | | * \brief this function will free memory associated with DetectU16Data |
168 | | * |
169 | | * \param de pointer to DetectU16Data |
170 | | */ |
171 | | void DetectDsizeFree(DetectEngineCtx *de_ctx, void *de_ptr) |
172 | 42.3k | { |
173 | 42.3k | rs_detect_u16_free(de_ptr); |
174 | 42.3k | } |
175 | | |
176 | | /* prefilter code */ |
177 | | |
178 | | static void |
179 | | PrefilterPacketDsizeMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) |
180 | 6.97k | { |
181 | 6.97k | if (PKT_IS_PSEUDOPKT(p)) { |
182 | 218 | SCReturn; |
183 | 218 | } |
184 | | |
185 | 6.76k | const PrefilterPacketHeaderCtx *ctx = pectx; |
186 | 6.76k | if (!PrefilterPacketHeaderExtraMatch(ctx, p)) |
187 | 2.38k | return; |
188 | | |
189 | 4.37k | const uint16_t dsize = p->payload_len; |
190 | 4.37k | DetectU16Data du16; |
191 | 4.37k | du16.mode = ctx->v1.u8[0]; |
192 | 4.37k | du16.arg1 = ctx->v1.u16[1]; |
193 | 4.37k | du16.arg2 = ctx->v1.u16[2]; |
194 | | |
195 | 4.37k | if (DetectU16Match(dsize, &du16)) { |
196 | 1.90k | SCLogDebug("packet matches dsize %u", dsize); |
197 | 1.90k | PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); |
198 | 1.90k | } |
199 | 4.37k | } |
200 | | |
201 | | static int PrefilterSetupDsize(DetectEngineCtx *de_ctx, SigGroupHead *sgh) |
202 | 5.63k | { |
203 | 5.63k | return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_DSIZE, PrefilterPacketU16Set, |
204 | 5.63k | PrefilterPacketU16Compare, PrefilterPacketDsizeMatch); |
205 | 5.63k | } |
206 | | |
207 | | static bool PrefilterDsizeIsPrefilterable(const Signature *s) |
208 | 0 | { |
209 | 0 | const SigMatch *sm; |
210 | 0 | for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) { |
211 | 0 | switch (sm->type) { |
212 | 0 | case DETECT_DSIZE: |
213 | 0 | return true; |
214 | 0 | } |
215 | 0 | } |
216 | 0 | return false; |
217 | 0 | } |
218 | | |
219 | | /** \brief get max dsize "depth" |
220 | | * \param s signature to get dsize value from |
221 | | * \retval depth or negative value |
222 | | */ |
223 | | int SigParseGetMaxDsize(const Signature *s) |
224 | 19.9k | { |
225 | 19.9k | if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) { |
226 | 19.9k | const DetectU16Data *dd = (const DetectU16Data *)s->init_data->dsize_sm->ctx; |
227 | | |
228 | 19.9k | switch (dd->mode) { |
229 | 1.67k | case DETECT_UINT_LT: |
230 | 17.5k | case DETECT_UINT_EQ: |
231 | 17.8k | case DETECT_UINT_NE: |
232 | 17.8k | return dd->arg1; |
233 | 416 | case DETECT_UINT_RA: |
234 | 416 | return dd->arg2; |
235 | 1.35k | case DETECT_UINT_GT: |
236 | 1.67k | default: |
237 | 1.67k | SCReturnInt(-2); |
238 | 19.9k | } |
239 | 19.9k | } |
240 | 19.9k | SCReturnInt(-1); |
241 | 19.9k | } |
242 | | |
243 | | /** \brief set prefilter dsize pair |
244 | | * \param s signature to get dsize value from |
245 | | */ |
246 | | void SigParseSetDsizePair(Signature *s) |
247 | 3.09k | { |
248 | 3.09k | if (s->flags & SIG_FLAG_DSIZE && s->init_data->dsize_sm != NULL) { |
249 | 3.09k | DetectU16Data *dd = (DetectU16Data *)s->init_data->dsize_sm->ctx; |
250 | | |
251 | 3.09k | uint16_t low = 0; |
252 | 3.09k | uint16_t high = 65535; |
253 | | |
254 | 3.09k | switch (dd->mode) { |
255 | 636 | case DETECT_UINT_LT: |
256 | 636 | low = 0; |
257 | 636 | high = dd->arg1; |
258 | 636 | break; |
259 | 116 | case DETECT_UINT_LTE: |
260 | 116 | low = 0; |
261 | 116 | high = dd->arg1 + 1; |
262 | 116 | break; |
263 | 1.59k | case DETECT_UINT_EQ: |
264 | 1.67k | case DETECT_UINT_NE: |
265 | 1.67k | low = dd->arg1; |
266 | 1.67k | high = dd->arg1; |
267 | 1.67k | break; |
268 | 82 | case DETECT_UINT_RA: |
269 | 82 | low = dd->arg1; |
270 | 82 | high = dd->arg2; |
271 | 82 | break; |
272 | 443 | case DETECT_UINT_GT: |
273 | 443 | low = dd->arg1; |
274 | 443 | high = 65535; |
275 | 443 | break; |
276 | 123 | case DETECT_UINT_GTE: |
277 | 123 | low = dd->arg1 - 1; |
278 | 123 | high = 65535; |
279 | 123 | break; |
280 | 3.09k | } |
281 | 3.09k | s->dsize_mode = dd->mode; |
282 | 3.09k | s->dsize_low = low; |
283 | 3.09k | s->dsize_high = high; |
284 | | |
285 | 3.09k | SCLogDebug("low %u, high %u, mode %u", low, high, dd->mode); |
286 | 3.09k | } |
287 | 3.09k | } |
288 | | |
289 | | /** |
290 | | * \brief Determine the required dsize for the signature |
291 | | * \param s signature to get dsize value from |
292 | | * |
293 | | * Note that negated content does not contribute to the maximum |
294 | | * required dsize value. However, each negated content's values |
295 | | * must not exceed the dsize value. See SigParseRequiredContentSize. |
296 | | * |
297 | | * \retval -1 Signature doesn't have a dsize keyword |
298 | | * \retval >= 0 Dsize value required to not exclude content matches |
299 | | */ |
300 | | int SigParseMaxRequiredDsize(const Signature *s) |
301 | 7.94k | { |
302 | 7.94k | SCEnter(); |
303 | | |
304 | 7.94k | if (!(s->flags & SIG_FLAG_DSIZE)) { |
305 | 0 | SCReturnInt(-1); |
306 | 0 | } |
307 | | |
308 | 7.94k | const int dsize = SigParseGetMaxDsize(s); |
309 | 7.94k | if (dsize < 0) { |
310 | | /* nothing to do */ |
311 | 0 | SCReturnInt(-1); |
312 | 0 | } |
313 | | |
314 | 7.94k | int total_length, offset; |
315 | 7.94k | SigParseRequiredContentSize( |
316 | 7.94k | s, dsize, s->init_data->smlists[DETECT_SM_LIST_PMATCH], &total_length, &offset); |
317 | 7.94k | SCLogDebug("dsize: %d len: %d; offset: %d [%s]", dsize, total_length, offset, s->sig_str); |
318 | | |
319 | 7.94k | if (total_length > dsize) { |
320 | 2.35k | SCLogDebug("required_dsize: %d exceeds dsize: %d", total_length, dsize); |
321 | 2.35k | return total_length; |
322 | 2.35k | } |
323 | | |
324 | 5.58k | if ((total_length + offset) > dsize) { |
325 | 259 | SCLogDebug("length + offset: %d exceeds dsize: %d", total_length + offset, dsize); |
326 | 259 | return total_length + offset; |
327 | 259 | } |
328 | | |
329 | 5.58k | SCReturnInt(-1); |
330 | 5.58k | } |
331 | | |
332 | | /** |
333 | | * \brief Apply dsize as depth to content matches in the rule |
334 | | * \param s signature to get dsize value from |
335 | | */ |
336 | | void SigParseApplyDsizeToContent(Signature *s) |
337 | 247k | { |
338 | 247k | SCEnter(); |
339 | | |
340 | 247k | if (s->flags & SIG_FLAG_DSIZE) { |
341 | 3.09k | SigParseSetDsizePair(s); |
342 | | |
343 | 3.09k | int dsize = SigParseGetMaxDsize(s); |
344 | 3.09k | if (dsize < 0) { |
345 | | /* nothing to do */ |
346 | 696 | return; |
347 | 696 | } |
348 | | |
349 | 2.39k | SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; |
350 | 4.06k | for ( ; sm != NULL; sm = sm->next) { |
351 | 1.66k | if (sm->type != DETECT_CONTENT) { |
352 | 489 | continue; |
353 | 489 | } |
354 | | |
355 | 1.17k | DetectContentData *cd = (DetectContentData *)sm->ctx; |
356 | 1.17k | if (cd == NULL) { |
357 | 0 | continue; |
358 | 0 | } |
359 | | |
360 | 1.17k | if (cd->depth == 0 || cd->depth >= dsize) { |
361 | 1.11k | cd->flags |= DETECT_CONTENT_DEPTH; |
362 | 1.11k | cd->depth = (uint16_t)dsize; |
363 | 1.11k | SCLogDebug("updated %u, content %u to have depth %u " |
364 | 1.11k | "because of dsize.", s->id, cd->id, cd->depth); |
365 | 1.11k | } |
366 | 1.17k | } |
367 | 2.39k | } |
368 | 247k | } |
369 | | |
370 | | /* |
371 | | * ONLY TESTS BELOW THIS COMMENT |
372 | | */ |
373 | | |
374 | | #ifdef UNITTESTS |
375 | | #include "util-unittest-helper.h" |
376 | | #include "detect-engine.h" |
377 | | #include "detect-engine-alert.h" |
378 | | #include "packet.h" |
379 | | |
380 | | /** |
381 | | * \test this is a test for a valid dsize value 1 |
382 | | * |
383 | | */ |
384 | | static int DsizeTestParse01(void) |
385 | | { |
386 | | DetectU16Data *dd = DetectU16Parse("1"); |
387 | | FAIL_IF_NULL(dd); |
388 | | FAIL_IF_NOT(dd->arg1 == 1); |
389 | | FAIL_IF_NOT(dd->arg2 == 0); |
390 | | |
391 | | DetectDsizeFree(NULL, dd); |
392 | | PASS; |
393 | | } |
394 | | |
395 | | /** |
396 | | * \test this is a test for a valid dsize value >10 |
397 | | * |
398 | | */ |
399 | | static int DsizeTestParse02(void) |
400 | | { |
401 | | DetectU16Data *dd = DetectU16Parse(">10"); |
402 | | FAIL_IF_NULL(dd); |
403 | | FAIL_IF_NOT(dd->arg1 == 10); |
404 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_GT); |
405 | | DetectDsizeFree(NULL, dd); |
406 | | PASS; |
407 | | } |
408 | | |
409 | | /** |
410 | | * \test this is a test for a valid dsize value <100 |
411 | | * |
412 | | */ |
413 | | static int DsizeTestParse03(void) |
414 | | { |
415 | | DetectU16Data *dd = DetectU16Parse("<100"); |
416 | | FAIL_IF_NULL(dd); |
417 | | FAIL_IF_NOT(dd->arg1 == 100); |
418 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_LT); |
419 | | |
420 | | DetectDsizeFree(NULL, dd); |
421 | | PASS; |
422 | | } |
423 | | |
424 | | /** |
425 | | * \test this is a test for a valid dsize value 1<>3 |
426 | | * |
427 | | */ |
428 | | static int DsizeTestParse04(void) |
429 | | { |
430 | | DetectU16Data *dd = DetectU16Parse("1<>3"); |
431 | | FAIL_IF_NULL(dd); |
432 | | FAIL_IF_NOT(dd->arg1 == 1); |
433 | | FAIL_IF_NOT(dd->arg2 == 3); |
434 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_RA); |
435 | | |
436 | | DetectDsizeFree(NULL, dd); |
437 | | PASS; |
438 | | } |
439 | | |
440 | | /** |
441 | | * \test this is a test for a valid dsize value 1 <> 3 |
442 | | * |
443 | | */ |
444 | | static int DsizeTestParse05(void) |
445 | | { |
446 | | DetectU16Data *dd = DetectU16Parse(" 1 <> 3 "); |
447 | | FAIL_IF_NULL(dd); |
448 | | FAIL_IF_NOT(dd->arg1 == 1); |
449 | | FAIL_IF_NOT(dd->arg2 == 3); |
450 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_RA); |
451 | | |
452 | | DetectDsizeFree(NULL, dd); |
453 | | PASS; |
454 | | } |
455 | | |
456 | | /** |
457 | | * \test this is test for a valid dsize value > 2 |
458 | | * |
459 | | */ |
460 | | static int DsizeTestParse06(void) |
461 | | { |
462 | | DetectU16Data *dd = DetectU16Parse("> 2 "); |
463 | | FAIL_IF_NULL(dd); |
464 | | FAIL_IF_NOT(dd->arg1 == 2); |
465 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_GT); |
466 | | |
467 | | DetectDsizeFree(NULL, dd); |
468 | | PASS; |
469 | | } |
470 | | |
471 | | /** |
472 | | * \test test for a valid dsize value < 12 |
473 | | * |
474 | | */ |
475 | | static int DsizeTestParse07(void) |
476 | | { |
477 | | DetectU16Data *dd = DetectU16Parse("< 12 "); |
478 | | FAIL_IF_NULL(dd); |
479 | | FAIL_IF_NOT(dd->arg1 == 12); |
480 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_LT); |
481 | | |
482 | | DetectDsizeFree(NULL, dd); |
483 | | PASS; |
484 | | } |
485 | | |
486 | | /** |
487 | | * \test test for a valid dsize value 12 |
488 | | * |
489 | | */ |
490 | | static int DsizeTestParse08(void) |
491 | | { |
492 | | DetectU16Data *dd = DetectU16Parse(" 12 "); |
493 | | FAIL_IF_NULL(dd); |
494 | | FAIL_IF_NOT(dd->arg1 == 12); |
495 | | FAIL_IF_NOT(dd->mode == DETECT_UINT_EQ); |
496 | | |
497 | | DetectDsizeFree(NULL, dd); |
498 | | PASS; |
499 | | } |
500 | | |
501 | | /** |
502 | | * \test this is a test for a valid dsize value !1 |
503 | | * |
504 | | */ |
505 | | static int DsizeTestParse09(void) |
506 | | { |
507 | | DetectU16Data *dd = DetectU16Parse("!1"); |
508 | | FAIL_IF_NULL(dd); |
509 | | DetectDsizeFree(NULL, dd); |
510 | | PASS; |
511 | | } |
512 | | |
513 | | /** |
514 | | * \test this is a test for a valid dsize value ! 1 |
515 | | * |
516 | | */ |
517 | | static int DsizeTestParse10(void) |
518 | | { |
519 | | DetectU16Data *dd = DetectU16Parse("! 1"); |
520 | | FAIL_IF_NULL(dd); |
521 | | DetectDsizeFree(NULL, dd); |
522 | | PASS; |
523 | | } |
524 | | |
525 | | /** |
526 | | * \test this is a test for invalid dsize values |
527 | | * A, >10<>10, <>10, 1<>, "", " ", 2<>1, 1! |
528 | | * |
529 | | */ |
530 | | static int DsizeTestParse11(void) |
531 | | { |
532 | | const char *strings[] = { "A", ">10<>10", "<>10", "1<>", "", " ", "2<>1", "1!", NULL }; |
533 | | for (int i = 0; strings[i]; i++) { |
534 | | DetectU16Data *dd = DetectU16Parse(strings[i]); |
535 | | FAIL_IF_NOT_NULL(dd); |
536 | | } |
537 | | |
538 | | PASS; |
539 | | } |
540 | | |
541 | | /** |
542 | | * \test this is a test for positive ! dsize matching |
543 | | * |
544 | | */ |
545 | | static int DsizeTestMatch01(void) |
546 | | { |
547 | | uint16_t psize = 1; |
548 | | uint16_t dsizelow = 2; |
549 | | uint16_t dsizehigh = 0; |
550 | | DetectU16Data du16; |
551 | | du16.mode = DETECT_UINT_NE; |
552 | | du16.arg1 = dsizelow; |
553 | | du16.arg2 = dsizehigh; |
554 | | FAIL_IF_NOT(DetectU16Match(psize, &du16)); |
555 | | |
556 | | PASS; |
557 | | } |
558 | | |
559 | | /** |
560 | | * \test this is a test for negative ! dsize matching |
561 | | * |
562 | | */ |
563 | | static int DsizeTestMatch02(void) |
564 | | { |
565 | | uint16_t psize = 1; |
566 | | uint16_t dsizelow = 1; |
567 | | uint16_t dsizehigh = 0; |
568 | | DetectU16Data du16; |
569 | | du16.mode = DETECT_UINT_NE; |
570 | | du16.arg1 = dsizelow; |
571 | | du16.arg2 = dsizehigh; |
572 | | FAIL_IF(DetectU16Match(psize, &du16)); |
573 | | |
574 | | PASS; |
575 | | } |
576 | | |
577 | | /** |
578 | | * \test DetectDsizeIcmpv6Test01 is a test for checking the working of |
579 | | * dsize keyword by creating 2 rules and matching a crafted packet |
580 | | * against them. Only the first one shall trigger. |
581 | | */ |
582 | | static int DetectDsizeIcmpv6Test01(void) |
583 | | { |
584 | | static uint8_t raw_icmpv6[] = { |
585 | | 0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3a, 0xff, |
586 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
587 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
588 | | 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
589 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, |
590 | | 0x01, 0x00, 0x7b, 0x85, 0x00, 0x00, 0x00, 0x00, |
591 | | 0x60, 0x4b, 0xe8, 0xbd, 0x00, 0x00, 0x3b, 0xff, |
592 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
593 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
594 | | 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
595 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; |
596 | | |
597 | | Packet *p = PacketGetFromAlloc(); |
598 | | FAIL_IF_NULL(p); |
599 | | |
600 | | IPV6Hdr ip6h; |
601 | | ThreadVars tv; |
602 | | DecodeThreadVars dtv; |
603 | | ThreadVars th_v; |
604 | | DetectEngineThreadCtx *det_ctx = NULL; |
605 | | |
606 | | memset(&tv, 0, sizeof(ThreadVars)); |
607 | | memset(&dtv, 0, sizeof(DecodeThreadVars)); |
608 | | memset(&ip6h, 0, sizeof(IPV6Hdr)); |
609 | | memset(&th_v, 0, sizeof(ThreadVars)); |
610 | | |
611 | | FlowInitConfig(FLOW_QUIET); |
612 | | p->src.family = AF_INET6; |
613 | | p->dst.family = AF_INET6; |
614 | | p->ip6h = &ip6h; |
615 | | |
616 | | DecodeIPV6(&tv, &dtv, p, raw_icmpv6, sizeof(raw_icmpv6)); |
617 | | |
618 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
619 | | FAIL_IF_NULL(de_ctx); |
620 | | |
621 | | de_ctx->flags |= DE_QUIET; |
622 | | |
623 | | Signature *s = DetectEngineAppendSig(de_ctx, |
624 | | "alert icmp any any -> any any " |
625 | | "(msg:\"ICMP Large ICMP Packet\"; dsize:>8; sid:1; rev:4;)"); |
626 | | FAIL_IF_NULL(s); |
627 | | |
628 | | s = DetectEngineAppendSig(de_ctx, |
629 | | "alert icmp any any -> any any " |
630 | | "(msg:\"ICMP Large ICMP Packet\"; dsize:>800; sid:2; rev:4;)"); |
631 | | FAIL_IF_NULL(s); |
632 | | |
633 | | SigGroupBuild(de_ctx); |
634 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
635 | | |
636 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
637 | | FAIL_IF(PacketAlertCheck(p, 1) == 0); |
638 | | FAIL_IF(PacketAlertCheck(p, 2)); |
639 | | |
640 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
641 | | DetectEngineCtxFree(de_ctx); |
642 | | |
643 | | PacketRecycle(p); |
644 | | FlowShutdown(); |
645 | | SCFree(p); |
646 | | |
647 | | PASS; |
648 | | } |
649 | | |
650 | | /** |
651 | | * \brief this function registers unit tests for dsize |
652 | | */ |
653 | | static void DsizeRegisterTests(void) |
654 | | { |
655 | | UtRegisterTest("DsizeTestParse01", DsizeTestParse01); |
656 | | UtRegisterTest("DsizeTestParse02", DsizeTestParse02); |
657 | | UtRegisterTest("DsizeTestParse03", DsizeTestParse03); |
658 | | UtRegisterTest("DsizeTestParse04", DsizeTestParse04); |
659 | | UtRegisterTest("DsizeTestParse05", DsizeTestParse05); |
660 | | UtRegisterTest("DsizeTestParse06", DsizeTestParse06); |
661 | | UtRegisterTest("DsizeTestParse07", DsizeTestParse07); |
662 | | UtRegisterTest("DsizeTestParse08", DsizeTestParse08); |
663 | | UtRegisterTest("DsizeTestParse09", DsizeTestParse09); |
664 | | UtRegisterTest("DsizeTestParse10", DsizeTestParse10); |
665 | | UtRegisterTest("DsizeTestParse11", DsizeTestParse11); |
666 | | UtRegisterTest("DsizeTestMatch01", DsizeTestMatch01); |
667 | | UtRegisterTest("DsizeTestMatch02", DsizeTestMatch02); |
668 | | |
669 | | UtRegisterTest("DetectDsizeIcmpv6Test01", DetectDsizeIcmpv6Test01); |
670 | | } |
671 | | #endif /* UNITTESTS */ |