]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #3548: HTTP/3 inspector implementation support
authorShanmugam S (shanms) <shanms@cisco.com>
Thu, 15 Sep 2022 07:32:50 +0000 (07:32 +0000)
committerShanmugam S (shanms) <shanms@cisco.com>
Thu, 15 Sep 2022 07:32:50 +0000 (07:32 +0000)
Merge in SNORT/snort3 from ~ABHPAL/snort3:h3 to master

Squashed commit of the following:

commit 18d340b34fb619533c4a8d1722cd57f823d817ba
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Aug 25 16:21:19 2022 +0530

    parser: add implicit http3 to http ips options otn

commit b38f067a20e4503d29916be966919fafee71d3c7
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Aug 25 16:20:14 2022 +0530

    stream: export support for creating udp session

commit 6f3f7109f8f3c8b0c3299a2aec7c58508a000840
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Aug 25 16:18:56 2022 +0530

    detection: add http3 to http ips buffers

commit 254ccfed242e89b5780407691c5b9fff69684be4
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:54:39 2022 +0530

    flow: abstract class added to work on stream based connections

commit d2b82a8feccd6ac3c37aa202ec58c505714f7546
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:53:56 2022 +0530

    pub_sub: handle httpx(2,3) traffic

commit 9bf0c34a118bd4f3dba8052ee141be1a86eea237
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:52:55 2022 +0530

    payload_injector: accomodate httpx(2,3) stream id values

commit 32e13e3f1f534f5632264e3e0d1d9f1f921c74b8
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:52:06 2022 +0530

    rna: handle httpx(2,3) traffic

commit c3ad5f625c98a337d2bf5b51742075d1d5b07c23
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:51:23 2022 +0530

    appid: handle http event for httpx(2,3) traffic

commit b7e9927040da7d01ebb3dbed0b256340a5bf4f94
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:50:20 2022 +0530

    http2_inspect: updated with abstracted httpx(2,3) flags

commit d27580f9f0666ec765c90347a34ccad619effcb0
Author: Abhijit Pal(abhpal) <abhpal@cisco.com>
Date:   Thu Jul 14 15:48:46 2022 +0530

    http_inspect: abstract inspection of httpx(2,3)

59 files changed:
src/detection/fp_utils.cc
src/flow/CMakeLists.txt
src/flow/flow.h
src/network_inspectors/appid/appid_http_event_handler.cc
src/network_inspectors/appid/appid_http_session.cc
src/network_inspectors/appid/appid_http_session.h
src/network_inspectors/appid/appid_session.cc
src/network_inspectors/appid/appid_session.h
src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h
src/network_inspectors/appid/test/appid_http_event_test.cc
src/network_inspectors/appid/test/appid_mock_http_session.h
src/network_inspectors/appid/test/appid_mock_session.h
src/network_inspectors/rna/rna_app_discovery.cc
src/parser/parse_conf.cc
src/payload_injector/payload_injector.h
src/pub_sub/appid_events.h
src/pub_sub/http_events.cc
src/pub_sub/http_events.h
src/pub_sub/http_request_body_event.cc
src/pub_sub/test/pub_sub_http_event_test.cc
src/pub_sub/test/pub_sub_http_request_body_event_test.cc
src/service_inspectors/http2_inspect/CMakeLists.txt
src/service_inspectors/http2_inspect/http2_data_cutter.cc
src/service_inspectors/http2_inspect/http2_flow_data.cc
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_headers_frame_header.cc
src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc
src/service_inspectors/http2_inspect/http2_hpack_table.h
src/service_inspectors/http2_inspect/http2_huffman_state_machine.h
src/service_inspectors/http2_inspect/http2_push_promise_frame.cc
src/service_inspectors/http2_inspect/http2_stream.cc
src/service_inspectors/http2_inspect/http2_stream_splitter.cc
src/service_inspectors/http2_inspect/http2_varlen_string_decode_impl.h
src/service_inspectors/http_inspect/CMakeLists.txt
src/service_inspectors/http_inspect/dev_notes.txt
src/service_inspectors/http_inspect/http_common.h
src/service_inspectors/http_inspect/http_cutter.cc
src/service_inspectors/http_inspect/http_cutter.h
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_field.h
src/service_inspectors/http_inspect/http_flow_data.cc
src/service_inspectors/http_inspect/http_flow_data.h
src/service_inspectors/http_inspect/http_inspect.cc
src/service_inspectors/http_inspect/http_inspect.h
src/service_inspectors/http_inspect/http_inspect_base.h
src/service_inspectors/http_inspect/http_msg_body_hx.cc [moved from src/service_inspectors/http_inspect/http_msg_body_h2.cc with 78% similarity]
src/service_inspectors/http_inspect/http_msg_body_hx.h [moved from src/service_inspectors/http_inspect/http_msg_body_h2.h with 86% similarity]
src/service_inspectors/http_inspect/http_msg_header.cc
src/service_inspectors/http_inspect/http_msg_start.cc
src/service_inspectors/http_inspect/http_stream_splitter.h
src/service_inspectors/http_inspect/http_stream_splitter_base.h
src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc
src/service_inspectors/http_inspect/http_stream_splitter_scan.cc
src/service_inspectors/http_inspect/http_test_manager.h
src/service_inspectors/http_inspect/ips_http.cc
src/service_inspectors/http_inspect/ips_http_version.cc
src/service_inspectors/http_inspect/test/http_transaction_test.cc
src/stream/udp/CMakeLists.txt
src/stream/udp/udp_session.h

index 33fdd8b8af6efc3dd309e0adbb80f00bd43665f2..2a559ace06bc44b8e09c07644ac3baf9c80db6ad 100644 (file)
@@ -140,13 +140,17 @@ void update_buffer_map(const char** bufs, const char* svc)
     {
         buffer_map[bufs[i]].push_back(svc);
         if ( !strcmp(svc, "http") )
+        {
             buffer_map[bufs[i]].push_back("http2");
+            buffer_map[bufs[i]].push_back("http3");
+        }
     }
 
     if ( !strcmp(svc, "http") )
     {
         buffer_map["file_data"].push_back("http");
         buffer_map["file_data"].push_back("http2");
+        buffer_map["file_data"].push_back("http3");
     }
 }
 
index 663832c551a9e4cdd10f6bc98fcc0da1c9075e9c..1b3a448fc232840e60ff1f10ed39f749dcc5656d 100644 (file)
@@ -6,6 +6,7 @@ set (FLOW_INCLUDES
     flow_key.h
     flow_stash.h
     ha.h
+    session.h
     stash_item.h
 )
 
@@ -28,7 +29,6 @@ add_library (flow OBJECT
     ha_module.cc
     ha_module.h
     prune_stats.h
-    session.h
     stash_item.h
 )
 
index 710ffe28e1b46dae811e5dd4fb2d2957c8aec175..d4343be5951db82c80bc0b873878ddcc46791b05 100644 (file)
@@ -39,6 +39,7 @@
 #include "framework/data_bus.h"
 #include "framework/decode_data.h"
 #include "framework/inspector.h"
+#include "network_inspectors/appid/application_ids.h"
 #include "protocols/layer.h"
 #include "sfip/sf_ip.h"
 #include "target_based/snort_protocols.h"
@@ -157,6 +158,15 @@ struct LwState
     char ignore_direction;
 };
 
+class SO_PUBLIC StreamFlowIntf
+{
+public:
+    virtual FlowData* get_stream_flow_data(const Flow* flow) = 0;
+    virtual void set_stream_flow_data(Flow* flow, FlowData* flow_data) = 0;
+    virtual void get_stream_id(const Flow* flow, int64_t& stream_id) = 0;
+    virtual AppId get_appid_from_stream(const Flow*) { return APP_ID_NONE; }
+};
+
 // this struct is organized by member size for compactness
 class SO_PUBLIC Flow
 {
@@ -425,6 +435,7 @@ public:  // FIXIT-M privatize if possible
     IpsContextChain context_chain;
     FlowData* flow_data;
     FlowStats flowstats;
+    StreamFlowIntf* stream_intf;
 
     SfIp client_ip;
     SfIp server_ip;
index 661f2eaf11c9ac6a4760595afdc8a00bb783d224..8e95f51a3ba602bfaa832f6d7650f6c23aea826e 100644 (file)
@@ -76,20 +76,20 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow)
     AppidChangeBits change_bits;
 
     if ((asd->get_tp_appid_ctxt() or ThirdPartyAppIdContext::get_tp_reload_in_progress()) and
-        !http_event->get_is_http2())
+        !http_event->get_is_httpx())
         return;
 
     if (appidDebug->is_enabled() and !is_debug_active)
         appidDebug->activate(flow, asd, inspector.get_ctxt().config.log_all_sessions);
 
     if (appidDebug->is_active())
-        LogMessage("AppIdDbg %s Processing HTTP metadata from HTTP Inspector for stream %u\n",
-            appidDebug->get_debug_session(), http_event->get_http2_stream_id());
+        LogMessage("AppIdDbg %s Processing HTTP metadata from HTTP Inspector for stream %" PRId64 "\n",
+            appidDebug->get_debug_session(), http_event->get_httpx_stream_id());
 
     asd->set_session_flags(APPID_SESSION_HTTP_SESSION);
 
     AppIdHttpSession* hsession;
-    if (http_event->get_is_http2())
+    if (http_event->get_is_httpx())
     {
         if (direction == APP_ID_FROM_INITIATOR)
         {
@@ -98,13 +98,13 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow)
                 asd->delete_all_http_sessions();
                 asd->set_prev_http2_raw_packet(asd->session_packet_count);
             }
-            hsession = asd->create_http_session(http_event->get_http2_stream_id());
+            hsession = asd->create_http_session(http_event->get_httpx_stream_id());
         }
         else
         {
-            hsession = asd->get_matching_http_session(http_event->get_http2_stream_id());
+            hsession = asd->get_matching_http_session(http_event->get_httpx_stream_id());
             if (!hsession)
-                hsession = asd->create_http_session(http_event->get_http2_stream_id());
+                hsession = asd->create_http_session(http_event->get_httpx_stream_id());
         }
     }
     else
@@ -179,9 +179,11 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow)
     if (header_length > 0)
         hsession->set_field(MISC_VIA_FID, header_start, header_length, change_bits);
 
-    if (http_event->get_is_http2())
+    if (http_event->get_is_httpx())
     {
-        asd->set_service_id(APP_ID_HTTP2, asd->get_odp_ctxt());
+        AppId http_app_id = flow->stream_intf->get_appid_from_stream(flow);
+        assert((http_app_id == APP_ID_HTTP2) || (http_app_id == APP_ID_HTTP3));
+        asd->set_service_id(http_app_id, asd->get_odp_ctxt());
     }
 
     hsession->process_http_packet(direction, change_bits,
@@ -194,7 +196,7 @@ void HttpEventHandler::handle(DataEvent& event, Flow* flow)
     else
         asd->set_application_ids_service(APP_ID_HTTP2, change_bits);
 
-    asd->publish_appid_event(change_bits, *p, http_event->get_is_http2(),
+    asd->publish_appid_event(change_bits, *p, http_event->get_is_httpx(),
         asd->get_api().get_hsessions_size() - 1);
 }
 
index e358ece03ad010f2bf8c5e64e01a118b3148b41d..62c5e7fcb424b071d8058684d4f1ab3f8bad044c 100644 (file)
@@ -39,8 +39,8 @@
 
 using namespace snort;
 
-AppIdHttpSession::AppIdHttpSession(AppIdSession& asd, uint32_t http2_stream_id)
-    : asd(asd), http2_stream_id(http2_stream_id)
+AppIdHttpSession::AppIdHttpSession(AppIdSession& asd, int64_t stream_id)
+    : asd(asd), httpx_stream_id(stream_id)
 { }
 
 AppIdHttpSession::~AppIdHttpSession()
@@ -923,9 +923,9 @@ void AppIdHttpSession::print_field(HttpFieldIds id, const std::string* field)
         return;
     }
 
