]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #198 in SNORT/snort3 from nhttp31 to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Thu, 7 Jan 2016 22:54:27 +0000 (17:54 -0500)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Thu, 7 Jan 2016 22:54:27 +0000 (17:54 -0500)
Squashed commit of the following:

commit 96a369d55ffe5bfb086286d61b41a8e40ca289fa
Author: Tom Peters <thopeter@cisco.com>
Date:   Thu Jan 7 17:41:43 2016 -0500

    code review cleanup + URI-related cleanup

commit 0c202be8b9128b377994b95309ba8ffd8e7f7cd7
Author: Tom Peters <thopeter@cisco.com>
Date:   Wed Nov 11 17:47:18 2015 -0500

    NHI IPS rule options

41 files changed:
doc/bugs.txt
src/detection/fp_detect.cc
src/framework/cursor.cc
src/framework/inspector.h
src/piglet_plugins/pp_inspector_iface.cc
src/service_inspectors/nhttp_inspect/ips_nhttp.cc
src/service_inspectors/nhttp_inspect/ips_nhttp.h
src/service_inspectors/nhttp_inspect/nhttp_api.cc
src/service_inspectors/nhttp_inspect/nhttp_api.h
src/service_inspectors/nhttp_inspect/nhttp_enum.h
src/service_inspectors/nhttp_inspect/nhttp_field.cc
src/service_inspectors/nhttp_inspect/nhttp_field.h
src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc
src/service_inspectors/nhttp_inspect/nhttp_flow_data.h
src/service_inspectors/nhttp_inspect/nhttp_head_norm.cc
src/service_inspectors/nhttp_inspect/nhttp_inspect.cc
src/service_inspectors/nhttp_inspect/nhttp_inspect.h
src/service_inspectors/nhttp_inspect/nhttp_module.h
src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_body.h
src/service_inspectors/nhttp_inspect/nhttp_msg_body_chunk.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_body_cl.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_body_old.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h
src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_header.h
src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_request.h
src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_section.h
src/service_inspectors/nhttp_inspect/nhttp_msg_start.h
src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc
src/service_inspectors/nhttp_inspect/nhttp_normalizers.cc
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc
src/service_inspectors/nhttp_inspect/nhttp_tables.cc
src/service_inspectors/nhttp_inspect/nhttp_test_input.cc
src/service_inspectors/nhttp_inspect/nhttp_uri.cc
src/service_inspectors/nhttp_inspect/nhttp_uri.h
src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc

index ca09d5a9de60b4e64bf49e6eacb0af1de392e01b..f06f712c73b99b3568ecb3f1644172f0bb1b477b 100644 (file)
 * --lua can only be used in addition to, not in place of, a -c config.
   Ideally, --lua could be used in lieu of -c.
 
+* Rule line numbers provided with syntax error messages are off by one. The first rule is
+  unnumbered, the second rule is one, etc. See nhttp_inspect/detection_buffers/bad_rules/expected
+  for an example.
+
 
 ==== Rules
 
index a6a3625c3a48244765847326a5137bfe567e6d08..92d8a32928b49994620af899ce15b1d5aec26cdf 100644 (file)
@@ -975,7 +975,7 @@ static int rule_tree_queue(
     }
 
 #define SEARCH_BUFFER(ibt, pmt, cnt) \
