]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #519 in SNORT/snort3 from nhttp46 to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Thu, 16 Jun 2016 16:28:05 +0000 (12:28 -0400)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Thu, 16 Jun 2016 16:28:05 +0000 (12:28 -0400)
Squashed commit of the following:

commit b0b0ceffa796e2ee7e0538edcdeb994db8abdfe4
Author: Tom Peters <thopeter@cisco.com>
Date:   Thu Jun 16 11:42:29 2016 -0400

    code review fix

commit aa9e862c5c243d3cda48c6af893c55b074acb8f1
Author: Tom Peters <thopeter@cisco.com>
Date:   Mon Jun 13 12:12:37 2016 -0400

    NHI peg counts

24 files changed:
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_inspect.cc
src/service_inspectors/nhttp_inspect/nhttp_module.cc
src/service_inspectors/nhttp_inspect/nhttp_module.h
src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc
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_status.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_reassemble.cc
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_scan.cc
src/service_inspectors/nhttp_inspect/nhttp_tables.cc
src/service_inspectors/nhttp_inspect/nhttp_test_input.cc
src/service_inspectors/nhttp_inspect/nhttp_test_manager.cc
src/service_inspectors/nhttp_inspect/nhttp_test_manager.h
src/service_inspectors/nhttp_inspect/nhttp_uri.cc
src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc
src/service_inspectors/nhttp_inspect/test/CMakeLists.txt
src/service_inspectors/nhttp_inspect/test/Makefile.am
src/service_inspectors/nhttp_inspect/test/nhttp_module_test.cc [new file with mode: 0644]

index a58eb0d02ed14e166b399f71eb4e94bc7c395553..551a8892458f9e10ff6ad5f99926dbce2bc50fa5 100644 (file)
@@ -33,7 +33,7 @@ Inspector* NHttpApi::nhttp_ctor(Module* mod)
     return new NHttpInspect(nhttp_mod->get_once_params());
 }
 
-const char* NHttpApi::classic_buffers[] =
+const char* NHttpApi::classic_buffer_names[] =
 {
     "http_client_body",
     "http_cookie",
@@ -69,7 +69,7 @@ const InspectApi NHttpApi::nhttp_api =
     },
     IT_SERVICE,
     (uint16_t)PktType::PDU,
-    classic_buffers,
+    classic_buffer_names,
     "http",
     NHttpApi::nhttp_init,
     NHttpApi::nhttp_term,
index 39926bd7163109db60f3948cb69e3ad5e792ec32..a9e844479a77c94f725976caf344e26582e18807 100644 (file)
@@ -31,7 +31,7 @@ class NHttpApi
 {
 public:
     static const InspectApi nhttp_api;
-    static const char* classic_buffers[];
+    static const char* classic_buffer_names[];
 
 private:
     NHttpApi() = delete;
index e9292843500b48af15651dea9dd83c9bd6cb09f9..6c5ac23c32429592a4bcdbd6f1709c9f87215316 100644 (file)
@@ -52,13 +52,20 @@ enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOT_COMPUTE=-14, SEC
     SEC_BODY_OLD };
 
 // Message buffers available to clients
-// This enum must remain synchronized with classic_buffers[]
+// This enum must remain synchronized with NHttpApi::classic_buffer_names[]
 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_RAW_REQUEST,
     NHTTP_BUFFER_RAW_STATUS, NHTTP_BUFFER_MAX };
 
+// Peg counts
+// This enum must remain synchronized with NHttpModule::peg_names[] in nhttp_tables.cc
+enum PEG_COUNT { PEG_FLOW = 0, PEG_SCAN, PEG_REASSEMBLE, PEG_INSPECT, PEG_REQUEST, PEG_RESPONSE,
+    PEG_GET, PEG_HEAD, PEG_POST, PEG_PUT, PEG_DELETE, PEG_CONNECT, PEG_OPTIONS, PEG_TRACE,
+    PEG_OTHER_METHOD, PEG_REQUEST_BODY, PEG_CHUNKED, PEG_URI_NORM, PEG_URI_PATH, PEG_URI_CODING,
+    PEG_COUNT_MAX };
+
 // Result of scanning by splitter
 enum ScanResult { SCAN_NOTFOUND, SCAN_FOUND, SCAN_FOUND_PIECE, SCAN_DISCARD, SCAN_DISCARD_PIECE,
     SCAN_ABORT, SCAN_END };