-    if (http2_stream_id > 0)
-        LogMessage("AppIdDbg %s stream %u: %s is %s\n", appidDebug->get_debug_session(),
-            http2_stream_id, field_name.c_str(), field->c_str());
+    if (httpx_stream_id >= 0)
+        LogMessage("AppIdDbg %s stream %" PRId64 ": %s is %s\n", appidDebug->get_debug_session(),
+            httpx_stream_id, field_name.c_str(), field->c_str());
     else
         LogMessage("AppIdDbg %s %s is %s\n", appidDebug->get_debug_session(),
             field_name.c_str(), field->c_str());
index 2697b5280c59a398535e974644ba9788b982d24a..4998830722961142f577b99600770a7f5b9ee1dc 100644 (file)
@@ -60,7 +60,7 @@ class AppIdHttpSession
 public:
     typedef std::pair<uint16_t,uint16_t> pair_t;
 
-    AppIdHttpSession(AppIdSession&, uint32_t);
+    AppIdHttpSession(AppIdSession&, int64_t);
     virtual ~AppIdHttpSession();
     ClientAppDescriptor client;
     PayloadAppDescriptor payload;
@@ -134,9 +134,9 @@ public:
         const char* version = nullptr);
     void set_referred_payload(AppId, AppidChangeBits&);
 
-    uint32_t get_http2_stream_id() const
+    int64_t get_httpx_stream_id() const
     {
-        return http2_stream_id;
+        return httpx_stream_id;
     }
     void set_rcvd_full_req_body(bool req_full_body)
     {
@@ -193,7 +193,7 @@ protected:
 #if RESPONSE_CODE_PACKET_THRESHHOLD
     unsigned response_code_packets = 0;
 #endif
-    uint32_t http2_stream_id = 0;
+    int64_t httpx_stream_id = -1;
     bool is_payload_processed = false;
     bool rcvd_full_req_body = false;
     bool is_tunnel = false;
index 954e8dcde644c5e1c3b3a17d876f5ce9b1971d75..1dab790e96db1f8f63053a3dc1baf413ea9f0f04 100644 (file)
@@ -1000,18 +1000,18 @@ AppIdHttpSession* AppIdSession::get_http_session(uint32_t stream_index) const
         return nullptr;
 }
 
-AppIdHttpSession* AppIdSession::create_http_session(uint32_t stream_id)
+AppIdHttpSession* AppIdSession::create_http_session(int64_t stream_id)
 {
     AppIdHttpSession* hsession = new AppIdHttpSession(*this, stream_id);
     api.hsessions.push_back(hsession);
     return hsession;
 }
 