-    if ( gadget->get_buf(ibt, p, buf) ) \
+    if ( gadget->get_fp_buf(ibt, p, buf) ) \
     { \
         if ( Mpse* so = port_group->mpse[pmt] ) \
             SEARCH_DATA(buf.data, buf.len, cnt) \
index 9e631d3e7aa2cacfbf72c075380523fe85ec6e31..64279118677de700cc11d87e038482d1cbb28328 100644 (file)
@@ -38,6 +38,7 @@ void Cursor::reset(Packet* p)
 {
     InspectionBuffer buf;
 
+    // FIXIT-M should this be converted to get_fp_buf()?
     if ( p->flow and p->flow->gadget and
         p->flow->gadget->get_buf(buf.IBT_ALT, p, buf) )
     {
index 9c27d0693788feec5f7ac591b39e68af7d74ffc8..afb9e95509ffe7539a293fad0054945f5eaf1eb2 100644 (file)
@@ -108,6 +108,9 @@ public:
     virtual bool get_buf(unsigned /*id*/, Packet*, InspectionBuffer&)
     { return false; }
 
+    virtual bool get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& bf)
+    { return get_buf(ibt, p, bf); }
+
     // IT_SERVICE only
     virtual class StreamSplitter* get_splitter(bool to_server);
 
index 280d340fe9c9c0bf20a19740bf491b108d7b4f21..ca9aee2e27a4b7bdd2fdb26e60386154d747ddc3 100644 (file)
@@ -31,6 +31,7 @@
 #include "pp_raw_buffer_iface.h"
 #include "pp_stream_splitter_iface.h"
 
+// FIXIT-H needs to be updated for addition of get_fp_buf()
 template<typename T>
 static inline bool get_buf(
     Inspector& i, T v, Packet& p, std::string& rb)
index ba45e53299c02c2bd73cc1d82664e50548752339..ec2b00f2db8ad54db609abdffa34c070a3f01bf7 100644 (file)
@@ -36,6 +36,7 @@ bool NHttpCursorModule::begin(const char*, int, SnortConfig*)
 {
     para_list.reset();
     sub_id = 0;
+    form = 0;
     switch (buffer_index)
     {
     case NHTTP_BUFFER_URI:
@@ -44,13 +45,13 @@ bool NHttpCursorModule::begin(const char*, int, SnortConfig*)
     case NHTTP_BUFFER_STAT_MSG:
     case NHTTP_BUFFER_VERSION:
     case NHTTP_BUFFER_METHOD:
-        inspect_section = IS_START;
-        break;
     case NHTTP_BUFFER_HEADER:
     case NHTTP_BUFFER_RAW_HEADER:
     case NHTTP_BUFFER_COOKIE:
     case NHTTP_BUFFER_RAW_COOKIE:
-        inspect_section = IS_HEADER;
+    case NHTTP_BUFFER_RAW_REQUEST:
+    case NHTTP_BUFFER_RAW_STATUS:
+        inspect_section = IS_DETECTION;
         break;
     case NHTTP_BUFFER_CLIENT_BODY:
         inspect_section = IS_BODY;
@@ -84,10 +85,15 @@ bool NHttpCursorModule::set(const char*, Value& v, SnortConfig*)
         if (sub_id == STAT_OTHER)
             ParseError("Unrecognized header field name");
     }
+    else if (v.is("request"))
+    {
+        para_list.request = true;
+        form |= FORM_REQUEST;
+    }
     else if (v.is("with_header"))
     {
         para_list.with_header = true;
-        inspect_section = IS_HEADER;
+        inspect_section = IS_DETECTION;
     }
     else if (v.is("with_body"))
     {
@@ -141,6 +147,10 @@ bool NHttpCursorModule::end(const char*, int, SnortConfig*)
     // Check for option conflicts
     if (para_list.with_header + para_list.with_body + para_list.with_trailer > 1)
         ParseError("Only specify one with_ option. Use the one that happens last.");
+    if (((buffer_index == NHTTP_BUFFER_TRAILER) || (buffer_index == NHTTP_BUFFER_RAW_TRAILER)) &&
+        (para_list.with_header || para_list.with_body) &&
+        !para_list.request)
+        ParseError("Trailers with with_ option must also specify request");
     if (para_list.scheme + para_list.host + para_list.port + para_list.path + para_list.query +
           para_list.fragment > 1)
         ParseError("Only specify one part of the URI");
@@ -150,6 +160,7 @@ bool NHttpCursorModule::end(const char*, int, SnortConfig*)
 void NHttpCursorModule::NHttpRuleParaList::reset()
 {
     field.clear();
+    request = false;
     with_header = false;
     with_body = false;
     with_trailer = false;
@@ -169,11 +180,17 @@ int NHttpIpsOption::eval(Cursor& c, Packet* p)
         return DETECTION_OPTION_NO_MATCH;
 
     if (NHttpInspect::get_latest_is() != inspect_section)
-        return DETECTION_OPTION_NO_MATCH;
+    {
+        // It is OK to provide a body buffer during the detection section. If there actually is
+        // a body buffer available then the detection section must also be the first body section.
+        if (! ((inspect_section == IS_BODY) && (NHttpInspect::get_latest_is() == IS_DETECTION)) )
+            return DETECTION_OPTION_NO_MATCH;
+    }
 
     InspectionBuffer hb;
 
-    if (! ((NHttpInspect*)(p->flow->gadget))->get_buf((unsigned)buffer_index, sub_id, nullptr, hb))
+    if (! ((NHttpInspect*)(p->flow->gadget))->
+           get_buf((unsigned)buffer_index, sub_id, form, nullptr, hb))
         return DETECTION_OPTION_NO_MATCH;
 
     c.set(key, hb.data, hb.len);
@@ -187,8 +204,6 @@ int NHttpIpsOption::eval(Cursor& c, Packet* p)
 
 static const Parameter http_uri_params[] =
 {
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "Parts of this rule examine HTTP message headers" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -290,8 +305,6 @@ static const IpsApi client_body_api =
 
 static const Parameter http_method_params[] =
 {
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "Parts of this rule examine HTTP message headers" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -341,6 +354,8 @@ static const IpsApi method_api =
 
 static const Parameter http_cookie_params[] =
 {
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the cookie from the request message even when examining the response" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -390,8 +405,6 @@ static const IpsApi cookie_api =
 
 static const Parameter http_stat_code_params[] =
 {
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "Parts of this rule examine HTTP message headers" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -441,8 +454,6 @@ static const IpsApi stat_code_api =
 
 static const Parameter http_stat_msg_params[] =
 {
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "Parts of this rule examine HTTP message headers" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -492,8 +503,6 @@ static const IpsApi stat_msg_api =
 
 static const Parameter http_raw_uri_params[] =
 {
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "Parts of this rule examine HTTP message headers" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -555,6 +564,8 @@ static const IpsApi raw_uri_api =
 
 static const Parameter http_raw_header_params[] =
 {
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the headers from the request message even when examining the response" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -604,6 +615,8 @@ static const IpsApi raw_header_api =
 
 static const Parameter http_raw_cookie_params[] =
 {
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the cookie from the request message even when examining the response" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -653,8 +666,8 @@ static const IpsApi raw_cookie_api =
 
 static const Parameter http_version_params[] =
 {
-    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
-        "Parts of this rule examine HTTP message headers" },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the version from the request message even when examining the response" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
@@ -708,12 +721,14 @@ static const IpsApi version_api =
 
 static const Parameter http_header_params[] =
 {
+    { "field", Parameter::PT_STRING, nullptr, nullptr,
+        "Restrict to given header. Header name is case insensitive." },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the headers from the request message even when examining the response" },
     { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message body" },
     { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
         "Parts of this rule examine HTTP message trailers" },
-    { "field", Parameter::PT_STRING, nullptr, nullptr,
-        "Restrict to given header. Header name is case insensitive." },
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -760,6 +775,13 @@ static const IpsApi header_api =
 static const Parameter http_trailer_params[] =
 {
     { "field", Parameter::PT_STRING, nullptr, nullptr, "restrict to given trailer" },
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the trailers from the request message even when examining the response" },
+    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP response message headers (must be combined with request)"
+        },
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP message body (must be combined with request)" },
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -770,7 +792,7 @@ static const Parameter http_trailer_params[] =
 
 static Module* trailer_mod_ctor()
 {
-    return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_TRAILER, CAT_SET_OTHER,
+    return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_TRAILER, CAT_SET_HEADER,
         PSI_TRAILER, http_trailer_params);
 }
 
@@ -803,6 +825,18 @@ static const IpsApi trailer_api =
 // http_raw_trailer
 //-------------------------------------------------------------------------
 
+static const Parameter http_raw_trailer_params[] =
+{
+    { "request", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Match against the trailers from the request message even when examining the response" },
+    { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP response message headers (must be combined with request)"
+        },
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP response message body (must be combined with request)" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
 #undef IPS_OPT
 #define IPS_OPT "http_raw_trailer"
 #undef IPS_HELP
@@ -811,7 +845,7 @@ static const IpsApi trailer_api =
 static Module* raw_trailer_mod_ctor()
 {
     return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_TRAILER, CAT_SET_OTHER,
-        PSI_RAW_TRAILER);
+        PSI_RAW_TRAILER, http_raw_trailer_params);
 }
 
 static const IpsApi raw_trailer_api =
@@ -839,6 +873,104 @@ static const IpsApi raw_trailer_api =
     nullptr
 };
 
+//-------------------------------------------------------------------------
+// http_raw_request
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_request_params[] =
+{
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP message body" },
+    { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP message trailers" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_request"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized request line"
+
+static Module* raw_request_mod_ctor()
+{
+    return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_REQUEST, CAT_SET_OTHER,
+        PSI_RAW_REQUEST, http_raw_request_params);
+}
+
+static const IpsApi raw_request_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_request_mod_ctor,
+        NHttpCursorModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    NHttpIpsOption::opt_ctor,
+    NHttpIpsOption::opt_dtor,
+    nullptr
+};
+
+//-------------------------------------------------------------------------
+// http_raw_status
+//-------------------------------------------------------------------------
+
+static const Parameter http_raw_status_params[] =
+{
+    { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP message body" },
+    { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr,
+        "Parts of this rule examine HTTP message trailers" },
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+#undef IPS_OPT
+#define IPS_OPT "http_raw_status"
+#undef IPS_HELP
+#define IPS_HELP "rule option to set the detection cursor to the unnormalized status line"
+
+static Module* raw_status_mod_ctor()
+{
+    return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_STATUS, CAT_SET_OTHER,
+        PSI_RAW_STATUS, http_raw_status_params);
+}
+
+static const IpsApi raw_status_api =
+{
+    {
+        PT_IPS_OPTION,
+        sizeof(IpsApi),
+        IPSAPI_VERSION,
+        1,
+        API_RESERVED,
+        API_OPTIONS,
+        IPS_OPT,
+        IPS_HELP,
+        raw_status_mod_ctor,
+        NHttpCursorModule::mod_dtor
+    },
+    OPT_TYPE_DETECTION,
+    0, PROTO_BIT__TCP,
+    nullptr,
+    nullptr,
+    nullptr,
+    nullptr,
+    NHttpIpsOption::opt_ctor,
+    NHttpIpsOption::opt_dtor,
+    nullptr
+};
+
 //-------------------------------------------------------------------------
 // plugins
 //-------------------------------------------------------------------------
@@ -858,6 +990,8 @@ SO_PUBLIC const BaseApi* snort_plugins[] =
     &header_api.base,
     &trailer_api.base,
     &raw_trailer_api.base,
+    &raw_request_api.base,
+    &raw_status_api.base,
     nullptr
 };
 
index 564cad283c5ebdf797137fd60e46eadff4d0352b..13523a56e0bb612ee9ae027e3700e9c0d42da719 100644 (file)
@@ -36,7 +36,7 @@
 
 enum PsIdx { PSI_URI, PSI_CLIENT_BODY, PSI_METHOD, PSI_COOKIE, PSI_STAT_CODE, PSI_STAT_MSG,
     PSI_RAW_URI, PSI_RAW_HEADER, PSI_RAW_COOKIE, PSI_HEADER, PSI_VERSION, PSI_TRAILER,
-    PSI_RAW_TRAILER, PSI_MAX };
+    PSI_RAW_TRAILER, PSI_RAW_REQUEST, PSI_RAW_STATUS, PSI_MAX };
 
 class NHttpCursorModule : public Module
 {
@@ -61,6 +61,7 @@ private:
     {
     public:
         std::string field;        // provide buffer containing specific header field
+        bool request;             // provide buffer from request not response
         bool with_header;         // provide buffer with a later section than it appears in
         bool with_body;
         bool with_trailer;
@@ -81,7 +82,8 @@ private:
 
     NHttpRuleParaList para_list;
     NHttpEnums::InspectSection inspect_section;
-    unsigned sub_id;
+    uint64_t sub_id;
+    uint64_t form;
 };
 
 class NHttpIpsOption : public IpsOption
@@ -89,7 +91,7 @@ class NHttpIpsOption : public IpsOption
 public:
     NHttpIpsOption(const NHttpCursorModule* cm) : IpsOption(cm->key), key(cm->key),
         buffer_index(cm->buffer_index), cat(cm->cat), psi(cm->psi),
-        inspect_section(cm->inspect_section), sub_id(cm->sub_id) {}
+        inspect_section(cm->inspect_section), sub_id(cm->sub_id), form(cm->form) {}
     CursorActionType get_cursor_type() const override { return cat; }
     int eval(Cursor&, Packet*) override;
     static IpsOption* opt_ctor(Module* m, OptTreeNode*)
@@ -101,7 +103,8 @@ private:
     const CursorActionType cat;
     const PsIdx psi;
     const NHttpEnums::InspectSection inspect_section;
-    const unsigned sub_id;
+    const uint64_t sub_id;
+    const uint64_t form;
 };
 
 #endif
index d2b06830e7fd6b8762eb517e923f149359e75784..52bce483f46d4739594f347b0858de491732f062 100644 (file)
@@ -33,7 +33,7 @@ Inspector* NHttpApi::nhttp_ctor(Module* mod)
     return new NHttpInspect(nhttp_mod->get_params());
 }
 
-const char* NHttpApi::legacy_buffers[] =
+const char* NHttpApi::classic_buffers[] =
 {
     "http_client_body",
     "http_cookie",
@@ -48,6 +48,8 @@ const char* NHttpApi::legacy_buffers[] =
     "http_version",
     "http_trailer",
     "http_raw_trailer",
+    "http_raw_request",
+    "http_raw_status",
     nullptr
 };
 
@@ -67,7 +69,7 @@ const InspectApi NHttpApi::nhttp_api =
     },
     IT_SERVICE,
     (uint16_t)PktType::PDU,
-    legacy_buffers,
+    classic_buffers,
     "http",
     NHttpApi::nhttp_init,
     NHttpApi::nhttp_term,
index d1fc7f600a05e29adc2d5b2aebc5a8d9762bc9c6..358138a6a7b4c29c2dd7403010e22df9775bf368 100644 (file)
@@ -31,7 +31,7 @@ class NHttpApi
 {
 public:
     static const InspectApi nhttp_api;
-    static const char* legacy_buffers[];
+    static const char* classic_buffers[];
 
 private:
     NHttpApi() = delete;
index 8fec1726c156d674caacc8dfbc194f09192fcb38..0549544ce9cd5a06ba0bbd8218458a7297eac997 100644 (file)
@@ -31,30 +31,34 @@ static const int GZIP_BLOCK_SIZE = 2048;
 static const int FINAL_GZIP_BLOCK_SIZE = 2304; // compromise value, too big causes gzip overruns
                                                // too small leaves too many little end sections
 static const uint32_t NHTTP_GID = 219;
-static const int GZIP_WINDOWBITS = 31;
-static const int DEFLATE_WINDOWBITS = 15;
+static const int GZIP_WINDOW_BITS = 31;
+static const int DEFLATE_WINDOW_BITS = 15;
 static const int MAX_FIELD_NAME_LENGTH = 100;
 
+// This can grow into a bitmap for the get_buf() form parameter
+static const uint64_t FORM_REQUEST = 0x1;
+
 // Field status codes for when no valid value is present in length or integer value. Positive
 // values are actual length or field value.
-enum StatusCode { STAT_NOSOURCE=-16, STAT_NOTCONFIGURED=-15, STAT_NOTCOMPUTE=-14,
-    STAT_INSUFMEMORY=-13, STAT_PROBLEMATIC=-12, STAT_NOTPRESENT=-11, STAT_EMPTYSTRING=0,
+enum StatusCode { STAT_NO_SOURCE=-16, STAT_NOT_CONFIGURED=-15, STAT_NOT_COMPUTE=-14,
+    STAT_INSUF_MEMORY=-13, STAT_PROBLEMATIC=-12, STAT_NOT_PRESENT=-11, STAT_EMPTY_STRING=0,
     STAT_OTHER=1 };
 
 // Message originator--client or server
-enum SourceId { SRC__NOTCOMPUTE=-14, SRC_CLIENT=0, SRC_SERVER=1 };
+enum SourceId { SRC__NOT_COMPUTE=-14, SRC_CLIENT=0, SRC_SERVER=1 };
 
 // Type of message section
-enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOTCOMPUTE=-14, SEC__NOTPRESENT=-11,
+enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOT_COMPUTE=-14, SEC__NOT_PRESENT=-11,
     SEC_REQUEST = 2, SEC_STATUS, SEC_HEADER, SEC_BODY_CL, SEC_BODY_CHUNK, SEC_TRAILER,
     SEC_BODY_OLD };
 
 // Message buffers available to clients
-// This enum must remain synchronized with legacy_buffers[]
+// This enum must remain synchronized with classic_buffers[]
 enum NHTTP_BUFFER { NHTTP_BUFFER_CLIENT_BODY = 1, NHTTP_BUFFER_COOKIE, NHTTP_BUFFER_HEADER,
     NHTTP_BUFFER_METHOD, NHTTP_BUFFER_RAW_COOKIE, NHTTP_BUFFER_RAW_HEADER, NHTTP_BUFFER_RAW_URI,
     NHTTP_BUFFER_STAT_CODE, NHTTP_BUFFER_STAT_MSG, NHTTP_BUFFER_URI, NHTTP_BUFFER_VERSION,
-    NHTTP_BUFFER_TRAILER, NHTTP_BUFFER_RAW_TRAILER, NHTTP_BUFFER_MAX };
+    NHTTP_BUFFER_TRAILER, NHTTP_BUFFER_RAW_TRAILER, NHTTP_BUFFER_RAW_REQUEST,
+    NHTTP_BUFFER_RAW_STATUS, NHTTP_BUFFER_MAX };
 
 // Result of scanning by splitter
 enum ScanResult { SCAN_NOTFOUND, SCAN_FOUND, SCAN_FOUND_PIECE, SCAN_DISCARD, SCAN_DISCARD_PIECE,
@@ -66,12 +70,12 @@ enum ChunkState { CHUNK_ZEROS, CHUNK_NUMBER, CHUNK_WHITESPACE, CHUNK_OPTIONS, CH
 
 // List of possible HTTP versions. Version 0.9 omitted because 0.9 predates creation of the
 // HTTP/X.Y token. There would never be a message with "HTTP/0.9"
-enum VersionId { VERS__NOSOURCE=-16, VERS__NOTCOMPUTE=-14, VERS__PROBLEMATIC=-12,
-    VERS__NOTPRESENT=-11, VERS__OTHER=1, VERS_1_0, VERS_1_1, VERS_2_0 };
+enum VersionId { VERS__NO_SOURCE=-16, VERS__NOT_COMPUTE=-14, VERS__PROBLEMATIC=-12,
+    VERS__NOT_PRESENT=-11, VERS__OTHER=1, VERS_1_0, VERS_1_1, VERS_2_0 };
 
 // Every request method we have ever heard of
-enum MethodId { METH__NOSOURCE=-16, METH__NOTCOMPUTE=-14, METH__INSUFMEMORY=-13,
-    METH__PROBLEMATIC=-12, METH__NOTPRESENT=-11, METH__OTHER=1, METH_OPTIONS, METH_GET, METH_HEAD,
+enum MethodId { METH__NO_SOURCE=-16, METH__NOT_COMPUTE=-14, METH__INSUF_MEMORY=-13,
+    METH__PROBLEMATIC=-12, METH__NOT_PRESENT=-11, METH__OTHER=1, METH_OPTIONS, METH_GET, METH_HEAD,
     METH_POST, METH_PUT, METH_DELETE, METH_TRACE, METH_CONNECT, METH_PROPFIND, METH_PROPPATCH,
     METH_MKCOL, METH_COPY, METH_MOVE, METH_LOCK, METH_UNLOCK, METH_VERSION_CONTROL, METH_REPORT,
     METH_CHECKOUT, METH_CHECKIN, METH_UNCHECKOUT, METH_MKWORKSPACE, METH_UPDATE, METH_LABEL,
@@ -82,25 +86,21 @@ enum MethodId { METH__NOSOURCE=-16, METH__NOTCOMPUTE=-14, METH__INSUFMEMORY=-13,
     METH_UPDATEREDIRECTREF };
 
 // URI formats
-enum UriType { URI__NOTCOMPUTE=-14, URI__PROBLEMATIC=-12, URI_ASTERISK = 2, URI_AUTHORITY,
+enum UriType { URI__NOT_COMPUTE=-14, URI__PROBLEMATIC=-12, URI_ASTERISK = 2, URI_AUTHORITY,
     URI_ABSPATH, URI_ABSOLUTE };
 
-// URI schemes
-enum SchemeId { SCH__NOSOURCE=-16, SCH__NOTCOMPUTE=-14, SCH__INSUFMEMORY=-13, SCH__NOTPRESENT=-11,
-    SCH_OTHER = 1, SCH_HTTP, SCH_HTTPS, SCH_FTP, SCH_GOPHER, SCH_FILE };
-
 // Body compression tpyes
 enum CompressId { CMP_NONE=2, CMP_GZIP, CMP_DEFLATE };
 
 // Message section in which an IPS option provides the buffer
-enum InspectSection { IS_NONE, IS_START, IS_HEADER, IS_BODY, IS_TRAILER };
+enum InspectSection { IS_NONE, IS_DETECTION, IS_BODY, IS_TRAILER };
 
 // Part of the URI to be provided
 enum UriComponent { UC_SCHEME = 1, UC_HOST, UC_PORT, UC_PATH, UC_QUERY, UC_FRAGMENT };
 
 // Every header we have ever heard of
-enum HeaderId { HEAD__NOTCOMPUTE=-14, HEAD__INSUFMEMORY=-13, HEAD__PROBLEMATIC=-12,
-    HEAD__NOTPRESENT=-11, HEAD__OTHER=1, HEAD_CACHE_CONTROL, HEAD_CONNECTION, HEAD_DATE,
+enum HeaderId { HEAD__NOT_COMPUTE=-14, HEAD__INSUF_MEMORY=-13, HEAD__PROBLEMATIC=-12,
+    HEAD__NOT_PRESENT=-11, HEAD__OTHER=1, HEAD_CACHE_CONTROL, HEAD_CONNECTION, HEAD_DATE,
     HEAD_PRAGMA, HEAD_TRAILER, HEAD_COOKIE, HEAD_SET_COOKIE, HEAD_TRANSFER_ENCODING, HEAD_UPGRADE,
     HEAD_VIA, HEAD_WARNING, HEAD_ACCEPT, HEAD_ACCEPT_CHARSET, HEAD_ACCEPT_ENCODING,
     HEAD_ACCEPT_LANGUAGE, HEAD_AUTHORIZATION, HEAD_EXPECT, HEAD_FROM, HEAD_HOST, HEAD_IF_MATCH,
@@ -131,7 +131,7 @@ enum Infraction
     INF_BAD_CHUNK_SIZE,
     INF_BAD_PHRASE,
     INF_BAD_URI,
-    INF_BAD_PORT,
+    INF_UNUSED,
     INF_URI_NEED_NORM,
     INF_URI_PERCENT_NORMAL,
     INF_URI_PERCENT_ASCII,
@@ -251,7 +251,7 @@ enum EventSid
     EVENT_BAD_HEADER,
     EVENT_CHUNK_OPTIONS,
     EVENT_URI_BAD_FORMAT,
-    EVENT_URI_BAD_PORT,
+    EVENT_UNUSED,
     EVENT_BROKEN_CHUNK,
     EVENT_CHUNK_WHITESPACE,
     EVENT_HEAD_NAME_WHITESPACE,
index cdc9bab5005166448a4ef0c5384c51f3ba61da38..420eba6267e8dca6e724fe220db507001b22b6a2 100644 (file)
 
 using namespace NHttpEnums;
 
-const Field Field::FIELD_NULL { STAT_NOSOURCE };
+const Field Field::FIELD_NULL { STAT_NO_SOURCE };
 
 #ifdef REG_TEST
 void Field::print(FILE* output, const char* name) const
 {
-    if ((length == STAT_NOTPRESENT) || (length == STAT_NOTCOMPUTE) || (length == STAT_NOSOURCE))
+    if ((length == STAT_NOT_PRESENT) || (length == STAT_NOT_COMPUTE) || (length == STAT_NO_SOURCE))
     {
         return;
     }
index 86650c6ef40216307ff270233c9ae5c90017c1bb..b50c75cbf1341e82e89dc599b8911e81833c78b1 100644 (file)
@@ -32,7 +32,7 @@
 class Field
 {
 public:
-    int32_t length = NHttpEnums::STAT_NOTCOMPUTE;
+    int32_t length = NHttpEnums::STAT_NOT_COMPUTE;
     const uint8_t* start = nullptr;
 
     static const Field FIELD_NULL;
index a811f6e4c62dbb32887e71e41d2dbb2c7023f4b2..6c5bbbd7df734ef23ce49977947ff2c7ed7ad7b0 100644 (file)
@@ -78,13 +78,13 @@ void NHttpFlowData::half_reset(SourceId source_id)
 {
     assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
 
-    version_id[source_id] = VERS__NOTPRESENT;
-    data_length[source_id] = STAT_NOTPRESENT;
-    body_octets[source_id] = STAT_NOTPRESENT;
+    version_id[source_id] = VERS__NOT_PRESENT;
+    data_length[source_id] = STAT_NOT_PRESENT;
+    body_octets[source_id] = STAT_NOT_PRESENT;
     section_size_target[source_id] = 0;
     section_size_max[source_id] = 0;
-    file_depth_remaining[source_id] = STAT_NOTPRESENT;
-    detect_depth_remaining[source_id] = STAT_NOTPRESENT;
+    file_depth_remaining[source_id] = STAT_NOT_PRESENT;
+    detect_depth_remaining[source_id] = STAT_NOT_PRESENT;
     compression[source_id] = CMP_NONE;
     if (compress_stream[source_id] != nullptr)
     {
@@ -100,7 +100,7 @@ void NHttpFlowData::half_reset(SourceId source_id)
 
     if (source_id == SRC_CLIENT)
     {
-        method_id = METH__NOTPRESENT;
+        method_id = METH__NOT_PRESENT;
         if (mime_state != nullptr)
         {
             delete mime_state;
@@ -109,7 +109,7 @@ void NHttpFlowData::half_reset(SourceId source_id)
     }
     else
     {
-        status_code_num = STAT_NOTPRESENT;
+        status_code_num = STAT_NOT_PRESENT;
     }
 }
 
index bd18bacc4ae319644ff7ab6d426542eceee3b44b..56321108c4ae1f5b38bb85d452cd512189c82120 100644 (file)
@@ -78,34 +78,35 @@ private:
     uint32_t num_good_chunks[2] = { 0, 0 };
 
     // *** StreamSplitter => Inspector (facts about the most recent message section)
-    NHttpEnums::SectionType section_type[2] = { NHttpEnums::SEC__NOTCOMPUTE,
-                                                NHttpEnums::SEC__NOTCOMPUTE };
+    NHttpEnums::SectionType section_type[2] = { NHttpEnums::SEC__NOT_COMPUTE,
+                                                NHttpEnums::SEC__NOT_COMPUTE };
     bool tcp_close[2] = { false, false };
     NHttpInfractions infractions[2];
     NHttpEventGen events[2];
-    int32_t num_head_lines[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
+    int32_t num_head_lines[2] = { NHttpEnums::STAT_NOT_PRESENT, NHttpEnums::STAT_NOT_PRESENT };
 
     // *** Inspector => StreamSplitter (facts about the message section that is coming next)
     NHttpEnums::SectionType type_expected[2] = { NHttpEnums::SEC_REQUEST, NHttpEnums::SEC_STATUS };
     // length of the data from Content-Length field
-    int64_t data_length[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
+    int64_t data_length[2] = { NHttpEnums::STAT_NOT_PRESENT, NHttpEnums::STAT_NOT_PRESENT };
     uint32_t section_size_target[2] = { 0, 0 };
     uint32_t section_size_max[2] = { 0, 0 };
     NHttpEnums::CompressId compression[2] = { NHttpEnums::CMP_NONE, NHttpEnums::CMP_NONE };
     z_stream* compress_stream[2] = { nullptr, nullptr };
 
     // *** Inspector's internal data about the current message
-    NHttpEnums::VersionId version_id[2] = { NHttpEnums::VERS__NOTPRESENT,
-                                            NHttpEnums::VERS__NOTPRESENT };
-    NHttpEnums::MethodId method_id = NHttpEnums::METH__NOTPRESENT;
-    int32_t status_code_num = NHttpEnums::STAT_NOTPRESENT;
-    int64_t file_depth_remaining[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
-    int64_t detect_depth_remaining[2] = { NHttpEnums::STAT_NOTPRESENT,
-        NHttpEnums::STAT_NOTPRESENT };
+    NHttpEnums::VersionId version_id[2] = { NHttpEnums::VERS__NOT_PRESENT,
+                                            NHttpEnums::VERS__NOT_PRESENT };
+    NHttpEnums::MethodId method_id = NHttpEnums::METH__NOT_PRESENT;
+    int32_t status_code_num = NHttpEnums::STAT_NOT_PRESENT;
+    int64_t file_depth_remaining[2] = { NHttpEnums::STAT_NOT_PRESENT,
+        NHttpEnums::STAT_NOT_PRESENT };
+    int64_t detect_depth_remaining[2] = { NHttpEnums::STAT_NOT_PRESENT,
+        NHttpEnums::STAT_NOT_PRESENT };
     MimeSession* mime_state = nullptr;  // SRC_CLIENT only
 
     // number of user data octets seen so far (regular body or chunks)
-    int64_t body_octets[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
+    int64_t body_octets[2] = { NHttpEnums::STAT_NOT_PRESENT, NHttpEnums::STAT_NOT_PRESENT };
 
     // Transaction management including pipelining
     // FIXIT-L pipeline deserves to be its own class
index 7c24d3821b90a3584085d6c4bb3b361fcc6ba748..c3d7ea35e9a1a4f837e3f68a10122e40c8c9fa8e 100644 (file)
@@ -63,7 +63,7 @@ void HeaderNormalizer::normalize(const HeaderId head_id, const int count, Scratc
     NHttpInfractions& infractions, NHttpEventGen& events, const HeaderId header_name_id[],
     const Field header_value[], const int32_t num_headers, Field& result_field) const
 {
-    if (result_field.length != STAT_NOTCOMPUTE)
+    if (result_field.length != STAT_NOT_COMPUTE)
     {
         return;
     }
@@ -109,7 +109,7 @@ void HeaderNormalizer::normalize(const HeaderId head_id, const int count, Scratc
     uint8_t* const scratch = scratch_pad.request(2*buffer_length);
     if (scratch == nullptr)
     {
-        result_field.length = STAT_INSUFMEMORY;
+        result_field.length = STAT_INSUF_MEMORY;
         return;
     }
 
index 7bcbdd123ebbd388de83c094bde1838f3aa4ab4d..e53d3edd51a21e0ad2753435f7e5cdae7221a2f0 100644 (file)
@@ -63,29 +63,26 @@ bool NHttpInspect::get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer
     switch (ibt)
     {
     case InspectionBuffer::IBT_KEY:
-        return get_buf(NHTTP_BUFFER_URI, 0, nullptr, b);
+        return get_buf(NHTTP_BUFFER_URI, 0, 0, nullptr, b);
     case InspectionBuffer::IBT_HEADER:
-        return get_buf(NHTTP_BUFFER_HEADER, 0, nullptr, b);
+        if (get_latest_is() == IS_TRAILER)
+            return get_buf(NHTTP_BUFFER_TRAILER, 0, 0, nullptr, b);
+        else
+            return get_buf(NHTTP_BUFFER_HEADER, 0, 0, nullptr, b);
     case InspectionBuffer::IBT_BODY:
-        return get_buf(NHTTP_BUFFER_CLIENT_BODY, 0, nullptr, b);
+        return get_buf(NHTTP_BUFFER_CLIENT_BODY, 0, 0, nullptr, b);
     default:
         return false;
     }
 }
 
-bool NHttpInspect::get_buf(unsigned id, Packet*, InspectionBuffer& b)
+SO_PUBLIC bool NHttpInspect::get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet*,
+    InspectionBuffer& b)
 {
-    return get_buf(id, 0, nullptr, b);
-}
-
-SO_PUBLIC bool NHttpInspect::get_buf(unsigned id, unsigned sub_id, Packet*, InspectionBuffer& b)
-{
-    // FIXIT-L some day we should add support for accessing the request headers, trailers, and
-    // version from the response side of the transaction.
     if (latest_section == nullptr)
         return false;
 
-    const Field& buffer = latest_section->get_classic_buffer(id, sub_id);
+    const Field& buffer = latest_section->get_classic_buffer(id, sub_id, form);
 
     if (buffer.length <= 0)
         return false;
@@ -95,6 +92,29 @@ SO_PUBLIC bool NHttpInspect::get_buf(unsigned id, unsigned sub_id, Packet*, Insp
     return true;
 }
 
+bool NHttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b)
+{
+    // Fast pattern buffers only supplied at specific times
+    switch (ibt)
+    {
+    case InspectionBuffer::IBT_KEY:
+        if ((get_latest_is() != IS_DETECTION) || (get_latest_src() != SRC_CLIENT))
+            return false;
+        break;
+    case InspectionBuffer::IBT_HEADER:
+        if ((get_latest_is() != IS_DETECTION) && (get_latest_is() != IS_TRAILER))
+            return false;
+        break;
+    case InspectionBuffer::IBT_BODY:
+        if ((get_latest_is() != IS_DETECTION) && (get_latest_is() != IS_BODY))
+            return false;
+        break;
+    default:
+        return false;
+    }
+    return get_buf(ibt, nullptr, b);
+}
+
 const Field& NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow,
     SourceId source_id, bool buf_owner) const
 {
index 93bd6a2ebc7cd7a87f768f2073514669dba949d2..8d6e4f407bf1fdefd5e551ffcb00a0612c5371ea 100644 (file)
@@ -42,13 +42,12 @@ public:
     NHttpInspect(NHttpParaList params_);
 
     bool get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) override;
-    bool get_buf(unsigned id, Packet*, InspectionBuffer& b) override;
-    bool get_buf(unsigned id, unsigned sub_id, Packet*, InspectionBuffer& b);
+    bool get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet*, InspectionBuffer& b);
+    bool get_fp_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) override;
     bool configure(SnortConfig*) override { return true; }
     void show(SnortConfig*) override { LogMessage("NHttpInspect\n"); }
     void eval(Packet*) override { }
     void clear(Packet* p) override;
-    void clear(NHttpFlowData* session_data, NHttpEnums::SourceId source_id);
     void tinit() override { }
     void tterm() override { }
     NHttpStreamSplitter* get_splitter(bool is_client_to_server) override
@@ -63,6 +62,9 @@ private:
 
     const Field& process(const uint8_t* data, const uint16_t dsize, Flow* const flow,
         NHttpEnums::SourceId source_id_, bool buf_owner) const;
+    void clear(NHttpFlowData* session_data, NHttpEnums::SourceId source_id);
+    static NHttpEnums::SourceId get_latest_src() { return (latest_section != nullptr) ?
+        latest_section->get_source_id() : NHttpEnums::SRC__NOT_COMPUTE; }
 
     static THREAD_LOCAL NHttpMsgSection* latest_section;
 
index 3c498e7a6d28a27859bb0e2f87e18c615aec969d..3978c19642245beecf211571d30f4e7ae4a4c0b6 100644 (file)
@@ -33,10 +33,11 @@ public:
     long request_depth;
     long response_depth;
     bool unzip;
-
+#ifdef REG_TEST
     bool test_input;
     bool test_output;
     long print_amount;
+#endif
 };
 
 class NHttpModule : public Module
index e9dc3fbba5475b77ec88243c6c255e3c8fb7f5f5..2aaf13036413ef8227c43dfbcfb24b299f081d18 100644 (file)
@@ -37,7 +37,8 @@ NHttpMsgBody::NHttpMsgBody(const uint8_t* buffer, const uint16_t buf_size,
     NHttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
     const NHttpParaList* params_) :
     NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_),
-    body_octets(session_data->body_octets[source_id])
+    body_octets(session_data->body_octets[source_id]),
+    detection_section((body_octets == 0) && (session_data->detect_depth_remaining[source_id] > 0))
 {
     transaction->set_body(this);
 }
@@ -100,7 +101,7 @@ void NHttpMsgBody::do_file_processing()
                 NHttpMsgRequest* request = transaction->get_request();
                 if (request != nullptr)
                 {
-                    const Field& tranaction_uri = request->get_uri_norm_legacy();
+                    const Field& tranaction_uri = request->get_uri_norm_classic();
                     if (tranaction_uri.length > 0)
                     {
                         file_flows->set_file_name(tranaction_uri.start, tranaction_uri.length);
@@ -133,8 +134,8 @@ void NHttpMsgBody::do_file_processing()
 void NHttpMsgBody::print_body_section(FILE* output)
 {
     detect_data.print(output, "Detect data");
-    get_classic_buffer(NHTTP_BUFFER_CLIENT_BODY, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_CLIENT_BODY-1]);
+    get_classic_buffer(NHTTP_BUFFER_CLIENT_BODY, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_CLIENT_BODY-1]);
     if (g_file_data.len > 0)
     {
         Field(g_file_data.len, g_file_data.data).print(output, "file_data");
index 1b23c5f1500099e1f547513ce43ff21a1d7bd889..53b110eabe0c862ffe41c28702c6018314f6e0b4 100644 (file)
@@ -33,7 +33,7 @@ public:
     void analyze() override;
     const Field& get_detect_buf() const override { return detect_data; }
     NHttpEnums::InspectSection get_inspection_section() const override
-        { return NHttpEnums::IS_BODY; }
+        { return detection_section ? NHttpEnums::IS_DETECTION : NHttpEnums::IS_BODY; }
 
 protected:
     NHttpMsgBody(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
@@ -44,6 +44,7 @@ protected:
     int64_t body_octets;
     Field detect_data;
     Field file_data;
+    const bool detection_section;
 
 #ifdef REG_TEST
     void print_body_section(FILE* output);
index cb636524f108ccf8f367d5e27adc8e0e69a87f0f..d9a014965d180033a2a911d79ae7d9287cec03bb 100644 (file)
@@ -48,7 +48,7 @@ void NHttpMsgBodyChunk::update_flow()
         session_data->infractions[source_id] = infractions;
         session_data->events[source_id] = events;
     }
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 }
 
 #ifdef REG_TEST
index 63989a3485dfbadb68986ae4095d5144a134e0d9..d356944997a8466a445a0d12834281cfd85a397e 100644 (file)
@@ -49,7 +49,7 @@ void NHttpMsgBodyCl::update_flow()
             SEC_STATUS;
         session_data->half_reset(source_id);
     }
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 }
 
 #ifdef REG_TEST
index 4e989572b23558ea2dbcc51e06bc9683ef2a2130..caf9b3fcae2437934c4d6a21b11bafb020a6fc37 100644 (file)
@@ -39,7 +39,7 @@ void NHttpMsgBodyOld::update_flow()
     update_depth();
     session_data->infractions[source_id] = infractions;
     session_data->events[source_id] = events;
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 }
 
 #ifdef REG_TEST
index cf8c7463bed01efde711d1bb733a038f0510a6d6..d4da16fb3c26dea09515a54876fc72bb4a032e29 100644 (file)
@@ -182,7 +182,7 @@ void NHttpMsgHeadShared::derive_header_name_id(int index)
     if ((lower_name = scratch_pad.request(length)) == nullptr)
     {
         infractions += INF_NO_SCRATCH;
-        header_name_id[index] = HEAD__INSUFMEMORY;
+        header_name_id[index] = HEAD__INSUF_MEMORY;
         return;
     }
     for (int32_t k=0; k < length; k++)
@@ -231,7 +231,7 @@ const Field& NHttpMsgHeadShared::get_header_value_norm(HeaderId header_id)
 void NHttpMsgHeadShared::print_headers(FILE* output)
 {
     char title_buf[100];
-    if (num_headers != STAT_NOSOURCE)
+    if (num_headers != STAT_NO_SOURCE)
         fprintf(output, "Number of headers: %d\n", num_headers);
     for (int j=0; j < num_headers; j++)
     {
@@ -240,7 +240,7 @@ void NHttpMsgHeadShared::print_headers(FILE* output)
     }
     for (int k=1; k <= HEAD__MAX_VALUE-1; k++)
     {
-        if (get_header_value_norm((HeaderId)k).length != STAT_NOSOURCE)
+        if (get_header_value_norm((HeaderId)k).length != STAT_NO_SOURCE)
         {
             snprintf(title_buf, sizeof(title_buf), "Normalized header %d", k);
             get_header_value_norm((HeaderId)k).print(output, title_buf);
index cb4b363ebe3d8e1d21520ad1aaf4eb730c1e1b01..05d38873dfdfbb908286e059a856f673ef697ec2 100644 (file)
@@ -77,7 +77,7 @@ protected:
     // All of these are indexed by the relative position of the header field in the message
     static const int MAX_HEADERS = 200;  // I'm an arbitrary number. FIXIT-L
     static const int MAX_HEADER_LENGTH = 4096; // Based on max cookie size of some browsers
-    int32_t num_headers = NHttpEnums::STAT_NOTCOMPUTE;
+    int32_t num_headers = NHttpEnums::STAT_NOT_COMPUTE;
     Field* header_line = nullptr;
     Field* header_name = nullptr;
     NHttpEnums::HeaderId* header_name_id = nullptr;
index 5b87294a7cbc8ce7184a8b4536f4b5bb67341b64..1c2e5b1752a5cb851e9e5567536ef73be4dbd993 100644 (file)
@@ -42,7 +42,7 @@ NHttpMsgHeader::NHttpMsgHeader(const uint8_t* buffer, const uint16_t buf_size,
 
 void NHttpMsgHeader::update_flow()
 {
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 
     // FIXIT-L put this test here for now. May want to integrate into the following code and
     // do more careful checks for inappropriate Content-Length.
@@ -52,6 +52,13 @@ void NHttpMsgHeader::update_flow()
     // The following logic to determine body type is by no means the last word on this topic.
     // FIXIT-H need to distinguish methods such as POST that should have a body from those that
     // should not.
+    if (tcp_close)
+    {
+        session_data->type_expected[source_id] = SEC_ABORT;
+        session_data->half_reset(source_id);
+        return;
+    }
+
     if ((source_id == SRC_SERVER) && ((status_code_num <= 199) || (status_code_num == 204) ||
         (status_code_num == 304)))
     {
@@ -138,6 +145,12 @@ void NHttpMsgHeader::prepare_body()
     const int64_t& depth = (source_id == SRC_CLIENT) ? params->request_depth :
         params->response_depth;
     session_data->detect_depth_remaining[source_id] = (depth != -1) ? depth : INT64_MAX;
+    if (session_data->detect_depth_remaining[source_id] > 0)
+    {
+        // Depth must be positive because first body section must actually go to detection in order
+        // to be the detection section
+        detection_section = false;
+    }
     setup_file_processing();
     setup_decompression();
     update_depth();
@@ -202,7 +215,7 @@ void NHttpMsgHeader::setup_decompression()
     session_data->compress_stream[source_id]->zfree = Z_NULL;
     session_data->compress_stream[source_id]->next_in = Z_NULL;
     session_data->compress_stream[source_id]->avail_in = 0;
-    const int window_bits = (compression == CMP_GZIP) ? GZIP_WINDOWBITS : DEFLATE_WINDOWBITS;
+    const int window_bits = (compression == CMP_GZIP) ? GZIP_WINDOW_BITS : DEFLATE_WINDOW_BITS;
     if (inflateInit2(session_data->compress_stream[source_id], window_bits) != Z_OK)
     {
         session_data->compression[source_id] = CMP_NONE;
@@ -216,14 +229,14 @@ void NHttpMsgHeader::print_section(FILE* output)
 {
     NHttpMsgSection::print_message_title(output, "header");
     NHttpMsgHeadShared::print_headers(output);
-    get_classic_buffer(NHTTP_BUFFER_COOKIE, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_COOKIE-1]);
-    get_classic_buffer(NHTTP_BUFFER_HEADER, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_HEADER-1]);
-    get_classic_buffer(NHTTP_BUFFER_RAW_COOKIE, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_COOKIE-1]);
-    get_classic_buffer(NHTTP_BUFFER_RAW_HEADER, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_HEADER-1]);
+    get_classic_buffer(NHTTP_BUFFER_COOKIE, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_COOKIE-1]);
+    get_classic_buffer(NHTTP_BUFFER_HEADER, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_HEADER-1]);
+    get_classic_buffer(NHTTP_BUFFER_RAW_COOKIE, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_COOKIE-1]);
+    get_classic_buffer(NHTTP_BUFFER_RAW_HEADER, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_HEADER-1]);
     NHttpMsgSection::print_message_wrapup(output);
 }
 #endif
index 42741d911ce5a7168cb2599189cd38ffd472353a..d0338745c31e2f1dc6ff8428e4c708d98fc694f6 100644 (file)
@@ -36,7 +36,7 @@ public:
         NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_,
         const NHttpParaList* params_);
     NHttpEnums::InspectSection get_inspection_section() const override
-        { return NHttpEnums::IS_HEADER; }
+        { return detection_section ? NHttpEnums::IS_DETECTION : NHttpEnums::IS_NONE; }
     void update_flow() override;
 private:
     // Dummy configurations to support MIME processing
@@ -47,6 +47,8 @@ private:
     void setup_file_processing();
     void setup_decompression();
 
+    bool detection_section = true;
+
 #ifdef REG_TEST
     void print_section(FILE* output) override;
 #endif
index 52f7669b06414dede9696a772338153ef667b7fc..7bae7494047a6d658670fb6ea86d9d29ed3f1a04 100644 (file)
@@ -94,11 +94,11 @@ const Field& NHttpMsgRequest::get_uri()
     return Field::FIELD_NULL;
 }
 
-const Field& NHttpMsgRequest::get_uri_norm_legacy()
+const Field& NHttpMsgRequest::get_uri_norm_classic()
 {
     if (uri != nullptr)
     {
-        return uri->get_norm_legacy();
+        return uri->get_norm_classic();
     }
     return Field::FIELD_NULL;
 }
@@ -162,7 +162,7 @@ void NHttpMsgRequest::update_flow()
         session_data->infractions[source_id].reset();
         session_data->events[source_id].reset();
     }
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 }
 
 #ifdef REG_TEST
@@ -177,14 +177,10 @@ void NHttpMsgRequest::print_section(FILE* output)
         uri->get_uri().print(output, "URI");
         fprintf(output, "URI Type: %d\n", uri->get_uri_type());
         uri->get_scheme().print(output, "Scheme");
-        if (uri->get_scheme_id() != SCH__NOSOURCE)
-            fprintf(output, "Scheme Id: %d\n", uri->get_scheme_id());
         uri->get_authority().print(output, "Authority");
         uri->get_host().print(output, "Host Name");
         uri->get_norm_host().print(output, "Normalized Host Name");
         uri->get_port().print(output, "Port");
-        if (uri->get_port_value() != STAT_NOSOURCE)
-            fprintf(output, "Port Value: %d\n", uri->get_port_value());
         uri->get_abs_path().print(output, "Absolute Path");
         uri->get_path().print(output, "Path");
         uri->get_norm_path().print(output, "Normalized Path");
@@ -193,14 +189,16 @@ void NHttpMsgRequest::print_section(FILE* output)
         uri->get_fragment().print(output, "Fragment");
         uri->get_norm_fragment().print(output, "Normalized Fragment");
     }
-    get_classic_buffer(NHTTP_BUFFER_METHOD, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_METHOD-1]);
-    get_classic_buffer(NHTTP_BUFFER_RAW_URI, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_URI-1]);
-    get_classic_buffer(NHTTP_BUFFER_URI, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_URI-1]);
-    get_classic_buffer(NHTTP_BUFFER_VERSION, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_VERSION-1]);
+    get_classic_buffer(NHTTP_BUFFER_METHOD, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_METHOD-1]);
+    get_classic_buffer(NHTTP_BUFFER_RAW_URI, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_URI-1]);
+    get_classic_buffer(NHTTP_BUFFER_URI, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_URI-1]);
+    get_classic_buffer(NHTTP_BUFFER_VERSION, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_VERSION-1]);
+    get_classic_buffer(NHTTP_BUFFER_RAW_REQUEST, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_REQUEST-1]);
     NHttpMsgSection::print_message_wrapup(output);
 }
 
index d83c6831de1a0de9755d35c8694760e71f634cb6..ab70f8322190cc51b0d1c1a13e601f69bc3d5ec5 100644 (file)
@@ -41,7 +41,7 @@ public:
     void update_flow() override;
     const Field& get_method() { return method; }
     const Field& get_uri();
-    const Field& get_uri_norm_legacy();
+    const Field& get_uri_norm_classic();
     NHttpUri* get_nhttp_uri() { return uri; }
 
 #ifdef REG_TEST
index 16332690c6fbb51b61986b83223488a3a69080c9..cb96cc00fcc482d8d0f7613b4dedde9e0c63a3c0 100644 (file)
@@ -47,8 +47,8 @@ NHttpMsgSection::NHttpMsgSection(const uint8_t* buffer, const uint16_t buf_size,
     infractions(session_data->infractions[source_id]),
     events(session_data->events[source_id]),
     version_id(session_data->version_id[source_id]),
-    method_id((source_id == SRC_CLIENT) ? session_data->method_id : METH__NOTPRESENT),
-    status_code_num((source_id == SRC_SERVER) ? session_data->status_code_num : STAT_NOTPRESENT),
+    method_id((source_id == SRC_CLIENT) ? session_data->method_id : METH__NOT_PRESENT),
+    status_code_num((source_id == SRC_SERVER) ? session_data->status_code_num : STAT_NOT_PRESENT),
     delete_msg_on_destruct(buf_owner)
 { }
 
@@ -79,8 +79,11 @@ void NHttpMsgSection::update_depth() const
     }
 }
 
-const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id)
+const Field& NHttpMsgSection::get_classic_buffer(unsigned id, uint64_t sub_id, uint64_t form)
 {
+    // Only use with buffers that support the request option
+    const SourceId buffer_side = (form & FORM_REQUEST) ? SRC_CLIENT : source_id;
+
     switch (id)
     {
     case NHTTP_BUFFER_CLIENT_BODY:
@@ -96,10 +99,10 @@ const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id)
     // Currently "normalization" is aggregation of multiple cookies. That is correct for raw
     // cookies and all there is for normalized cookies.
       {
-        NHttpMsgHeader* header = transaction->get_header(source_id);
+        NHttpMsgHeader* header = transaction->get_header(buffer_side);
         if (header == nullptr)
             return Field::FIELD_NULL;
-        HeaderId cookie_head = (source_id == SRC_CLIENT) ? HEAD_COOKIE : HEAD_SET_COOKIE;
+        HeaderId cookie_head = (buffer_side == SRC_CLIENT) ? HEAD_COOKIE : HEAD_SET_COOKIE;
         return header->get_header_value_norm(cookie_head);
       }
     case NHTTP_BUFFER_HEADER:
@@ -107,8 +110,8 @@ const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id)
       {
         // FIXIT-L Someday want to be able to return field name or raw field value
         NHttpMsgHeadShared* const header = (id == NHTTP_BUFFER_HEADER) ?
-            (NHttpMsgHeadShared*)transaction->get_header(source_id) :
-            (NHttpMsgHeadShared*)transaction->get_trailer(source_id);
+            (NHttpMsgHeadShared*)transaction->get_header(buffer_side) :
+            (NHttpMsgHeadShared*)transaction->get_trailer(buffer_side);
         if (header == nullptr)
             return Field::FIELD_NULL;
         if (sub_id == 0)
@@ -122,7 +125,7 @@ const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id)
       }
     case NHTTP_BUFFER_RAW_HEADER:
       {
-        NHttpMsgHeader* header = transaction->get_header(source_id);
+        NHttpMsgHeader* header = transaction->get_header(buffer_side);
         return (header != nullptr) ? header->get_headers() : Field::FIELD_NULL;
       }
     case NHTTP_BUFFER_STAT_CODE:
@@ -143,7 +146,7 @@ const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id)
         if (request == nullptr)
             return Field::FIELD_NULL;
         if (sub_id == 0)
-            return raw ? request->get_uri() : request->get_uri_norm_legacy();
+            return raw ? request->get_uri() : request->get_uri_norm_classic();
         NHttpUri* const uri = request->get_nhttp_uri();
         if (uri == nullptr)
             return Field::FIELD_NULL;
@@ -167,13 +170,23 @@ const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id)
       }
     case NHTTP_BUFFER_VERSION:
       {
-        NHttpMsgStart* start = (source_id == SRC_CLIENT) ?
+        NHttpMsgStart* start = (buffer_side == SRC_CLIENT) ?
             (NHttpMsgStart*)transaction->get_request() : (NHttpMsgStart*)transaction->get_status();
         return (start != nullptr) ? start->get_version() : Field::FIELD_NULL;
       }
+    case NHTTP_BUFFER_RAW_REQUEST:
+      {
+        NHttpMsgRequest* request = transaction->get_request();
+        return (request != nullptr) ? request->get_detect_buf() : Field::FIELD_NULL;
+      }
+    case NHTTP_BUFFER_RAW_STATUS:
+      {
+        NHttpMsgStatus* status = transaction->get_status();
+        return (status != nullptr) ? status->get_detect_buf() : Field::FIELD_NULL;
+      }
     case NHTTP_BUFFER_RAW_TRAILER:
       {
-        NHttpMsgTrailer* trailer = transaction->get_trailer(source_id);
+        NHttpMsgTrailer* trailer = transaction->get_trailer(buffer_side);
         return (trailer != nullptr) ? trailer->get_headers() : Field::FIELD_NULL;
       }
     default:
