]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
implemented default fp selection
authorRuss Combs <rucombs@cisco.com>
Tue, 1 Jul 2014 12:43:56 +0000 (08:43 -0400)
committerRuss Combs <rucombs@cisco.com>
Tue, 1 Jul 2014 12:43:56 +0000 (08:43 -0400)
ChangeLog
configure.ac
lua/snort.lua
src/detection/fpcreate.cc
src/ips_options/ips_content.cc
src/ips_options/ips_content.h
src/ips_options/ips_raw_data.cc
src/service_inspectors/nhttp_inspect/nhttp_api.cc
src/service_inspectors/nhttp_inspect/nhttp_inspect.cc
src/service_inspectors/nhttp_inspect/nhttp_inspect.h

index fb75589fea16a55c65c5833924908f74ad1db45f..51468945e46bbe849560c1456ec144976f845736 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+96
+-- finished default fp selection
+-- added NHttpInspect::get_buf() and related
+
 95
 -- added some wizard module foo
 -- fixed cmake build with static inspectors for wizard and binder
index e3677261dbe5abf0b0ae612d641ef1a176248cf8..b343d2311bb0ab60eec9dcc719ac2f49ad617890 100644 (file)
@@ -25,7 +25,7 @@
 # initialization
 #--------------------------------------------------------------------------
 
-AC_INIT([snort], [2.10.095])
+AC_INIT([snort], [2.10.096])
 AC_PREREQ([2.68])
 
 AC_CONFIG_SRCDIR([src/main.h])
index 8838df330404d6e6e69dbf6e5f8b0f5df483f0d4..5bca86a5a10ee5dc093b060281af26e00ea91f73 100644 (file)
@@ -328,7 +328,7 @@ hi_x =
     post_depth = 65495,
 }
 
---nhttp_inspect = { }
+nhttp_inspect = { }
 
 ---------------------------------------------------------------------------
 -- ftp / telnet normalization and anomaly detection
@@ -560,9 +560,10 @@ default_rules =
 #alert tcp any any -> any any ( sid:412; pcre:"/ABA/"; pcre:"/AC/"; )
 #alert tcp any any -> any any ( sid:414; pcre:"/ABA/"; pcre:"/C/R"; )
 
-alert ( gid:134; sid:1; )
-alert ( gid:134; sid:2; )
-alert ( gid:134; sid:3; )
+#alert ( gid:134; sid:1; )
+#alert ( gid:134; sid:2; )
+#alert ( gid:134; sid:3; )
+alert tcp any any -> any 80 ( sid:2; rev:3; http_uri; content:"evil", nocase, fast_pattern; )
 ]]
 
 network =
@@ -573,9 +574,9 @@ network =
 -- put classic rules and includes in the include file and/or rules string
 ips =
 {
-    include = '../active.rules',
+    --include = '../active.rules',
     rules = default_rules,
-    enable_builtin_rules = false
+    enable_builtin_rules = true
 }
 
 --[[
@@ -637,30 +638,30 @@ telnet_commands =
     '|FF FC|', '|FF FD|', '|FF FE|', '|FF FF|'
 }
 
-xwizard =
+wizard =
 {
     spells =
     {
         { service = 'ftp', proto = 'tcp', client_first = false,
-          to_client = ftp_commands, to_server = { '220*FTP' } },
+          to_server = ftp_commands, to_client = { '220*FTP' } },
 
         { service = 'http', proto = 'tcp', client_first = true,
           to_server = default_http_methods, to_client = { 'HTTP/' } },
 
         { service = 'imap', proto = 'tcp', client_first = false,
-          to_client = { 'LOGIN', 'AUTHENTICATE', 'STARTTLS' },
-          to_server = { '**OK', '**BYE' } },
+          to_server = { 'LOGIN', 'AUTHENTICATE', 'STARTTLS' },
+          to_client = { '**OK', '**BYE' } },
 
         { service = 'pop', proto = 'tcp', client_first = false,
-          to_client = { 'USER', 'APOP' },
-          to_server = { '+OK', '-ERR' } },
+          to_server = { 'USER', 'APOP' },
+          to_client = { '+OK', '-ERR' } },
 
         { service = 'sip', proto = 'tcp', client_first = true,
           to_server = sip_methods, to_client = { 'SIP/' } },
 
         { service = 'smtp', proto = 'tcp', client_first = false,
-          to_client = { 'HELO', 'EHLO' },
-          to_server = { '220*SMTP', '220*MAIL' } },
+          to_server = { 'HELO', 'EHLO' },
+          to_client = { '220*SMTP', '220*MAIL' } },
 
         { service = 'ssh', proto = 'tcp', client_first = true,
           to_server = { '*SSH' }, to_client = { '*SSH' } }
