From: Mike Stepanek (mstepane) Date: Mon, 9 Nov 2020 14:34:19 +0000 (+0000) Subject: Merge pull request #2597 in SNORT/snort3 from ~MDAGON/snort3:injector_refactor to... X-Git-Tag: 3.0.3-5~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=27eba8479282a9a774ef171104277e1f51ba082a;p=thirdparty%2Fsnort3.git Merge pull request #2597 in SNORT/snort3 from ~MDAGON/snort3:injector_refactor to master Squashed commit of the following: commit 309221de1466bd5bcabf52c70960da18648f1291 Author: mdagon Date: Wed Oct 28 14:45:49 2020 -0400 payload_injector: refactoring --- diff --git a/src/actions/act_react.cc b/src/actions/act_react.cc index dbc05ebd5..b5eb8a4b7 100644 --- a/src/actions/act_react.cc +++ b/src/actions/act_react.cc @@ -54,7 +54,7 @@ #include "main/snort_config.h" #include "main/snort_debug.h" #include "packet_io/active.h" -#include "payload_injector/payload_injector_module.h" +#include "payload_injector/payload_injector.h" #include "profiler/profiler.h" #include "protocols/packet.h" #include "service_inspectors/http2_inspect/http2_flow_data.h" @@ -164,11 +164,11 @@ private: assert(control.stream_id != NO_STREAM_ID); } } - InjectionReturnStatus status = PayloadInjectorModule::inject_http_payload(p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(p, control); #ifdef DEBUG_MSGS if (status != INJECTION_SUCCESS) debug_logf(react_trace, nullptr, "Injection error: %s\n", - PayloadInjectorModule::get_err_string(status)); + PayloadInjector::get_err_string(status)); #else UNUSED(status); #endif diff --git a/src/main/snort_config.cc b/src/main/snort_config.cc index ced01551d..3a8b4b788 100644 --- a/src/main/snort_config.cc +++ b/src/main/snort_config.cc @@ -56,6 +56,7 @@ #include "packet_io/sfdaq_config.h" #include "parser/parser.h" #include "parser/vars.h" +#include "payload_injector/payload_injector_config.h" #include "ports/rule_port_tables.h" #include "profiler/profiler.h" #include "protocols/packet.h" @@ -274,6 +275,7 @@ SnortConfig::~SnortConfig() delete so_rules; if ( plugins ) delete plugins; + delete payload_injector_config; clear_reload_resource_tuner_list(); trim_heap(); diff --git a/src/main/snort_config.h b/src/main/snort_config.h index 0dcc5252c..dbd734a61 100644 --- a/src/main/snort_config.h +++ b/src/main/snort_config.h @@ -148,6 +148,7 @@ struct HighAvailabilityConfig; struct IpsActionsConfig; struct LatencyConfig; struct MemoryConfig; +struct PayloadInjectorConfig; struct Plugins; struct PORT_RULE_MAP; struct RateFilterConfig; @@ -322,6 +323,7 @@ public: // various modules FastPatternConfig* fast_pattern_config = nullptr; EventQueueConfig* event_queue_config = nullptr; + PayloadInjectorConfig* payload_injector_config = nullptr; /* policy specific? */ ThresholdConfig* threshold_config = nullptr; diff --git a/src/payload_injector/CMakeLists.txt b/src/payload_injector/CMakeLists.txt index cf9c91772..24e1382aa 100644 --- a/src/payload_injector/CMakeLists.txt +++ b/src/payload_injector/CMakeLists.txt @@ -1,10 +1,13 @@ set (PAYLOAD_INJECTOR_INCLUDES - payload_injector_module.h + payload_injector.h ) add_library ( payload_injector OBJECT ${PAYLOAD_INJECTOR_INCLUDES} + payload_injector.cc + payload_injector_config.h payload_injector_module.cc + payload_injector_module.h payload_injector_translate_page.cc ) diff --git a/src/payload_injector/payload_injector.cc b/src/payload_injector/payload_injector.cc new file mode 100644 index 000000000..0afb93706 --- /dev/null +++ b/src/payload_injector/payload_injector.cc @@ -0,0 +1,152 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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. +//-------------------------------------------------------------------------- + +// payload_injector.cc author Maya Dagon + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "payload_injector.h" + +#include "detection/detection_engine.h" +#include "packet_io/active.h" +#include "protocols/packet.h" +#include "service_inspectors/http2_inspect/http2_flow_data.h" +#include "utils/util.h" + +#include "payload_injector_config.h" +#include "payload_injector_module.h" + +using namespace snort; + +// Should have an entry for each error in InjectionReturnStatus +static const std::map InjectionErrorToString = +{ + { ERR_INJECTOR_NOT_CONFIGURED, "Payload injector is not configured" }, + { ERR_STREAM_NOT_ESTABLISHED, "TCP stream not established" }, + { ERR_UNIDENTIFIED_PROTOCOL, "Unidentified protocol" }, + { ERR_HTTP2_STREAM_ID_0, "HTTP/2 - injection to stream 0" }, + { ERR_PAGE_TRANSLATION, "Error in translating HTTP block page to HTTP/2. " + "Unsupported or bad format." }, + { ERR_HTTP2_MID_FRAME, "HTTP/2 - attempt to inject mid frame. Currently not supported." }, + { ERR_TRANSLATED_HDRS_SIZE, + "HTTP/2 translated header size is bigger than expected. Update max size." }, + { ERR_HTTP2_EVEN_STREAM_ID, "HTTP/2 - injection to server initiated stream" }, + { ERR_PKT_FROM_SERVER, "Packet is from server" } +}; + +InjectionReturnStatus PayloadInjector::inject_http2_payload(Packet* p, + const InjectionControl& control, EncodeFlags df) +{ + InjectionReturnStatus status; + + if (control.stream_id == 0) + status = ERR_HTTP2_STREAM_ID_0; + else if (control.stream_id % 2 == 0) + { + // Don't inject against server initiated streams + status = ERR_HTTP2_EVEN_STREAM_ID; + } + else + { + // Check if mid frame + Http2FlowData* const session_data = + (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id); + if (!session_data || session_data->is_mid_frame()) + { + payload_injector_stats.http2_mid_frame++; + // FIXIT-E mid-frame injection not supported + status = ERR_HTTP2_MID_FRAME; + } + else + { + uint8_t* http2_payload; + uint32_t payload_len; + status = get_http2_payload(control, http2_payload, payload_len); + if (status == INJECTION_SUCCESS) + { + p->active->send_data(p, df, http2_payload, payload_len); + snort_free(http2_payload); + payload_injector_stats.http2_injects++; + return INJECTION_SUCCESS; + } + else + payload_injector_stats.http2_translate_err++; + } + } + + // If we got here, shouldn't inject the page + p->active->send_data(p, df, nullptr, 0); + return status; +} + +InjectionReturnStatus PayloadInjector::inject_http_payload(Packet* p, + const InjectionControl& control) +{ + InjectionReturnStatus status = INJECTION_SUCCESS; + + assert(p != nullptr); + + const PayloadInjectorConfig* conf = p->context->conf->payload_injector_config; + if (conf) + { + if (p->packet_flags & PKT_FROM_SERVER) + status = ERR_PKT_FROM_SERVER; + else + { + EncodeFlags df = ENC_FLAG_RST_SRVR; // Send RST to server. + + if (p->packet_flags & PKT_STREAM_EST) + { + if (!p->flow) + status = ERR_UNIDENTIFIED_PROTOCOL; + else if (!p->flow->gadget || strcmp(p->flow->gadget->get_name(),"http_inspect") == + 0) + { + payload_injector_stats.http_injects++; + p->active->send_data(p, df, control.http_page, control.http_page_len); + } + else if (strcmp(p->flow->gadget->get_name(),"http2_inspect") == 0) + status = inject_http2_payload(p, control, df); + else + status = ERR_UNIDENTIFIED_PROTOCOL; + } + else + status = ERR_STREAM_NOT_ESTABLISHED; + } + } + else + status = ERR_INJECTOR_NOT_CONFIGURED; + + p->active->block_session(p, true); + + DetectionEngine::disable_all(p); + + if ( p->flow ) + p->flow->set_state(Flow::FlowState::BLOCK); + + return status; +} + +const char* PayloadInjector::get_err_string(InjectionReturnStatus status) +{ + auto iter = InjectionErrorToString.find(status); + assert (iter != InjectionErrorToString.end()); + return iter->second; +} diff --git a/src/payload_injector/payload_injector.h b/src/payload_injector/payload_injector.h new file mode 100644 index 000000000..009bb0662 --- /dev/null +++ b/src/payload_injector/payload_injector.h @@ -0,0 +1,76 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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. +//-------------------------------------------------------------------------- + +// payload_injector.h author Maya Dagon + +#ifndef PAYLOAD_INJECTOR_H +#define PAYLOAD_INJECTOR_H + +#include "framework/codec.h" + +namespace snort +{ +struct Packet; +} + +enum InjectionReturnStatus : int8_t +{ + INJECTION_SUCCESS = 1, + ERR_INJECTOR_NOT_CONFIGURED = -1, + ERR_STREAM_NOT_ESTABLISHED = -2, + ERR_UNIDENTIFIED_PROTOCOL = -3, + ERR_HTTP2_STREAM_ID_0 = -4, + ERR_PAGE_TRANSLATION = -5, + ERR_HTTP2_MID_FRAME = -6, + ERR_TRANSLATED_HDRS_SIZE = -7, + ERR_HTTP2_EVEN_STREAM_ID = -8, + ERR_PKT_FROM_SERVER = -9, + // Update InjectionErrorToString when adding/removing error codes +}; + +struct InjectionControl +{ + const uint8_t* http_page = nullptr; + uint32_t http_page_len = 0; + uint32_t stream_id = 0; +}; + +class SO_PUBLIC PayloadInjector +{ +public: + static InjectionReturnStatus inject_http_payload(snort::Packet* p, const + InjectionControl& control); + + static const char* get_err_string(InjectionReturnStatus status); + +private: + static InjectionReturnStatus inject_http2_payload(snort::Packet* p, const + InjectionControl& control, snort::EncodeFlags df); + +#ifdef UNIT_TEST + +public: +#endif + static InjectionReturnStatus get_http2_payload(InjectionControl control, uint8_t*& http2_payload, uint32_t& payload_len); +}; + +#ifdef UNIT_TEST +InjectionReturnStatus write_7_bit_prefix_int(uint32_t val, uint8_t*& out, uint32_t& out_free_space); +#endif + +#endif diff --git a/src/payload_injector/payload_injector_config.h b/src/payload_injector/payload_injector_config.h new file mode 100644 index 000000000..e9f96be6a --- /dev/null +++ b/src/payload_injector/payload_injector_config.h @@ -0,0 +1,28 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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. +//-------------------------------------------------------------------------- + +// payload_injector_config.h author Maya Dagon + +#ifndef PAYLOAD_INJECTOR_CONFIG_H +#define PAYLOAD_INJECTOR_CONFIG_H + +struct PayloadInjectorConfig +{ +}; + +#endif diff --git a/src/payload_injector/payload_injector_module.cc b/src/payload_injector/payload_injector_module.cc index 0187242ef..11172cc51 100644 --- a/src/payload_injector/payload_injector_module.cc +++ b/src/payload_injector/payload_injector_module.cc @@ -24,11 +24,9 @@ #include "payload_injector_module.h" -#include "detection/detection_engine.h" -#include "packet_io/active.h" -#include "protocols/packet.h" -#include "service_inspectors/http2_inspect/http2_flow_data.h" -#include "utils/util.h" +#include "main/snort_config.h" + +#include "payload_injector_config.h" #define s_name "payload_injector" #define s_help \ @@ -47,24 +45,6 @@ const PegInfo payload_injector_pegs[] = { CountType::END, nullptr, nullptr } }; -// Should have an entry for each error in InjectionReturnStatus -static const std::map InjectionErrorToString = -{ - { ERR_INJECTOR_NOT_CONFIGURED, "Payload injector is not configured" }, - { ERR_STREAM_NOT_ESTABLISHED, "TCP stream not established" }, - { ERR_UNIDENTIFIED_PROTOCOL, "Unidentified protocol" }, - { ERR_HTTP2_STREAM_ID_0, "HTTP/2 - injection to stream 0" }, - { ERR_PAGE_TRANSLATION, "Error in translating HTTP block page to HTTP/2. " - "Unsupported or bad format." }, - { ERR_HTTP2_MID_FRAME, "HTTP/2 - attempt to inject mid frame. Currently not supported." }, - { ERR_TRANSLATED_HDRS_SIZE, - "HTTP/2 translated header size is bigger than expected. Update max size." }, - { ERR_HTTP2_EVEN_STREAM_ID, "HTTP/2 - injection to server initiated stream" }, - { ERR_PKT_FROM_SERVER, "Packet is from server" } -}; - -bool PayloadInjectorModule::configured = false; - PayloadInjectorModule::PayloadInjectorModule() : Module(s_name, s_help) { } @@ -75,108 +55,9 @@ const PegInfo* PayloadInjectorModule::get_pegs() const PegCount* PayloadInjectorModule::get_counts() const { return (PegCount*)&payload_injector_stats; } -bool PayloadInjectorModule::end(const char*, int, SnortConfig*) +bool PayloadInjectorModule::end(const char*, int, SnortConfig* sc) { - configured = true; + assert(sc->payload_injector_config == nullptr); + sc->payload_injector_config = new PayloadInjectorConfig; return true; } - -InjectionReturnStatus PayloadInjectorModule::inject_http2_payload(Packet* p, - const InjectionControl& control, EncodeFlags df) -{ - InjectionReturnStatus status; - - if (control.stream_id == 0) - status = ERR_HTTP2_STREAM_ID_0; - else if (control.stream_id % 2 == 0) - { - // Don't inject against server initiated streams - status = ERR_HTTP2_EVEN_STREAM_ID; - } - else - { - // Check if mid frame - Http2FlowData* const session_data = - (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id); - if (!session_data || session_data->is_mid_frame()) - { - payload_injector_stats.http2_mid_frame++; - // FIXIT-E mid-frame injection not supported - status = ERR_HTTP2_MID_FRAME; - } - else - { - uint8_t* http2_payload; - uint32_t payload_len; - status = get_http2_payload(control, http2_payload, payload_len); - if (status == INJECTION_SUCCESS) - { - p->active->send_data(p, df, http2_payload, payload_len); - snort_free(http2_payload); - payload_injector_stats.http2_injects++; - return INJECTION_SUCCESS; - } - else - payload_injector_stats.http2_translate_err++; - } - } - - // If we got here, shouldn't inject the page - p->active->send_data(p, df, nullptr, 0); - return status; -} - -InjectionReturnStatus PayloadInjectorModule::inject_http_payload(Packet* p, - const InjectionControl& control) -{ - InjectionReturnStatus status = INJECTION_SUCCESS; - - assert(p != nullptr); - - if (configured) - { - if (p->packet_flags & PKT_FROM_SERVER) - status = ERR_PKT_FROM_SERVER; - else - { - EncodeFlags df = ENC_FLAG_RST_SRVR; // Send RST to server. - - if (p->packet_flags & PKT_STREAM_EST) - { - if (!p->flow) - status = ERR_UNIDENTIFIED_PROTOCOL; - else if (!p->flow->gadget || strcmp(p->flow->gadget->get_name(),"http_inspect") == - 0) - { - payload_injector_stats.http_injects++; - p->active->send_data(p, df, control.http_page, control.http_page_len); - } - else if (strcmp(p->flow->gadget->get_name(),"http2_inspect") == 0) - status = inject_http2_payload(p, control, df); - else - status = ERR_UNIDENTIFIED_PROTOCOL; - } - else - status = ERR_STREAM_NOT_ESTABLISHED; - } - } - else - status = ERR_INJECTOR_NOT_CONFIGURED; - - p->active->block_session(p, true); - - DetectionEngine::disable_all(p); - - if ( p->flow ) - p->flow->set_state(Flow::FlowState::BLOCK); - - return status; -} - -const char* PayloadInjectorModule::get_err_string(InjectionReturnStatus status) -{ - auto iter = InjectionErrorToString.find(status); - assert (iter != InjectionErrorToString.end()); - return iter->second; -} - diff --git a/src/payload_injector/payload_injector_module.h b/src/payload_injector/payload_injector_module.h index 18b225879..0c2732aea 100644 --- a/src/payload_injector/payload_injector_module.h +++ b/src/payload_injector/payload_injector_module.h @@ -21,14 +21,8 @@ #ifndef PAYLOAD_INJECTOR_MODULE_H #define PAYLOAD_INJECTOR_MODULE_H -#include "framework/codec.h" #include "framework/module.h" -namespace snort -{ -struct Packet; -} - struct PayloadInjectorCounts { PegCount http_injects; @@ -37,29 +31,7 @@ struct PayloadInjectorCounts PegCount http2_mid_frame; }; -extern THREAD_LOCAL PayloadInjectorCounts payload_injection_stats; - -enum InjectionReturnStatus : int8_t -{ - INJECTION_SUCCESS = 1, - ERR_INJECTOR_NOT_CONFIGURED = -1, - ERR_STREAM_NOT_ESTABLISHED = -2, - ERR_UNIDENTIFIED_PROTOCOL = -3, - ERR_HTTP2_STREAM_ID_0 = -4, - ERR_PAGE_TRANSLATION = -5, - ERR_HTTP2_MID_FRAME = -6, - ERR_TRANSLATED_HDRS_SIZE = -7, - ERR_HTTP2_EVEN_STREAM_ID = -8, - ERR_PKT_FROM_SERVER = -9, - // Update InjectionErrorToString when adding/removing error codes -}; - -struct InjectionControl -{ - const uint8_t* http_page = nullptr; - uint32_t http_page_len = 0; - uint32_t stream_id = 0; -}; +extern THREAD_LOCAL PayloadInjectorCounts payload_injector_stats; class SO_PUBLIC PayloadInjectorModule : public snort::Module { @@ -72,32 +44,7 @@ public: { return GLOBAL; } bool end(const char*, int, snort::SnortConfig*) override; - - static InjectionReturnStatus inject_http_payload(snort::Packet* p, const - InjectionControl& control); - - static const char* get_err_string(InjectionReturnStatus status); - -#ifdef UNIT_TEST - void set_configured(bool val) { configured = val; } -#endif - -private: - static bool configured; - - static InjectionReturnStatus inject_http2_payload(snort::Packet* p, const - InjectionControl& control, snort::EncodeFlags df); - -#ifdef UNIT_TEST - -public: -#endif - static InjectionReturnStatus get_http2_payload(InjectionControl control, uint8_t*& http2_payload, uint32_t& payload_len); }; -#ifdef UNIT_TEST -InjectionReturnStatus write_7_bit_prefix_int(uint32_t val, uint8_t*& out, uint32_t& out_free_space); -#endif - #endif diff --git a/src/payload_injector/payload_injector_translate_page.cc b/src/payload_injector/payload_injector_translate_page.cc index b4ece4d5b..933a73d1c 100644 --- a/src/payload_injector/payload_injector_translate_page.cc +++ b/src/payload_injector/payload_injector_translate_page.cc @@ -31,7 +31,7 @@ #include "config.h" #endif -#include "payload_injector_module.h" +#include "payload_injector.h" #include "service_inspectors/http2_inspect/http2_enum.h" #include "utils/util.h" @@ -244,7 +244,7 @@ static void write_frame_hdr(uint8_t*& out, uint32_t len, uint8_t type, uint8_t f out += Http2Enums::FRAME_HEADER_LENGTH; } -InjectionReturnStatus PayloadInjectorModule::get_http2_payload(InjectionControl control, +InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl control, uint8_t*& http2_payload, uint32_t& payload_len) { if (control.http_page == nullptr || control.http_page_len == 0) diff --git a/src/payload_injector/test/CMakeLists.txt b/src/payload_injector/test/CMakeLists.txt index 531233974..738cfe24e 100644 --- a/src/payload_injector/test/CMakeLists.txt +++ b/src/payload_injector/test/CMakeLists.txt @@ -1,5 +1,6 @@ add_cpputest (payload_injector_test SOURCES + ../payload_injector.cc ../payload_injector_module.cc ../../framework/module.cc ) diff --git a/src/payload_injector/test/payload_injector_test.cc b/src/payload_injector/test/payload_injector_test.cc index a63966390..d77efba24 100644 --- a/src/payload_injector/test/payload_injector_test.cc +++ b/src/payload_injector/test/payload_injector_test.cc @@ -23,6 +23,7 @@ #include "config.h" #endif +#include "payload_injector/payload_injector.h" #include "payload_injector/payload_injector_module.h" #include "detection/detection_engine.h" @@ -33,6 +34,8 @@ #include "service_inspectors/http_inspect/http_enum.h" #include "service_inspectors/http2_inspect/http2_flow_data.h" +#include "payload_injector/payload_injector_config.h" + #include #include @@ -56,8 +59,27 @@ Flow::Flow() gadget = nullptr; flow_state = Flow::FlowState::SETUP; } + Flow::~Flow() { } -Packet::Packet(bool) { packet_flags = 0; flow = nullptr; } +IpsContext::IpsContext(unsigned int) { } +IpsContext::~IpsContext() { } +SnortConfig::SnortConfig(snort::SnortConfig const*) { } +SnortConfig::~SnortConfig() { } + +IpsContext ips_context; +SnortConfig conf; +PayloadInjectorConfig pi_conf; +Packet::Packet(bool) +{ + packet_flags = 0; + flow = nullptr; + context = &ips_context; + context->conf = &conf; +} + +static void set_not_configured() { conf.payload_injector_config = nullptr; } +static void set_configured() { conf.payload_injector_config = &pi_conf; } + Packet::~Packet() { } int DetectionEngine::queue_event(unsigned int, unsigned int, snort::Actions::Type) { return 0; } FlowData::~FlowData() { } @@ -94,7 +116,7 @@ public: // Mocks for PayloadInjectorModule::get_http2_payload static InjectionReturnStatus translation_status = INJECTION_SUCCESS; -InjectionReturnStatus PayloadInjectorModule::get_http2_payload(InjectionControl, +InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl, uint8_t*& http2_payload, uint32_t& payload_len) { if (translation_status == INJECTION_SUCCESS) @@ -122,8 +144,8 @@ Http2FlowData::Http2FlowData(snort::Flow*) : Http2HpackDecoder(this, SRC_CLIENT, events[SRC_CLIENT], infractions[SRC_CLIENT]), Http2HpackDecoder(this, SRC_SERVER, events[SRC_SERVER], infractions[SRC_SERVER]) }, - data_cutter { Http2DataCutter(this, SRC_CLIENT), Http2DataCutter(this, SRC_SERVER) } - { } + data_cutter {Http2DataCutter(this, SRC_CLIENT), Http2DataCutter(this, SRC_SERVER)} +{ } Http2FlowData::~Http2FlowData() { } Http2FlowData http2_flow_data(nullptr); void Http2FlowData::set_mid_frame(bool val) { continuation_expected[SRC_SERVER] = val; } @@ -154,24 +176,24 @@ TEST_GROUP(payload_injector_test) TEST(payload_injector_test, not_configured_stream_not_established) { - mod.set_configured(false); Packet p(false); + set_not_configured(); p.flow = &flow; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http_injects == 0); CHECK(status == ERR_INJECTOR_NOT_CONFIGURED); CHECK(flow.flow_state == Flow::FlowState::BLOCK); - const char* err_string = mod.get_err_string(status); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "Payload injector is not configured") == 0); } TEST(payload_injector_test, not_configured_stream_established) { - mod.set_configured(false); Packet p(false); + set_not_configured(); p.packet_flags = PKT_STREAM_EST; p.flow = &flow; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http_injects == 0); CHECK(status == ERR_INJECTOR_NOT_CONFIGURED); CHECK(flow.flow_state == Flow::FlowState::BLOCK); @@ -179,27 +201,27 @@ TEST(payload_injector_test, not_configured_stream_established) TEST(payload_injector_test, configured_stream_not_established) { - mod.set_configured(true); Packet p(false); + set_configured(); p.flow = &flow; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http_injects == 0); CHECK(status == ERR_STREAM_NOT_ESTABLISHED); - const char* err_string = mod.get_err_string(status); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "TCP stream not established") == 0); CHECK(flow.flow_state == Flow::FlowState::BLOCK); } TEST(payload_injector_test, configured_stream_established) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "http_inspect"; flow.gadget = new MockInspector(); p.flow = &flow; p.active = &active; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http_injects == 1); CHECK(status == INJECTION_SUCCESS); CHECK(flow.flow_state == Flow::FlowState::BLOCK); @@ -208,50 +230,50 @@ TEST(payload_injector_test, configured_stream_established) TEST(payload_injector_test, http2_stream0) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "http2_inspect"; flow.gadget = new MockInspector(); p.flow = &flow; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http2_injects == 0); CHECK(status == ERR_HTTP2_STREAM_ID_0); CHECK(flow.flow_state == Flow::FlowState::BLOCK); - const char* err_string = mod.get_err_string(status); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "HTTP/2 - injection to stream 0") == 0); delete flow.gadget; } TEST(payload_injector_test, http2_even_stream_id) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "http2_inspect"; flow.gadget = new MockInspector(); p.flow = &flow; control.stream_id = 2; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http2_injects == 0); CHECK(status == ERR_HTTP2_EVEN_STREAM_ID); CHECK(flow.flow_state == Flow::FlowState::BLOCK); - const char* err_string = mod.get_err_string(status); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "HTTP/2 - injection to server initiated stream") == 0); delete flow.gadget; } TEST(payload_injector_test, http2_success) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "http2_inspect"; flow.gadget = new MockInspector(); p.flow = &flow; p.active = &active; control.stream_id = 1; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http2_injects == 1); CHECK(status == INJECTION_SUCCESS); CHECK(flow.flow_state == Flow::FlowState::BLOCK); @@ -260,12 +282,12 @@ TEST(payload_injector_test, http2_success) TEST(payload_injector_test, unidentified_gadget_is_null) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; p.flow = &flow; p.active = &active; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http_injects == 1); CHECK(status == INJECTION_SUCCESS); CHECK(flow.flow_state == Flow::FlowState::BLOCK); @@ -273,13 +295,13 @@ TEST(payload_injector_test, unidentified_gadget_is_null) TEST(payload_injector_test, unidentified_gadget_name) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "inspector"; flow.gadget = new MockInspector(); p.flow = &flow; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(status == ERR_UNIDENTIFIED_PROTOCOL); CHECK(flow.flow_state == Flow::FlowState::BLOCK); delete flow.gadget; @@ -287,19 +309,19 @@ TEST(payload_injector_test, unidentified_gadget_name) TEST(payload_injector_test, http2_mid_frame) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "http2_inspect"; flow.gadget = new MockInspector(); p.flow = &flow; control.stream_id = 1; http2_flow_data.set_mid_frame(true); - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http2_mid_frame == 1); CHECK(status == ERR_HTTP2_MID_FRAME); CHECK(flow.flow_state == Flow::FlowState::BLOCK); - const char* err_string = mod.get_err_string(status); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "HTTP/2 - attempt to inject mid frame. Currently not supported.") == 0); delete flow.gadget; @@ -307,15 +329,15 @@ TEST(payload_injector_test, http2_mid_frame) TEST(payload_injector_test, http2_continuation_expected) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; mock_api.base.name = "http2_inspect"; flow.gadget = new MockInspector(); p.flow = &flow; control.stream_id = 1; http2_flow_data.set_mid_frame(true); - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http2_mid_frame == 1); CHECK(status == ERR_HTTP2_MID_FRAME); CHECK(flow.flow_state == Flow::FlowState::BLOCK); @@ -324,12 +346,12 @@ TEST(payload_injector_test, http2_continuation_expected) TEST(payload_injector_test, http2_pkt_from_srvr) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_FROM_SERVER; flow.gadget = new MockInspector(); p.flow = &flow; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(status == ERR_PKT_FROM_SERVER); CHECK(flow.flow_state == Flow::FlowState::BLOCK); delete flow.gadget; @@ -337,13 +359,13 @@ TEST(payload_injector_test, http2_pkt_from_srvr) TEST(payload_injector_test, flow_is_null) { - mod.set_configured(true); Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; - InjectionReturnStatus status = mod.inject_http_payload(&p, control); + InjectionReturnStatus status = PayloadInjector::inject_http_payload(&p, control); CHECK(counts->http_injects == 0); CHECK(status == ERR_UNIDENTIFIED_PROTOCOL); - const char* err_string = mod.get_err_string(status); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "Unidentified protocol") == 0); } @@ -365,7 +387,6 @@ TEST_GROUP(payload_injector_translate_err_test) control.http_page_len = 4; flow.set_state(Flow::FlowState::INSPECT); http2_flow_data.set_mid_frame(false); - mod.set_configured(true); mock_api.base.name = "http2_inspect"; flow.gadget = new MockInspector(); control.stream_id = 1; @@ -383,11 +404,12 @@ TEST_GROUP(payload_injector_translate_err_test) TEST(payload_injector_translate_err_test, http2_page_translation_err) { Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; p.flow = &flow; translation_status = ERR_PAGE_TRANSLATION; - status = mod.inject_http_payload(&p, control); - const char* err_string = mod.get_err_string(status); + status = PayloadInjector::inject_http_payload(&p, control); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "Error in translating HTTP block page to HTTP/2. " "Unsupported or bad format.") == 0); } @@ -395,11 +417,12 @@ TEST(payload_injector_translate_err_test, http2_page_translation_err) TEST(payload_injector_translate_err_test, http2_hdrs_size) { Packet p(false); + set_configured(); p.packet_flags = PKT_STREAM_EST; p.flow = &flow; translation_status = ERR_TRANSLATED_HDRS_SIZE; - status = mod.inject_http_payload(&p, control); - const char* err_string = mod.get_err_string(status); + status = PayloadInjector::inject_http_payload(&p, control); + const char* err_string = PayloadInjector::get_err_string(status); CHECK(strcmp(err_string, "HTTP/2 translated header size is bigger than expected. Update max size.") == 0); } diff --git a/src/payload_injector/test/payload_injector_translate_test.cc b/src/payload_injector/test/payload_injector_translate_test.cc index 21db443df..d59eeb20d 100644 --- a/src/payload_injector/test/payload_injector_translate_test.cc +++ b/src/payload_injector/test/payload_injector_translate_test.cc @@ -22,7 +22,7 @@ #include "config.h" #endif -#include "payload_injector/payload_injector_module.h" +#include "payload_injector/payload_injector.h" #include "utils/util.h" @@ -46,7 +46,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); uint8_t out[] = @@ -78,7 +78,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation2) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); @@ -107,7 +107,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation3) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); @@ -136,7 +136,7 @@ TEST(payload_injector_translate_test, mix_n_and_rn) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); @@ -164,7 +164,7 @@ TEST(payload_injector_translate_test, only_body) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -178,7 +178,7 @@ TEST(payload_injector_translate_test, no_body) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -192,7 +192,7 @@ TEST(payload_injector_translate_test, missing_last_rn) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -206,7 +206,7 @@ TEST(payload_injector_translate_test, missing_space_after_colon) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -220,7 +220,7 @@ TEST(payload_injector_translate_test, extra_space_before_colon) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -234,7 +234,7 @@ TEST(payload_injector_translate_test, unsupported_status) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -248,7 +248,7 @@ TEST(payload_injector_translate_test, unsupported_hdr) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -261,7 +261,7 @@ TEST(payload_injector_translate_test, hdr_ends_wo_value) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -274,7 +274,7 @@ TEST(payload_injector_translate_test, missing_value) control.stream_id = 1; control.http_page = (uint8_t*)http_page; control.http_page_len = strlen(http_page); - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -292,7 +292,7 @@ TEST(payload_injector_translate_test, val_len1) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); @@ -329,7 +329,7 @@ TEST(payload_injector_translate_test, val_len2) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); uint8_t out[] = @@ -364,7 +364,7 @@ TEST(payload_injector_translate_test, val_len3) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); @@ -440,7 +440,7 @@ TEST(payload_injector_translate_test, http2_hdr_is_max) control.http_page = http_page; control.http_page_len = size; control.stream_id = 0xf000; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); CHECK(payload_len == 2019); @@ -472,7 +472,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -499,7 +499,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big3) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -527,7 +527,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big4) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -554,7 +554,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big5) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_TRANSLATED_HDRS_SIZE); } @@ -570,7 +570,7 @@ TEST(payload_injector_translate_test, payload_body_is_exactly_1_data_frame) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); // Headers frame header + status ok + data frame header uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 1, 0, 0, 0, 1 }; @@ -592,7 +592,7 @@ TEST(payload_injector_translate_test, payload_body_is_data_frame_plus_1) control.stream_id = 1; control.http_page = http_page; control.http_page_len = size; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == INJECTION_SUCCESS); // Headers frame header + status ok + data frame header uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 0, 0, 0, 0, 1 }; @@ -611,7 +611,7 @@ TEST(payload_injector_translate_test, http_page_is_nullptr) InjectionControl control; control.http_page = nullptr; control.http_page_len = 1; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); } @@ -622,7 +622,7 @@ TEST(payload_injector_translate_test, http_page_is_0_length) InjectionControl control; control.http_page = http_page; control.http_page_len = 0; - status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len); + status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len); CHECK(status == ERR_PAGE_TRANSLATION); }