index 4a8058dcc67bf8763ab1b49fc6551df1d91e2603..f07e1cc7725e01964bc87a98d11fca28d2c3a3b1 100644 (file)
@@ -38,7 +38,9 @@ class NHttpMsgSection
 {
 public:
     virtual ~NHttpMsgSection() { if (delete_msg_on_destruct) delete[] msg_text.start; }
-    virtual NHttpEnums::InspectSection get_inspection_section() const = 0;
+    virtual NHttpEnums::InspectSection get_inspection_section() const
+        { return NHttpEnums::IS_NONE; }
+    NHttpEnums::SourceId get_source_id() { return source_id; }
 
     // Minimum necessary processing for every message
     virtual void analyze() = 0;
@@ -46,7 +48,7 @@ public:
     // Manages the splitter and communication between message sections
     virtual void update_flow() = 0;
 
-    const Field& get_classic_buffer(unsigned id, unsigned sub_id);
+    const Field& get_classic_buffer(unsigned id, uint64_t sub_id, uint64_t form);
 
     // Provide buffer to be sent to detection
     virtual const Field& get_detect_buf() const { return msg_text; }
index e36a9bdbee3c2a66a9d6d49562edf653468022d4..35230ff9e69879b9339cae9c22116acfcbaa480b 100644 (file)
@@ -32,8 +32,6 @@ class NHttpMsgStart : public NHttpMsgSection
 public:
     void analyze() override;
     const Field& get_version() const { return version; }
-    NHttpEnums::InspectSection get_inspection_section() const override
-        { return NHttpEnums::IS_START; }
 
 protected:
     NHttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_,
@@ -41,7 +39,7 @@ protected:
         : NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
         { }
     virtual void parse_start_line() = 0;
-    virtual void gen_events() {};
+    virtual void gen_events() = 0;
     void derive_version_id();
 
     Field start_line;
index 357f72f540ad78c2679e9b29cf2337f6d5780487..85d1572aed92ea28015275530354425f13a93b01 100644 (file)
@@ -161,7 +161,7 @@ void NHttpMsgStatus::update_flow()
         session_data->infractions[source_id].reset();
         session_data->events[source_id].reset();
     }
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 }
 
 #ifdef REG_TEST
