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