@@ -133,7 +140,7 @@ enum Infraction
     INF_URI_PERCENT_UTF8_3B,
     INF_URI_PERCENT_UNRESERVED,
     INF_URI_PERCENT_UTF8_2B,
-    INF_URI_PERCENT_UCODE,
+    INF_NOT_USED_1,
     INF_URI_PERCENT_OTHER,
     INF_URI_BAD_CHAR,
     INF_URI_8BIT_CHAR,
@@ -173,9 +180,9 @@ enum Infraction
     INF_URI_NEED_NORM_HOST,
     INF_URI_NEED_NORM_QUERY,
     INF_URI_NEED_NORM_FRAGMENT,
-    INF_U_ENCODE,
-    INF_UNKNOWN_PERCENT,
-    INF_DOUBLE_DECODE,
+    INF_URI_U_ENCODE,
+    INF_URI_UNKNOWN_PERCENT,
+    INF_URI_DOUBLE_DECODE,
     INF_MULTIPLE_CONTLEN,
     INF_BOTH_CL_AND_TE,
     INF_BAD_CODE_BODY_HEADER,
index 2271c681b4f0deccef1a568cec0c51b3d467198d..15b5e665eb489689e4f49021a6b5c5eb35a1f2ce 100644 (file)
@@ -52,6 +52,7 @@ NHttpInspect::NHttpInspect(const NHttpParaList* params_) : params(params_)
     }
     NHttpTestManager::set_print_amount(params->print_amount);
     NHttpTestManager::set_print_hex(params->print_hex);
+    NHttpTestManager::set_show_pegs(params->show_pegs);
 #endif
 }
 
@@ -129,6 +130,8 @@ const Field& NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Fl
         NHttpFlowData::nhttp_flow_id);
     assert(session_data != nullptr);
 
+    NHttpModule::increment_peg_counts(PEG_INSPECT);
+
     switch (session_data->section_type[source_id])
     {
     case SEC_REQUEST:
index 779e311da70d72509fd1972e8ae696509fe2a283..4206982585bbe83c9ba6ff0355eb819d5c3f642c 100644 (file)
@@ -65,10 +65,13 @@ const Parameter NHttpModule::nhttp_params[] =
           "number of characters to print from a Field" },
     { "print_hex", Parameter::PT_BOOL, nullptr, "false",
       "nonprinting characters printed in [HH] format instead of using an asterisk" },
+    { "show_pegs", Parameter::PT_BOOL, nullptr, "true", "display peg counts with test output" },
 #endif
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
+THREAD_LOCAL PegCount NHttpModule::peg_counts[PEG_COUNT_MAX] = { 0 };
+
 bool NHttpModule::begin(const char*, int, SnortConfig*)
 {
     delete params;
@@ -163,6 +166,10 @@ bool NHttpModule::set(const char*, Value& val, SnortConfig*)
     {
         params->print_hex = val.get_bool();
     }
+    else if (val.is("show_pegs"))
+    {
+        params->show_pegs = val.get_bool();
+    }
 #endif
     else
     {
index 99789eee039dbcf9b8114dbf30a3aebe72a81095..7197d6f4e640fd7d06eca4ca3e0389c95fe61b95 100644 (file)
@@ -63,6 +63,7 @@ public:
     bool test_output;
     long print_amount;
     bool print_hex;
+    bool show_pegs;
 #endif
 };
 
@@ -83,10 +84,26 @@ public:
         return ret_val;
     }
 