@@ -171,12 +171,14 @@ void NHttpMsgStatus::print_section(FILE* output)
     fprintf(output, "Version Id: %d\n", version_id);
     fprintf(output, "Status Code Num: %d\n", status_code_num);
     reason_phrase.print(output, "Reason Phrase");
-    get_classic_buffer(NHTTP_BUFFER_STAT_CODE, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_STAT_CODE-1]);
-    get_classic_buffer(NHTTP_BUFFER_STAT_MSG, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_STAT_MSG-1]);
-    get_classic_buffer(NHTTP_BUFFER_VERSION, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_VERSION-1]);
+    get_classic_buffer(NHTTP_BUFFER_STAT_CODE, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_STAT_CODE-1]);
+    get_classic_buffer(NHTTP_BUFFER_STAT_MSG, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_STAT_MSG-1]);
+    get_classic_buffer(NHTTP_BUFFER_VERSION, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_VERSION-1]);
+    get_classic_buffer(NHTTP_BUFFER_RAW_STATUS, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_STATUS-1]);
     NHttpMsgSection::print_message_wrapup(output);
 }
 #endif
index 7059ee247c2d70ab0a54dd8d375783fb7199f0c2..e1b643a0ddef529f19a78b355126fd4e9d294a18 100644 (file)
@@ -42,7 +42,7 @@ void NHttpMsgTrailer::update_flow()
     session_data->type_expected[source_id] =
         (source_id == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
     session_data->half_reset(source_id);
-    session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+    session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 }
 
 #ifdef REG_TEST
