From: Shanmugam S (shanms) Date: Thu, 15 Sep 2022 07:32:50 +0000 (+0000) Subject: Pull request #3548: HTTP/3 inspector implementation support X-Git-Tag: 3.1.42.0~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e26358e980f1d2a8d38ee80ec36135d1003304ff;p=thirdparty%2Fsnort3.git Pull request #3548: HTTP/3 inspector implementation support Merge in SNORT/snort3 from ~ABHPAL/snort3:h3 to master Squashed commit of the following: commit 18d340b34fb619533c4a8d1722cd57f823d817ba Author: Abhijit Pal(abhpal) Date: Thu Aug 25 16:21:19 2022 +0530 parser: add implicit http3 to http ips options otn commit b38f067a20e4503d29916be966919fafee71d3c7 Author: Abhijit Pal(abhpal) Date: Thu Aug 25 16:20:14 2022 +0530 stream: export support for creating udp session commit 6f3f7109f8f3c8b0c3299a2aec7c58508a000840 Author: Abhijit Pal(abhpal) Date: Thu Aug 25 16:18:56 2022 +0530 detection: add http3 to http ips buffers commit 254ccfed242e89b5780407691c5b9fff69684be4 Author: Abhijit Pal(abhpal) 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) Date: Thu Jul 14 15:53:56 2022 +0530 pub_sub: handle httpx(2,3) traffic commit 9bf0c34a118bd4f3dba8052ee141be1a86eea237 Author: Abhijit Pal(abhpal) Date: Thu Jul 14 15:52:55 2022 +0530 payload_injector: accomodate httpx(2,3) stream id values commit 32e13e3f1f534f5632264e3e0d1d9f1f921c74b8 Author: Abhijit Pal(abhpal) Date: Thu Jul 14 15:52:06 2022 +0530 rna: handle httpx(2,3) traffic commit c3ad5f625c98a337d2bf5b51742075d1d5b07c23 Author: Abhijit Pal(abhpal) Date: Thu Jul 14 15:51:23 2022 +0530 appid: handle http event for httpx(2,3) traffic commit b7e9927040da7d01ebb3dbed0b256340a5bf4f94 Author: Abhijit Pal(abhpal) Date: Thu Jul 14 15:50:20 2022 +0530 http2_inspect: updated with abstracted httpx(2,3) flags commit d27580f9f0666ec765c90347a34ccad619effcb0 Author: Abhijit Pal(abhpal) Date: Thu Jul 14 15:48:46 2022 +0530 http_inspect: abstract inspection of httpx(2,3) --- diff --git a/src/detection/fp_utils.cc b/src/detection/fp_utils.cc index 33fdd8b8a..2a559ace0 100644 --- a/src/detection/fp_utils.cc +++ b/src/detection/fp_utils.cc @@ -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"); } } diff --git a/src/flow/CMakeLists.txt b/src/flow/CMakeLists.txt index 663832c55..1b3a448fc 100644 --- a/src/flow/CMakeLists.txt +++ b/src/flow/CMakeLists.txt @@ -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 ) diff --git a/src/flow/flow.h b/src/flow/flow.h index 710ffe28e..d4343be59 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -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; diff --git a/src/network_inspectors/appid/appid_http_event_handler.cc b/src/network_inspectors/appid/appid_http_event_handler.cc index 661f2eaf1..8e95f51a3 100644 --- a/src/network_inspectors/appid/appid_http_event_handler.cc +++ b/src/network_inspectors/appid/appid_http_event_handler.cc @@ -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); } diff --git a/src/network_inspectors/appid/appid_http_session.cc b/src/network_inspectors/appid/appid_http_session.cc index e358ece03..62c5e7fcb 100644 --- a/src/network_inspectors/appid/appid_http_session.cc +++ b/src/network_inspectors/appid/appid_http_session.cc @@ -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()); diff --git a/src/network_inspectors/appid/appid_http_session.h b/src/network_inspectors/appid/appid_http_session.h index 2697b5280..499883072 100644 --- a/src/network_inspectors/appid/appid_http_session.h +++ b/src/network_inspectors/appid/appid_http_session.h @@ -60,7 +60,7 @@ class AppIdHttpSession public: typedef std::pair 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; diff --git a/src/network_inspectors/appid/appid_session.cc b/src/network_inspectors/appid/appid_session.cc index 954e8dcde..1dab790e9 100644 --- a/src/network_inspectors/appid/appid_session.cc +++ b/src/network_inspectors/appid/appid_session.cc @@ -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()); diff --git a/src/network_inspectors/appid/appid_session.h b/src/network_inspectors/appid/appid_session.h index 592134819..76549a523 100644 --- a/src/network_inspectors/appid/appid_session.h +++ b/src/network_inspectors/appid/appid_session.h @@ -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; diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h b/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h index 184f5a8cd..c541685db 100644 --- a/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h +++ b/src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h @@ -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; diff --git a/src/network_inspectors/appid/test/appid_http_event_test.cc b/src/network_inspectors/appid/test/appid_http_event_test.cc index f9418a62d..d61c8b1ac 100644 --- a/src/network_inspectors/appid/test/appid_http_event_test.cc +++ b/src/network_inspectors/appid/test/appid_http_event_test.cc @@ -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; } diff --git a/src/network_inspectors/appid/test/appid_mock_http_session.h b/src/network_inspectors/appid/test/appid_mock_http_session.h index 27fef68ab..3fcdc047d 100644 --- a/src/network_inspectors/appid/test/appid_mock_http_session.h +++ b/src/network_inspectors/appid/test/appid_mock_http_session.h @@ -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; diff --git a/src/network_inspectors/appid/test/appid_mock_session.h b/src/network_inspectors/appid/test/appid_mock_session.h index 61a409834..3b1dcc0c6 100644 --- a/src/network_inspectors/appid/test/appid_mock_session.h +++ b/src/network_inspectors/appid/test/appid_mock_session.h @@ -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; diff --git a/src/network_inspectors/rna/rna_app_discovery.cc b/src/network_inspectors/rna/rna_app_discovery.cc index 1bee49eed..6245b9421 100644 --- a/src/network_inspectors/rna/rna_app_discovery.cc +++ b/src/network_inspectors/rna/rna_app_discovery.cc @@ -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(); diff --git a/src/parser/parse_conf.cc b/src/parser/parse_conf.cc index e8d860b50..c400c8312 100644 --- a/src/parser/parse_conf.cc +++ b/src/parser/parse_conf.cc @@ -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); diff --git a/src/payload_injector/payload_injector.h b/src/payload_injector/payload_injector.h index a60e07b6f..c93f76d60 100644 --- a/src/payload_injector/payload_injector.h +++ b/src/payload_injector/payload_injector.h @@ -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 diff --git a/src/pub_sub/appid_events.h b/src/pub_sub/appid_events.h index e2650de90..29a1dee42 100644 --- a/src/pub_sub/appid_events.h +++ b/src/pub_sub/appid_events.h @@ -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; }; diff --git a/src/pub_sub/http_events.cc b/src/pub_sub/http_events.cc index b796f8a31..db661a58c 100644 --- a/src/pub_sub/http_events.cc +++ b/src/pub_sub/http_events.cc @@ -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; } diff --git a/src/pub_sub/http_events.h b/src/pub_sub/http_events.h index 1ee9f0793..94ccc5917 100644 --- a/src/pub_sub/http_events.h +++ b/src/pub_sub/http_events.h @@ -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&); diff --git a/src/pub_sub/http_request_body_event.cc b/src/pub_sub/http_request_body_event.cc index ab9aeb55c..4cd4d743d 100644 --- a/src/pub_sub/http_request_body_event.cc +++ b/src/pub_sub/http_request_body_event.cc @@ -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(); } diff --git a/src/pub_sub/test/pub_sub_http_event_test.cc b/src/pub_sub/test/pub_sub_http_event_test.cc index f66625421..3ab47dc83 100644 --- a/src/pub_sub/test/pub_sub_http_event_test.cc +++ b/src/pub_sub/test/pub_sub_http_event_test.cc @@ -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) diff --git a/src/pub_sub/test/pub_sub_http_request_body_event_test.cc b/src/pub_sub/test/pub_sub_http_request_body_event_test.cc index 21770eb90..c27c8b4d6 100644 --- a/src/pub_sub/test/pub_sub_http_request_body_event_test.cc +++ b/src/pub_sub/test/pub_sub_http_request_body_event_test.cc @@ -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(); } diff --git a/src/service_inspectors/http2_inspect/CMakeLists.txt b/src/service_inspectors/http2_inspect/CMakeLists.txt index bb05cf9d5..d3cf4c993 100644 --- a/src/service_inspectors/http2_inspect/CMakeLists.txt +++ b/src/service_inspectors/http2_inspect/CMakeLists.txt @@ -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 ) diff --git a/src/service_inspectors/http2_inspect/http2_data_cutter.cc b/src/service_inspectors/http2_inspect/http2_data_cutter.cc index fc20430ce..0b68e060e 100644 --- a/src/service_inspectors/http2_inspect/http2_data_cutter.cc +++ b/src/service_inspectors/http2_inspect/http2_data_cutter.cc @@ -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); diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.cc b/src/service_inspectors/http2_inspect/http2_flow_data.cc index 6a6599eb9..73f08ea28 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.cc +++ b/src/service_inspectors/http2_inspect/http2_flow_data.cc @@ -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; +} diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.h b/src/service_inspectors/http2_inspect/http2_flow_data.h index 63b84b679..d975155be 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.h +++ b/src/service_inspectors/http2_inspect/http2_flow_data.h @@ -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 diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc b/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc index deff6a113..9fdebe30b 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc @@ -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); } diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc index 365f6d2f3..7a7c13c7e 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc @@ -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; diff --git a/src/service_inspectors/http2_inspect/http2_hpack_table.h b/src/service_inspectors/http2_inspect/http2_hpack_table.h index 648ba6d77..a5eaac3d7 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack_table.h +++ b/src/service_inspectors/http2_inspect/http2_hpack_table.h @@ -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]; diff --git a/src/service_inspectors/http2_inspect/http2_huffman_state_machine.h b/src/service_inspectors/http2_inspect/http2_huffman_state_machine.h index 5bf8909c6..7553d3047 100644 --- a/src/service_inspectors/http2_inspect/http2_huffman_state_machine.h +++ b/src/service_inspectors/http2_inspect/http2_huffman_state_machine.h @@ -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 diff --git a/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc b/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc index c21899b3c..0a1ccc5b3 100644 --- a/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc @@ -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); } diff --git a/src/service_inspectors/http2_inspect/http2_stream.cc b/src/service_inspectors/http2_inspect/http2_stream.cc index aea2b4b54..304ad8aa3 100644 --- a/src/service_inspectors/http2_inspect/http2_stream.cc +++ b/src/service_inspectors/http2_inspect/http2_stream.cc @@ -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( diff --git a/src/service_inspectors/http2_inspect/http2_stream_splitter.cc b/src/service_inspectors/http2_inspect/http2_stream_splitter.cc index 41bae3d32..2c9bd0f29 100644 --- a/src/service_inspectors/http2_inspect/http2_stream_splitter.cc +++ b/src/service_inspectors/http2_inspect/http2_stream_splitter.cc @@ -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]))) { diff --git a/src/service_inspectors/http2_inspect/http2_varlen_string_decode_impl.h b/src/service_inspectors/http2_inspect/http2_varlen_string_decode_impl.h index 64eb5b305..d5fb7e002 100644 --- a/src/service_inspectors/http2_inspect/http2_varlen_string_decode_impl.h +++ b/src/service_inspectors/http2_inspect/http2_varlen_string_decode_impl.h @@ -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" diff --git a/src/service_inspectors/http_inspect/CMakeLists.txt b/src/service_inspectors/http_inspect/CMakeLists.txt index 3ef0ac168..062c28339 100644 --- a/src/service_inspectors/http_inspect/CMakeLists.txt +++ b/src/service_inspectors/http_inspect/CMakeLists.txt @@ -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 diff --git a/src/service_inspectors/http_inspect/dev_notes.txt b/src/service_inspectors/http_inspect/dev_notes.txt index be626dbb3..ca4bed748 100755 --- a/src/service_inspectors/http_inspect/dev_notes.txt +++ b/src/service_inspectors/http_inspect/dev_notes.txt @@ -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 diff --git a/src/service_inspectors/http_inspect/http_common.h b/src/service_inspectors/http_inspect/http_common.h index 679a9ff79..170a788b0 100644 --- a/src/service_inspectors/http_inspect/http_common.h +++ b/src/service_inspectors/http_inspect/http_common.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_cutter.cc b/src/service_inspectors/http_inspect/http_cutter.cc index cab0d6c84..2a1f087d9 100644 --- a/src/service_inspectors/http_inspect/http_cutter.cc +++ b/src/service_inspectors/http_inspect/http_cutter.cc @@ -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) diff --git a/src/service_inspectors/http_inspect/http_cutter.h b/src/service_inspectors/http_inspect/http_cutter.h index 1edc8b70f..57bf254b6 100644 --- a/src/service_inspectors/http_inspect/http_cutter.h +++ b/src/service_inspectors/http_inspect/http_cutter.h @@ -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; diff --git a/src/service_inspectors/http_inspect/http_enum.h b/src/service_inspectors/http_inspect/http_enum.h index b4acfaec4..ffbdc80ec 100755 --- a/src/service_inspectors/http_inspect/http_enum.h +++ b/src/service_inspectors/http_inspect/http_enum.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_field.h b/src/service_inspectors/http_inspect/http_field.h index 1ba5d995f..19b17296b 100644 --- a/src/service_inspectors/http_inspect/http_field.h +++ b/src/service_inspectors/http_inspect/http_field.h @@ -24,13 +24,14 @@ #include #include +#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; diff --git a/src/service_inspectors/http_inspect/http_flow_data.cc b/src/service_inspectors/http_inspect/http_flow_data.cc index e44ab62d4..26ff9ba42 100644 --- a/src/service_inspectors/http_inspect/http_flow_data.cc +++ b/src/service_inspectors/http_inspect/http_flow_data.cc @@ -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 { diff --git a/src/service_inspectors/http_inspect/http_flow_data.h b/src/service_inspectors/http_inspect/http_flow_data.h index fa7b7c7cc..aa824c7a3 100644 --- a/src/service_inspectors/http_inspect/http_flow_data.h +++ b/src/service_inspectors/http_inspect/http_flow_data.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index 433525f11..66a9e47ff 100755 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -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: diff --git a/src/service_inspectors/http_inspect/http_inspect.h b/src/service_inspectors/http_inspect/http_inspect.h index 93790e178..4835c00e7 100644 --- a/src/service_inspectors/http_inspect/http_inspect.h +++ b/src/service_inspectors/http_inspect/http_inspect.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_inspect_base.h b/src/service_inspectors/http_inspect/http_inspect_base.h index 1c853f6e3..202765142 100644 --- a/src/service_inspectors/http_inspect/http_inspect_base.h +++ b/src/service_inspectors/http_inspect/http_inspect_base.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_msg_body_h2.cc b/src/service_inspectors/http_inspect/http_msg_body_hx.cc 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 0a601958b..fd00c4cfc 100644 --- a/src/service_inspectors/http_inspect/http_msg_body_h2.cc +++ b/src/service_inspectors/http_inspect/http_msg_body_hx.cc @@ -15,28 +15,28 @@ // 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 +// http_msg_body_hx.cc author Katura Harvey #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"); } diff --git a/src/service_inspectors/http_inspect/http_msg_body_h2.h b/src/service_inspectors/http_inspect/http_msg_body_hx.h 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 9617382da..58b777e2d 100644 --- a/src/service_inspectors/http_inspect/http_msg_body_h2.h +++ b/src/service_inspectors/http_inspect/http_msg_body_hx.h @@ -15,22 +15,22 @@ // 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 +// http_msg_body_hx.h author Katura Harvey -#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_) {} diff --git a/src/service_inspectors/http_inspect/http_msg_header.cc b/src/service_inspectors/http_inspect/http_msg_header.cc index eadaf2a2d..b3a68f2ce 100755 --- a/src/service_inspectors/http_inspect/http_msg_header.cc +++ b/src/service_inspectors/http_inspect/http_msg_header.cc @@ -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); diff --git a/src/service_inspectors/http_inspect/http_msg_start.cc b/src/service_inspectors/http_inspect/http_msg_start.cc index f9bf322ba..5eb13bcba 100644 --- a/src/service_inspectors/http_inspect/http_msg_start.cc +++ b/src/service_inspectors/http_inspect/http_msg_start.cc @@ -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; } diff --git a/src/service_inspectors/http_inspect/http_stream_splitter.h b/src/service_inspectors/http_inspect/http_stream_splitter.h index ffa690d1b..7f66db3da 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter.h +++ b/src/service_inspectors/http_inspect/http_stream_splitter.h @@ -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; diff --git a/src/service_inspectors/http_inspect/http_stream_splitter_base.h b/src/service_inspectors/http_inspect/http_stream_splitter_base.h index 65b98fb1b..fe10a451a 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter_base.h +++ b/src/service_inspectors/http_inspect/http_stream_splitter_base.h @@ -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 diff --git a/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc b/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc index 605003371..b1c0eb023 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc +++ b/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc @@ -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) diff --git a/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc b/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc index 71116ea9f..d790ff5ad 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc +++ b/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc @@ -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: diff --git a/src/service_inspectors/http_inspect/http_test_manager.h b/src/service_inspectors/http_inspect/http_test_manager.h index 89aff1921..08c619bca 100644 --- a/src/service_inspectors/http_inspect/http_test_manager.h +++ b/src/service_inspectors/http_inspect/http_test_manager.h @@ -25,17 +25,18 @@ #include #include +#include
//------------------------------------------------------------------------- // 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); diff --git a/src/service_inspectors/http_inspect/ips_http.cc b/src/service_inspectors/http_inspect/ips_http.cc index a0e14a0f8..609c14fd3 100644 --- a/src/service_inspectors/http_inspect/ips_http.cc +++ b/src/service_inspectors/http_inspect/ips_http.cc @@ -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; diff --git a/src/service_inspectors/http_inspect/ips_http_version.cc b/src/service_inspectors/http_inspect/ips_http_version.cc index 23c9980f5..cd7166b67 100644 --- a/src/service_inspectors/http_inspect/ips_http_version.cc +++ b/src/service_inspectors/http_inspect/ips_http_version.cc @@ -55,6 +55,7 @@ static const std::map 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 } }; diff --git a/src/service_inspectors/http_inspect/test/http_transaction_test.cc b/src/service_inspectors/http_inspect/test/http_transaction_test.cc index 398903838..86a24c9ea 100644 --- a/src/service_inspectors/http_inspect/test/http_transaction_test.cc +++ b/src/service_inspectors/http_inspect/test/http_transaction_test.cc @@ -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; } }; diff --git a/src/stream/udp/CMakeLists.txt b/src/stream/udp/CMakeLists.txt index 322a472ce..7c23d6917 100644 --- a/src/stream/udp/CMakeLists.txt +++ b/src/stream/udp/CMakeLists.txt @@ -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 diff --git a/src/stream/udp/udp_session.h b/src/stream/udp/udp_session.h index 80611683e..7465caeb7 100644 --- a/src/stream/udp/udp_session.h +++ b/src/stream/udp/udp_session.h @@ -23,8 +23,9 @@ #include #include "flow/session.h" +#include "main/snort_types.h" -class UdpSession : public Session +class SO_PUBLIC UdpSession : public Session { public: UdpSession(snort::Flow*);