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  *  \author Breno Silva <breno.silva@gmail.com>
23  *
24  * Implements the flowbits keyword
25  */
26 
27 #include "suricata-common.h"
28 #include "decode.h"
29 #include "detect.h"
30 #include "threads.h"
31 #include "flow.h"
32 #include "flow-bit.h"
33 #include "flow-util.h"
34 #include "detect-flowbits.h"
35 #include "util-spm.h"
36 
37 #include "app-layer-parser.h"
38 
39 #include "detect-parse.h"
40 #include "detect-engine.h"
41 #include "detect-engine-mpm.h"
42 #include "detect-engine-state.h"
43 
44 #include "util-var-name.h"
45 #include "util-unittest.h"
46 #include "util-debug.h"
47 
48 #define PARSE_REGEX         "^([a-z]+)(?:,\\s*(.*))?"
49 static DetectParseRegex parse_regex;
50 
51 #define MAX_TOKENS 100
52 
53 int DetectFlowbitMatch (DetectEngineThreadCtx *, Packet *,
54         const Signature *, const SigMatchCtx *);
55 static int DetectFlowbitSetup (DetectEngineCtx *, Signature *, const char *);
56 static int FlowbitOrAddData(DetectEngineCtx *, DetectFlowbitsData *, char *);
57 void DetectFlowbitFree (DetectEngineCtx *, void *);
58 #ifdef UNITTESTS
59 void FlowBitsRegisterTests(void);
60 #endif
61 
DetectFlowbitsRegister(void)62 void DetectFlowbitsRegister (void)
63 {
64     sigmatch_table[DETECT_FLOWBITS].name = "flowbits";
65     sigmatch_table[DETECT_FLOWBITS].desc = "operate on flow flag";
66     sigmatch_table[DETECT_FLOWBITS].url = "/rules/flow-keywords.html#flowbits";
67     sigmatch_table[DETECT_FLOWBITS].Match = DetectFlowbitMatch;
68     sigmatch_table[DETECT_FLOWBITS].Setup = DetectFlowbitSetup;
69     sigmatch_table[DETECT_FLOWBITS].Free  = DetectFlowbitFree;
70 #ifdef UNITTESTS
71     sigmatch_table[DETECT_FLOWBITS].RegisterTests = FlowBitsRegisterTests;
72 #endif
73     /* this is compatible to ip-only signatures */
74     sigmatch_table[DETECT_FLOWBITS].flags |= SIGMATCH_IPONLY_COMPAT;
75 
76     DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
77 }
78 
FlowbitOrAddData(DetectEngineCtx * de_ctx,DetectFlowbitsData * cd,char * arrptr)79 static int FlowbitOrAddData(DetectEngineCtx *de_ctx, DetectFlowbitsData *cd, char *arrptr)
80 {
81     char *strarr[MAX_TOKENS];
82     char *token;
83     char *saveptr = NULL;
84     uint8_t i = 0;
85 
86     while ((token = strtok_r(arrptr, "|", &saveptr))) {
87         // Check for leading/trailing spaces in the token
88         while(isspace((unsigned char)*token))
89             token++;
90         if (*token == 0)
91             goto next;
92         char *end = token + strlen(token) - 1;
93         while(end > token && isspace((unsigned char)*end))
94             *(end--) = '\0';
95 
96         // Check for spaces in between the flowbit names
97         if (strchr(token, ' ') != NULL) {
98             SCLogError(SC_ERR_INVALID_SIGNATURE, "Spaces are not allowed in flowbit names.");
99             return -1;
100         }
101 
102         if (i == MAX_TOKENS) {
103             SCLogError(SC_ERR_INVALID_SIGNATURE, "Number of flowbits exceeds "
104                        "maximum allowed: %d.", MAX_TOKENS);
105             return -1;
106         }
107         strarr[i++] = token;
108     next:
109         arrptr = NULL;
110     }
111 
112     cd->or_list_size = i;
113     cd->or_list = SCCalloc(cd->or_list_size, sizeof(uint32_t));
114     if (unlikely(cd->or_list == NULL))
115         return -1;
116     for (uint8_t j = 0; j < cd->or_list_size ; j++) {
117         cd->or_list[j] = VarNameStoreSetupAdd(strarr[j], VAR_TYPE_FLOW_BIT);
118         de_ctx->max_fb_id = MAX(cd->or_list[j], de_ctx->max_fb_id);
119     }
120 
121     return 1;
122 }
123 
DetectFlowbitMatchToggle(Packet * p,const DetectFlowbitsData * fd)124 static int DetectFlowbitMatchToggle (Packet *p, const DetectFlowbitsData *fd)
125 {
126     if (p->flow == NULL)
127         return 0;
128 
129     FlowBitToggle(p->flow,fd->idx);
130 
131     return 1;
132 }
133 
DetectFlowbitMatchUnset(Packet * p,const DetectFlowbitsData * fd)134 static int DetectFlowbitMatchUnset (Packet *p, const DetectFlowbitsData *fd)
135 {
136     if (p->flow == NULL)
137         return 0;
138 
139     FlowBitUnset(p->flow,fd->idx);
140 
141     return 1;
142 }
143 
DetectFlowbitMatchSet(Packet * p,const DetectFlowbitsData * fd)144 static int DetectFlowbitMatchSet (Packet *p, const DetectFlowbitsData *fd)
145 {
146     if (p->flow == NULL)
147         return 0;
148 
149     FlowBitSet(p->flow,fd->idx);
150 
151     return 1;
152 }
153 
DetectFlowbitMatchIsset(Packet * p,const DetectFlowbitsData * fd)154 static int DetectFlowbitMatchIsset (Packet *p, const DetectFlowbitsData *fd)
155 {
156     if (p->flow == NULL)
157         return 0;
158     if (fd->or_list_size > 0) {
159         for (uint8_t i = 0; i < fd->or_list_size; i++) {
160             if (FlowBitIsset(p->flow, fd->or_list[i]) == 1)
161                 return 1;
162         }
163         return 0;
164     }
165 
166     return FlowBitIsset(p->flow,fd->idx);
167 }
168 
DetectFlowbitMatchIsnotset(Packet * p,const DetectFlowbitsData * fd)169 static int DetectFlowbitMatchIsnotset (Packet *p, const DetectFlowbitsData *fd)
170 {
171     if (p->flow == NULL)
172         return 0;
173     if (fd->or_list_size > 0) {
174         for (uint8_t i = 0; i < fd->or_list_size; i++) {
175             if (FlowBitIsnotset(p->flow, fd->or_list[i]) == 1)
176                 return 1;
177         }
178         return 0;
179     }
180     return FlowBitIsnotset(p->flow,fd->idx);
181 }
182 
183 /*
184  * returns 0: no match
185  *         1: match
186  *        -1: error
187  */
188 
DetectFlowbitMatch(DetectEngineThreadCtx * det_ctx,Packet * p,const Signature * s,const SigMatchCtx * ctx)189 int DetectFlowbitMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
190         const Signature *s, const SigMatchCtx *ctx)
191 {
192     const DetectFlowbitsData *fd = (const DetectFlowbitsData *)ctx;
193     if (fd == NULL)
194         return 0;
195 
196     switch (fd->cmd) {
197         case DETECT_FLOWBITS_CMD_ISSET:
198             return DetectFlowbitMatchIsset(p,fd);
199         case DETECT_FLOWBITS_CMD_ISNOTSET:
200             return DetectFlowbitMatchIsnotset(p,fd);
201         case DETECT_FLOWBITS_CMD_SET:
202             return DetectFlowbitMatchSet(p,fd);
203         case DETECT_FLOWBITS_CMD_UNSET:
204             return DetectFlowbitMatchUnset(p,fd);
205         case DETECT_FLOWBITS_CMD_TOGGLE:
206             return DetectFlowbitMatchToggle(p,fd);
207         default:
208             SCLogError(SC_ERR_UNKNOWN_VALUE, "unknown cmd %" PRIu32 "", fd->cmd);
209             return 0;
210     }
211 
212     return 0;
213 }
214 
DetectFlowbitParse(const char * str,char * cmd,int cmd_len,char * name,int name_len)215 static int DetectFlowbitParse(const char *str, char *cmd, int cmd_len, char *name,
216     int name_len)
217 {
218     const int max_substrings = 30;
219     int count, rc;
220     int ov[max_substrings];
221 
222     count = DetectParsePcreExec(&parse_regex, str, 0, 0, ov, max_substrings);
223     if (count != 2 && count != 3) {
224         SCLogError(SC_ERR_PCRE_MATCH,
225             "\"%s\" is not a valid setting for flowbits.", str);
226         return 0;
227     }
228 
229     rc = pcre_copy_substring((char *)str, ov, max_substrings, 1, cmd, cmd_len);
230     if (rc < 0) {
231         SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
232         return 0;
233     }
234 
235     if (count == 3) {
236         rc = pcre_copy_substring((char *)str, ov, max_substrings, 2, name,
237             name_len);
238         if (rc < 0) {
239             SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
240             return 0;
241         }
242 
243         /* Trim trailing whitespace. */
244         while (strlen(name) > 0 && isblank(name[strlen(name) - 1])) {
245             name[strlen(name) - 1] = '\0';
246         }
247 
248         if (strchr(name, '|') == NULL) {
249             /* Validate name, spaces are not allowed. */
250             for (size_t i = 0; i < strlen(name); i++) {
251                 if (isblank(name[i])) {
252                     SCLogError(SC_ERR_INVALID_SIGNATURE,
253                         "spaces not allowed in flowbit names");
254                     return 0;
255                 }
256             }
257         }
258     }
259 
260     return 1;
261 }
262 
DetectFlowbitSetup(DetectEngineCtx * de_ctx,Signature * s,const char * rawstr)263 int DetectFlowbitSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
264 {
265     DetectFlowbitsData *cd = NULL;
266     SigMatch *sm = NULL;
267     uint8_t fb_cmd = 0;
268     char fb_cmd_str[16] = "", fb_name[256] = "";
269 
270     if (!DetectFlowbitParse(rawstr, fb_cmd_str, sizeof(fb_cmd_str), fb_name,
271             sizeof(fb_name))) {
272         return -1;
273     }
274 
275     if (strcmp(fb_cmd_str,"noalert") == 0) {
276         fb_cmd = DETECT_FLOWBITS_CMD_NOALERT;
277     } else if (strcmp(fb_cmd_str,"isset") == 0) {
278         fb_cmd = DETECT_FLOWBITS_CMD_ISSET;
279     } else if (strcmp(fb_cmd_str,"isnotset") == 0) {
280         fb_cmd = DETECT_FLOWBITS_CMD_ISNOTSET;
281     } else if (strcmp(fb_cmd_str,"set") == 0) {
282         fb_cmd = DETECT_FLOWBITS_CMD_SET;
283     } else if (strcmp(fb_cmd_str,"unset") == 0) {
284         fb_cmd = DETECT_FLOWBITS_CMD_UNSET;
285     } else if (strcmp(fb_cmd_str,"toggle") == 0) {
286         fb_cmd = DETECT_FLOWBITS_CMD_TOGGLE;
287     } else {
288         SCLogError(SC_ERR_UNKNOWN_VALUE, "ERROR: flowbits action \"%s\" is not supported.", fb_cmd_str);
289         goto error;
290     }
291 
292     switch (fb_cmd) {
293         case DETECT_FLOWBITS_CMD_NOALERT:
294             if (strlen(fb_name) != 0)
295                 goto error;
296             s->flags |= SIG_FLAG_NOALERT;
297             return 0;
298         case DETECT_FLOWBITS_CMD_ISNOTSET:
299         case DETECT_FLOWBITS_CMD_ISSET:
300         case DETECT_FLOWBITS_CMD_SET:
301         case DETECT_FLOWBITS_CMD_UNSET:
302         case DETECT_FLOWBITS_CMD_TOGGLE:
303         default:
304             if (strlen(fb_name) == 0)
305                 goto error;
306             break;
307     }
308 
309     cd = SCCalloc(1, sizeof(DetectFlowbitsData));
310     if (unlikely(cd == NULL))
311         goto error;
312     if (strchr(fb_name, '|') != NULL) {
313         int retval = FlowbitOrAddData(de_ctx, cd, fb_name);
314         if (retval == -1) {
315             goto error;
316         }
317         cd->cmd = fb_cmd;
318     } else {
319         cd->idx = VarNameStoreSetupAdd(fb_name, VAR_TYPE_FLOW_BIT);
320         de_ctx->max_fb_id = MAX(cd->idx, de_ctx->max_fb_id);
321         cd->cmd = fb_cmd;
322         cd->or_list_size = 0;
323         cd->or_list = NULL;
324         SCLogDebug("idx %" PRIu32 ", cmd %s, name %s",
325             cd->idx, fb_cmd_str, strlen(fb_name) ? fb_name : "(none)");
326     }
327     /* Okay so far so good, lets get this into a SigMatch
328      * and put it in the Signature. */
329     sm = SigMatchAlloc();
330     if (sm == NULL)
331         goto error;
332 
333     sm->type = DETECT_FLOWBITS;
334     sm->ctx = (SigMatchCtx *)cd;
335 
336     switch (fb_cmd) {
337         /* case DETECT_FLOWBITS_CMD_NOALERT can't happen here */
338 
339         case DETECT_FLOWBITS_CMD_ISNOTSET:
340         case DETECT_FLOWBITS_CMD_ISSET:
341             /* checks, so packet list */
342             SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
343             break;
344 
345         case DETECT_FLOWBITS_CMD_SET:
346         case DETECT_FLOWBITS_CMD_UNSET:
347         case DETECT_FLOWBITS_CMD_TOGGLE:
348             /* modifiers, only run when entire sig has matched */
349             SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_POSTMATCH);
350             break;
351 
352         // suppress coverity warning as scan-build-7 warns w/o this.
353         // coverity[deadcode : FALSE]
354         default:
355             goto error;
356     }
357 
358     return 0;
359 
360 error:
361     if (cd != NULL)
362         DetectFlowbitFree(de_ctx, cd);
363     if (sm != NULL)
364         SCFree(sm);
365     return -1;
366 }
367 
DetectFlowbitFree(DetectEngineCtx * de_ctx,void * ptr)368 void DetectFlowbitFree (DetectEngineCtx *de_ctx, void *ptr)
369 {
370     DetectFlowbitsData *fd = (DetectFlowbitsData *)ptr;
371     if (fd == NULL)
372         return;
373     if (fd->or_list != NULL)
374         SCFree(fd->or_list);
375     SCFree(fd);
376 }
377 
378 struct FBAnalyze {
379     uint16_t cnts[DETECT_FLOWBITS_CMD_MAX];
380     uint16_t state_cnts[DETECT_FLOWBITS_CMD_MAX];
381 
382     uint32_t *set_sids;
383     uint32_t set_sids_idx;
384     uint32_t set_sids_size;
385 
386     uint32_t *isset_sids;
387     uint32_t isset_sids_idx;
388     uint32_t isset_sids_size;
389 
390     uint32_t *isnotset_sids;
391     uint32_t isnotset_sids_idx;
392     uint32_t isnotset_sids_size;
393 
394     uint32_t *unset_sids;
395     uint32_t unset_sids_idx;
396     uint32_t unset_sids_size;
397 
398     uint32_t *toggle_sids;
399     uint32_t toggle_sids_idx;
400     uint32_t toggle_sids_size;
401 };
402 
403 extern int rule_engine_analysis_set;
404 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
405         struct FBAnalyze *array, uint32_t elements);
406 
DetectFlowbitsAnalyze(DetectEngineCtx * de_ctx)407 int DetectFlowbitsAnalyze(DetectEngineCtx *de_ctx)
408 {
409     const uint32_t max_fb_id = de_ctx->max_fb_id;
410     if (max_fb_id == 0)
411         return 0;
412 
413 #define MAX_SIDS 8
414     uint32_t array_size = max_fb_id + 1;
415     struct FBAnalyze *array = SCCalloc(array_size, sizeof(struct FBAnalyze));
416 
417     if (array == NULL) {
418         SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate flowbit analyze array");
419         return -1;
420     }
421 
422     SCLogDebug("fb analyzer array size: %"PRIu64,
423             (uint64_t)(array_size * sizeof(struct FBAnalyze)));
424 
425     /* fill flowbit array, updating counters per sig */
426     for (uint32_t i = 0; i < de_ctx->sig_array_len; i++) {
427         const Signature *s = de_ctx->sig_array[i];
428         bool has_state = false;
429 
430         /* see if the signature uses stateful matching */
431         for (uint32_t x = DETECT_SM_LIST_DYNAMIC_START; x < s->init_data->smlists_array_size; x++) {
432             if (s->init_data->smlists[x] == NULL)
433                 continue;
434             has_state = true;
435             break;
436         }
437 
438         for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
439             switch (sm->type) {
440                 case DETECT_FLOWBITS:
441                 {
442                     /* figure out the flowbit action */
443                     const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
444                     // Handle flowbit array in case of ORed flowbits
445                     for (uint8_t k = 0; k < fb->or_list_size; k++) {
446                         array[fb->or_list[k]].cnts[fb->cmd]++;
447                         if (has_state)
448                             array[fb->or_list[k]].state_cnts[fb->cmd]++;
449                         if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
450                             if (array[fb->or_list[k]].isset_sids_idx >= array[fb->or_list[k]].isset_sids_size) {
451                                 uint32_t old_size = array[fb->or_list[k]].isset_sids_size;
452                                 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
453 
454                                 void *ptr = SCRealloc(array[fb->or_list[k]].isset_sids, new_size * sizeof(uint32_t));
455                                 if (ptr == NULL)
456                                     goto end;
457                                 array[fb->or_list[k]].isset_sids_size = new_size;
458                                 array[fb->or_list[k]].isset_sids = ptr;
459                             }
460 
461                             array[fb->or_list[k]].isset_sids[array[fb->or_list[k]].isset_sids_idx] = s->num;
462                             array[fb->or_list[k]].isset_sids_idx++;
463                         } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
464                             if (array[fb->or_list[k]].isnotset_sids_idx >= array[fb->or_list[k]].isnotset_sids_size) {
465                                 uint32_t old_size = array[fb->or_list[k]].isnotset_sids_size;
466                                 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
467 
468                                 void *ptr = SCRealloc(array[fb->or_list[k]].isnotset_sids, new_size * sizeof(uint32_t));
469                                 if (ptr == NULL)
470                                     goto end;
471                                 array[fb->or_list[k]].isnotset_sids_size = new_size;
472                                 array[fb->or_list[k]].isnotset_sids = ptr;
473                             }
474 
475                             array[fb->or_list[k]].isnotset_sids[array[fb->or_list[k]].isnotset_sids_idx] = s->num;
476                             array[fb->or_list[k]].isnotset_sids_idx++;
477                         }
478                     }
479                     if (fb->or_list_size == 0) {
480                         array[fb->idx].cnts[fb->cmd]++;
481                         if (has_state)
482                             array[fb->idx].state_cnts[fb->cmd]++;
483                         if (fb->cmd == DETECT_FLOWBITS_CMD_ISSET) {
484                             if (array[fb->idx].isset_sids_idx >= array[fb->idx].isset_sids_size) {
485                                 uint32_t old_size = array[fb->idx].isset_sids_size;
486                                 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
487 
488                                 void *ptr = SCRealloc(array[fb->idx].isset_sids, new_size * sizeof(uint32_t));
489                                 if (ptr == NULL)
490                                     goto end;
491                                 array[fb->idx].isset_sids_size = new_size;
492                                 array[fb->idx].isset_sids = ptr;
493                             }
494 
495                             array[fb->idx].isset_sids[array[fb->idx].isset_sids_idx] = s->num;
496                             array[fb->idx].isset_sids_idx++;
497                         } else if (fb->cmd == DETECT_FLOWBITS_CMD_ISNOTSET) {
498                             if (array[fb->idx].isnotset_sids_idx >= array[fb->idx].isnotset_sids_size) {
499                                 uint32_t old_size = array[fb->idx].isnotset_sids_size;
500                                 uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
501 
502                                 void *ptr = SCRealloc(array[fb->idx].isnotset_sids, new_size * sizeof(uint32_t));
503                                 if (ptr == NULL)
504                                     goto end;
505                                 array[fb->idx].isnotset_sids_size = new_size;
506                                 array[fb->idx].isnotset_sids = ptr;
507                             }
508 
509                             array[fb->idx].isnotset_sids[array[fb->idx].isnotset_sids_idx] = s->num;
510                             array[fb->idx].isnotset_sids_idx++;
511                         }
512                     }
513                 }
514             }
515         }
516         for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_POSTMATCH] ; sm != NULL; sm = sm->next) {
517             switch (sm->type) {
518                 case DETECT_FLOWBITS:
519                 {
520                     /* figure out what flowbit action */
521                     const DetectFlowbitsData *fb = (DetectFlowbitsData *)sm->ctx;
522                     array[fb->idx].cnts[fb->cmd]++;
523                     if (has_state)
524                         array[fb->idx].state_cnts[fb->cmd]++;
525                     if (fb->cmd == DETECT_FLOWBITS_CMD_SET) {
526                         if (array[fb->idx].set_sids_idx >= array[fb->idx].set_sids_size) {
527                             uint32_t old_size = array[fb->idx].set_sids_size;
528                             uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
529 
530                             void *ptr = SCRealloc(array[fb->idx].set_sids, new_size * sizeof(uint32_t));
531                             if (ptr == NULL)
532                                 goto end;
533                             array[fb->idx].set_sids_size = new_size;
534                             array[fb->idx].set_sids = ptr;
535                         }
536 
537                         array[fb->idx].set_sids[array[fb->idx].set_sids_idx] = s->num;
538                         array[fb->idx].set_sids_idx++;
539                     }
540                     else if (fb->cmd == DETECT_FLOWBITS_CMD_UNSET) {
541                         if (array[fb->idx].unset_sids_idx >= array[fb->idx].unset_sids_size) {
542                             uint32_t old_size = array[fb->idx].unset_sids_size;
543                             uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
544 
545                             void *ptr = SCRealloc(array[fb->idx].unset_sids, new_size * sizeof(uint32_t));
546                             if (ptr == NULL)
547                                 goto end;
548                             array[fb->idx].unset_sids_size = new_size;
549                             array[fb->idx].unset_sids = ptr;
550                         }
551 
552                         array[fb->idx].unset_sids[array[fb->idx].unset_sids_idx] = s->num;
553                         array[fb->idx].unset_sids_idx++;
554                     }
555                     else if (fb->cmd == DETECT_FLOWBITS_CMD_TOGGLE) {
556                         if (array[fb->idx].toggle_sids_idx >= array[fb->idx].toggle_sids_size) {
557                             uint32_t old_size = array[fb->idx].toggle_sids_size;
558                             uint32_t new_size = MAX(2 * old_size, MAX_SIDS);
559 
560                             void *ptr = SCRealloc(array[fb->idx].toggle_sids, new_size * sizeof(uint32_t));
561                             if (ptr == NULL)
562                                 goto end;
563                             array[fb->idx].toggle_sids_size = new_size;
564                             array[fb->idx].toggle_sids = ptr;
565                         }
566 
567                         array[fb->idx].toggle_sids[array[fb->idx].toggle_sids_idx] = s->num;
568                         array[fb->idx].toggle_sids_idx++;
569                     }
570                 }
571             }
572         }
573     }
574 
575     /* walk array to see if all bits make sense */
576     for (uint32_t i = 0; i < array_size; i++) {
577         char *varname = VarNameStoreSetupLookup(i, VAR_TYPE_FLOW_BIT);
578         if (varname == NULL)
579             continue;
580 
581         bool to_state = false;
582 
583         if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] &&
584             array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE] == 0 &&
585             array[i].cnts[DETECT_FLOWBITS_CMD_SET] == 0) {
586 
587             const Signature *s = de_ctx->sig_array[array[i].isset_sids[0]];
588             SCLogWarning(SC_WARN_FLOWBIT, "flowbit '%s' is checked but not "
589                     "set. Checked in %u and %u other sigs",
590                     varname, s->id, array[i].isset_sids_idx - 1);
591         }
592         if (array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] &&
593             array[i].state_cnts[DETECT_FLOWBITS_CMD_SET] == 0)
594         {
595             SCLogDebug("flowbit %s/%u: isset in state, set not in state", varname, i);
596         }
597 
598         /* if signature depends on 'stateful' flowbits, then turn the
599          * sig into a stateful sig itself */
600         if (array[i].cnts[DETECT_FLOWBITS_CMD_ISSET] > 0 &&
601             array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET] == 0 &&
602             array[i].state_cnts[DETECT_FLOWBITS_CMD_SET])
603         {
604             SCLogDebug("flowbit %s/%u: isset not in state, set in state", varname, i);
605             to_state = true;
606         }
607 
608         SCLogDebug("ALL flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
609                 array[i].cnts[DETECT_FLOWBITS_CMD_SET], array[i].cnts[DETECT_FLOWBITS_CMD_TOGGLE],
610                 array[i].cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
611                 array[i].cnts[DETECT_FLOWBITS_CMD_ISSET]);
612         SCLogDebug("STATE flowbit %s/%u: sets %u toggles %u unsets %u isnotsets %u issets %u", varname, i,
613                 array[i].state_cnts[DETECT_FLOWBITS_CMD_SET], array[i].state_cnts[DETECT_FLOWBITS_CMD_TOGGLE],
614                 array[i].state_cnts[DETECT_FLOWBITS_CMD_UNSET], array[i].state_cnts[DETECT_FLOWBITS_CMD_ISNOTSET],
615                 array[i].state_cnts[DETECT_FLOWBITS_CMD_ISSET]);
616         for (uint32_t x = 0; x < array[i].set_sids_idx; x++) {
617             SCLogDebug("SET flowbit %s/%u: SID %u", varname, i,
618                     de_ctx->sig_array[array[i].set_sids[x]]->id);
619         }
620         for (uint32_t x = 0; x < array[i].isset_sids_idx; x++) {
621             Signature *s = de_ctx->sig_array[array[i].isset_sids[x]];
622             SCLogDebug("GET flowbit %s/%u: SID %u", varname, i, s->id);
623 
624             if (to_state) {
625                 s->init_data->init_flags |= SIG_FLAG_INIT_STATE_MATCH;
626                 SCLogDebug("made SID %u stateful because it depends on "
627                         "stateful rules that set flowbit %s", s->id, varname);
628             }
629         }
630         SCFree(varname);
631     }
632 
633     if (rule_engine_analysis_set) {
634         DetectFlowbitsAnalyzeDump(de_ctx, array, array_size);
635     }
636 
637 end:
638     for (uint32_t i = 0; i < array_size; i++) {
639         SCFree(array[i].set_sids);
640         SCFree(array[i].unset_sids);
641         SCFree(array[i].isset_sids);
642         SCFree(array[i].isnotset_sids);
643         SCFree(array[i].toggle_sids);
644     }
645     SCFree(array);
646 
647     return 0;
648 }
649 
650 SCMutex g_flowbits_dump_write_m = SCMUTEX_INITIALIZER;
DetectFlowbitsAnalyzeDump(const DetectEngineCtx * de_ctx,struct FBAnalyze * array,uint32_t elements)651 static void DetectFlowbitsAnalyzeDump(const DetectEngineCtx *de_ctx,
652         struct FBAnalyze *array, uint32_t elements)
653 {
654     JsonBuilder *js = jb_new_object();
655     if (js == NULL)
656         return;
657 
658     jb_open_array(js, "flowbits");
659     for (uint32_t x = 0; x < elements; x++) {
660         char *varname = VarNameStoreSetupLookup(x, VAR_TYPE_FLOW_BIT);
661         if (varname == NULL)
662             continue;
663 
664         const struct FBAnalyze *e = &array[x];
665 
666         jb_start_object(js);
667         jb_set_string(js, "name", varname);
668         jb_set_uint(js, "internal_id", x);
669         jb_set_uint(js, "set_cnt", e->cnts[DETECT_FLOWBITS_CMD_SET]);
670         jb_set_uint(js, "unset_cnt", e->cnts[DETECT_FLOWBITS_CMD_UNSET]);
671         jb_set_uint(js, "toggle_cnt", e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]);
672         jb_set_uint(js, "isset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISSET]);
673         jb_set_uint(js, "isnotset_cnt", e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]);
674 
675         // sets
676         if (e->cnts[DETECT_FLOWBITS_CMD_SET]) {
677             jb_open_array(js, "sets");
678             for (uint32_t i = 0; i < e->set_sids_idx; i++) {
679                 const Signature *s = de_ctx->sig_array[e->set_sids[i]];
680                 jb_append_uint(js, s->id);
681             }
682             jb_close(js);
683         }
684         // gets
685         if (e->cnts[DETECT_FLOWBITS_CMD_ISSET]) {
686             jb_open_array(js, "isset");
687             for (uint32_t i = 0; i < e->isset_sids_idx; i++) {
688                 const Signature *s = de_ctx->sig_array[e->isset_sids[i]];
689                 jb_append_uint(js, s->id);
690             }
691             jb_close(js);
692         }
693         // isnotset
694         if (e->cnts[DETECT_FLOWBITS_CMD_ISNOTSET]) {
695             jb_open_array(js, "isnotset");
696             for (uint32_t i = 0; i < e->isnotset_sids_idx; i++) {
697                 const Signature *s = de_ctx->sig_array[e->isnotset_sids[i]];
698                 jb_append_uint(js, s->id);
699             }
700             jb_close(js);
701         }
702         // unset
703         if (e->cnts[DETECT_FLOWBITS_CMD_UNSET]) {
704             jb_open_array(js, "unset");
705             for (uint32_t i = 0; i < e->unset_sids_idx; i++) {
706                 const Signature *s = de_ctx->sig_array[e->unset_sids[i]];
707                 jb_append_uint(js, s->id);
708             }
709             jb_close(js);
710         }
711         // toggle
712         if (e->cnts[DETECT_FLOWBITS_CMD_TOGGLE]) {
713             jb_open_array(js, "toggle");
714             for (uint32_t i = 0; i < e->toggle_sids_idx; i++) {
715                 const Signature *s = de_ctx->sig_array[e->toggle_sids[i]];
716                 jb_append_uint(js, s->id);
717             }
718             jb_close(js);
719         }
720         SCFree(varname);
721         jb_close(js);
722     }
723     jb_close(js); // array
724     jb_close(js); // object
725 
726     const char *filename = "flowbits.json";
727     const char *log_dir = ConfigGetLogDirectory();
728     char log_path[PATH_MAX] = "";
729     snprintf(log_path, sizeof(log_path), "%s/%s", log_dir, filename);
730 
731     SCMutexLock(&g_flowbits_dump_write_m);
732     FILE *fp = fopen(log_path, "w");
733     if (fp != NULL) {
734         fwrite(jb_ptr(js), jb_len(js), 1, fp);
735         fprintf(fp, "\n");
736         fclose(fp);
737     }
738     SCMutexUnlock(&g_flowbits_dump_write_m);
739 
740     jb_free(js);
741 }
742 
743 #ifdef UNITTESTS
744 
FlowBitsTestParse01(void)745 static int FlowBitsTestParse01(void)
746 {
747     char command[16] = "", name[16] = "";
748 
749     /* Single argument version. */
750     FAIL_IF(!DetectFlowbitParse("noalert", command, sizeof(command), name,
751             sizeof(name)));
752     FAIL_IF(strcmp(command, "noalert") != 0);
753 
754     /* No leading or trailing spaces. */
755     FAIL_IF(!DetectFlowbitParse("set,flowbit", command, sizeof(command), name,
756             sizeof(name)));
757     FAIL_IF(strcmp(command, "set") != 0);
758     FAIL_IF(strcmp(name, "flowbit") != 0);
759 
760     /* Leading space. */
761     FAIL_IF(!DetectFlowbitParse("set, flowbit", command, sizeof(command), name,
762             sizeof(name)));
763     FAIL_IF(strcmp(command, "set") != 0);
764     FAIL_IF(strcmp(name, "flowbit") != 0);
765 
766     /* Trailing space. */
767     FAIL_IF(!DetectFlowbitParse("set,flowbit ", command, sizeof(command), name,
768             sizeof(name)));
769     FAIL_IF(strcmp(command, "set") != 0);
770     FAIL_IF(strcmp(name, "flowbit") != 0);
771 
772     /* Leading and trailing space. */
773     FAIL_IF(!DetectFlowbitParse("set, flowbit ", command, sizeof(command), name,
774             sizeof(name)));
775     FAIL_IF(strcmp(command, "set") != 0);
776     FAIL_IF(strcmp(name, "flowbit") != 0);
777 
778     /* Spaces are not allowed in the name. */
779     FAIL_IF(DetectFlowbitParse("set,namewith space", command, sizeof(command),
780             name, sizeof(name)));
781 
782     PASS;
783 }
784 
785 /**
786  * \test FlowBitsTestSig01 is a test for a valid noalert flowbits option
787  *
788  *  \retval 1 on succces
789  *  \retval 0 on failure
790  */
791 
FlowBitsTestSig01(void)792 static int FlowBitsTestSig01(void)
793 {
794     Signature *s = NULL;
795     DetectEngineCtx *de_ctx = NULL;
796 
797     de_ctx = DetectEngineCtxInit();
798     FAIL_IF_NULL(de_ctx);
799 
800     de_ctx->flags |= DE_QUIET;
801 
802     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert,wrongusage; content:\"GET \"; sid:1;)");
803     FAIL_IF_NOT_NULL(s);
804 
805     SigGroupBuild(de_ctx);
806     DetectEngineCtxFree(de_ctx);
807     PASS;
808 }
809 
810 /**
811  * \test FlowBitsTestSig02 is a test for a valid isset,set,isnotset,unset,toggle flowbits options
812  *
813  *  \retval 1 on succces
814  *  \retval 0 on failure
815  */
816 
FlowBitsTestSig02(void)817 static int FlowBitsTestSig02(void)
818 {
819     Signature *s = NULL;
820     ThreadVars th_v;
821     DetectEngineCtx *de_ctx = NULL;
822 
823     memset(&th_v, 0, sizeof(th_v));
824 
825     de_ctx = DetectEngineCtxInit();
826     FAIL_IF_NULL(de_ctx);
827 
828     de_ctx->flags |= DE_QUIET;
829 
830     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset rule need an option\"; flowbits:isset; content:\"GET \"; sid:1;)");
831     FAIL_IF_NOT_NULL(s);
832 
833     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isnotset rule need an option\"; flowbits:isnotset; content:\"GET \"; sid:2;)");
834     FAIL_IF_NOT_NULL(s);
835 
836     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"set rule need an option\"; flowbits:set; content:\"GET \"; sid:3;)");
837     FAIL_IF_NOT_NULL(s);
838 
839     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"unset rule need an option\"; flowbits:unset; content:\"GET \"; sid:4;)");
840     FAIL_IF_NOT_NULL(s);
841 
842     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"toggle rule need an option\"; flowbits:toggle; content:\"GET \"; sid:5;)");
843     FAIL_IF_NOT_NULL(s);
844 
845     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"!set is not an option\"; flowbits:!set,myerr; content:\"GET \"; sid:6;)");
846     FAIL_IF_NOT_NULL(s);
847 
848     SigGroupBuild(de_ctx);
849     DetectEngineCtxFree(de_ctx);
850 
851     PASS;
852 }
853 
854 /**
855  * \test FlowBitsTestSig03 is a test for a invalid flowbits option
856  *
857  *  \retval 1 on succces
858  *  \retval 0 on failure
859  */
860 
FlowBitsTestSig03(void)861 static int FlowBitsTestSig03(void)
862 {
863     Signature *s = NULL;
864     DetectEngineCtx *de_ctx = NULL;
865 
866     de_ctx = DetectEngineCtxInit();
867     FAIL_IF_NULL(de_ctx);
868 
869     de_ctx->flags |= DE_QUIET;
870 
871     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Unknown cmd\"; flowbits:wrongcmd; content:\"GET \"; sid:1;)");
872     FAIL_IF_NOT_NULL(s);
873 
874     SigGroupBuild(de_ctx);
875     DetectEngineCtxFree(de_ctx);
876     PASS;
877 }
878 
879 /**
880  * \test FlowBitsTestSig04 is a test check idx value
881  *
882  *  \retval 1 on succces
883  *  \retval 0 on failure
884  */
885 
FlowBitsTestSig04(void)886 static int FlowBitsTestSig04(void)
887 {
888     Signature *s = NULL;
889     DetectEngineCtx *de_ctx = NULL;
890     int idx = 0;
891     de_ctx = DetectEngineCtxInit();
892     FAIL_IF_NULL(de_ctx);
893 
894     de_ctx->flags |= DE_QUIET;
895 
896     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"isset option\"; flowbits:isset,fbt; content:\"GET \"; sid:1;)");
897     FAIL_IF_NULL(s);
898 
899     idx = VarNameStoreSetupAdd("fbt", VAR_TYPE_FLOW_BIT);
900     FAIL_IF(idx != 1);
901 
902     SigGroupBuild(de_ctx);
903     DetectEngineCtxFree(de_ctx);
904     PASS;
905 }
906 
907 /**
908  * \test FlowBitsTestSig05 is a test check noalert flag
909  *
910  *  \retval 1 on succces
911  *  \retval 0 on failure
912  */
913 
FlowBitsTestSig05(void)914 static int FlowBitsTestSig05(void)
915 {
916     Signature *s = NULL;
917     DetectEngineCtx *de_ctx = NULL;
918 
919     de_ctx = DetectEngineCtxInit();
920     FAIL_IF_NULL(de_ctx);
921 
922     de_ctx->flags |= DE_QUIET;
923 
924     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Noalert\"; flowbits:noalert; content:\"GET \"; sid:1;)");
925     FAIL_IF_NULL(s);
926     FAIL_IF((s->flags & SIG_FLAG_NOALERT) != SIG_FLAG_NOALERT);
927 
928     SigGroupBuild(de_ctx);
929     DetectEngineCtxFree(de_ctx);
930     PASS;
931 }
932 
933 /**
934  * \test FlowBitsTestSig06 is a test set flowbits option
935  *
936  *  \retval 1 on succces
937  *  \retval 0 on failure
938  */
939 
FlowBitsTestSig06(void)940 static int FlowBitsTestSig06(void)
941 {
942     uint8_t *buf = (uint8_t *)
943                     "GET /one/ HTTP/1.1\r\n"
944                     "Host: one.example.org\r\n"
945                     "\r\n";
946     uint16_t buflen = strlen((char *)buf);
947     Packet *p = SCMalloc(SIZE_OF_PACKET);
948     FAIL_IF_NULL(p);
949     Signature *s = NULL;
950     ThreadVars th_v;
951     DetectEngineThreadCtx *det_ctx = NULL;
952     DetectEngineCtx *de_ctx = NULL;
953     Flow f;
954     GenericVar flowvar, *gv = NULL;
955     int result = 0;
956     uint32_t idx = 0;
957 
958     memset(p, 0, SIZE_OF_PACKET);
959     memset(&th_v, 0, sizeof(th_v));
960     memset(&f, 0, sizeof(Flow));
961     memset(&flowvar, 0, sizeof(GenericVar));
962 
963     FLOW_INITIALIZE(&f);
964     p->flow = &f;
965     p->flow->flowvar = &flowvar;
966 
967     p->src.family = AF_INET;
968     p->dst.family = AF_INET;
969     p->payload = buf;
970     p->payload_len = buflen;
971     p->proto = IPPROTO_TCP;
972     p->flags |= PKT_HAS_FLOW;
973     p->flowflags |= FLOW_PKT_TOSERVER;
974 
975     de_ctx = DetectEngineCtxInit();
976     FAIL_IF_NULL(de_ctx);
977 
978     de_ctx->flags |= DE_QUIET;
979 
980     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow; sid:10;)");
981     FAIL_IF_NULL(s);
982 
983     idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
984     SigGroupBuild(de_ctx);
985     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
986 
987     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
988 
989     gv = p->flow->flowvar;
990     FAIL_IF_NULL(gv);
991     for ( ; gv != NULL; gv = gv->next) {
992         if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
993                 result = 1;
994         }
995     }
996     FAIL_IF_NOT(result);
997 
998     DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
999     DetectEngineCtxFree(de_ctx);
1000 
1001     FLOW_DESTROY(&f);
1002 
1003     SCFree(p);
1004     PASS;
1005 }
1006 
1007 /**
1008  * \test FlowBitsTestSig07 is a test unset flowbits option
1009  *
1010  *  \retval 1 on succces
1011  *  \retval 0 on failure
1012  */
1013 
FlowBitsTestSig07(void)1014 static int FlowBitsTestSig07(void)
1015 {
1016     uint8_t *buf = (uint8_t *)
1017                     "GET /one/ HTTP/1.1\r\n"
1018                     "Host: one.example.org\r\n"
1019                     "\r\n";
1020     uint16_t buflen = strlen((char *)buf);
1021     Packet *p = SCMalloc(SIZE_OF_PACKET);
1022     FAIL_IF_NULL(p);
1023     Signature *s = NULL;
1024     ThreadVars th_v;
1025     DetectEngineThreadCtx *det_ctx = NULL;
1026     DetectEngineCtx *de_ctx = NULL;
1027     Flow f;
1028     GenericVar flowvar, *gv = NULL;
1029     int result = 0;
1030     uint32_t idx = 0;
1031 
1032     memset(p, 0, SIZE_OF_PACKET);
1033     memset(&th_v, 0, sizeof(th_v));
1034     memset(&f, 0, sizeof(Flow));
1035     memset(&flowvar, 0, sizeof(GenericVar));
1036 
1037     FLOW_INITIALIZE(&f);
1038     p->flow = &f;
1039     p->flow->flowvar = &flowvar;
1040 
1041     p->src.family = AF_INET;
1042     p->dst.family = AF_INET;
1043     p->payload = buf;
1044     p->payload_len = buflen;
1045     p->proto = IPPROTO_TCP;
1046 
1047     de_ctx = DetectEngineCtxInit();
1048     FAIL_IF_NULL(de_ctx);
1049 
1050     de_ctx->flags |= DE_QUIET;
1051 
1052     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1053     FAIL_IF_NULL(s);
1054 
1055     s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:unset,myflow2; sid:11;)");
1056     FAIL_IF_NULL(s);
1057 
1058     idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1059     SigGroupBuild(de_ctx);
1060     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1061 
1062     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1063 
1064     gv = p->flow->flowvar;
1065     FAIL_IF_NULL(gv);
1066 
1067     for ( ; gv != NULL; gv = gv->next) {
1068         if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1069                 result = 1;
1070         }
1071     }
1072     FAIL_IF(result);
1073 
1074     DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1075     DetectEngineCtxFree(de_ctx);
1076 
1077     FLOW_DESTROY(&f);
1078 
1079     SCFree(p);
1080     PASS;
1081 }
1082 
1083 /**
1084  * \test FlowBitsTestSig08 is a test toogle flowbits option
1085  *
1086  *  \retval 1 on succces
1087  *  \retval 0 on failure
1088  */
1089 
FlowBitsTestSig08(void)1090 static int FlowBitsTestSig08(void)
1091 {
1092     uint8_t *buf = (uint8_t *)
1093                     "GET /one/ HTTP/1.1\r\n"
1094                     "Host: one.example.org\r\n"
1095                     "\r\n";
1096     uint16_t buflen = strlen((char *)buf);
1097     Packet *p = SCMalloc(SIZE_OF_PACKET);
1098     if (unlikely(p == NULL))
1099         return 0;
1100     Signature *s = NULL;
1101     ThreadVars th_v;
1102     DetectEngineThreadCtx *det_ctx = NULL;
1103     DetectEngineCtx *de_ctx = NULL;
1104     Flow f;
1105     GenericVar flowvar, *gv = NULL;
1106     int result = 0;
1107     uint32_t idx = 0;
1108 
1109     memset(p, 0, SIZE_OF_PACKET);
1110     memset(&th_v, 0, sizeof(th_v));
1111     memset(&f, 0, sizeof(Flow));
1112     memset(&flowvar, 0, sizeof(GenericVar));
1113 
1114     FLOW_INITIALIZE(&f);
1115     p->flow = &f;
1116     p->flow->flowvar = &flowvar;
1117 
1118     p->src.family = AF_INET;
1119     p->dst.family = AF_INET;
1120     p->payload = buf;
1121     p->payload_len = buflen;
1122     p->proto = IPPROTO_TCP;
1123 
1124     de_ctx = DetectEngineCtxInit();
1125     FAIL_IF_NULL(de_ctx);
1126 
1127     de_ctx->flags |= DE_QUIET;
1128 
1129     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,myflow2; sid:10;)");
1130     FAIL_IF_NULL(s);
1131 
1132     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit unset\"; flowbits:toggle,myflow2; sid:11;)");
1133     FAIL_IF_NULL(s);
1134 
1135     idx = VarNameStoreSetupAdd("myflow", VAR_TYPE_FLOW_BIT);
1136     SigGroupBuild(de_ctx);
1137     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1138 
1139     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1140 
1141     gv = p->flow->flowvar;
1142     FAIL_IF_NULL(gv);
1143 
1144     for ( ; gv != NULL; gv = gv->next) {
1145         if (gv->type == DETECT_FLOWBITS && gv->idx == idx) {
1146                 result = 1;
1147         }
1148     }
1149     FAIL_IF(result);
1150 
1151     DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1152     DetectEngineCtxFree(de_ctx);
1153 
1154     FLOW_DESTROY(&f);
1155 
1156     SCFree(p);
1157     PASS;
1158 }
1159 
1160 /**
1161  * \test FlowBitsTestSig09 is to test isset flowbits option with oring
1162  *
1163  *  \retval 1 on success
1164  *  \retval 0 on failure
1165  */
1166 
FlowBitsTestSig09(void)1167 static int FlowBitsTestSig09(void)
1168 {
1169     uint8_t *buf = (uint8_t *)
1170                     "GET /one/ HTTP/1.1\r\n"
1171                     "Host: one.example.org\r\n"
1172                     "\r\n";
1173     uint16_t buflen = strlen((char *)buf);
1174     Packet *p = SCMalloc(SIZE_OF_PACKET);
1175     FAIL_IF_NULL(p);
1176     Signature *s = NULL;
1177     ThreadVars th_v;
1178     DetectEngineThreadCtx *det_ctx = NULL;
1179     DetectEngineCtx *de_ctx = NULL;
1180     Flow f;
1181 
1182     memset(p, 0, SIZE_OF_PACKET);
1183     memset(&th_v, 0, sizeof(th_v));
1184     memset(&f, 0, sizeof(Flow));
1185 
1186     FLOW_INITIALIZE(&f);
1187     p->flow = &f;
1188 
1189     p->src.family = AF_INET;
1190     p->dst.family = AF_INET;
1191     p->payload = buf;
1192     p->payload_len = buflen;
1193     p->proto = IPPROTO_TCP;
1194     p->flags |= PKT_HAS_FLOW;
1195     p->flowflags |= FLOW_PKT_TOSERVER;
1196 
1197     de_ctx = DetectEngineCtxInit();
1198     FAIL_IF_NULL(de_ctx);
1199 
1200     de_ctx->flags |= DE_QUIET;
1201 
1202     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1203     FAIL_IF_NULL(s);
1204     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1205     FAIL_IF_NULL(s);
1206     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isset ored flowbits\"; flowbits:isset,fb3|fb4; sid:3;)");
1207     FAIL_IF_NULL(s);
1208 
1209     SigGroupBuild(de_ctx);
1210     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1211 
1212     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1213 
1214     FAIL_IF_NOT(PacketAlertCheck(p, 1));
1215     FAIL_IF_NOT(PacketAlertCheck(p, 2));
1216     FAIL_IF(PacketAlertCheck(p, 3));
1217 
1218     DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1219     DetectEngineCtxFree(de_ctx);
1220 
1221     FLOW_DESTROY(&f);
1222 
1223     SCFree(p);
1224     PASS;
1225 }
1226 
1227 /**
1228  * \test FlowBitsTestSig10 is to test isset flowbits option with oring
1229  *
1230  *  \retval 1 on success
1231  *  \retval 0 on failure
1232  */
1233 
FlowBitsTestSig10(void)1234 static int FlowBitsTestSig10(void)
1235 {
1236     uint8_t *buf = (uint8_t *)
1237                     "GET /one/ HTTP/1.1\r\n"
1238                     "Host: one.example.org\r\n"
1239                     "\r\n";
1240     uint16_t buflen = strlen((char *)buf);
1241     Packet *p = SCMalloc(SIZE_OF_PACKET);
1242     FAIL_IF_NULL(p);
1243     Signature *s = NULL;
1244     ThreadVars th_v;
1245     DetectEngineThreadCtx *det_ctx = NULL;
1246     DetectEngineCtx *de_ctx = NULL;
1247     Flow f;
1248 
1249     memset(p, 0, SIZE_OF_PACKET);
1250     memset(&th_v, 0, sizeof(th_v));
1251     memset(&f, 0, sizeof(Flow));
1252 
1253     FLOW_INITIALIZE(&f);
1254     p->flow = &f;
1255 
1256     p->src.family = AF_INET;
1257     p->dst.family = AF_INET;
1258     p->payload = buf;
1259     p->payload_len = buflen;
1260     p->proto = IPPROTO_TCP;
1261     p->flags |= PKT_HAS_FLOW;
1262     p->flowflags |= FLOW_PKT_TOSERVER;
1263 
1264     de_ctx = DetectEngineCtxInit();
1265     FAIL_IF_NULL(de_ctx);
1266 
1267     de_ctx->flags |= DE_QUIET;
1268 
1269     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1270     FAIL_IF_NULL(s);
1271     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1272     FAIL_IF_NULL(s);
1273     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb3; sid:3;)");
1274     FAIL_IF_NULL(s);
1275     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isset ored flowbits\"; flowbits:isset,fb3|fb4; sid:4;)");
1276     FAIL_IF_NULL(s);
1277 
1278     SigGroupBuild(de_ctx);
1279     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1280 
1281     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1282 
1283     FAIL_IF_NOT(PacketAlertCheck(p, 1));
1284     FAIL_IF_NOT(PacketAlertCheck(p, 2));
1285     FAIL_IF_NOT(PacketAlertCheck(p, 3));
1286     FAIL_IF_NOT(PacketAlertCheck(p, 4));
1287 
1288     DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1289     DetectEngineCtxFree(de_ctx);
1290 
1291     FLOW_DESTROY(&f);
1292 
1293     SCFree(p);
1294     PASS;
1295 }
1296 
1297 /**
1298  * \test FlowBitsTestSig11 is to test isnotset flowbits option with oring
1299  *
1300  *  \retval 1 on success
1301  *  \retval 0 on failure
1302  */
1303 
FlowBitsTestSig11(void)1304 static int FlowBitsTestSig11(void)
1305 {
1306     uint8_t *buf = (uint8_t *)
1307                     "GET /one/ HTTP/1.1\r\n"
1308                     "Host: one.example.org\r\n"
1309                     "\r\n";
1310     uint16_t buflen = strlen((char *)buf);
1311     Packet *p = SCMalloc(SIZE_OF_PACKET);
1312     FAIL_IF_NULL(p);
1313     Signature *s = NULL;
1314     ThreadVars th_v;
1315     DetectEngineThreadCtx *det_ctx = NULL;
1316     DetectEngineCtx *de_ctx = NULL;
1317     Flow f;
1318 
1319     memset(p, 0, SIZE_OF_PACKET);
1320     memset(&th_v, 0, sizeof(th_v));
1321     memset(&f, 0, sizeof(Flow));
1322 
1323     FLOW_INITIALIZE(&f);
1324     p->flow = &f;
1325 
1326     p->src.family = AF_INET;
1327     p->dst.family = AF_INET;
1328     p->payload = buf;
1329     p->payload_len = buflen;
1330     p->proto = IPPROTO_TCP;
1331     p->flags |= PKT_HAS_FLOW;
1332     p->flowflags |= FLOW_PKT_TOSERVER;
1333 
1334     de_ctx = DetectEngineCtxInit();
1335     FAIL_IF_NULL(de_ctx);
1336 
1337     de_ctx->flags |= DE_QUIET;
1338 
1339     s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb1; sid:1;)");
1340     FAIL_IF_NULL(s);
1341     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb2; sid:2;)");
1342     FAIL_IF_NULL(s);
1343     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit set\"; flowbits:set,fb3; sid:3;)");
1344     FAIL_IF_NULL(s);
1345     s = s->next  = SigInit(de_ctx,"alert ip any any -> any any (msg:\"Flowbit isnotset ored flowbits\"; flowbits:isnotset, fb1 | fb2 ; sid:4;)");
1346     FAIL_IF_NULL(s);
1347 
1348     SigGroupBuild(de_ctx);
1349     DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
1350 
1351     SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
1352 
1353     FAIL_IF_NOT(PacketAlertCheck(p, 1));
1354     FAIL_IF_NOT(PacketAlertCheck(p, 2));
1355     FAIL_IF_NOT(PacketAlertCheck(p, 3));
1356     FAIL_IF(PacketAlertCheck(p, 4));
1357 
1358     DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
1359     DetectEngineCtxFree(de_ctx);
1360 
1361     FLOW_DESTROY(&f);
1362 
1363     SCFree(p);
1364     PASS;
1365 }
1366 
1367 /**
1368  * \brief this function registers unit tests for FlowBits
1369  */
FlowBitsRegisterTests(void)1370 void FlowBitsRegisterTests(void)
1371 {
1372     UtRegisterTest("FlowBitsTestParse01", FlowBitsTestParse01);
1373     UtRegisterTest("FlowBitsTestSig01", FlowBitsTestSig01);
1374     UtRegisterTest("FlowBitsTestSig02", FlowBitsTestSig02);
1375     UtRegisterTest("FlowBitsTestSig03", FlowBitsTestSig03);
1376     UtRegisterTest("FlowBitsTestSig04", FlowBitsTestSig04);
1377     UtRegisterTest("FlowBitsTestSig05", FlowBitsTestSig05);
1378     UtRegisterTest("FlowBitsTestSig06", FlowBitsTestSig06);
1379     UtRegisterTest("FlowBitsTestSig07", FlowBitsTestSig07);
1380     UtRegisterTest("FlowBitsTestSig08", FlowBitsTestSig08);
1381     UtRegisterTest("FlowBitsTestSig09", FlowBitsTestSig09);
1382     UtRegisterTest("FlowBitsTestSig10", FlowBitsTestSig10);
1383     UtRegisterTest("FlowBitsTestSig11", FlowBitsTestSig11);
1384 }
1385 #endif /* UNITTESTS */
1386