@@ -50,10 +50,10 @@ void NHttpMsgTrailer::print_section(FILE* output)
 {
     NHttpMsgSection::print_message_title(output, "trailer");
     NHttpMsgHeadShared::print_headers(output);
-    get_classic_buffer(NHTTP_BUFFER_TRAILER, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_TRAILER-1]);
-    get_classic_buffer(NHTTP_BUFFER_RAW_TRAILER, 0).print(output,
-        NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_TRAILER-1]);
+    get_classic_buffer(NHTTP_BUFFER_TRAILER, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_TRAILER-1]);
+    get_classic_buffer(NHTTP_BUFFER_RAW_TRAILER, 0, 0).print(output,
+        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_TRAILER-1]);
     NHttpMsgSection::print_message_wrapup(output);
 }
 #endif
index 6d1026363f7914d3413aea2fa08d3659ab1bc993..98f6cb39739bd261dd2497441e43dc37a001db57 100644 (file)
@@ -35,6 +35,7 @@ int32_t norm_to_lower(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf
 {
     for (int32_t k=0; k < in_length; k++)
     {
+        // FIXIT-P tolower() might perform better but must be sure <locale> cannot be pulled in
         out_buf[k] = ((in_buf[k] < 'A') || (in_buf[k] > 'Z')) ? in_buf[k] : in_buf[k] - ('A' -
             'a');
     }
index 21e3109f09b5ead8c4949e6b2c9e32348db7b0f3..cae7b71d7d32ddb420f0f256e5719ac3fa506f89 100644 (file)
@@ -363,12 +363,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
 
     copied = len;
 
-    // FIXIT-M (b042cf28c49)
-    // assert(total <= MAX_OCTETS) was broke after changes in stream
-    // to accommodate asymmetric TCP connections.
-    // See "FIXIT-M (b042cf28c49)" in "src/tcp/tcp_session.c".
-    if (total > MAX_OCTETS)
-        total = MAX_OCTETS;
+    assert(total <= MAX_OCTETS);
 
     NHttpFlowData* session_data = (NHttpFlowData*)flow->get_application_data(
         NHttpFlowData::nhttp_flow_id);
@@ -409,7 +404,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
     }
 #endif
 
-    if (session_data->section_type[source_id] == SEC__NOTCOMPUTE)
+    if (session_data->section_type[source_id] == SEC__NOT_COMPUTE)
     {   // FIXIT-M In theory this check should not be necessary
         return nullptr;
     }
@@ -427,7 +422,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
 #endif
         if (flags & PKT_PDU_TAIL)
         {
-            session_data->section_type[source_id] = SEC__NOTCOMPUTE;
+            session_data->section_type[source_id] = SEC__NOT_COMPUTE;
 
             // When we are skipping through a message body beyond flow depth this is the end of
             // the line. Here we do the message section's normal job of updating the flow for the
@@ -488,12 +483,26 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
         session_data->section_offset[source_id] = 0;
 
         // Buffers are reset to nullptr without delete[] because NHttpMsgSection holds the pointer
-        // and is responsible
-        if (send_to_detection.length > 0)
+        // and is responsible.
+        // The detection section of a message is the first body section, unless there is no body
+        // section in which case it is the headers. The detection section is always returned to the
+        // framework and forwarded to detection even if it is empty. Other body sections and the
+        // trailer section are only forwarded if nonempty. The start line section and header
+        // sections other than the detection section are never forwarded.
+        if (((send_to_detection.length > 0) && (NHttpInspect::get_latest_is() != IS_NONE)) ||
+            ((send_to_detection.length == 0) && (NHttpInspect::get_latest_is() == IS_DETECTION)))
         {
-            nhttp_buf.data = send_to_detection.start;
-            nhttp_buf.length = send_to_detection.length;
-            assert((nhttp_buf.length <= MAX_OCTETS) && (nhttp_buf.length != 0));
+            // FIXIT-M kludge until we work out issues with returning an empty buffer
+            if (send_to_detection.length > 0)
+            {
+                nhttp_buf.data = send_to_detection.start;
+                nhttp_buf.length = send_to_detection.length;
+            }
+            else
+            {
+                nhttp_buf.data = (const uint8_t*)"";
+                nhttp_buf.length = 1;
+            }
             buffer = nullptr;
 #ifdef REG_TEST
             if (NHttpTestManager::use_test_output())
@@ -537,7 +546,7 @@ bool NHttpStreamSplitter::finish(Flow* flow)
     // If there is leftover data for which we returned PAF_SEARCH and never flushed, we need to set
     // up to process because it is about to go to reassemble(). But we don't support partial start
     // lines.
-    if ((session_data->section_type[source_id] == SEC__NOTCOMPUTE) &&
+    if ((session_data->section_type[source_id] == SEC__NOT_COMPUTE) &&
         (session_data->cutter[source_id] != nullptr)               &&
         (session_data->cutter[source_id]->get_octets_seen() > 0))
     {
@@ -558,7 +567,7 @@ bool NHttpStreamSplitter::finish(Flow* flow)
     }
 
     // If there is no more data to process we need to wrap up file processing right now
-    if ((session_data->section_type[source_id] == SEC__NOTCOMPUTE) &&
+    if ((session_data->section_type[source_id] == SEC__NOT_COMPUTE) &&
         (session_data->file_depth_remaining[source_id] > 0)        &&
         (session_data->cutter[source_id] != nullptr)               &&
         (session_data->cutter[source_id]->get_octets_seen() == 0))
@@ -568,7 +577,7 @@ bool NHttpStreamSplitter::finish(Flow* flow)
             FileFlows* file_flows = FileFlows::get_file_flows(flow);
             file_flows->file_process(nullptr, 0, SNORT_FILE_END, false);
         }
-        else
+        else if (session_data->mime_state != nullptr)
         {
             session_data->mime_state->process_mime_data(flow, nullptr, 0, true,
                 SNORT_FILE_END);
index 839a45a7b4565a1d746eb8be0b2466cda39cd200..0bbb4959c913a3df323952321648c42c5ac812e5 100644 (file)
@@ -91,16 +91,6 @@ const StrCode NHttpMsgRequest::method_list[] =
     { 0,                       nullptr }
 };
 
-const StrCode NHttpUri::scheme_list[] =
-{
-    { SCH_HTTP,                "http" },
-    { SCH_HTTPS,               "https" },
-    { SCH_FTP,                 "ftp" },
-    { SCH_GOPHER,              "gopher" },
-    { SCH_FILE,                "file" },
-    { 0,                       nullptr }
-};
-
 SO_PUBLIC const StrCode NHttpMsgHeadShared::header_list[] =
 {
     { HEAD_CACHE_CONTROL,        "cache-control" },
@@ -330,7 +320,7 @@ const RuleMap NHttpModule::nhttp_events[] =
     { EVENT_BAD_HEADER,                 "Format error in HTTP header" },
     { EVENT_CHUNK_OPTIONS,              "Chunk header options present" },
     { EVENT_URI_BAD_FORMAT,             "URI badly formatted" },
-    { EVENT_URI_BAD_PORT,               "URI bad port number" },
+    { EVENT_UNUSED,                     "Unused" },
     { EVENT_BROKEN_CHUNK,               "HTTP chunk misformatted" },
     { EVENT_CHUNK_WHITESPACE,           "White space following chunk length" },
     { EVENT_GZIP_OVERRUN,               "Excessive gzip compression" },
index 1164f74b1a6f3a565e7d95a5047c9bc8a7cddfb4..2ad39d1519d9c1843dfc6da9dfca8e3575f11009 100644 (file)
@@ -67,7 +67,7 @@ void NHttpTestInput::reset()
 
 // Read from the test data file and present to StreamSplitter. In the process we may need to skip
 // comments, execute simple commands, and handle escape sequences. The best way to understand this
-// function is to read the comments at the top of the file of test cases.
+// function is to read dev_notes.txt.
 void NHttpTestInput::scan(uint8_t*& data, uint32_t& length, SourceId source_id, uint64_t seq_num)
 {
     bool skip_to_break = false;
index 7f0011b9b420490d783f9d2c922d936d5671c0a3..927b39af03c731730fe74985c0b55d8865e5edba 100644 (file)
@@ -30,35 +30,30 @@ using namespace NHttpEnums;
 
 void NHttpUri::parse_uri()
 {
-    if (uri_type != URI__NOTCOMPUTE)
-    {
-        return;
-    }
-
     // Four basic types of HTTP URI
     // "*" means request does not apply to any specific resource
     if ((uri.length == 1) && (uri.start[0] == '*'))
     {
         uri_type = URI_ASTERISK;
-        scheme.length = STAT_NOTPRESENT;
-        authority.length = STAT_NOTPRESENT;
-        abs_path.length = STAT_NOTPRESENT;
+        scheme.length = STAT_NOT_PRESENT;
+        authority.length = STAT_NOT_PRESENT;
+        abs_path.length = STAT_NOT_PRESENT;
     }
     // CONNECT method uses an authority
     else if (method_id == METH_CONNECT)
     {
         uri_type = URI_AUTHORITY;
-        scheme.length = STAT_NOTPRESENT;
+        scheme.length = STAT_NOT_PRESENT;
         authority.length = uri.length;
         authority.start = uri.start;
-        abs_path.length = STAT_NOTPRESENT;
+        abs_path.length = STAT_NOT_PRESENT;
     }
     // Absolute path is a path but no scheme or authority
     else if (uri.start[0] == '/')
     {
         uri_type = URI_ABSPATH;
-        scheme.length = STAT_NOTPRESENT;
-        authority.length = STAT_NOTPRESENT;
+        scheme.length = STAT_NOT_PRESENT;
+        authority.length = STAT_NOT_PRESENT;
         abs_path.length = uri.length;
         abs_path.start = uri.start;
     }
@@ -92,200 +87,86 @@ void NHttpUri::parse_uri()
     }
 }
 
-SchemeId NHttpUri::get_scheme_id()
-{
-    if (scheme_id != SCH__NOTCOMPUTE)
-    {
-        return scheme_id;
-    }
-    if (get_scheme().length <= 0)
-    {
-        scheme_id = SCH__NOSOURCE;
-        return scheme_id;
-    }
-
-    // Normalize scheme name to lower case for matching purposes
-    uint8_t* lower_scheme;
-    if ((lower_scheme = scratch_pad.request(scheme.length)) == nullptr)
-    {
-        infractions += INF_NO_SCRATCH;
-        scheme_id = SCH__INSUFMEMORY;
-        return scheme_id;
-    }
-    norm_to_lower(scheme.start, scheme.length, lower_scheme, infractions, events);
-    scheme_id = (SchemeId)str_to_code(lower_scheme, scheme.length, scheme_list);
-    return scheme_id;
-}
-
-const Field& NHttpUri::get_norm_host()
-{
-    if (host_norm.length != STAT_NOTCOMPUTE)
-    {
-        return host_norm;
-    }
-    if (get_host().length < 0)
-    {
-        host_norm.length = STAT_NOSOURCE;
-        return host_norm;
-    }
-    UriNormalizer::normalize(host, host_norm, false, scratch_pad, infractions, events);
-    return host_norm;
-}
-
-const Field& NHttpUri::get_norm_path()
-{
-    if (path_norm.length != STAT_NOTCOMPUTE)
-    {
-        return path_norm;
-    }
-    if (get_path().length < 0)
-    {
-        path_norm.length = STAT_NOSOURCE;
-        return path_norm;
-    }
-    UriNormalizer::normalize(path, path_norm, true, scratch_pad, infractions, events);
-    return path_norm;
-}
-
-const Field& NHttpUri::get_norm_query()
-{
-    if (query_norm.length != STAT_NOTCOMPUTE)
-    {
-        return query_norm;
-    }
-    if (get_query().length < 0)
-    {
-        query_norm.length = STAT_NOSOURCE;
-        return query_norm;
-    }
-    UriNormalizer::normalize(query, query_norm, false, scratch_pad, infractions, events);
-    return query_norm;
-}
-
-const Field& NHttpUri::get_norm_fragment()
-{
-    if (fragment_norm.length != STAT_NOTCOMPUTE)
-    {
-        return fragment_norm;
-    }
-    if (get_fragment().length < 0)
-    {
-        fragment_norm.length = STAT_NOSOURCE;
-        return fragment_norm;
-    }
-    UriNormalizer::normalize(fragment, fragment_norm, false, scratch_pad, infractions, events);
-    return fragment_norm;
-}
-
-int32_t NHttpUri::get_port_value()
-{
-    if (port_value != STAT_NOTCOMPUTE)
-    {
-        return port_value;
-    }
-    if (get_port().length <= 0)
-    {
-        port_value = STAT_NOSOURCE;
-        return port_value;
-    }
-    port_value = 0;
-    for (int k = 0; k < port.length; k++)
-    {
-        port_value = port_value * 10 + (port.start[k] - '0');
-        if ((port.start[k] < '0') || (port.start[k] > '9') || (port_value > MAX_PORT_VALUE))
-        {
-            infractions += INF_BAD_PORT;
-            events.create_event(EVENT_URI_BAD_PORT);
-            port_value = STAT_PROBLEMATIC;
-            break;
-        }
-    }
-    return port_value;
-}
-
 void NHttpUri::parse_authority()
 {
-    if (host.length != STAT_NOTCOMPUTE)
+    if (authority.length <= 0)
     {
-        return;
-    }
-    if (get_authority().length <= 0)
-    {
-        host.length = STAT_NOSOURCE;
-        port.length = STAT_NOSOURCE;
+        host.length = STAT_NO_SOURCE;
+        port.length = STAT_NO_SOURCE;
         return;
     }
     host.start = authority.start;
     for (host.length = 0; (authority.start[host.length] != ':') && (host.length <
-        authority.length); host.length++)
-        ;
+        authority.length); host.length++);
     if (host.length < authority.length)
     {
         port.length = authority.length - host.length - 1;
         port.start = authority.start + host.length + 1;
     }
     else
-        port.length = STAT_NOTPRESENT;
+        port.length = STAT_NOT_PRESENT;
 }
 
 void NHttpUri::parse_abs_path()
 {
-    if (path.length != STAT_NOTCOMPUTE)
-        return;
-    if (get_abs_path().length <= 0)
+    // path?query#fragment
+    // path is always present in absolute path, while query and fragment are optional
+    if (abs_path.length <= 0)
     {
-        path.length = STAT_NOSOURCE;
-        query.length = STAT_NOSOURCE;
-        fragment.length = STAT_NOSOURCE;
+        path.length = STAT_NO_SOURCE;
+        query.length = STAT_NO_SOURCE;
+        fragment.length = STAT_NO_SOURCE;
         return;
     }
     path.start = abs_path.start;
     for (path.length = 0; (abs_path.start[path.length] != '?') && (abs_path.start[path.length] !=
-        '#') && (path.length < abs_path.length); path.length++)
-        ;
+        '#') && (path.length < abs_path.length); path.length++);
     if (path.length == abs_path.length)
     {
-        query.length = STAT_NOTPRESENT;
-        fragment.length = STAT_NOTPRESENT;
+        query.length = STAT_NOT_PRESENT;
+        fragment.length = STAT_NOT_PRESENT;
         return;
     }
     if (abs_path.start[path.length] == '?')
     {
         query.start = abs_path.start + path.length + 1;
         for (query.length = 0; (query.start[query.length] != '#') && (query.length <
-            abs_path.length - path.length - 1); query.length++)
-            ;
+            abs_path.length - path.length - 1); query.length++);
         fragment.start = query.start + query.length + 1;
         fragment.length = abs_path.length - path.length - 1 - query.length - 1;
     }
     else
     {
-        query.length = STAT_NOTPRESENT;
+        query.length = STAT_NOT_PRESENT;
         fragment.start = abs_path.start + path.length + 1;
         fragment.length = abs_path.length - path.length - 1;
     }
 }
 