-AppIdHttpSession* AppIdSession::get_matching_http_session(uint32_t stream_id) const
+AppIdHttpSession* AppIdSession::get_matching_http_session(int64_t stream_id) const
 {
     for (uint32_t stream_index=0; stream_index < api.hsessions.size(); stream_index++)
     {
-        if(stream_id == api.hsessions[stream_index]->get_http2_stream_id())
+        if(stream_id == api.hsessions[stream_index]->get_httpx_stream_id())
             return api.hsessions[stream_index];
     }
     return nullptr;
@@ -1116,7 +1116,7 @@ void AppIdSession::set_tp_payload_app_id(const Packet& p, AppidSessionDirection
 }
 
 void AppIdSession::publish_appid_event(AppidChangeBits& change_bits, const Packet& p,
-    bool is_http2, uint32_t http2_stream_index)
+    bool is_httpx, uint32_t httpx_stream_index)
 {
     if (!api.stored_in_stash)
     {
@@ -1151,15 +1151,15 @@ void AppIdSession::publish_appid_event(AppidChangeBits& change_bits, const Packe
     if (change_bits.none())
         return;
 
-    AppidEvent app_event(change_bits, is_http2, http2_stream_index, api, p);
+    AppidEvent app_event(change_bits, is_httpx, httpx_stream_index, api, p);
     DataBus::publish(APPID_EVENT_ANY_CHANGE, app_event, p.flow);
     if (appidDebug->is_active())
     {
         std::string str;
         change_bits_to_string(change_bits, str);
-        if (is_http2)
-            LogMessage("AppIdDbg %s Published event for changes: %s for HTTP2 stream index %u\n",
-                appidDebug->get_debug_session(), str.c_str(), http2_stream_index);
+        if (is_httpx)
+            LogMessage("AppIdDbg %s Published event for changes: %s for HTTPX stream index %u\n",
+                appidDebug->get_debug_session(), str.c_str(), httpx_stream_index);
         else
             LogMessage("AppIdDbg %s Published event for changes: %s\n",
                 appidDebug->get_debug_session(), str.c_str());
index 5921348194daf15ea334ae7c4a0a13e89712be2a..76549a523340c510164cb006b3e3d046c9c1f4e0 100644 (file)
@@ -356,8 +356,8 @@ public:
     void reset_session_data(AppidChangeBits& change_bits);
 
     AppIdHttpSession* get_http_session(uint32_t stream_index = 0) const;
-    AppIdHttpSession* create_http_session(uint32_t stream_id = 0);
-    AppIdHttpSession* get_matching_http_session(uint32_t stream_id) const;
+    AppIdHttpSession* create_http_session(int64_t stream_id = -1);
+    AppIdHttpSession* get_matching_http_session(int64_t stream_id) const;
     void delete_all_http_sessions();
 
     AppIdDnsSession* create_dns_session();
@@ -371,8 +371,8 @@ public:
         AppidChangeBits& change_bits);
     void set_tp_payload_app_id(const snort::Packet& p, AppidSessionDirection dir, AppId app_id,
         AppidChangeBits& change_bits);
-    void publish_appid_event(AppidChangeBits&, const snort::Packet&, bool is_http2 = false,
-        uint32_t http2_stream_index = 0);
+    void publish_appid_event(AppidChangeBits&, const snort::Packet&, bool is_httpx = false,
+        uint32_t httpx_stream_index = 0);
 
     bool need_to_delete_tp_conn(ThirdPartyAppIdContext*) const;
 
index 184f5a8cd82c77ea8b4ab2f240cd7a2ee94f1ff8..c541685db1ddfb6dcb6b8de58407bacbbcaa8238 100644 (file)
@@ -163,8 +163,8 @@ AppIdSession::AppIdSession(IpProtocol, const SfIp* ip, uint16_t, AppIdInspector&
     this->set_session_flags(APPID_SESSION_DISCOVER_APP);
 }
 AppIdSession::~AppIdSession() { delete &api; }
-AppIdHttpSession::AppIdHttpSession(AppIdSession& asd, uint32_t http2_stream_id)
-  : asd(asd), http2_stream_id(http2_stream_id)
+AppIdHttpSession::AppIdHttpSession(AppIdSession& asd, int64_t http2_stream_id)
+  : asd(asd), httpx_stream_id(http2_stream_id)
 {
     for ( int i = 0; i < NUM_METADATA_FIELDS; i++)
         meta_data[i] = nullptr;
index f9418a62d6a75bcaae4b2c7bcdcbd0e556bc7916..d61c8b1acd5c93347c8165dbf3a4c812fa324dab 100644 (file)
@@ -261,12 +261,12 @@ bool HttpEvent::contains_webdav_method()
     return true;
 }
 
-bool HttpEvent::get_is_http2() const
+bool HttpEvent::get_is_httpx() const
 {
     return false;
 }
 
-uint32_t HttpEvent::get_http2_stream_id() const
+int64_t HttpEvent::get_httpx_stream_id() const
 {
     return 0;
 }
index 27fef68ab41a32f0c4160cbef580bee6e485e4e5..3fcdc047da219bfe515b6b9a167f3873aa479146 100644 (file)
@@ -25,8 +25,8 @@
 
 typedef AppIdHttpSession::pair_t pair_t;
 
-AppIdHttpSession::AppIdHttpSession(AppIdSession& session, uint32_t http2_stream_id)
-    : asd(session), http2_stream_id(http2_stream_id)
+AppIdHttpSession::AppIdHttpSession(AppIdSession& session, int64_t http2_stream_id)
+    : asd(session), httpx_stream_id(http2_stream_id)
 {
     for ( int i = 0; i < NUM_METADATA_FIELDS; i++)
         meta_data[i] = nullptr;
index 61a4098344c141209011e15a8a5be4d507c1dd54..3b1dcc0c620f82f37394948e78358a2063abec5f 100644 (file)
@@ -163,7 +163,7 @@ AppId AppIdSession::pick_ss_referred_payload_app_id() const
     return APPID_UT_ID;
 }
 
-AppIdHttpSession* AppIdSession::create_http_session(uint32_t)
+AppIdHttpSession* AppIdSession::create_http_session(int64_t)
 {
     AppIdHttpSession* hsession = new MockAppIdHttpSession(*this);
     AppidChangeBits change_bits;
@@ -178,11 +178,11 @@ AppIdHttpSession* AppIdSession::create_http_session(uint32_t)
     return hsession;
 }
 
-AppIdHttpSession* AppIdSession::get_matching_http_session(uint32_t stream_id) const
+AppIdHttpSession* AppIdSession::get_matching_http_session(int64_t stream_id) const
 {
-    for (uint32_t stream_index=0; stream_index < api.hsessions.size(); stream_index++)
+    for (uint64_t stream_index=0; stream_index < api.hsessions.size(); stream_index++)
     {
-        if (stream_id == api.hsessions[stream_index]->get_http2_stream_id())
+        if (stream_id == api.hsessions[stream_index]->get_httpx_stream_id())
             return api.hsessions[stream_index];
     }
     return nullptr;
index 1bee49eed93948e423cbdce9b11642161f039710..6245b94217d4d0c3ab863240cc4d409e703330a2 100644 (file)
@@ -147,9 +147,9 @@ void RnaAppDiscovery::process(AppidEvent* appid_event, DiscoveryFilter& filter,
         {
             const AppIdHttpSession* hsession;
 
-            if ( appid_event->get_is_http2() )
+            if ( appid_event->get_is_httpx() )
                 hsession = appid_session_api.get_http_session(
-                    appid_event->get_http2_stream_index());
+                    appid_event->get_httpx_stream_index());
             else
                 hsession = appid_session_api.get_http_session();
 
index e8d860b50302ffed6fe9781905797dbc52e3bbbc..c400c831281ada9cce83674c7ed61de641bbaa48 100644 (file)
@@ -218,7 +218,7 @@ void ParseIpVar(const char* var, const char* value)
 {
     int ret;
     IpsPolicy* p = get_ips_policy();
-    DisallowCrossTableDuplicateVars(var, VAR_TYPE__IPVAR); 
+    DisallowCrossTableDuplicateVars(var, VAR_TYPE__IPVAR);
     // FIXIT-M: ip checked for duplicates twice: in the function above and in sfvt_add_str
 
     if ((ret = sfvt_define(p->ip_vartable, var, value)) != SFIP_SUCCESS)
@@ -263,7 +263,10 @@ void add_service_to_otn(SnortConfig* sc, OptTreeNode* otn, const char* svc_name)
     }
 
     if ( !strcmp(svc_name, "http") )
+    {
         add_service_to_otn(sc, otn, "http2");
+        add_service_to_otn(sc, otn, "http3");
+    }
 
     SnortProtocolId svc_id = sc->proto_ref->add(svc_name);
 
index a60e07b6fee07f508a07c5a708f8adef56ad8890..c93f76d600d2ecbd740d172d73d7f93d9b660ada 100644 (file)
@@ -48,7 +48,7 @@ struct InjectionControl
 {
     const uint8_t* http_page = nullptr;
     uint32_t http_page_len = 0;
-    uint32_t stream_id = 0;
+    int64_t stream_id = 0;
 };
 
 class SO_PUBLIC PayloadInjector
index e2650de906a2a35feee25215dc44aa8216799ffd..29a1dee424e533b43fcc50fc8f40ccb2a3012ce6 100644 (file)
@@ -119,18 +119,18 @@ inline void change_bits_to_string(AppidChangeBits& change_bits, std::string& str
 class AppidEvent : public snort::DataEvent
 {
 public:
-    AppidEvent(const AppidChangeBits& ac, bool is_http2, uint32_t http2_stream_index,
+    AppidEvent(const AppidChangeBits& ac, bool is_httpx, uint32_t httpx_stream_index,
         const snort::AppIdSessionApi& api, const snort::Packet& p) :
-        ac_bits(ac), is_http2(is_http2), http2_stream_index(http2_stream_index), api(api), p(p) {}
+        ac_bits(ac), is_httpx(is_httpx), httpx_stream_index(httpx_stream_index), api(api), p(p) {}
 
     const AppidChangeBits& get_change_bitset() const
     { return ac_bits; }
 
-    bool get_is_http2() const
-    { return is_http2; }
+    bool get_is_httpx() const
+    { return is_httpx; }
 
-    uint32_t get_http2_stream_index() const
-    { return http2_stream_index; }
+    uint32_t get_httpx_stream_index() const
+    { return httpx_stream_index; }
 
     const snort::AppIdSessionApi& get_appid_session_api() const
     { return api; }
@@ -140,8 +140,8 @@ public:
 
 private:
     const AppidChangeBits& ac_bits;
-    bool is_http2;
-    uint32_t http2_stream_index;
+    bool is_httpx;
+    uint32_t httpx_stream_index;
     const snort::AppIdSessionApi& api;
     const snort::Packet& p;
 };
index b796f8a31f2ff1ea508c9e0fa9a096bf56e1d891..db661a58c06ded0f2a859fec6c9a0a92454f5712 100644 (file)
@@ -166,12 +166,12 @@ bool HttpEvent::contains_webdav_method()
     return HttpMsgRequest::is_webdav(method);
 }
 
-bool HttpEvent::get_is_http2() const
+bool HttpEvent::get_is_httpx() const
 {
-    return is_http2;
+    return is_httpx;
 }
 
-uint32_t HttpEvent::get_http2_stream_id() const
+int64_t HttpEvent::get_httpx_stream_id() const
 {
-    return http2_stream_id;
+    return httpx_stream_id;
 }
index 1ee9f0793cf17c69c83dd9eb0b535945bed884f6..94ccc59175c772c4ba764f2b1d7a2aac8cd160e0 100644 (file)
@@ -36,8 +36,8 @@ namespace snort
 class SO_PUBLIC HttpEvent : public snort::DataEvent
 {
 public:
-    HttpEvent(HttpMsgHeader* http_msg_header_, bool http2, uint32_t stream_id) :
-        http_msg_header(http_msg_header_), is_http2(http2), http2_stream_id(stream_id) { }
+    HttpEvent(HttpMsgHeader* http_msg_header_, bool httpx, int64_t stream_id) :
+        http_msg_header(http_msg_header_), is_httpx(httpx), httpx_stream_id(stream_id) { }
 
 
     const uint8_t* get_content_type(int32_t &length);
@@ -54,13 +54,13 @@ public:
     const uint8_t* get_x_working_with(int32_t &length);
     int32_t get_response_code();
     bool contains_webdav_method();
-    bool get_is_http2() const;
-    uint32_t get_http2_stream_id() const;
+    bool get_is_httpx() const;
+    int64_t get_httpx_stream_id() const;
 
 private:
     HttpMsgHeader* const http_msg_header;
-    bool is_http2 = false;
-    uint32_t http2_stream_id = 0;
+    bool is_httpx = false;
+    int64_t httpx_stream_id = -1;
 
     const uint8_t* get_header(unsigned, uint64_t, int32_t&);
 
index ab9aeb55ccc12992f1619d664084a05ebfa485ef..4cd4d743dcb76efe343848fb3c93692030fefecd 100644 (file)
@@ -53,5 +53,5 @@ bool HttpRequestBodyEvent::is_last_request_body_piece()
 
 uint32_t HttpRequestBodyEvent::get_http2_stream_id() const
 {
-    return http_flow_data->get_h2_stream_id();
+    return http_flow_data->get_hx_stream_id();
 }
index f66625421e27b2ebe5107ffd4a0cb482210c2b77..3ab47dc8348492f1c578d8ec672cef605fe8a511 100644 (file)
@@ -73,18 +73,18 @@ TEST_GROUP(pub_sub_http_event_test)
 
 TEST(pub_sub_http_event_test, http_traffic)
 {
-    uint32_t stream_id = 0;
+    int64_t stream_id = 0;
     HttpEvent event(nullptr, false, stream_id);
-    CHECK_FALSE(event.get_is_http2());
-    CHECK(event.get_http2_stream_id() == stream_id);
+    CHECK_FALSE(event.get_is_httpx());
+    CHECK(event.get_httpx_stream_id() == stream_id);
 }
 
-TEST(pub_sub_http_event_test, http2_traffic)
+TEST(pub_sub_http_event_test, httpx_traffic)
 {
-    uint32_t stream_id = 3;
+    int64_t stream_id = 3;
     HttpEvent event(nullptr, true, stream_id);
-    CHECK(event.get_is_http2());
-    CHECK(event.get_http2_stream_id() == stream_id);
+    CHECK(event.get_is_httpx());
+    CHECK(event.get_httpx_stream_id() == stream_id);
 }
 
 TEST(pub_sub_http_event_test, no_true_ip_addr)
index 21770eb9066c0ed4bb847bf0b8cd78e1ac5bf937..c27c8b4d638ffe9496ada5cd64e857001e7c0e29 100644 (file)
@@ -103,9 +103,9 @@ int32_t HttpMsgBody::get_publish_length() const
     return mock().getData("pub_length").getIntValue();
 }
 
-uint32_t HttpFlowData::get_h2_stream_id() const
+int64_t HttpFlowData::get_hx_stream_id() const
 {
-    return  mock().getData("stream_id").getUnsignedIntValue();
+    return  mock().getData("stream_id").getLongLongIntValue();
 }
 
 
index bb05cf9d5399e1c359f760ce2950f44913ad390e..d3cf4c99317935af3244d6ee7410e1fdd531c829 100644 (file)
@@ -1,5 +1,13 @@
 
+set(HTTP2_INCLUDES
+    http2_huffman_state_machine.h
+    http2_varlen_int_decode.h
+    http2_varlen_int_decode_impl.h
+    http2_varlen_string_decode.h
+    http2_varlen_string_decode_impl.h
+)
 set (FILE_LIST
+    ${HTTP2_INCLUDES}
     http2_api.cc
     http2_api.h
     http2_data_frame.cc
@@ -25,16 +33,11 @@ set (FILE_LIST
     http2_hpack.h
     http2_hpack_dynamic_table.cc
     http2_hpack_dynamic_table.h
-    http2_varlen_int_decode.h
-    http2_varlen_int_decode_impl.h
-    http2_varlen_string_decode.h
-    http2_varlen_string_decode_impl.h
     http2_hpack_int_decode.h
     http2_hpack_string_decode.h
     http2_hpack_table.cc
     http2_hpack_table.h
     http2_huffman_state_machine.cc
-    http2_huffman_state_machine.h
     http2_inspect.cc
     http2_inspect.h
     http2_module.cc
@@ -74,6 +77,8 @@ set (FILE_LIST
     #add_dynamic_module(http2_inspect inspectors ${FILE_LIST})
 
 #endif(STATIC_INSPECTORS)
-
+install(FILES ${HTTP2_INCLUDES}
+    DESTINATION "${INCLUDE_INSTALL_PATH}/service_inspectors/http2_inspect"
+)
 add_subdirectory ( test )
 
index fc20430ce4afab4490551719e9a6cac1ff9a9ef9..0b68e060e6883e405fd8533e5631f897d9f23628 100644 (file)
@@ -73,7 +73,7 @@ StreamSplitter::Status Http2DataCutter::skip_over_frame(Http2Stream* const strea
 bool Http2DataCutter::check_http_state(Http2Stream* const stream)
 {
     HttpFlowData* const http_flow = stream->get_hi_flow_data();
-    if ((http_flow->get_type_expected(source_id) != SEC_BODY_H2))
+    if ((http_flow->get_type_expected(source_id) != SEC_BODY_HX))
     {
         stream->set_state(source_id, STREAM_ERROR);
         if (data_len > 0)
@@ -134,7 +134,7 @@ StreamSplitter::Status Http2DataCutter::scan(const uint8_t* data, uint32_t lengt
         if ((data_bytes_read == data_len) && (frame_flags & FLAG_END_STREAM))
         {
             HttpFlowData* const hi_flow = stream->get_hi_flow_data();
-            hi_flow->set_h2_body_state(source_id, H2_BODY_LAST_SEG);
+            hi_flow->set_hx_body_state(source_id, HX_BODY_LAST_SEG);
         }
         scan_result = session_data->hi_ss[source_id]->scan(session_data->flow, data + cur_data_offset, cur_data,
             &http_flush_offset);
index 6a6599eb953fb6a779711b73b150a6c35b41dd80..73f08ea2833c4874edef94adfb35a925f687cbab 100644 (file)
@@ -53,6 +53,7 @@ Http2FlowData::Http2FlowData(Flow* flow_) :
                         infractions[SRC_SERVER]) },
     data_cutter { Http2DataCutter(this, SRC_CLIENT), Http2DataCutter(this, SRC_SERVER) }
 {
+    static Http2FlowStreamIntf h2_stream;
     if (hi != nullptr)
     {
         hi_ss[SRC_CLIENT] = hi->get_splitter(true);
@@ -72,6 +73,8 @@ Http2FlowData::Http2FlowData(Flow* flow_) :
     if (Http2Module::get_peg_counts(PEG_MAX_CONCURRENT_SESSIONS) <
         Http2Module::get_peg_counts(PEG_CONCURRENT_SESSIONS))
         Http2Module::increment_peg_counts(PEG_MAX_CONCURRENT_SESSIONS);
+
+    flow->stream_intf = &h2_stream;
 }
 
 Http2FlowData::~Http2FlowData()
@@ -251,3 +254,39 @@ bool Http2FlowData::is_mid_frame() const
         continuation_expected[SRC_SERVER];
 }
 
+FlowData* Http2FlowStreamIntf::get_stream_flow_data(const Flow* flow)
+{
+    Http2FlowData* h2i_flow_data = nullptr;
+
+    h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
+    assert(h2i_flow_data);
+
+    return h2i_flow_data->get_hi_flow_data();
+}
+
+void Http2FlowStreamIntf::set_stream_flow_data(Flow* flow, FlowData* flow_data)
+{
+    Http2FlowData* h2i_flow_data =
+        (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
+    assert(h2i_flow_data);
+    h2i_flow_data->set_hi_flow_data((HttpFlowData*)flow_data);
+}
+
+void Http2FlowStreamIntf::get_stream_id(const Flow* flow, int64_t& stream_id)
+{
+    Http2FlowData* h2i_flow_data = nullptr;
+
+    h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
+    assert(h2i_flow_data);
+    stream_id = h2i_flow_data->get_processing_stream_id();
+}
+
+AppId Http2FlowStreamIntf::get_appid_from_stream(const Flow* flow)
+{
+    Http2FlowData* h2i_flow_data = nullptr;
+
+    h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
+    assert(h2i_flow_data);
+
+    return APP_ID_HTTP2;
+}
index 63b84b6796d3df9552c04949d583c8f57aa7a47b..d975155bededae519792f3ea858e30b597082075 100644 (file)
@@ -105,7 +105,7 @@ public:
     // frame into the S2C direction of an HTTP/2 flow.
     bool is_mid_frame() const;
 
-    // Used by payload injection to determine whether we should inject S2C settings frame 
+    // Used by payload injection to determine whether we should inject S2C settings frame
     // before injecting payload
     bool was_server_settings_received() const
     { return server_settings_frame_received; }
@@ -206,5 +206,14 @@ private:
     void delete_processing_stream();
 };
 
+class Http2FlowStreamIntf : public snort::StreamFlowIntf
+{
+public:
+    snort::FlowData* get_stream_flow_data(const snort::Flow* flow) override;
+    void set_stream_flow_data(snort::Flow* flow, snort::FlowData* flow_data) override;
+    void get_stream_id(const snort::Flow* flow, int64_t& stream_id) override;
+    AppId get_appid_from_stream(const snort::Flow* flow) override;
+};
+
 #endif
 
index deff6a11351b5bc3e90f4014558d3168710f2804..9fdebe30b555267a881a33dd32dd4c0e0a577b87 100644 (file)
@@ -72,7 +72,7 @@ void Http2HeadersFrameHeader::analyze_http1(Packet* p)
 
     // if END_STREAM flag set on headers, tell http_inspect not to expect a message body
     if (get_flags() & FLAG_END_STREAM)
-        stream->get_hi_flow_data()->finish_h2_body(source_id, H2_BODY_NO_BODY, false);
+        stream->get_hi_flow_data()->finish_hx_body(source_id, HX_BODY_NO_BODY, false);
 
     process_decoded_headers(http_flow, source_id, p);
 }
index 365f6d2f3ea865d7de021ad8605274ac904acd13..7a7c13c7eccf3121ff52f7766903550d75a455ab 100644 (file)
@@ -74,7 +74,7 @@ void Http2HeadersFrameTrailer::analyze_http1(Packet* p)
     {
         // http_inspect is not yet expecting trailers. Flush empty buffer through scan, reassemble,
         // and eval to prepare http_inspect for trailers.
-        assert(http_flow->get_type_expected(source_id) == SEC_BODY_H2);
+        assert(http_flow->get_type_expected(source_id) == SEC_BODY_HX);
         stream->finish_msg_body(source_id, valid_headers, true); // calls http_inspect scan()
 
         unsigned copied;
index 648ba6d77276bf9d6736d10ea1648bbc861bbf1f..a5eaac3d77b2345ca6d09653dda3c254af4c1837 100644 (file)
@@ -46,7 +46,6 @@ public:
     HpackDynamicTable& get_dynamic_table() { return dynamic_table; }
 
     const static uint8_t STATIC_MAX_INDEX = 61;
-    const static uint8_t PSEUDO_HEADER_MAX_STATIC_INDEX = 14;
 
 private:
     const static HpackTableEntry static_table[STATIC_MAX_INDEX + 1];
index 5bf8909c67da96677badc6eb0ed75be86d9cfc38..7553d3047a846be933a833f201710455a5ea3dab 100644 (file)
@@ -51,7 +51,7 @@ struct HuffmanEntry
     HuffmanState state;
 };
 
-extern const HuffmanEntry huffman_decode[][UINT8_MAX+1];
+SO_PUBLIC extern const HuffmanEntry huffman_decode[][UINT8_MAX+1];
 
 #endif
 
index c21899b3c0925d2ab3b31b4d96100ac1f176679e..0a1ccc5b3b16a768be29a821ef9c54cb58bcdb5d 100644 (file)
@@ -116,7 +116,7 @@ void Http2PushPromiseFrame::analyze_http1(Packet* p)
 
     // Push promise cannot have a message body
     // FIXIT-E handle bad request lines and cases where a message body is implied
-    stream->get_hi_flow_data()->finish_h2_body(SRC_CLIENT, H2_BODY_NO_BODY, false);
+    stream->get_hi_flow_data()->finish_hx_body(SRC_CLIENT, HX_BODY_NO_BODY, false);
 
     process_decoded_headers(http_flow, SRC_CLIENT, p);
 }
index aea2b4b5479f4e2383a6377289d6e1823aba7425..304ad8aa3a137cfc56c787941862f48947ba2912 100644 (file)
@@ -130,9 +130,9 @@ void Http2Stream::finish_msg_body(HttpCommon::SourceId source_id, bool expect_tr
     bool clear_partial_buffer)
 {
     uint32_t http_flush_offset = 0;
-    const H2BodyState body_state = expect_trailers ?
-        H2_BODY_COMPLETE_EXPECT_TRAILERS : H2_BODY_COMPLETE;
-    get_hi_flow_data()->finish_h2_body(source_id, body_state, clear_partial_buffer);
+    const HXBodyState body_state = expect_trailers ?
+        HX_BODY_COMPLETE_EXPECT_TRAILERS : HX_BODY_COMPLETE;
+    get_hi_flow_data()->finish_hx_body(source_id, body_state, clear_partial_buffer);
     if (clear_partial_buffer)
     {
         const StreamSplitter::Status scan_result = session_data->hi_ss[source_id]->scan(
index 41bae3d32e81209fee570eb95cefbb1ae036c548..2c9bd0f2918eb39731c995632b10d39c90a30439 100644 (file)
@@ -268,7 +268,7 @@ bool Http2StreamSplitter::finish(Flow* flow)
             (stream->get_state(source_id) >= STREAM_COMPLETE)         ||
             (stream->get_hi_flow_data() == nullptr)                   ||
             (stream->get_hi_flow_data()->get_type_expected(source_id)
-                != SEC_BODY_H2)                                       ||
+                != SEC_BODY_HX)                                       ||
             (session_data->processing_partial_header &&
                 (stream->get_stream_id() == session_data->current_stream[source_id])))
         {
index 64eb5b305d8bba8e9a0a0d6b3f5ccc08be7e0f30..d5fb7e0028f2462e0e30a75cc7922016c00233a1 100644 (file)
@@ -20,8 +20,6 @@
 #ifndef HTTP2_VARLEN_STRING_DECODE_IMPL_H
 #define HTTP2_VARLEN_STRING_DECODE_IMPL_H
 
-
-#include "http2_enum.h"
 #include "http2_huffman_state_machine.h"
 #include "http2_varlen_string_decode.h"
 
index 3ef0ac16851c886f33b77699048f40af19cc7112..062c28339dcf7f8973fa70ead8d8507af37fbda3 100644 (file)
@@ -4,6 +4,7 @@ set(HTTP_INCLUDES
     http_common.h
     http_inspect_base.h
     http_stream_splitter_base.h
+    http_test_manager.h
 )
 set (FILE_LIST
     ${HTTP_INCLUDES}
@@ -32,8 +33,8 @@ set (FILE_LIST
     http_msg_body_chunk.h
     http_msg_body_cl.cc
     http_msg_body_cl.h
-    http_msg_body_h2.cc
-    http_msg_body_h2.h
+    http_msg_body_hx.cc
+    http_msg_body_hx.h
     http_msg_body_old.cc
     http_msg_body_old.h
     http_msg_trailer.cc
@@ -67,6 +68,7 @@ set (FILE_LIST
     http_transaction.h
     http_test_manager.cc
     http_test_manager.h
+    http_enum.h
     http_field.cc
     http_stream_splitter_finish.cc
     http_stream_splitter_reassemble.cc
index be626dbb3bacd44cd7071f906d4100ce8296b5f6..ca4bed7484ba7a70b79ad2469ff8df2427cdd687 100755 (executable)
@@ -75,7 +75,7 @@ processed together. There are eight types of message section:
 5. Chunked message body (same but from a chunked body)
 6. Old message body (same but from a body with no Content-Length header that runs to connection
    close)
-7. HTTP/2 message body (same but content taken from an HTTP/2 Data frame)
+7. HTTP/X message body (same but content taken from an HTTP/2 or HTTP/3 Data frame)
 8. Trailers (all header lines following a chunked body as a group)
 
 Message sections are represented by message section objects that contain and process them. There
@@ -92,7 +92,7 @@ are twelve message section classes that inherit as follows. An asterisk denotes
 9. HttpMsgBodyCl : HttpMsgBody
 10. HttpMsgBodyChunk : HttpMsgBody
 11. HttpMsgBodyOld : HttpMsgBody
-12. HttpMsgBodyH2 : HttpMsgBody
+12. HttpMsgBodyHX : HttpMsgBody
 
 An HttpTransaction is a container that keeps all the sections of a message together and associates
 the request message with the response message. Transactions may be organized into pipelines when an
index 679a9ff79818808519bc9407e2d83591080cfe6d..170a788b08bd8f4830926678c1d86e8efeec7317 100644 (file)
@@ -35,10 +35,11 @@ enum SourceId { SRC__NOT_COMPUTE=-14, SRC_CLIENT=0, SRC_SERVER=1 };
 // Type of message section
 enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOT_COMPUTE=-14, SEC__NOT_PRESENT=-11,
     SEC_REQUEST = 2, SEC_STATUS, SEC_HEADER, SEC_BODY_CL, SEC_BODY_CHUNK, SEC_TRAILER,
-    SEC_BODY_OLD, SEC_BODY_H2 };
+    SEC_BODY_OLD, SEC_BODY_HX };
 
-enum H2BodyState { H2_BODY_NOT_COMPLETE, H2_BODY_LAST_SEG, H2_BODY_COMPLETE,
-    H2_BODY_COMPLETE_EXPECT_TRAILERS, H2_BODY_NO_BODY };
+// Caters to all extended versions of HTTP, i.e. HTTP/2, HTTP/3
+enum HXBodyState { HX_BODY_NOT_COMPLETE, HX_BODY_LAST_SEG, HX_BODY_COMPLETE,
+    HX_BODY_COMPLETE_EXPECT_TRAILERS, HX_BODY_NO_BODY };
 
 } // end namespace HttpCommon
 
index cab0d6c84199758083d4cc06e87d160113c967cd..2a1f087d94559700e3f1d876682d23e9051291a2 100644 (file)
@@ -32,7 +32,7 @@ using namespace HttpEnums;
 using namespace HttpCommon;
 
 ScanResult HttpStartCutter::cut(const uint8_t* buffer, uint32_t length,
-    HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, H2BodyState)
+    HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, HXBodyState)
 {
     for (uint32_t k = 0; k < length; k++)
     {
@@ -190,7 +190,7 @@ HttpStartCutter::ValidationResult HttpStatusCutter::validate(uint8_t octet,
 }
 
 ScanResult HttpHeaderCutter::cut(const uint8_t* buffer, uint32_t length,
-    HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, H2BodyState)
+    HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, HXBodyState)
 {
     // Header separators: leading \r\n, leading \n, leading \r\r\n, nonleading \r\n\r\n, nonleading
     // \n\r\n, nonleading \r\r\n, nonleading \r\n\n, and nonleading \n\n. The separator itself
@@ -330,7 +330,7 @@ HttpBodyCutter::~HttpBodyCutter()
 }
 
 ScanResult HttpBodyClCutter::cut(const uint8_t* buffer, uint32_t length, HttpInfractions*,
-    HttpEventGen*, uint32_t flow_target, bool stretch, H2BodyState)
+    HttpEventGen*, uint32_t flow_target, bool stretch, HXBodyState)
 {
     assert(remaining > octets_seen);
 
@@ -407,7 +407,7 @@ ScanResult HttpBodyClCutter::cut(const uint8_t* buffer, uint32_t length, HttpInf
 }
 
 ScanResult HttpBodyOldCutter::cut(const uint8_t* buffer, uint32_t length, HttpInfractions*,
-    HttpEventGen*, uint32_t flow_target, bool stretch, H2BodyState)
+    HttpEventGen*, uint32_t flow_target, bool stretch, HXBodyState)
 {
     if (flow_target == 0)
     {
@@ -453,7 +453,7 @@ void HttpBodyChunkCutter::transition_to_chunk_bad(bool& accelerate_this_packet)
 
 ScanResult HttpBodyChunkCutter::cut(const uint8_t* buffer, uint32_t length,
     HttpInfractions* infractions, HttpEventGen* events, uint32_t flow_target, bool stretch,
-    H2BodyState)
+    HXBodyState)
 {
     // Are we skipping through the rest of this chunked body to the trailers and the next message?
     const bool discard_mode = (flow_target == 0);
@@ -758,9 +758,9 @@ ScanResult HttpBodyChunkCutter::cut(const uint8_t* buffer, uint32_t length,
     return SCAN_NOT_FOUND;
 }
 
-ScanResult HttpBodyH2Cutter::cut(const uint8_t* buffer, uint32_t length,
+ScanResult HttpBodyHXCutter::cut(const uint8_t* buffer, uint32_t length,
     HttpInfractions* infractions, HttpEventGen* events, uint32_t flow_target, bool stretch,
-    H2BodyState state)
+    HXBodyState state)
 {
     // If the headers included a content length header (expected length >= 0), check it against the
     // actual message body length. Alert if it does not match at the end of the message body or if
@@ -773,7 +773,7 @@ ScanResult HttpBodyH2Cutter::cut(const uint8_t* buffer, uint32_t length,
             events->create_event(EVENT_H2_DATA_OVERRUNS_CL);
             expected_body_length = STAT_NOT_COMPUTE;
         }
-        else if (state != H2_BODY_NOT_COMPLETE and
+        else if (state != HX_BODY_NOT_COMPLETE and
             ((total_octets_scanned + length) < expected_body_length))
         {
             *infractions += INF_H2_DATA_UNDERRUNS_CL;
@@ -785,13 +785,13 @@ ScanResult HttpBodyH2Cutter::cut(const uint8_t* buffer, uint32_t length,
     {
         num_flush = length;
         total_octets_scanned += length;
-        if (state != H2_BODY_NOT_COMPLETE)
+        if (state != HX_BODY_NOT_COMPLETE)
             return SCAN_DISCARD;
 
         return SCAN_DISCARD_PIECE;
     }
 
-    if (state == H2_BODY_NOT_COMPLETE)
+    if (state == HX_BODY_NOT_COMPLETE)
     {
         if (octets_seen + length < flow_target)
         {
@@ -812,7 +812,7 @@ ScanResult HttpBodyH2Cutter::cut(const uint8_t* buffer, uint32_t length,
             return SCAN_FOUND_PIECE;
         }
     }
-    else if (state == H2_BODY_LAST_SEG)
+    else if (state == HX_BODY_LAST_SEG)
     {
         const uint32_t adjusted_target = stretch ? MAX_SECTION_STRETCH + flow_target : flow_target;
         if (octets_seen + length <= adjusted_target)
index 1edc8b70fc8947f801f19747014863bbde1a7c0c..57bf254b60fb21302b30db28591e7eea04d84f50 100644 (file)
@@ -40,7 +40,7 @@ public:
     virtual ~HttpCutter() = default;
     virtual HttpEnums::ScanResult cut(const uint8_t* buffer, uint32_t length,
         HttpInfractions* infractions, HttpEventGen* events, uint32_t flow_target, bool stretch,
-        HttpCommon::H2BodyState state) = 0;
+        HttpCommon::HXBodyState state) = 0;
     uint32_t get_num_flush() const { return num_flush; }
     uint32_t get_octets_seen() const { return octets_seen; }
     uint32_t get_num_excess() const { return num_crlf; }
@@ -60,7 +60,7 @@ class HttpStartCutter : public HttpCutter
 {
 public:
     HttpEnums::ScanResult cut(const uint8_t* buffer, uint32_t length,
-        HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, HttpCommon::H2BodyState)
+        HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, HttpCommon::HXBodyState)
         override;
 
 protected:
@@ -91,7 +91,7 @@ class HttpHeaderCutter : public HttpCutter
 {
 public:
     HttpEnums::ScanResult cut(const uint8_t* buffer, uint32_t length,
-        HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, HttpCommon::H2BodyState)
+        HttpInfractions* infractions, HttpEventGen* events, uint32_t, bool, HttpCommon::HXBodyState)
         override;
     uint32_t get_num_head_lines() const override { return num_head_lines; }
 
@@ -138,7 +138,7 @@ public:
         remaining(expected_length)
         { assert(remaining > 0); }
     HttpEnums::ScanResult cut(const uint8_t*, uint32_t length, HttpInfractions*, HttpEventGen*,
-        uint32_t flow_target, bool stretch, HttpCommon::H2BodyState) override;
+        uint32_t flow_target, bool stretch, HttpCommon::HXBodyState) override;
 
 private:
     int64_t remaining;
@@ -152,7 +152,7 @@ public:
         HttpBodyCutter(accelerated_blocking, finder, compression)
         {}
     HttpEnums::ScanResult cut(const uint8_t*, uint32_t, HttpInfractions*, HttpEventGen*,
-        uint32_t flow_target, bool stretch, HttpCommon::H2BodyState) override;
+        uint32_t flow_target, bool stretch, HttpCommon::HXBodyState) override;
 };
 
 class HttpBodyChunkCutter : public HttpBodyCutter
@@ -165,7 +165,7 @@ public:
         {}
     HttpEnums::ScanResult cut(const uint8_t* buffer, uint32_t length,
         HttpInfractions* infractions, HttpEventGen* events, uint32_t flow_target, bool stretch,
-        HttpCommon::H2BodyState) override;
+        HttpCommon::HXBodyState) override;
     bool get_is_broken_chunk() const override { return curr_state == HttpEnums::CHUNK_BAD; }
     uint32_t get_num_good_chunks() const override { return num_good_chunks; }
     void soft_reset() override { num_good_chunks = 0; HttpBodyCutter::soft_reset(); }
@@ -185,16 +185,16 @@ private:
     bool zero_chunk = true;
 };
 
-class HttpBodyH2Cutter : public HttpBodyCutter
+class HttpBodyHXCutter : public HttpBodyCutter
 {
 public:
-    HttpBodyH2Cutter(int64_t expected_length, bool accelerated_blocking, ScriptFinder* finder,
+    HttpBodyHXCutter(int64_t expected_length, bool accelerated_blocking, ScriptFinder* finder,
         HttpEnums::CompressId compression) :
         HttpBodyCutter(accelerated_blocking, finder, compression),
             expected_body_length(expected_length)
         {}
     HttpEnums::ScanResult cut(const uint8_t* buffer, uint32_t length, HttpInfractions*,
-        HttpEventGen*, uint32_t flow_target, bool stretch, HttpCommon::H2BodyState state) override;
+        HttpEventGen*, uint32_t flow_target, bool stretch, HttpCommon::HXBodyState state) override;
 private:
     int64_t expected_body_length;
     uint32_t total_octets_scanned = 0;
index b4acfaec4f6c507e675789373a26c2cdbd979c42..ffbdc80ec1f048afe0d6108bb748b4ebcaca6b01 100755 (executable)
@@ -81,7 +81,7 @@ enum ChunkState { CHUNK_NEWLINES, CHUNK_ZEROS, CHUNK_LEADING_WS, CHUNK_NUMBER, C
 
 // List of possible HTTP versions.
 enum VersionId { VERS__PROBLEMATIC=-12, VERS__NOT_PRESENT=-11, VERS__OTHER=1,
-    VERS_1_0, VERS_1_1, VERS_2_0, VERS_0_9, VERS__MIN = VERS__PROBLEMATIC,
+    VERS_1_0, VERS_1_1, VERS_2_0, VERS_3_0, VERS_0_9, VERS__MIN = VERS__PROBLEMATIC,
     VERS__MAX = VERS_0_9};
 
 // Every request method we have ever heard of
index 1ba5d995fea5bfcf26c5770e1e22fb25eb4343bb..19b17296b8fe1db46a1612598c2042d4d3a8217a 100644 (file)
 #include <cstdio>
 #include <cassert>
 
+#include "main/snort_types.h"
+
 #include "http_common.h"
-#include "http_enum.h"
 
 // Individual pieces of the message found during parsing.
 // Length values <= 0 are StatusCode values and imply that the start pointer is meaningless.
 // Never use the start pointer without verifying that length > 0.
-class Field
+class SO_PUBLIC Field
 {
 public:
     static const Field FIELD_NULL;
index e44ab62d46e53a70599ba417682fc4cebf263faa..26ff9ba42e93170780f8845d70044b78761f78ca 100644 (file)
@@ -53,6 +53,7 @@ uint64_t HttpFlowData::instance_count = 0;
 
 HttpFlowData::HttpFlowData(Flow* flow) : FlowData(inspector_id)
 {
+    static HttpFlowStreamIntf h1_stream;
 #ifdef REG_TEST
     if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP))
     {
@@ -70,16 +71,17 @@ HttpFlowData::HttpFlowData(Flow* flow) : FlowData(inspector_id)
         HttpModule::get_peg_counts(PEG_CONCURRENT_SESSIONS))
         HttpModule::increment_peg_counts(PEG_MAX_CONCURRENT_SESSIONS);
 
-    Http2FlowData* h2i_flow_data = nullptr;
-    if (Http2FlowData::inspector_id != 0)
-        h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
-    if (h2i_flow_data != nullptr)
+    if (flow->stream_intf)
+        flow->stream_intf->get_stream_id(flow, hx_stream_id);
+
+    if (valid_hx_stream_id())
     {
-        for_http2 = true;
-        h2_stream_id = h2i_flow_data->get_processing_stream_id();
+        for_httpx = true;
         events[0]->suppress_event(HttpEnums::EVENT_LOSS_OF_SYNC);
         events[1]->suppress_event(HttpEnums::EVENT_LOSS_OF_SYNC);
     }
+    else
+        flow->stream_intf = &h1_stream;
 }
 
 HttpFlowData::~HttpFlowData()
@@ -254,7 +256,7 @@ snort::JSNormalizer& HttpFlowData::acquire_js_ctx(const HttpParaList::JsNormPara
 
     if (!js_ident_ctx)
     {
-        js_ident_ctx = new JSIdentifierCtx(js_norm_param.js_identifier_depth, 
+        js_ident_ctx = new JSIdentifierCtx(js_norm_param.js_identifier_depth,
             js_norm_param.max_scope_depth, js_norm_param.ignored_ids, js_norm_param.ignored_props);
 
         debug_logf(4, http_trace, TRACE_JS_PROC, nullptr,
@@ -348,12 +350,12 @@ HttpInfractions* HttpFlowData::get_infractions(SourceId source_id)
     return transaction[source_id]->get_infractions(source_id);
 }
 
-void HttpFlowData::finish_h2_body(HttpCommon::SourceId source_id, HttpCommon::H2BodyState state,
+void HttpFlowData::finish_hx_body(HttpCommon::SourceId source_id, HttpCommon::HXBodyState state,
     bool clear_partial_buffer)
 {
-    assert((h2_body_state[source_id] == H2_BODY_NOT_COMPLETE) ||
-        (h2_body_state[source_id] == H2_BODY_LAST_SEG));
-    h2_body_state[source_id] = state;
+    assert((hx_body_state[source_id] == HX_BODY_NOT_COMPLETE) ||
+        (hx_body_state[source_id] == HX_BODY_LAST_SEG));
+    hx_body_state[source_id] = state;
     partial_flush[source_id] = false;
     if (clear_partial_buffer)
     {
@@ -372,11 +374,34 @@ void HttpFlowData::finish_h2_body(HttpCommon::SourceId source_id, HttpCommon::H2
     }
 }
 
-uint32_t HttpFlowData::get_h2_stream_id() const
+int64_t HttpFlowData::get_hx_stream_id() const
+{
+    return hx_stream_id;
+}
+
+bool HttpFlowData::valid_hx_stream_id() const
+{
+    return (hx_stream_id >= 0);
+}
+
+FlowData* HttpFlowStreamIntf::get_stream_flow_data(const Flow* flow)
 {
-    return h2_stream_id;
+    return (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
 }
 
+void HttpFlowStreamIntf::set_stream_flow_data(Flow* flow, FlowData* flow_data)
+{
+    flow->set_flow_data(flow_data);
+}
+
+void HttpFlowStreamIntf::get_stream_id(const Flow*, int64_t& stream_id)
+{
+    // HTTP Flows by itself doesn't have any stream id, thus assigning -1 to
+    // indicate invalid value
+    stream_id = -1;
+}
+
+
 #ifdef REG_TEST
 void HttpFlowData::show(FILE* out_file) const
 {
index fa7b7c7cc2bf6765318fe31d486d937e74f44c47..aa824c7a3e0e97977f6ded57209dea3001d18bc7 100644 (file)
@@ -67,7 +67,7 @@ public:
     friend class HttpMsgBody;
     friend class HttpMsgBodyChunk;
     friend class HttpMsgBodyCl;
-    friend class HttpMsgBodyH2;
+    friend class HttpMsgBodyHX;
     friend class HttpMsgBodyOld;
     friend class HttpQueryParser;
     friend class HttpStreamSplitter;
@@ -79,13 +79,15 @@ public:
     HttpCommon::SectionType get_type_expected(HttpCommon::SourceId source_id) const
     { return type_expected[source_id]; }
 
-    void finish_h2_body(HttpCommon::SourceId source_id, HttpCommon::H2BodyState state,
+    void finish_hx_body(HttpCommon::SourceId source_id, HttpCommon::HXBodyState state,
         bool clear_partial_buffer);
 
-    void set_h2_body_state(HttpCommon::SourceId source_id, HttpCommon::H2BodyState state)
-    { h2_body_state[source_id] = state; }
+    void set_hx_body_state(HttpCommon::SourceId source_id, HttpCommon::HXBodyState state)
+    { hx_body_state[source_id] = state; }
 
-    uint32_t get_h2_stream_id() const;
+    bool valid_hx_stream_id() const;
+    int64_t get_hx_stream_id() const;
+    bool is_for_httpx() const { return for_httpx; }
 
 private:
     // Convenience routines
@@ -219,11 +221,11 @@ private:
     bool cutover_on_clear = false;
     bool ssl_search_abandoned = false;
 
-    // *** HTTP/2 handling
-    bool for_http2 = false;
-    uint32_t h2_stream_id = 0;
-    HttpCommon::H2BodyState h2_body_state[2] = { HttpCommon::H2_BODY_NOT_COMPLETE,
-        HttpCommon::H2_BODY_NOT_COMPLETE };
+    // *** HTTP/X handling
+    bool for_httpx = false;
+    int64_t hx_stream_id = -1;
+    HttpCommon::HXBodyState hx_body_state[2] = { HttpCommon::HX_BODY_NOT_COMPLETE,
+        HttpCommon::HX_BODY_NOT_COMPLETE };
 
 #ifdef REG_TEST
     static uint64_t instance_count;
@@ -233,5 +235,13 @@ private:
 #endif
 };
 
+class HttpFlowStreamIntf : public snort::StreamFlowIntf
+{
+public:
+    snort::FlowData* get_stream_flow_data(const snort::Flow* flow) override;
+    void set_stream_flow_data(snort::Flow* flow, snort::FlowData* flow_data) override;
+    void get_stream_id(const snort::Flow* flow, int64_t& stream_id) override;
+};
+
 #endif
 
index 433525f11a83832403334beeb9226421f30ffbf0..66a9e47ff35c85d516d7e9f9df391f81a41e0e98 100755 (executable)
@@ -41,7 +41,7 @@
 #include "http_msg_body.h"
 #include "http_msg_body_chunk.h"
 #include "http_msg_body_cl.h"
-#include "http_msg_body_h2.h"
+#include "http_msg_body_hx.h"
 #include "http_msg_body_old.h"
 #include "http_msg_header.h"
 #include "http_msg_request.h"
@@ -358,17 +358,17 @@ HttpCommon::SectionType HttpInspect::get_type_expected(snort::Flow* flow, HttpCo
     return session_data->get_type_expected(source_id);
 }
 
-void HttpInspect::finish_h2_body(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::H2BodyState state,
+void HttpInspect::finish_hx_body(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::HXBodyState state,
     bool clear_partial_buffer) const
 {
     HttpFlowData* session_data = http_get_flow_data(flow);
-    session_data->finish_h2_body(source_id, state, clear_partial_buffer);
+    session_data->finish_hx_body(source_id, state, clear_partial_buffer);
 }
 
-void HttpInspect::set_h2_body_state(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::H2BodyState state) const
+void HttpInspect::set_hx_body_state(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::HXBodyState state) const
 {
     HttpFlowData* session_data = http_get_flow_data(flow);
-    session_data->set_h2_body_state(source_id, state);
+    session_data->set_hx_body_state(source_id, state);
 }
 
 bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b)
@@ -510,7 +510,7 @@ int HttpInspect::get_xtra_jsnorm(Flow* flow, uint8_t** buf, uint32_t* len, uint3
 void HttpInspect::disable_detection(Packet* p)
 {
     HttpFlowData* session_data = http_get_flow_data(p->flow);
-    if (!session_data->for_http2)
+    if (!session_data->for_httpx)
     {
         assert(p->context);
         DetectionEngine::disable_all(p);
@@ -519,27 +519,15 @@ void HttpInspect::disable_detection(Packet* p)
 
 HttpFlowData* HttpInspect::http_get_flow_data(const Flow* flow)
 {
-    Http2FlowData* h2i_flow_data = nullptr;
-    if (Http2FlowData::inspector_id != 0)
-        h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
-    if (h2i_flow_data == nullptr)
-        return (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
+    if (flow->stream_intf)
+        return (HttpFlowData*)flow->stream_intf->get_stream_flow_data(flow);
     else
-        return h2i_flow_data->get_hi_flow_data();
+        return nullptr;
 }
 
 void HttpInspect::http_set_flow_data(Flow* flow, HttpFlowData* flow_data)
 {
-    // for_http2 set in HttpFlowData constructor after checking for h2i_flow_data
-    if (!flow_data->for_http2)
-        flow->set_flow_data(flow_data);
-    else
-    {
-        Http2FlowData* h2i_flow_data =
-            (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
-        assert(h2i_flow_data);
-        h2i_flow_data->set_hi_flow_data(flow_data);
-    }
+    flow->stream_intf->set_stream_flow_data(flow, flow_data);
 }
 
 void HttpInspect::eval(Packet* p)
@@ -573,7 +561,7 @@ void HttpInspect::eval(Packet* p, SourceId source_id, const uint8_t* data, uint1
         return;
     }
 
-    if (!session_data->for_http2)
+    if (!session_data->for_httpx)
         HttpModule::increment_peg_counts(PEG_TOTAL_BYTES, dsize);
 
     session_data->octets_reassembled[source_id] = STAT_NOT_PRESENT;
@@ -598,7 +586,7 @@ void HttpInspect::eval(Packet* p, SourceId source_id, const uint8_t* data, uint1
     process(data, dsize, p->flow, source_id, true, p);
 
     // Detection was done in process()
-    if (!session_data->for_http2)
+    if (!session_data->for_httpx)
         disable_detection(p);
 
     // If current transaction is complete then we are done with it. This is strictly a memory
@@ -655,8 +643,8 @@ void HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const
         current_section = new HttpMsgBodyChunk(
             data, dsize, session_data, source_id, buf_owner, flow, params);
         break;
-    case SEC_BODY_H2:
-        current_section = new HttpMsgBodyH2(
+    case SEC_BODY_HX:
+        current_section = new HttpMsgBodyHX(
             data, dsize, session_data, source_id, buf_owner, flow, params);
         break;
     case SEC_TRAILER:
index 93790e178a9ff244c8cf3cc8e0e329f40d7aac15..4835c00e7cd00f82f11b0990c0321d0e01240787 100644 (file)
@@ -57,15 +57,15 @@ public:
     HttpEnums::VersionId http_get_version_id(snort::Packet* p,
         const HttpBufferInfo& buffer_info) const;
     HttpCommon::SectionType get_type_expected(snort::Flow* flow, HttpCommon::SourceId source_id) const override;
-    void finish_h2_body(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::H2BodyState state,
+    void finish_hx_body(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::HXBodyState state,
         bool clear_partial_buffer) const override;
-    void set_h2_body_state(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::H2BodyState state) const override;
+    void set_hx_body_state(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::HXBodyState state) const override;
     bool get_fp_buf(snort::InspectionBuffer::Type ibt, snort::Packet* p,
         snort::InspectionBuffer& b) override;
     bool configure(snort::SnortConfig*) override;
     void show(const snort::SnortConfig*) const override;
     void eval(snort::Packet* p) override;
-    void eval(snort::Packet* p, HttpCommon::SourceId source_id, const uint8_t* data, uint16_t dsize);
+    void eval(snort::Packet* p, HttpCommon::SourceId source_id, const uint8_t* data, uint16_t dsize) override;
     void clear(snort::Packet* p) override;
 
     HttpStreamSplitter* get_splitter(bool is_client_to_server) override
index 1c853f6e30a9fb249a5092486860127ca155a5c6..202765142ecc2acb62e9551877ca863446018f0c 100644 (file)
@@ -30,11 +30,14 @@ class SO_PUBLIC HttpInspectBase : public snort::Inspector
 {
 public:
     virtual ~HttpInspectBase() override = default;
-    
+
     virtual HttpCommon::SectionType get_type_expected(snort::Flow* flow, HttpCommon::SourceId source_id) const = 0;
-    virtual void finish_h2_body(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::H2BodyState state,
+    virtual void finish_hx_body(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::HXBodyState state,
         bool clear_partial_buffer) const = 0;
-    virtual void set_h2_body_state(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::H2BodyState state) const = 0;
+    virtual void set_hx_body_state(snort::Flow* flow, HttpCommon::SourceId source_id, HttpCommon::HXBodyState state) const = 0;
+    virtual void eval(snort::Packet* p, HttpCommon::SourceId source_id, const uint8_t* data, uint16_t dsize) = 0;
+private:
+     using snort::Inspector::eval;
 };
 
 #endif
similarity index 78%
rename from src/service_inspectors/http_inspect/http_msg_body_h2.cc
rename to src/service_inspectors/http_inspect/http_msg_body_hx.cc
index 0a601958be133c6e463eb55f27bd46eff2635bf6..fd00c4cfcdaa00e7287533536441ea4fcec64d38 100644 (file)
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
-// http_msg_body_h2.cc author Katura Harvey <katharve@cisco.com>
+// http_msg_body_hx.cc author Katura Harvey <katharve@cisco.com>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "http_msg_body_h2.h"
+#include "http_msg_body_hx.h"
 
 using namespace HttpCommon;
 
-void HttpMsgBodyH2::update_flow()
+void HttpMsgBodyHX::update_flow()
 {
     session_data->body_octets[source_id] = body_octets;
-    if (session_data->h2_body_state[source_id] == H2_BODY_NOT_COMPLETE ||
-        session_data->h2_body_state[source_id] == H2_BODY_LAST_SEG)
+    if (session_data->hx_body_state[source_id] == HX_BODY_NOT_COMPLETE ||
+        session_data->hx_body_state[source_id] == HX_BODY_LAST_SEG)
         update_depth();
-    else if (session_data->h2_body_state[source_id] == H2_BODY_COMPLETE_EXPECT_TRAILERS)
+    else if (session_data->hx_body_state[source_id] == HX_BODY_COMPLETE_EXPECT_TRAILERS)
         session_data->trailer_prep(source_id);
 }
 
 #ifdef REG_TEST
-void HttpMsgBodyH2::print_section(FILE* output)
+void HttpMsgBodyHX::print_section(FILE* output)
 {
     print_body_section(output, "HTTP/2 body");
 }
similarity index 86%
rename from src/service_inspectors/http_inspect/http_msg_body_h2.h
rename to src/service_inspectors/http_inspect/http_msg_body_hx.h
index 9617382da9ff72ddbc3de957e70e856930eaaed0..58b777e2db3605f9e438b8724fb514a30fac41ec 100644 (file)
 // with this program; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
-// http_msg_body_h2.h author Katura Harvey <katharve@cisco.com>
+// http_msg_body_hx.h author Katura Harvey <katharve@cisco.com>
 
-#ifndef HTTP_MSG_BODY_H2_H
-#define HTTP_MSG_BODY_H2_H
+#ifndef HTTP_MSG_BODY_HX_H
+#define HTTP_MSG_BODY_HX_H
 
 #include "http_common.h"
 #include "http_msg_body.h"
 
 //-------------------------------------------------------------------------
-// HttpMsgBodyH2 class
+// HttpMsgBodyHX class
 //-------------------------------------------------------------------------
 
-class HttpMsgBodyH2 : public HttpMsgBody
+class HttpMsgBodyHX : public HttpMsgBody
 {
 public:
-    HttpMsgBodyH2(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
+    HttpMsgBodyHX(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
         HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
         const HttpParaList* params_)
         : HttpMsgBody(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_) {}
index eadaf2a2d7fc860858156e7479b3d4a6353ff79c..b3a68f2ce3faf0885a18119c82e7e73ffa1d130c 100755 (executable)
@@ -58,9 +58,9 @@ HttpMsgHeader::HttpMsgHeader(const uint8_t* buffer, const uint16_t buf_size,
 
 void HttpMsgHeader::publish()
 {
-    const uint32_t stream_id = session_data->get_h2_stream_id();
+    const int64_t stream_id = session_data->get_hx_stream_id();
 
-    HttpEvent http_header_event(this, session_data->for_http2, stream_id);
+    HttpEvent http_header_event(this, session_data->for_httpx, stream_id);
 
     const char* key = (source_id == SRC_CLIENT) ?
         HTTP_REQUEST_HEADER_EVENT_KEY : HTTP_RESPONSE_HEADER_EVENT_KEY;
@@ -164,7 +164,7 @@ int32_t HttpMsgHeader::get_num_cookies()
 void HttpMsgHeader::gen_events()
 {
     if ((get_header_count(HEAD_CONTENT_LENGTH) > 0) &&
-        (get_header_count(HEAD_TRANSFER_ENCODING) > 0) && !session_data->for_http2)
+        (get_header_count(HEAD_TRANSFER_ENCODING) > 0) && !session_data->for_httpx)
     {
         add_infraction(INF_BOTH_CL_AND_TE);
         create_event(EVENT_BOTH_CL_AND_TE);
@@ -210,7 +210,7 @@ void HttpMsgHeader::gen_events()
         {
             const int32_t upgrade = get_code_from_token_list(up_header.start(), up_header.length(),
                 consumed, upgrade_list);
-            if ((upgrade == UP_H2C) || (upgrade == UP_H2) || (upgrade == UP_HTTP20))
+            if ((upgrade == UP_H2C) || (upgrade == UP_H2) || (upgrade == UP_HTTP20)) //FIXIT-E: Handle upgrade for h3
             {
                 add_infraction(INF_UPGRADE_HEADER_HTTP2);
                 if (source_id == SRC_CLIENT)
@@ -243,7 +243,7 @@ void HttpMsgHeader::update_flow()
     }
 
     if ((source_id == SRC_SERVER) && request && (request->get_method_id() == METH_CONNECT) &&
-        !session_data->for_http2)
+        !session_data->for_httpx)
     {
         // Successful CONNECT responses (2XX) switch to tunneled traffic immediately following the
         // header. Transfer-Encoding and Content-Length headers are not allowed in successful
@@ -325,7 +325,7 @@ void HttpMsgHeader::update_flow()
 
     const Field& te_header = get_header_value_norm(HEAD_TRANSFER_ENCODING);
 
-    if (session_data->for_http2)
+    if (session_data->for_httpx)
     {
         // The only transfer-encoding header we should see for HTTP/2 traffic is "identity"
         if (te_header.length() > 0)
@@ -350,11 +350,11 @@ void HttpMsgHeader::update_flow()
                 create_event(EVENT_BAD_CONTENT_LENGTH);
             }
         }
-        if (session_data->h2_body_state[source_id] == H2_BODY_NO_BODY)
+        if (session_data->hx_body_state[source_id] == HX_BODY_NO_BODY)
             session_data->half_reset(source_id);
         else
         {
-            session_data->type_expected[source_id] = SEC_BODY_H2;
+            session_data->type_expected[source_id] = SEC_BODY_HX;
             prepare_body();
         }
         return;
@@ -485,7 +485,7 @@ void HttpMsgHeader::prepare_body()
         // body
         session_data->detect_depth_remaining[source_id] = INT64_MAX;
     }
-    if ((source_id == SRC_CLIENT) and params->publish_request_body and session_data->for_http2)
+    if ((source_id == SRC_CLIENT) and params->publish_request_body and session_data->for_httpx)
     {
         session_data->publish_octets[source_id] = 0;
         session_data->publish_depth_remaining[source_id] = REQUEST_PUBLISH_DEPTH;
@@ -504,7 +504,7 @@ void HttpMsgHeader::prepare_body()
         HttpModule::increment_peg_counts(PEG_REQUEST_BODY);
 
         // Message bodies for CONNECT requests have no defined semantics
-        if ((method_id == METH_CONNECT) && !session_data->for_http2)
+        if ((method_id == METH_CONNECT) && !session_data->for_httpx)
         {
             add_infraction(INF_CONNECT_REQUEST_BODY);
             create_event(EVENT_CONNECT_REQUEST_BODY);
@@ -523,7 +523,7 @@ void HttpMsgHeader::setup_mime()
             if (boundary_present(content_type))
             {
                 // Generate the unique file id for multi file processing
-                set_multi_file_processing_id(get_transaction_id(), session_data->get_h2_stream_id());
+                set_multi_file_processing_id(get_transaction_id(), session_data->get_hx_stream_id());
 
                 Packet* p = DetectionEngine::get_current_packet();
                 const Field& uri = request->get_uri_norm_classic();
@@ -565,7 +565,7 @@ void HttpMsgHeader::setup_file_processing()
     }
 
     // Generate the unique file id for multi file processing
-    set_multi_file_processing_id(get_transaction_id(), session_data->get_h2_stream_id());
+    set_multi_file_processing_id(get_transaction_id(), session_data->get_hx_stream_id());
 
     session_data->file_depth_remaining[source_id] = max_file_depth;
     FileFlows* file_flows = FileFlows::get_file_flows(flow);
index f9bf322ba2c7a6fd6ed538408776d9af6afa1f48..5eb13bcbab4fd9e77c57f03704dfe03862ca3e1d 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "http_msg_start.h"
 
+#include "service_inspectors/http2_inspect/http2_flow_data.h"
+
 #include "http_enum.h"
 
 using namespace HttpEnums;
@@ -52,8 +54,13 @@ void HttpMsgStart::derive_version_id()
     }
     else if ((version.start()[5] == '1') && (version.start()[7] == '1'))
     {
-        if (session_data->for_http2)
-            version_id = VERS_2_0;
+        if (session_data->for_httpx)
+        {
+            const Http2FlowData* const h2i_flow_data =
+                (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
+
+            version_id = (h2i_flow_data) ? VERS_2_0 : VERS_3_0;
+        }
         else
             version_id = VERS_1_1;
     }
index ffa690d1b5325ec6d2e781dcc08ee9d5e3de1aff..7f66db3da481f1d8f785cb52ef82d9d18a1e71e0 100644 (file)
@@ -39,7 +39,7 @@ public:
         source_id(is_client_to_server ? HttpCommon::SRC_CLIENT : HttpCommon::SRC_SERVER) {}
     Status scan(snort::Packet* pkt, const uint8_t* data, uint32_t length, uint32_t not_used,
         uint32_t* flush_offset) override;
-    Status scan(snort::Flow* flow, const uint8_t* data, uint32_t length, uint32_t* flush_offset);
+    Status scan(snort::Flow* flow, const uint8_t* data, uint32_t length, uint32_t* flush_offset) override;
     const snort::StreamBuffer reassemble(snort::Flow* flow, unsigned total, unsigned, const
         uint8_t* data, unsigned len, uint32_t flags, unsigned& copied) override;
     bool finish(snort::Flow* flow) override;
index 65b98fb1bf4dd8a82570ab849eed23e49663c79d..fe10a451ab875c5e982a79ed6bb65482323b204b 100644 (file)
@@ -29,9 +29,12 @@ public:
     virtual ~HttpStreamSplitterBase() override = default;
 
     virtual void prep_partial_flush(snort::Flow* flow, uint32_t num_flush) = 0;
-    
+
+    virtual Status scan(snort::Flow* flow, const uint8_t* data, uint32_t length, uint32_t* flush_offset) = 0;
 protected:
     HttpStreamSplitterBase(bool c2s) : StreamSplitter(c2s) { }
+private:
+    using snort::StreamSplitter::scan;
 };
 
 #endif
index 605003371d843623986284c98f7cc2bbd9d2bbde..b1c0eb023c97940cfc8ff9640257a2b88ca8fa2f 100644 (file)
@@ -154,7 +154,7 @@ void HttpStreamSplitter::process_gzip_header(const uint8_t* data,
             (magic_length - header_bytes_processed) : length;
 
         if (memcmp(data, gzip_magic + header_bytes_processed, magic_cmp_len))
-            session_data->gzip_state[source_id] = GZIP_MAGIC_BAD; 
+            session_data->gzip_state[source_id] = GZIP_MAGIC_BAD;
         else if (header_bytes_processed + length >= magic_length)
             session_data->gzip_state[source_id] = GZIP_MAGIC_GOOD;
         header_bytes_processed += magic_cmp_len;
@@ -174,7 +174,7 @@ void HttpStreamSplitter::process_gzip_header(const uint8_t* data,
 }
 
 bool HttpStreamSplitter::gzip_header_check_done(HttpFlowData* session_data) const
-{ 
+{
     return session_data->gzip_state[source_id] == HttpEnums::GZIP_MAGIC_BAD or
         session_data->gzip_state[source_id] == HttpEnums::GZIP_FLAGS_PROCESSED;
 }
@@ -348,7 +348,7 @@ const StreamBuffer HttpStreamSplitter::reassemble(Flow* flow, unsigned total,
     if ((session_data->section_offset[source_id] == 0) &&
         (session_data->octets_expected[source_id] != partial_raw_bytes + total))
     {
-        assert(!session_data->for_http2);
+        assert(!session_data->for_httpx);
         assert(total == 0); // FIXIT-L this special exception for total of zero is needed for now
         session_data->type_expected[source_id] = SEC_ABORT;
         return { nullptr, 0 };
@@ -390,8 +390,8 @@ const StreamBuffer HttpStreamSplitter::reassemble(Flow* flow, unsigned total,
                     session_data->half_reset(source_id);
                 }
                 else if (session_data->type_expected[source_id] == SEC_BODY_CHUNK ||
-                        (session_data->type_expected[source_id] == SEC_BODY_H2 &&
-                        session_data->h2_body_state[source_id] == H2_BODY_COMPLETE_EXPECT_TRAILERS))
+                        (session_data->type_expected[source_id] == SEC_BODY_HX &&
+                        session_data->hx_body_state[source_id] == HX_BODY_COMPLETE_EXPECT_TRAILERS))
                 {
                     session_data->trailer_prep(source_id);
                 }
@@ -406,7 +406,7 @@ const StreamBuffer HttpStreamSplitter::reassemble(Flow* flow, unsigned total,
         (session_data->section_type[source_id] == SEC_BODY_CHUNK) ||
         (session_data->section_type[source_id] == SEC_BODY_CL) ||
         (session_data->section_type[source_id] == SEC_BODY_OLD) ||
-        (session_data->section_type[source_id] == SEC_BODY_H2);
+        (session_data->section_type[source_id] == SEC_BODY_HX);
 
     uint8_t*& buffer = session_data->section_buffer[source_id];
     if (buffer == nullptr)
index 71116ea9fddbf412123c5dbfca041ebb4f18d3d1..d790ff5ad87a5c7dcdc572c8a78e778889197e27 100644 (file)
@@ -92,8 +92,8 @@ HttpCutter* HttpStreamSplitter::get_cutter(SectionType type,
             session_data->accelerated_blocking[source_id],
             my_inspector->script_finder,
             session_data->compression[source_id]);
-    case SEC_BODY_H2:
-        return (HttpCutter*)new HttpBodyH2Cutter(
+    case SEC_BODY_HX:
+        return (HttpCutter*)new HttpBodyHXCutter(
             session_data->data_length[source_id],
             session_data->accelerated_blocking[source_id],
             my_inspector->script_finder,
@@ -140,7 +140,9 @@ StreamSplitter::Status HttpStreamSplitter::scan(Flow* flow, const uint8_t* data,
     // This is the session state information we share with HttpInspect and store with stream. A
     // session is defined by a TCP connection. Since scan() is the first to see a new TCP
     // connection the new flow data object is created here.
-    HttpFlowData* session_data = HttpInspect::http_get_flow_data(flow);
+    HttpFlowData* session_data = nullptr;
+    if (flow->stream_intf)
+        session_data = (HttpFlowData*)flow->stream_intf->get_stream_flow_data(flow);
 
     if (session_data == nullptr)
     {
@@ -201,7 +203,7 @@ StreamSplitter::Status HttpStreamSplitter::scan(Flow* flow, const uint8_t* data,
     // If the last request was a CONNECT and we have not yet seen the response, this is early C2S
     // traffic. If there has been a pipeline overflow or underflow we cannot match requests to
     // responses, so there is no attempt to track early C2S traffic.
-    if ((source_id == SRC_CLIENT) && (type == SEC_REQUEST) && !session_data->for_http2 &&
+    if ((source_id == SRC_CLIENT) && (type == SEC_REQUEST) && !session_data->for_httpx &&
         session_data->last_request_was_connect)
     {
         const uint64_t last_request_trans_num = session_data->expected_trans_num[SRC_CLIENT] - 1;
@@ -251,7 +253,7 @@ StreamSplitter::Status HttpStreamSplitter::scan(Flow* flow, const uint8_t* data,
         max_length, session_data->get_infractions(source_id), session_data->events[source_id],
         session_data->section_size_target[source_id],
         session_data->stretch_section_to_packet[source_id],
-        session_data->h2_body_state[source_id]);
+        session_data->hx_body_state[source_id]);
     switch (cut_result)
     {
     case SCAN_NOT_FOUND:
index 89aff19210d447bf6bc79703a8a5349dfe262a46..08c619bca7ad7f09603ed3a2f92269c8e9f8b4c8 100644 (file)
 #include <sys/types.h>
 #include <cstdio>
 
+#include <main/snort_types.h>
 //-------------------------------------------------------------------------
 // HttpTestManager class
 //-------------------------------------------------------------------------
 
 class HttpTestInput;
 
-class HttpTestManager
+class SO_PUBLIC HttpTestManager
 {
 public:
     // Bitmap: 1, 2, 4, 8, ...
-    enum INPUT_TYPE { IN_NONE = 0, IN_HTTP = 0x1, IN_HTTP2 = 0x2 };
+    enum INPUT_TYPE { IN_NONE = 0, IN_HTTP = 0x1, IN_HTTP2 = 0x2, IN_HTTP3 = 0x3 };
 
     static bool use_test_input(INPUT_TYPE type) { return (type & test_input) != 0; }
     static void activate_test_input(INPUT_TYPE type);
index a0e14a0f839d9b332ded5d4c2098de8d2c0d6bf8..609c14fd31efeb7cfc941a7100f609ad8bc338a7 100644 (file)
@@ -28,7 +28,6 @@
 #include "log/messages.h"
 #include "parser/parse_utils.h"
 #include "protocols/packet.h"
-#include "service_inspectors/http2_inspect/http2_flow_data.h"
 
 #include "http_common.h"
 #include "http_enum.h"
@@ -145,10 +144,11 @@ HttpInspect const* HttpIpsOption::eval_helper(Packet* p)
     if (!section_match)
         return nullptr;
 
-    const Http2FlowData* const h2i_flow_data =
-        (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
+    assert(p->flow->stream_intf);
+    const HttpFlowData* const hi_flow_data =
+        (HttpFlowData*)p->flow->stream_intf->get_stream_flow_data(p->flow);
 
-    const HttpInspect* const hi = (h2i_flow_data != nullptr) ?
+    const HttpInspect* const hi = (hi_flow_data->is_for_httpx()) ?
         (HttpInspect*)(p->flow->assistant_gadget) : (HttpInspect*)(p->flow->gadget);
 
     return hi;
index 23c9980f5bd3c1eeb9a474c96eb7cac850ec9bc7..cd7166b67ded861156c4e252cd8bc120886ea836 100644 (file)
@@ -55,6 +55,7 @@ static const std::map <std::string, VersionId> VersionStrToEnum =
     { "1.0", VERS_1_0 },
     { "1.1", VERS_1_1 },
     { "2.0", VERS_2_0 },
+    { "3.0", VERS_3_0 },
     { "0.9", VERS_0_9 }
 };
 
index 39890383860094f736591c604f6ec3f77236a9b1..86a24c9ea2dd85661c24e7cffb47c000c52edac8 100644 (file)
@@ -48,6 +48,9 @@ int DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
 fd_status_t File_Decomp_StopFree(fd_session_t*) { return File_Decomp_OK; }
 uint32_t str_to_hash(const uint8_t *, size_t) { return 0; }
 FlowData* Flow::get_flow_data(uint32_t) const { return nullptr; }
+int Flow::set_flow_data(FlowData*) { return 0;}
+Flow::Flow() { stream_intf = nullptr; }
+Flow::~Flow() = default;
 }
 
 unsigned Http2FlowData::inspector_id = 0;
@@ -66,13 +69,15 @@ public:
 
 TEST_GROUP(http_transaction_test)
 {
-    HttpFlowData* const flow_data = new HttpFlowData(nullptr);
+    Flow* const flow = new Flow();
+    HttpFlowData* const flow_data = new HttpFlowData(flow);
     SectionType* const section_type = HttpUnitTestSetup::get_section_type(flow_data);
     SectionType* const type_expected = HttpUnitTestSetup::get_type_expected(flow_data);
 
     void teardown() override
     {
         delete flow_data;
+        delete flow;
     }
 };
 
index 322a472ce6391200567413726292eacf1e91be4c..7c23d6917bf2789c3d9c07cfc7479dcf6c946b0b 100644 (file)
@@ -1,11 +1,17 @@
+set(UDP_STREAM_INCLUDES
+   stream_udp.h
+   udp_ha.h
+   udp_module.h
+   udp_session.h
+)
 
 add_library( stream_udp OBJECT
     stream_udp.cc
-    stream_udp.h
     udp_ha.cc
-    udp_ha.h
     udp_module.cc
-    udp_module.h
     udp_session.cc
-    udp_session.h
 )
+
+install(FILES ${UDP_STREAM_INCLUDES}
+    DESTINATION "${INCLUDE_INSTALL_PATH}/stream/udp"
+)
\ No newline at end of file
index 80611683e5a34950401e25014aefe6f8579d0e4a..7465caeb75f563a65220278503690a47fed949fe 100644 (file)
@@ -23,8 +23,9 @@
 #include <sys/time.h>
 
 #include "flow/session.h"
+#include "main/snort_types.h"
 
-class UdpSession : public Session
+class SO_PUBLIC UdpSession : public Session
 {
 public:
     UdpSession(snort::Flow*);