+    const PegInfo* get_pegs() const override { return peg_names; }
+    PegCount* get_counts() const override { return peg_counts; }
+    static void increment_peg_counts(NHttpEnums::PEG_COUNT counter)
+        { peg_counts[counter]++; return; }
+
+#ifdef REG_TEST
+    static const PegInfo* get_peg_names() { return peg_names; }
+    static const PegCount* get_peg_counts() { return peg_counts; }
+    static void reset_peg_counts()
+    {
+        for (unsigned k=0; k < NHttpEnums::PEG_COUNT_MAX; peg_counts[k++] = 0);
+    }
+#endif
+
 private:
     static const Parameter nhttp_params[];
     static const RuleMap nhttp_events[];
     NHttpParaList* params = nullptr;
+    static const PegInfo peg_names[];
+    static THREAD_LOCAL PegCount peg_counts[];
 };
 
 #endif
index 6e212e22004bbe4974f3710714f32d23ee598387..7535f927a4b71caec6345350fc455b803a072760 100644 (file)
@@ -147,7 +147,7 @@ void NHttpMsgBody::print_body_section(FILE* output)
 {
     detect_data.print(output, "Detect data");
     get_classic_buffer(NHTTP_BUFFER_CLIENT_BODY, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_CLIENT_BODY-1]);
+        NHttpApi::classic_buffer_names[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 c73a8943092e5e20b3eac15056a7a36c76026305..f747058a8a0233556c65b16a1d6d742cf7069e6b 100644 (file)
@@ -26,6 +26,7 @@
 #include "file_api/file_service.h"
 #include "file_api/file_flows.h"
 
+#include "nhttp_module.h"
 #include "nhttp_api.h"
 #include "nhttp_normalizers.h"
 #include "nhttp_msg_request.h"
@@ -108,6 +109,7 @@ void NHttpMsgHeader::update_flow()
         {
             // Chunked body
             session_data->type_expected[source_id] = SEC_BODY_CHUNK;
+            NHttpModule::increment_peg_counts(PEG_CHUNKED);
             prepare_body();
             return;
         }
@@ -178,6 +180,10 @@ void NHttpMsgHeader::prepare_body()
     update_depth();
     session_data->infractions[source_id].reset();
     session_data->events[source_id].reset();
+    if (source_id == SRC_CLIENT)
+    {
+        NHttpModule::increment_peg_counts(PEG_REQUEST_BODY);
+    }
 }
 
 void NHttpMsgHeader::setup_file_processing()
@@ -252,13 +258,13 @@ void NHttpMsgHeader::print_section(FILE* output)
     NHttpMsgSection::print_section_title(output, "header");
     NHttpMsgHeadShared::print_headers(output);
     get_classic_buffer(NHTTP_BUFFER_COOKIE, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_COOKIE-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_COOKIE-1]);
     get_classic_buffer(NHTTP_BUFFER_HEADER, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_HEADER-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_HEADER-1]);
     get_classic_buffer(NHTTP_BUFFER_RAW_COOKIE, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_COOKIE-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_RAW_COOKIE-1]);
     get_classic_buffer(NHTTP_BUFFER_RAW_HEADER, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_HEADER-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_RAW_HEADER-1]);
     NHttpMsgSection::print_section_wrapup(output);
 }
 #endif
