From: Russ Combs (rucombs) Date: Thu, 16 Jun 2016 16:28:05 +0000 (-0400) Subject: Merge pull request #519 in SNORT/snort3 from nhttp46 to master X-Git-Tag: 3.0.0-233~364^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4797a1b5e66e674e95d61474f6e3ef1a028fcb51;p=thirdparty%2Fsnort3.git Merge pull request #519 in SNORT/snort3 from nhttp46 to master Squashed commit of the following: commit b0b0ceffa796e2ee7e0538edcdeb994db8abdfe4 Author: Tom Peters Date: Thu Jun 16 11:42:29 2016 -0400 code review fix commit aa9e862c5c243d3cda48c6af893c55b074acb8f1 Author: Tom Peters Date: Mon Jun 13 12:12:37 2016 -0400 NHI peg counts --- diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.cc b/src/service_inspectors/nhttp_inspect/nhttp_api.cc index a58eb0d02..551a88924 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.cc @@ -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, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.h b/src/service_inspectors/nhttp_inspect/nhttp_api.h index 39926bd71..a9e844479 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.h @@ -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; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_enum.h b/src/service_inspectors/nhttp_inspect/nhttp_enum.h index e92928435..6c5ac23c3 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_enum.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_enum.h @@ -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, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc index 2271c681b..15b5e665e 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc @@ -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: diff --git a/src/service_inspectors/nhttp_inspect/nhttp_module.cc b/src/service_inspectors/nhttp_inspect/nhttp_module.cc index 779e311da..420698258 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_module.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_module.cc @@ -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 { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_module.h b/src/service_inspectors/nhttp_inspect/nhttp_module.h index 99789eee0..7197d6f4e 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_module.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_module.h @@ -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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc index 6e212e220..7535f927a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc @@ -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"); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc index c73a89430..f747058a8 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc @@ -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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc index 74009df65..814e711c2 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc @@ -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 " 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); } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc index d87ecb437..f9d617b67 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc @@ -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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h index d005336ec..61c583466 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h @@ -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: diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc index b5a2f4496..c35a7b2a0 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc @@ -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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc index 15365a808..10b95fc9f 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc @@ -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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_reassemble.cc b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_reassemble.cc index 877b4c360..f644ff86a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_reassemble.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_reassemble.cc @@ -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) || diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_scan.cc b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_scan.cc index 9ace222a4..f9f57db36 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_scan.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter_scan.cc @@ -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)) diff --git a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc index 105317590..78da33054 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc @@ -25,6 +25,7 @@ #include #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, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc index 9ce2df21c..b7ee651dd 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc @@ -22,6 +22,7 @@ #include #include +#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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_manager.cc b/src/service_inspectors/nhttp_inspect/nhttp_test_manager.cc index 52a4f6b6a..30b7a4ffa 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_manager.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_manager.cc @@ -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) { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_manager.h b/src/service_inspectors/nhttp_inspect/nhttp_test_manager.h index 388032944..d13e0e616 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_manager.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_manager.h @@ -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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri.cc b/src/service_inspectors/nhttp_inspect/nhttp_uri.cc index fe579f571..e4d32667f 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri.cc @@ -23,6 +23,7 @@ #include #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; } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc b/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc index e244d4500..0f79a9b3b 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc @@ -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); diff --git a/src/service_inspectors/nhttp_inspect/test/CMakeLists.txt b/src/service_inspectors/nhttp_inspect/test/CMakeLists.txt index e19c94e53..cee1fa8af 100644 --- a/src/service_inspectors/nhttp_inspect/test/CMakeLists.txt +++ b/src/service_inspectors/nhttp_inspect/test/CMakeLists.txt @@ -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) diff --git a/src/service_inspectors/nhttp_inspect/test/Makefile.am b/src/service_inspectors/nhttp_inspect/test/Makefile.am index 1628ff562..1f28e9cd1 100644 --- a/src/service_inspectors/nhttp_inspect/test/Makefile.am +++ b/src/service_inspectors/nhttp_inspect/test/Makefile.am @@ -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 index 000000000..c854b6be6 --- /dev/null +++ b/src/service_inspectors/nhttp_inspect/test/nhttp_module_test.cc @@ -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 +// 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 +#include +#include + +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); +} +