]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #675 in SNORT/snort3 from fp2 to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Thu, 13 Oct 2016 19:13:23 +0000 (15:13 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Thu, 13 Oct 2016 19:13:23 +0000 (15:13 -0400)
Squashed commit of the following:

commit 07080ae448c2b753c2f4eaff4a5667677ab58cac
Author: Russ Combs <rucombs@cisco.com>
Date:   Tue Oct 11 14:25:26 2016 -0400

    update snort2lua

commit 740f8a84e44b8b97ca9e81de015337351450d206
Author: Russ Combs <rucombs@cisco.com>
Date:   Mon Oct 10 20:33:53 2016 -0400

    fix fp selection bug

commit 4a44c5b15948f3c5bdcd501392e15efbda3fc4ad
Author: Russ Combs <rucombs@cisco.com>
Date:   Mon Oct 10 19:08:27 2016 -0400

    establish baseline unit tests

commit 510ab5e00a2a92f02635259eba942d118a91389d
Author: Russ Combs <rucombs@cisco.com>
Date:   Mon Oct 10 14:56:21 2016 -0400

    replace broken nfp counts with warnings; prepare to update fp selection

commit c208ae14acbc421c48b520d9fb58e4fe7881f109
Author: Russ Combs <rucombs@cisco.com>
Date:   Sun Oct 9 11:49:38 2016 -0400

    change search_engine.debug_print_fast_pattern to show_fast_patterns and cleanup

commit 41355c5e489906752d2f128989cbe426575870f6
Author: Russ Combs <rucombs@cisco.com>
Date:   Sat Oct 8 21:21:57 2016 -0400

    remove cruft and broken match counts

commit 151f310c2088a87c1f25b19858d289c1435da62f
Author: Russ Combs <rucombs@cisco.com>
Date:   Sat Oct 8 20:19:29 2016 -0400

    refactor / clean up

21 files changed:
src/detection/CMakeLists.txt
src/detection/Makefile.am
src/detection/fp_create.cc
src/detection/fp_create.h
src/detection/fp_detect.cc
src/detection/fp_detect.h
src/detection/fp_utils.cc [new file with mode: 0644]
src/detection/fp_utils.h [new file with mode: 0644]
src/detection/pattern_match_data.h
src/detection/pcrm.cc
src/detection/pcrm.h
src/detection/service_map.cc
src/framework/ips_option.h
src/framework/range.cc
src/main/modules.cc
src/parser/parse_rule.cc
src/ports/port_group.cc
src/ports/port_group.h
src/utils/stats.cc
src/utils/stats.h
tools/snort2lua/config_states/config_detection.cc

index 974b9d23486b377f76da157a4283fb3b87df5832..782c8816cae53f57f86c7d5860dc2f54b6b6ad40 100644 (file)
@@ -22,6 +22,8 @@ add_library (detection STATIC
     fp_create.h
     fp_detect.cc
     fp_detect.h
+    fp_utils.cc
+    fp_utils.h
     pcrm.cc
     pcrm.h
     service_map.cc
index ea68ba2918fc9d318c9ff9fc0deb3c599371f535..e405d0b4c77b756b2c0a772a7227726c8b2d4279 100644 (file)
@@ -24,6 +24,8 @@ fp_create.cc \
 fp_create.h \
 fp_detect.cc \
 fp_detect.h \
+fp_utils.cc \
+fp_utils.h \
 pcrm.cc \
 pcrm.h \
 service_map.cc \
index aff64df26b627b2a0f06b17f0612fc09785f840e..c20f460745dffc538934d51e4994d88141980643 100644 (file)
 #include "rules.h"
 #include "treenodes.h"
 #include "fp_detect.h"
+#include "fp_utils.h"
 #include "detection_options.h"
 #include "detection_defines.h"
 #include "sfrim.h"
 #include "pattern_match_data.h"
 
 static unsigned mpse_count = 0;
+static const char* s_group = "";
 
 static void fpDeletePMX(void* data);
 
 static int fpGetFinalPattern(
     FastPatternConfig*, PatternMatchData*, const char*& ret_pattern, int& ret_bytes);
 
-static void PrintFastPatternInfo(
-    OptTreeNode*, PatternMatchData*, const char* pattern, int pattern_length);
+static void print_nfp_info(const char*, const OptTreeNode*);
+static void print_fp_info(const char*, const OptTreeNode*, const PatternMatchData*,
+    const char* pattern, int pattern_length);
 
 static const char* const pm_type_strings[PM_TYPE_MAX] =
 {
@@ -291,7 +294,7 @@ static int add_patrn_to_neg_list(void* id, void** list)
         return -1;
 
     NCListNode** ncl = (NCListNode**)list;
-    NCListNode* node = (NCListNode*)snort_calloc(sizeof(NCListNode));
+    NCListNode* node = (NCListNode*)snort_alloc(sizeof(NCListNode));
 
     node->pmx = (PMX*)id;
     node->next = *ncl;
@@ -325,7 +328,9 @@ static int pmx_create_tree(SnortConfig* sc, void* id, void** existing_tree)
 
     if (!id)
     {
-        assert(*existing_tree);
+        if ( !*existing_tree )
+            return -1;
+
         /* NULL input id (PMX *), last call for this pattern state */
         return finalize_detection_option_tree(sc, (detection_option_tree_root_t*)*existing_tree);
     }
@@ -339,282 +344,58 @@ static int pmx_create_tree(SnortConfig* sc, void* id, void** existing_tree)
     return otn_create_tree(otn, existing_tree);
 }
 
-/* FLP_Trim
-  * Trim zero byte prefixes, this increases uniqueness
-  * will not alter regex since they can't contain bald \0
-  *
-  * returns
-  *   length - of trimmed pattern
-  *   buff - ptr to new beggining of trimmed buffer
-  */
-static int FLP_Trim(const char* p, int plen, const char** buff)
-{
-    int i;
-    int size = 0;
-
-    if ( !p )
-        return 0;
-
-    for (i=0; i<plen; i++)
-    {
-        if ( p[i] != 0 )
-            break;
-    }
-
-    if ( i < plen )
-        size = plen - i;
-    else
-        size = 0;
-
-    if ( buff && (size==0) )
-    {
-        *buff = 0;
-    }
-    else if ( buff )
-    {
-        *buff = &p[i];
-    }
-    return size;
-}
-
-static bool pmd_can_be_fp(PatternMatchData* pmd, CursorActionType cat)
-{
-    if ( cat <= CAT_SET_OTHER )
-        return false;
-
-    return pmd->can_be_fp();
-}
-
-struct FpFoo
-{
-    CursorActionType cat;
-    PatternMatchData* pmd;
-    int size;
-
-    FpFoo()
-    { cat = CAT_NONE; pmd = nullptr; size = 0; }
-
-    FpFoo(CursorActionType c, PatternMatchData* p)
-    {
-        cat = c;
-        pmd = p;
-        size = FLP_Trim(pmd->pattern_buf, pmd->pattern_size, nullptr);
-    }
-
-    bool is_better(FpFoo& rhs)
-    {
-        if ( size && !rhs.size )
-            return true;
-
-        if ( !rhs.pmd )
-            return true;
-
-        if ( !pmd->negated && rhs.pmd->negated )
-            return true;
-
-        if ( cat > rhs.cat )
-            return true;
-
-        if ( cat < rhs.cat )
-            return false;
-
-        if ( size > rhs.size )
-            return true;
-
-        return false;
-    }
-};
-
-static PmType get_pm_type(CursorActionType cat)
-{
-    switch ( cat )
-    {
-    case CAT_SET_RAW:
-    case CAT_SET_OTHER:
-        return PM_TYPE_PKT;
-
-    case CAT_SET_BODY:
-        return PM_TYPE_BODY;
-
-    case CAT_SET_HEADER:
-        return PM_TYPE_HEADER;
-
-    case CAT_SET_KEY:
-        return PM_TYPE_KEY;
-
-    case CAT_SET_FILE:
-        return PM_TYPE_FILE;
-
-    default:
-        break;
-    }
-    assert(false);
-    return PM_TYPE_MAX;
-}
-
-bool set_fp_content(OptTreeNode* otn)
-{
-    CursorActionType curr_cat = CAT_SET_RAW;
-    FpFoo best;
-    PatternMatchData* pmd = nullptr;
-    bool content = false;
-    bool fp_only = true;
-
-    for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next)
-    {
-        if ( !ofl->ips_opt )
-            continue;
-
-        CursorActionType cat = ofl->ips_opt->get_cursor_type();
-
-        if ( cat > CAT_ADJUST )
-        {
-            curr_cat = cat;
-            fp_only = !ofl->ips_opt->fp_research();
-        }
-
-        // Set rule direction
-        RuleDirection dir = RULE_WO_DIR;
-        if (OtnFlowFromServer(otn))
-            dir = RULE_FROM_SERVER;
-        else if (OtnFlowFromClient(otn))
-            dir = RULE_FROM_CLIENT;
-
-        PatternMatchData* tmp = get_pmd(ofl, otn->proto, dir);
-
-        if ( !tmp )
-            continue;
-
-        content = true;
-
-        if ( !fp_only )
-            tmp->fp_only = -1;
-
-        tmp->pm_type = get_pm_type(curr_cat);
-
-        if ( tmp->fp )
-        {
-            if ( pmd )
-                ParseWarning(WARN_RULES,
-                    "only one fast_pattern content per rule allowed - ignored");
-
-            else if ( !pmd_can_be_fp(tmp, curr_cat) )
-                ParseWarning(WARN_RULES,
-                    "content ineligible for fast_pattern matcher - ignored");
-
-            else
-                pmd = tmp;
-        }
-
-        if ( !pmd_can_be_fp(tmp, curr_cat) )
-            continue;
-
-        FpFoo curr(curr_cat, tmp);
-
-        if ( curr.is_better(best) )
-            best = curr;
-    }
-    if ( !pmd && best.pmd )
-    {
-        pmd = best.pmd;
-        pmd->fp = 1;
-    }
-
-    if ( best.pmd and otn->proto == SNORT_PROTO_FILE and best.cat != CAT_SET_FILE )
-    {
-        ParseWarning(WARN_RULES, "file rule %u:%u does not have file_data fast pattern",
-            otn->sigInfo.generator, otn->sigInfo.id);
-
-        best.pmd->fp = 0;
-        return false;
-    }
-
-    if ( pmd )
-        return true;
-
-    if ( content )
-        ParseWarning(WARN_RULES, "content based rule %u:%u has no fast pattern",
-            otn->sigInfo.generator, otn->sigInfo.id);
-
-    return false;
-}
-
-static PatternMatchData* get_fp_content(OptTreeNode* otn, OptFpList*& next)
-{
-    for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next)
-    {
-        if ( !ofl->ips_opt )
-            continue;
-
-        PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
-
-        if ( !pmd )
-            continue;
-
-        next = ofl->next;
-
-        if ( pmd->fp )
-            return pmd;
-    }
-    return nullptr;
-}
-
 static int fpFinishPortGroupRule(
     SnortConfig* sc, PortGroup* pg,
     OptTreeNode* otn, PatternMatchData* pmd, FastPatternConfig* fp)
 {
-    const char* pattern;
-    int pattern_length;
-
     if ( !pmd )
     {
         pg->add_nfp_rule(otn);
-        return 0;  /* Not adding any content to pattern matcher */
+        print_nfp_info(s_group, otn);
+        return 0;
     }
-    else
+    if ( !pg->mpse[pmd->pm_type] )
     {
-        if (pmd->negated)
-            pg->add_nfp_rule(otn);
+        static MpseAgent agent =
+        {
+            pmx_create_tree, add_patrn_to_neg_list,
+            fpDeletePMX, free_detection_option_root, neg_list_free
+        };
 
-        else
-            pg->add_rule();
+        pg->mpse[pmd->pm_type] = MpseManager::get_search_engine(
+            sc, fp->get_search_api(), true, &agent);
 
-        if (fpGetFinalPattern(fp, pmd, pattern, pattern_length) == -1)
+        if ( !pg->mpse[pmd->pm_type] )
+        {
+            ParseError("Failed to create pattern matcher for %d", pmd->pm_type);
             return -1;
+        }
+        mpse_count++;
 
-        /* create pmx */
-        PMX* pmx = (PMX*)snort_calloc(sizeof(PMX));
-        pmx->rule_node.rnRuleData = otn;
-        pmx->pmd = pmd;
+        if ( fp->get_search_opt() )
+            pg->mpse[pmd->pm_type]->set_opt(1);
+    }
+    if (pmd->negated)
+        pg->add_nfp_rule(otn);
 
-        if (fp->get_debug_print_fast_patterns())
-            PrintFastPatternInfo(otn, pmd, pattern, pattern_length);
+    else
+        pg->add_rule();
 
-        if ( !pg->mpse[pmd->pm_type] )
-        {
-            static MpseAgent agent =
-            {
-                pmx_create_tree, add_patrn_to_neg_list,
-                fpDeletePMX, free_detection_option_root, neg_list_free
-            };
+    const char* pattern;
+    int pattern_length;
 
-            pg->mpse[pmd->pm_type] = MpseManager::get_search_engine(
-                sc, fp->get_search_api(), true, &agent);
+    if (fpGetFinalPattern(fp, pmd, pattern, pattern_length) == -1)
+        return -1;
 
-            if ( !pg->mpse[pmd->pm_type] )
-            {
-                ParseError("Failed to create pattern matcher for %d", pmd->pm_type);
-                return -1;
-            }
-            mpse_count++;
+    if ( fp->get_debug_print_fast_patterns() )
+        print_fp_info(s_group, otn, pmd, pattern, pattern_length);
 
-            if ( fp->get_search_opt() )
-                pg->mpse[pmd->pm_type]->set_opt(1);
-        }
+    PMX* pmx = (PMX*)snort_calloc(sizeof(PMX));
+    pmx->rule_node.rnRuleData = otn;
+    pmx->pmd = pmd;
 
-        Mpse::PatternDescriptor desc(pmd->no_case, pmd->negated, pmd->literal, pmd->flags);
-        pg->mpse[pmd->pm_type]->add_pattern(sc, (uint8_t*)pattern, pattern_length, desc, pmx);
-    }
+    Mpse::PatternDescriptor desc(pmd->no_case, pmd->negated, pmd->literal, pmd->flags);
+    pg->mpse[pmd->pm_type]->add_pattern(sc, (uint8_t*)pattern, pattern_length, desc, pmx);
 
     return 0;
 }