@@ -733,8 +734,8 @@ binder =
     --{ when = target_x, use = { type = 'http_server', name = 'hi_x' } },
 
     -- classic ports only config
-    { when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'http_server' } },
-    --{ when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'nhttp_inspect' } },
+    --{ when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'http_server' } },
+    { when = { proto = 'tcp', ports = HTTP_PORTS }, use = { type = 'nhttp_inspect' } },
     { when = { proto = 'tcp', ports = FTP_PORTS }, use = { type = 'ftp_server' } },
     { when = { proto = 'tcp', ports = RPC_PORTS }, use = { type = 'rpc_decode' } },
 
index cd481804a7ecf07ee7068fce371d3f3fbd031433..dee986f7d36a9408785233be6c017368c153d4c2 100644 (file)
@@ -81,16 +81,14 @@ static void fpDeletePortGroup(void *);
 static void fpDeletePMX(void *data);
 static int fpGetFinalPattern(FastPatternConfig *fp, PatternMatchData *pmd,
         char **ret_pattern, int *ret_bytes);
-static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn);
-static int fpFinishPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, PmType pm_type,
+static int fpFinishPortGroupRule(SnortConfig *sc, PORT_GROUP *pg,
         OptTreeNode *otn, PatternMatchData *pmd, FastPatternConfig *fp);
 static int fpFinishPortGroup(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp);
 static int fpAllocPms(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp);
 static int fpAddPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp);
 static int fpAddPortGroupPrmx(PORT_GROUP *pg, OptTreeNode *otn, int cflag);
-static inline int IsPmdFpEligible(PatternMatchData *content);
 static void PrintFastPatternInfo(OptTreeNode *otn, PatternMatchData *pmd,
-        const char *pattern, int pattern_length, PmType pm_type);
+        const char *pattern, int pattern_length);
 
 static const char *pm_type_strings[PM_TYPE__MAX] =
 {
@@ -859,48 +857,94 @@ static int FLP_Trim( char * p, int plen, char ** buff )
     return size;
  }
 
-static inline int IsPmdFpEligible(PatternMatchData *content)
+static bool pmd_can_be_fp(PatternMatchData* pmd, CursorActionType cat)
 {
-    if (content == NULL)
-        return 0;
+    if ( !pmd->pattern_buf || !pmd->pattern_size )
+        return false;
 
-    if ((content->pattern_buf != NULL) && (content->pattern_size != 0))
-    {
-        if (content->negated)
-        {
-            /* Negative contents can only be considered if they are not relative
-             * and don't have any offset or depth.  This is because the pattern
-             * matcher does not take these into consideration and may find the
-             * content in a non-relevant section of the payload and thus disable
-             * the rule when it shouldn't be.
-             * Also case sensitive patterns cannot be considered since patterns
-             * are inserted into the pattern matcher without case which may
-             * lead to false negatives */
-            if (content->relative || !content->no_case
-                    || (content->offset != 0) || (content->depth != 0))
-            {
-                return 0;
-            }
-        }
+    if ( pmd->relative )
+        return false;
 
-        return 1;
-    }
+    if ( cat <= CAT_SET_OTHER )
+        return false;
 
-    return 0;
+    if ( !pmd->negated )
+        return true;
+
+    /* Negative contents can only be considered if they are not relative
+     * and don't have any offset or depth.  This is because the pattern
+     * matcher does not take these into consideration and may find the
+     * content in a non-relevant section of the payload and thus disable
+     * the rule when it shouldn't be.
+     * Also case sensitive patterns cannot be considered since patterns
+     * are inserted into the pattern matcher without case which may
+     * lead to false negatives */
+    if ( pmd->relative || !pmd->no_case ||
+         pmd->offset || pmd->depth )
+        return false;
+
+    return true;
 }
 
