"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/detection-plugins/sp_byte_extract.c" (16 Oct 2020, 23783 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sp_byte_extract.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /*
    2  ** Copyright (C) 2014-2020 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 */
   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 */
   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. */
   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! */
  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 
  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 
  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. */
  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 
  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 
  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 */
  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. */
  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. */
  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 */
  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 */
  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. */
  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 
  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 */
  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 */
  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 
  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 }