@@ -678,7 +459,7 @@ static int fpFinishPortGroup(
 }
 
 static int fpAddPortGroupRule(
-    SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp)
+    SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp, bool srvc)
 {
     PatternMatchData* pmd = NULL;
 
@@ -691,9 +472,9 @@ static int fpAddPortGroupRule(
         return -1;
 
     OptFpList* next = nullptr;
-    pmd = get_fp_content(otn, next);
+    pmd = get_fp_content(otn, next, srvc);
 
-    if ( pmd && pmd->fp )
+    if ( pmd )
     {
         if (
             !pmd->relative && !pmd->negated && pmd->fp_only >= 0 &&
@@ -713,16 +494,7 @@ static int fpAddPortGroupRule(
         }
     }
 
-    /* If we get this far then no URI contents were added */
-
-    if ( pmd && fpFinishPortGroupRule(sc, pg, otn, pmd, fp) == 0)
-    {
-        if (pmd->pattern_size > otn->longestPatternLen)
-            otn->longestPatternLen = pmd->pattern_size;
-        return 0;
-    }
-
-    /* No content added */
+    // no fast pattern added
     if (fpFinishPortGroupRule(sc, pg, otn, NULL, fp) != 0)
         return -1;
 
@@ -988,7 +760,7 @@ static int fpGetFinalPattern(
         if ( fp->get_trim() )
         {
             bytes =
-                FLP_Trim(pmd->pattern_buf, pmd->pattern_size, &pattern);
+                flp_trim(pmd->pattern_buf, pmd->pattern_size, &pattern);
 
             if (bytes < (int)pmd->pattern_size)
             {
@@ -1091,6 +863,7 @@ static int fpCreatePortObject2PortGroup(
 
     /* create a port_group */
     pg = (PortGroup*)snort_calloc(sizeof(PortGroup));
+    s_group = "port";
 
     /*
      * Walk the rules in the PortObject and add to
@@ -1129,7 +902,7 @@ static int fpCreatePortObject2PortGroup(
             assert(otn);
 
             if ( is_network_protocol(otn->proto) )
-                fpAddPortGroupRule(sc, pg, otn, fp);
+                fpAddPortGroupRule(sc, pg, otn, fp, false);
         }
 
         if (fp->get_debug_print_rule_group_build_details())
@@ -1393,6 +1166,7 @@ static void fpBuildServicePortGroupByServiceOtnList(
 {
     OptTreeNode* otn;
     PortGroup* pg = (PortGroup*)snort_calloc(sizeof(PortGroup));
+    s_group = srvc;
 
     /*
      * add each rule to the port group pattern matchers,
@@ -1404,7 +1178,7 @@ static void fpBuildServicePortGroupByServiceOtnList(
         otn;
         otn = (OptTreeNode*)sflist_next(&cursor))
     {
-        if (fpAddPortGroupRule(sc, pg, otn, fp) != 0)
+        if (fpAddPortGroupRule(sc, pg, otn, fp, true) != 0)
             continue;
     }
 
@@ -1812,119 +1586,16 @@ void fpDeleteFastPacketDetection(SnortConfig* sc)
         delete sc->sopgTable;
 }
 
-/*
-**  Wrapper for prmShowEventStats
-*/
-void fpShowEventStats(SnortConfig* sc)
+static void print_nfp_info(const char* group, const OptTreeNode* otn)
 {
-    if ((sc == NULL) || (sc->fast_pattern_config == NULL))
-        return;
-
-    /* If not debug, then we don't print anything. */
-    if (!sc->fast_pattern_config->get_debug_mode())
-        return;
-
-    LogMessage("\n");
-    LogMessage("** IP Event Stats --\n");
-    prmShowEventStats(sc->prmIpRTNX);
-
-    LogMessage("\n");
-    LogMessage("** ICMP Event Stats --\n");
-    prmShowEventStats(sc->prmIcmpRTNX);
-
-    LogMessage("\n");
-    LogMessage("** TCP Event Stats --\n");
-    prmShowEventStats(sc->prmTcpRTNX);
-
-    LogMessage("\n");
-    LogMessage("** UDP Event Stats --\n");
-    prmShowEventStats(sc->prmUdpRTNX);
+    ParseWarning(WARN_RULES, "%s rule %u:%u:%u has no fast pattern",
+        group, otn->sigInfo.generator, otn->sigInfo.id, otn->sigInfo.rev);
 }
 
-static const char* PatternRawToContent(const char* pattern, int pattern_len)
-{
-    static char content_buf[1024];
-    int max_write_size = sizeof(content_buf) - 64;
-    int i, j = 0;
-    int hex = 0;
-
-    if ((pattern == NULL) || (pattern_len <= 0))
-        return "";
-
-    content_buf[j++] = '"';
-
-    for (i = 0; i < pattern_len; i++)
-    {
-        uint8_t c = (uint8_t)pattern[i];
-
-        if ((c < 128) && isprint(c) && !isspace(c)
-            && (c != '|') && (c != '"') && (c != ';'))
-        {
-            if (hex)
-            {
-                content_buf[j-1] = '|';
-                hex = 0;
-            }
-
-            content_buf[j++] = c;
-        }
-        else
-        {
-            uint8_t up4, lo4;
-
-            if (!hex)
-            {
-                content_buf[j++] = '|';
-                hex = 1;
-            }
-
-            up4 = c >> 4;
-            lo4 = c & 0x0f;
-
-            if (up4 > 0x09)
-                up4 += ('A' - 0x0a);
-            else
-                up4 += '0';
-
-            if (lo4 > 0x09)
-                lo4 += ('A' - 0x0a);
-            else
-                lo4 += '0';
-
-            content_buf[j++] = up4;
-            content_buf[j++] = lo4;
-            content_buf[j++] = ' ';
-        }
-
-        if (j > max_write_size)
-            break;
-    }
-
-    if (j > max_write_size)
-    {
-        content_buf[j] = 0;
-        SnortSnprintfAppend(content_buf, sizeof(content_buf),
-            " ... \" (pattern too large)");
-    }
-    else
-    {
-        if (hex)
-            content_buf[j-1] = '|';
-
-        content_buf[j++] = '"';
-        content_buf[j] = 0;
-    }
-
-    return content_buf;
-}
-
-static void PrintFastPatternInfo(OptTreeNode* otn, PatternMatchData* pmd,
+static void print_fp_info(
+    const char* group, const OptTreeNode* otn, const PatternMatchData* pmd,
     const char* pattern, int pattern_length)
 {
-    if ((otn == NULL) || (pmd == NULL))
-        return;
-
-#if 0
     std::string hex, txt;
     char buf[8];
 
@@ -1934,48 +1605,15 @@ static void PrintFastPatternInfo(OptTreeNode* otn, PatternMatchData* pmd,
         hex += buf;
         txt += isprint(pattern[i]) ? pattern[i] : '.';
     }
-    printf("fast pattern[%d] = x%s '%s'\n", pattern_length, hex.c_str(), txt.c_str());
-#else
-    LogMessage("%u:%u\n", otn->sigInfo.generator, otn->sigInfo.id);
-    LogMessage("  Fast pattern matcher: %s\n", pm_type_strings[pmd->pm_type]);
-    LogMessage("  Fast pattern set: %s\n", pmd->fp ? "yes" : "no");
-    LogMessage("  Fast pattern only: %d\n", pmd->fp_only);
-    LogMessage("  Negated: %s\n", pmd->negated ? "yes" : "no");
-
-    /* Fast pattern only patterns don't use offset and length */
-    if ((pmd->fp_length != 0) && pmd->fp_only <= 0)
-    {
-        LogMessage("  Pattern <offset,length>: %d,%d\n",
-            pmd->fp_offset, pmd->fp_length);
-        LogMessage("    %s\n",
-            PatternRawToContent(pmd->pattern_buf + pmd->fp_offset,
-            pmd->fp_length));
-    }
-    else
-    {
-        LogMessage("  Pattern offset,length: none\n");
-    }
+    std::string opts = "(";
+    if ( pmd->fp ) opts += " user";
+    if ( pmd->fp_only ) opts += " only";
+    if ( pmd->negated ) opts += " negated";
+    opts += " )";
 
-    /* Fast pattern only patterns don't get truncated */
-    if ( pmd->fp_only <= 0 &&
-        (((pmd->fp_length != 0) && (pmd->fp_length > pattern_length)) ||
-        ((pmd->fp_length == 0) && ((int)pmd->pattern_size > pattern_length))) )
-    {
-        LogMessage("  Pattern truncated: %d to %d bytes\n",
-            pmd->fp_length ? pmd->fp_length : pmd->pattern_size,
-            pattern_length);
-    }
-    else
-    {
-        LogMessage("  Pattern truncated: no\n");
-    }
-
-    LogMessage("  Original pattern\n");
-    LogMessage("    %s\n",
-        PatternRawToContent(pmd->pattern_buf,pmd->pattern_size));
-
-    LogMessage("  Final pattern\n");
-    LogMessage("    %s\n", PatternRawToContent(pattern, pattern_length));
-#endif
+    LogMessage("FP %s %u:%u:%u %s[%d] = '%s' |%s| %s\n",
+        group, otn->sigInfo.generator, otn->sigInfo.id, otn->sigInfo.rev,
+        pm_type_strings[pmd->pm_type], pattern_length,
+        txt.c_str(), hex.c_str(), opts.c_str());
 }
 
index b1f875c9be441485d8793f4e16c4eca7388645c3..e96ca261aa519c007ca4965b2eb2e459ae4e5a88 100644 (file)
@@ -54,11 +54,7 @@ struct NCListNode
 int fpCreateFastPacketDetection(SnortConfig*);
 void fpDeleteFastPacketDetection(SnortConfig*);
 
-void fpShowEventStats(SnortConfig*);
-
 void fpDeletePortGroup(void*);
 
-bool set_fp_content(struct OptTreeNode*);
-
 #endif
 
index a70c4cd9b66acde39d27befd6fbb8906a0198d17..2df4da52c35ab95a93bb84c5e08edf653f74e800 100644 (file)
@@ -425,17 +425,9 @@ static int rule_tree_match(
         }
 
         if ( ret )
-        {
-            //  We have a qualified event from this tree
-            pomd->pg->event_count++;
             pmqs.qualified_events++;
-        }
         else
-        {
-            // This means that the event is non-qualified.
-            pomd->pg->match_count++;
             pmqs.non_qualified_events++;
-        }
     }
 
     if (eval_data.flowbit_failed)
@@ -511,6 +503,8 @@ static int sortOrderByPriority(const void* e1, const void* e2)
     return 0;
 }
 
+// FIXIT-L pattern length is not a valid event sort criterion for
+// non-literals
 static int sortOrderByContentLength(const void* e1, const void* e2)
 {
     OptTreeNode* otn1;
@@ -1042,18 +1036,11 @@ static inline int fpEvalHeaderSW(PortGroup* port_group, Packet* p,
             }
 
             if (rval)
-            {
-                // We have a qualified event from this tree
-                port_group->event_count++;
                 pmqs.qualified_events++;
-            }
             else
-            {
-                // This means that the event is non-qualified.
-                port_group->match_count++;
                 pmqs.non_qualified_events++;
-            }
-            pc.slow_searches++;
+
+            pc.hard_evals++;
         }
 
         // FIXIT-L need to eval all IP layers, etc.
index da9236f830f3b8822cb655b0975fec3900ca25df..957b429d5961b871c32f51b58d4c590e6f69a3ee 100644 (file)
@@ -33,7 +33,6 @@
 #include "config.h"
 #endif
 
-#include "detection/fp_create.h"
 #include "main/snort_debug.h"
 #include "protocols/packet.h"
 #include "utils/sflsq.h"
@@ -41,6 +40,8 @@
 #define REBUILD_FLAGS (PKT_REBUILT_FRAG | PKT_REBUILT_STREAM)
 
 struct ProfileStats;
+struct OptTreeNode;
+struct PortGroup;
 
 extern THREAD_LOCAL ProfileStats rulePerfStats;
 extern THREAD_LOCAL ProfileStats ruleRTNEvalPerfStats;
@@ -51,11 +52,11 @@ extern THREAD_LOCAL ProfileStats ruleNFPEvalPerfStats;
 **  This is the only function that is needed to do an
 **  inspection on a packet.
 */
-int fpEvalPacket(Packet* p);
+int fpEvalPacket(Packet*);
 
 struct RuleTreeNode;
-int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p);
-int fpEvalRTN(RuleTreeNode* rtn, Packet* p, int check_ports);
+int fpLogEvent(const RuleTreeNode*, const OptTreeNode*, Packet*);
+int fpEvalRTN(RuleTreeNode*, Packet*, int check_ports);
 
 /*
 **  This define is for the number of unique events
@@ -105,7 +106,7 @@ struct OTNX_MATCH_DATA
 void otnx_match_data_init(int);
 void otnx_match_data_term();
 
-int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn);
+int fpAddMatch(OTNX_MATCH_DATA*, int pLen, const OptTreeNode*);
 OptTreeNode* GetOTN(uint32_t gid, uint32_t sid);
 
 /* counter for number of times we evaluate rules.  Used to
diff --git a/src/detection/fp_utils.cc b/src/detection/fp_utils.cc
new file mode 100644 (file)
index 0000000..bec326e
--- /dev/null
@@ -0,0 +1,597 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#include "fp_utils.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#ifdef UNIT_TEST
+#include "catch/catch.hpp"
+#endif
+
+#include "ips_options/ips_flow.h"
+#include "log/messages.h"
+#include "ports/port_group.h"
+#include "target_based/snort_protocols.h"
+
+#include "pattern_match_data.h"
+#include "treenodes.h"
+
+//--------------------------------------------------------------------------
+// private utilities
+//--------------------------------------------------------------------------
+
+static void finalize_content(OptFpList* ofl)
+{
+    PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
+
+    if ( !pmd )
+        return;
+
+    if ( pmd->negated )
+        pmd->last_check = (PmdLastCheck*)snort_calloc(
+            ThreadConfig::get_instance_max(), sizeof(*pmd->last_check));
+}
+
+static void clear_fast_pattern_only(OptFpList* ofl)
+{
+    PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
+
+    if ( pmd && pmd->fp_only > 0 )
+        pmd->fp_only = 0;
+}
+
+static bool pmd_can_be_fp(PatternMatchData* pmd, CursorActionType cat)
+{
+    if ( cat <= CAT_SET_OTHER )
+        return false;
+
+    return pmd->can_be_fp();
+}
+
+static PmType get_pm_type(CursorActionType cat)
+{
+    switch ( cat )
+    {
+    case CAT_SET_RAW:
+    case CAT_SET_OTHER:
+        return PM_TYPE_PKT;
+
+    case CAT_SET_BODY:
+        return PM_TYPE_BODY;
+
+    case CAT_SET_HEADER:
+        return PM_TYPE_HEADER;
+
+    case CAT_SET_KEY:
+        return PM_TYPE_KEY;
+
+    case CAT_SET_FILE:
+        return PM_TYPE_FILE;
+
+    default:
+        break;
+    }
+    assert(false);
+    return PM_TYPE_MAX;
+}
+
+static RuleDirection get_dir(OptTreeNode* otn)
+{
+    if ( OtnFlowFromServer(otn) )
+        return RULE_FROM_SERVER;
+
+    if ( OtnFlowFromClient(otn) )
+        return RULE_FROM_CLIENT;
+
+    return RULE_WO_DIR;
+}
+
+//--------------------------------------------------------------------------
+// public utilities
+//--------------------------------------------------------------------------
+
+PatternMatchData* get_pmd(OptFpList* ofl, int proto, RuleDirection direction)
+{
+    if ( !ofl->ips_opt )
+        return nullptr;
+
+    return ofl->ips_opt->get_pattern(proto, direction);
+}
+
+bool is_fast_pattern_only(OptFpList* ofl)
+{
+    PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
+
+    if ( !pmd )
+        return false;
+
+    return pmd->fp_only > 0;
+}
+
+/*
+  * Trim zero byte prefixes, this increases uniqueness
+  * will not alter regex since they can't contain bald \0
+  *
+  * returns
+  *   length - of trimmed pattern
+  *   buff - ptr to new beggining of trimmed buffer
+  */
+int flp_trim(const char* p, int plen, const char** buff)
+{
+    int i;
+    int size = 0;
+
+    if ( !p )
+        return 0;
+
+    for (i=0; i<plen; i++)
+    {
+        if ( p[i] != 0 )
+            break;
+    }
+
+    if ( i < plen )
+        size = plen - i;
+    else
+        size = 0;
+
+    if ( buff && (size==0) )
+    {
+        *buff = 0;
+    }
+    else if ( buff )
+    {
+        *buff = &p[i];
+    }
+    return size;
+}
+
+void validate_fast_pattern(OptTreeNode* otn)
+{
+    OptFpList* fp = nullptr;
+    bool relative_is_bad_mkay = false;
+
+    for (OptFpList* fpl = otn->opt_func; fpl; fpl = fpl->next)
+    {
+        // a relative option is following a fast_pattern/only and
+        if ( relative_is_bad_mkay )
+        {
+            if (fpl->isRelative)
+            {
+                assert(fp);
+                clear_fast_pattern_only(fp);
+            }
+        }
+
+        // reset the check if one of these are present.
+        if ( fpl->ips_opt and !fpl->ips_opt->get_pattern(0))
+        {
+            if ( fpl->ips_opt->get_cursor_type() > CAT_NONE )
+                relative_is_bad_mkay = false;
+        }
+        // set/unset the check on content options.
+        else
+        {
+            if ( is_fast_pattern_only(fpl) )
+            {
+                fp = fpl;
+                relative_is_bad_mkay = true;
+            }
+            else
+                relative_is_bad_mkay = false;
+        }
+        finalize_content(fpl);
+    }
+}
+
+//--------------------------------------------------------------------------
+// class to help determine which of two candidate patterns is better for
+// a rule that does not have a valid fast_pattern flag.
+//--------------------------------------------------------------------------
+
+struct FpSelector
+{
+    CursorActionType cat;
+    PatternMatchData* pmd;
+    int size;
+
+    FpSelector(CursorActionType, PatternMatchData*);
+
+    FpSelector()
+    { cat = CAT_NONE; pmd = nullptr; size = 0; }
+
+    bool is_better_than(FpSelector&, bool, RuleDirection);
+};
+
+FpSelector::FpSelector(CursorActionType c, PatternMatchData* p)
+{
+    cat = c;
+    pmd = p;
+
+    // FIXIT-H unconditional trim is bad mkay? see fpGetFinalPattern
+    size = flp_trim(pmd->pattern_buf, pmd->pattern_size, nullptr);
+}
+
+bool FpSelector::is_better_than(FpSelector& rhs, bool srvc, RuleDirection dir)
+{
+    if ( !pmd_can_be_fp(pmd, cat) )
+    {
+        if ( pmd->fp )
+        {
+            ParseWarning(WARN_RULES, "content ineligible for fast_pattern matcher - ignored");
+            pmd->fp = 0;
+        }
+        return false;
+    }
+
+    if ( !rhs.pmd )
+        return true;
+
+    if ( !srvc )
+    {
+        if ( cat == CAT_SET_RAW and rhs.cat != CAT_SET_RAW )
+            return true;
+
+        if ( cat != CAT_SET_RAW and rhs.cat == CAT_SET_RAW )
+            return false;
+    }
+    else if ( dir == RULE_FROM_SERVER )
+    {
+        if ( cat != CAT_SET_KEY and rhs.cat == CAT_SET_KEY )
+            return true;
+
+        if ( cat == CAT_SET_KEY and rhs.cat != CAT_SET_KEY )
+            return false;
+    }
+    if ( pmd->fp )
+    {
+        if ( rhs.pmd->fp )
+        {
+            ParseWarning(WARN_RULES,
+                "only one fast_pattern content per rule allowed - using first");
+            pmd->fp = 0;
+        }
+        return true;
+    }
+    if ( rhs.pmd->fp )
+        return false;
+
+    if ( !pmd->negated && rhs.pmd->negated )
+        return true;
+
+    if ( size > rhs.size )
+        return true;
+
+    return false;
+}
+
+//--------------------------------------------------------------------------
+// public methods
+//--------------------------------------------------------------------------
+
+PatternMatchData* get_fp_content(OptTreeNode* otn, OptFpList*& next, bool srvc)
+{
+    CursorActionType curr_cat = CAT_SET_RAW;
+    FpSelector best;
+    bool content = false;
+    bool fp_only = true;
+
+    for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next)
+    {
+        if ( !ofl->ips_opt )
+            continue;
+
+        CursorActionType cat = ofl->ips_opt->get_cursor_type();
+
+        if ( cat > CAT_ADJUST )
+        {
+            curr_cat = cat;
+            fp_only = !ofl->ips_opt->fp_research();
+        }
+
+        RuleDirection dir = get_dir(otn);
+        PatternMatchData* tmp = get_pmd(ofl, otn->proto, dir);
+
+        if ( !tmp )
+            continue;
+
+        content = true;
+
+        if ( !fp_only )
+            tmp->fp_only = -1;
+
+        tmp->pm_type = get_pm_type(curr_cat);
+
+        FpSelector curr(curr_cat, tmp);
+
+        if ( curr.is_better_than(best, srvc, dir) )
+        {
+            best = curr;
+            next = ofl->next;
+        }
+    }
+
+    if ( best.pmd and otn->proto == SNORT_PROTO_FILE and best.cat != CAT_SET_FILE )
+    {
+        ParseWarning(WARN_RULES, "file rule %u:%u does not have file_data fast pattern",
+            otn->sigInfo.generator, otn->sigInfo.id);
+        return nullptr;
+    }
+
+    if ( best.pmd )
+        return best.pmd;
+
+    if ( content )
+        ParseWarning(WARN_RULES, "content based rule %u:%u has no eligible fast pattern",
+            otn->sigInfo.generator, otn->sigInfo.id);
+
+    return nullptr;
+}
+
+//--------------------------------------------------------------------------
+// unit tests
+//--------------------------------------------------------------------------
+
+#ifdef UNIT_TEST
+static void set_pmd(PatternMatchData& pmd, unsigned flags, const char* s)
+{
+    memset(&pmd, 0, sizeof(pmd));
+    pmd.negated = (flags & 0x01) != 0;
+    pmd.no_case = (flags & 0x02) != 0;
+    pmd.relative = (flags & 0x04) != 0;
+    pmd.literal = (flags & 0x08) != 0;
+    pmd.fp = (flags & 0x10) != 0;
+    pmd.pattern_buf = s;
+    pmd.pattern_size = strlen(s);
+}
+
+TEST_CASE("pmd_no_options", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x0, "foo");
+    CHECK(pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_negated", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x1, "foo");
+    CHECK(!pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_no_case", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x2, "foo");
+    CHECK(pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_relative", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x4, "foo");
+    CHECK(pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_negated_no_case", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x3, "foo");
+    CHECK(pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_negated_relative", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x5, "foo");
+    CHECK(!pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_negated_no_case_offset", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x1, "foo");
+    pmd.offset = 3;
+    CHECK(!pmd.can_be_fp());
+}
+
+TEST_CASE("pmd_negated_no_case_depth", "[PatternMatchData]")
+{
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x3, "foo");
+    pmd.depth = 1;
+    CHECK(!pmd.can_be_fp());
+}
+
+TEST_CASE("fp_simple", "[FastPatternSelect]")
+{
+    FpSelector test;
+    PatternMatchData pmd;
+    set_pmd(pmd, 0x0, "foo");
+    FpSelector left(CAT_SET_RAW, &pmd);
+    CHECK(left.is_better_than(test, false, RULE_WO_DIR));
+
+    test.size = 1;
+    CHECK(left.is_better_than(test, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_negated", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "foo");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x1, "foo");
+    FpSelector s1(CAT_SET_RAW, &p1);
+
+    CHECK(s0.is_better_than(s1, false, RULE_WO_DIR));
+    CHECK(!s1.is_better_than(s0, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_cat1", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "longer");
+    FpSelector s0(CAT_SET_FILE, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "short");
+    FpSelector s1(CAT_SET_BODY, &p1);
+
+    CHECK(s0.is_better_than(s1, true, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_cat2", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "foo");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "foo");
+    FpSelector s1(CAT_SET_FILE, &p1);
+
+    CHECK(s0.is_better_than(s1, false, RULE_WO_DIR));
+    CHECK(!s1.is_better_than(s0, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_cat3", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "foo");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "foo");
+    FpSelector s1(CAT_SET_FILE, &p1);
+
+    CHECK(!s0.is_better_than(s1, true, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_size", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "longer");
+    FpSelector s0(CAT_SET_HEADER, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "short");
+    FpSelector s1(CAT_SET_HEADER, &p1);
+
+    CHECK(s0.is_better_than(s1, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_port", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "short");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "longer");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(s0.is_better_than(s1, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_port_user", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x10, "short");
+    FpSelector s0(CAT_SET_KEY, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "longer");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(s0.is_better_than(s1, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_port_user_user", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x10, "short");
+    FpSelector s0(CAT_SET_KEY, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x10, "longer");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(s0.is_better_than(s1, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_port_user_user2", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "longer");
+    FpSelector s0(CAT_SET_KEY, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x10, "short");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(!s0.is_better_than(s1, false, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_srvc_1", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "short");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "longer");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(s1.is_better_than(s0, true, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_srvc_2", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "longer");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "short");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(s0.is_better_than(s1, true, RULE_WO_DIR));
+}
+
+TEST_CASE("fp_pkt_key_srvc_rsp", "[FastPatternSelect]")
+{
+    PatternMatchData p0;
+    set_pmd(p0, 0x0, "short");
+    FpSelector s0(CAT_SET_RAW, &p0);
+
+    PatternMatchData p1;
+    set_pmd(p1, 0x0, "longer");
+    FpSelector s1(CAT_SET_KEY, &p1);
+
+    CHECK(s0.is_better_than(s1, true, RULE_FROM_SERVER));
+    CHECK(!s1.is_better_than(s0, true, RULE_FROM_SERVER));
+}
+#endif
+
diff --git a/src/detection/fp_utils.h b/src/detection/fp_utils.h
new file mode 100644 (file)
index 0000000..1f4d07c
--- /dev/null
@@ -0,0 +1,41 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
+// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifndef FP_UTILS_H
+#define FP_UTILS_H
+
+// fast pattern utilities
+
+#include "framework/ips_option.h"
+
+struct OptFpList;
+struct OptTreeNode;
+
+struct PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection);
+bool is_fast_pattern_only(OptFpList*);
+void validate_fast_pattern(OptTreeNode*);
+
+int flp_trim(const char* p, int plen, const char** buff);
+bool set_fp_content(OptTreeNode*);
+
+PatternMatchData* get_fp_content(OptTreeNode*, OptFpList*&, bool srvc);
+
+#endif
+
index 50f86ee039be315bb7719f913f85a6236f78f241..4cad2b418c1cbeb5eed55a284f403ea40e1a64ed 100644 (file)
 #ifndef PATTERN_MATCH_DATA_H
 #define PATTERN_MATCH_DATA_H
 
+#include <assert.h>
 #include <ctype.h>
 #include <sys/time.h>
 
-#include "main/snort_types.h"
 #include "detection/treenodes.h"
+#include "framework/ips_option.h"  // FIXIT-L not a good dependency
+#include "main/snort_types.h"
+#include "main/thread_config.h"
+#include "utils/util.h"
 
 struct PmdLastCheck
 {
@@ -38,10 +42,10 @@ struct PatternMatchData
 {
     // used by both
     bool negated;            // search for "not this pattern"
-    bool fp;                 // for fast_pattern arguments
     bool no_case;            // toggle case sensitivity
     bool relative;           // do relative pattern searching
     bool literal;            // true for plain contents only
+    bool fp;                 // for fast_pattern arguments
 
     uint16_t fp_offset;
     uint16_t fp_length;
@@ -100,5 +104,11 @@ inline bool PatternMatchData::can_be_fp() const
     return true;
 }
 
+// pmd related utilities
+struct OptFpList;
+
+PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection);
+bool is_fast_pattern_only(OptFpList*);
+
 #endif
 
index 3e043d98a8233cab0b2a8e105450e3fbb74b8fe3..7378438de92ab3fc26c4dd3f0e206b7c7b6219a0 100644 (file)
 #include "main/snort_config.h"
 #include "utils/util.h"
 
-/*
-**
-**  NAME
-**    prmNewMap::
-**
-**  DESCRIPTION
-**    Allocate new PORT_RULE_MAP and return pointer.
-**
-**  FORMAL INPUTS
-**    None
-**
-**  FORMAL OUTPUT
-**    PORT_RULE_MAP * - NULL if failed, ptr otherwise.
-**
-*/
 PORT_RULE_MAP* prmNewMap()
 {
     PORT_RULE_MAP* p = (PORT_RULE_MAP*)snort_calloc(sizeof(PORT_RULE_MAP));
@@ -66,10 +51,6 @@ PORT_RULE_MAP* prmNewMap()
 }
 
 /*
-**
-**  NAME
-**    prmFindRuleGroup::
-**
 **  DESCRIPTION
 **    Given a PORT_RULE_MAP, this function selects the PortGroup or
 **    PortGroups necessary to fully match a given dport, sport pair.
@@ -79,14 +60,6 @@ PORT_RULE_MAP* prmNewMap()
 **    both th src and dst PortGroup ptrs are set.  If neither of the
 **    ports are unique, then the gen PortGroup ptr is set.
 **
-**  FORMAL INPUTS
-**    PORT_RULE_MAP * - the PORT_RULE_MAP to pick PortGroups from.
-**    int             - the dst port value (0->64K or -1 for generic)
-**    int             - the src port value (0->64K or -1 for generic)
-**    PortGroup **   - the src PortGroup ptr to set.
-**    PortGroup **   - the dst PortGroup ptr to set.
-**    PortGroup **   - the generic PortGroup ptr to set.
-**
 **  FORMAL OUTPUT
 **    int -  0: Don't evaluate
 **           1: There are port groups to evaluate
@@ -174,156 +147,3 @@ int prmFindRuleGroupUdp(PORT_RULE_MAP* prm, int dport, int sport, PortGroup** sr
     return prmFindRuleGroup(prm, dport, sport, src, dst, gen);
 }
 
-int prmFindGenericRuleGroup(PORT_RULE_MAP* p, PortGroup** gen)
-{
-    if ( !p or !gen )
-    {
-        return 0;
-    }
-
-    *gen = NULL;
-    if ((p->prmGeneric != NULL) && (p->prmGeneric->rule_count > 0))
-    {
-        if (snort_conf->fast_pattern_config->get_split_any_any())
-        {
-            *gen = p->prmGeneric;
-            return 1;
-        }
-    }
-    return 0;
-}
-
-/*
-** Access each Rule group by index (0-MAX_PORTS)
-*/
-static PortGroup* prmFindDstRuleGroup(PORT_RULE_MAP* p, int port)
-{
-    if ( port < 0 || port >= MAX_PORTS )
-        return 0;
-
-    if ( p->prmDstPort[port])
-        return p->prmDstPort[port];
-
-    return 0;
-}
-
-/*
-** Access each Rule group by index (0-MAX_PORTS)
-*/
-static PortGroup* prmFindSrcRuleGroup(PORT_RULE_MAP* p, int port)
-{
-    if ( port < 0 || port >= MAX_PORTS )
-        return 0;
-
-    if ( p->prmSrcPort[port])
-        return p->prmSrcPort[port];
-
-    return 0;
-}
-
-/*
-**
-**  NAME
-**    prmShowEventStats::
-**
-**  DESCRIPTION
-**    This function is used at the close of the Fast Packet
-**    inspection.  It tells how many non-qualified and qualified
-**    hits occurred for each PortGroup.  A non-qualified hit
-**    is defined by an initial match against a packet, but upon
-**    further inspection a hit was not validated.  Non-qualified
-**    hits occur because we can match on the most unique aspect
-**    of a packet, this is the content.  Snort has other flags
-**    then content though, so once we hit a content match we must
-**    verify these additional flags.  Sometimes these flags do
-**    not pass the validation.  A qualified hit is an event that
-**    has been fully qualified, and has been put in the event
-**    cache for event selection.  Qualified hits are not a subset
-**    of non-qualified hits.  Ideally, non-qualified hits should
-**    be zero.  The reason for these stats is that it allows
-**    users to trouble shoot PortGroups.  A poorly written rule
-**    may cause many non-qualified events, and these stats
-**    allow the user to track this down.
-**
-**  FORMAL INPUTS
-**    PORT_RULE_MAP * -  the PORT_RULE_MAP to show stats on.
-**
-**  FORMAL OUTPUT
-**    int - 0 is successful.
-**
-*/
-int prmShowEventStats(PORT_RULE_MAP* p)
-{
-    int i;
-    PortGroup* pg;
-
-    int NQEvents = 0;
-    int QEvents = 0;
-
-    LogMessage("Packet Classification Rule Manager Stats ----\n");
-    LogMessage("NumDstGroups   : %d\n",p->prmNumDstGroups);
-    LogMessage("NumSrcGroups   : %d\n",p->prmNumSrcGroups);
-    LogMessage("\n");
-    LogMessage("NumDstRules    : %d\n",p->prmNumDstRules);
-    LogMessage("NumSrcRules    : %d\n",p->prmNumSrcRules);
-    LogMessage("NumGenericRules: %d\n",p->prmNumGenericRules);
-    LogMessage("\n");
-
-    LogMessage("%d Dst Groups In Use, %d Unique Rules, includes generic\n",p->prmNumDstGroups,
-        p->prmNumDstRules);
-    for (i=0; i<MAX_PORTS; i++)
-    {
-        pg = prmFindDstRuleGroup(p, i);
-        if (pg)
-        {
-            NQEvents += pg->match_count;
-            QEvents  += pg->event_count;
-
-            if ( pg->match_count + pg->event_count )
-            {
-                LogMessage("  Dst Port %5d : %d group entries \n",i, pg->rule_count);
-                LogMessage("    NQ Events  : %d\n", pg->match_count);
-                LogMessage("     Q Events  : %d\n", pg->event_count);
-            }
-        }
-    }
-
-    LogMessage("%d Src Groups In Use, %d Unique Rules, includes generic\n",p->prmNumSrcGroups,
-        p->prmNumSrcRules);
-    for (i=0; i<MAX_PORTS; i++)
-    {
-        pg = prmFindSrcRuleGroup(p, i);
-        if (pg)
-        {
-            NQEvents += pg->match_count;
-            QEvents += pg->event_count;
-
-            if ( pg->match_count + pg->event_count )
-            {
-                LogMessage("  Src Port %5d : %d group entries \n",i, pg->rule_count);
-                LogMessage("    NQ Events  : %d\n", pg->match_count);
-                LogMessage("     Q Events  : %d\n", pg->event_count);
-            }
-        }
-    }
-
-    pg = p->prmGeneric;
-    if (pg)
-    {
-        NQEvents += pg->match_count;
-        QEvents += pg->event_count;
-
-        if ( pg->match_count + pg->event_count )
-        {
-            LogMessage("  Generic Rules : %d group entries\n", pg->rule_count);
-            LogMessage("    NQ Events   : %d\n", pg->match_count);
-            LogMessage("     Q Events   : %d\n", pg->event_count);
-        }
-    }
-
-    LogMessage("Total NQ Events : %d\n", NQEvents);
-    LogMessage("Total  Q Events  : %d\n", QEvents);
-
-    return 0;
-}
-
index 8fee0f112d217ad0802b965d43a4d2cce3a1e9b7..76a579ed0178af411ad50340cb66cbfafb4d8a37 100644 (file)
@@ -50,10 +50,6 @@ struct PORT_RULE_MAP
 
 PORT_RULE_MAP* prmNewMap();
 
-int prmShowEventStats(PORT_RULE_MAP*);
-
-int prmFindGenericRuleGroup(PORT_RULE_MAP*, PortGroup**);
-
 int prmFindRuleGroupTcp(PORT_RULE_MAP*, int, int, PortGroup**, PortGroup**, PortGroup**);
 int prmFindRuleGroupUdp(PORT_RULE_MAP*, int, int, PortGroup**, PortGroup**, PortGroup**);
 int prmFindRuleGroupIp(PORT_RULE_MAP*, int, PortGroup**, PortGroup**);
index cab80f44f8579228f5160ade303872cc3d309c1e..6502dc9e3220c88fbda1fecc2be3662a9badd742 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include "log/messages.h"
-#include "main/snort_config.h"
 #include "hash/sfghash.h"
-#include "utils/sflsq.h"
 #include "ips_options/ips_flow.h"
-#include "detection/treenodes.h"
-#include "detection/fp_detect.h"
+#include "log/messages.h"
+#include "main/snort_config.h"
 #include "parser/parser.h"
+#include "utils/sflsq.h"
+
+#include "fp_create.h"
+#include "treenodes.h"
 
 //-------------------------------------------------------------------------
 // service map stuff
index b31cea5a30ac64a20336a0e4ab97c6198d3165b7..f2ad4600ab67a12bc9a5c5b64a4c33af77c28166 100644 (file)
@@ -85,7 +85,7 @@ public:
     { return CAT_NONE; }
 
     // for fast-pattern options like content
-    virtual struct PatternMatchData* get_pattern(int /*proto*/, RuleDirection)
+    virtual struct PatternMatchData* get_pattern(int /*proto*/, RuleDirection = RULE_WO_DIR)
     { return nullptr; }
 
     static int eval(void* v, Cursor& c, Packet* p)
index 6cfbbfffce8f2d82e078524d1bec15a57671c068..f2e295a06cbb1b005a5c251d3e36c4b5dca482bf 100644 (file)
 
 #include "framework/range.h"
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
index 4b568d556f3ad9fbeeaf6f5d1117b24734665c26..c0d3f4042c99dcc7dba6dc48ea693fd2da7d1d32 100644 (file)
@@ -217,9 +217,6 @@ static const Parameter search_engine_params[] =
     { "debug_print_rule_groups_compiled", Parameter::PT_BOOL, nullptr, "false",
       "prints compiled rule group information" },
 
-    { "debug_print_fast_pattern", Parameter::PT_BOOL, nullptr, "false",
-      "print fast pattern info for each rule" },
-
     { "max_pattern_len", Parameter::PT_INT, "0:", "0",
       "truncate patterns when compiling into state machine (0 means no maximum)" },
 
@@ -232,12 +229,15 @@ static const Parameter search_engine_params[] =
     { "search_method", Parameter::PT_DYNAMIC, (void*)&get_search_methods, "ac_bnfa",
       "set fast pattern algorithm - choose available search engine" },
 
-    { "split_any_any", Parameter::PT_BOOL, nullptr, "false",
-      "evaluate any-any rules separately to save memory" },
-
     { "search_optimize", Parameter::PT_BOOL, nullptr, "true",
       "tweak state machine construction for better performance" },
 
+    { "show_fast_patterns", Parameter::PT_BOOL, nullptr, "false",
+      "print fast pattern info for each rule" },
+
+    { "split_any_any", Parameter::PT_BOOL, nullptr, "false",
+      "evaluate any-any rules separately to save memory" },
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -312,9 +312,6 @@ bool SearchEngineModule::set(const char*, Value& v, SnortConfig* sc)
         if ( v.get_bool() )
             fp->set_debug_print_rule_groups_compiled();
     }
-    else if ( v.is("debug_print_fast_pattern") )
-        fp->set_debug_print_fast_patterns(v.get_bool());
-
     else if ( v.is("max_pattern_len") )
         fp->set_max_pattern_len(v.get_long());
 
@@ -329,12 +326,15 @@ bool SearchEngineModule::set(const char*, Value& v, SnortConfig* sc)
         if ( !fp->set_detect_search_method(v.get_string()) )
             return false;
     }
-    else if ( v.is("split_any_any") )
-        fp->set_split_any_any(v.get_long());
-
     else if ( v.is("search_optimize") )
         fp->set_search_opt(v.get_long());
 
+    else if ( v.is("show_fast_patterns") )
+        fp->set_debug_print_fast_patterns(v.get_bool());
+
+    else if ( v.is("split_any_any") )
+        fp->set_split_any_any(v.get_long());
+
     else
         return false;
 
index 5db2c8106de743fee6865f21595ae403a310a6a9..af65c8f248e0e6fee19873e3074597aa89bfc232 100644 (file)
@@ -50,6 +50,7 @@
 #include "detection/signature.h"
 #include "detection/fp_config.h"
 #include "detection/fp_create.h"
+#include "detection/fp_utils.h"
 #include "detection/pattern_match_data.h"
 #include "detection/sfrim.h"
 #include "main/snort_debug.h"
@@ -76,9 +77,6 @@
 #include "managers/so_manager.h"
 #include "target_based/snort_protocols.h"
 
-#define RULE_DIR_OPT__DIRECTIONAL    "->"
-#define RULE_DIR_OPT__BIDIRECTIONAL  "<>"
-
 #define SRC  0
 #define DST  1
 
@@ -87,9 +85,8 @@ struct rule_count_t
 {
     int src;
     int dst;
-    int any;  /* any-any */
-    int both;  /* src+dst ports specified */
-    int nfp;  /* no content */
+    int any;
+    int both;
 };
 
 static int rule_count = 0;
@@ -123,7 +120,7 @@ static bool s_ignore = false;  // for skipping drop rules when not inline, etc.
  */
 static int FinishPortListRule(
     RulePortTables* port_tables, RuleTreeNode* rtn, OptTreeNode* otn,
-    int proto, bool has_fp, FastPatternConfig* fp)
+    int proto, FastPatternConfig* fp)
 {
     int large_port_group = 0;
     int src_cnt = 0;
@@ -191,10 +188,6 @@ static int FinishPortListRule(
      * and use as reference in Port Objects */
     rim_index = otn->ruleIndex;
 
-    /* Add up the nfp rules */
-    if ( !has_fp )
-        prc->nfp++;
-
     /* If not an any-any rule test for port bleedover, if we are using a
      * single rule group, don't bother */
     if (!fp->get_single_rule_group() &&
@@ -291,20 +284,16 @@ static int FinishPortListRule(
     /* add rule index to dst table if we have a specific dst port or port list */
     if (!(rtn->flags & ANY_DST_PORT))
     {
-        PortObject* pox;
-
         prc->dst++;
-
-        DebugMessage(DEBUG_PORTLISTS,
-            "Finishing rule: dst port rule\n");
+        DebugMessage(DEBUG_PORTLISTS, "Finishing rule: dst port rule\n");
 
         /* find the proper port object */
-        pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
-        if (pox == NULL)
+        PortObject* pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject);
+        if ( !pox )
         {
             /* Create a permanent port object */
             pox = PortObjectDupPorts(rtn->dst_portobject);
-            if (pox == NULL)
+            if ( !pox )
             {
                 ParseError("could not dup a port object - out of memory.");
                 return -1;
@@ -320,10 +309,10 @@ static int FinishPortListRule(
         if (rtn->flags & BIDIRECTIONAL)
         {
             pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject);
-            if (pox == NULL)
+            if ( !pox )
             {
                 pox = PortObjectDupPorts(rtn->dst_portobject);
-                if (pox == NULL)
+                if ( !pox )
                 {
                     ParseError("could not dup a bidir-port object - out of memory.");
                     return -1;
@@ -339,20 +328,17 @@ static int FinishPortListRule(
     /* add rule index to src table if we have a specific src port or port list */
     if (!(rtn->flags & ANY_SRC_PORT))
     {
-        PortObject* pox;
-
         prc->src++;
+        PortObject* pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
 
-        pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject);
-        if (pox == NULL)
+        if ( !pox )
         {
             pox = PortObjectDupPorts(rtn->src_portobject);
-            if (pox == NULL)
+            if ( !pox )
             {
                 ParseError("could not dup a port object - out of memory.");
                 return -1;
             }
-
             PortTableAddObject(srcTable, pox);
         }
 
@@ -362,10 +348,10 @@ static int FinishPortListRule(
         if (rtn->flags & BIDIRECTIONAL)
         {
             pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject);
-            if (pox == NULL)
+            if ( !pox )
             {
                 pox = PortObjectDupPorts(rtn->src_portobject);
-                if (pox == NULL)
+                if ( !pox )
                 {
                     ParseError("could not dup a bidir-port object - out of memory.");
                     return -1;
@@ -373,11 +359,9 @@ static int FinishPortListRule(
 
                 PortTableAddObject(dstTable, pox);
             }
-
             PortObjectAddRule(pox, rim_index);
         }
     }
-
     return 0;
 }
 
@@ -389,7 +373,6 @@ static int ValidateIPList(sfip_var_t* addrset, const char* token)
             "destination IP in a rule. IP list: %s.", token);
         return -1;
     }
-
     return 0;
 }
 
@@ -407,16 +390,13 @@ static int ProcessIP(
     {
         int ret;
 
-        if (rtn->sip == NULL)
+        if ( !rtn->sip )
         {
             sfip_var_t* tmp = sfvt_lookup_var(ip_vartable, addr);
-            if (tmp != NULL)
+            if ( tmp )
             {
                 rtn->sip = sfvar_create_alias(tmp, tmp->name);
-                if (rtn->sip == NULL)
-                    ret = SFIP_FAILURE;
-                else
-                    ret = SFIP_SUCCESS;
+                ret = rtn->sip ?  SFIP_SUCCESS : SFIP_FAILURE;
             }
             else
             {
@@ -466,16 +446,13 @@ static int ProcessIP(
     {
         int ret;
 
-        if (rtn->dip == NULL)
+        if ( !rtn->dip )
         {
             sfip_var_t* tmp = sfvt_lookup_var(ip_vartable, addr);
-            if (tmp != NULL)
+            if ( tmp )
             {
                 rtn->dip = sfvar_create_alias(tmp, tmp->name);
-                if (rtn->dip == NULL)
-                    ret = SFIP_FAILURE;
-                else
-                    ret = SFIP_SUCCESS;
+                ret = rtn->dip ?  SFIP_SUCCESS : SFIP_FAILURE;
             }
             else
             {
@@ -536,7 +513,6 @@ static int ProcessIP(
 *
 *  These should not be confused with the port objects used to merge ports and rules
 *  to build port group objects. Those are generated after the otn processing.
-*
 */
 static PortObject* ParsePortListTcpUdpPort(
     PortVarTable* pvt, PortTable* noname, const char* port_str)
@@ -544,14 +520,14 @@ static PortObject* ParsePortListTcpUdpPort(
     PortObject* portobject;
     POParser poparser;
 
-    if ((pvt == NULL) || (noname == NULL) || (port_str == NULL))
-        return NULL;
+    if ( !pvt or !noname or !port_str )
+        return nullptr;
 
     /* 1st - check if we have an any port */
     if ( strcasecmp(port_str,"any")== 0 )
     {
         portobject = PortVarTableFind(pvt, "any");
-        if (portobject == NULL)
+        if ( !portobject )
             ParseAbort("PortVarTable missing an 'any' variable.");
 
         return portobject;
@@ -566,7 +542,7 @@ static PortObject* ParsePortListTcpUdpPort(
 
         /* look it up  in the port var table */
         portobject = PortVarTableFind(pvt, name);
-        if (portobject == NULL)
+        if ( !portobject )
             ParseAbort("***PortVar Lookup failed on '%s'.", port_str);
 
         DebugFormat(DEBUG_PORTLISTS,"PortVarTableFind: '%s' found!\n", port_str);
@@ -640,7 +616,7 @@ static int ParsePortList(
     RuleTreeNode* rtn, PortVarTable* pvt, PortTable* noname,
     const char* port_str, int dst_flag)
 {
-    PortObject* portobject = NULL;  /* src or dst */
+    PortObject* portobject;  /* src or dst */
 
     /* Get the protocol specific port object */
     if ( rule_proto & (PROTO_BIT__TCP | PROTO_BIT__UDP) )
@@ -650,7 +626,7 @@ static int ParsePortList(
     else /* ICMP, IP  - no real ports just Type and Protocol */
     {
         portobject = PortVarTableFind(pvt, "any");
-        if (portobject == NULL)
+        if ( !portobject )
         {
             ParseError("PortVarTable missing an 'any' variable.");
             return -1;
@@ -698,141 +674,97 @@ static int ParsePortList(
     return 0;
 }
 
-/****************************************************************************
- *
- * Function: TestHeader(RuleTreeNode *, RuleTreeNode *)
- *
- * Purpose: Check to see if the two header blocks are identical
- *
- * Arguments: rule => uh
- *            rtn  => uuuuhhhhh....
- *
- * Returns: 1 if they match, 0 if they don't
- *
- ***************************************************************************/
-static int TestHeader(RuleTreeNode* rule, RuleTreeNode* rtn)
+static bool same_headers(RuleTreeNode* rule, RuleTreeNode* rtn)
 {
-    if ((rule == NULL) || (rtn == NULL))
-        return 0;
+    if ( !rule or !rtn )
+        return false;
 
     if (rule->type != rtn->type)
-        return 0;
+        return false;
 
     if (rule->proto != rtn->proto)
-        return 0;
+        return false;
 
     /* For custom rule type declarations */
     if (rule->listhead != rtn->listhead)
-        return 0;
+        return false;
 
     if (rule->flags != rtn->flags)
-        return 0;
+        return false;
 
-    if ((rule->sip != NULL) && (rtn->sip != NULL) &&
-        (sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL))
-    {
-        return 0;
-    }
+    if ( rule->sip and rtn->sip and sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL )
+        return false;
 
-    if ((rule->dip != NULL) && (rtn->dip != NULL) &&
-        (sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL))
-    {
-        return 0;
-    }
+    if ( rule->dip and rtn->dip and sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL )
+        return false;
 
     /* compare the port group pointers - this prevents confusing src/dst port objects
      * with the same port set, and it's quicker. It does assume that we only have
      * one port object and pointer for each unique port set...this is handled by the
      * parsing and initial port object storage and lookup.  This must be consistent during
      * the rule parsing phase. - man */
-    if ((rule->src_portobject != rtn->src_portobject)
-        || (rule->dst_portobject != rtn->dst_portobject))
+    if ( (rule->src_portobject != rtn->src_portobject)
+        or (rule->dst_portobject != rtn->dst_portobject))
     {
-        return 0;
+        return false;
     }
-
-    return 1;
+    return true;
 }
 
-/**returns matched header node.
-*/
 static RuleTreeNode* findHeadNode(
-    SnortConfig* sc, RuleTreeNode* testNode,
-    PolicyId policyId)
+    SnortConfig* sc, RuleTreeNode* testNode, PolicyId policyId)
 {
-    RuleTreeNode* rtn;
-    OptTreeNode* otn;
     SFGHASH_NODE* hashNode;
 
     for (hashNode = sfghash_findfirst(sc->otn_map);
         hashNode;
         hashNode = sfghash_findnext(sc->otn_map))
     {
-        otn = (OptTreeNode*)hashNode->data;
-        rtn = getRtnFromOtn(otn, policyId);
+        OptTreeNode* otn = (OptTreeNode*)hashNode->data;
+        RuleTreeNode* rtn = getRtnFromOtn(otn, policyId);
 
-        if (TestHeader(rtn, testNode))
+        if (same_headers(rtn, testNode))
             return rtn;
     }
 
-    return NULL;
+    return nullptr;
 }
 
-/****************************************************************************
- *
- * Function: XferHeader(RuleTreeNode *, RuleTreeNode *)
- *
- * Purpose: Transfer the rule block header data from point A to point B
- *
- * Arguments: rule => the place to xfer from
- *            rtn => the place to xfer to
- *
- * Returns: void function
- *
- ***************************************************************************/
-static void XferHeader(RuleTreeNode* test_node, RuleTreeNode* rtn)
+static void XferHeader(RuleTreeNode* from, RuleTreeNode* to)
 {
-    rtn->flags = test_node->flags;
-    rtn->type = test_node->type;
-    rtn->sip = test_node->sip;
-    rtn->dip = test_node->dip;
+    to->flags = from->flags;
+    to->type = from->type;
+    to->sip = from->sip;
+    to->dip = from->dip;
 
-    rtn->proto = test_node->proto;
+    to->proto = from->proto;
 
-    rtn->src_portobject = test_node->src_portobject;
-    rtn->dst_portobject = test_node->dst_portobject;
+    to->src_portobject = from->src_portobject;
+    to->dst_portobject = from->dst_portobject;
 }
 
 /****************************************************************************
- *
- * Function: AddRuleFuncToList(int (*func)(), RuleTreeNode *)
- *
  * Purpose:  Adds RuleTreeNode associated detection functions to the
  *          current rule's function list
  *
  * Arguments: *func => function pointer to the detection function
  *            rtn   => pointer to the current rule
- *
- * Returns: void function
- *
  ***************************************************************************/
 static void AddRuleFuncToList(
     int (* rfunc)(Packet*, RuleTreeNode*, struct RuleFpList*, int),
     RuleTreeNode* rtn)
 {
-    RuleFpList* idx;
-
     DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n");
+    RuleFpList* idx = rtn->rule_func;
 
-    idx = rtn->rule_func;
-    if (idx == NULL)
+    if ( !idx )
     {
         rtn->rule_func = (RuleFpList*)snort_calloc(sizeof(RuleFpList));
         rtn->rule_func->RuleHeadFunc = rfunc;
     }
     else
     {
-        while (idx->next != NULL)
+        while ( idx->next )
             idx = idx->next;
 
         idx->next = (RuleFpList*)snort_calloc(sizeof(RuleFpList));
@@ -842,18 +774,12 @@ static void AddRuleFuncToList(
 }
 
 /****************************************************************************
- *
- * Function: AddrToFunc(RuleTreeNode *, u_long, u_long, int, int)
- *
  * Purpose: Links the proper IP address testing function to the current RTN
  *          based on the address, netmask, and addr flags
  *
  * Arguments: rtn => the pointer to the current rules list entry to attach to
  *            mode => indicates whether this is a rule for the source
  *                    or destination IP for the rule
- *
- * Returns: void function
- *
  ***************************************************************************/
 static void AddrToFunc(RuleTreeNode* rtn, int mode)
 {
@@ -869,7 +795,6 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode)
             DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> ");
             AddRuleFuncToList(CheckSrcIP, rtn);
         }
-
         break;
 
     case DST:
@@ -878,15 +803,11 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode)
             DebugMessage(DEBUG_CONFIGRULES,"CheckDstIP -> ");
             AddRuleFuncToList(CheckDstIP, rtn);
         }
-
         break;
     }
 }
 
 /****************************************************************************
- *
- * Function: PortToFunc(RuleTreeNode *, int, int, int)
- *
  * Purpose: Links in the port analysis function for the current rule
  *
  * Arguments: rtn => the pointer to the current rules list entry to attach to
@@ -894,9 +815,6 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode)
  *            except_flag => indicates negation (logical NOT) of the test
  *            mode => indicates whether this is a rule for the source
  *                    or destination port for the rule
- *
- * Returns: void function
- *
  ***************************************************************************/
 static void PortToFunc(RuleTreeNode* rtn, int any_flag, int except_flag, int mode)
 {
@@ -940,18 +858,8 @@ static void PortToFunc(RuleTreeNode* rtn, int any_flag, int except_flag, int mod
     }
 }
 
-/****************************************************************************
- *
- * Function: SetupRTNFuncList(RuleTreeNode *)
- *
- * Purpose: Configures the function list for the rule header detection
- *          functions (addrs and ports)
- *
- * Arguments: rtn => the pointer to the current rules list entry to attach to
- *
- * Returns: void function
- *
- ***************************************************************************/
+// Configures the function list for the rule header detection
+// functions (addrs and ports)
 static void SetupRTNFuncList(RuleTreeNode* rtn)
 {
     DebugMessage(DEBUG_CONFIGRULES,"Initializing RTN function list!\n");
@@ -990,20 +898,7 @@ static void SetupRTNFuncList(RuleTreeNode* rtn)
     AddRuleFuncToList(RuleListEnd, rtn);
 }
 
-/****************************************************************************
- *
- * Function: ProcessHeadNode(RuleTreeNode *, ListHead *, int)
- *
- * Purpose:  Process the header block info and add to the block list if
- *           necessary
- *
- * Arguments: test_node => data generated by the rules parsers
- *            list => List Block Header refernece
- *            protocol => ip protocol
- *
- * Returns: void function
- *
- ***************************************************************************/
+// Process the header block info and add to the block list if necessary
 static RuleTreeNode* ProcessHeadNode(
     SnortConfig* sc, RuleTreeNode* test_node, ListHead* list)
 {
@@ -1012,7 +907,7 @@ static RuleTreeNode* ProcessHeadNode(
 
     /* if it doesn't match any of the existing nodes, make a new node and
      * stick it at the end of the list */
-    if (rtn == NULL)
+    if ( !rtn )
     {
         DebugMessage(DEBUG_CONFIGRULES,"Building New Chain head node\n");
         head_count++;
@@ -1041,64 +936,45 @@ static RuleTreeNode* ProcessHeadNode(
     return rtn;
 }
 
-/****************************************************************************
- *
- * Function: mergeDuplicateOtn()
- *
- * Purpose:  Conditionally removes duplicate SID/GIDs. Keeps duplicate with
- *           higher revision.  If revision is the same, keeps newest rule.
- *
- * Arguments: otn_cur => The current version
- *            rtn => the RTN chain to check
- *            char => String describing the rule
- *
- * Returns: 0 if original rule stays, 1 if new rule stays
- *
- ***************************************************************************/
+// Conditionally removes duplicate SID/GIDs. Keeps duplicate with
+// higher revision.  If revision is the same, keeps newest rule.
 static int mergeDuplicateOtn(
     SnortConfig* sc, OptTreeNode* otn_cur,
     OptTreeNode* otn_new, RuleTreeNode* rtn_new)
 {
-    RuleTreeNode* rtn_cur = NULL;
-    RuleTreeNode* rtnTmp2 = NULL;
-    unsigned i;
-
     if (otn_cur->proto != otn_new->proto)
     {
-        ParseError("GID %u SID %u in rule duplicates previous rule, with "
-            "different protocol.",
+        ParseError("GID %u SID %u in rule duplicates previous rule, with different protocol.",
             otn_new->sigInfo.generator, otn_new->sigInfo.id);
-        return 0;
+        return true;
     }
 
-    rtn_cur = getRtnFromOtn(otn_cur);
+    RuleTreeNode* rtn_cur = getRtnFromOtn(otn_cur);
 
-    if ((rtn_cur != NULL) && (rtn_cur->type != rtn_new->type))
+    if ( rtn_cur and rtn_cur->type != rtn_new->type )
     {
-        ParseError("GID %u SID %u in rule duplicates previous rule, with "
-            "different type.",
+        ParseError("GID %u SID %u in rule duplicates previous rule, with different type.",
             otn_new->sigInfo.generator, otn_new->sigInfo.id);
-        return 0;
+        return true;
     }
 
     if ( otn_new->sigInfo.rev < otn_cur->sigInfo.rev )
     {
-        //current OTN is newer version. Keep current and discard the new one.
-        //OTN is for new policy group, salvage RTN
+        // current OTN is newer version. Keep current and discard the new one.
+        // OTN is for new policy group, salvage RTN
         deleteRtnFromOtn(otn_new);
 
-        ParseWarning(WARN_RULES,
-            "%u:%u duplicates previous rule. Using revision %u.",
+        ParseWarning(WARN_RULES, "%u:%u duplicates previous rule. Using revision %u.",
             otn_cur->sigInfo.generator, otn_cur->sigInfo.id, otn_cur->sigInfo.rev);
 
-        /* Now free the OTN itself -- this function is also used
-         * by the hash-table calls out of OtnRemove, so it cannot
-         * be modified to delete data for rule options */
+        // Now free the OTN itself -- this function is also used
+        // by the hash-table calls out of OtnRemove, so it cannot
+        // be modified to delete data for rule options
         OtnFree(otn_new);
 
-        //Add rtn to current otn for the first rule instance in a policy,
-        //otherwise ignore it
-        if (rtn_cur == NULL)
+        // Add rtn to current otn for the first rule instance in a policy,
+        // otherwise ignore it
+        if ( !rtn_cur )
         {
             addRtnToOtn(otn_cur, rtn_new);
         }
@@ -1106,17 +982,16 @@ static int mergeDuplicateOtn(
         {
             DestroyRuleTreeNode(rtn_new);
         }
-
-        return 0;
+        return true;
     }
 
-    //delete current rule instance and keep the new one
+    // delete current rule instance and keep the new one
 
-    for (i = 0; i < otn_cur->proto_node_num; i++)
+    for ( unsigned i = 0; i < otn_cur->proto_node_num; ++i )
     {
-        rtnTmp2 = deleteRtnFromOtn(otn_cur, i);
+        RuleTreeNode* rtnTmp2 = deleteRtnFromOtn(otn_cur, i);
 
-        if (rtnTmp2 && (i != get_ips_policy()->policy_id))
+        if ( rtnTmp2 and (i != get_ips_policy()->policy_id) )
         {
             addRtnToOtn(otn_new, rtnTmp2, i);
         }
@@ -1126,98 +1001,20 @@ static int mergeDuplicateOtn(
     {
         if (SnortConfig::conf_error_out())
         {
-            ParseError(
-                "%u:%u:%u duplicates previous rule.",
+            ParseError("%u:%u:%u duplicates previous rule.",
                 otn_new->sigInfo.generator, otn_new->sigInfo.id, otn_new->sigInfo.rev);
-            return 0;
+            return true;
         }
         else
         {
-            ParseWarning(WARN_RULES,
-                "%u:%u duplicates previous rule. Using revision %u.",
+            ParseWarning(WARN_RULES, "%u:%u duplicates previous rule. Using revision %u.",
                 otn_new->sigInfo.generator, otn_new->sigInfo.id, otn_new->sigInfo.rev);
         }
     }
     OtnRemove(sc->otn_map, otn_cur);
     DestroyRuleTreeNode(rtn_cur);
 
-    return 1;
-}
-
-PatternMatchData* get_pmd(OptFpList* ofl, int proto, RuleDirection direction)
-{
-    if ( !ofl->ips_opt )
-        return nullptr;
-
-    return ofl->ips_opt->get_pattern(proto, direction);
-}
-
-static void finalize_content(OptFpList* ofl)
-{
-    PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
-
-    if ( !pmd )
-        return;
-
-    if ( pmd->negated )
-        pmd->last_check = (PmdLastCheck*)snort_calloc(
-            ThreadConfig::get_instance_max(), sizeof(*pmd->last_check));
-}
-
-bool is_fast_pattern_only(OptFpList* ofl)
-{
-    PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
-
-    if ( !pmd )
-        return false;
-
-    return pmd->fp_only > 0;
-}
-
-static void clear_fast_pattern_only(OptFpList* ofl)
-{
-    PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
-
-    if ( pmd && pmd->fp_only > 0 )
-        pmd->fp_only = 0;
-}
-
-static void ValidateFastPattern(OptTreeNode* otn)
-{
-    OptFpList* fp = nullptr;
-    bool relative_is_bad_mkay = false;
-
-    for (OptFpList* fpl = otn->opt_func; fpl; fpl = fpl->next)
-    {
-        // a relative option is following a fast_pattern/only and
-        if ( relative_is_bad_mkay )
-        {
-            if (fpl->isRelative)
-            {
-                assert(fp);
-                clear_fast_pattern_only(fp);
-            }
-        }
-
-        // reset the check if one of these are present.
-        if ( fpl->ips_opt and !fpl->ips_opt->get_pattern(0, RULE_WO_DIR))
-        {
-            if ( fpl->ips_opt->get_cursor_type() > CAT_NONE )
-                relative_is_bad_mkay = false;
-        }
-        // set/unset the check on content options.
-        else
-        {
-            if ( is_fast_pattern_only(fpl) )
-            {
-                fp = fpl;
-                relative_is_bad_mkay = true;
-            }
-            else
-                relative_is_bad_mkay = false;
-        }
-        finalize_content(fpl);
-    }
+    return false;
 }
 
 int get_rule_count()
@@ -1256,10 +1053,10 @@ void parse_rule_print()
     LogCount("option chains", otn_count);
     LogCount("chain headers", head_count);
 
-    unsigned ip = ipCnt.src + ipCnt.dst + ipCnt.any + ipCnt.both + ipCnt.nfp;
-    unsigned icmp = icmpCnt.src + icmpCnt.dst + icmpCnt.any + icmpCnt.both + icmpCnt.nfp;
-    unsigned tcp = tcpCnt.src + tcpCnt.dst + tcpCnt.any + tcpCnt.both + tcpCnt.nfp;
-    unsigned udp = udpCnt.src + udpCnt.dst + udpCnt.any + udpCnt.both + udpCnt.nfp;
+    unsigned ip = ipCnt.src + ipCnt.dst + ipCnt.any + ipCnt.both;
+    unsigned icmp = icmpCnt.src + icmpCnt.dst + icmpCnt.any + icmpCnt.both;
+    unsigned tcp = tcpCnt.src + tcpCnt.dst + tcpCnt.any + tcpCnt.both;
+    unsigned udp = udpCnt.src + udpCnt.dst + udpCnt.any + udpCnt.both;
 
     if ( !ip and !icmp and !tcp and !udp )
         return;
@@ -1283,10 +1080,6 @@ void parse_rule_print()
         LogMessage("%8s%8u%8u%8u%8u\n", "both",
             tcpCnt.both, udpCnt.both, icmpCnt.both, ipCnt.both);
 
-    if ( tcpCnt.nfp || udpCnt.nfp || icmpCnt.nfp || ipCnt.nfp )
-        LogMessage("%8s%8u%8u%8u%8u\n", "slow",
-            tcpCnt.nfp, udpCnt.nfp, icmpCnt.nfp, ipCnt.nfp);
-
     LogMessage("%8s%8u%8u%8u%8u\n", "total", tcp, udp, icmp, ip);
 }
 
@@ -1368,10 +1161,10 @@ void parse_rule_dir(SnortConfig*, const char* s, RuleTreeNode& rtn)
     if ( s_ignore )
         return;
 
-    if (strcmp(s, RULE_DIR_OPT__BIDIRECTIONAL) == 0)
+    if (strcmp(s, "<>") == 0)
         rtn.flags |= BIDIRECTIONAL;
 
-    else if ( strcmp(s, RULE_DIR_OPT__DIRECTIONAL) )
+    else if ( strcmp(s, "->") )
         ParseError("illegal direction specifier: %s", s);
 }
 
@@ -1465,8 +1258,6 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot
         }
     }
 
-    bool has_fp = set_fp_content(otn);
-
     /* The IPs in the test node get free'd in ProcessHeadNode if there is
      * already a matching RTN.  The portobjects will get free'd when the
      * port var table is free'd */
@@ -1481,7 +1272,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot
     {
         otn->ruleIndex = otn_dup->ruleIndex;
 
-        if (mergeDuplicateOtn(sc, otn_dup, otn, new_rtn) == 0)
+        if ( mergeDuplicateOtn(sc, otn_dup, otn, new_rtn) )
         {
             /* We are keeping the old/dup OTN and trashing the new one
              * we just created - it's free'd in the remove dup function */
@@ -1524,7 +1315,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot
     OptFpList* fpl = AddOptFuncToList(OptListEnd, otn);
     fpl->type = RULE_OPTION_TYPE_LEAF_NODE;
 
-    ValidateFastPattern(otn);
+    validate_fast_pattern(otn);
     OtnLookupAdd(sc->otn_map, otn);
 
     if ( is_service_protocol(otn->proto) )
@@ -1537,7 +1328,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot
      * After otn processing we can finalize port object processing for this rule
      */
     if ( FinishPortListRule(
-        sc->port_tables, new_rtn, otn, rtn.proto, has_fp, sc->fast_pattern_config) )
+        sc->port_tables, new_rtn, otn, rtn.proto, sc->fast_pattern_config) )
         ParseError("Failed to finish a port list rule.");
 
     return nullptr;
index 0f2b15325026def0ac23d9994c38c10cf622a2a2..f64e9f2533609b16a0a60353c2d6dda9e440bf30 100644 (file)
@@ -27,51 +27,22 @@ void PortGroup::add_rule()
     rule_count++;
 }
 
-/*
-**
-**  DESCRIPTION
-**    Adds a RULE_NODE to a PortGroup.  This particular
-**    function is specific in that it adds "no content" rules.
-**    A "no content" rule is a snort rule that has no "content"
-**    or "uri" flag, and hence does not need to be pattern
-**    matched.
-**
-**    Each RULE_NODE in a PortGroup is given a RULE_NODE
-**    ID.  This allows us to track particulars as to what
-**    rules have been alerted upon, and allows other neat
-**    things like correlating events on different streams.
-**    The RULE_NODE IDs may not be consecutive, because
-**    we can add RULE_NODES into "content", "uri", and
-**    "no content" lists.
-**
-**  FORMAL INPUTS
-**    PortGroup* - PortGroup to add the rule to.
-**    void* - ptr to the user information
-**
-**  FORMAL OUTPUT
-**    int - 0 is successful, 1 is failure
-**
-*/
 bool PortGroup::add_nfp_rule(void* rd)
 {
     if ( !nfp_head )
     {
-        nfp_head = (RULE_NODE*)snort_calloc(sizeof(RULE_NODE));
+        nfp_head = (RULE_NODE*)snort_alloc(sizeof(RULE_NODE));
         nfp_tail = nfp_head;
-        nfp_head->rnNext = 0;
-        nfp_head->rnRuleData = rd;
+        nfp_head->rnNext = nullptr;
     }
     else
     {
-        nfp_tail->rnNext = (RULE_NODE*)snort_calloc(sizeof(RULE_NODE));
+        nfp_tail->rnNext = (RULE_NODE*)snort_alloc(sizeof(RULE_NODE));
         nfp_tail = nfp_tail->rnNext;
-        nfp_tail->rnNext = 0;
-        nfp_tail->rnRuleData = rd;
+        nfp_tail->rnNext = nullptr;
     }
 
-    /*
-    **  Set RULE_NODE ID to unique identifier
-    */
+    nfp_tail->rnRuleData = rd;
     nfp_tail->iRuleNodeID = rule_count;
 
     nfp_rule_count++;
index 5dacd02919e301b5bd718de3d5606effd84ad7e3..ed34e658da39df678265a0b41185ab7b87acde3d 100644 (file)
@@ -63,10 +63,6 @@ struct PortGroup
     unsigned rule_count;
     unsigned nfp_rule_count;
 
-    // FIXIT-L these runtime counts are only valid with one packet thread
-    unsigned match_count;
-    unsigned event_count;
-
     void add_rule();
     bool add_nfp_rule(void*);
     void delete_nfp_rules();
index 75a1862b589fdeef9c3f4adbd750ba51dc86e486..4d523276cd0c793f49f2534d9f355d4070a72f93 100644 (file)
@@ -190,7 +190,7 @@ const PegInfo daq_names[] =
 const PegInfo pc_names[] =
 {
     { "analyzed", "packets sent to detection" },
-    { "slow searches", "non-fast pattern rule evaluations" },
+    { "hard evals", "non-fast pattern rule evaluations" },
     { "raw searches", "fast pattern searches in raw packet data" },
     { "cooked searches", "fast pattern searches in cooked packet data" },
     { "pkt searches", "fast pattern searches in packet data" },
@@ -322,7 +322,6 @@ void PrintStatistics()
     timing_stats();
 
     // FIXIT-L below stats need to be made consistent with above
-    fpShowEventStats(snort_conf);
     print_thresholding(snort_conf->threshold_config, 1);
 
     {
index 0f2e9a2ba89f000d46a89a230f8c800ca402e634..4a98a84443ee4b8db4fdc3a8984779aadeb420f9 100644 (file)
@@ -41,7 +41,7 @@ typedef std::vector<unsigned> IndexVec;
 struct PacketCount
 {
     PegCount total_from_daq;
-    PegCount slow_searches;
+    PegCount hard_evals;
     PegCount raw_searches;
     PegCount cooked_searches;
     PegCount pkt_searches;
index d507462a29469090ac56d5f15acb2644daeed400..c451599e279457a29e21ba0ec1a566044fa375d6 100644 (file)
@@ -111,9 +111,8 @@ bool Detection::convert(std::istringstream& data_stream)
         }
         else if (!keyword.compare("debug-print-fast-pattern"))
         {
-            table_api.add_diff_option_comment("debug-print-fast-pattern",
-                "debug_print_fast_pattern");
-            tmpval = table_api.add_option("debug_print_fast_pattern", true);
+            table_api.add_diff_option_comment("debug-print-fast-pattern", "show_fast_patterns");
+            tmpval = table_api.add_option("show_fast_patterns", true);
         }
         else if (!keyword.compare("max_queue_events"))
         {