-static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn)
+struct FpFoo
 {
-    PatternMatchData *pmd = NULL;
-    PatternMatchData *pmd_not = NULL;
-    PatternMatchData *pmd_zero = NULL;
-    PatternMatchData *pmd_zero_not = NULL;
+    CursorActionType cat;
+    PatternMatchData* pmd;
+    int size;
 
-    OptFpList *ofl;
-    int max_size = 0, max_zero_size = 0;
+    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 ( !pmd->negated && rhs.pmd->negated )
+            return true;
+
+        if ( cat > rhs.cat )
+            return true;
+
+        if ( cat < rhs.cat )
+            return false;
 
-    CursorActionType last_cat = CAT_SET_RAW;  // default is raw packet
-    CursorActionType curr_cat = CAT_NONE;     // selected for fast pattern
+        if ( size > rhs.size )
+            return true;
+
+        return false;
+    };
+};
+
+static PmType get_pm_type(CursorActionType cat)
+{
+    switch ( cat )
+    {
+    case CAT_SET_RAW:
+        return PM_TYPE__CONTENT;
+    case CAT_SET_BODY:
+        return PM_TYPE__HTTP_CLIENT_BODY_CONTENT;
+    case CAT_SET_HEADER:
+        return PM_TYPE__HTTP_HEADER_CONTENT;
+    case CAT_SET_COMMAND:
+        return PM_TYPE__HTTP_URI_CONTENT;
+    default:
+        break;
+    }
+    return PM_TYPE__MAX;
+}
+
+static PatternMatchData * get_fp_content(OptTreeNode *otn)
+{
+    OptFpList *ofl;
+    CursorActionType curr_cat = CAT_SET_RAW;
+    FpFoo best;
 
     for (ofl = otn->opt_func; ofl != NULL; ofl = ofl->next)
     {
@@ -909,11 +953,8 @@ static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn)
 
         CursorActionType cat = IpsOption::get_cat(ofl->context);
 
-        if ( cat == CAT_NONE )
-            continue;
-
-        if ( cat > CAT_SET_RAW )
-            last_cat = cat;
+        if ( cat > CAT_ADJUST )
+            curr_cat = cat;
 
         if ( ofl->type != RULE_OPTION_TYPE_CONTENT )
             continue;
@@ -921,56 +962,24 @@ static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn)
         PatternMatchData* tmp = get_pmd(ofl);
         assert(tmp);
 
+        tmp->pm_type = get_pm_type(curr_cat);
+
         if (tmp->fp)
             return tmp;
 
-        if ( !IsPmdFpEligible(tmp) )
+        if ( !pmd_can_be_fp(tmp, curr_cat) )
             continue;
 
-        int size = FLP_Trim(tmp->pattern_buf, tmp->pattern_size, NULL);
+        FpFoo curr(curr_cat, tmp);
 
-        /* In case we get all zeros patterns */
-        if ((size == 0) && ((int)tmp->pattern_size > max_zero_size))
-        {
-            if (tmp->negated)
-            {
-                pmd_zero_not = tmp;
-            }
-            else
-            {
-                max_zero_size = tmp->pattern_size;
-                pmd_zero = tmp;
-            }
-        }
-        else if ( last_cat > curr_cat || size > max_size )
-        {
-            if (tmp->negated)
-            {
-                pmd_not = tmp;
-            }
-            else
-            {
-                max_size = size;
-                pmd = tmp;
-            }
-            curr_cat = last_cat;
-        }
+        if ( curr.is_better(best) )
+            best = curr;
     }