index 74009df65ba79cfbb87a756805c9688383b9a84b..814e711c2a7c637f83d800466d2a45858224868f 100644 (file)
@@ -41,10 +41,7 @@ NHttpMsgRequest::NHttpMsgRequest(const uint8_t* buffer, const uint16_t buf_size,
 
 void NHttpMsgRequest::parse_start_line()
 {
-    // Status line: "HTTP/X.Y KLM <text>" where X, Y, K, L, and M are decimal digits
     // Check the version field
-    // FIXIT-L An idea would be to move this test into the cutter and abort the scan() instead of
-    // allowing it to come here.
     if ((start_line.length < 10) || !is_sp_tab[start_line.start[start_line.length-9]] ||
          memcmp(start_line.start + start_line.length - 8, "HTTP/", 5))
     {
@@ -57,6 +54,8 @@ void NHttpMsgRequest::parse_start_line()
         return;
     }
 
+    NHttpModule::increment_peg_counts(PEG_REQUEST);
+
     // The splitter guarantees there will be a non-whitespace at octet 1 and a whitespace within
     // octets 2-81. The following algorithm uses those assumptions.
 
@@ -76,6 +75,19 @@ void NHttpMsgRequest::parse_start_line()
     method.length = first_space;
     method_id = (MethodId)str_to_code(method.start, method.length, method_list);
 
+    switch (method_id)
+    {
+    case METH_GET: NHttpModule::increment_peg_counts(PEG_GET); break;
+    case METH_HEAD: NHttpModule::increment_peg_counts(PEG_HEAD); break;
+    case METH_POST: NHttpModule::increment_peg_counts(PEG_POST); break;
+    case METH_PUT: NHttpModule::increment_peg_counts(PEG_PUT); break;
+    case METH_DELETE: NHttpModule::increment_peg_counts(PEG_DELETE); break;
+    case METH_CONNECT: NHttpModule::increment_peg_counts(PEG_CONNECT); break;
+    case METH_OPTIONS: NHttpModule::increment_peg_counts(PEG_OPTIONS); break;
+    case METH_TRACE: NHttpModule::increment_peg_counts(PEG_TRACE); break;
+    default: NHttpModule::increment_peg_counts(PEG_OTHER_METHOD); break;
+    }
+
     version.start = start_line.start + (start_line.length - 8);
     version.length = 8;
     derive_version_id();
@@ -264,15 +276,15 @@ void NHttpMsgRequest::print_section(FILE* output)
         uri->get_norm_fragment().print(output, "Normalized Fragment");
     }
     get_classic_buffer(NHTTP_BUFFER_METHOD, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_METHOD-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_METHOD-1]);
     get_classic_buffer(NHTTP_BUFFER_RAW_URI, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_URI-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_RAW_URI-1]);
     get_classic_buffer(NHTTP_BUFFER_URI, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_URI-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_URI-1]);
     get_classic_buffer(NHTTP_BUFFER_VERSION, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_VERSION-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_VERSION-1]);
     get_classic_buffer(NHTTP_BUFFER_RAW_REQUEST, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_REQUEST-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_RAW_REQUEST-1]);
     NHttpMsgSection::print_section_wrapup(output);
 }
 
index d87ecb437c04bf0e8d9b426aea6e0d1d4d1cfddd..f9d617b678194891cdd0a19a64055e29c00ea839 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "nhttp_enum.h"
 #include "nhttp_transaction.h"
+#include "nhttp_test_manager.h"
 #include "nhttp_msg_section.h"
 #include "nhttp_msg_request.h"
 #include "nhttp_msg_status.h"
@@ -222,9 +223,29 @@ void NHttpMsgSection::print_section_wrapup(FILE* output) const
     fprintf(output, "Infractions: %016" PRIx64 " %016" PRIx64 ", Events: %016" PRIx64 " %016"
         PRIx64 ", TCP Close: %s\n\n", infractions.get_raw2(), infractions.get_raw(),
         events.get_raw2(), events.get_raw(), tcp_close ? "True" : "False");
+    if (NHttpTestManager::get_show_pegs())
+    {
+        print_peg_counts(output);
+    }
     session_data->show(output);
     fprintf(output, "\n");
 }
 
+void NHttpMsgSection::print_peg_counts(FILE* output) const
+{
+    const PegInfo* const peg_names = NHttpModule::get_peg_names();
+    const PegCount* const peg_counts = NHttpModule::get_peg_counts();
+
+    fprintf(output, "Peg Counts\n");
+    for (unsigned k = 0; k < PEG_COUNT_MAX; k++)
+    {
+        if (peg_counts[k] > 0)
+        {
+            fprintf(output, "%s: %" PRIu64 "\n", peg_names[k].name, peg_counts[k]);
+        }
+    }
+    fprintf(output, "\n");
+}
+
 #endif
 
index d005336ec66f9d19e2dbcc884e14b91746adfb71..61c58346641adcb2dfa2c67212d3151bd14bc7a4 100644 (file)
@@ -87,6 +87,7 @@ protected:
 #ifdef REG_TEST
     void print_section_title(FILE* output, const char* title) const;
     void print_section_wrapup(FILE* output) const;
+    void print_peg_counts(FILE* output) const;
 #endif
 
 private:
index b5a2f449663c74ca61bbc7fd772909f83b2524e1..c35a7b2a0e693e5bdc6eb9848454504e5a29595f 100644 (file)
@@ -71,6 +71,8 @@ void NHttpMsgStatus::parse_start_line()
         return;
     }
 
+    NHttpModule::increment_peg_counts(PEG_RESPONSE);
+
     version.start = start_line.start;
     version.length = 8;
     derive_version_id();
@@ -173,13 +175,13 @@ void NHttpMsgStatus::print_section(FILE* output)
     fprintf(output, "Status Code Num: %d\n", status_code_num);
     reason_phrase.print(output, "Reason Phrase");
     get_classic_buffer(NHTTP_BUFFER_STAT_CODE, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_STAT_CODE-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_STAT_CODE-1]);
     get_classic_buffer(NHTTP_BUFFER_STAT_MSG, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_STAT_MSG-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_STAT_MSG-1]);
     get_classic_buffer(NHTTP_BUFFER_VERSION, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_VERSION-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_VERSION-1]);
     get_classic_buffer(NHTTP_BUFFER_RAW_STATUS, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_STATUS-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_RAW_STATUS-1]);
     NHttpMsgSection::print_section_wrapup(output);
 }
 #endif
index 15365a8083e05a7c2b1d06da0c569085db5040ba..10b95fc9f76b46000d0928f5f0f8dabc3851e2cb 100644 (file)
@@ -49,9 +49,9 @@ void NHttpMsgTrailer::print_section(FILE* output)
     NHttpMsgSection::print_section_title(output, "trailer");
     NHttpMsgHeadShared::print_headers(output);
     get_classic_buffer(NHTTP_BUFFER_TRAILER, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_TRAILER-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_TRAILER-1]);
     get_classic_buffer(NHTTP_BUFFER_RAW_TRAILER, 0, 0).print(output,
-        NHttpApi::classic_buffers[NHTTP_BUFFER_RAW_TRAILER-1]);
+        NHttpApi::classic_buffer_names[NHTTP_BUFFER_RAW_TRAILER-1]);
     NHttpMsgSection::print_section_wrapup(output);
 }
 #endif
index 877b4c360c75affaf8ffe5f010e0b23cbe640bc8..f644ff86a4948df2e9b6e2de2859d4b0ece0a593 100644 (file)
@@ -284,6 +284,8 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
         return nullptr;
     }
 
+    NHttpModule::increment_peg_counts(PEG_REASSEMBLE);
+
     uint8_t*& buffer = session_data->section_buffer[source_id];
 
     const bool is_body = (session_data->section_type[source_id] == SEC_BODY_CHUNK) ||
