/src/suricata7/src/detect-isdataat.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2007-2020 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 Pablo Rincon <pablo.rincon.crespo@gmail.com> |
22 | | * |
23 | | * Implements isdataat keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "decode.h" |
28 | | #include "detect.h" |
29 | | #include "detect-engine.h" |
30 | | #include "detect-parse.h" |
31 | | #include "app-layer.h" |
32 | | |
33 | | #include "util-unittest.h" |
34 | | #include "util-unittest-helper.h" |
35 | | |
36 | | #include "detect-isdataat.h" |
37 | | #include "detect-content.h" |
38 | | #include "detect-uricontent.h" |
39 | | #include "detect-engine-build.h" |
40 | | |
41 | | #include "flow.h" |
42 | | #include "flow-var.h" |
43 | | |
44 | | #include "util-debug.h" |
45 | | #include "util-byte.h" |
46 | | #include "detect-pcre.h" |
47 | | #include "detect-byte.h" |
48 | | |
49 | | /** |
50 | | * \brief Regex for parsing our isdataat options |
51 | | */ |
52 | 73 | #define PARSE_REGEX "^\\s*!?([^\\s,]+)\\s*(,\\s*relative)?\\s*(,\\s*rawbytes\\s*)?\\s*$" |
53 | | |
54 | | static DetectParseRegex parse_regex; |
55 | | |
56 | | int DetectIsdataatSetup (DetectEngineCtx *, Signature *, const char *); |
57 | | #ifdef UNITTESTS |
58 | | static void DetectIsdataatRegisterTests(void); |
59 | | #endif |
60 | | void DetectIsdataatFree(DetectEngineCtx *, void *); |
61 | | |
62 | | static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr); |
63 | | |
64 | | /** |
65 | | * \brief Registration function for isdataat: keyword |
66 | | */ |
67 | | void DetectIsdataatRegister(void) |
68 | 73 | { |
69 | 73 | sigmatch_table[DETECT_ISDATAAT].name = "isdataat"; |
70 | 73 | sigmatch_table[DETECT_ISDATAAT].desc = "check if there is still data at a specific part of the payload"; |
71 | 73 | sigmatch_table[DETECT_ISDATAAT].url = "/rules/payload-keywords.html#isdataat"; |
72 | | /* match is handled in DetectEngineContentInspection() */ |
73 | 73 | sigmatch_table[DETECT_ISDATAAT].Match = NULL; |
74 | 73 | sigmatch_table[DETECT_ISDATAAT].Setup = DetectIsdataatSetup; |
75 | 73 | sigmatch_table[DETECT_ISDATAAT].Free = DetectIsdataatFree; |
76 | | #ifdef UNITTESTS |
77 | | sigmatch_table[DETECT_ISDATAAT].RegisterTests = DetectIsdataatRegisterTests; |
78 | | #endif |
79 | 73 | sigmatch_table[DETECT_ENDS_WITH].name = "endswith"; |
80 | 73 | sigmatch_table[DETECT_ENDS_WITH].desc = "make sure the previous content matches exactly at the end of the buffer"; |
81 | 73 | sigmatch_table[DETECT_ENDS_WITH].url = "/rules/payload-keywords.html#endswith"; |
82 | 73 | sigmatch_table[DETECT_ENDS_WITH].Setup = DetectEndsWithSetup; |
83 | 73 | sigmatch_table[DETECT_ENDS_WITH].flags = SIGMATCH_NOOPT; |
84 | | |
85 | 73 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
86 | 73 | } |
87 | | |
88 | | /** |
89 | | * \brief This function is used to parse isdataat options passed via isdataat: keyword |
90 | | * |
91 | | * \param de_ctx Pointer to the detection engine context |
92 | | * \param isdataatstr Pointer to the user provided isdataat options |
93 | | * |
94 | | * \retval idad pointer to DetectIsdataatData on success |
95 | | * \retval NULL on failure |
96 | | */ |
97 | | static DetectIsdataatData *DetectIsdataatParse (DetectEngineCtx *de_ctx, const char *isdataatstr, char **offset) |
98 | 12.5k | { |
99 | 12.5k | DetectIsdataatData *idad = NULL; |
100 | 12.5k | char *args[3] = {NULL,NULL,NULL}; |
101 | 12.5k | int res = 0; |
102 | 12.5k | size_t pcre2_len; |
103 | 12.5k | int i=0; |
104 | | |
105 | 12.5k | pcre2_match_data *match = NULL; |
106 | 12.5k | int ret = DetectParsePcreExec(&parse_regex, &match, isdataatstr, 0, 0); |
107 | 12.5k | if (ret < 1 || ret > 4) { |
108 | 1.42k | SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, isdataatstr); |
109 | 1.42k | goto error; |
110 | 1.42k | } |
111 | | |
112 | 11.1k | if (ret > 1) { |
113 | 11.1k | const char *str_ptr; |
114 | 11.1k | res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
115 | 11.1k | if (res < 0) { |
116 | 0 | SCLogError("pcre2_substring_get_bynumber failed"); |
117 | 0 | goto error; |
118 | 0 | } |
119 | 11.1k | args[0] = (char *)str_ptr; |
120 | | |
121 | | |
122 | 11.1k | if (ret > 2) { |
123 | 8.19k | res = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
124 | 8.19k | if (res < 0) { |
125 | 2 | SCLogError("pcre2_substring_get_bynumber failed"); |
126 | 2 | goto error; |
127 | 2 | } |
128 | 8.19k | args[1] = (char *)str_ptr; |
129 | 8.19k | } |
130 | 11.1k | if (ret > 3) { |
131 | 0 | res = pcre2_substring_get_bynumber(match, 3, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len); |
132 | 0 | if (res < 0) { |
133 | 0 | SCLogError("pcre2_substring_get_bynumber failed"); |
134 | 0 | goto error; |
135 | 0 | } |
136 | 0 | args[2] = (char *)str_ptr; |
137 | 0 | } |
138 | | |
139 | 11.1k | idad = SCMalloc(sizeof(DetectIsdataatData)); |
140 | 11.1k | if (unlikely(idad == NULL)) |
141 | 0 | goto error; |
142 | | |
143 | 11.1k | idad->flags = 0; |
144 | 11.1k | idad->dataat = 0; |
145 | | |
146 | 11.1k | if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) { |
147 | 878 | if (offset == NULL) { |
148 | 0 | SCLogError("isdataat supplied with " |
149 | 0 | "var name for offset. \"offset\" argument supplied to " |
150 | 0 | "this function has to be non-NULL"); |
151 | 0 | goto error; |
152 | 0 | } |
153 | 878 | *offset = SCStrdup(args[0]); |
154 | 878 | if (*offset == NULL) |
155 | 0 | goto error; |
156 | 10.2k | } else { |
157 | 10.2k | if (StringParseUint16(&idad->dataat, 10, |
158 | 10.2k | strlen(args[0]), args[0]) < 0 ) { |
159 | 755 | SCLogError("isdataat out of range"); |
160 | 755 | SCFree(idad); |
161 | 755 | idad = NULL; |
162 | 755 | goto error; |
163 | 755 | } |
164 | 10.2k | } |
165 | | |
166 | 10.3k | if (args[1] !=NULL) { |
167 | 8.11k | idad->flags |= ISDATAAT_RELATIVE; |
168 | | |
169 | 8.11k | if(args[2] !=NULL) |
170 | 0 | idad->flags |= ISDATAAT_RAWBYTES; |
171 | 8.11k | } |
172 | | |
173 | 10.3k | if (isdataatstr[0] == '!') { |
174 | 2.49k | idad->flags |= ISDATAAT_NEGATED; |
175 | 2.49k | } |
176 | | |
177 | 28.8k | for (i = 0; i < (ret -1); i++) { |
178 | 18.4k | if (args[i] != NULL) |
179 | 18.4k | pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); |
180 | 18.4k | } |
181 | | |
182 | 10.3k | pcre2_match_data_free(match); |
183 | 10.3k | return idad; |
184 | | |
185 | 11.1k | } |
186 | | |
187 | 2.18k | error: |
188 | 2.18k | if (match) { |
189 | 2.18k | pcre2_match_data_free(match); |
190 | 2.18k | } |
191 | 3.02k | for (i = 0; i < (ret -1) && i < 3; i++){ |
192 | 841 | if (args[i] != NULL) |
193 | 837 | pcre2_substring_free((PCRE2_UCHAR8 *)args[i]); |
194 | 841 | } |
195 | | |
196 | 2.18k | if (idad != NULL) |
197 | 0 | DetectIsdataatFree(de_ctx, idad); |
198 | 2.18k | return NULL; |
199 | | |
200 | 11.1k | } |
201 | | |
202 | | /** |
203 | | * \brief This function is used to add the parsed isdataatdata into the current |
204 | | * signature. |
205 | | * \param de_ctx pointer to the Detection Engine Context |
206 | | * \param s pointer to the Current Signature |
207 | | * \param isdataatstr pointer to the user provided isdataat options |
208 | | * |
209 | | * \retval 0 on Success |
210 | | * \retval -1 on Failure |
211 | | */ |
212 | | int DetectIsdataatSetup (DetectEngineCtx *de_ctx, Signature *s, const char *isdataatstr) |
213 | 12.5k | { |
214 | 12.5k | SigMatch *sm = NULL; |
215 | 12.5k | SigMatch *prev_pm = NULL; |
216 | 12.5k | DetectIsdataatData *idad = NULL; |
217 | 12.5k | char *offset = NULL; |
218 | 12.5k | int ret = -1; |
219 | | |
220 | 12.5k | idad = DetectIsdataatParse(de_ctx, isdataatstr, &offset); |
221 | 12.5k | if (idad == NULL) |
222 | 2.18k | return -1; |
223 | | |
224 | 10.3k | int sm_list; |
225 | 10.3k | if (s->init_data->list != DETECT_SM_LIST_NOTSET) { |
226 | 2.58k | if (DetectBufferGetActiveList(de_ctx, s) == -1) |
227 | 2 | goto end; |
228 | 2.58k | sm_list = s->init_data->list; |
229 | | |
230 | 2.58k | if (idad->flags & ISDATAAT_RELATIVE) { |
231 | 1.66k | prev_pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, DETECT_PCRE, -1); |
232 | 1.66k | } |
233 | 7.78k | } else if (idad->flags & ISDATAAT_RELATIVE) { |
234 | 6.45k | prev_pm = DetectGetLastSMFromLists(s, |
235 | 6.45k | DETECT_CONTENT, DETECT_PCRE, |
236 | 6.45k | DETECT_BYTETEST, DETECT_BYTEJUMP, DETECT_BYTE_EXTRACT, |
237 | 6.45k | DETECT_ISDATAAT, DETECT_BYTEMATH, -1); |
238 | 6.45k | if (prev_pm == NULL) |
239 | 137 | sm_list = DETECT_SM_LIST_PMATCH; |
240 | 6.31k | else { |
241 | 6.31k | sm_list = SigMatchListSMBelongsTo(s, prev_pm); |
242 | 6.31k | if (sm_list < 0) |
243 | 0 | goto end; |
244 | 6.31k | } |
245 | 6.45k | } else { |
246 | 1.33k | sm_list = DETECT_SM_LIST_PMATCH; |
247 | 1.33k | } |
248 | | |
249 | 10.3k | if (offset != NULL) { |
250 | 878 | DetectByteIndexType index; |
251 | 878 | if (!DetectByteRetrieveSMVar(offset, s, &index)) { |
252 | 464 | SCLogError("Unknown byte_extract var " |
253 | 464 | "seen in isdataat - %s\n", |
254 | 464 | offset); |
255 | 464 | goto end; |
256 | 464 | } |
257 | 414 | idad->dataat = index; |
258 | 414 | idad->flags |= ISDATAAT_OFFSET_VAR; |
259 | 414 | SCLogDebug("isdataat uses byte_extract with local id %u", idad->dataat); |
260 | 414 | SCFree(offset); |
261 | 414 | offset = NULL; |
262 | 414 | } |
263 | | |
264 | | /* 'ends with' scenario */ |
265 | 9.90k | if (prev_pm != NULL && prev_pm->type == DETECT_CONTENT && |
266 | 9.90k | idad->dataat == 1 && |
267 | 9.90k | (idad->flags & (ISDATAAT_RELATIVE|ISDATAAT_NEGATED)) == (ISDATAAT_RELATIVE|ISDATAAT_NEGATED)) |
268 | 419 | { |
269 | 419 | DetectIsdataatFree(de_ctx, idad); |
270 | 419 | DetectContentData *cd = (DetectContentData *)prev_pm->ctx; |
271 | 419 | cd->flags |= DETECT_CONTENT_ENDS_WITH; |
272 | 419 | ret = 0; |
273 | 419 | goto end; |
274 | 419 | } |
275 | | |
276 | 9.48k | sm = SigMatchAlloc(); |
277 | 9.48k | if (sm == NULL) |
278 | 0 | goto end; |
279 | 9.48k | sm->type = DETECT_ISDATAAT; |
280 | 9.48k | sm->ctx = (SigMatchCtx *)idad; |
281 | 9.48k | SigMatchAppendSMToList(s, sm, sm_list); |
282 | | |
283 | 9.48k | if (!(idad->flags & ISDATAAT_RELATIVE)) { |
284 | 1.79k | ret = 0; |
285 | 1.79k | goto end; |
286 | 1.79k | } |
287 | | |
288 | 7.68k | if (prev_pm == NULL) { |
289 | 638 | ret = 0; |
290 | 638 | goto end; |
291 | 638 | } |
292 | | |
293 | 7.05k | if (prev_pm->type == DETECT_CONTENT) { |
294 | 4.31k | DetectContentData *cd = (DetectContentData *)prev_pm->ctx; |
295 | 4.31k | cd->flags |= DETECT_CONTENT_RELATIVE_NEXT; |
296 | 4.31k | } else if (prev_pm->type == DETECT_PCRE) { |
297 | 644 | DetectPcreData *pd = (DetectPcreData *)prev_pm->ctx; |
298 | 644 | pd->flags |= DETECT_PCRE_RELATIVE_NEXT; |
299 | 644 | } |
300 | | |
301 | 7.05k | ret = 0; |
302 | | |
303 | 10.3k | end: |
304 | 10.3k | if (offset) |
305 | 464 | SCFree(offset); |
306 | 10.3k | if (ret != 0) |
307 | 466 | DetectIsdataatFree(de_ctx, idad); |
308 | 10.3k | return ret; |
309 | 7.05k | } |
310 | | |
311 | | /** |
312 | | * \brief this function will free memory associated with DetectIsdataatData |
313 | | * |
314 | | * \param idad pointer to DetectIsdataatData |
315 | | */ |
316 | | void DetectIsdataatFree(DetectEngineCtx *de_ctx, void *ptr) |
317 | 10.3k | { |
318 | 10.3k | DetectIsdataatData *idad = (DetectIsdataatData *)ptr; |
319 | 10.3k | SCFree(idad); |
320 | 10.3k | } |
321 | | |
322 | | static int DetectEndsWithSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) |
323 | 39.9k | { |
324 | 39.9k | SigMatch *pm = NULL; |
325 | 39.9k | int ret = -1; |
326 | | |
327 | | /* retrieve the sm to apply the depth against */ |
328 | 39.9k | pm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1); |
329 | 39.9k | if (pm == NULL) { |
330 | 681 | SCLogError("endswith needs a " |
331 | 681 | "preceding content option"); |
332 | 681 | goto end; |
333 | 681 | } |
334 | | |
335 | | /* verify other conditions. */ |
336 | 39.3k | DetectContentData *cd = (DetectContentData *)pm->ctx; |
337 | | |
338 | 39.3k | cd->flags |= DETECT_CONTENT_ENDS_WITH; |
339 | | |
340 | 39.3k | ret = 0; |
341 | 39.9k | end: |
342 | 39.9k | return ret; |
343 | 39.3k | } |
344 | | |
345 | | #ifdef UNITTESTS |
346 | | static int g_dce_stub_data_buffer_id = 0; |
347 | | |
348 | | /** |
349 | | * \test DetectIsdataatTestParse01 is a test to make sure that we return a correct IsdataatData structure |
350 | | * when given valid isdataat opt |
351 | | */ |
352 | | static int DetectIsdataatTestParse01 (void) |
353 | | { |
354 | | int result = 0; |
355 | | DetectIsdataatData *idad = NULL; |
356 | | idad = DetectIsdataatParse(NULL, "30 ", NULL); |
357 | | if (idad != NULL) { |
358 | | DetectIsdataatFree(NULL, idad); |
359 | | result = 1; |
360 | | } |
361 | | |
362 | | return result; |
363 | | } |
364 | | |
365 | | /** |
366 | | * \test DetectIsdataatTestParse02 is a test to make sure that we return a correct IsdataatData structure |
367 | | * when given valid isdataat opt |
368 | | */ |
369 | | static int DetectIsdataatTestParse02 (void) |
370 | | { |
371 | | int result = 0; |
372 | | DetectIsdataatData *idad = NULL; |
373 | | idad = DetectIsdataatParse(NULL, "30 , relative", NULL); |
374 | | if (idad != NULL && idad->flags & ISDATAAT_RELATIVE && !(idad->flags & ISDATAAT_RAWBYTES)) { |
375 | | DetectIsdataatFree(NULL, idad); |
376 | | result = 1; |
377 | | } |
378 | | |
379 | | return result; |
380 | | } |
381 | | |
382 | | /** |
383 | | * \test DetectIsdataatTestParse03 is a test to make sure that we return a correct IsdataatData structure |
384 | | * when given valid isdataat opt |
385 | | */ |
386 | | static int DetectIsdataatTestParse03 (void) |
387 | | { |
388 | | int result = 0; |
389 | | DetectIsdataatData *idad = NULL; |
390 | | idad = DetectIsdataatParse(NULL, "30,relative, rawbytes ", NULL); |
391 | | if (idad != NULL && idad->flags & ISDATAAT_RELATIVE && idad->flags & ISDATAAT_RAWBYTES) { |
392 | | DetectIsdataatFree(NULL, idad); |
393 | | result = 1; |
394 | | } |
395 | | |
396 | | return result; |
397 | | } |
398 | | |
399 | | /** |
400 | | * \test Test isdataat option for dce sig. |
401 | | */ |
402 | | static int DetectIsdataatTestParse04(void) |
403 | | { |
404 | | Signature *s = SigAlloc(); |
405 | | FAIL_IF_NULL(s); |
406 | | |
407 | | FAIL_IF(DetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0); |
408 | | |
409 | | FAIL_IF_NOT(DetectIsdataatSetup(NULL, s, "30") == 0); |
410 | | SigMatch *sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id); |
411 | | FAIL_IF_NOT_NULL(sm); |
412 | | FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]); |
413 | | SigFree(NULL, s); |
414 | | |
415 | | s = SigAlloc(); |
416 | | FAIL_IF_NULL(s); |
417 | | FAIL_IF(DetectSignatureSetAppProto(s, ALPROTO_DCERPC) < 0); |
418 | | /* relative w/o preceeding match defaults to "pmatch" */ |
419 | | FAIL_IF_NOT(DetectIsdataatSetup(NULL, s, "30,relative") == 0); |
420 | | sm = DetectBufferGetFirstSigMatch(s, g_dce_stub_data_buffer_id); |
421 | | FAIL_IF_NOT_NULL(sm); |
422 | | FAIL_IF_NULL(s->init_data->smlists[DETECT_SM_LIST_PMATCH]); |
423 | | |
424 | | SigFree(NULL, s); |
425 | | PASS; |
426 | | } |
427 | | |
428 | | static int DetectIsdataatTestParse06(void) |
429 | | { |
430 | | DetectEngineCtx *de_ctx = DetectEngineCtxInit(); |
431 | | FAIL_IF(de_ctx == NULL); |
432 | | de_ctx->flags |= DE_QUIET; |
433 | | |
434 | | Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
435 | | "(msg:\"Testing bytejump_body\"; " |
436 | | "content:\"one\"; " |
437 | | "isdataat:!4,relative; sid:1;)"); |
438 | | FAIL_IF(s == NULL); |
439 | | |
440 | | FAIL_IF(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL); |
441 | | |
442 | | FAIL_IF_NOT(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_ISDATAAT); |
443 | | DetectIsdataatData *data = |
444 | | (DetectIsdataatData *)s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->ctx; |
445 | | |
446 | | FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); |
447 | | FAIL_IF(data->flags & ISDATAAT_RAWBYTES); |
448 | | FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); |
449 | | |
450 | | s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any " |
451 | | "(msg:\"Testing bytejump_body\"; " |
452 | | "content:\"one\"; " |
453 | | "isdataat: !4,relative; sid:2;)"); |
454 | | FAIL_IF(s == NULL); |
455 | | |
456 | | FAIL_IF(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH] == NULL); |
457 | | |
458 | | FAIL_IF_NOT(s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_ISDATAAT); |
459 | | data = (DetectIsdataatData *)s->init_data->smlists_tail[DETECT_SM_LIST_PMATCH]->ctx; |
460 | | |
461 | | FAIL_IF_NOT(data->flags & ISDATAAT_RELATIVE); |
462 | | FAIL_IF(data->flags & ISDATAAT_RAWBYTES); |
463 | | FAIL_IF_NOT(data->flags & ISDATAAT_NEGATED); |
464 | | DetectEngineCtxFree(de_ctx); |
465 | | |
466 | | PASS; |
467 | | } |
468 | | |
469 | | /** |
470 | | * \test DetectIsdataatTestPacket01 is a test to check matches of |
471 | | * isdataat, and isdataat relative |
472 | | */ |
473 | | static int DetectIsdataatTestPacket01 (void) |
474 | | { |
475 | | int result = 0; |
476 | | uint8_t *buf = (uint8_t *)"Hi all!"; |
477 | | uint16_t buflen = strlen((char *)buf); |
478 | | Packet *p[3]; |
479 | | p[0] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
480 | | p[1] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_UDP); |
481 | | p[2] = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_ICMP); |
482 | | |
483 | | if (p[0] == NULL || p[1] == NULL ||p[2] == NULL) |
484 | | goto end; |
485 | | |
486 | | const char *sigs[5]; |
487 | | sigs[0]= "alert ip any any -> any any (msg:\"Testing window 1\"; isdataat:6; sid:1;)"; |
488 | | sigs[1]= "alert ip any any -> any any (msg:\"Testing window 2\"; content:\"all\"; isdataat:1, relative; isdataat:6; sid:2;)"; |
489 | | sigs[2]= "alert ip any any -> any any (msg:\"Testing window 3\"; isdataat:8; sid:3;)"; |
490 | | sigs[3]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:5, relative; sid:4;)"; |
491 | | sigs[4]= "alert ip any any -> any any (msg:\"Testing window 4\"; content:\"Hi\"; isdataat:6, relative; sid:5;)"; |
492 | | |
493 | | uint32_t sid[5] = {1, 2, 3, 4, 5}; |
494 | | |
495 | | uint32_t results[3][5] = { |
496 | | /* packet 0 match sid 1 but should not match sid 2 */ |
497 | | {1, 1, 0, 1, 0}, |
498 | | /* packet 1 should not match */ |
499 | | {1, 1, 0, 1, 0}, |
500 | | /* packet 2 should not match */ |
501 | | {1, 1, 0, 1, 0} }; |
502 | | |
503 | | result = UTHGenericTest(p, 3, sigs, sid, (uint32_t *) results, 5); |
504 | | |
505 | | UTHFreePackets(p, 3); |
506 | | end: |
507 | | return result; |
508 | | } |
509 | | |
510 | | /** |
511 | | * \test DetectIsdataatTestPacket02 is a test to check matches of |
512 | | * isdataat, and isdataat relative works if the previous keyword is pcre |
513 | | * (bug 144) |
514 | | */ |
515 | | static int DetectIsdataatTestPacket02 (void) |
516 | | { |
517 | | int result = 0; |
518 | | uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" |
519 | | "User-Agent: Wget/1.11.4" |
520 | | "Accept: */*" |
521 | | "Host: www.google.com" |
522 | | "Connection: Keep-Alive" |
523 | | "Date: Mon, 04 Jan 2010 17:29:39 GMT"; |
524 | | uint16_t buflen = strlen((char *)buf); |
525 | | Packet *p; |
526 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
527 | | |
528 | | if (p == NULL) |
529 | | goto end; |
530 | | |
531 | | char sig[] = "alert tcp any any -> any any (msg:\"pcre with" |
532 | | " isdataat + relative\"; pcre:\"/A(ll|pp)WorkAndNoPlayMakesWillA" |
533 | | "DullBoy/\"; isdataat:96,relative; sid:1;)"; |
534 | | |
535 | | result = UTHPacketMatchSig(p, sig); |
536 | | |
537 | | UTHFreePacket(p); |
538 | | end: |
539 | | return result; |
540 | | } |
541 | | |
542 | | /** |
543 | | * \test DetectIsdataatTestPacket03 is a test to check matches of |
544 | | * isdataat, and isdataat relative works if the previous keyword is byte_jump |
545 | | * (bug 146) |
546 | | */ |
547 | | static int DetectIsdataatTestPacket03 (void) |
548 | | { |
549 | | int result = 0; |
550 | | uint8_t *buf = (uint8_t *)"GET /AllWorkAndNoPlayMakesWillADullBoy HTTP/1.0" |
551 | | "User-Agent: Wget/1.11.4" |
552 | | "Accept: */*" |
553 | | "Host: www.google.com" |
554 | | "Connection: Keep-Alive" |
555 | | "Date: Mon, 04 Jan 2010 17:29:39 GMT"; |
556 | | uint16_t buflen = strlen((char *)buf); |
557 | | Packet *p; |
558 | | p = UTHBuildPacket((uint8_t *)buf, buflen, IPPROTO_TCP); |
559 | | |
560 | | if (p == NULL) |
561 | | goto end; |
562 | | |
563 | | char sig[] = "alert tcp any any -> any any (msg:\"byte_jump match = 0 " |
564 | | "with distance content HTTP/1. relative against HTTP/1.0\"; byte_jump:1," |
565 | | "46,string,dec; isdataat:87,relative; sid:109; rev:1;)"; |
566 | | |
567 | | result = UTHPacketMatchSig(p, sig); |
568 | | |
569 | | UTHFreePacket(p); |
570 | | end: |
571 | | return result; |
572 | | } |
573 | | |
574 | | /** |
575 | | * \brief this function registers unit tests for DetectIsdataat |
576 | | */ |
577 | | void DetectIsdataatRegisterTests(void) |
578 | | { |
579 | | g_dce_stub_data_buffer_id = DetectBufferTypeGetByName("dce_stub_data"); |
580 | | |
581 | | UtRegisterTest("DetectIsdataatTestParse01", DetectIsdataatTestParse01); |
582 | | UtRegisterTest("DetectIsdataatTestParse02", DetectIsdataatTestParse02); |
583 | | UtRegisterTest("DetectIsdataatTestParse03", DetectIsdataatTestParse03); |
584 | | UtRegisterTest("DetectIsdataatTestParse04", DetectIsdataatTestParse04); |
585 | | UtRegisterTest("DetectIsdataatTestParse06", DetectIsdataatTestParse06); |
586 | | |
587 | | UtRegisterTest("DetectIsdataatTestPacket01", DetectIsdataatTestPacket01); |
588 | | UtRegisterTest("DetectIsdataatTestPacket02", DetectIsdataatTestPacket02); |
589 | | UtRegisterTest("DetectIsdataatTestPacket03", DetectIsdataatTestPacket03); |
590 | | } |
591 | | #endif |