-
-    if (pmd != NULL)
-        return pmd;
-    else if (pmd_zero != NULL)
-        return pmd_zero;
-    else if (pmd_not != NULL)
-        return pmd_not;
-    else if (pmd_zero_not != NULL)
-        return pmd_zero_not;
-
-    return NULL;
+    return best.pmd;
 }
 
 static int fpFinishPortGroupRule(
-    SnortConfig *sc, PORT_GROUP *pg, PmType pm_type,
+    SnortConfig *sc, PORT_GROUP *pg,
     OptTreeNode *otn, PatternMatchData* pmd, FastPatternConfig *fp)
 {
     PMX * pmx;
@@ -982,27 +991,15 @@ static int fpFinishPortGroupRule(
     if ((pg == NULL) || (otn == NULL) || (fp == NULL))
         return -1;
 
-    switch (pm_type)
+    if ( !pmd )
     {
-        case PM_TYPE__CONTENT:
-            if (pmd == NULL)
-                return -1;
-            pg_type = PGCT_CONTENT;
-            break;
-        case PM_TYPE__HTTP_URI_CONTENT:
-        case PM_TYPE__HTTP_HEADER_CONTENT:
-        case PM_TYPE__HTTP_CLIENT_BODY_CONTENT:
-            if (pmd == NULL)
-                return -1;
-            pg_type = PGCT_URICONTENT;
-            break;
-        case PM_TYPE__MAX:
-        default:
-            if (pmd != NULL)
-                return -1;
-            fpAddPortGroupPrmx(pg, otn, PGCT_NOCONTENT);
-            return 0;  /* Not adding any content to pattern matcher */
+        fpAddPortGroupPrmx(pg, otn, PGCT_NOCONTENT);
+        return 0;  /* Not adding any content to pattern matcher */
     }
+    if (pmd->pm_type == PM_TYPE__CONTENT )
+        pg_type = PGCT_CONTENT;
+    else
+        pg_type = PGCT_URICONTENT;
 
     {
         if (pmd->negated)
@@ -1023,9 +1020,9 @@ static int fpFinishPortGroupRule(
         pmx->PatternMatchData = pmd;
 
         if (fpDetectGetDebugPrintFastPatterns(fp))
-            PrintFastPatternInfo(otn, pmd, pattern, pattern_length, pm_type);
+            PrintFastPatternInfo(otn, pmd, pattern, pattern_length);
 
-        pg->pgPms[pm_type]->add_pattern(
+        pg->pgPms[pmd->pm_type]->add_pattern(
                 sc,
                 pattern,
                 pattern_length,
@@ -1137,34 +1134,12 @@ static int fpAllocPms(
     return 0;
 }
 
-#if 0
-// FIXIT fast_pattern
-static PmType GetPmType (HTTP_BUFFER hb_type)
-{
-    switch ( hb_type )
-    {
-    case HTTP_BUFFER_URI:
-        return PM_TYPE__HTTP_URI_CONTENT;
-
-    case HTTP_BUFFER_HEADER:
-        return PM_TYPE__HTTP_HEADER_CONTENT;
-
-    case HTTP_BUFFER_CLIENT_BODY:
-        return PM_TYPE__HTTP_CLIENT_BODY_CONTENT;
-
-    default:
-        break;
-    }
-    return PM_TYPE__CONTENT;
-}
-#endif
-
 static int fpAddPortGroupRule(
     SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp)
 {
     PatternMatchData *pmd = NULL;
 
-    if ((pg == NULL) || (otn == NULL))
+    if ( !pg || !otn )
         return -1;
 
     // skip builtin rules
@@ -1175,11 +1150,18 @@ static int fpAddPortGroupRule(
     if ( !otn->enabled )
         return -1;
 
-    pmd = GetLongestPmdContent(otn);
+    pmd = get_fp_content(otn);
 
-    if ((pmd != NULL) && pmd->fp)
+    if ( pmd && pmd->fp)
     {
-        if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0)
+        if (
+            pmd->fp && !pmd->relative && !pmd->negated &&
+            !pmd->offset && !pmd->depth && pmd->no_case )
+        {
+            pmd->fp_only = 1;
+        }
+
+        if (fpFinishPortGroupRule(sc, pg, otn, pmd, fp) == 0)
         {
             if (pmd->pattern_size > otn->longestPatternLen)
                 otn->longestPatternLen = pmd->pattern_size;
@@ -1190,7 +1172,7 @@ static int fpAddPortGroupRule(
 
     /* If we get this far then no URI contents were added */
 
-    if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0)
+    if ( pmd && fpFinishPortGroupRule(sc, pg, otn, pmd, fp) == 0)
     {
         if (pmd->pattern_size > otn->longestPatternLen)
             otn->longestPatternLen = pmd->pattern_size;
@@ -1198,7 +1180,7 @@ static int fpAddPortGroupRule(
     }
 
     /* No content added */
-    if (fpFinishPortGroupRule(sc, pg, PM_TYPE__MAX, otn, NULL, fp) != 0)
+    if (fpFinishPortGroupRule(sc, pg, otn, NULL, fp) != 0)
         return -1;
 
     return 0;
@@ -2681,13 +2663,13 @@ const char * PatternRawToContent(const char *pattern, int pattern_len)
 }
 
 static void PrintFastPatternInfo(OptTreeNode *otn, PatternMatchData *pmd,
-        const char *pattern, int pattern_length, PmType pm_type)
+        const char *pattern, int pattern_length)
 {
     if ((otn == NULL) || (pmd == NULL))
         return;
 
     LogMessage("%u:%u\n", otn->sigInfo.generator, otn->sigInfo.id);
-    LogMessage("  Fast pattern matcher: %s\n", pm_type_strings[pm_type]);
+    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: %s\n", pmd->fp_only ? "yes" : "no");
     LogMessage("  Negated: %s\n", pmd->negated ? "yes" : "no");
index 3066ef516ef8f139693887a94fb1f6769e8f7ba9..2a07ac96a800b3af8dc03ae2191c9abc295dc039 100644 (file)
@@ -279,20 +279,10 @@ static int32_t parse_int(
 }
 
 static void validate_content(
-    SnortConfig*, PatternMatchData *pmd, OptTreeNode* otn)
+    SnortConfig*, PatternMatchData*, OptTreeNode* otn)
 {
     if ( fast_pattern_count(otn, RULE_OPTION_TYPE_CONTENT) > 1 )
         ParseError("Only one content per rule may be used for fast pattern matching.");
-
-    if (
-        pmd->fp && !pmd->relative && !pmd->negated &&
-        !pmd->offset && !pmd->depth && pmd->no_case )
-    {
-        // this is provisional; will be disabled later if there
-        // is a relative rule option following this one
-        // see parse_rule.cc::ValidateFastPattern()
-        pmd->fp_only = 1;
-    }
 }
 
 static void make_precomp(PatternMatchData * idx)
index f4b886bdc22227f513bb247ac462b7efa30c7025..f6e3edcdfdb1134643e5b0b95050dbe9dbf6fce3 100644 (file)
@@ -69,6 +69,7 @@ struct PatternMatchData
     uint16_t fp_length;
 
     uint8_t negated;        /* search for "not this pattern" */
+    uint8_t pm_type;
 
     // FIXIT wasting some memory here:
     // - this is not used by content option logic directly
@@ -79,7 +80,6 @@ struct PatternMatchData
        but the rule option specifies a negated content. Only
        applies to negative contents that are not relative */
     PmdLastCheck* last_check;
-
 };
 
 PatternMatchData* content_get_data(void*);
index adef361f7e893d213190f8ae3f1674fa7c15ae3a..3aaaa4786966b89526e24aeeaa5ce5b90a795d02 100644 (file)
@@ -60,6 +60,10 @@ class RawDataOption : public IpsOption
 {
 public:
     RawDataOption() : IpsOption(s_name) { };
+
+    CursorActionType get_cursor_type() const
+    { return CAT_SET_RAW; };
+
     int eval(Cursor&, Packet*);
 };
 
index 477c89ce89c14c498f5dcc8450c4a909535582d1..68d6cd09267b91cd639b8cb87507c484f90b6856 100644 (file)
@@ -95,6 +95,21 @@ void NHttpApi::nhttp_reset()
 {
 }
 
+static const char* buffers[] =
+{
+    "http_client_body",
+    "http_cookie",
+    "http_header",
+    "http_method",
+    "http_raw_cookie",
+    "http_raw_header",
+    "http_raw_uri",
+    "http_stat_code",
+    "http_stat_msg",
+    "http_uri",
+    nullptr
+};
+
 const InspectApi NHttpApi::nhttp_api =
 {
     {
@@ -107,7 +122,7 @@ const InspectApi NHttpApi::nhttp_api =
     },
     IT_SERVICE,
     PROTO_BIT__TCP,
-    nullptr, // buffers
+    buffers,
     "http",
     NHttpApi::nhttp_init,
     NHttpApi::nhttp_term,
index 5b13c8d725df5c97dfe4c115e4d4c3cffcd37d27..ee0a8be0c7f1799b875e2ff0993945f03a4e06a0 100644 (file)
@@ -76,6 +76,18 @@ bool NHttpInspect::configure (SnortConfig *)
     return true;
 }
 
+bool NHttpInspect::get_buf(unsigned id, Packet*, InspectionBuffer& b)
+{
+    const HttpBuffer* h = GetHttpBuffer((HTTP_BUFFER)id);
+
+    if ( !h )
+        return false;
+
+    b.data = h->buf;
+    b.len = h->length;
+    return true;
+}
+
 int NHttpInspect::verify(SnortConfig*)
 {
     return 0; // 0 = good, -1 = bad
index d36a3668c04e0fef2d67d8b34dfc09a71d61bed3..1117bc5e86207522e5d5ff062de115c711781c14 100644 (file)
@@ -45,6 +45,7 @@ public:
     NHttpInspect(bool test_input, bool _test_output);
     ~NHttpInspect();
 
+    bool get_buf(unsigned, Packet*, InspectionBuffer&);
     bool configure(SnortConfig*);
     int verify(SnortConfig*);
     void show(SnortConfig*);