-// Glue normalized URI fields back together
-const Field& NHttpUri::get_norm_legacy()
+void NHttpUri::normalize()
 {
-    if (legacy_norm.length != STAT_NOTCOMPUTE)
-    {
-        return legacy_norm;
-    }
-    if (get_path().length >= 0)
+    // FIXIT-P generating the normalized URI components directly into the normalized classic buffer
+    // would save a lot of memory and some copying.
+
+    // Divide the URI up into its six components: scheme, host, port, path, query, and fragment
+    parse_uri();
+    parse_authority();
+    parse_abs_path();
+
+    // Normalize the individual components. We don't do anything with scheme or port.
+    if (path.length >= 0)
     {
         UriNormalizer::normalize(path, path_norm, true, scratch_pad, infractions, events);
     }
-    if (get_host().length >= 0)
+    if (host.length >= 0)
     {
         UriNormalizer::normalize(host, host_norm, false, scratch_pad, infractions, events);
     }
-    if (get_query().length >= 0)
+    if (query.length >= 0)
     {
         UriNormalizer::normalize(query, query_norm, false, scratch_pad, infractions, events);
     }
-    if (get_fragment().length >= 0)
+    if (fragment.length >= 0)
     {
         UriNormalizer::normalize(fragment, fragment_norm, false, scratch_pad,
             infractions, events);
@@ -294,9 +175,9 @@ const Field& NHttpUri::get_norm_legacy()
     // We can reuse the raw URI for the normalized URI if no normalization is required
     if (!(infractions & INF_URI_NEED_NORM))
     {
-        legacy_norm.start = uri.start;
-        legacy_norm.length = uri.length;
-        return legacy_norm;
+        classic_norm.start = uri.start;
+        classic_norm.length = uri.length;
+        return;
     }
 
     // Glue normalized URI pieces back together
@@ -350,11 +231,10 @@ const Field& NHttpUri::get_norm_legacy()
         }
         assert(total_length == current - scratch);
         scratch_pad.commit(current - scratch);
-        legacy_norm.start = scratch;
-        legacy_norm.length = current - scratch;
+        classic_norm.start = scratch;
+        classic_norm.length = current - scratch;
     }
     else