index 9ace222a4b4500792dede960bda465ebb165d329..f9f57db363b50e318d1891784c98775b95410b4c 100644 (file)
@@ -90,6 +90,7 @@ StreamSplitter::Status NHttpStreamSplitter::scan(Flow* flow, const uint8_t* data
     if (session_data == nullptr)
     {
         flow->set_application_data(session_data = new NHttpFlowData);
+        NHttpModule::increment_peg_counts(PEG_FLOW);
     }
 
     SectionType type = session_data->type_expected[source_id];
@@ -120,6 +121,8 @@ StreamSplitter::Status NHttpStreamSplitter::scan(Flow* flow, const uint8_t* data
 
     assert(!session_data->tcp_close[source_id]);
 
+    NHttpModule::increment_peg_counts(PEG_SCAN);
+
     // Check for 0.9 response message
     if ((type == SEC_STATUS) &&
         (session_data->expected_msg_num[SRC_SERVER] == session_data->zero_nine_expected))
index 1053175906eb881ae6a8a9adcd3217a0239ec980..78da33054af12fe72634962ff47447c5198454ab 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/types.h>
 
 #include "framework/module.h"
+#include "framework/counts.h"
 
 #include "nhttp_enum.h"
 #include "nhttp_str_to_code.h"
@@ -335,6 +336,31 @@ const RuleMap NHttpModule::nhttp_events[] =
     { 0, nullptr }
 };
 
+const PegInfo NHttpModule::peg_names[PEG_COUNT_MAX+1] =
+{
+    { "flows", "HTTP connections inspected" },
+    { "scans", "TCP segments scanned looking for HTTP messages" },
+    { "reassembles", "TCP segments combined into HTTP messages" },
+    { "inspections", "total message sections inspected" },
+    { "requests", "HTTP request messages inspected" },
+    { "responses", "HTTP response messages inspected" },
+    { "GET requests", "GET requests inspected" },
+    { "HEAD requests", "HEAD requests inspected" },
+    { "POST requests", "POST requests inspected" },
+    { "PUT requests", "PUT requests inspected" },
+    { "DELETE requests", "DELETE requests inspected" },
+    { "CONNECT requests", "CONNECT requests inspected" },
+    { "OPTIONS requests", "OPTIONS requests inspected" },
+    { "TRACE requests", "TRACE requests inspected" },
+    { "other requests", "other request methods inspected" },
+    { "request bodies", "POST, PUT, and other requests with message bodies" },
+    { "chunked", "chunked message bodies" },
+    { "URI normalizations", "URIs needing to be normalization" },
+    { "URI path", "URIs with path problems" },
+    { "URI coding", "URIs with character coding problems" },
+    { nullptr, nullptr }
+};
+
 const int8_t NHttpEnums::as_hex[256] =
 {
     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
index 9ce2df21c0eadd72690d55721f1668f71859f2eb..b7ee651dde579915bcb54bad69760f76bfb84c88 100644 (file)
@@ -22,6 +22,7 @@
 #include <assert.h>
 #include <stdexcept>
 
+#include "nhttp_module.h"
 #include "nhttp_test_manager.h"
 #include "nhttp_test_input.h"
 
@@ -63,6 +64,9 @@ void NHttpTestInput::reset()
         fclose(include_file);
         include_file = nullptr;
     }
+
+    // Each test needs separate peg counts
+    NHttpModule::reset_peg_counts();
 }
 
 // Read from the test data file and present to StreamSplitter. In the process we may need to skip
index 52a4f6b6aa654a34c3695e15d6c1192197844211..30b7a4ffa67da3d28ff69dd1179b15652f3bb54c 100644 (file)
@@ -32,6 +32,7 @@ int64_t NHttpTestManager::test_number = -1;
 FILE* NHttpTestManager::test_out = nullptr;
 long NHttpTestManager::print_amount = 1200;
 bool NHttpTestManager::print_hex = false;
+bool NHttpTestManager::show_pegs = true;
 
 void NHttpTestManager::update_test_number(int64_t new_test_number)
 {
index 388032944a92fc8f020257495b98c0ed08f1ec85..d13e0e616cbd289158bce31fae0097b9dd03d887 100644 (file)
@@ -46,6 +46,8 @@ public:
     static long get_print_amount() { return print_amount; }
     static void set_print_hex(bool print_hex_) { print_hex = print_hex_; }
     static bool get_print_hex() { return print_hex; }
+    static void set_show_pegs(bool show_pegs_) { show_pegs = show_pegs_; }
+    static bool get_show_pegs() { return show_pegs; }
 
 private:
     NHttpTestManager() = delete;
@@ -60,6 +62,7 @@ private:
     static int64_t test_number;
     static long print_amount;
     static bool print_hex;
+    static bool show_pegs;
 };
 
 #endif
index fe579f57197df5801dedfa198a8b52dd27c4c579..e4d32667f12a3d4a5fe6d0d21c424630cb8e1d86 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdio.h>
 
 #include "nhttp_enum.h"
+#include "nhttp_module.h"
 #include "nhttp_uri.h"
 
 using namespace NHttpEnums;
@@ -177,6 +178,7 @@ void NHttpUri::normalize()
     if (!((infractions & INF_URI_NEED_NORM_PATH)  || (infractions & INF_URI_NEED_NORM_HOST) ||
           (infractions & INF_URI_NEED_NORM_QUERY) || (infractions & INF_URI_NEED_NORM_FRAGMENT)))
     {
+        // This URI is OK, normalization not required
         host_norm = host;
         path_norm = path;
         query_norm = query;
@@ -185,6 +187,8 @@ void NHttpUri::normalize()
         return;
     }
 
