1 /*
2  ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3  ** Copyright (C) 2010-2013 Sourcefire, Inc.
4  ** Author: Ryan Jordan <ryan.jordan@sourcefire.com>
5  **
6  ** This program is free software; you can redistribute it and/or modify
7  ** it under the terms of the GNU General Public License Version 2 as
8  ** published by the Free Software Foundation.  You may not use, modify or
9  ** distribute this program under any other version of the GNU General
10  ** Public License.
11  **
12  ** This program is distributed in the hope that it will be useful,
13  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  ** GNU General Public License for more details.
16  **
17  ** You should have received a copy of the GNU General Public License
18  ** along with this program; if not, write to the Free Software
19  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  */
21 
22 /* sp_byte_extract
23  *
24  * Description goes here. Snort rule interface for byte_extract functionality.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include "sf_types.h"
33 #include "snort.h"
34 #include "parser.h"
35 #include "plugbase.h"
36 #include "preprocids.h"
37 #include "detection_options.h"
38 #include "detection_util.h"
39 #include "sfhashfcn.h"
40 #include "profiler.h"
41 #include "byte_extract.h"
42 
43 #include "sp_byte_extract.h"
44 #include "sp_byte_math.h"
45 
46 #ifdef PERF_PROFILING
47 PreprocStats byteExtractPerfStats;
48 extern PreprocStats ruleOTNEvalPerfStats;
49 #endif
50 
51 extern int file_line;
52 extern char *file_name;
53 
54 uint32_t Byte_Extract_Offset_Var;
55 
56 /* Storage for extracted variables */
57 static uint32_t extracted_values[NUM_BYTE_EXTRACT_VARS];
58 static char *variable_names[NUM_BYTE_EXTRACT_VARS];
59 
60 /* Prototypes */
61 static void ByteExtractInit(struct _SnortConfig *, char *, OptTreeNode *, int);
62 static void ByteExtractCleanup(int, void *);
63 
64 /* Setup function */
SetupByteExtract(void)65 void SetupByteExtract(void)
66 {
67     RegisterRuleOption("byte_extract", ByteExtractInit, NULL, OPT_TYPE_DETECTION, NULL);
68     AddFuncToCleanExitList(ByteExtractCleanup, NULL);
69 
70 #ifdef PERF_PROFILING
71     RegisterPreprocessorProfile("byte_extract", &byteExtractPerfStats, 3, &ruleOTNEvalPerfStats, NULL);
72 #endif
73 }
74 
75 /* Clean up some strings left over from parsing */
ByteExtractCleanup(int signal,void * data)76 static void ByteExtractCleanup(int signal, void *data)
77 {
78     int i;
79     for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
80     {
81         free(variable_names[i]);
82         variable_names[i] = NULL;
83     }
84 }
85 
86 #ifdef DEBUG_MSGS
87 /* Print a byte_extract option to console. For debugging purposes. */
PrintByteExtract(ByteExtractData * data)88 void PrintByteExtract(ByteExtractData *data)
89 {
90     if (data == NULL)
91         return;
92 
93     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,
94            "bytes_to_grab = %d, offset = %d, relative = %d, convert = %d, "
95            "align = %d, endianess = %d, base = %d, "
96            "multiplier = %d, var_num = %d, name = %s,  bitmask_val = 0x%x\n",
97            data->bytes_to_grab,
98            data->offset,
99            data->relative_flag,
100            data->data_string_convert_flag,
101            data->align,
102            data->endianess,
103            data->base,
104            data->multiplier,
105            data->var_number,
106            data->name,
107            data->bitmask_val););
108 }
109 #endif
110 
111 /* Hash functions. Make sure to update these when the data struct changes! */
ByteExtractHash(void * d)112 uint32_t ByteExtractHash(void *d)
113 {
114     uint32_t a,b,c;
115     ByteExtractData *data = (ByteExtractData *)d;
116 
117     a = data->bytes_to_grab;
118     b = data->offset;
119     c = data->base;
120 
121     mix(a,b,c);
122 
123     a += (data->relative_flag << 24 |
124           data->data_string_convert_flag << 16 |
125           data->align << 8 |
126           data->endianess);
127     b += data->multiplier;
128     c += data->bitmask_val;
129 
130     mix(a,b,c);
131 
132     a += RULE_OPTION_TYPE_BYTE_EXTRACT;
133     b += data->var_number;
134 
135     mix(a,b,c);
136 
137 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
138     {
139         /* Cleanup warning because of cast from 64bit ptr to 32bit int
140          * warning on 64bit OSs */
141         uint64_t ptr; /* Addresses are 64bits */
142 
143         ptr = (uint64_t) data->byte_order_func;
144         a += (ptr >> 32);
145         b += (ptr & 0xFFFFFFFF);
146     }
147 #else
148     a += (uint32_t)data->byte_order_func;
149 #endif
150 
151     final(a,b,c);
152 
153     return c;
154 }
155 
ByteExtractCompare(void * l,void * r)156 int ByteExtractCompare(void *l, void *r)
157 {
158     ByteExtractData *left = (ByteExtractData *) l;
159     ByteExtractData *right = (ByteExtractData *) r;
160 
161     if (!left || !right)
162         return DETECTION_OPTION_NOT_EQUAL;
163 
164     if ((left->bytes_to_grab == right->bytes_to_grab) &&
165         (left->offset == right->offset) &&
166         (left->relative_flag == right->relative_flag) &&
167         (left->data_string_convert_flag == right->data_string_convert_flag) &&
168         (left->align == right->align) &&
169         (left->endianess == right->endianess) &&
170         (left->base == right->base) &&
171         (left->multiplier == right->multiplier) &&
172         (left->var_number == right->var_number) &&
173         (left->byte_order_func == right->byte_order_func) &&
174         (left->bitmask_val == right->bitmask_val))
175     {
176         return DETECTION_OPTION_EQUAL;
177     }
178 
179     return DETECTION_OPTION_NOT_EQUAL;
180 }
181 
ByteExtractFree(void * d)182 void ByteExtractFree(void *d)
183 {
184     ByteExtractData *data = (ByteExtractData *)d;
185     free(data->name);
186     free(data);
187 }
188 
189 /* Checks a ByteExtractData instance for errors. */
ByteExtractVerify(ByteExtractData * data)190 static int ByteExtractVerify(ByteExtractData *data)
191 {
192     if (data->bytes_to_grab > MAX_BYTES_TO_GRAB && data->data_string_convert_flag == 0)
193     {
194         ParseError("byte_extract rule option cannot extract more than %d bytes.",
195                      MAX_BYTES_TO_GRAB);
196     }
197 
198     if (data->bytes_to_grab > PARSELEN && data->data_string_convert_flag == 1)
199     {
200         ParseError("byte_extract rule cannot process more than %d bytes for "
201                    "string extraction.",  PARSELEN);
202     }
203 
204     if (Byte_Extract_Offset_Var != BYTE_MATH_VAR_INDEX )
205     {
206          if (data->offset < MIN_BYTE_EXTRACT_OFFSET || data->offset > MAX_BYTE_EXTRACT_OFFSET)
207          {
208               ParseError("byte_extract rule option has invalid offset. "
209                    "Valid offsets are between %d and %d.",
210                      MIN_BYTE_EXTRACT_OFFSET, MAX_BYTE_EXTRACT_OFFSET);
211          }
212     }
213 
214     if (data->multiplier < MIN_BYTE_EXTRACT_MULTIPLIER || data->multiplier > MAX_BYTE_EXTRACT_MULTIPLIER)
215     {
216         ParseError("byte_extract rule option has invalid multiplier. "
217                    "Valid multipliers are between %d and %d.",
218                     MIN_BYTE_EXTRACT_MULTIPLIER, MAX_BYTE_EXTRACT_MULTIPLIER);
219     }
220 
221     if (data->bytes_to_grab == 0)
222         ParseError("byte_extract rule option extracts zero bytes. "
223                    "\"bytes_to_extract\" must be 1 or greater.");
224 
225     if (data->align != 0 && data->align != 2 && data->align != 4)
226         ParseError("byte_extract rule option has an invalid argument "
227                    "to \"align\". Valid arguments are \'2\' and \'4\'.");
228 
229     if (data->offset < 0 && data->relative_flag == 0)
230         ParseError("byte_extract rule option has a negative offset, but does "
231                    "not use the \"relative\" option.");
232 
233     if (data->name && isdigit(data->name[0]))
234     {
235         ParseError("byte_extract rule option has a name which starts with a digit. "
236                    "Variable names must start with a letter.");
237     }
238 
239     if (data->base && !data->data_string_convert_flag)
240     {
241         ParseError("byte_extract rule option has a string converstion type "
242                    "(\"dec\", \"hex\", or \"oct\") without the \"string\" "
243                    "argument.");
244     }
245 
246     return BYTE_EXTRACT_SUCCESS;
247 }
248 
249 
numBytesInBitmask(uint32_t bitmask_value)250 int numBytesInBitmask(uint32_t bitmask_value)
251 {
252    int num_bytes;
253    if( bitmask_value <= 0xFF )
254        num_bytes = 1;
255    else if ( bitmask_value <= 0xFFFF )
256        num_bytes = 2;
257    else if ( bitmask_value <= 0xFFFFFF )
258        num_bytes = 3;
259    else
260        num_bytes = 4;
261 
262    return num_bytes;
263 }
264 
RuleOptionBitmaskParse(uint32_t * bitmask_val,char * cptr,uint32_t bytes_to_extract,char * ruleOptionName)265 void RuleOptionBitmaskParse(uint32_t* bitmask_val, char *cptr, uint32_t bytes_to_extract,char* ruleOptionName)
266 {
267      char* endp = NULL;
268      char* startp = (cptr + 8);
269      uint32_t bitmask_value;
270      uint32_t num_bytes=0;
271 
272      if(*bitmask_val == 0 )
273      {
274           if(SnortStrToU32(startp,&endp,&bitmask_value,16) == -1 )
275                ParseError("%s :: Invalid input value for \"bitmask\" rule option.\n", ruleOptionName);
276           else if( errno == ERANGE )
277                ParseError("%s :: \"bitmask\" value is OUT OF RANGE.\n", ruleOptionName);
278           else if (bitmask_value == 0 )
279                ParseError("%s :: \"bitmask\" value is ZERO.\n", ruleOptionName);
280           else if (*endp != '\0')
281                 ParseError("%s :: Rule option has invalid argument to \"bitmask\".\n", ruleOptionName);
282           else
283           {
284                num_bytes = numBytesInBitmask(bitmask_value);
285                if (bytes_to_extract  <= MAX_BYTES_TO_EXTRACT)
286                {
287                    if(bytes_to_extract >= num_bytes )
288                    {
289                        *bitmask_val = bitmask_value;
290                    }
291                    else
292                        ParseError("%s :: Number of bytes in \"bitmask\" value is greater than  bytes_to_grab.\n", ruleOptionName);
293                }
294                else
295                     ParseError("%s :: Number of extracted bytes from packet are more than MAX_BYTES_TO_GRAB.\n", ruleOptionName);
296           }
297      }
298      else
299           ParseError("%s :: Rule option includes the \"bitmask\" argument twice.\n",ruleOptionName);
300 }
301 
302 /* String Validation for all special characters in the varaibale name */
isvalidstr(char * str,char * feature)303 void isvalidstr(char *str,char *feature)
304 {
305    int cnt=0,pos=0;
306    for (;str[pos]!='\0';pos++)
307    {
308       if (!((str[pos] >= 'a' && str[pos] <= 'z') || (str[pos] >= 'A' && str[pos] <= 'Z') || (str[pos] >= '0' && str[pos] <='9')))
309            cnt++;
310    }
311    if (pos == cnt)
312            ParseError("%s input %s.Complete string with special characters are not allowed in variable name field",feature,str);
313 }
314 
315 /* Parsing function. */
ByteExtractParse(ByteExtractData * data,char * args)316 static int ByteExtractParse(ByteExtractData *data, char *args)
317 {
318     char *args_copy = SnortStrdup(args);
319     char *endptr, *saveptr = args_copy;
320     char *token = strtok_r(args_copy, ",", &saveptr);
321     RuleOptByteOrderFunc tmp_byte_order_func = NULL;
322 
323     /* set defaults / sentinels */
324     data->multiplier = 1;
325     data->endianess = ENDIAN_NONE;
326 
327     /* first: bytes_to_extract */
328     if (token)
329     {
330         data->bytes_to_grab = SnortStrtoul(token, &endptr, 10);
331         if (*endptr != '\0')
332             ParseError("byte_extract rule option has non-digits in the "
333                     "\"bytes_to_extract\" field.");
334         token = strtok_r(NULL, ",", &saveptr);
335     }
336 
337     /* second: offset */
338     if (token)
339     {
340         if (isdigit(token[0]) || token[0] == '-')
341         {
342              data->offset = SnortStrtoul(token, &endptr, 10);
343              if (*endptr != '\0')
344                  ParseError("byte_extract rule option has non-digits in the "
345                         "\"offset\" field.");
346         }
347         else
348         {
349             if ( bytemath_variable_name  && (!strcmp(bytemath_variable_name,token)))
350             {
351                     data->offset = (int32_t) bytemath_variable;
352                     Byte_Extract_Offset_Var = BYTE_MATH_VAR_INDEX;
353             }
354             else
355             {
356                   ParseError("byte_extract rule option has invalid Variable name in the "
357                         "\"offset\" field.");
358             }
359         }
360         token = strtok_r(NULL, ",", &saveptr);
361     }
362 
363     /* third: variable name */
364     if (token)
365     {
366         data->name = SnortStrdup(token);
367         isvalidstr(token,"byte_extract");
368         token = strtok_r(NULL, ",", &saveptr);
369     }
370 
371     /* optional arguments */
372     while (token)
373     {
374         while(isspace((int)*token)) {token++;}
375         if (strcmp(token, "relative") == 0)
376         {
377             data->relative_flag = 1;
378         }
379 
380         else if (strncmp(token, "align ", 6) == 0)
381         {
382             char *value = (token+6);
383 
384             if (data->align == 0)
385                 data->align = (uint8_t)SnortStrtoul(value, &endptr, 10);
386             else
387                 ParseError("byte_extract rule option includes the "
388                         "\"align\" argument twice.");
389 
390             if (*endptr != '\0')
391                 ParseError("byte_extract rule option has non-digits in the "
392                         "argument to \"align\". ");
393         }
394 
395         else if (strcmp(token, "little") == 0)
396         {
397             if (data->endianess == ENDIAN_NONE)
398                 data->endianess = LITTLE;
399             else
400                 ParseError("byte_extract rule option specifies the "
401                         "byte order twice. Use only one of \"big\", \"little\", "
402                         "or \"dce\".");
403         }
404 
405         else if (strcmp(token, "big") == 0)
406         {
407             if (data->endianess == ENDIAN_NONE)
408                 data->endianess = BIG;
409             else
410                 ParseError("byte_extract rule option specifies the "
411                         "byte order twice. Use only one of \"big\", \"little\", "
412                         "or \"dce\".");
413         }
414 
415         else if (strncmp(token, "multiplier ", 11) == 0)
416         {
417             char *value = (token+11);
418             if (value[0] == '\0')
419                 ParseError("byte_extract rule option has a \"multiplier\" "
420                         "argument with no value specified.");
421 
422             if (data->multiplier == 1)
423             {
424                 data->multiplier = SnortStrtoul(value, &endptr, 10);
425 
426                 if (*endptr != '\0')
427                     ParseError("byte_extract rule option has non-digits in the "
428                             "argument to \"multiplier\". ");
429             }
430             else
431                 ParseError("byte_extract rule option has multiple "
432                         "\"multiplier\" arguments. Use only one.");
433         }
434 
435         else if (strcmp(token, "string") == 0)
436         {
437             if (data->data_string_convert_flag == 0)
438                 data->data_string_convert_flag = 1;
439             else
440                 ParseError("byte_extract rule option has multiple "
441                         "\"string\" arguments. Use only one.");
442         }
443 
444         else if (strcmp(token, "dec") == 0)
445         {
446             if (data->base == 0)
447                 data->base = 10;
448             else
449                 ParseError("byte_extract rule option has multiple arguments "
450                         "specifying the type of string conversion. Use only "
451                         "one of \"dec\", \"hex\", or \"oct\".");
452         }
453 
454         else if (strcmp(token, "hex") == 0)
455         {
456             if (data->base == 0)
457                 data->base = 16;
458             else
459                 ParseError("byte_extract rule option has multiple arguments "
460                         "specifying the type of string conversion. Use only "
461                         "one of \"dec\", \"hex\", or \"oct\".");
462         }
463 
464         else if (strcmp(token, "oct") == 0)
465         {
466             if (data->base == 0)
467                 data->base = 8;
468             else
469                 ParseError("byte_extract rule option has multiple arguments "
470                         "specifying the type of string conversion. Use only "
471                         "one of \"dec\", \"hex\", or \"oct\".");
472         }
473 
474         else if ((tmp_byte_order_func = GetByteOrderFunc(token)) != NULL)
475         {
476             if (data->endianess == ENDIAN_NONE)
477             {
478                 data->endianess = ENDIAN_FUNC;
479                 data->byte_order_func = tmp_byte_order_func;
480             }
481             else
482             {
483                 ParseError("byte_extract rule option specifies the "
484                         "byte order twice. Use only one of \"big\", \"little\", "
485                         "or \"dce\".");
486             }
487         }
488 
489         else if(strncasecmp(token,"bitmask ",8) == 0)
490         {
491             RuleOptionBitmaskParse(&(data->bitmask_val) , token, data->bytes_to_grab, "BYTE_EXTRACT" );
492         }
493 
494         else
495         {
496             ParseError("byte_extract rule option has invalid argument \"%s\".", token);
497         }
498 
499         token = strtok_r(NULL, ",", &saveptr);
500     }
501 
502     free(args_copy);
503 
504     /* Need to check this error before the sentinel gets replaced */
505     if (data->endianess != ENDIAN_NONE && data->data_string_convert_flag == 1)
506     {
507         ParseError("byte_extract rule option can't have \"string\" specified "
508             "at the same time as a byte order (\"big\" or \"little\").");
509     }
510 
511     /* Replace sentinels with defaults */
512     if (data->endianess == ENDIAN_NONE)
513         data->endianess = BIG;
514 
515     if (data->data_string_convert_flag && (data->base == 0))
516         data->base = 10;
517 
518     /* At this point you could verify the data and return something. */
519     return ByteExtractVerify(data);
520 }
521 
522 /* Given a variable name, retrieve its index. For use by other options. */
GetVarByName(char * name)523 int8_t GetVarByName(char *name)
524 {
525     int i;
526 
527     if (name == NULL)
528         return BYTE_EXTRACT_NO_VAR;
529 
530     for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
531     {
532         if (variable_names[i] != NULL && strcmp(variable_names[i], name) == 0)
533             return i;
534     }
535 
536     return BYTE_EXTRACT_NO_VAR;
537 }
538 
539 /* If given an OptFpList with no byte_extracts, clear the variable_names array */
ClearVarNames(OptFpList * fpl)540 void ClearVarNames(OptFpList *fpl)
541 {
542     int i;
543 
544     while (fpl != NULL)
545     {
546         if (fpl->type == RULE_OPTION_TYPE_BYTE_EXTRACT)
547             return;
548 
549         fpl = fpl->next;
550     }
551 
552     for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
553     {
554         free(variable_names[i]);
555         variable_names[i] = NULL;
556     }
557 }
558 
559 /* Add a variable's name to the variable_names array
560    Returns: variable index
561 */
AddVarNameToList(ByteExtractData * data)562 int8_t AddVarNameToList(ByteExtractData *data)
563 {
564     int i;
565 
566     for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
567     {
568         if (variable_names[i] == NULL)
569         {
570             variable_names[i] = SnortStrdup(data->name);
571             break;
572         }
573 
574         else if ( strcmp(variable_names[i], data->name) == 0 )
575         {
576             break;
577         }
578     }
579 
580     return i;
581 }
582 
583 
584 /* Inititialization function. Handles rule parsing. */
ByteExtractInit(struct _SnortConfig * sc,char * data,OptTreeNode * otn,int protocol)585 static void ByteExtractInit(struct _SnortConfig *sc, char *data, OptTreeNode *otn, int protocol)
586 {
587     ByteExtractData *idx;
588     OptFpList *fpl;
589     void *idx_dup;
590 
591     idx = (ByteExtractData *) SnortAlloc(sizeof(ByteExtractData));
592 
593     /* Clear out the variable_names array if this is the first byte_extract in a rule. */
594     ClearVarNames(otn->opt_func);
595 
596     /* Parse the options */
597     ByteExtractParse(idx, data);
598 
599     /* There can only be two unique variables names in a rule. */
600     idx->var_number = AddVarNameToList(idx);
601     if (idx->var_number >= NUM_BYTE_EXTRACT_VARS)
602     {
603         ParseError("Rule has more than %d byte_extract variables.", NUM_BYTE_EXTRACT_VARS);
604     }
605 #ifdef DEBUG_MSGS
606     PrintByteExtract(idx);
607 #endif
608 
609     fpl = AddOptFuncToList(DetectByteExtract, otn);
610     fpl->type = RULE_OPTION_TYPE_BYTE_EXTRACT;
611     if (add_detection_option(sc, RULE_OPTION_TYPE_BYTE_EXTRACT, (void *)idx, &idx_dup) == DETECTION_OPTION_EQUAL)
612     {
613         /* duplicate exists. */
614         free(idx->name);
615         free(idx);
616         idx = idx_dup;
617     }
618 
619     fpl->context = (void *) idx;
620 
621     if (idx->relative_flag == 1)
622         fpl->isRelative = 1;
623 }
624 
getNumberTailingZerosInBitmask(uint32_t bitmask)625 uint32_t getNumberTailingZerosInBitmask(uint32_t bitmask)
626 {
627    unsigned int num_tailing_zeros;
628 
629    if (bitmask & 0x1)
630    {
631        num_tailing_zeros = 0;
632    }
633    else
634    {
635        num_tailing_zeros = 1;
636        if ((bitmask & 0xffff) == 0)
637        {
638             bitmask >>= 16;
639             num_tailing_zeros += 16;
640        }
641        if ((bitmask & 0xff) == 0)
642        {
643             bitmask >>= 8;
644             num_tailing_zeros += 8;
645        }
646        if ((bitmask & 0xf) == 0)
647        {
648              bitmask >>= 4;
649              num_tailing_zeros += 4;
650        }
651        if ((bitmask & 0x3) == 0)
652        {
653              bitmask >>= 2;
654              num_tailing_zeros += 2;
655        }
656        num_tailing_zeros -= bitmask & 0x1;
657    }
658 
659    return num_tailing_zeros;
660 }
661 
662 /* Main detection callback */
DetectByteExtract(void * option_data,Packet * p)663 int DetectByteExtract(void *option_data, Packet *p)
664 {
665     ByteExtractData *data = (ByteExtractData *) option_data;
666     int ret, bytes_read, dsize;
667     const uint8_t *ptr, *start, *end;
668     uint32_t *value;
669     int32_t offset;
670     uint8_t rst_doe_flags = 1;
671     PROFILE_VARS;
672 
673     PREPROC_PROFILE_START(byteExtractPerfStats);
674 
675     if (data == NULL || p == NULL)
676     {
677         PREPROC_PROFILE_END(byteExtractPerfStats);
678         return DETECTION_OPTION_NO_MATCH;
679     }
680 
681     /* setup our fun pointers */
682     if (Is_DetectFlag(FLAG_ALT_DETECT))
683     {
684         dsize = DetectBuffer.len;
685         start = DetectBuffer.data;
686     }
687     else if (Is_DetectFlag(FLAG_ALT_DECODE))
688     {
689         dsize = DecodeBuffer.len;
690         start = DecodeBuffer.data;
691     }
692     else
693     {
694         if(IsLimitedDetect(p))
695             dsize = p->alt_dsize;
696         else
697             dsize = p->dsize;
698         start = p->data;
699     }
700 
701     if (data->relative_flag)
702     {
703         ptr = doe_ptr;
704         rst_doe_flags = 0;
705     }
706     else
707         ptr = start;
708 
709     ptr += data->offset;
710     end = start + dsize;
711     value = &(extracted_values[data->var_number]);
712 
713     /* check bounds */
714     if (ptr < start || ptr >= end)
715     {
716         PREPROC_PROFILE_END(byteExtractPerfStats);
717         return DETECTION_OPTION_NO_MATCH;
718     }
719 
720     /* get the endianess at run-time if we have a byte_order_func */
721     if (data->byte_order_func)
722     {
723         offset = (int32_t) (ptr - start);
724         data->endianess = data->byte_order_func((void *)p, offset);
725     }
726     if (data->endianess == -1)
727     {
728         /* Sometimes the byte_order_func deems that the packet should be skipped */
729         PREPROC_PROFILE_END(byteExtractPerfStats);
730         return DETECTION_OPTION_NO_MATCH;
731     }
732 
733     if (data->data_string_convert_flag == 0)
734     {
735         ret = byte_extract(data->endianess, data->bytes_to_grab, ptr, start, end, value);
736         if (ret < 0)
737         {
738             PREPROC_PROFILE_END(byteExtractPerfStats);
739             return DETECTION_OPTION_NO_MATCH;
740         }
741         bytes_read = data->bytes_to_grab;
742     }
743     else
744     {
745         ret = string_extract(data->bytes_to_grab, data->base, ptr, start, end, value);
746         if (ret < 0)
747         {
748              PREPROC_PROFILE_END(byteExtractPerfStats);
749              return DETECTION_OPTION_NO_MATCH;
750         }
751         bytes_read = ret;
752     }
753 
754     if(data->bitmask_val != 0 )
755     {
756         int num_tailing_zeros_bitmask = getNumberTailingZerosInBitmask(data->bitmask_val);
757         *value = (*value) & data->bitmask_val ;
758          if ( (*value) && num_tailing_zeros_bitmask )
759          {
760             *value = (*value) >> num_tailing_zeros_bitmask;
761          }
762     }
763 
764     /* mulitply */
765     *value *= data->multiplier;
766 
767     /* align to next 32-bit or 16-bit boundary */
768     if ((data->align == 4) && (*value % 4))
769     {
770         *value = *value + 4 - (*value % 4);
771     }
772     else if ((data->align == 2) && (*value % 2))
773     {
774         *value = *value + 2 - (*value % 2);
775     }
776 
777     /* push doe_ptr */
778     UpdateDoePtr((ptr + bytes_read), rst_doe_flags);
779 
780     /* this rule option always "matches" if the read is performed correctly */
781     PREPROC_PROFILE_END(byteExtractPerfStats);
782     common_var = *value;
783     return DETECTION_OPTION_MATCH;
784 }
785 
786 /* Setters & Getters for extracted values */
GetByteExtractValue(uint32_t * dst,int8_t var_number)787 int GetByteExtractValue(uint32_t *dst, int8_t var_number)
788 {
789     if (dst == NULL || var_number >= NUM_BYTE_EXTRACT_VARS)
790         return BYTE_EXTRACT_NO_VAR;
791 
792     *dst = extracted_values[var_number];
793     return 0;
794 }
795 
SetByteExtractValue(uint32_t value,int8_t var_number)796 int SetByteExtractValue(uint32_t value, int8_t var_number)
797 {
798     if (var_number >= NUM_BYTE_EXTRACT_VARS)
799         return BYTE_EXTRACT_NO_VAR;
800 
801     extracted_values[var_number] = value;
802 
803     return 0;
804 }
805