-        legacy_norm.length = STAT_INSUFMEMORY;
-    return legacy_norm;
+        classic_norm.length = STAT_INSUF_MEMORY;
 }
 
index 2ce68db0d0ab85fa33d5b2412de3cb4bc5ab3a9f..4333f3c5810e11277fd9f51c4b09b02f77b7d297 100644 (file)
@@ -37,30 +37,25 @@ public:
     NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method,
         NHttpInfractions& infractions_, NHttpEventGen& events_) :
         uri(length, start), method_id(method), infractions(infractions_), events(events_),
-        scratch_pad(2*length+200) { }
+        scratch_pad(2*length+200) { normalize(); }
     const Field& get_uri() const { return uri; }
-    NHttpEnums::UriType get_uri_type() { parse_uri(); return uri_type; }
-    const Field& get_scheme() { parse_uri(); return scheme; }
-    const Field& get_authority() { parse_uri(); return authority; }
-    const Field& get_host() { parse_authority(); return host; }
-    const Field& get_port() { parse_authority(); return port; }
-    const Field& get_abs_path() { parse_uri(); return abs_path; }
-    const Field& get_path() { parse_abs_path(); return path; }
-    const Field& get_query() { parse_abs_path(); return query; }
-    const Field& get_fragment() { parse_abs_path(); return fragment; }
+    NHttpEnums::UriType get_uri_type() { return uri_type; }
+    const Field& get_scheme() { return scheme; }
+    const Field& get_authority() { return authority; }
+    const Field& get_host() { return host; }
+    const Field& get_port() { return port; }
+    const Field& get_abs_path() { return abs_path; }
+    const Field& get_path() { return path; }
+    const Field& get_query() { return query; }
+    const Field& get_fragment() { return fragment; }
 
-    NHttpEnums::SchemeId get_scheme_id();
-    const Field& get_norm_host();
-    int32_t get_port_value();
-    const Field& get_norm_path();
-    const Field& get_norm_query();
-    const Field& get_norm_fragment();
-    const Field& get_norm_legacy();
+    const Field& get_norm_host() { return host_norm; }
+    const Field& get_norm_path() { return path_norm; }
+    const Field& get_norm_query() { return query_norm; }
+    const Field& get_norm_fragment() { return fragment_norm; }
+    const Field& get_norm_classic() { return classic_norm; }
 
 private:
-    static const StrCode scheme_list[];
-    static const int MAX_PORT_VALUE = 65535;
-
     const Field uri;
     const NHttpEnums::MethodId method_id;
     NHttpInfractions& infractions;
@@ -75,19 +70,20 @@ private:
     Field query;
     Field fragment;
 
-    NHttpEnums::UriType uri_type = NHttpEnums::URI__NOTCOMPUTE;
-    NHttpEnums::SchemeId scheme_id = NHttpEnums::SCH__NOTCOMPUTE;
+    NHttpEnums::UriType uri_type = NHttpEnums::URI__NOT_COMPUTE;
     Field host_norm;
-    int32_t port_value = NHttpEnums::STAT_NOTCOMPUTE;
     Field path_norm;
     Field query_norm;
     Field fragment_norm;
-    Field legacy_norm;
+    Field classic_norm;
 
+    void normalize();
     void parse_uri();
     void parse_authority();
     void parse_abs_path();
 
+    // FIXIT-P there is an enormous memory waste that this is always allocated. It is only needed
+    // when the URI requires normalization. Most of the time the raw URI is already in normal form.
     ScratchPad scratch_pad;
 };
 
index 4b08fe3a94c9a769e74b1698e815d7f770ad8a10..6d7514b92a09e65c17a6c3e5039a51ebcafea17c 100644 (file)
@@ -28,10 +28,6 @@ using namespace NHttpEnums;
 void UriNormalizer::normalize(const Field& input, Field& result, bool do_path,
     ScratchPad& scratch_pad, NHttpInfractions& infractions, NHttpEventGen& events)
 {
-    if (result.length != STAT_NOTCOMPUTE)
-        return;
-    assert (input.length >= 0);
-
     // Almost all HTTP requests are honest and rarely need expensive normalization processing. We
     // do a quick scan for red flags and only perform normalization if something comes up.
     // Otherwise we set the normalized field to point at the raw value.
@@ -50,7 +46,7 @@ void UriNormalizer::normalize(const Field& input, Field& result, bool do_path,
     uint8_t* const scratch = scratch_pad.request(2 * buffer_length);
     if (scratch == nullptr)
     {
-        result.length = STAT_INSUFMEMORY;
+        result.length = STAT_INSUF_MEMORY;
         return;
     }
     uint8_t* const front_half = scratch;