1 /*
2  ** $Id$
3 
4  ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
5  ** Copyright (C) 2003-2013 Sourcefire, Inc.
6  **
7  ** This program is free software; you can redistribute it and/or modify
8  ** it under the terms of the GNU General Public License Version 2 as
9  ** published by the Free Software Foundation.  You may not use, modify or
10  ** distribute this program under any other version of the GNU General
11  ** Public License.
12  **
13  ** This program is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  ** GNU General Public License for more details.
17  **
18  ** You should have received a copy of the GNU General Public License
19  ** along with this program; if not, write to the Free Software
20  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  *
22  *
23  *  Major rewrite: Hui Cao <hcao@sourcefire.com>
24  *
25  *  Add flowbits OR support
26  *
27  **
28  ** sp_flowbits
29  **
30  ** Purpose:
31  **
32  ** Wouldn't it be nice if we could do some simple state tracking
33  ** across multiple packets?  Well, this allows you to do just that.
34  **
35  ** Effect:
36  **
37  ** - [Un]set a bitmask stored with the session
38  ** - Check the value of the bitmask
39  **
40  *
41  */
42 
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <sys/types.h>
47 
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51 
52 #include "sf_types.h"
53 #include "rules.h"
54 #include "treenodes.h"
55 #include "decode.h"
56 #include "plugbase.h"
57 #include "parser.h"
58 #include "snort_debug.h"
59 #include "util.h"
60 #include "plugin_enum.h"
61 #include "snort.h"
62 #include "bitop_funcs.h"
63 #include "sfghash.h"
64 #include "sp_flowbits.h"
65 #include "sf_types.h"
66 #include "mstring.h"
67 
68 #include "session_api.h"
69 #include "stream_api.h"
70 
71 #include "snort.h"
72 #include "profiler.h"
73 #ifdef PERF_PROFILING
74 PreprocStats flowBitsPerfStats;
75 extern PreprocStats ruleOTNEvalPerfStats;
76 #endif
77 
78 #include "sfhashfcn.h"
79 #include "detection_options.h"
80 #define DEFAULT_FLOWBIT_GROUP  "default"
81 
82 #define ALLOWED_SPECIAL_CHARS       ".-_"
83 
84 SFGHASH *flowbits_hash = NULL;
85 SFGHASH *flowbits_grp_hash = NULL;
86 SF_QUEUE *flowbits_bit_queue = NULL;
87 uint32_t flowbits_count = 0;
88 uint32_t flowbits_grp_count = 0;
89 int flowbits_toggle = 1;
90 
91 #define DEFAULT_FLOWBIT_SIZE  1024
92 #define MAX_FLOWBIT_SIZE      2048
93 #define CONVERT_BITS_TO_BYTES(size)    ( (size > 1)?(((size -1) >> 3)+ 1):0)
94 static unsigned int giFlowbitSizeInBytes = CONVERT_BITS_TO_BYTES(DEFAULT_FLOWBIT_SIZE);
95 static unsigned int giFlowbitSize = DEFAULT_FLOWBIT_SIZE;
96 
97 void FlowItemFree(void *);
98 void FlowBitsGrpFree(void *);
99 static void FlowBitsInit(struct _SnortConfig *, char *, OptTreeNode *, int);
100 static void FlowBitsParse(struct _SnortConfig *, char *, FLOWBITS_OP *, OptTreeNode *);
101 static void FlowBitsCleanExit(int, void *);
102 
103 #ifdef SNORT_RELOAD
104 extern volatile bool reloadInProgress;
105 #endif
106 
107 /****************************************************************************
108  *
109  * Function: FlowBitsHashInit(void)
110  *
111  * Purpose: Initialize the hash table and queue storage for flowbits IDs
112  *
113  * Arguments: None
114  *
115  * Returns: void function
116  *
117  ****************************************************************************/
FlowBitsHashInit(void)118 void FlowBitsHashInit(void)
119 {
120     if (flowbits_hash != NULL)
121         return;
122 
123     flowbits_hash = sfghash_new(10000, 0, 0, FlowItemFree);
124     if (flowbits_hash == NULL)
125     {
126         FatalError("%s(%d) Could not create flowbits hash.\n",
127                 __FILE__, __LINE__);
128     }
129 
130 
131     flowbits_bit_queue = sfqueue_new();
132     if (flowbits_bit_queue == NULL)
133     {
134         FatalError("%s(%d) Could not create flowbits bit queue.\n",
135                 __FILE__, __LINE__);
136     }
137 }
138 
FlowBitsGrpHashInit(void)139 void FlowBitsGrpHashInit(void)
140 {
141     if (flowbits_grp_hash != NULL)
142         return;
143 
144     flowbits_grp_hash = sfghash_new(10000, 0, 0, FlowBitsGrpFree);
145     if (flowbits_grp_hash == NULL)
146     {
147         FatalError("%s(%d) Could not create flowbits group hash.\n",
148                 __FILE__, __LINE__);
149     }
150 
151 }
152 
FlowItemFree(void * d)153 void FlowItemFree(void *d)
154 {
155     FLOWBITS_OBJECT *data = (FLOWBITS_OBJECT *)d;
156     free(data);
157 }
158 
FlowBitsGrpFree(void * d)159 void FlowBitsGrpFree(void *d)
160 {
161     FLOWBITS_GRP *data = (FLOWBITS_GRP *)d;
162     boFreeBITOP(&(data->GrpBitOp));
163     if (data->name)
164         free(data->name);
165     free(data);
166 }
167 
FlowBitsFree(void * d)168 void FlowBitsFree(void *d)
169 {
170     FLOWBITS_OP *data = (FLOWBITS_OP *)d;
171     if (data->ids)
172         free(data->ids);
173     if (data->name)
174         free(data->name);
175     if (data->group)
176         free(data->group);
177     free(data);
178 }
179 
FlowBitsHash(void * d)180 uint32_t FlowBitsHash(void *d)
181 {
182     uint32_t a,b,c;
183     FLOWBITS_OP *data = (FLOWBITS_OP *)d;
184     int i;
185     int j = 0;
186 
187     a = data->eval;
188     b = data->type;
189     c = RULE_OPTION_TYPE_FLOWBIT;
190 
191     mix(a,b,c);
192 
193     for (i = 0, j = 0; i < data->num_ids; i++, j++)
194     {
195         if (j >= 3)
196         {
197             a += data->ids[i - 2];
198             b += data->ids[i - 1];
199             c += data->ids[i];
200             mix(a,b,c);
201             j -= 3;
202         }
203     }
204     if (1 == j)
205     {
206         a += data->ids[data->num_ids - 1];
207         b += data->num_ids;
208     }
209     else if (2 == j)
210     {
211         a += data->ids[data->num_ids - 2];
212         b += data->ids[data->num_ids - 1]|data->num_ids << 16;
213     }
214 
215     c += data->group_id;
216 
217     final(a,b,c);
218 
219     return c;
220 }
221 
FlowBitsCompare(void * l,void * r)222 int FlowBitsCompare(void *l, void *r)
223 {
224     FLOWBITS_OP *left = (FLOWBITS_OP *)l;
225     FLOWBITS_OP *right = (FLOWBITS_OP *)r;
226     int i;
227 
228     if (!left || !right)
229         return DETECTION_OPTION_NOT_EQUAL;
230 
231     if ((left->num_ids != right->num_ids)||
232             (left->eval != right->eval)||
233             (left->type != right->type)||
234             (left->group_id != right->group_id))
235         return DETECTION_OPTION_NOT_EQUAL;
236 
237 
238     for (i = 0; i < left->num_ids; i++)
239     {
240         if (left->ids[i] != right->ids[i])
241 
242             return DETECTION_OPTION_NOT_EQUAL;
243     }
244 
245     return DETECTION_OPTION_EQUAL;
246 }
247 
248 /****************************************************************************
249  *
250  * Function: SetupFlowBits()
251  *
252  * Purpose: Generic detection engine plugin template.  Registers the
253  *          configuration function and links it to a rule keyword.  This is
254  *          the function that gets called from InitPlugins in plugbase.c.
255  *
256  * Arguments: None.
257  *
258  * Returns: void function
259  *
260  * 3/4/05 - man beefed up the hash table size from 100 -> 10000
261  *
262  ****************************************************************************/
SetupFlowBits(void)263 void SetupFlowBits(void)
264 {
265     /* map the keyword to an initialization/processing function */
266     RegisterRuleOption("flowbits", FlowBitsInit, NULL, OPT_TYPE_DETECTION, NULL);
267 
268 #ifdef PERF_PROFILING
269     RegisterPreprocessorProfile("flowbits", &flowBitsPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
270 #endif
271 
272     AddFuncToCleanExitList(FlowBitsCleanExit, NULL);
273 
274     DEBUG_WRAP(DebugMessage(DEBUG_FLOWBITS, "Plugin: FlowBits Setup\n"););
275 }
276 
277 
278 /****************************************************************************
279  *
280  * Function: FlowBitsInit(struct _SnortConfig *, char *, OptTreeNode *)
281  *
282  * Purpose: Configure the flow init option to register the appropriate checks
283  *
284  * Arguments: data => rule arguments/data
285  *            otn => pointer to the current rule option list node
286  *
287  * Returns: void function
288  *
289  ****************************************************************************/
FlowBitsInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)290 static void FlowBitsInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
291 {
292     FLOWBITS_OP *flowbits;
293     OptFpList *fpl;
294     void *idx_dup;
295 
296     /* Flowbits are now part of the rule stub for .so rules.
297      * We avoid adding the flowbit twice by skipping it here. */
298     if (otn->sigInfo.generator == 3)
299         return;
300 
301     /* Flow bits are handled by Stream if its enabled */
302     if( stream_api && stream_api->version != STREAM_API_VERSION5)
303     {
304         if (ScConfErrorOut())
305         {
306             FatalError("WARNING: %s (%d) => flowbits without Stream. "
307                     "Stream must be enabled for this plugin.\n",
308                     file_name,file_line);
309         }
310         else
311         {
312             LogMessage("WARNING: %s (%d) => flowbits without Stream. "
313                     "Stream must be enabled for this plugin.\n",
314                     file_name,file_line);
315         }
316     }
317 
318     /* Auto init hash table and queue */
319     if (flowbits_hash == NULL)
320         FlowBitsHashInit();
321 
322     if (flowbits_grp_hash == NULL )
323         FlowBitsGrpHashInit();
324 
325     flowbits = (FLOWBITS_OP *) SnortAlloc(sizeof(FLOWBITS_OP));
326     if (!flowbits) {
327         FatalError("%s (%d): Unable to allocate flowbits node\n", file_name,
328                 file_line);
329     }
330 
331     /* Set the ds_list value to 1 (yes, we have flowbits for this rule) */
332     otn->ds_list[PLUGIN_FLOWBIT] = (void *)1;
333 
334     FlowBitsParse(sc, data, flowbits, otn);
335     if (add_detection_option(sc, RULE_OPTION_TYPE_FLOWBIT, (void *)flowbits, &idx_dup) == DETECTION_OPTION_EQUAL)
336     {
337         char *group_name =  ((FLOWBITS_OP *)idx_dup)->group;
338 
339 #ifdef DEBUG_RULE_OPTION_TREE
340         LogMessage("Duplicate FlowBit:\n%d %c\n%d %c\n\n",
341                 flowbits->id,
342                 flowbits->type,
343                 ((FLOWBITS_OP *)idx_dup)->id,
344                 ((FLOWBITS_OP *)idx_dup)->type);
345 #endif
346         if (flowbits->group)
347         {
348             if (group_name && strcmp(group_name, flowbits->group))
349                 free(group_name);
350             ((FLOWBITS_OP *)idx_dup)->group = SnortStrdup(flowbits->group);
351         }
352 
353         free(flowbits->ids);
354         free(flowbits->name);
355         free(flowbits->group);
356         free(flowbits);
357         flowbits = idx_dup;
358     }
359 
360     fpl = AddOptFuncToList(FlowBitsCheck, otn);
361     fpl->type = RULE_OPTION_TYPE_FLOWBIT;
362 
363     /*
364      * attach it to the context node so that we can call each instance
365      * individually
366      */
367 
368     fpl->context = (void *) flowbits;
369     return;
370 }
371 
udpateFlowBitGroupInfo(FLOWBITS_GRP * flowbits_grp,char * flowbitName,FLOWBITS_OBJECT * flowbits_item)372 static void udpateFlowBitGroupInfo(FLOWBITS_GRP *flowbits_grp, char *flowbitName,
373         FLOWBITS_OBJECT *flowbits_item)
374 {
375 
376     char *groupName;
377 
378     if (!flowbits_grp)
379         return;
380 
381     groupName = flowbits_grp->name;
382 
383     if (!groupName)
384         return;
385 
386     flowbits_grp->count++;
387     if ( flowbits_grp->max_id < flowbits_item->id )
388         flowbits_grp->max_id = flowbits_item->id;
389     boSetBit(&(flowbits_grp->GrpBitOp),flowbits_item->id);
390 
391 }
392 
validateName(char * name)393 static bool validateName(char *name)
394 {
395     unsigned i;
396 
397     if (!name)
398         return false;
399 
400     for (i=0; i<strlen(name); i++)
401     {
402         if (!isalnum(name[i])&&(NULL == strchr(ALLOWED_SPECIAL_CHARS,name[i])))
403             return false;
404     }
405     return true;
406 }
407 /****************************************************************************
408  *
409  * Function: getFlowBitItem(char *, FLOWBITS_OP *, FLOWBITS_GRP *)
410  *
411  * Purpose: update the flowbits
412  *
413  * Arguments:
414  *   char *flowbit --> flowbits name,
415  *   FLOWBITS_OP *flowbits
416  *   FLOWBITS_GRP *flowbits_grp
417  *
418  * Returns: FLOWBITS_OBJECT*, whether exist before
419  *
420  ****************************************************************************/
getFlowBitItem(char * flowbitName,FLOWBITS_OP * flowbits,FLOWBITS_GRP * flowbits_grp)421 static  FLOWBITS_OBJECT* getFlowBitItem(char *flowbitName, FLOWBITS_OP *flowbits, FLOWBITS_GRP *flowbits_grp)
422 {
423     FLOWBITS_OBJECT *flowbits_item;
424     int hstatus;
425 
426     if (!validateName(flowbitName))
427     {
428         ParseError("Flowbits: flowbits name is limited to any alphanumeric string including %s"
429         , ALLOWED_SPECIAL_CHARS);
430     }
431 
432     flowbits_item = (FLOWBITS_OBJECT *)sfghash_find(flowbits_hash, flowbitName);
433 
434     if (flowbits_item == NULL)
435     {
436         flowbits_item = (FLOWBITS_OBJECT *)SnortAlloc(sizeof(FLOWBITS_OBJECT));
437 
438         if (sfqueue_count(flowbits_bit_queue) > 0)
439         {
440             flowbits_item->id = (uint16_t)(uintptr_t)sfqueue_remove(flowbits_bit_queue);
441 
442         }
443         else
444         {
445             flowbits_item->id = (uint16_t)flowbits_count;
446 
447             flowbits_count++;
448 
449             if(flowbits_count > giFlowbitSize)
450             {
451                 ParseError("The number of flowbit IDs in the "
452                         "current ruleset exceeds the maximum number of IDs "
453                         "that are allowed (%d).", giFlowbitSize);
454             }
455         }
456 
457         hstatus = sfghash_add(flowbits_hash, flowbitName, flowbits_item);
458         if(hstatus != SFGHASH_OK)
459         {
460             FatalError("Could not add flowbits key (%s) to hash.\n",flowbitName);
461         }
462     }
463 
464     flowbits_item->toggle = flowbits_toggle;
465     flowbits_item->types |= flowbits->type;
466 
467     switch (flowbits->type)
468     {
469     case FLOWBITS_SET:
470     case FLOWBITS_SETX:
471     case FLOWBITS_UNSET:
472     case FLOWBITS_TOGGLE:
473     case FLOWBITS_RESET:
474         flowbits_item->set++;
475         break;
476     case FLOWBITS_ISSET:
477     case FLOWBITS_ISNOTSET:
478         flowbits_item->isset++;
479         break;
480     default:
481         break;
482     }
483     udpateFlowBitGroupInfo(flowbits_grp, flowbitName, flowbits_item);
484 
485     return flowbits_item;
486 }
487 
getFlowBitGroup(char * groupName)488 static FLOWBITS_GRP *getFlowBitGroup(char *groupName)
489 {
490     int hstatus;
491     FLOWBITS_GRP *flowbits_grp = NULL;
492 
493     if(!groupName)
494         return NULL;
495 
496     if (!validateName(groupName))
497     {
498         ParseError("Flowbits: flowbits group name is limited to any alphanumeric string including %s",
499          ALLOWED_SPECIAL_CHARS);
500     }
501 
502     flowbits_grp = (FLOWBITS_GRP *)sfghash_find(flowbits_grp_hash, groupName);
503 
504     /*New group defined, add*/
505     if (flowbits_grp == NULL)
506     {
507         flowbits_grp = (FLOWBITS_GRP *)SnortAlloc(sizeof(FLOWBITS_GRP));
508         boInitBITOP(&(flowbits_grp->GrpBitOp), giFlowbitSizeInBytes);
509         boResetBITOP(&(flowbits_grp->GrpBitOp));
510         hstatus = sfghash_add(flowbits_grp_hash, groupName, flowbits_grp);
511         if(hstatus != SFGHASH_OK)
512         {
513             FatalError("Could not add flowbits group (%s) to hash.\n",groupName);
514         }
515         flowbits_grp_count++;
516         flowbits_grp->group_id = flowbits_grp_count;
517         flowbits_grp->name = SnortStrdup(groupName);
518 
519     }
520 
521     return flowbits_grp;
522 }
523 
524 #ifdef DEBUG_MSGS
printOutFlowbits(FLOWBITS_OP * flowbits)525 static void printOutFlowbits(FLOWBITS_OP *flowbits)
526 {
527     int i;
528 
529     DebugMessage(DEBUG_FLOWBITS,"flowbits: type = %d\n",flowbits->type);
530     DebugMessage(DEBUG_FLOWBITS,"flowbits: name = %s\n",flowbits->name);
531     DebugMessage(DEBUG_FLOWBITS,"flowbits: eval = %d\n",flowbits->eval);
532     DebugMessage(DEBUG_FLOWBITS,"flowbits: num_ids = %d\n",flowbits->num_ids);
533     DebugMessage(DEBUG_FLOWBITS,"flowbits: grp_id = %d\n",flowbits->group_id);
534     DebugMessage(DEBUG_FLOWBITS,"flowbits: group_name = %s\n",flowbits->group);
535     for (i = 0; i < flowbits->num_ids; i++)
536     {
537         DebugMessage(DEBUG_FLOWBITS,"flowbits: value = %d\n",flowbits->ids[i]);
538     }
539 }
540 #endif
541 
542 /****************************************************************************
543  *
544  * Function: processFlowbits(char *, FlowBits *flowbits, OptTreeNode *)
545  *
546  * Purpose: parse the arguments to the flow plugin and alter the otn
547  *          accordingly
548  *
549  * Arguments: flowbits => pointer to the current flowbits op
550  *
551  * Returns: void function
552  *
553  ****************************************************************************/
processFlowbits(char * flowbits_names,FLOWBITS_GRP * flowbits_grp,FLOWBITS_OP * flowbits)554 static void processFlowbits(char *flowbits_names, FLOWBITS_GRP *flowbits_grp, FLOWBITS_OP *flowbits)
555 {
556     char **toks;
557     int num_toks;
558     int i;
559     char *flowbits_name;
560 
561     FLOWBITS_OBJECT *flowbits_item;
562 
563     if (!flowbits_names || ((*flowbits_names) == 0))
564     {
565        return;
566     }
567 
568     DEBUG_WRAP(DebugMessage(DEBUG_FLOWBITS, "flowbits tag id parsing %s\n",flowbits_names););
569 
570     flowbits_name = SnortStrdup(flowbits_names);
571 
572     if (NULL != strchr(flowbits_name, '|'))
573     {
574         if(NULL != strchr(flowbits_name, '&'))
575         {
576             ParseError("Flowbits: flowbits tag id operator '|' and '&' are used together.");
577         }
578         toks = mSplit(flowbits_name, "|", 0, &num_toks, 0);
579         flowbits->ids = SnortAlloc(num_toks*sizeof(*(flowbits->ids)));
580         flowbits->num_ids = num_toks;
581         for (i = 0; i < num_toks; i++)
582         {
583             flowbits_item = getFlowBitItem(toks[i], flowbits, flowbits_grp);
584             flowbits->ids[i] = flowbits_item->id;
585         }
586         flowbits->eval = FLOWBITS_OR;
587         mSplitFree(&toks, num_toks);
588     }
589     else if (NULL != strchr(flowbits_name, '&'))
590     {
591         toks = mSplit(flowbits_name, "&", 0, &num_toks, 0);
592         flowbits->ids = SnortAlloc(num_toks*sizeof(*(flowbits->ids)));
593         flowbits->num_ids = num_toks;
594         for (i = 0; i < num_toks; i++)
595         {
596             flowbits_item = getFlowBitItem(toks[i], flowbits, flowbits_grp);
597             flowbits->ids[i] = flowbits_item->id;
598         }
599         flowbits->eval = FLOWBITS_AND;
600         mSplitFree(&toks, num_toks);
601     }
602     else if (!strcasecmp(flowbits_name,"all"))
603     {
604         flowbits->eval = FLOWBITS_ALL;
605     }
606     else if (!strcasecmp(flowbits_name,"any"))
607     {
608         flowbits->eval = FLOWBITS_ANY;
609     }
610     else
611     {
612         flowbits_item = getFlowBitItem(flowbits_name, flowbits, flowbits_grp);
613         flowbits->ids = SnortAlloc(sizeof(*(flowbits->ids)));
614         flowbits->num_ids = 1;
615         flowbits->ids[0] = flowbits_item->id;
616     }
617 
618     free(flowbits_name);
619 
620 }
621 
validateFlowbitsSyntax(FLOWBITS_OP * flowbits)622 void validateFlowbitsSyntax(FLOWBITS_OP *flowbits)
623 {
624     switch (flowbits->type)
625     {
626     case FLOWBITS_SET:
627         if ((flowbits->eval == FLOWBITS_AND) && (flowbits->ids))
628             break;
629 
630         ParseError("Flowbits: operation set uses syntax: flowbits:set,bit[&bit],[group].");
631         break;
632     case FLOWBITS_SETX:
633         if ((flowbits->eval == FLOWBITS_AND)&&(flowbits->group) && (flowbits->ids) )
634             break;
635 
636         ParseError("Flowbits: operation setx uses syntax: flowbits:setx,bit[&bit],group.");
637 
638         break;
639     case FLOWBITS_UNSET:
640         if (((flowbits->eval == FLOWBITS_AND) && (!flowbits->group) && (flowbits->ids))
641                 ||((flowbits->eval == FLOWBITS_ALL) && (flowbits->group)))
642             break;
643 
644         ParseError("Flowbits: operation unset uses syntax: flowbits:unset,bit[&bit] OR"
645                 " flowbits:unset, all, group.");
646 
647         break;
648     case FLOWBITS_TOGGLE:
649         if (((flowbits->eval == FLOWBITS_AND) && (!flowbits->group) &&(flowbits->ids))
650                 ||((flowbits->eval == FLOWBITS_ALL) && (flowbits->group)))
651             break;
652 
653         ParseError("Flowbits: operation toggle uses syntax: flowbits:toggle,bit[&bit] OR"
654                 " flowbits:toggle,all,group.");
655         break;
656     case FLOWBITS_ISSET:
657         if ((((flowbits->eval == FLOWBITS_AND) || (flowbits->eval == FLOWBITS_OR)) && (!flowbits->group) && flowbits->ids)
658                 ||((((flowbits->eval == FLOWBITS_ANY))||(flowbits->eval == FLOWBITS_ALL)) && (flowbits->group)))
659             break;
660 
661         ParseError("Flowbits: operation isset uses syntax: flowbits:isset,bit[&bit] OR "
662                 "flowbits:isset,bit[|bit] OR flowbits:isset,all,group OR flowbits:isset,any,group.");
663 
664         break;
665     case FLOWBITS_ISNOTSET:
666         if ((((flowbits->eval == FLOWBITS_AND) || (flowbits->eval == FLOWBITS_OR)) && (!flowbits->group) && flowbits->ids)
667                 ||((((flowbits->eval == FLOWBITS_ANY))||(flowbits->eval == FLOWBITS_ALL)) && (flowbits->group)))
668             break;
669 
670         ParseError("Flowbits: operation isnotset uses syntax: flowbits:isnotset,bit[&bit] OR "
671                 "flowbits:isnotset,bit[|bit] OR flowbits:isnotset,all,group OR flowbits:isnotset,any,group.");
672 
673         break;
674     case FLOWBITS_RESET:
675         if (flowbits->ids == NULL)
676             break;
677         ParseError("Flowbits: operation unset uses syntax: flowbits:reset OR flowbits:reset, group." );
678         break;
679 
680     case FLOWBITS_NOALERT:
681         if ((flowbits->ids == NULL) && (flowbits->group == NULL))
682             break;
683         ParseError("Flowbits: operation noalert uses syntax: flowbits:noalert." );
684         break;
685 
686     default:
687         ParseError("Flowbits: unknown operator.\n"
688                 , file_name, file_line);
689         break;
690     }
691 }
692 
processFlowBitsWithGroup(char * flowbitsName,char * groupName,FLOWBITS_OP * flowbits)693 void processFlowBitsWithGroup(char *flowbitsName, char *groupName, FLOWBITS_OP *flowbits)
694 {
695     FLOWBITS_GRP *flowbits_grp;
696 
697     if (!flowbits_hash)
698         FlowBitsHashInit();
699 
700     if ((groupName)&& (!flowbits_grp_hash))
701         FlowBitsGrpHashInit();
702 
703     flowbits_grp = getFlowBitGroup(groupName);
704     processFlowbits(flowbitsName,flowbits_grp, flowbits);
705 
706     if (groupName && !(flowbits->group))
707     {
708         flowbits->group = SnortStrdup(groupName);
709         flowbits->group_id = flowbits_grp->group_id;
710     }
711     validateFlowbitsSyntax(flowbits);
712     DEBUG_WRAP( printOutFlowbits(flowbits));
713 
714 }
715 /****************************************************************************
716  *
717  * Function: FlowBitsParse(char *, FlowBits *flowbits, OptTreeNode *)
718  *
719  * Purpose: parse the arguments to the flow plugin and alter the otn
720  *          accordingly
721  *
722  * Arguments: otn => pointer to the current rule option list node
723  *
724  * Returns: void function
725  *
726  ****************************************************************************/
FlowBitsParse(struct _SnortConfig * sc,char * data,FLOWBITS_OP * flowbits,OptTreeNode * otn)727 static void FlowBitsParse(struct _SnortConfig *sc, char *data, FLOWBITS_OP *flowbits, OptTreeNode *otn)
728 {
729     char **toks;
730     int num_toks;
731     char *typeName = NULL;
732     char *groupName = NULL;
733     char *flowbitsName = NULL;
734     FLOWBITS_GRP *flowbits_grp;
735 
736     if (sc == NULL)
737     {
738         FatalError("%s(%d) Snort config for parsing is NULL.\n",
739                 __FILE__, __LINE__);
740     }
741 
742     DEBUG_WRAP(DebugMessage(DEBUG_FLOWBITS, "flowbits parsing %s\n",data););
743 
744     toks = mSplit(data, ",", 0, &num_toks, 0);
745 
746     if(num_toks < 1)
747     {
748         ParseError("ParseFlowArgs: Must specify flowbits operation.");
749     }
750     else if (num_toks > 3)
751     {
752         ParseError("ParseFlowArgs: Too many arguments.");
753     }
754 
755     typeName = toks[0];
756 
757     if(!strcasecmp("set",typeName))
758     {
759         flowbits->type = FLOWBITS_SET;
760     }
761     else if(!strcasecmp("setx",typeName))
762     {
763         flowbits->type = FLOWBITS_SETX;
764     }
765     else if(!strcasecmp("unset",typeName))
766     {
767         flowbits->type = FLOWBITS_UNSET;
768     }
769     else if(!strcasecmp("toggle",typeName))
770     {
771         flowbits->type = FLOWBITS_TOGGLE;
772     }
773     else if(!strcasecmp("isset",typeName))
774     {
775         flowbits->type = FLOWBITS_ISSET;
776     }
777     else if(!strcasecmp("isnotset",typeName))
778     {
779         flowbits->type = FLOWBITS_ISNOTSET;
780     }
781     else if(!strcasecmp("noalert", typeName))
782     {
783         if(num_toks > 1)
784         {
785             ParseError("Flowbits: Do not specify a flowbits tag id for the keyword 'noalert'.");
786         }
787 
788         flowbits->type = FLOWBITS_NOALERT;
789         flowbits->ids   = NULL;
790         flowbits->num_ids  = 0;
791         flowbits->name  = SnortStrdup(typeName);
792 
793         mSplitFree(&toks, num_toks);
794         return;
795     }
796     else if(!strcasecmp("reset",typeName))
797     {
798 
799         if(num_toks > 2)
800         {
801             ParseError("Flowbits: Too many arguments for the keyword 'reset'.");
802         }
803 
804         if (num_toks == 2)
805         {
806             /*Save the group name*/
807             groupName = SnortStrdup(toks[1]);
808             flowbits_grp = getFlowBitGroup(groupName);
809             flowbits->group = groupName;
810             flowbits->group_id = flowbits_grp->group_id;
811         }
812         flowbits->type = FLOWBITS_RESET;
813         flowbits->ids   = NULL;
814         flowbits->num_ids   = 0;
815         flowbits->name  = SnortStrdup(typeName);
816         mSplitFree(&toks, num_toks);
817         return;
818 
819     }
820     else
821     {
822         ParseError("Flowbits: Invalid token %s.", typeName);
823     }
824 
825     flowbits->name = SnortStrdup(typeName);
826     /*
827      **  Let's parse the flowbits name
828      */
829     if( num_toks < 2 )
830     {
831         ParseError("Flowbit: flowbits tag id must be provided.",
832                 file_name, file_line);
833     }
834 
835     flowbitsName = toks[1];
836 
837     if(num_toks == 3)
838     {
839         groupName = toks[2];
840     }
841     processFlowBitsWithGroup(flowbitsName, groupName, flowbits);
842 
843     mSplitFree(&toks, num_toks);
844 }
845 
boUnSetGrpBit(BITOP * BitOp,char * group)846 static inline int boUnSetGrpBit(BITOP *BitOp, char *group)
847 {
848     FLOWBITS_GRP *flowbits_grp;
849     BITOP *GrpBitOp;
850     unsigned int i, max_bytes;
851 
852     if( group == NULL )
853         return 0;
854     flowbits_grp = (FLOWBITS_GRP *)sfghash_find(flowbits_grp_hash, group);
855     if( flowbits_grp == NULL )
856         return 0;
857     if((BitOp == NULL) || (BitOp->uiMaxBits <= flowbits_grp->max_id) || flowbits_grp->count == 0)
858         return 0;
859     GrpBitOp = &(flowbits_grp->GrpBitOp);
860 
861     /* note, max_id is an index, not a count.
862      * Calculate max_bytes by adding 8 to max_id, then dividing by 8.  */
863     max_bytes = (flowbits_grp->max_id + 8) >> 3;
864     for ( i = 0; i < max_bytes; i++ )
865     {
866         BitOp->pucBitBuffer[i] &= ~GrpBitOp->pucBitBuffer[i];
867     }
868     return 1;
869 }
870 
boToggleGrpBit(BITOP * BitOp,char * group)871 static inline int boToggleGrpBit(BITOP *BitOp, char *group)
872 {
873     FLOWBITS_GRP *flowbits_grp;
874     BITOP *GrpBitOp;
875     unsigned int i, max_bytes;
876 
877     if( group == NULL )
878         return 0;
879     flowbits_grp = (FLOWBITS_GRP *)sfghash_find(flowbits_grp_hash, group);
880     if( flowbits_grp == NULL )
881         return 0;
882     if((BitOp == NULL) || (BitOp->uiMaxBits <= flowbits_grp->max_id) || flowbits_grp->count == 0)
883         return 0;
884     GrpBitOp = &(flowbits_grp->GrpBitOp);
885 
886     /* note, max_id is an index, not a count.
887      * Calculate max_bytes by adding 8 to max_id, then dividing by 8.  */
888     max_bytes = (flowbits_grp->max_id + 8) >> 3;
889     for ( i = 0; i < max_bytes; i++ )
890     {
891         BitOp->pucBitBuffer[i] ^= GrpBitOp->pucBitBuffer[i];
892     }
893     return 1;
894 }
895 
boSetxBitsToGrp(BITOP * BitOp,uint16_t * ids,uint16_t num_ids,char * group)896 static inline int boSetxBitsToGrp(BITOP *BitOp, uint16_t *ids, uint16_t num_ids, char *group)
897 {
898     unsigned int i;
899     if (!boUnSetGrpBit(BitOp, group))
900         return 0;
901     for(i = 0; i < num_ids; i++)
902         boSetBit(BitOp,ids[i]);
903     return 1;
904 }
905 
906 
issetFlowbits(StreamFlowData * flowdata,uint8_t eval,uint16_t * ids,uint16_t num_ids,char * group)907 static inline int issetFlowbits(StreamFlowData *flowdata, uint8_t eval, uint16_t *ids,
908         uint16_t num_ids, char *group )
909 {
910     unsigned int i;
911     FLOWBITS_GRP *flowbits_grp;
912     Flowbits_eval  evalType = (Flowbits_eval)eval;
913 
914     switch (evalType)
915     {
916     case FLOWBITS_AND:
917         for(i = 0; i < num_ids; i++)
918         {
919             if(!boIsBitSet(&(flowdata->boFlowbits), ids[i]))
920                 return 0;
921         }
922         return 1;
923         break;
924     case FLOWBITS_OR:
925         for(i = 0; i < num_ids; i++)
926         {
927             if(boIsBitSet(&(flowdata->boFlowbits), ids[i]))
928                 return 1;
929         }
930         return 0;
931         break;
932     case FLOWBITS_ALL:
933         flowbits_grp = (FLOWBITS_GRP *)sfghash_find(flowbits_grp_hash, group);
934         if( flowbits_grp == NULL )
935             return 0;
936         for ( i = 0; i <= (unsigned int)(flowbits_grp->max_id >>3) ; i++ )
937         {
938             uint8_t val = flowdata->boFlowbits.pucBitBuffer[i] & flowbits_grp->GrpBitOp.pucBitBuffer[i];
939             if (val != flowbits_grp->GrpBitOp.pucBitBuffer[i])
940                 return 0;
941         }
942         return 1;
943         break;
944     case FLOWBITS_ANY:
945         flowbits_grp = (FLOWBITS_GRP *)sfghash_find(flowbits_grp_hash, group);
946         if( flowbits_grp == NULL )
947             return 0;
948         for ( i = 0; i <= (unsigned int)(flowbits_grp->max_id >>3) ; i++ )
949         {
950             uint8_t val = flowdata->boFlowbits.pucBitBuffer[i] & flowbits_grp->GrpBitOp.pucBitBuffer[i];
951             if (val)
952                 return 1;
953         }
954         return 0;
955         break;
956     default:
957         return 0;
958     }
959 }
960 
961 /****************************************************************************
962  *
963  * Function: checkFlowBits
964  *
965  * Purpose: Check flow bits
966  *
967  * Arguments: Packet *p => packet data
968  *            uint8_t type,
969  *            uint8_t evalType,
970  *            uint16_t *ids,
971  *            uint16_t num_ids,
972  *            char *group
973  *
974  * Returns: 0 on failure
975  *
976  ****************************************************************************/
checkFlowBits(uint8_t type,uint8_t evalType,uint16_t * ids,uint16_t num_ids,char * group,Packet * p)977 int checkFlowBits( uint8_t type, uint8_t evalType, uint16_t *ids, uint16_t num_ids, char *group, Packet *p)
978 {
979     int rval = DETECTION_OPTION_NO_MATCH;
980     StreamFlowData *flowdata;
981     Flowbits_eval eval = (Flowbits_eval) evalType;
982     int result = 0;
983     int i;
984 
985     /* Need session pointer to get flowbits */
986     if ((stream_api == NULL) || (p->ssnptr == NULL))
987         return rval;
988 
989 
990     flowdata = session_api->get_flow_data(p);
991     if(!flowdata)
992     {
993         DEBUG_WRAP(DebugMessage(DEBUG_FLOWBITS, "No FLOWBITS_DATA"););
994         return rval;
995     }
996 
997     switch(type)
998     {
999     case FLOWBITS_SET:
1000         for(i = 0; i < num_ids; i++)
1001             boSetBit(&(flowdata->boFlowbits),ids[i]);
1002         result = 1;
1003         break;
1004 
1005     case FLOWBITS_SETX:
1006         result = boSetxBitsToGrp(&(flowdata->boFlowbits), ids, num_ids, group);
1007         break;
1008 
1009     case FLOWBITS_UNSET:
1010         if (eval == FLOWBITS_ALL )
1011             boUnSetGrpBit(&(flowdata->boFlowbits), group);
1012         else
1013         {
1014             for(i = 0; i < num_ids; i++)
1015                 boClearBit(&(flowdata->boFlowbits),ids[i]);
1016         }
1017         result = 1;
1018         break;
1019 
1020     case FLOWBITS_RESET:
1021         if (!group)
1022             boResetBITOP(&(flowdata->boFlowbits));
1023         else
1024             boUnSetGrpBit(&(flowdata->boFlowbits), group);
1025         result = 1;
1026         break;
1027 
1028     case FLOWBITS_ISSET:
1029 
1030         if(issetFlowbits(flowdata,(uint8_t)eval, ids, num_ids, group))
1031         {
1032             result = 1;
1033         }
1034         else
1035         {
1036             rval = DETECTION_OPTION_FAILED_BIT;
1037         }
1038 
1039         break;
1040 
1041     case FLOWBITS_ISNOTSET:
1042         if(!issetFlowbits(flowdata, (uint8_t)eval, ids, num_ids, group))
1043         {
1044             result = 1;
1045         }
1046         else
1047         {
1048             rval = DETECTION_OPTION_FAILED_BIT;
1049         }
1050         break;
1051 
1052     case FLOWBITS_TOGGLE:
1053         if (group)
1054             boToggleGrpBit(&(flowdata->boFlowbits),group);
1055         else
1056         {
1057             for(i = 0; i < num_ids; i++)
1058             {
1059                 if (boIsBitSet(&(flowdata->boFlowbits),ids[i]))
1060                 {
1061                     boClearBit(&(flowdata->boFlowbits),ids[i]);
1062                 }
1063                 else
1064                 {
1065                     boSetBit(&(flowdata->boFlowbits),ids[i]);
1066                 }
1067             }
1068         }
1069         result = 1;
1070 
1071         break;
1072 
1073     case FLOWBITS_NOALERT:
1074         /*
1075          **  This logic allows us to put flowbits: noalert any where
1076          **  in the detection chain, and still do bit ops after this
1077          **  option.
1078          */
1079         return DETECTION_OPTION_NO_ALERT;
1080 
1081     default:
1082         /*
1083          **  Always return failure here.
1084          */
1085         return rval;
1086     }
1087 
1088     /*
1089      **  Now return what we found
1090      */
1091     if (result == 1)
1092     {
1093         rval = DETECTION_OPTION_MATCH;
1094     }
1095 
1096     return rval;
1097 }
1098 
1099 /****************************************************************************
1100  *
1101  * Function: FlowBitsCheck(Packet *, struct _OptTreeNode *, OptFpList *)
1102  *
1103  * Purpose: Check flow bits foo
1104  *
1105  * Arguments: data => argument data
1106  *            otn => pointer to the current rule's OTN
1107  *
1108  * Returns: 0 on failure
1109  *
1110  ****************************************************************************/
FlowBitsCheck(void * option_data,Packet * p)1111 int FlowBitsCheck(void *option_data, Packet *p)
1112 {
1113     FLOWBITS_OP *flowbits = (FLOWBITS_OP*)option_data;
1114     int rval = DETECTION_OPTION_NO_MATCH;
1115 
1116     PROFILE_VARS;
1117 
1118     if (!flowbits)
1119         return rval;
1120 
1121     PREPROC_PROFILE_START(flowBitsPerfStats);
1122 
1123     rval = checkFlowBits( flowbits->type, (uint8_t)flowbits->eval,
1124             flowbits->ids, flowbits->num_ids, flowbits->group, p);
1125 
1126     PREPROC_PROFILE_END(flowBitsPerfStats);
1127     return rval;
1128 }
1129 
1130 /****************************************************************************
1131  *
1132  * Function: FlowBitsVerify()
1133  *
1134  * Purpose: Check flow bits foo to make sure its valid
1135  *
1136  * Arguments:
1137  *
1138  * Returns: 0 on failure
1139  *
1140  ****************************************************************************/
FlowBitsVerify(void)1141 void FlowBitsVerify(void)
1142 {
1143     SFGHASH_NODE * n;
1144     FLOWBITS_OBJECT *fb;
1145     int num_flowbits = 0;
1146 
1147     if (flowbits_hash == NULL)
1148         return;
1149 
1150     for (n = sfghash_findfirst(flowbits_hash);
1151             n != NULL;
1152             n= sfghash_findnext(flowbits_hash))
1153     {
1154         fb = (FLOWBITS_OBJECT *)n->data;
1155 
1156         if (fb->toggle != flowbits_toggle)
1157         {
1158             if (sfqueue_add(flowbits_bit_queue, (NODE_DATA)(uintptr_t)fb->id) == -1)
1159             {
1160                 FatalError("%s(%d) Failed to add flow bit id to queue.\n",
1161                         __FILE__, __LINE__);
1162             }
1163 
1164             sfghash_remove(flowbits_hash, n->key);
1165             continue;
1166         }
1167 
1168         if ((fb->set > 0) && (fb->isset == 0))
1169         {
1170             LogMessage("WARNING: flowbits key '%s' is set but not ever checked.\n",
1171                     (char*)n->key);
1172         }
1173         else if ((fb->isset > 0) && (fb->set == 0))
1174         {
1175             LogMessage("WARNING: flowbits key '%s' is checked but not ever set.\n",
1176                     (char*)n->key);
1177         }
1178         else if ((fb->set == 0) && (fb->isset == 0))
1179         {
1180             continue; /* don't count this bit as used */
1181         }
1182 
1183         num_flowbits++;
1184     }
1185 
1186     flowbits_toggle ^= 1;
1187 
1188     LogMessage("%d out of %d flowbits in use.\n",
1189             num_flowbits, giFlowbitSize);
1190 }
1191 
FlowBitsCleanExit(int signal,void * data)1192 static void FlowBitsCleanExit(int signal, void *data)
1193 {
1194 #ifdef SNORT_RELOAD
1195     if (reloadInProgress)
1196     {
1197         return;
1198     }
1199 #endif
1200 
1201     if (flowbits_hash != NULL)
1202     {
1203         sfghash_delete(flowbits_hash);
1204         flowbits_hash = NULL;
1205     }
1206 
1207     if (flowbits_grp_hash != NULL)
1208     {
1209         sfghash_delete(flowbits_grp_hash);
1210         flowbits_grp_hash = NULL;
1211     }
1212 
1213     if (flowbits_bit_queue != NULL)
1214     {
1215         sfqueue_free_all(flowbits_bit_queue, NULL);
1216         flowbits_bit_queue = NULL;
1217     }
1218 }
setFlowbitSize(char * args)1219 void setFlowbitSize(char *args)
1220 {
1221     char *endptr;
1222     long int size;
1223     size = SnortStrtol(args, &endptr, 0);
1224     if ((errno == ERANGE) || (*endptr != '\0') ||
1225             (size < 0) || (size > MAX_FLOWBIT_SIZE))
1226     {
1227         ParseError("Invalid argument to 'flowbits_size': %s.  Must be a "
1228                 "positive integer and less than %d.", args, MAX_FLOWBIT_SIZE);
1229     }
1230 
1231     giFlowbitSize = size;
1232     giFlowbitSizeInBytes = CONVERT_BITS_TO_BYTES(giFlowbitSize);
1233 }
1234 
getFlowbitSize(void)1235 unsigned int getFlowbitSize(void)
1236 {
1237     return giFlowbitSize;
1238 }
getFlowbitSizeInBytes(void)1239 unsigned int getFlowbitSizeInBytes(void)
1240 {
1241     return giFlowbitSizeInBytes;
1242 }
1243 
FlowbitResetCounts(void)1244 void FlowbitResetCounts(void)
1245 {
1246     SFGHASH_NODE *n;
1247     FLOWBITS_OBJECT *fb;
1248 
1249     if (flowbits_hash == NULL)
1250         return;
1251 
1252     for (n = sfghash_findfirst(flowbits_hash);
1253             n != NULL;
1254             n = sfghash_findnext(flowbits_hash))
1255     {
1256         fb = (FLOWBITS_OBJECT *)n->data;
1257         fb->set = 0;
1258         fb->isset = 0;
1259     }
1260 }
1261