1 /* $Id$ */
2 /*
3  * sp_dynamic.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License Version 2 as
7  * published by the Free Software Foundation.  You may not use, modify or
8  * distribute this program under any other version of the GNU General
9  * Public License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
21  * Copyright (C) 2005-2013 Sourcefire, Inc.
22  *
23  * Author: Steven Sturges
24  *
25  * Purpose:
26  *      Supports dynamically loaded detection plugin to check the packet.
27  *
28  *      does not update the doe_ptr
29  *
30  * Arguments:
31  *      Required:
32  *        None
33  *      Optional:
34  *        None
35  *
36  *   sample rules:
37  *   alert tcp any any -> any any (msg: "DynamicRuleCheck"; );
38  *
39  * Effect:
40  *
41  *      Returns 1 if the dynamic detection plugin matches, 0 if it doesn't.
42  *
43  * Comments:
44  *
45  *
46  */
47 #ifdef HAVE_CONFIG_H
48 #include "config.h"
49 #endif
50 
51 #include <sys/types.h>
52 #include <stdlib.h>
53 #include <ctype.h>
54 #ifdef HAVE_STRINGS_H
55 #include <strings.h>
56 #endif
57 #include <errno.h>
58 
59 #include "sf_types.h"
60 #include "rules.h"
61 #include "treenodes.h"
62 #include "decode.h"
63 #include "bitop_funcs.h"
64 #include "plugbase.h"
65 #include "parser.h"
66 #include "snort_debug.h"
67 #include "util.h"
68 #include "plugin_enum.h"
69 #include "sp_dynamic.h"
70 #include "sf_dynamic_engine.h"
71 #include "detection-plugins/sp_flowbits.h"
72 #include "detection-plugins/sp_asn1_detect.h"
73 #include "dynamic-plugins/sf_engine/sf_snort_plugin_api.h"
74 #include "sf_convert_dynamic.h"
75 #include "sfhashfcn.h"
76 #include "sp_preprocopt.h"
77 #include "sfutil/sf_base64decode.h"
78 #include "detection_util.h"
79 #include "stream_api.h"
80 
81 #include "snort.h"
82 #include "profiler.h"
83 #include "reload.h"
84 
85 #ifdef PERF_PROFILING
86 PreprocStats dynamicRuleEvalPerfStats;
87 extern PreprocStats ruleOTNEvalPerfStats;
88 #endif
89 
90 extern SFGHASH *flowbits_hash;
91 extern SF_QUEUE *flowbits_bit_queue;
92 extern uint32_t flowbits_count;
93 
94 void DynamicInit(struct _SnortConfig *, char *, OptTreeNode *, int);
95 void DynamicParse(char *, OptTreeNode *);
96 int DynamicCheck(void *option_data, Packet *p);
97 
DynamicRuleHash(void * d)98 uint32_t DynamicRuleHash(void *d)
99 {
100     uint32_t a,b,c;
101     DynamicData *dynData = (DynamicData *)d;
102 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
103     {
104         /* Cleanup warning because of cast from 64bit ptr to 32bit int
105          * warning on 64bit OSs */
106         uint64_t ptr; /* Addresses are 64bits */
107         ptr = (uint64_t)dynData->contextData;
108         a = (ptr >> 32);
109         b = (ptr & 0xFFFFFFFF);
110 
111         ptr = (uint64_t)dynData->checkFunction;
112         c = (ptr >> 32);
113 
114         mix (a,b,c);
115 
116         a += (ptr & 0xFFFFFFFF);
117 
118         ptr = (uint64_t)dynData->hasOptionFunction;
119         b += (ptr >> 32);
120         c += (ptr & 0xFFFFFFFF);
121 
122         ptr = (uint64_t)dynData->getDynamicContents;
123         a += (ptr >> 32);
124         b += (ptr & 0xFFFFFFFF);
125         c += dynData->contentFlags;
126 
127         mix (a,b,c);
128 
129         a += RULE_OPTION_TYPE_DYNAMIC;
130     }
131 #else
132     {
133         a = (uint32_t)dynData->contextData;
134         b = (uint32_t)dynData->checkFunction;
135         c = (uint32_t)dynData->hasOptionFunction;
136         mix(a,b,c);
137 
138         a += (uint32_t)dynData->getDynamicContents;
139         b += dynData->contentFlags;
140         c += RULE_OPTION_TYPE_DYNAMIC;
141     }
142 #endif
143 
144     final(a,b,c);
145 
146     return c;
147 }
148 
DynamicRuleCompare(void * l,void * r)149 int DynamicRuleCompare(void *l, void *r)
150 {
151     DynamicData *left = (DynamicData *)l;
152     DynamicData *right = (DynamicData *)r;
153 
154     if (!left || !right)
155         return DETECTION_OPTION_NOT_EQUAL;
156 
157     if ((left->contextData == right->contextData) &&
158         (left->checkFunction == right->checkFunction) &&
159         (left->hasOptionFunction == right->hasOptionFunction) &&
160         (left->getDynamicContents == right->getDynamicContents) &&
161         (left->contentFlags == right->contentFlags))
162     {
163         return DETECTION_OPTION_EQUAL;
164     }
165 
166     return DETECTION_OPTION_NOT_EQUAL;
167 }
168 
169 /****************************************************************************
170  *
171  * Function: SetupDynamic()
172  *
173  * Purpose: Load it up
174  *
175  * Arguments: None.
176  *
177  * Returns: void function
178  *
179  ****************************************************************************/
SetupDynamic(void)180 void SetupDynamic(void)
181 {
182     /* map the keyword to an initialization/processing function */
183     RegisterRuleOption("dynamic", DynamicInit, NULL, OPT_TYPE_DETECTION, NULL);
184 
185 #ifdef PERF_PROFILING
186     RegisterPreprocessorProfile("dynamic_rule", &dynamicRuleEvalPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
187 #endif
188     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Plugin: Dynamic Setup\n"););
189 }
190 
191 
192 /****************************************************************************
193  *
194  * Function: DynamicInit(struct _SnortConfig *, char *, OptTreeNode *)
195  *
196  * Purpose: Configuration function.  Handles parsing the rule
197  *          information and attaching the associated detection function to
198  *          the OTN.
199  *
200  * Arguments: data => rule arguments/data
201  *            otn => pointer to the current rule option list node
202  *            protocol => protocol the rule is on (we don't care in this case)
203  *
204  * Returns: void function
205  *
206  ****************************************************************************/
DynamicInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)207 void DynamicInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
208 {
209     OptFpList *fpl;
210     DynamicData *dynData;
211     void *option_dup;
212 
213     dynData = (DynamicData *)otn->ds_list[PLUGIN_DYNAMIC];
214 
215     fpl = AddOptFuncToList(DynamicCheck, otn);
216 
217     /* attach it to the context node so that we can call each instance
218      * individually
219      */
220     fpl->context = (void *) dynData;
221 
222     if (add_detection_option(sc, RULE_OPTION_TYPE_DYNAMIC, (void *)dynData, &option_dup) == DETECTION_OPTION_EQUAL)
223     {
224         free(dynData);
225         fpl->context = dynData = option_dup;
226     }
227     fpl->type = RULE_OPTION_TYPE_DYNAMIC;
228 }
229 
230 /****************************************************************************
231  *
232  * Function: DynamicCheck(char *, OptTreeNode *, OptFpList *)
233  *
234  * Purpose: Use this function to perform the particular detection routine
235  *          that this rule keyword is supposed to encompass.
236  *
237  * Arguments: p => pointer to the decoded packet
238  *            otn => pointer to the current rule's OTN
239  *            fp_list => pointer to the function pointer list
240  *
241  * Returns: If the detection test fails, this function *must* return a zero!
242  *          On success, it calls the next function in the detection list
243  *
244  ****************************************************************************/
DynamicCheck(void * option_data,Packet * p)245 int DynamicCheck(void *option_data, Packet *p)
246 {
247     DynamicData *dynData = (DynamicData *)option_data;
248     int result = 0;
249     PROFILE_VARS;
250 
251     PREPROC_PROFILE_START(dynamicRuleEvalPerfStats);
252 
253     if (!dynData)
254     {
255         LogMessage("Dynamic Rule with no context data available");
256         PREPROC_PROFILE_END(dynamicRuleEvalPerfStats);
257         return DETECTION_OPTION_NO_MATCH;
258     }
259 
260     result = dynData->checkFunction((void *)p, dynData->contextData);
261     if (result)
262     {
263         PREPROC_PROFILE_END(dynamicRuleEvalPerfStats);
264         return result;
265     }
266 
267     /* Detection failed */
268     PREPROC_PROFILE_END(dynamicRuleEvalPerfStats);
269     return DETECTION_OPTION_NO_MATCH;
270 }
271 
DynamicRuleListFree(DynamicRuleNode * head)272 void DynamicRuleListFree(DynamicRuleNode *head)
273 {
274     while (head != NULL)
275     {
276         DynamicRuleNode *tmp = head->next;
277 
278         /*
279          * Clean up will be executed only when snort exits or
280          * dynamic libs have changed
281          */
282         if (head->freeFunc)
283         {
284             head->freeFunc((void *)head->rule);
285         }
286 
287         free(head);
288         head = tmp;
289     }
290 }
291 
292 /****************************************************************************
293  *
294  * Function: RegisterDynamicRule(Snortconfig *, uint32_t, uint32_t, char *,
295  *                               void *,
296  *                               OTNCheckFunction, int, GetFPContentFunction)
297  *
298  * Purpose: A dynamically loaded detection engine library can use this
299  *          function to register a dynamically loaded rule/preprocessor.  It
300  *          provides a pointer to context specific data for the
301  *          rule/preprocessor and a reference to the function used to
302  *          check the rule.
303  *
304  * Arguments: sid => Signature ID
305  *            gid => Generator ID
306  *            info => context specific data
307  *            chkFunc => Function to call to check if the rule matches
308  *            has*Funcs => Functions used to categorize this rule
309  *            contentFlags => Flags indicating which contents are available
310  *            contentsFunc => Function to call to get list of rule contents
311  *
312  * Returns: 0 on success
313  *
314  ****************************************************************************/
RegisterDynamicRule(SnortConfig * sc,uint32_t sid,uint32_t gid,void * info,OTNCheckFunction chkFunc,OTNHasFunction hasFunc,int contentFlags,GetDynamicContentsFunction contentsFunc,RuleFreeFunc freeFunc,GetDynamicPreprocOptFpContentsFunc preprocFpFunc)315 int RegisterDynamicRule(
316     SnortConfig *sc,
317     uint32_t sid,
318     uint32_t gid,
319     void *info,
320     OTNCheckFunction chkFunc,
321     OTNHasFunction hasFunc,
322     int contentFlags,
323     GetDynamicContentsFunction contentsFunc,
324     RuleFreeFunc freeFunc,
325     GetDynamicPreprocOptFpContentsFunc preprocFpFunc
326     )
327 {
328     DynamicData *dynData;
329     struct _OptTreeNode *otn = NULL;
330     OptFpList *idx;     /* index pointer */
331     OptFpList *fpl;
332     char done_once = 0;
333     void *option_dup;
334     DynamicRuleNode *node = NULL;
335 
336     if (sc == NULL)
337     {
338         FatalError("%s(%d) Snort config is NULL.\n",
339                    __FILE__, __LINE__);
340     }
341 
342     if ( SnortDynamicLibsChanged() || SnortIsInitializing() )
343     {
344         node = (DynamicRuleNode *)SnortAlloc(sizeof(DynamicRuleNode));
345 
346         if (sc->dynamic_rules == NULL)
347         {
348             sc->dynamic_rules = node;
349         }
350         else
351         {
352             DynamicRuleNode *tmp = sc->dynamic_rules;
353 
354             while (tmp->next != NULL)
355                 tmp = tmp->next;
356 
357             tmp->next = node;
358         }
359 
360         node->rule = (Rule *)info;
361         node->chkFunc = chkFunc;
362         node->hasFunc = hasFunc;
363         node->contentFlags = contentFlags;
364         node->contentsFunc = contentsFunc;
365         node->freeFunc = freeFunc;
366         node->preprocFpContentsFunc = preprocFpFunc;
367     }
368 
369     /* Get OTN/RTN from SID */
370     otn = SoRuleOtnLookup(sc->so_rule_otn_map, gid, sid);
371     if (!otn)
372     {
373         if (ScConfErrorOut())
374         {
375             FatalError("DynamicPlugin: Rule [%u:%u] not enabled in configuration.\n", gid, sid);
376         }
377         else
378         {
379 #ifndef SOURCEFIRE
380             LogMessage("DynamicPlugin: Rule [%u:%u] not enabled in "
381                        "configuration, rule will not be used.\n", gid, sid);
382 #endif
383         }
384 
385         return -1;
386     }
387 
388     /* If this dynamic rule can be expressed as a regular rule, break it down
389      * and convert it to use the rule option tree. */
390     if (ConvertDynamicRule(sc, (Rule *)info, otn) > 0)
391     {
392         if (node != NULL)
393             node->converted = 1;
394 
395         return 0;
396     }
397 
398     /* allocate the data structure and attach it to the
399      * rule's data struct list */
400     dynData = (DynamicData *)SnortAlloc(sizeof(DynamicData));
401     dynData->contextData = info;
402     dynData->checkFunction = chkFunc;
403     dynData->hasOptionFunction = hasFunc;
404     dynData->getDynamicContents = contentsFunc;
405     dynData->contentFlags = contentFlags;
406     dynData->getPreprocFpContents = preprocFpFunc;
407 
408     while (otn)
409     {
410         OptFpList *prev = NULL;
411 
412         otn->ds_list[PLUGIN_DYNAMIC] = (void *)dynData;
413 
414         /* And add this function into the tail of the list */
415         fpl = AddOptFuncToList(DynamicCheck, otn);
416         fpl->context = dynData;
417         fpl->type = RULE_OPTION_TYPE_DYNAMIC;
418 
419         if (done_once == 0)
420         {
421             if (add_detection_option(sc, RULE_OPTION_TYPE_DYNAMIC,
422                                      (void *)dynData, &option_dup) == DETECTION_OPTION_EQUAL)
423             {
424                 free(dynData);
425                 fpl->context = dynData = option_dup;
426             }
427 
428             done_once = 1;
429         }
430 
431         /* Arrgh.  Because we read this rule in earlier, there is
432          * already an OptListEnd node there.  Need to move this new
433          * one to just before it.
434          */
435         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n"););
436 
437         /* set the index pointer to the start of this OTN's function list */
438         idx = otn->opt_func;
439 
440         /* if there are no nodes on the function list... */
441         while(idx != NULL)
442         {
443             if (idx->next == fpl) /* The last one in the list before us */
444             {
445                 if (prev)
446                 {
447                     prev->next = fpl;
448                     fpl->next = idx;
449                     idx->next = NULL;
450                 }
451                 else /* idx is the head of the list */
452                 {
453                     otn->opt_func = fpl;
454                     fpl->next = idx;
455                     idx->next = NULL;
456                 }
457             }
458             prev = idx;
459             idx = idx->next;
460         }
461 
462         otn = SoRuleOtnLookupNext(gid, sid);
463     }
464 
465     return 0;
466 }
467 
468 #ifdef SNORT_RELOAD
ReloadDynamicRules(SnortConfig * sc)469 int ReloadDynamicRules(SnortConfig *sc)
470 {
471     /*
472      * We are registering the dynamic rules from old
473      * snort config to new one. Hence this should be
474      * snort_conf. This code will not be execute if
475      * dynamic detection has changed.
476      */
477     DynamicRuleNode *node = snort_conf->dynamic_rules;
478 
479     sc->dynamic_rules = snort_conf->dynamic_rules;
480     sc->loadedDetectionPlugins = snort_conf->loadedDetectionPlugins;
481     snort_conf->loadedDetectionPlugins = NULL;
482     snort_conf->dynamic_rules = NULL;
483 
484     for (; node != NULL; node = node->next)
485     {
486         int i;
487 
488         if (node->rule == NULL || (!node->rule->initialized) || node->rule->options == NULL)
489             continue;
490 
491         for (i = 0; node->rule->options[i] != NULL; i++)
492         {
493             RuleOption *option = node->rule->options[i];
494 
495             switch (option->optionType)
496             {
497                 case OPTION_TYPE_FLOWBIT:
498                     {
499                         FlowBitsInfo *flowbits = option->option_u.flowBit;
500                         flowbits = DynamicFlowbitRegister(flowbits);
501                     }
502 
503                     break;
504 
505                 default:
506                     break;
507             }
508         }
509 
510         if (RegisterDynamicRule(sc, node->rule->info.sigID, node->rule->info.genID,
511                     (void *)node->rule, node->chkFunc, node->hasFunc,
512                     node->contentFlags, node->contentsFunc,
513                     node->freeFunc, node->preprocFpContentsFunc) == -1)
514         {
515             for (i = 0; node->rule->options[i] != NULL; i++)
516             {
517                 RuleOption *option = node->rule->options[i];
518                 switch (option->optionType)
519                 {
520                     case OPTION_TYPE_FLOWBIT:
521                         {
522                             FlowBitsInfo *flowbits = option->option_u.flowBit;
523                             DynamicFlowbitUnregister(flowbits);
524                         }
525                         break;
526 
527                     default:
528                         break;
529                 }
530             }
531 
532         }
533     }
534 
535     return 0;
536 }
537 #endif
538 
DynamicPreprocRuleOptInit(struct _SnortConfig * sc,void * opt)539 int DynamicPreprocRuleOptInit(struct _SnortConfig *sc, void *opt)
540 {
541     PreprocessorOption *preprocOpt = (PreprocessorOption *)opt;
542     PreprocOptionInit optionInit;
543     PreprocOptionOtnHandler otnHandler;
544     char *option_name = NULL;
545     char *option_params = NULL;
546     char *tmp;
547     int result;
548 
549     if (preprocOpt == NULL)
550         return -1;
551 
552     if (preprocOpt->optionName == NULL)
553         return -1;
554 
555     result = GetPreprocessorRuleOptionFuncs(sc, (char *)preprocOpt->optionName,
556                                      &preprocOpt->optionInit,
557                                      &preprocOpt->optionEval,
558                                      &otnHandler,
559                                      &preprocOpt->optionFpFunc,
560                                      &preprocOpt->optionCleanup);
561     if (!result)
562         return -1;
563 
564     optionInit = (PreprocOptionInit)preprocOpt->optionInit;
565 
566     option_name = SnortStrdup(preprocOpt->optionName);
567 
568     /* XXX Hack right now for override options where the rule
569      * option is stored as <option> <override>, e.g.
570      * "byte_test dce"
571      * Since name is passed in to init function, the function
572      * is expecting the first word in the option name and not
573      * the whole string */
574     tmp = option_name;
575     while ((*tmp != '\0') && !isspace((int)*tmp)) tmp++;
576     *tmp = '\0';
577 
578     if (preprocOpt->optionParameters != NULL)
579         option_params = SnortStrdup(preprocOpt->optionParameters);
580 
581     result = optionInit(sc, option_name, option_params, &preprocOpt->dataPtr);
582 
583     free(option_name);
584     if (option_params != NULL) free(option_params);
585 
586     if (!result)
587         return -1;
588 
589     return 0;
590 }
591 
DynamicFlowbitRegister(void * info)592 void *DynamicFlowbitRegister(void *info)
593 {
594     FlowBitsInfo *flowbitsInfo = (FlowBitsInfo *)info;
595     FLOWBITS_OP *flowbits;
596 
597     if (!info)
598         return NULL;
599 
600     flowbits = (FLOWBITS_OP *) SnortAlloc(sizeof(FLOWBITS_OP));
601     flowbits->type = flowbitsInfo->operation;
602     processFlowBitsWithGroup(flowbitsInfo->flowBitsName, flowbitsInfo->groupName, flowbits);
603 
604     // SO rules sometimes reuse the same option structure for multiple rule
605     // definitions.  Also on snort reload we can't muck with the structure
606     // since it'll possibly be in use.  So if flowbitsInfo->ids is already set,
607     // the flowbits structure has already been parsed and flowbits->ids will
608     // remain unchanged, so just return.
609     // processFlowBitsWithGroup() is called again, mainly for reload in
610     // case flowbits have been removed or added and/or the actual id values
611     // have changed.
612     if (flowbitsInfo->ids != NULL)
613     {
614         if (flowbits->ids != NULL)
615             free(flowbits->ids);
616         free(flowbits);
617         return flowbitsInfo;
618     }
619 
620     flowbitsInfo->eval = flowbits->eval;
621     flowbitsInfo->ids = flowbits->ids;
622     flowbitsInfo->num_ids = flowbits->num_ids;
623     free(flowbits);
624     return flowbitsInfo;
625 }
626 
unregisterFlowbit(char * name,int op)627 static void unregisterFlowbit(char *name, int op)
628 {
629     FLOWBITS_OBJECT *flowbits_item;
630 
631     if (flowbits_hash == NULL)
632         return;
633 
634     flowbits_item = sfghash_find(flowbits_hash, name);
635     if (flowbits_item == NULL)
636         return;
637 
638     switch (op)
639     {
640         case FLOWBITS_SET:
641         case FLOWBITS_SETX:
642         case FLOWBITS_UNSET:
643         case FLOWBITS_TOGGLE:
644         case FLOWBITS_RESET:
645             if (flowbits_item->set == 0)
646                 return;
647             flowbits_item->set--;
648             break;
649 
650         case FLOWBITS_ISSET:
651         case FLOWBITS_ISNOTSET:
652             if (flowbits_item->isset == 0)
653                 return;
654             flowbits_item->isset--;
655             break;
656 
657         default:
658             break;
659     }
660 }
661 
DynamicFlowbitUnregister(void * info)662 void DynamicFlowbitUnregister(void *info)
663 {
664     FlowBitsInfo *flowbitsInfo = (FlowBitsInfo *)info;
665     char *names;
666     char *flowbitName;
667     char *nextName;
668     int op;
669 
670     if ((!flowbitsInfo)||(!flowbitsInfo->flowBitsName))
671         return;
672 
673     op = flowbitsInfo->operation;
674     names = SnortStrdup(flowbitsInfo->flowBitsName);
675     flowbitName = strtok_r(names, "|&", &nextName);
676     while ( flowbitName )
677     {
678         unregisterFlowbit(flowbitName, op);
679         flowbitName = strtok_r(nextName, "|&", &nextName);
680     }
681 
682     // Don't free flowbits->ids here for SO rules as it may cause a segfault
683     // with rules that share the same flowbits structure when not all of the
684     // stub rules are enabled.  The ids array will be free'd at shutdown in
685     // FreeOneRule().
686 
687     free(names);
688 }
689 
DynamicFlowbitCheck(void * pkt,void * info)690 int DynamicFlowbitCheck(void *pkt, void *info)
691 {
692     Packet *p = (Packet *)pkt;
693     FlowBitsInfo *flowbitsInfo = (FlowBitsInfo *)info;
694     int result = 0;
695     result = checkFlowBits(flowbitsInfo->operation, flowbitsInfo->eval, flowbitsInfo->ids,
696             flowbitsInfo->num_ids,flowbitsInfo->groupName, p);
697     return result;
698 }
699 
700 
DynamicAsn1Detect(void * pkt,void * ctxt,const uint8_t * cursor)701 int DynamicAsn1Detect(void *pkt, void *ctxt, const uint8_t *cursor)
702 {
703     Packet *p    = (Packet *) pkt;
704     ASN1_CTXT *c = (ASN1_CTXT *) ctxt;
705 
706     /* Call same detection function that snort calls */
707     return Asn1DoDetect(p->data, p->dsize, c, cursor);
708 }
709 
DynamicsfUnfold(const uint8_t * inbuf,uint32_t insize,uint8_t * outbuf,uint32_t outsize,uint32_t * read)710 int DynamicsfUnfold(const uint8_t *inbuf, uint32_t insize, uint8_t *outbuf, uint32_t outsize, uint32_t *read)
711 {
712     return sf_unfold_header(inbuf, insize, outbuf, outsize, read, 0, 0);
713 }
714 
Dynamicsfbase64decode(uint8_t * inbuf,uint32_t insize,uint8_t * outbuf,uint32_t outsize,uint32_t * read)715 int Dynamicsfbase64decode(uint8_t *inbuf, uint32_t insize, uint8_t *outbuf, uint32_t outsize, uint32_t *read)
716 {
717     return sf_base64decode(inbuf, insize, outbuf, outsize, read);
718 }
719 
DynamicGetAltDetect(uint8_t ** bufPtr,uint16_t * altLenPtr)720 int DynamicGetAltDetect(uint8_t **bufPtr, uint16_t *altLenPtr)
721 {
722     return GetAltDetect(bufPtr, altLenPtr);
723 }
724 
DynamicSetAltDetect(uint8_t * buf,uint16_t altLen)725 void DynamicSetAltDetect(uint8_t *buf, uint16_t altLen)
726 {
727     SetAltDetect(buf, altLen);
728 }
729 
DynamicIsDetectFlag(SFDetectFlagType df)730 int DynamicIsDetectFlag(SFDetectFlagType df)
731 {
732     return Is_DetectFlag((DetectFlagType)df);
733 }
734 
DynamicDetectFlagDisable(SFDetectFlagType df)735 void DynamicDetectFlagDisable(SFDetectFlagType df)
736 {
737         DetectFlag_Disable((DetectFlagType)df);
738 }
739 
740 
DynamicHasOption(OptTreeNode * otn,DynamicOptionType optionType,int flowFlag)741 static inline int DynamicHasOption(
742     OptTreeNode *otn, DynamicOptionType optionType, int flowFlag
743 ) {
744     DynamicData *dynData;
745 
746     dynData = (DynamicData *)otn->ds_list[PLUGIN_DYNAMIC];
747     if (!dynData)
748     {
749         return 0;
750     }
751 
752     return dynData->hasOptionFunction(dynData->contextData, optionType, flowFlag);
753 }
754 
DynamicHasFlow(OptTreeNode * otn)755 int DynamicHasFlow(OptTreeNode *otn)
756 {
757     return DynamicHasOption(otn, OPTION_TYPE_FLOWFLAGS, 0);
758 }
759 
DynamicHasFlowbit(OptTreeNode * otn)760 int DynamicHasFlowbit(OptTreeNode *otn)
761 {
762     return DynamicHasOption(otn, OPTION_TYPE_FLOWBIT, 0);
763 }
764 
DynamicHasContent(OptTreeNode * otn)765 int DynamicHasContent(OptTreeNode *otn)
766 {
767     return DynamicHasOption(otn, OPTION_TYPE_CONTENT, 0);
768 }
769 
DynamicHasByteTest(OptTreeNode * otn)770 int DynamicHasByteTest(OptTreeNode *otn)
771 {
772     return DynamicHasOption(otn, OPTION_TYPE_BYTE_TEST, 0);
773 }
774 
DynamicHasByteMath(OptTreeNode * otn)775 int DynamicHasByteMath(OptTreeNode *otn)
776 {
777     return DynamicHasOption(otn, OPTION_TYPE_BYTE_MATH, 0);
778 }
779 
DynamicHasPCRE(OptTreeNode * otn)780 int DynamicHasPCRE(OptTreeNode *otn)
781 {
782     return DynamicHasOption(otn, OPTION_TYPE_PCRE, 0);
783 }
784