/src/suricata7/src/detect-xbits.c
Line | Count | Source |
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 Victor Julien <victor@inliniac.net> |
22 | | * |
23 | | * Implements the xbits keyword |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "decode.h" |
28 | | #include "action-globals.h" |
29 | | #include "detect.h" |
30 | | #include "threads.h" |
31 | | #include "flow.h" |
32 | | #include "flow-util.h" |
33 | | #include "detect-xbits.h" |
34 | | #include "detect-hostbits.h" |
35 | | #include "util-spm.h" |
36 | | #include "util-byte.h" |
37 | | |
38 | | #include "detect-engine-sigorder.h" |
39 | | |
40 | | #include "app-layer-parser.h" |
41 | | |
42 | | #include "detect-parse.h" |
43 | | #include "detect-engine.h" |
44 | | #include "detect-engine-mpm.h" |
45 | | #include "detect-engine-state.h" |
46 | | #include "detect-engine-build.h" |
47 | | |
48 | | #include "flow-bit.h" |
49 | | #include "host-bit.h" |
50 | | #include "ippair-bit.h" |
51 | | #include "util-var-name.h" |
52 | | #include "util-unittest.h" |
53 | | #include "util-debug.h" |
54 | | |
55 | | /* |
56 | | xbits:set,bitname,track ip_pair,expire 60 |
57 | | */ |
58 | | |
59 | 73 | #define PARSE_REGEX "^([a-z]+)" "(?:,\\s*([^,]+))?" "(?:,\\s*(?:track\\s+([^,]+)))" "(?:,\\s*(?:expire\\s+([^,]+)))?" |
60 | | static DetectParseRegex parse_regex; |
61 | | |
62 | | static int DetectXbitMatch (DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); |
63 | | static int DetectXbitSetup (DetectEngineCtx *, Signature *, const char *); |
64 | | #ifdef UNITTESTS |
65 | | static void XBitsRegisterTests(void); |
66 | | #endif |
67 | | static void DetectXbitFree (DetectEngineCtx *, void *); |
68 | | |
69 | | void DetectXbitsRegister (void) |
70 | 73 | { |
71 | 73 | sigmatch_table[DETECT_XBITS].name = "xbits"; |
72 | 73 | sigmatch_table[DETECT_XBITS].desc = "operate on bits"; |
73 | 73 | sigmatch_table[DETECT_XBITS].url = "/rules/xbits.html"; |
74 | 73 | sigmatch_table[DETECT_XBITS].Match = DetectXbitMatch; |
75 | 73 | sigmatch_table[DETECT_XBITS].Setup = DetectXbitSetup; |
76 | 73 | sigmatch_table[DETECT_XBITS].Free = DetectXbitFree; |
77 | | #ifdef UNITTESTS |
78 | | sigmatch_table[DETECT_XBITS].RegisterTests = XBitsRegisterTests; |
79 | | #endif |
80 | | /* this is compatible to ip-only signatures */ |
81 | 73 | sigmatch_table[DETECT_XBITS].flags |= SIGMATCH_IPONLY_COMPAT; |
82 | | |
83 | 73 | DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); |
84 | 73 | } |
85 | | |
86 | | static int DetectIPPairbitMatchToggle (Packet *p, const DetectXbitsData *fd) |
87 | 0 | { |
88 | 0 | IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); |
89 | 0 | if (pair == NULL) |
90 | 0 | return 0; |
91 | | |
92 | 0 | IPPairBitToggle(pair, fd->idx, SCTIME_SECS(p->ts) + fd->expire); |
93 | 0 | IPPairRelease(pair); |
94 | 0 | return 1; |
95 | 0 | } |
96 | | |
97 | | /* return true even if bit not found */ |
98 | | static int DetectIPPairbitMatchUnset (Packet *p, const DetectXbitsData *fd) |
99 | 0 | { |
100 | 0 | IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); |
101 | 0 | if (pair == NULL) |
102 | 0 | return 1; |
103 | | |
104 | 0 | IPPairBitUnset(pair,fd->idx); |
105 | 0 | IPPairRelease(pair); |
106 | 0 | return 1; |
107 | 0 | } |
108 | | |
109 | | static int DetectIPPairbitMatchSet (Packet *p, const DetectXbitsData *fd) |
110 | 186 | { |
111 | 186 | IPPair *pair = IPPairGetIPPairFromHash(&p->src, &p->dst); |
112 | 186 | if (pair == NULL) |
113 | 0 | return 0; |
114 | | |
115 | 186 | IPPairBitSet(pair, fd->idx, SCTIME_SECS(p->ts) + fd->expire); |
116 | 186 | IPPairRelease(pair); |
117 | 186 | return 1; |
118 | 186 | } |
119 | | |
120 | | static int DetectIPPairbitMatchIsset (Packet *p, const DetectXbitsData *fd) |
121 | 464 | { |
122 | 464 | int r = 0; |
123 | 464 | IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); |
124 | 464 | if (pair == NULL) |
125 | 181 | return 0; |
126 | | |
127 | 283 | r = IPPairBitIsset(pair, fd->idx, SCTIME_SECS(p->ts)); |
128 | 283 | IPPairRelease(pair); |
129 | 283 | return r; |
130 | 464 | } |
131 | | |
132 | | static int DetectIPPairbitMatchIsnotset (Packet *p, const DetectXbitsData *fd) |
133 | 0 | { |
134 | 0 | int r = 0; |
135 | 0 | IPPair *pair = IPPairLookupIPPairFromHash(&p->src, &p->dst); |
136 | 0 | if (pair == NULL) |
137 | 0 | return 1; |
138 | | |
139 | 0 | r = IPPairBitIsnotset(pair, fd->idx, SCTIME_SECS(p->ts)); |
140 | 0 | IPPairRelease(pair); |
141 | 0 | return r; |
142 | 0 | } |
143 | | |
144 | | static int DetectXbitMatchIPPair(Packet *p, const DetectXbitsData *xd) |
145 | 650 | { |
146 | 650 | switch (xd->cmd) { |
147 | 464 | case DETECT_XBITS_CMD_ISSET: |
148 | 464 | return DetectIPPairbitMatchIsset(p,xd); |
149 | 0 | case DETECT_XBITS_CMD_ISNOTSET: |
150 | 0 | return DetectIPPairbitMatchIsnotset(p,xd); |
151 | 186 | case DETECT_XBITS_CMD_SET: |
152 | 186 | return DetectIPPairbitMatchSet(p,xd); |
153 | 0 | case DETECT_XBITS_CMD_UNSET: |
154 | 0 | return DetectIPPairbitMatchUnset(p,xd); |
155 | 0 | case DETECT_XBITS_CMD_TOGGLE: |
156 | 0 | return DetectIPPairbitMatchToggle(p,xd); |
157 | 650 | } |
158 | 0 | return 0; |
159 | 650 | } |
160 | | |
161 | | /* |
162 | | * returns 0: no match |
163 | | * 1: match |
164 | | * -1: error |
165 | | */ |
166 | | |
167 | | static int DetectXbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) |
168 | 245 | { |
169 | 245 | const DetectXbitsData *fd = (const DetectXbitsData *)ctx; |
170 | 245 | if (fd == NULL) |
171 | 0 | return 0; |
172 | | |
173 | 245 | switch (fd->type) { |
174 | 0 | case VAR_TYPE_HOST_BIT: |
175 | 0 | return DetectXbitMatchHost(p, (const DetectXbitsData *)fd); |
176 | 0 | break; |
177 | 245 | case VAR_TYPE_IPPAIR_BIT: |
178 | 245 | return DetectXbitMatchIPPair(p, (const DetectXbitsData *)fd); |
179 | 0 | break; |
180 | 0 | default: |
181 | 0 | break; |
182 | 245 | } |
183 | 0 | return 0; |
184 | 245 | } |
185 | | |
186 | | /** \internal |
187 | | * \brief parse xbits rule options |
188 | | * \retval 0 ok |
189 | | * \retval -1 bad |
190 | | * \param[out] cdout return DetectXbitsData structure or NULL if noalert |
191 | | */ |
192 | | static int DetectXbitParse(DetectEngineCtx *de_ctx, |
193 | | const char *rawstr, DetectXbitsData **cdout) |
194 | 2.71k | { |
195 | 2.71k | DetectXbitsData *cd = NULL; |
196 | 2.71k | uint8_t fb_cmd = 0; |
197 | 2.71k | uint8_t hb_dir = 0; |
198 | 2.71k | size_t pcre2len; |
199 | 2.71k | char fb_cmd_str[16] = "", fb_name[256] = ""; |
200 | 2.71k | char hb_dir_str[16] = ""; |
201 | 2.71k | enum VarTypes var_type = VAR_TYPE_NOT_SET; |
202 | 2.71k | uint32_t expire = DETECT_XBITS_EXPIRE_DEFAULT; |
203 | | |
204 | 2.71k | pcre2_match_data *match = NULL; |
205 | 2.71k | int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); |
206 | 2.71k | if (ret != 2 && ret != 3 && ret != 4 && ret != 5) { |
207 | 140 | SCLogError("\"%s\" is not a valid setting for xbits.", rawstr); |
208 | 140 | if (match) { |
209 | 140 | pcre2_match_data_free(match); |
210 | 140 | } |
211 | 140 | return -1; |
212 | 140 | } |
213 | 2.57k | SCLogDebug("ret %d, %s", ret, rawstr); |
214 | 2.57k | pcre2len = sizeof(fb_cmd_str); |
215 | 2.57k | int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)fb_cmd_str, &pcre2len); |
216 | 2.57k | if (res < 0) { |
217 | 4 | SCLogError("pcre2_substring_copy_bynumber failed"); |
218 | 4 | pcre2_match_data_free(match); |
219 | 4 | return -1; |
220 | 4 | } |
221 | | |
222 | 2.57k | if (ret >= 3) { |
223 | 2.57k | pcre2len = sizeof(fb_name); |
224 | 2.57k | res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)fb_name, &pcre2len); |
225 | 2.57k | if (res < 0) { |
226 | 30 | SCLogError("pcre2_substring_copy_bynumber failed"); |
227 | 30 | pcre2_match_data_free(match); |
228 | 30 | return -1; |
229 | 30 | } |
230 | 2.54k | if (ret >= 4) { |
231 | 2.54k | pcre2len = sizeof(hb_dir_str); |
232 | 2.54k | res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)hb_dir_str, &pcre2len); |
233 | 2.54k | if (res < 0) { |
234 | 87 | SCLogError("pcre2_substring_copy_bynumber failed"); |
235 | 87 | pcre2_match_data_free(match); |
236 | 87 | return -1; |
237 | 87 | } |
238 | 2.45k | SCLogDebug("hb_dir_str %s", hb_dir_str); |
239 | 2.45k | if (strlen(hb_dir_str) > 0) { |
240 | 2.45k | if (strcmp(hb_dir_str, "ip_src") == 0) { |
241 | 209 | hb_dir = DETECT_XBITS_TRACK_IPSRC; |
242 | 209 | var_type = VAR_TYPE_HOST_BIT; |
243 | 2.24k | } else if (strcmp(hb_dir_str, "ip_dst") == 0) { |
244 | 1.08k | hb_dir = DETECT_XBITS_TRACK_IPDST; |
245 | 1.08k | var_type = VAR_TYPE_HOST_BIT; |
246 | 1.16k | } else if (strcmp(hb_dir_str, "ip_pair") == 0) { |
247 | 1.03k | hb_dir = DETECT_XBITS_TRACK_IPPAIR; |
248 | 1.03k | var_type = VAR_TYPE_IPPAIR_BIT; |
249 | 1.03k | } else { |
250 | | // TODO |
251 | 127 | pcre2_match_data_free(match); |
252 | 127 | return -1; |
253 | 127 | } |
254 | 2.45k | } |
255 | | |
256 | 2.32k | if (ret >= 5) { |
257 | 31 | char expire_str[16] = ""; |
258 | 31 | pcre2len = sizeof(expire_str); |
259 | 31 | res = pcre2_substring_copy_bynumber( |
260 | 31 | match, 4, (PCRE2_UCHAR8 *)expire_str, &pcre2len); |
261 | 31 | if (res < 0) { |
262 | 1 | SCLogError("pcre2_substring_copy_bynumber failed"); |
263 | 1 | pcre2_match_data_free(match); |
264 | 1 | return -1; |
265 | 1 | } |
266 | 30 | SCLogDebug("expire_str %s", expire_str); |
267 | 30 | if (StringParseUint32(&expire, 10, 0, (const char *)expire_str) < 0) { |
268 | 1 | SCLogError("Invalid value for " |
269 | 1 | "expire: \"%s\"", |
270 | 1 | expire_str); |
271 | 1 | pcre2_match_data_free(match); |
272 | 1 | return -1; |
273 | 1 | } |
274 | 29 | if (expire == 0) { |
275 | 3 | SCLogError("expire must be bigger than 0"); |
276 | 3 | pcre2_match_data_free(match); |
277 | 3 | return -1; |
278 | 3 | } |
279 | 26 | SCLogDebug("expire %d", expire); |
280 | 26 | } |
281 | 2.32k | } |
282 | 2.54k | } |
283 | | |
284 | 2.57k | pcre2_match_data_free(match); |
285 | 2.32k | if (strcmp(fb_cmd_str,"noalert") == 0) { |
286 | 6 | fb_cmd = DETECT_XBITS_CMD_NOALERT; |
287 | 2.31k | } else if (strcmp(fb_cmd_str,"isset") == 0) { |
288 | 1.04k | fb_cmd = DETECT_XBITS_CMD_ISSET; |
289 | 1.27k | } else if (strcmp(fb_cmd_str,"isnotset") == 0) { |
290 | 72 | fb_cmd = DETECT_XBITS_CMD_ISNOTSET; |
291 | 1.20k | } else if (strcmp(fb_cmd_str,"set") == 0) { |
292 | 471 | fb_cmd = DETECT_XBITS_CMD_SET; |
293 | 732 | } else if (strcmp(fb_cmd_str,"unset") == 0) { |
294 | 382 | fb_cmd = DETECT_XBITS_CMD_UNSET; |
295 | 382 | } else if (strcmp(fb_cmd_str,"toggle") == 0) { |
296 | 269 | fb_cmd = DETECT_XBITS_CMD_TOGGLE; |
297 | 269 | } else { |
298 | 81 | SCLogError("xbits action \"%s\" is not supported.", fb_cmd_str); |
299 | 81 | return -1; |
300 | 81 | } |
301 | | |
302 | 2.24k | switch (fb_cmd) { |
303 | 6 | case DETECT_XBITS_CMD_NOALERT: { |
304 | 6 | if (strlen(fb_name) != 0) |
305 | 6 | return -1; |
306 | | /* return ok, cd is NULL. Flag sig. */ |
307 | 0 | *cdout = NULL; |
308 | 0 | return 0; |
309 | 6 | } |
310 | 72 | case DETECT_XBITS_CMD_ISNOTSET: |
311 | 1.11k | case DETECT_XBITS_CMD_ISSET: |
312 | 1.58k | case DETECT_XBITS_CMD_SET: |
313 | 1.96k | case DETECT_XBITS_CMD_UNSET: |
314 | 2.23k | case DETECT_XBITS_CMD_TOGGLE: |
315 | 2.23k | if (strlen(fb_name) == 0) |
316 | 0 | return -1; |
317 | 2.23k | break; |
318 | 2.24k | } |
319 | | |
320 | 2.23k | cd = SCMalloc(sizeof(DetectXbitsData)); |
321 | 2.23k | if (unlikely(cd == NULL)) |
322 | 0 | return -1; |
323 | | |
324 | 2.23k | cd->idx = VarNameStoreRegister(fb_name, var_type); |
325 | 2.23k | cd->cmd = fb_cmd; |
326 | 2.23k | cd->tracker = hb_dir; |
327 | 2.23k | cd->type = var_type; |
328 | 2.23k | cd->expire = expire; |
329 | | |
330 | 2.23k | SCLogDebug("idx %" PRIu32 ", cmd %s, name %s", |
331 | 2.23k | cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)"); |
332 | | |
333 | 2.23k | *cdout = cd; |
334 | 2.23k | return 0; |
335 | 2.23k | } |
336 | | |
337 | | int DetectXbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) |
338 | 2.71k | { |
339 | 2.71k | SigMatch *sm = NULL; |
340 | 2.71k | DetectXbitsData *cd = NULL; |
341 | | |
342 | 2.71k | int result = DetectXbitParse(de_ctx, rawstr, &cd); |
343 | 2.71k | if (result < 0) { |
344 | 480 | return -1; |
345 | 2.23k | } else if (cd == NULL) { |
346 | | /* noalert doesn't use a cd/sm struct. It flags the sig. We're done. */ |
347 | 0 | s->action &= ~ACTION_ALERT; |
348 | 0 | return 0; |
349 | 0 | } |
350 | | |
351 | | /* Okay so far so good, lets get this into a SigMatch |
352 | | * and put it in the Signature. */ |
353 | 2.23k | sm = SigMatchAlloc(); |
354 | 2.23k | if (sm == NULL) |
355 | 0 | goto error; |
356 | | |
357 | 2.23k | sm->type = DETECT_XBITS; |
358 | 2.23k | sm->ctx = (void *)cd; |
359 | | |
360 | 2.23k | switch (cd->cmd) { |
361 | | /* case DETECT_XBITS_CMD_NOALERT can't happen here */ |
362 | | |
363 | 72 | case DETECT_XBITS_CMD_ISNOTSET: |
364 | 1.11k | case DETECT_XBITS_CMD_ISSET: |
365 | | /* checks, so packet list */ |
366 | 1.11k | SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH); |
367 | 1.11k | break; |
368 | | |
369 | 471 | case DETECT_XBITS_CMD_SET: |
370 | 853 | case DETECT_XBITS_CMD_UNSET: |
371 | 1.12k | case DETECT_XBITS_CMD_TOGGLE: |
372 | | /* modifiers, only run when entire sig has matched */ |
373 | 1.12k | SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH); |
374 | 1.12k | break; |
375 | 2.23k | } |
376 | | |
377 | 2.23k | return 0; |
378 | | |
379 | 0 | error: |
380 | 0 | if (cd != NULL) |
381 | 0 | SCFree(cd); |
382 | 0 | return -1; |
383 | 2.23k | } |
384 | | |
385 | | static void DetectXbitFree (DetectEngineCtx *de_ctx, void *ptr) |
386 | 8.22k | { |
387 | 8.22k | DetectXbitsData *fd = (DetectXbitsData *)ptr; |
388 | | |
389 | 8.22k | if (fd == NULL) |
390 | 2.07k | return; |
391 | 6.14k | VarNameStoreUnregister(fd->idx, fd->type); |
392 | | |
393 | 6.14k | SCFree(fd); |
394 | 6.14k | } |
395 | | |
396 | | #ifdef UNITTESTS |
397 | | |
398 | | static void XBitsTestSetup(void) |
399 | | { |
400 | | StorageInit(); |
401 | | HostBitInitCtx(); |
402 | | IPPairBitInitCtx(); |
403 | | StorageFinalize(); |
404 | | HostInitConfig(true); |
405 | | IPPairInitConfig(true); |
406 | | } |
407 | | |
408 | | static void XBitsTestShutdown(void) |
409 | | { |
410 | | HostCleanup(); |
411 | | IPPairCleanup(); |
412 | | StorageCleanup(); |
413 | | } |
414 | | |
415 | | |
416 | | static int XBitsTestParse01(void) |
417 | | { |
418 | | DetectEngineCtx *de_ctx = NULL; |
419 | | de_ctx = DetectEngineCtxInit(); |
420 | | FAIL_IF_NULL(de_ctx); |
421 | | de_ctx->flags |= DE_QUIET; |
422 | | DetectXbitsData *cd = NULL; |
423 | | |
424 | | #define BAD_INPUT(str) \ |
425 | | FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == -1); |
426 | | |
427 | | BAD_INPUT("alert"); |
428 | | BAD_INPUT("n0alert"); |
429 | | BAD_INPUT("nOalert"); |
430 | | BAD_INPUT("set,abc,track nonsense, expire 3600"); |
431 | | BAD_INPUT("set,abc,track ip_source, expire 3600"); |
432 | | BAD_INPUT("set,abc,track ip_src, expire -1"); |
433 | | BAD_INPUT("set,abc,track ip_src, expire 0"); |
434 | | |
435 | | #undef BAD_INPUT |
436 | | |
437 | | #define GOOD_INPUT(str, command, trk, typ, exp) \ |
438 | | FAIL_IF_NOT(DetectXbitParse(de_ctx, (str), &cd) == 0); \ |
439 | | FAIL_IF_NULL(cd); \ |
440 | | FAIL_IF_NOT(cd->cmd == (command)); \ |
441 | | FAIL_IF_NOT(cd->tracker == (trk)); \ |
442 | | FAIL_IF_NOT(cd->type == (typ)); \ |
443 | | FAIL_IF_NOT(cd->expire == (exp)); \ |
444 | | DetectXbitFree(NULL, cd); \ |
445 | | cd = NULL; |
446 | | |
447 | | GOOD_INPUT("set,abc,track ip_pair", |
448 | | DETECT_XBITS_CMD_SET, |
449 | | DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, |
450 | | DETECT_XBITS_EXPIRE_DEFAULT); |
451 | | GOOD_INPUT("set,abc,track ip_pair, expire 3600", |
452 | | DETECT_XBITS_CMD_SET, |
453 | | DETECT_XBITS_TRACK_IPPAIR, VAR_TYPE_IPPAIR_BIT, |
454 | | 3600); |
455 | | GOOD_INPUT("set,abc,track ip_src, expire 1234", |
456 | | DETECT_XBITS_CMD_SET, |
457 | | DETECT_XBITS_TRACK_IPSRC, VAR_TYPE_HOST_BIT, |
458 | | 1234); |
459 | | |
460 | | #undef GOOD_INPUT |
461 | | |
462 | | DetectEngineCtxFree(de_ctx); |
463 | | PASS; |
464 | | } |
465 | | |
466 | | /** |
467 | | * \test |
468 | | */ |
469 | | |
470 | | static int XBitsTestSig01(void) |
471 | | { |
472 | | uint8_t *buf = (uint8_t *) |
473 | | "GET /one/ HTTP/1.1\r\n" |
474 | | "Host: one.example.org\r\n" |
475 | | "\r\n"; |
476 | | uint16_t buflen = strlen((char *)buf); |
477 | | Packet *p = PacketGetFromAlloc(); |
478 | | FAIL_IF_NULL(p); |
479 | | Signature *s = NULL; |
480 | | ThreadVars th_v; |
481 | | DetectEngineThreadCtx *det_ctx = NULL; |
482 | | DetectEngineCtx *de_ctx = NULL; |
483 | | |
484 | | memset(&th_v, 0, sizeof(th_v)); |
485 | | p->src.family = AF_INET; |
486 | | p->dst.family = AF_INET; |
487 | | p->payload = buf; |
488 | | p->payload_len = buflen; |
489 | | p->proto = IPPROTO_TCP; |
490 | | |
491 | | XBitsTestSetup(); |
492 | | |
493 | | de_ctx = DetectEngineCtxInit(); |
494 | | FAIL_IF_NULL(de_ctx); |
495 | | de_ctx->flags |= DE_QUIET; |
496 | | |
497 | | s = DetectEngineAppendSig(de_ctx, |
498 | | "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:1;)"); |
499 | | FAIL_IF_NULL(s); |
500 | | |
501 | | SigGroupBuild(de_ctx); |
502 | | DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); |
503 | | SigMatchSignatures(&th_v, de_ctx, det_ctx, p); |
504 | | DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); |
505 | | DetectEngineCtxFree(de_ctx); |
506 | | XBitsTestShutdown(); |
507 | | SCFree(p); |
508 | | StatsThreadCleanup(&th_v); |
509 | | StatsReleaseResources(); |
510 | | PASS; |
511 | | } |
512 | | |
513 | | /** |
514 | | * \test various options |
515 | | * |
516 | | * \retval 1 on success |
517 | | * \retval 0 on failure |
518 | | */ |
519 | | |
520 | | static int XBitsTestSig02(void) |
521 | | { |
522 | | Signature *s = NULL; |
523 | | DetectEngineCtx *de_ctx = NULL; |
524 | | de_ctx = DetectEngineCtxInit(); |
525 | | FAIL_IF_NULL(de_ctx); |
526 | | de_ctx->flags |= DE_QUIET; |
527 | | |
528 | | s = DetectEngineAppendSig(de_ctx, |
529 | | "alert ip any any -> any any (xbits:isset,abc,track ip_src; content:\"GET \"; sid:1;)"); |
530 | | FAIL_IF_NULL(s); |
531 | | |
532 | | s = DetectEngineAppendSig(de_ctx, |
533 | | "alert ip any any -> any any (xbits:isnotset,abc,track ip_dst; content:\"GET \"; sid:2;)"); |
534 | | FAIL_IF_NULL(s); |
535 | | |
536 | | s = DetectEngineAppendSig(de_ctx, |
537 | | "alert ip any any -> any any (xbits:set,abc,track ip_pair; content:\"GET \"; sid:3;)"); |
538 | | FAIL_IF_NULL(s); |
539 | | |
540 | | s = DetectEngineAppendSig(de_ctx, |
541 | | "alert ip any any -> any any (xbits:unset,abc,track ip_src; content:\"GET \"; sid:4;)"); |
542 | | FAIL_IF_NULL(s); |
543 | | |
544 | | s = DetectEngineAppendSig(de_ctx, |
545 | | "alert ip any any -> any any (xbits:toggle,abc,track ip_dst; content:\"GET \"; sid:5;)"); |
546 | | FAIL_IF_NULL(s); |
547 | | |
548 | | s = DetectEngineAppendSig(de_ctx, |
549 | | "alert ip any any -> any any (xbits:!set,abc,track ip_dst; content:\"GET \"; sid:6;)"); |
550 | | FAIL_IF_NOT_NULL(s); |
551 | | |
552 | | DetectEngineCtxFree(de_ctx); |
553 | | PASS; |
554 | | } |
555 | | |
556 | | /** |
557 | | * \brief this function registers unit tests for XBits |
558 | | */ |
559 | | static void XBitsRegisterTests(void) |
560 | | { |
561 | | UtRegisterTest("XBitsTestParse01", XBitsTestParse01); |
562 | | UtRegisterTest("XBitsTestSig01", XBitsTestSig01); |
563 | | UtRegisterTest("XBitsTestSig02", XBitsTestSig02); |
564 | | } |
565 | | #endif /* UNITTESTS */ |