"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/detection-plugins/detection_options.c" (16 Oct 2020, 53177 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 "detection_options.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 /* $Id$ */
    2 /*
    3 ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    4 ** Copyright (C) 2007-2013 Sourcefire, Inc.
    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 
   23 /**
   24 **  @file        detection_options.c
   25 **
   26 **  @author      Steven Sturges
   27 **
   28 **  @brief       Support functions for rule option tree
   29 **
   30 **  This implements tree processing for rule options, evaluating common
   31 **  detection options only once per pattern match.
   32 **
   33 */
   34 
   35 #ifdef HAVE_CONFIG_H
   36 #include "config.h"
   37 #endif
   38 
   39 #include "sfutil/sfxhash.h"
   40 #include "sfutil/sfhashfcn.h"
   41 #include "detection_options.h"
   42 #include "detection_util.h"
   43 #include "rules.h"
   44 #include "treenodes.h"
   45 #include "util.h"
   46 #include "fpcreate.h"
   47 #include "parser.h"
   48 
   49 #include "sp_asn1.h"
   50 #include "sp_byte_check.h"
   51 #include "sp_byte_jump.h"
   52 #include "sp_byte_extract.h"
   53 #include "sp_byte_math.h"
   54 #include "sp_clientserver.h"
   55 #include "sp_cvs.h"
   56 #include "sp_dsize_check.h"
   57 #include "sp_flowbits.h"
   58 #include "sp_ftpbounce.h"
   59 #include "sp_icmp_code_check.h"
   60 #include "sp_icmp_id_check.h"
   61 #include "sp_icmp_seq_check.h"
   62 #include "sp_icmp_type_check.h"
   63 #include "sp_ip_fragbits.h"
   64 #include "sp_ip_id_check.h"
   65 #include "sp_ipoption_check.h"
   66 #include "sp_ip_proto.h"
   67 #include "sp_ip_same_check.h"
   68 #include "sp_ip_tos_check.h"
   69 #include "sp_file_data.h"
   70 #include "sp_base64_decode.h"
   71 #include "sp_isdataat.h"
   72 #include "sp_pattern_match.h"
   73 #include "sp_pcre.h"
   74 #ifdef ENABLE_REACT
   75 #include "sp_react.h"
   76 #endif
   77 #include "sp_replace.h"
   78 #ifdef ENABLE_RESPOND
   79 #include "sp_respond.h"
   80 #endif
   81 #include "sp_rpc_check.h"
   82 #include "sp_session.h"
   83 #include "sp_tcp_ack_check.h"
   84 #include "sp_tcp_flag_check.h"
   85 #include "sp_tcp_seq_check.h"
   86 #include "sp_tcp_win_check.h"
   87 #include "sp_ttl_check.h"
   88 #include "sp_urilen_check.h"
   89 #include "sp_hdr_opt_wrap.h"
   90 # include "sp_file_type.h"
   91 
   92 #include "sp_preprocopt.h"
   93 #include "sp_dynamic.h"
   94 
   95 #include "fpdetect.h"
   96 #include "ppm.h"
   97 #include "profiler.h"
   98 #include "sfPolicy.h"
   99 #include "detection_filter.h"
  100 #include "encode.h"
  101 #if defined(FEAT_OPEN_APPID)
  102 #include "stream_common.h"
  103 #include "sp_appid.h"
  104 #endif /* defined(FEAT_OPEN_APPID) */
  105 
  106 typedef struct _detection_option_key
  107 {
  108     option_type_t option_type;
  109     void *option_data;
  110 } detection_option_key_t;
  111 
  112 #define HASH_RULE_OPTIONS 16384
  113 #define HASH_RULE_TREE 8192
  114 
  115 uint32_t detection_option_hash_func(SFHASHFCN *p, unsigned char *k, int n)
  116 {
  117     uint32_t hash = 0;
  118     detection_option_key_t *key = (detection_option_key_t*)k;
  119 
  120     switch (key->option_type)
  121     {
  122         /* Call hash function specific to the key type */
  123         case RULE_OPTION_TYPE_ASN1:
  124             hash = Asn1Hash(key->option_data);
  125             break;
  126         case RULE_OPTION_TYPE_BYTE_TEST:
  127             hash = ByteTestHash(key->option_data);
  128             break;
  129         case RULE_OPTION_TYPE_BYTE_JUMP:
  130             hash = ByteJumpHash(key->option_data);
  131             break;
  132         case RULE_OPTION_TYPE_BYTE_EXTRACT:
  133             hash = ByteExtractHash(key->option_data);
  134             break;
  135         case RULE_OPTION_TYPE_BYTE_MATH:
  136             hash = ByteMathHash(key->option_data);
  137             break;
  138         case RULE_OPTION_TYPE_FLOW:
  139             hash = FlowHash(key->option_data);
  140             break;
  141         case RULE_OPTION_TYPE_CVS:
  142             hash = CvsHash(key->option_data);
  143             break;
  144         case RULE_OPTION_TYPE_DSIZE:
  145             hash = DSizeCheckHash(key->option_data);
  146             break;
  147         case RULE_OPTION_TYPE_FLOWBIT:
  148             hash = FlowBitsHash(key->option_data);
  149             break;
  150         case RULE_OPTION_TYPE_FTPBOUNCE:
  151             break;
  152         case RULE_OPTION_TYPE_FILE_DATA:
  153             hash = FileDataHash(key->option_data);
  154             break;
  155         case RULE_OPTION_TYPE_BASE64_DECODE:
  156             hash = Base64DecodeHash(key->option_data);
  157             break;
  158         case RULE_OPTION_TYPE_BASE64_DATA:
  159             break;
  160         case RULE_OPTION_TYPE_PKT_DATA:
  161             break;
  162         case RULE_OPTION_TYPE_ICMP_CODE:
  163             hash = IcmpCodeCheckHash(key->option_data);
  164             break;
  165         case RULE_OPTION_TYPE_ICMP_ID:
  166             hash = IcmpIdCheckHash(key->option_data);
  167             break;
  168         case RULE_OPTION_TYPE_ICMP_SEQ:
  169             hash = IcmpSeqCheckHash(key->option_data);
  170             break;
  171         case RULE_OPTION_TYPE_ICMP_TYPE:
  172             hash = IcmpTypeCheckHash(key->option_data);
  173             break;
  174         case RULE_OPTION_TYPE_IP_FRAGBITS:
  175             hash = IpFragBitsCheckHash(key->option_data);
  176             break;
  177         case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
  178             hash = IpFragOffsetCheckHash(key->option_data);
  179             break;
  180         case RULE_OPTION_TYPE_IP_ID:
  181             hash = IpIdCheckHash(key->option_data);
  182             break;
  183         case RULE_OPTION_TYPE_IP_OPTION:
  184             hash = IpOptionCheckHash(key->option_data);
  185             break;
  186         case RULE_OPTION_TYPE_IP_PROTO:
  187             hash = IpProtoCheckHash(key->option_data);
  188             break;
  189         case RULE_OPTION_TYPE_IP_SAME:
  190             hash = IpSameCheckHash(key->option_data);
  191             break;
  192         case RULE_OPTION_TYPE_IP_TOS:
  193             hash = IpTosCheckHash(key->option_data);
  194             break;
  195         case RULE_OPTION_TYPE_IS_DATA_AT:
  196             hash = IsDataAtHash(key->option_data);
  197             break;
  198         case RULE_OPTION_TYPE_CONTENT:
  199         case RULE_OPTION_TYPE_CONTENT_URI:
  200             hash = PatternMatchHash(key->option_data);
  201             break;
  202         case RULE_OPTION_TYPE_PCRE:
  203             hash = PcreHash(key->option_data);
  204             break;
  205 #ifdef ENABLE_REACT
  206         case RULE_OPTION_TYPE_REACT:
  207             hash = ReactHash(key->option_data);
  208             break;
  209 #endif
  210 #ifdef ENABLE_RESPOND
  211         case RULE_OPTION_TYPE_RESPOND:
  212             hash = RespondHash(key->option_data);
  213             break;
  214 #endif
  215         case RULE_OPTION_TYPE_RPC_CHECK:
  216             hash = RpcCheckHash(key->option_data);
  217             break;
  218         case RULE_OPTION_TYPE_SESSION:
  219             hash = SessionHash(key->option_data);
  220             break;
  221         case RULE_OPTION_TYPE_TCP_ACK:
  222             hash = TcpAckCheckHash(key->option_data);
  223             break;
  224         case RULE_OPTION_TYPE_TCP_FLAG:
  225             hash = TcpFlagCheckHash(key->option_data);
  226             break;
  227         case RULE_OPTION_TYPE_TCP_SEQ:
  228             hash = TcpSeqCheckHash(key->option_data);
  229             break;
  230         case RULE_OPTION_TYPE_TCP_WIN:
  231             hash = TcpWinCheckHash(key->option_data);
  232             break;
  233         case RULE_OPTION_TYPE_TTL:
  234             hash = TtlCheckHash(key->option_data);
  235             break;
  236         case RULE_OPTION_TYPE_URILEN:
  237             hash = UriLenCheckHash(key->option_data);
  238             break;
  239         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
  240             hash = HdrOptCheckHash(key->option_data);
  241             break;
  242         case RULE_OPTION_TYPE_FILE_TYPE:
  243             hash = FileTypeHash(key->option_data);
  244             break;
  245         case RULE_OPTION_TYPE_PREPROCESSOR:
  246             hash = PreprocessorRuleOptionHash(key->option_data);
  247             break;
  248         case RULE_OPTION_TYPE_DYNAMIC:
  249             hash = DynamicRuleHash(key->option_data);
  250             break;
  251         case RULE_OPTION_TYPE_LEAF_NODE:
  252             hash = 0;
  253             break;
  254 #if defined(FEAT_OPEN_APPID)
  255         case RULE_OPTION_TYPE_APPID:
  256             hash = optionAppIdHash(key->option_data);
  257             break;
  258 #endif /* defined(FEAT_OPEN_APPID) */
  259     }
  260 
  261     return hash;
  262 }
  263 
  264 int detection_option_key_compare_func(const void *k1, const void *k2, size_t n)
  265 {
  266     int ret = DETECTION_OPTION_NOT_EQUAL;
  267     const detection_option_key_t *key1 = (detection_option_key_t*)k1;
  268     const detection_option_key_t *key2 = (detection_option_key_t*)k2;
  269 
  270 #ifdef KEEP_THEM_ALLOCATED
  271     return DETECTION_OPTION_NOT_EQUAL;
  272 #endif
  273 
  274     if (!key1 || !key2)
  275         return DETECTION_OPTION_NOT_EQUAL;
  276 
  277     if (key1->option_type != key2->option_type)
  278         return DETECTION_OPTION_NOT_EQUAL;
  279 
  280     switch (key1->option_type)
  281     {
  282         /* Call compare function specific to the key type */
  283         case RULE_OPTION_TYPE_LEAF_NODE:
  284             /* Leaf node always not equal. */
  285             break;
  286         case RULE_OPTION_TYPE_ASN1:
  287             ret = Asn1Compare(key1->option_data, key2->option_data);
  288             break;
  289         case RULE_OPTION_TYPE_BYTE_TEST:
  290             ret = ByteTestCompare(key1->option_data, key2->option_data);
  291             break;
  292         case RULE_OPTION_TYPE_BYTE_JUMP:
  293             ret = ByteJumpCompare(key1->option_data, key2->option_data);
  294             break;
  295         case RULE_OPTION_TYPE_BYTE_EXTRACT:
  296             ret = ByteExtractCompare(key1->option_data, key2->option_data);
  297             break;
  298         case RULE_OPTION_TYPE_BYTE_MATH:
  299             ret = ByteMathCompare(key1->option_data, key2->option_data);
  300             break;
  301         case RULE_OPTION_TYPE_FLOW:
  302             ret = FlowCompare(key1->option_data, key2->option_data);
  303             break;
  304         case RULE_OPTION_TYPE_CVS:
  305             ret = CvsCompare(key1->option_data, key2->option_data);
  306             break;
  307         case RULE_OPTION_TYPE_DSIZE:
  308             ret = DSizeCheckCompare(key1->option_data, key2->option_data);
  309             break;
  310         case RULE_OPTION_TYPE_FLOWBIT:
  311             ret = FlowBitsCompare(key1->option_data, key2->option_data);
  312             break;
  313         case RULE_OPTION_TYPE_FTPBOUNCE:
  314             break;
  315         case RULE_OPTION_TYPE_FILE_DATA:
  316             ret = FileDataCompare(key1->option_data, key2->option_data);
  317             break;
  318         case RULE_OPTION_TYPE_BASE64_DECODE:
  319             ret = Base64DecodeCompare(key1->option_data, key2->option_data);
  320             break;
  321         case RULE_OPTION_TYPE_BASE64_DATA:
  322             break;
  323         case RULE_OPTION_TYPE_PKT_DATA:
  324             break;
  325         case RULE_OPTION_TYPE_ICMP_CODE:
  326             ret = IcmpCodeCheckCompare(key1->option_data, key2->option_data);
  327             break;
  328         case RULE_OPTION_TYPE_ICMP_ID:
  329             ret = IcmpIdCheckCompare(key1->option_data, key2->option_data);
  330             break;
  331         case RULE_OPTION_TYPE_ICMP_SEQ:
  332             ret = IcmpSeqCheckCompare(key1->option_data, key2->option_data);
  333             break;
  334         case RULE_OPTION_TYPE_ICMP_TYPE:
  335             ret = IcmpTypeCheckCompare(key1->option_data, key2->option_data);
  336             break;
  337         case RULE_OPTION_TYPE_IP_FRAGBITS:
  338             ret = IpFragBitsCheckCompare(key1->option_data, key2->option_data);
  339             break;
  340         case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
  341             ret = IpFragOffsetCheckCompare(key1->option_data, key2->option_data);
  342             break;
  343         case RULE_OPTION_TYPE_IP_ID:
  344             ret = IpIdCheckCompare(key1->option_data, key2->option_data);
  345             break;
  346         case RULE_OPTION_TYPE_IP_OPTION:
  347             ret = IpOptionCheckCompare(key1->option_data, key2->option_data);
  348             break;
  349         case RULE_OPTION_TYPE_IP_PROTO:
  350             ret = IpProtoCheckCompare(key1->option_data, key2->option_data);
  351             break;
  352         case RULE_OPTION_TYPE_IP_SAME:
  353             ret = IpSameCheckCompare(key1->option_data, key2->option_data);
  354             break;
  355         case RULE_OPTION_TYPE_IP_TOS:
  356             ret = IpTosCheckCompare(key1->option_data, key2->option_data);
  357             break;
  358         case RULE_OPTION_TYPE_IS_DATA_AT:
  359             ret = IsDataAtCompare(key1->option_data, key2->option_data);
  360             break;
  361         case RULE_OPTION_TYPE_CONTENT:
  362         case RULE_OPTION_TYPE_CONTENT_URI:
  363             ret = PatternMatchCompare(key1->option_data, key2->option_data);
  364             break;
  365         case RULE_OPTION_TYPE_PCRE:
  366             ret = PcreCompare(key1->option_data, key2->option_data);
  367             break;
  368 #ifdef ENABLE_REACT
  369         case RULE_OPTION_TYPE_REACT:
  370             ret = ReactCompare(key1->option_data, key2->option_data);
  371             break;
  372 #endif
  373 #ifdef ENABLE_RESPOND
  374         case RULE_OPTION_TYPE_RESPOND:
  375             ret = RespondCompare(key1->option_data, key2->option_data);
  376             break;
  377 #endif
  378         case RULE_OPTION_TYPE_RPC_CHECK:
  379             ret = RpcCheckCompare(key1->option_data, key2->option_data);
  380             break;
  381         case RULE_OPTION_TYPE_SESSION:
  382             ret = SessionCompare(key1->option_data, key2->option_data);
  383             break;
  384         case RULE_OPTION_TYPE_TCP_ACK:
  385             ret = TcpAckCheckCompare(key1->option_data, key2->option_data);
  386             break;
  387         case RULE_OPTION_TYPE_TCP_FLAG:
  388             ret = TcpFlagCheckCompare(key1->option_data, key2->option_data);
  389             break;
  390         case RULE_OPTION_TYPE_TCP_SEQ:
  391             ret = TcpSeqCheckCompare(key1->option_data, key2->option_data);
  392             break;
  393         case RULE_OPTION_TYPE_TCP_WIN:
  394             ret = TcpWinCheckCompare(key1->option_data, key2->option_data);
  395             break;
  396         case RULE_OPTION_TYPE_TTL:
  397             ret = TtlCheckCompare(key1->option_data, key2->option_data);
  398             break;
  399         case RULE_OPTION_TYPE_URILEN:
  400             ret = UriLenCheckCompare(key1->option_data, key2->option_data);
  401             break;
  402         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
  403             ret = HdrOptCheckCompare(key1->option_data, key2->option_data);
  404             break;
  405         case RULE_OPTION_TYPE_FILE_TYPE:
  406             ret = FileTypeCompare(key1->option_data, key2->option_data);
  407             break;
  408         case RULE_OPTION_TYPE_PREPROCESSOR:
  409             ret = PreprocessorRuleOptionCompare(key1->option_data, key2->option_data);
  410             break;
  411         case RULE_OPTION_TYPE_DYNAMIC:
  412             ret = DynamicRuleCompare(key1->option_data, key2->option_data);
  413             break;
  414 #if defined(FEAT_OPEN_APPID)
  415         case RULE_OPTION_TYPE_APPID:
  416             ret = optionAppIdCompare(key1->option_data, key2->option_data);
  417             break;
  418 #endif /* defined(FEAT_OPEN_APPID) */
  419     }
  420 
  421     return ret;
  422 }
  423 
  424 int detection_hash_free_func(void *option_key, void *data)
  425 {
  426     detection_option_key_t *key = (detection_option_key_t*)option_key;
  427 
  428     switch (key->option_type)
  429     {
  430         /* Call free function specific to the key type */
  431         case RULE_OPTION_TYPE_ASN1:
  432             free(key->option_data);
  433             break;
  434         case RULE_OPTION_TYPE_BYTE_TEST:
  435             free(key->option_data);
  436             break;
  437         case RULE_OPTION_TYPE_BYTE_JUMP:
  438             free(key->option_data);
  439             break;
  440         case RULE_OPTION_TYPE_BYTE_EXTRACT:
  441             ByteExtractFree(key->option_data);
  442             break;
  443         case RULE_OPTION_TYPE_BYTE_MATH:
  444             ByteMathFree(key->option_data);
  445             break;
  446         case RULE_OPTION_TYPE_FLOW:
  447             free(key->option_data);
  448             break;
  449         case RULE_OPTION_TYPE_CVS:
  450             free(key->option_data);
  451             break;
  452         case RULE_OPTION_TYPE_DSIZE:
  453             free(key->option_data);
  454             break;
  455         case RULE_OPTION_TYPE_FLOWBIT:
  456             FlowBitsFree(key->option_data);
  457             break;
  458         case RULE_OPTION_TYPE_FTPBOUNCE:
  459             /* Data is NULL, nothing to free */
  460             break;
  461         case RULE_OPTION_TYPE_FILE_DATA:
  462             free(key->option_data);
  463             break;
  464         case RULE_OPTION_TYPE_BASE64_DECODE:
  465             free(key->option_data);
  466             break;
  467         case RULE_OPTION_TYPE_BASE64_DATA:
  468             break;
  469         case RULE_OPTION_TYPE_PKT_DATA:
  470             break;
  471         case RULE_OPTION_TYPE_ICMP_CODE:
  472             free(key->option_data);
  473             break;
  474         case RULE_OPTION_TYPE_ICMP_ID:
  475             free(key->option_data);
  476             break;
  477         case RULE_OPTION_TYPE_ICMP_SEQ:
  478             free(key->option_data);
  479             break;
  480         case RULE_OPTION_TYPE_ICMP_TYPE:
  481             free(key->option_data);
  482             break;
  483         case RULE_OPTION_TYPE_IP_FRAGBITS:
  484             free(key->option_data);
  485             break;
  486         case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
  487             free(key->option_data);
  488             break;
  489         case RULE_OPTION_TYPE_IP_ID:
  490             free(key->option_data);
  491             break;
  492         case RULE_OPTION_TYPE_IP_OPTION:
  493             free(key->option_data);
  494             break;
  495         case RULE_OPTION_TYPE_IP_PROTO:
  496             free(key->option_data);
  497             break;
  498         case RULE_OPTION_TYPE_IP_SAME:
  499             /* Data is NULL, nothing to free */
  500             break;
  501         case RULE_OPTION_TYPE_IP_TOS:
  502             free(key->option_data);
  503             break;
  504         case RULE_OPTION_TYPE_IS_DATA_AT:
  505             free(key->option_data);
  506             break;
  507         case RULE_OPTION_TYPE_CONTENT:
  508         case RULE_OPTION_TYPE_CONTENT_URI:
  509             PatternMatchFree(key->option_data);
  510             break;
  511         case RULE_OPTION_TYPE_PCRE:
  512             PcreFree(key->option_data);
  513             break;
  514 #ifdef ENABLE_REACT
  515         case RULE_OPTION_TYPE_REACT:
  516             ReactFree(key->option_data);
  517             break;
  518 #endif
  519 #ifdef ENABLE_RESPOND
  520         case RULE_OPTION_TYPE_RESPOND:
  521             free(key->option_data);
  522             break;
  523 #endif
  524         case RULE_OPTION_TYPE_RPC_CHECK:
  525             free(key->option_data);
  526             break;
  527         case RULE_OPTION_TYPE_SESSION:
  528             free(key->option_data);
  529             break;
  530         case RULE_OPTION_TYPE_TCP_ACK:
  531             free(key->option_data);
  532             break;
  533         case RULE_OPTION_TYPE_TCP_FLAG:
  534             free(key->option_data);
  535             break;
  536         case RULE_OPTION_TYPE_TCP_SEQ:
  537             free(key->option_data);
  538             break;
  539         case RULE_OPTION_TYPE_TCP_WIN:
  540             free(key->option_data);
  541             break;
  542         case RULE_OPTION_TYPE_TTL:
  543             free(key->option_data);
  544             break;
  545         case RULE_OPTION_TYPE_URILEN:
  546             free(key->option_data);
  547             break;
  548         case RULE_OPTION_TYPE_HDR_OPT_CHECK:
  549             break;
  550         case RULE_OPTION_TYPE_FILE_TYPE:
  551             FileTypeFree(key->option_data);
  552             break;
  553         case RULE_OPTION_TYPE_PREPROCESSOR:
  554             PreprocessorRuleOptionsFreeFunc(key->option_data);
  555             break;
  556         case RULE_OPTION_TYPE_DYNAMIC:
  557             fpDynamicDataFree(key->option_data);
  558             break;
  559         case RULE_OPTION_TYPE_LEAF_NODE:
  560             break;
  561 #if defined(FEAT_OPEN_APPID)
  562         case RULE_OPTION_TYPE_APPID:
  563             optionAppIdFree(key->option_data);
  564             break;
  565 #endif /* defined(FEAT_OPEN_APPID) */
  566     }
  567     return 0;
  568 }
  569 
  570 SFXHASH * DetectionHashTableNew(void)
  571 {
  572     SFXHASH *doht = sfxhash_new(HASH_RULE_OPTIONS,
  573                                 sizeof(detection_option_key_t),
  574                                 0,      /* Data size == 0, just store the ptr */
  575                                 0,      /* Memcap */
  576                                 0,      /* Auto node recovery */
  577                                 NULL,   /* Auto free function */
  578                                 detection_hash_free_func,   /* User free function */
  579                                 1);     /* Recycle nodes */
  580 
  581 
  582     if (doht == NULL)
  583         FatalError("Failed to create rule detection option hash table");
  584 
  585     sfxhash_set_keyops(doht, detection_option_hash_func,
  586                        detection_option_key_compare_func);
  587 
  588     return doht;
  589 }
  590 
  591 void DetectionHashTableFree(SFXHASH *doht)
  592 {
  593     if (doht != NULL)
  594         sfxhash_delete(doht);
  595 }
  596 
  597 int add_detection_option(struct _SnortConfig *sc, option_type_t type, void *option_data, void **existing_data)
  598 {
  599     detection_option_key_t key;
  600 
  601     if (sc == NULL)
  602     {
  603         FatalError("%s(%d) Snort config is NULL.\n",
  604                    __FILE__, __LINE__);
  605     }
  606 
  607     if (sc->detection_option_hash_table == NULL)
  608         sc->detection_option_hash_table = DetectionHashTableNew();
  609 
  610     if (!option_data)
  611     {
  612         /* No option data, no conflict to resolve. */
  613         return DETECTION_OPTION_EQUAL;
  614     }
  615 
  616     key.option_type = type;
  617     key.option_data = option_data;
  618 
  619     *existing_data = sfxhash_find(sc->detection_option_hash_table, &key);
  620     if (*existing_data)
  621     {
  622         return DETECTION_OPTION_EQUAL;
  623     }
  624 
  625     sfxhash_add(sc->detection_option_hash_table, &key, option_data);
  626     return DETECTION_OPTION_NOT_EQUAL;
  627 }
  628 
  629 uint32_t detection_option_tree_hash(detection_option_tree_node_t *node)
  630 {
  631     uint32_t a,b,c;
  632     int i;
  633 
  634     if (!node)
  635         return 0;
  636 
  637     a = b = c = 0;
  638 
  639     for (i=0;i<node->num_children;i++)
  640     {
  641 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
  642         {
  643             /* Cleanup warning because of cast from 64bit ptr to 32bit int
  644              * warning on 64bit OSs */
  645             uint64_t ptr; /* Addresses are 64bits */
  646             ptr = (uint64_t)node->children[i]->option_data;
  647             a += (ptr >> 32);
  648             b += (ptr & 0xFFFFFFFF);
  649         }
  650 #else
  651         a += (uint32_t)node->children[i]->option_data;
  652         b += 0;
  653 #endif
  654         c += detection_option_tree_hash(node->children[i]);
  655         mix(a,b,c);
  656         a += node->children[i]->num_children;
  657         mix(a,b,c);
  658 #if 0
  659         a += (uint32_t)node->children[i]->option_data;
  660         /* Recurse & hash up this guy's children */
  661         b += detection_option_tree_hash(node->children[i]);
  662         c += node->children[i]->num_children;
  663         mix(a,b,c);
  664 #endif
  665     }
  666 
  667     final(a,b,c);
  668 
  669     return c;
  670 }
  671 
  672 uint32_t detection_option_tree_hash_func(SFHASHFCN *p, unsigned char *k, int n)
  673 {
  674     detection_option_key_t *key = (detection_option_key_t *)k;
  675     detection_option_tree_node_t *node;
  676 
  677     if (!key || !key->option_data)
  678         return 0;
  679 
  680     node = (detection_option_tree_node_t*)key->option_data;
  681 
  682     return detection_option_tree_hash(node);
  683 }
  684 
  685 int detection_option_tree_compare(detection_option_tree_node_t *r, detection_option_tree_node_t *l)
  686 {
  687     int ret = DETECTION_OPTION_NOT_EQUAL;
  688     int i;
  689 
  690     if ((r == NULL) && (l == NULL))
  691         return DETECTION_OPTION_EQUAL;
  692 
  693     if ((!r && l) || (r && !l))
  694         return DETECTION_OPTION_NOT_EQUAL;
  695 
  696     if (r->option_data != l->option_data)
  697         return DETECTION_OPTION_NOT_EQUAL;
  698 
  699     if (r->num_children != l->num_children)
  700         return DETECTION_OPTION_NOT_EQUAL;
  701 
  702     for (i=0;i<r->num_children;i++)
  703     {
  704         /* Recurse & check the children for equality */
  705         ret = detection_option_tree_compare(r->children[i], l->children[i]);
  706         if (ret != DETECTION_OPTION_EQUAL)
  707             return ret;
  708     }
  709 
  710     return DETECTION_OPTION_EQUAL;
  711 }
  712 
  713 int detection_option_tree_compare_func(const void *k1, const void *k2, size_t n)
  714 {
  715     detection_option_key_t *key_r = (detection_option_key_t *)k1;
  716     detection_option_key_t *key_l = (detection_option_key_t *)k2;
  717     detection_option_tree_node_t *r;
  718     detection_option_tree_node_t *l;
  719 
  720     if (!key_r || !key_l)
  721         return DETECTION_OPTION_NOT_EQUAL;
  722 
  723     r = (detection_option_tree_node_t *)key_r->option_data;
  724     l = (detection_option_tree_node_t *)key_l->option_data;
  725 
  726     return detection_option_tree_compare(r, l);
  727 }
  728 
  729 int detection_option_tree_free_func(void *option_key, void *data)
  730 {
  731     detection_option_tree_node_t *node = (detection_option_tree_node_t *)data;
  732     /* In fpcreate.c */
  733     free_detection_option_tree(node);
  734     return 0;
  735 }
  736 
  737 void DetectionTreeHashTableFree(SFXHASH *dtht)
  738 {
  739     if (dtht != NULL)
  740         sfxhash_delete(dtht);
  741 }
  742 
  743 SFXHASH * DetectionTreeHashTableNew(void)
  744 {
  745     SFXHASH *dtht = sfxhash_new(HASH_RULE_TREE,
  746                                 sizeof(detection_option_key_t),
  747                                 0,      /* Data size == 0, just store the ptr */
  748                                 0,      /* Memcap */
  749                                 0,      /* Auto node recovery */
  750                                 NULL,   /* Auto free function */
  751                                 detection_option_tree_free_func,   /* User free function */
  752                                 1);     /* Recycle nodes */
  753 
  754 
  755     if (dtht == NULL)
  756         FatalError("Failed to create rule detection option hash table");
  757 
  758     sfxhash_set_keyops(dtht, detection_option_tree_hash_func,
  759                        detection_option_tree_compare_func);
  760 
  761     return dtht;
  762 }
  763 
  764 char *option_type_str[] =
  765 {
  766     "RULE_OPTION_TYPE_LEAF_NODE",
  767     "RULE_OPTION_TYPE_ASN1",
  768     "RULE_OPTION_TYPE_BYTE_TEST",
  769     "RULE_OPTION_TYPE_BYTE_JUMP",
  770     "RULE_OPTION_TYPE_BYTE_EXTRACT",
  771     "RULE_OPTION_TYPE_FLOW",
  772     "RULE_OPTION_TYPE_CVS",
  773     "RULE_OPTION_TYPE_DSIZE",
  774     "RULE_OPTION_TYPE_FLOWBIT",
  775     "RULE_OPTION_TYPE_FTPBOUNCE",
  776     "RULE_OPTION_TYPE_ICMP_CODE",
  777     "RULE_OPTION_TYPE_ICMP_ID",
  778     "RULE_OPTION_TYPE_ICMP_SEQ",
  779     "RULE_OPTION_TYPE_ICMP_TYPE",
  780     "RULE_OPTION_TYPE_IP_FRAGBITS",
  781     "RULE_OPTION_TYPE_IP_FRAG_OFFSET",
  782     "RULE_OPTION_TYPE_IP_ID",
  783     "RULE_OPTION_TYPE_IP_OPTION",
  784     "RULE_OPTION_TYPE_IP_PROTO",
  785     "RULE_OPTION_TYPE_IP_SAME",
  786     "RULE_OPTION_TYPE_IP_TOS",
  787     "RULE_OPTION_TYPE_IS_DATA_AT",
  788     "RULE_OPTION_TYPE_FILE_DATA",
  789     "RULE_OPTION_TYPE_FILE_TYPE",
  790     "RULE_OPTION_TYPE_BASE64_DECODE",
  791     "RULE_OPTION_TYPE_BASE64_DATA",
  792     "RULE_OPTION_TYPE_PKT_DATA",
  793     "RULE_OPTION_TYPE_CONTENT",
  794     "RULE_OPTION_TYPE_CONTENT_URI",
  795     "RULE_OPTION_TYPE_PCRE",
  796 #ifdef ENABLE_REACT
  797     "RULE_OPTION_TYPE_REACT",
  798 #endif
  799 #ifdef ENABLE_RESPOND
  800     "RULE_OPTION_TYPE_RESPOND",
  801 #endif
  802     "RULE_OPTION_TYPE_RPC_CHECK",
  803     "RULE_OPTION_TYPE_SESSION",
  804     "RULE_OPTION_TYPE_TCP_ACK",
  805     "RULE_OPTION_TYPE_TCP_FLAG",
  806     "RULE_OPTION_TYPE_TCP_SEQ",
  807     "RULE_OPTION_TYPE_TCP_WIN",
  808     "RULE_OPTION_TYPE_TTL",
  809     "RULE_OPTION_TYPE_URILEN",
  810     "RULE_OPTION_TYPE_HDR_OPT_CHECK",
  811     "RULE_OPTION_TYPE_PREPROCESSOR",
  812     "RULE_OPTION_TYPE_DYNAMIC"
  813 #if defined(FEAT_OPEN_APPID)
  814     ,"RULE_OPTION_TYPE_APPID"
  815 #endif /* defined(FEAT_OPEN_APPID) */
  816     ,"RULE_OPTION_TYPE_BYTE_MATH"
  817 };
  818 
  819 #ifdef DEBUG_OPTION_TREE
  820 void print_option_tree(detection_option_tree_node_t *node, int level)
  821 {
  822     int i;
  823     unsigned int indent = 12 - (11 - level) + strlen(option_type_str[node->option_type]);
  824     unsigned int offset = 0;
  825     if (level >= 10)
  826         offset++;
  827 
  828     DEBUG_WRAP(
  829         DebugMessage(DEBUG_DETECT, "%d%*s%*d 0x%x\n",
  830            level, indent - offset, option_type_str[node->option_type],
  831            54 - indent, node->num_children,
  832            node->option_data);
  833         for (i=0;i<node->num_children;i++)
  834             print_option_tree(node->children[i], level+1);
  835     );
  836 }
  837 #endif
  838 
  839 int add_detection_option_tree(SnortConfig *sc, detection_option_tree_node_t *option_tree, void **existing_data)
  840 {
  841     detection_option_key_t key;
  842 
  843     if (sc == NULL)
  844     {
  845         FatalError("%s(%d) Snort config for parsing is NULL.\n",
  846                    __FILE__, __LINE__);
  847     }
  848 
  849     if (sc->detection_option_tree_hash_table == NULL)
  850         sc->detection_option_tree_hash_table = DetectionTreeHashTableNew();
  851 
  852     if (!option_tree)
  853     {
  854         /* No option data, no conflict to resolve. */
  855         return DETECTION_OPTION_EQUAL;
  856     }
  857 
  858     key.option_data = (void *)option_tree;
  859     key.option_type = RULE_OPTION_TYPE_LEAF_NODE;
  860 
  861     *existing_data = sfxhash_find(sc->detection_option_tree_hash_table, &key);
  862     if (*existing_data)
  863     {
  864         return DETECTION_OPTION_EQUAL;
  865     }
  866 
  867     sfxhash_add(sc->detection_option_tree_hash_table, &key, option_tree);
  868     return DETECTION_OPTION_NOT_EQUAL;
  869 }
  870 
  871 
  872 uint64_t rule_eval_pkt_count = 0;
  873 
  874 /* Include "detection_leaf_node.c"
  875  *
  876  * Service matches, toggles 'check_ports' and then evaluation
  877  * of the leaf nodes (ie. the rule header stuffs).
  878  *
  879  * This defines the routine "detection_leaf_node_eval($,$)" which
  880  * is called from the switch case RULE_OPTION_TYPE_LEAF_NODE below.
  881  */
  882 #include "detection_leaf_node.c"
  883 
  884 int detection_option_node_evaluate(detection_option_tree_node_t *node, detection_option_eval_data_t *eval_data)
  885 {
  886     int i, result = 0, prior_result = 0;
  887     int rval = DETECTION_OPTION_NO_MATCH;
  888     const uint8_t *orig_doe_ptr;
  889     char tmp_noalert_flag = 0;
  890     PatternMatchData dup_content_option_data;
  891     PcreData dup_pcre_option_data;
  892     const uint8_t *dp = NULL;
  893     char continue_loop = 1;
  894     char flowbits_setoperation = 0;
  895     int loop_count = 0;
  896     uint32_t tmp_byte_extract_vars[NUM_BYTE_EXTRACT_VARS];
  897     uint16_t save_dflags = 0;
  898     uint64_t cur_eval_pkt_count = (rule_eval_pkt_count + (GetRebuiltPktCount()));
  899     NODE_PROFILE_VARS;
  900 
  901     if (!node || !eval_data || !eval_data->p || !eval_data->pomd)
  902         return 0;
  903 
  904     save_dflags = Get_DetectFlags();
  905 
  906     /* see if evaluated it before ... */
  907     if (node->last_check.is_relative == 0)
  908     {
  909         /* Only matters if not relative... */
  910         if ((node->last_check.ts.tv_usec == eval_data->p->pkth->ts.tv_usec) &&
  911             (node->last_check.ts.tv_sec == eval_data->p->pkth->ts.tv_sec) &&
  912             (node->last_check.packet_number == cur_eval_pkt_count) &&
  913             (node->last_check.rebuild_flag == (eval_data->p->packet_flags & PKT_REBUILT_STREAM)) &&
  914             (!(eval_data->p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT)))
  915         {
  916             /* eval'd this rule option before on this packet,
  917              * use the cached result. */
  918             if ((node->last_check.flowbit_failed == 0) &&
  919                 !(eval_data->p->packet_flags & PKT_IP_RULE_2ND) &&
  920                 !(eval_data->p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP )))
  921             {
  922                 return node->last_check.result;
  923             }
  924         }
  925     }
  926 
  927     NODE_PROFILE_START(node);
  928 
  929     node->last_check.ts.tv_sec = eval_data->p->pkth->ts.tv_sec;
  930     node->last_check.ts.tv_usec = eval_data->p->pkth->ts.tv_usec;
  931     node->last_check.packet_number = cur_eval_pkt_count;
  932     node->last_check.rebuild_flag = (eval_data->p->packet_flags & PKT_REBUILT_STREAM);
  933     node->last_check.flowbit_failed = 0;
  934 
  935     /* Save some stuff off for repeated pattern tests */
  936     orig_doe_ptr = doe_ptr;
  937 
  938     if ((node->option_type == RULE_OPTION_TYPE_CONTENT) ||
  939             (node->option_type == RULE_OPTION_TYPE_CONTENT_URI))
  940     {
  941         PatternMatchDuplicatePmd(node->option_data, &dup_content_option_data);
  942 
  943         if (dup_content_option_data.buffer_func == CHECK_URI_PATTERN_MATCH)
  944         {
  945             const HttpBuffer* hb = GetHttpBuffer(dup_content_option_data.http_buffer);
  946             dp = hb ? hb->buf : NULL;  // FIXTHIS set length too
  947         }
  948         else if (dup_content_option_data.rawbytes == 0)
  949         {
  950             /* If AltDetect is set by calling the rule options which set it,
  951              * we should use the Alt Detect before checking for any other buffers.
  952              * Alt Detect will take precedence over the Alt Decode and/or packet data.
  953              */
  954             if(Is_DetectFlag(FLAG_ALT_DETECT))
  955                 dp = DetectBuffer.data;
  956             else if(Is_DetectFlag(FLAG_ALT_DECODE))
  957                 dp = (uint8_t *)DecodeBuffer.data;
  958             else
  959                 dp = eval_data->p->data;
  960         }
  961         else
  962         {
  963             dp = eval_data->p->data;
  964         }
  965     }
  966     else if (node->option_type == RULE_OPTION_TYPE_PCRE)
  967     {
  968         unsigned hb_type;
  969         PcreDuplicatePcreData(node->option_data, &dup_pcre_option_data);
  970         hb_type = dup_pcre_option_data.options & SNORT_PCRE_HTTP_BUFS;
  971 
  972         if ( hb_type )
  973         {
  974             const HttpBuffer* hb = GetHttpBuffer(hb_type);
  975             dp = hb ? hb->buf : NULL;  // FIXTHIS set length too
  976         }
  977         else if (!(dup_pcre_option_data.options & SNORT_PCRE_RAWBYTES))
  978         {
  979             /* If AltDetect is set by calling the rule options which set it,
  980              * we should use the Alt Detect before checking for any other buffers.
  981              * Alt Detect will take precedence over the Alt Decode and/or packet data.
  982              */
  983             if(Is_DetectFlag(FLAG_ALT_DETECT))
  984                 dp = DetectBuffer.data;
  985             else if(Is_DetectFlag(FLAG_ALT_DECODE))
  986                 dp = (uint8_t *)DecodeBuffer.data;
  987             else
  988                 dp = eval_data->p->data;
  989         }
  990         else
  991         {
  992             dp = eval_data->p->data;
  993         }
  994     }
  995 
  996     /* No, haven't evaluated this one before... Check it. */
  997     do
  998     {
  999         switch (node->option_type)
 1000         {
 1001             case RULE_OPTION_TYPE_LEAF_NODE:
 1002                 /* Add the match for this otn to the queue. */
 1003                 {
 1004                     int pattern_size    = 0;
 1005                     int eval_rtn_result = 1;
 1006                     int check_ports     = 1;
 1007                     OptTreeNode *otn = (OptTreeNode*) node->option_data;
 1008                     PatternMatchData *pmd = (PatternMatchData*) eval_data->pmd;
 1009 
 1010                     if (pmd) 
 1011                         pattern_size = pmd->pattern_size;
 1012 
 1013                     // See "detection_leaf_node.c" (detection_leaf_node_eval).
 1014 #ifdef TARGET_BASED
 1015                     switch (detection_leaf_node_eval (node, eval_data))
 1016                     {
 1017                         case Leaf_Abort:
 1018                             eval_rtn_result = 0;
 1019                             break;
 1020 
 1021                         case Leaf_SkipPorts:
 1022                             check_ports = 0;
 1023                             // fall through
 1024 
 1025                         case Leaf_CheckPorts:
 1026                             NODE_PROFILE_TMPEND(node);
 1027                             eval_rtn_result = fpEvalRTN (getRuntimeRtnFromOtn (otn), eval_data->p, check_ports);
 1028                             NODE_PROFILE_TMPSTART(node);
 1029                             break;
 1030                     }
 1031 #endif
 1032 
 1033                     if (eval_rtn_result)
 1034                     {
 1035                 if ((!otn->detection_filter) ||
 1036                                  !detection_filter_test(
 1037                                  otn->detection_filter,
 1038                                  GET_SRC_IP(eval_data->p), GET_DST_IP(eval_data->p),
 1039                                  eval_data->p->pkth->ts.tv_sec, eval_data))
 1040                         {
 1041 #ifdef PERF_PROFILING
 1042                             if (PROFILING_RULES)
 1043                                 otn->matches++;
 1044 #endif
 1045                             if (!eval_data->flowbit_noalert)
 1046                             {
 1047                                 fpAddMatch(eval_data->pomd, pattern_size, otn);
 1048                             }
 1049                             result = rval = DETECTION_OPTION_MATCH;
 1050                         }
 1051                     }
 1052                 }
 1053                 break;
 1054 
 1055             case RULE_OPTION_TYPE_CONTENT:
 1056                 if (node->evaluate)
 1057                 {
 1058                     /* This will be set in the fast pattern matcher if we found
 1059                      * a content and the rule option specifies not that
 1060                      * content. Essentially we've already evaluated this rule
 1061                      * option via the content option processing since only not
 1062                      * contents that are not relative in any way will have this
 1063                      * flag set */
 1064                     if (dup_content_option_data.exception_flag)
 1065                     {
 1066                         if ((dup_content_option_data.last_check.ts.tv_sec == eval_data->p->pkth->ts.tv_sec) &&
 1067                             (dup_content_option_data.last_check.ts.tv_usec == eval_data->p->pkth->ts.tv_usec) &&
 1068                             (dup_content_option_data.last_check.packet_number == cur_eval_pkt_count) &&
 1069                             (dup_content_option_data.last_check.rebuild_flag == (eval_data->p->packet_flags & PKT_REBUILT_STREAM)))
 1070                         {
 1071                             rval = DETECTION_OPTION_NO_MATCH;
 1072                             break;
 1073                         }
 1074                     }
 1075 
 1076                     rval = node->evaluate(&dup_content_option_data, eval_data->p);
 1077                 }
 1078                 break;
 1079             case RULE_OPTION_TYPE_CONTENT_URI:
 1080                 if (node->evaluate)
 1081                 {
 1082                     rval = node->evaluate(&dup_content_option_data, eval_data->p);
 1083                 }
 1084                 break;
 1085             case RULE_OPTION_TYPE_PCRE:
 1086                 if (node->evaluate)
 1087                 {
 1088                     rval = node->evaluate(&dup_pcre_option_data, eval_data->p);
 1089                 }
 1090                 break;
 1091             case RULE_OPTION_TYPE_PKT_DATA:
 1092             case RULE_OPTION_TYPE_FILE_DATA:
 1093             case RULE_OPTION_TYPE_BASE64_DATA:
 1094                 if (node->evaluate)
 1095                 {
 1096                     save_dflags = Get_DetectFlags();
 1097                     rval = node->evaluate(node->option_data, eval_data->p);
 1098                 }
 1099                 break;
 1100             case RULE_OPTION_TYPE_FLOWBIT:
 1101                 if (node->evaluate)
 1102                 {
 1103                     flowbits_setoperation = FlowBits_SetOperation(node->option_data);
 1104                     if (!flowbits_setoperation)
 1105                     {
 1106                         rval = node->evaluate(node->option_data, eval_data->p);
 1107                     }
 1108                     else
 1109                     {
 1110                         /* set to match so we don't bail early.  */
 1111                         rval = DETECTION_OPTION_MATCH;
 1112                     }
 1113                 }
 1114                 break;
 1115             case RULE_OPTION_TYPE_ASN1:
 1116             case RULE_OPTION_TYPE_BYTE_TEST:
 1117             case RULE_OPTION_TYPE_BYTE_JUMP:
 1118             case RULE_OPTION_TYPE_BYTE_EXTRACT:
 1119             case RULE_OPTION_TYPE_BYTE_MATH:
 1120             case RULE_OPTION_TYPE_FLOW:
 1121             case RULE_OPTION_TYPE_CVS:
 1122             case RULE_OPTION_TYPE_DSIZE:
 1123             case RULE_OPTION_TYPE_FTPBOUNCE:
 1124             case RULE_OPTION_TYPE_BASE64_DECODE:
 1125             case RULE_OPTION_TYPE_ICMP_CODE:
 1126             case RULE_OPTION_TYPE_ICMP_ID:
 1127             case RULE_OPTION_TYPE_ICMP_SEQ:
 1128             case RULE_OPTION_TYPE_ICMP_TYPE:
 1129             case RULE_OPTION_TYPE_IP_FRAGBITS:
 1130             case RULE_OPTION_TYPE_IP_FRAG_OFFSET:
 1131             case RULE_OPTION_TYPE_IP_ID:
 1132             case RULE_OPTION_TYPE_IP_OPTION:
 1133             case RULE_OPTION_TYPE_IP_PROTO:
 1134             case RULE_OPTION_TYPE_IP_SAME:
 1135             case RULE_OPTION_TYPE_IP_TOS:
 1136             case RULE_OPTION_TYPE_IS_DATA_AT:
 1137 #ifdef ENABLE_REACT
 1138             case RULE_OPTION_TYPE_REACT:
 1139 #endif
 1140 #ifdef ENABLE_RESPOND
 1141             case RULE_OPTION_TYPE_RESPOND:
 1142 #endif
 1143             case RULE_OPTION_TYPE_RPC_CHECK:
 1144             case RULE_OPTION_TYPE_SESSION:
 1145             case RULE_OPTION_TYPE_TCP_ACK:
 1146             case RULE_OPTION_TYPE_TCP_FLAG:
 1147             case RULE_OPTION_TYPE_TCP_SEQ:
 1148             case RULE_OPTION_TYPE_TCP_WIN:
 1149             case RULE_OPTION_TYPE_TTL:
 1150             case RULE_OPTION_TYPE_URILEN:
 1151             case RULE_OPTION_TYPE_HDR_OPT_CHECK:
 1152             case RULE_OPTION_TYPE_FILE_TYPE:
 1153             case RULE_OPTION_TYPE_PREPROCESSOR:
 1154                 if (node->evaluate)
 1155                     rval = node->evaluate(node->option_data, eval_data->p);
 1156                 break;
 1157             case RULE_OPTION_TYPE_DYNAMIC:
 1158                 if (node->evaluate)
 1159                     rval = node->evaluate(node->option_data, eval_data->p);
 1160                 break;
 1161 #if defined(FEAT_OPEN_APPID)
 1162             case RULE_OPTION_TYPE_APPID:
 1163                 if (node->evaluate)
 1164                     rval = node->evaluate(node->option_data, eval_data->p);
 1165                 break;
 1166 #endif /* defined(FEAT_OPEN_APPID) */
 1167         }
 1168 
 1169         if (rval == DETECTION_OPTION_NO_MATCH)
 1170         {
 1171             node->last_check.result = result;
 1172             NODE_PROFILE_END_NOMATCH(node);
 1173             return result;
 1174         }
 1175         else if (rval == DETECTION_OPTION_FAILED_BIT)
 1176         {
 1177             eval_data->flowbit_failed = 1;
 1178             /* clear the timestamp so failed flowbit gets eval'd again */
 1179             node->last_check.flowbit_failed = 1;
 1180             node->last_check.result = result;
 1181             NODE_PROFILE_END_NOMATCH(node);
 1182             return 0;
 1183         }
 1184         else if (rval == DETECTION_OPTION_NO_ALERT)
 1185         {
 1186             /* Cache the current flowbit_noalert flag, and set it
 1187              * so nodes below this don't alert. */
 1188             tmp_noalert_flag = eval_data->flowbit_noalert;
 1189             eval_data->flowbit_noalert = 1;
 1190         }
 1191 
 1192         /* Back up byte_extract vars so they don't get overwritten between rules */
 1193         for (i = 0; i < NUM_BYTE_EXTRACT_VARS; i++)
 1194         {
 1195             GetByteExtractValue(&(tmp_byte_extract_vars[i]), (int8_t)i);
 1196         }
 1197 
 1198 #ifdef PPM_MGR
 1199         if( PPM_PKTS_ENABLED() )
 1200         {
 1201             PPM_GET_TIME();
 1202             PPM_PACKET_TEST();
 1203             if( PPM_PACKET_ABORT_FLAG() )
 1204             {
 1205                 /* bail if we exceeded time */
 1206                 if (result == DETECTION_OPTION_NO_MATCH)
 1207                 {
 1208                     NODE_PROFILE_END_NOMATCH(node);
 1209                 }
 1210                 else
 1211                 {
 1212                     NODE_PROFILE_END_MATCH(node);
 1213                 }
 1214                 node->last_check.result = result;
 1215                 Reset_DetectFlags(save_dflags);
 1216                 return result;
 1217             }
 1218         }
 1219 #endif
 1220         /* Don't include children's time in this node */
 1221         NODE_PROFILE_TMPEND(node);
 1222 
 1223         /* Passed, check the children. */
 1224         if (node->num_children)
 1225         {
 1226             const uint8_t *tmp_doe_ptr = doe_ptr;
 1227             const uint8_t tmp_doe_flags = doe_buf_flags;
 1228 
 1229             for (i=0;i<node->num_children; i++)
 1230             {
 1231                 int j = 0;
 1232                 detection_option_tree_node_t *child_node = node->children[i];
 1233 
 1234                 /* reset the DOE ptr for each child from here */
 1235                 SetDoePtr(tmp_doe_ptr, tmp_doe_flags);
 1236 
 1237                 for (j = 0; j < NUM_BYTE_EXTRACT_VARS; j++)
 1238                 {
 1239                     SetByteExtractValue(tmp_byte_extract_vars[j], (int8_t)j);
 1240                 }
 1241 
 1242                 if (loop_count > 0)
 1243                 {
 1244                     if (child_node->result == DETECTION_OPTION_NO_MATCH)
 1245                     {
 1246                         if (((child_node->option_type == RULE_OPTION_TYPE_CONTENT)
 1247                                     || (child_node->option_type == RULE_OPTION_TYPE_PCRE))
 1248                                 && !child_node->last_check.is_relative)
 1249                         {
 1250                             /* If it's a non-relative content or pcre, no reason
 1251                              * to check again.  Only increment result once.
 1252                              * Should hit this condition on first loop iteration. */
 1253                             if (loop_count == 1)
 1254                                 result++;
 1255                             continue;
 1256                         }
 1257                         else if ((child_node->option_type == RULE_OPTION_TYPE_CONTENT)
 1258                                 && child_node->last_check.is_relative)
 1259                         {
 1260                             PatternMatchData *pmd = (PatternMatchData *)child_node->option_data;
 1261 
 1262                             /* Check for an unbounded relative search.  If this
 1263                              * failed before, it's going to fail again so don't
 1264                              * go down this path again 
 1265                              * Check for protected pattern because in this case 
 1266                              * we had checked for 'n'bytes only where 'n' is the 
 1267                              * length of protected pattern.
 1268                              * */
 1269                             if (pmd->within == PMD_WITHIN_UNDEFINED && !pmd->protected_pattern)
 1270                             {
 1271                                 /* Only increment result once. Should hit this
 1272                                  * condition on first loop iteration. */
 1273                                 if (loop_count == 1)
 1274                                     result++;
 1275                                 continue;
 1276                             }
 1277                         }
 1278                     }
 1279                     else if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
 1280                     {
 1281                         /* Leaf node matched, don't eval again */
 1282                         continue;
 1283                     }
 1284                     else if (child_node->result == child_node->num_children)
 1285                     {
 1286                         /* This branch of the tree matched or has options that
 1287                          * don't need to be evaluated again, so don't need to
 1288                          * evaluate this option again */
 1289                         continue;
 1290                     }
 1291                 }
 1292 
 1293                 child_node->result = detection_option_node_evaluate(node->children[i], eval_data);
 1294                 if (child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
 1295                 {
 1296                     /* Leaf node won't have any children but will return success
 1297                      * or failure; regardless we must count them here */ 
 1298                     result += 1;
 1299                 }
 1300                 else if (child_node->result == child_node->num_children)
 1301                 {
 1302                     /* Indicate that the child's tree branches are done */
 1303                     result++;
 1304                 }
 1305 #ifdef PPM_MGR
 1306                 if( PPM_PKTS_ENABLED() )
 1307                 {
 1308                     PPM_GET_TIME();
 1309                     PPM_PACKET_TEST();
 1310                     if( PPM_PACKET_ABORT_FLAG() )
 1311                     {
 1312                         /* bail if we exceeded time */
 1313                         node->last_check.result = result;
 1314                         Reset_DetectFlags(save_dflags);
 1315                         return result;
 1316                     }
 1317                 }
 1318 #endif
 1319             }
 1320 
 1321             /* If all children branches matched, we don't need to reeval any of
 1322              * the children so don't need to reeval this content/pcre rule
 1323              * option at a new offset.
 1324              * Else, reset the DOE ptr to last eval for offset/depth,
 1325              * distance/within adjustments for this same content/pcre
 1326              * rule option */
 1327             if (result == node->num_children)
 1328                 continue_loop = 0;
 1329             else
 1330                 SetDoePtr(tmp_doe_ptr, tmp_doe_flags);
 1331 
 1332             /* Don't need to reset since it's only checked after we've gone
 1333              * through the loop at least once and the result will have
 1334              * been set again already */
 1335             //for (i = 0; i < node->num_children; i++)
 1336             //    node->children[i]->result;
 1337         }
 1338 
 1339         if (result - prior_result > 0
 1340             && node->option_type == RULE_OPTION_TYPE_CONTENT
 1341             && Replace_OffsetStored(&dup_content_option_data) && ScIpsInlineMode())
 1342         {
 1343           if(!ScDisableReplaceOpt())
 1344           {
 1345             Replace_QueueChange(&dup_content_option_data);
 1346             prior_result = result;
 1347           }
 1348         }
 1349 
 1350         NODE_PROFILE_TMPSTART(node);
 1351 
 1352         if (rval == DETECTION_OPTION_NO_ALERT)
 1353         {
 1354             /* Reset the flowbit_noalert flag in eval data */
 1355             eval_data->flowbit_noalert = tmp_noalert_flag;
 1356         }
 1357 
 1358         if (continue_loop && (rval == DETECTION_OPTION_MATCH) && (node->relative_children))
 1359         {
 1360             if ((node->option_type == RULE_OPTION_TYPE_CONTENT) ||
 1361                     (node->option_type == RULE_OPTION_TYPE_CONTENT_URI))
 1362             {
 1363                 if (dup_content_option_data.exception_flag)
 1364                 {
 1365                     continue_loop = 0;
 1366                 }
 1367                 else
 1368                 {
 1369                     const uint8_t *orig_ptr;
 1370 
 1371                     if (dup_content_option_data.use_doe)
 1372                         orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr;
 1373                     else
 1374                         orig_ptr = dp;
 1375 
 1376                     continue_loop = PatternMatchAdjustRelativeOffsets((PatternMatchData *)node->option_data,
 1377                             &dup_content_option_data, doe_ptr, orig_ptr);
 1378                 }
 1379             }
 1380             else if (node->option_type == RULE_OPTION_TYPE_PCRE)
 1381             {
 1382                 if (dup_pcre_option_data.options & SNORT_PCRE_INVERT)
 1383                 {
 1384                     continue_loop = 0;
 1385                 }
 1386                 else
 1387                 {
 1388                     const uint8_t *orig_ptr;
 1389 
 1390                     if (dup_pcre_option_data.options & SNORT_PCRE_RELATIVE)
 1391                         orig_ptr = (orig_doe_ptr == NULL) ? dp : orig_doe_ptr;
 1392                     else
 1393                         orig_ptr = dp;
 1394 
 1395                     continue_loop = PcreAdjustRelativeOffsets(&dup_pcre_option_data, doe_ptr - orig_ptr);
 1396                 }
 1397             }
 1398             else
 1399             {
 1400                 continue_loop = 0;
 1401             }
 1402         }
 1403         else
 1404         {
 1405             continue_loop = 0;
 1406         }
 1407 
 1408 #ifdef PERF_PROFILING
 1409         /* We're essentially checking this node again and it potentially
 1410          * might match again */
 1411         if (continue_loop && PROFILING_RULES)
 1412             node->checks++;
 1413 #endif
 1414 
 1415         loop_count++;
 1416 
 1417         if (continue_loop)
 1418             UpdateDoePtr(orig_doe_ptr, 0);
 1419 
 1420     } while (continue_loop);
 1421 
 1422     if (flowbits_setoperation && (result == DETECTION_OPTION_MATCH))
 1423     {
 1424         /* Do any setting/clearing/resetting/toggling of flowbits here
 1425          * given that other rule options matched. */
 1426         rval = node->evaluate(node->option_data, eval_data->p);
 1427         if (rval != DETECTION_OPTION_MATCH)
 1428         {
 1429             result = rval;
 1430         }
 1431     }
 1432 
 1433     if (eval_data->flowbit_failed)
 1434     {
 1435         /* something deeper in the tree failed a flowbit test, we may need to
 1436          * reeval this node. */
 1437         node->last_check.flowbit_failed = 1;
 1438     }
 1439     node->last_check.result = result;
 1440 
 1441     if (result == DETECTION_OPTION_NO_MATCH)
 1442     {
 1443         NODE_PROFILE_END_NOMATCH(node);
 1444     }
 1445     else
 1446     {
 1447         NODE_PROFILE_END_MATCH(node);
 1448     }
 1449 
 1450     Reset_DetectFlags(save_dflags);
 1451     return result;
 1452 }
 1453 
 1454 #ifdef PERF_PROFILING
 1455 typedef struct node_profile_stats
 1456 {
 1457     uint64_t ticks;
 1458     uint64_t ticks_match;
 1459     uint64_t ticks_no_match;
 1460     uint64_t checks;
 1461     uint64_t disables;
 1462 } node_profile_stats_t;
 1463 
 1464 static void detection_option_node_update_otn_stats(detection_option_tree_node_t *node,
 1465                                                    node_profile_stats_t *stats, uint64_t checks
 1466 #ifdef PPM_MGR
 1467                                                    , uint64_t disables
 1468 #endif
 1469                                                    )
 1470 {
 1471     int i;
 1472     node_profile_stats_t local_stats; /* cumulative stats for this node */
 1473 
 1474     if (stats)
 1475     {
 1476         local_stats.ticks = stats->ticks + node->ticks;
 1477         local_stats.ticks_match = stats->ticks_match + node->ticks_match;
 1478         local_stats.ticks_no_match = stats->ticks_no_match + node->ticks_no_match;
 1479         if (node->checks > stats->checks)
 1480             local_stats.checks = node->checks;
 1481         else
 1482             local_stats.checks = stats->checks;
 1483 #ifdef PPM_MGR
 1484         local_stats.disables = disables;
 1485 #endif
 1486     }
 1487     else
 1488     {
 1489         local_stats.ticks = node->ticks;
 1490         local_stats.ticks_match = node->ticks_match;
 1491         local_stats.ticks_no_match = node->ticks_no_match;
 1492         local_stats.checks = node->checks;
 1493 #ifdef PPM_MGR
 1494         local_stats.disables = disables;
 1495 #endif
 1496     }
 1497 
 1498     if (node->option_type == RULE_OPTION_TYPE_LEAF_NODE)
 1499     {
 1500         OptTreeNode *otn = (OptTreeNode *)node->option_data;
 1501         /* Update stats for this otn */
 1502         otn->ticks += local_stats.ticks;
 1503         otn->ticks_match += local_stats.ticks_match;
 1504         otn->ticks_no_match += local_stats.ticks_no_match;
 1505         if (local_stats.checks > otn->checks)
 1506             otn->checks = local_stats.checks;
 1507 #ifdef PPM_MGR
 1508         otn->ppm_disable_cnt += local_stats.disables;
 1509 #endif
 1510     }
 1511 
 1512     if (node->num_children)
 1513     {
 1514         for (i=0;i<node->num_children; i++)
 1515         {
 1516             detection_option_node_update_otn_stats(node->children[i], &local_stats, checks
 1517 #ifdef PPM_MGR
 1518                 , disables
 1519 #endif
 1520                 );
 1521         }
 1522     }
 1523 }
 1524 
 1525 void detection_option_tree_update_otn_stats(SFXHASH *doth)
 1526 {
 1527     SFXHASH_NODE *hashnode;
 1528 
 1529     if (doth == NULL)
 1530         return;
 1531 
 1532     /* Find the first tree root in the table */
 1533     hashnode = sfxhash_findfirst(doth);
 1534     while (hashnode)
 1535     {
 1536         detection_option_tree_node_t *node = hashnode->data;
 1537         if (node->checks)
 1538         {
 1539             detection_option_node_update_otn_stats(node, NULL, node->checks
 1540 #ifdef PPM_MGR
 1541                                                    , node->ppm_disable_cnt
 1542 #endif
 1543                                                   );
 1544         }
 1545         hashnode = sfxhash_findnext(doth);
 1546     }
 1547 }
 1548 #endif