+    NHttpModule::increment_peg_counts(PEG_URI_NORM);
+
     // Create a new buffer containing the normalized URI by normalizing each individual piece.
     const uint32_t total_length = uri.length + UriNormalizer::URI_NORM_EXPANSION;
     uint8_t* const new_buf = new uint8_t[total_length];
@@ -260,6 +264,20 @@ void NHttpUri::normalize()
         current += fragment_norm.length;
     }
     assert(current - new_buf <= total_length);
+
+    if ((infractions & INF_URI_MULTISLASH) || (infractions & INF_URI_SLASH_DOT) ||
+        (infractions & INF_URI_SLASH_DOT_DOT))
+    {
+        NHttpModule::increment_peg_counts(PEG_URI_PATH);
+    }
+
+    if ((infractions & INF_URI_U_ENCODE) || (infractions & INF_URI_UNKNOWN_PERCENT) ||
+        (infractions & INF_URI_PERCENT_UNRESERVED) || (infractions & INF_URI_PERCENT_UTF8_2B) ||
+        (infractions & INF_URI_PERCENT_UTF8_3B) || (infractions & INF_URI_DOUBLE_DECODE))
+    {
+        NHttpModule::increment_peg_counts(PEG_URI_CODING);
+    }
+
     classic_norm.set(current - new_buf, new_buf);
     classic_norm_allocated = true;
 }
index e244d450022d0944b8de04cfde30bef6460cd641..0f79a9b3bf2236ed8c6f32b5d9ab8f862bbadc22 100644 (file)
@@ -182,7 +182,7 @@ int32_t UriNormalizer::norm_percent_processing(const Field& input, uint8_t* out_
             else if (uri_param.percent_u && is_u_encoding(input, k))
             {
                 // %u encoding, this is nonstandard and likely to be malicious
-                infractions += INF_U_ENCODE;
+                infractions += INF_URI_U_ENCODE;
                 events.create_event(EVENT_U_ENCODE);
                 percent_encoded[length] = true;
                 const uint8_t byte_val = reduce_to_eight_bits(extract_u_encoding(input, k),
@@ -197,7 +197,7 @@ int32_t UriNormalizer::norm_percent_processing(const Field& input, uint8_t* out_
             else
             {
                 // don't recognize, pass it through
-                infractions += INF_UNKNOWN_PERCENT;
+                infractions += INF_URI_UNKNOWN_PERCENT;
                 events.create_event(EVENT_UNKNOWN_PERCENT);
                 double_decoding_needed = true;
                 out_buf[length++] = '%';
@@ -295,16 +295,16 @@ int32_t UriNormalizer::norm_double_decode(const Field& input, uint8_t* out_buf,
         {
             if (is_percent_encoding(input, k))
             {
-                infractions += INF_DOUBLE_DECODE;
+                infractions += INF_URI_DOUBLE_DECODE;
                 events.create_event(EVENT_DOUBLE_DECODE);
                 out_buf[length++] = extract_percent_encoding(input, k);
                 k += 2;
             }
             else if (uri_param.percent_u && is_u_encoding(input, k))
             {
-                infractions += INF_DOUBLE_DECODE;
+                infractions += INF_URI_DOUBLE_DECODE;
                 events.create_event(EVENT_DOUBLE_DECODE);
-                infractions += INF_U_ENCODE;
+                infractions += INF_URI_U_ENCODE;
                 events.create_event(EVENT_U_ENCODE);
                 out_buf[length++] = reduce_to_eight_bits(extract_u_encoding(input, k), uri_param,
                     infractions, events);
index e19c94e53d1ffc97cef311d49faa51b4b566265e..cee1fa8afa3d9ce3becc87cea4d6e2b3846f516c 100644 (file)
@@ -1,3 +1,4 @@
 add_cpputest(nhttp_uri_norm_test nhttp_inspect framework)
 add_cpputest(nhttp_normalizers_test nhttp_inspect framework)
+add_cpputest(nhttp_module_test nhttp_inspect framework)
 
index 1628ff562b7fad87b09349d20b676b6131b2705d..1f28e9cd1abe07c6cebdb9db52feeabd89ec53b8 100644 (file)
@@ -3,7 +3,8 @@ AM_DEFAULT_SOURCE_EXT = .cc
 
 check_PROGRAMS = \
 nhttp_uri_norm_test \
-nhttp_normalizers_test
+nhttp_normalizers_test \
+nhttp_module_test
 
 TESTS = $(check_PROGRAMS)
 
@@ -26,3 +27,13 @@ nhttp_normalizers_test_LDADD = \
 ../nhttp_field.o \
 @CPPUTEST_LDFLAGS@
 
+nhttp_module_test_CPPFLAGS = $(AM_CPPFLAGS) @CPPUTEST_CPPFLAGS@
+nhttp_module_test_LDADD = \
+../nhttp_module.o \
+../nhttp_tables.o \
+../nhttp_normalizers.o \
+../nhttp_uri_norm.o \
+../nhttp_field.o \
+../../../framework/module.o \
+@CPPUTEST_LDFLAGS@
+
diff --git a/src/service_inspectors/nhttp_inspect/test/nhttp_module_test.cc b/src/service_inspectors/nhttp_inspect/test/nhttp_module_test.cc
new file mode 100644 (file)
index 0000000..c854b6b
--- /dev/null
@@ -0,0 +1,106 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// nhttp_module_test.cc author Tom Peters <thopeter@cisco.com>
+// unit test main
+
+#include "log/messages.h"
+#include "events/event_queue.h"
+
+#include "service_inspectors/nhttp_inspect/nhttp_module.h"
+#include "service_inspectors/nhttp_inspect/nhttp_test_manager.h"
+#include "service_inspectors/nhttp_inspect/nhttp_str_to_code.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+using namespace NHttpEnums;
+
+// Stubs whose sole purpose is to make the test code link
+void ParseWarning(WarningGroup, const char*, ...) {}
+void ParseError(const char*, ...) {}
+
+void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
+void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*, FILE*) { }
+void show_stats(SimpleStats*, const char*) { }
+
+void Value::get_bits(std::bitset<256ul>&) const {}
+int SnortEventqAdd(unsigned int, unsigned int, RuleType) { return 0; }
+
+int32_t str_to_code(const uint8_t*, const int32_t, const StrCode []) { return 0; }
+long NHttpTestManager::print_amount {};
+bool NHttpTestManager::print_hex {};
+
+TEST_GROUP(nhttp_peg_count_test)
+{
+    NHttpModule mod;
+
+    void setup()
+    {
+        PegCount* counts = mod.get_counts();
+        for (unsigned k=0; k < PEG_COUNT_MAX; k++)
+        {
+            CHECK(counts[k] == 0);
+        }
+    }
+
+    void teardown()
+    {
+        PegCount* counts = mod.get_counts();
+        for (unsigned k=0; k < PEG_COUNT_MAX; k++)
+        {
+            counts[k] = 0;
+        }
+    }
+};
+
+TEST(nhttp_peg_count_test, increment)
+{
+    for (unsigned k=0; k < 13; k++)
+    {
+        NHttpModule::increment_peg_counts(PEG_SCAN);
+    }
+    for (unsigned k=0; k < 27816; k++)
+    {
+       NHttpModule::increment_peg_counts(PEG_INSPECT);
+    }
+    PegCount* counts = mod.get_counts();
+    CHECK(counts[PEG_SCAN] == 13);
+    CHECK(counts[PEG_INSPECT] == 27816);
+}
+
+TEST(nhttp_peg_count_test, zero_out)
+{
+    for (unsigned k=0; k < 12; k++)
+    {
+        NHttpModule::increment_peg_counts(PEG_INSPECT);
+    }
+    PegCount* counts = mod.get_counts();
+    CHECK(counts[PEG_INSPECT] == 12);
+    counts[PEG_INSPECT] = 0;
+    NHttpModule::increment_peg_counts(PEG_INSPECT);
+    counts = mod.get_counts();
+    CHECK(counts[PEG_INSPECT] == 1);
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
+