From: Tom Peters (thopeter) Date: Fri, 22 Jul 2022 18:20:21 +0000 (+0000) Subject: Pull request #3506: http_inspect directly calls detection X-Git-Tag: 3.1.38.0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=256e6d659e7d02b1db607d339074b18265eff398;p=thirdparty%2Fsnort3.git Pull request #3506: http_inspect directly calls detection Merge in SNORT/snort3 from ~THOPETER/snort3:nhttp164 to master Squashed commit of the following: commit 0b70bc4f11ef4639ef8fa5cd33bcfd9b0d80b57d Author: Tom Peters Date: Mon Jun 27 13:19:09 2022 -0400 http_inspect: directly call detection commit 792288626c150c068752c053d2de20d39845c74b Author: Tom Peters Date: Tue Jul 5 16:15:35 2022 -0400 http2_inspect: Interface to http_inspect now uses real reassembled packet --- diff --git a/src/service_inspectors/http2_inspect/http2_data_cutter.cc b/src/service_inspectors/http2_inspect/http2_data_cutter.cc index 89ff65ba2..fc20430ce 100644 --- a/src/service_inspectors/http2_inspect/http2_data_cutter.cc +++ b/src/service_inspectors/http2_inspect/http2_data_cutter.cc @@ -26,7 +26,6 @@ #include "service_inspectors/http_inspect/http_flow_data.h" #include "service_inspectors/http_inspect/http_stream_splitter.h" -#include "http2_dummy_packet.h" #include "http2_utils.h" using namespace snort; @@ -131,17 +130,14 @@ StreamSplitter::Status Http2DataCutter::scan(const uint8_t* data, uint32_t lengt if (cur_data > 0) { uint32_t http_flush_offset = 0; - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - uint32_t unused = 0; session_data->stream_in_hi = session_data->current_stream[source_id]; 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); } - scan_result = session_data->hi_ss[source_id]->scan(&dummy_pkt, data + cur_data_offset, - cur_data, unused, &http_flush_offset); + scan_result = session_data->hi_ss[source_id]->scan(session_data->flow, data + cur_data_offset, cur_data, + &http_flush_offset); session_data->stream_in_hi = NO_STREAM_ID; switch (scan_result) { diff --git a/src/service_inspectors/http2_inspect/http2_data_frame.cc b/src/service_inspectors/http2_inspect/http2_data_frame.cc index 57b55fe57..fa90b80a0 100644 --- a/src/service_inspectors/http2_inspect/http2_data_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_data_frame.cc @@ -27,7 +27,6 @@ #include "service_inspectors/http_inspect/http_inspect.h" #include "service_inspectors/http_inspect/http_stream_splitter.h" -#include "http2_dummy_packet.h" #include "http2_flow_data.h" #include "http2_module.h" @@ -48,25 +47,15 @@ bool Http2DataFrame::valid_sequence(Http2Enums::StreamState state) return (state == Http2Enums::STREAM_EXPECT_BODY) || (state == Http2Enums::STREAM_BODY); } -void Http2DataFrame::analyze_http1() +void Http2DataFrame::analyze_http1(Packet* p) { - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - dummy_pkt.packet_flags = (source_id == SRC_CLIENT) ? PKT_FROM_CLIENT : PKT_FROM_SERVER; - dummy_pkt.dsize = data_length; - dummy_pkt.data = data_buffer; - dummy_pkt.xtradata_mask = 0; // FIXIT-E no checks here - session_data->hi->eval(&dummy_pkt); - detection_required = dummy_pkt.is_detection_required(); - xtradata_mask = dummy_pkt.xtradata_mask; + session_data->hi->eval(p, source_id, data_buffer, data_length); } -void Http2DataFrame::clear() +void Http2DataFrame::clear(Packet* p) { - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - session_data->hi->clear(&dummy_pkt); + session_data->hi->clear(p); } void Http2DataFrame::update_stream_state() diff --git a/src/service_inspectors/http2_inspect/http2_data_frame.h b/src/service_inspectors/http2_inspect/http2_data_frame.h index c4dfd24c4..345e77eab 100644 --- a/src/service_inspectors/http2_inspect/http2_data_frame.h +++ b/src/service_inspectors/http2_inspect/http2_data_frame.h @@ -30,11 +30,10 @@ class Http2DataFrame : public Http2Frame public: ~Http2DataFrame() override = default; bool valid_sequence(Http2Enums::StreamState state) override; - void analyze_http1() override; - void clear() override; + void analyze_http1(snort::Packet*) override; + void clear(snort::Packet*) override; - uint32_t get_xtradata_mask() override { return xtradata_mask; } - bool is_detection_required() const override { return detection_required; } + bool is_detection_required() const override { return false; } void update_stream_state() override; friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*, @@ -52,7 +51,5 @@ private: const uint32_t data_length; const uint8_t* const data_buffer; - uint32_t xtradata_mask = 0; - bool detection_required = false; }; #endif diff --git a/src/service_inspectors/http2_inspect/http2_dummy_packet.h b/src/service_inspectors/http2_inspect/http2_dummy_packet.h deleted file mode 100644 index cafe3b0a6..000000000 --- a/src/service_inspectors/http2_inspect/http2_dummy_packet.h +++ /dev/null @@ -1,43 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2020-2022 Cisco and/or its affiliates. All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program; if not, write to the Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -//-------------------------------------------------------------------------- -// http2_dummy_packet.h author Katura Harvey - -/* - * The purpose of this Packet subclass is to enable H2I to take direction from http_inspect on - * whether or not to send a frame to detection. When http_inspect is processing normal HTTP/1.1 - * traffic it is dealing with a real packet that has a context, the field on which disable_all() - * is called to disable detection on that packet. With HTTP/2 traffic, http_inspect is processing a - * dummy packet that H2I created, which does not contain a context object. Rather than create an - * entire new context object when we really only need a bool, http_inspect checks if the flow is - * HTTP/2 and sets a bool instead of calling it's usual disable_all(). H2I checks the bool and can - * then call disable_all() on the real packet. - */ - -#ifndef HTTP2_DUMMY_PACKET_H -#define HTTP2_DUMMY_PACKET_H - -#include "protocols/packet.h" - -class Http2DummyPacket : public snort::Packet -{ -public: - Http2DummyPacket() : snort::Packet(false) { } - bool is_detection_required() { return !disable_inspect; } -}; - -#endif diff --git a/src/service_inspectors/http2_inspect/http2_frame.h b/src/service_inspectors/http2_inspect/http2_frame.h index 7b4c60168..38991a07c 100644 --- a/src/service_inspectors/http2_inspect/http2_frame.h +++ b/src/service_inspectors/http2_inspect/http2_frame.h @@ -20,6 +20,7 @@ #ifndef HTTP2_FRAME_H #define HTTP2_FRAME_H +#include "protocols/packet.h" #include "service_inspectors/http_inspect/http_common.h" #include "service_inspectors/http_inspect/http_field.h" @@ -44,10 +45,9 @@ public: const uint8_t* data_buffer, const uint32_t data_len, Http2FlowData* session_data, HttpCommon::SourceId source_id, Http2Stream* stream); virtual bool valid_sequence(Http2Enums::StreamState) { return true; } - virtual void analyze_http1() { } - virtual void clear() { } + virtual void analyze_http1(snort::Packet*) { } + virtual void clear(snort::Packet*) { } virtual const Field& get_buf(unsigned id); - virtual uint32_t get_xtradata_mask() { return 0; } virtual bool is_detection_required() const { return true; } virtual void update_stream_state() { } diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame.cc b/src/service_inspectors/http2_inspect/http2_headers_frame.cc index 239e44633..bbcac2567 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame.cc @@ -28,7 +28,6 @@ #include "service_inspectors/http_inspect/http_inspect.h" #include "service_inspectors/http_inspect/http_stream_splitter.h" -#include "http2_dummy_packet.h" #include "http2_enum.h" #include "http2_flow_data.h" #include "http2_hpack.h" @@ -57,13 +56,11 @@ bool Http2HeadersFrame::in_error_state() const return stream->get_state(source_id) == STREAM_ERROR; } -void Http2HeadersFrame::clear() +void Http2HeadersFrame::clear(Packet* p) { if (session_data->abort_flow[source_id] || in_error_state()) return; - Packet dummy_pkt(false); - dummy_pkt.flow = session_data->flow; - session_data->hi->clear(&dummy_pkt); + session_data->hi->clear(p); } bool Http2HeadersFrame::decode_headers(Http2StartLine* start_line_generator, bool trailers) @@ -87,7 +84,7 @@ bool Http2HeadersFrame::decode_headers(Http2StartLine* start_line_generator, boo return true; } -void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceId hi_source_id) +void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceId hi_source_id, Packet* p) { if (session_data->abort_flow[source_id] or http1_header.length() < 0) return; @@ -110,12 +107,9 @@ void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceI if (http1_header.length() > 0) { uint32_t flush_offset; - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - const uint32_t unused = 0; const StreamSplitter::Status header_scan_result = - session_data->hi_ss[hi_source_id]->scan(&dummy_pkt, http1_header.start(), - http1_header.length(), unused, &flush_offset); + session_data->hi_ss[hi_source_id]->scan(session_data->flow, http1_header.start(), http1_header.length(), + &flush_offset); assert((session_data->is_processing_partial_header() and (header_scan_result == StreamSplitter::SEARCH)) or ((!session_data->is_processing_partial_header() and @@ -145,20 +139,13 @@ void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceI // http_inspect eval() of headers { - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - dummy_pkt.packet_flags = (hi_source_id == SRC_CLIENT) ? PKT_FROM_CLIENT : PKT_FROM_SERVER; - dummy_pkt.dsize = stream_buf.length; - dummy_pkt.data = stream_buf.data; - dummy_pkt.xtradata_mask = 0; - session_data->hi->eval(&dummy_pkt); + session_data->hi->eval(p, hi_source_id, stream_buf.data, stream_buf.length); + if (http_flow->get_type_expected(hi_source_id) == SEC_ABORT) { assert(session_data->is_processing_partial_header()); stream->set_state(hi_source_id, STREAM_ERROR); } - detection_required = dummy_pkt.is_detection_required(); - xtradata_mask = dummy_pkt.xtradata_mask; } } diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame.h b/src/service_inspectors/http2_inspect/http2_headers_frame.h index 9e3ea1262..22451b872 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame.h +++ b/src/service_inspectors/http2_inspect/http2_headers_frame.h @@ -32,11 +32,10 @@ class HttpFlowData; class Http2HeadersFrame : public Http2Frame { public: - void clear() override; + void clear(snort::Packet*) override; const Field& get_buf(unsigned id) override; - uint32_t get_xtradata_mask() override { return xtradata_mask; } - bool is_detection_required() const override { return detection_required; } + bool is_detection_required() const override { return false; } #ifdef REG_TEST void print_frame(FILE* output) override; @@ -47,13 +46,11 @@ protected: const uint8_t* data_buffer, const uint32_t data_len, Http2FlowData* ssn_data, HttpCommon::SourceId src_id, Http2Stream* stream); bool decode_headers(Http2StartLine* start_line_generator, bool trailers); - void process_decoded_headers(HttpFlowData* http_flow, HttpCommon::SourceId hi_source_id); + void process_decoded_headers(HttpFlowData* http_flow, HttpCommon::SourceId hi_source_id, snort::Packet* p); uint8_t get_flags_mask() const override; virtual bool in_error_state() const; Field http1_header; // finalized headers to be passed to http_inspect - uint32_t xtradata_mask = 0; - bool detection_required = false; Http2HpackDecoder* hpack_decoder; uint8_t hpack_headers_offset = 0; }; 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 41b823084..deff6a113 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc @@ -64,17 +64,17 @@ bool Http2HeadersFrameHeader::valid_sequence(Http2Enums::StreamState state) return (state == Http2Enums::STREAM_EXPECT_HEADERS); } -void Http2HeadersFrameHeader::analyze_http1() +void Http2HeadersFrameHeader::analyze_http1(Packet* p) { HttpFlowData* http_flow; - if (!process_start_line(http_flow, source_id)) + if (!process_start_line(http_flow, source_id, p)) return; // 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); - process_decoded_headers(http_flow, source_id); + process_decoded_headers(http_flow, source_id, p); } void Http2HeadersFrameHeader::update_stream_state() diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_header.h b/src/service_inspectors/http2_inspect/http2_headers_frame_header.h index 144ffe675..88f61a3f8 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_header.h +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_header.h @@ -32,7 +32,7 @@ public: const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream); bool valid_sequence(Http2Enums::StreamState state) override; - void analyze_http1() override; + void analyze_http1(snort::Packet*) override; void update_stream_state() override; #ifdef REG_TEST 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 7925e9861..365f6d2f3 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc @@ -28,7 +28,6 @@ #include "service_inspectors/http_inspect/http_inspect.h" #include "service_inspectors/http_inspect/http_stream_splitter.h" -#include "http2_dummy_packet.h" #include "http2_enum.h" #include "http2_flow_data.h" #include "http2_hpack.h" @@ -65,7 +64,7 @@ bool Http2HeadersFrameTrailer::valid_sequence(Http2Enums::StreamState state) return false; } -void Http2HeadersFrameTrailer::analyze_http1() +void Http2HeadersFrameTrailer::analyze_http1(Packet* p) { HttpFlowData* const http_flow = stream->get_hi_flow_data(); assert(http_flow); @@ -86,19 +85,14 @@ void Http2HeadersFrameTrailer::analyze_http1() if (stream_buf.data != nullptr) { - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - dummy_pkt.packet_flags = (source_id == SRC_CLIENT) ? PKT_FROM_CLIENT : PKT_FROM_SERVER; - dummy_pkt.dsize = stream_buf.length; - dummy_pkt.data = stream_buf.data; - session_data->hi->eval(&dummy_pkt); + session_data->hi->eval(p, source_id, stream_buf.data, stream_buf.length); assert (!valid_headers || http_flow->get_type_expected(source_id) == SEC_TRAILER); if (http_flow->get_type_expected(source_id) == SEC_ABORT) { stream->set_state(source_id, STREAM_ERROR); return; } - session_data->hi->clear(&dummy_pkt); + session_data->hi->clear(p); } } @@ -108,7 +102,7 @@ void Http2HeadersFrameTrailer::analyze_http1() return; } - process_decoded_headers(http_flow, source_id); + process_decoded_headers(http_flow, source_id, p); } void Http2HeadersFrameTrailer::update_stream_state() diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.h b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.h index 046a60e45..87970b9aa 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.h +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.h @@ -30,7 +30,7 @@ public: const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream); bool valid_sequence(Http2Enums::StreamState state) override; - void analyze_http1() override; + void analyze_http1(snort::Packet*) override; void update_stream_state() override; #ifdef REG_TEST diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc index 057ed1031..8ab841ea9 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc @@ -28,7 +28,6 @@ #include "service_inspectors/http_inspect/http_inspect.h" #include "service_inspectors/http_inspect/http_stream_splitter.h" -#include "http2_dummy_packet.h" #include "http2_enum.h" #include "http2_flow_data.h" #include "http2_hpack.h" @@ -47,8 +46,7 @@ Http2HeadersFrameWithStartline::~Http2HeadersFrameWithStartline() delete start_line_generator; } -bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow, - SourceId hi_source_id) +bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow, SourceId hi_source_id, Packet* p) { if (session_data->abort_flow[source_id]) return false; @@ -56,12 +54,9 @@ bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow // http_inspect scan() of start line { uint32_t flush_offset; - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - const uint32_t unused = 0; const StreamSplitter::Status start_scan_result = - session_data->hi_ss[hi_source_id]->scan(&dummy_pkt, start_line.start(), - start_line.length(), unused, &flush_offset); + session_data->hi_ss[hi_source_id]->scan(session_data->flow, start_line.start(), start_line.length(), + &flush_offset); if (start_scan_result != StreamSplitter::FLUSH) { stream->set_state(hi_source_id, STREAM_ERROR); @@ -86,18 +81,13 @@ bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow assert(http_flow); // http_inspect eval() and clear() of start line { - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; - dummy_pkt.packet_flags = (hi_source_id == SRC_CLIENT) ? PKT_FROM_CLIENT : PKT_FROM_SERVER; - dummy_pkt.dsize = stream_buf.length; - dummy_pkt.data = stream_buf.data; - session_data->hi->eval(&dummy_pkt); + session_data->hi->eval(p, hi_source_id, stream_buf.data, stream_buf.length); if (http_flow->get_type_expected(hi_source_id) != SEC_HEADER) { stream->set_state(hi_source_id, STREAM_ERROR); return false; } - session_data->hi->clear(&dummy_pkt); + session_data->hi->clear(p); } return true; } diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h index 07528b04b..fb02dd3eb 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h @@ -46,7 +46,7 @@ protected: HttpCommon::SourceId src_id, Http2Stream* stream_) : Http2HeadersFrame(header_buffer, header_len, data_buffer, data_len, ssn_data, src_id, stream_) { } - bool process_start_line(HttpFlowData*& http_flow, HttpCommon::SourceId hi_source_id); + bool process_start_line(HttpFlowData*& http_flow, HttpCommon::SourceId hi_source_id, snort::Packet* p); bool are_pseudo_headers_complete(); Http2StartLine* start_line_generator = nullptr; diff --git a/src/service_inspectors/http2_inspect/http2_inspect.cc b/src/service_inspectors/http2_inspect/http2_inspect.cc index 6243ad9f3..86556d4a9 100644 --- a/src/service_inspectors/http2_inspect/http2_inspect.cc +++ b/src/service_inspectors/http2_inspect/http2_inspect.cc @@ -83,7 +83,7 @@ bool Http2Inspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b) // Otherwise we can return buffers for raw packets because frame header is available before // frame is reassembled. - if (!session_data->frame_in_detection) + if (session_data->stream_in_hi == Http2Enums::NO_STREAM_ID) return false; Http2Stream* const stream = session_data->find_processing_stream(); @@ -151,11 +151,10 @@ void Http2Inspect::eval(Packet* p) uint8_t* const frame_header_copy = new uint8_t[FRAME_HEADER_LENGTH]; memcpy(frame_header_copy, session_data->lead_frame_header[source_id], FRAME_HEADER_LENGTH); stream->eval_frame(frame_header_copy, FRAME_HEADER_LENGTH, - session_data->frame_data[source_id], session_data->frame_data_size[source_id], source_id); + session_data->frame_data[source_id], session_data->frame_data_size[source_id], source_id, p); if (!stream->get_current_frame()->is_detection_required()) DetectionEngine::disable_all(p); - p->xtradata_mask |= stream->get_xtradata_mask(); // The current frame now owns these buffers, clear them from the flow data session_data->frame_data[source_id] = nullptr; @@ -199,7 +198,7 @@ void Http2Inspect::clear(Packet* p) Http2Stream* stream = session_data->find_processing_stream(); assert(stream != nullptr); - stream->clear_frame(); + stream->clear_frame(p); if (session_data->delete_stream) session_data->delete_processing_stream(); session_data->stream_in_hi = NO_STREAM_ID; 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 2083985cf..c21899b3c 100644 --- a/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc @@ -100,7 +100,7 @@ bool Http2PushPromiseFrame::valid_sequence(Http2Enums::StreamState) return true; } -void Http2PushPromiseFrame::analyze_http1() +void Http2PushPromiseFrame::analyze_http1(Packet* p) { if (!start_line_generator->generate_start_line(start_line, are_pseudo_headers_complete())) { @@ -111,14 +111,14 @@ void Http2PushPromiseFrame::analyze_http1() } HttpFlowData* http_flow; - if (!process_start_line(http_flow, SRC_CLIENT)) + if (!process_start_line(http_flow, SRC_CLIENT, p)) return; // 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); - process_decoded_headers(http_flow, SRC_CLIENT); + process_decoded_headers(http_flow, SRC_CLIENT, p); } void Http2PushPromiseFrame::update_stream_state() diff --git a/src/service_inspectors/http2_inspect/http2_push_promise_frame.h b/src/service_inspectors/http2_inspect/http2_push_promise_frame.h index 8a2e7da93..2c56f2974 100644 --- a/src/service_inspectors/http2_inspect/http2_push_promise_frame.h +++ b/src/service_inspectors/http2_inspect/http2_push_promise_frame.h @@ -41,7 +41,7 @@ class Http2PushPromiseFrame : public Http2HeadersFrameWithStartline { public: bool valid_sequence(Http2Enums::StreamState state) override; - void analyze_http1() override; + void analyze_http1(snort::Packet*) override; void update_stream_state() override; static uint32_t get_promised_stream_id(Http2EventGen* const events, Http2Infractions* const infractions, const uint8_t* data_buffer, uint32_t data_len); diff --git a/src/service_inspectors/http2_inspect/http2_stream.cc b/src/service_inspectors/http2_inspect/http2_stream.cc index cdbdbcf6f..aea2b4b54 100644 --- a/src/service_inspectors/http2_inspect/http2_stream.cc +++ b/src/service_inspectors/http2_inspect/http2_stream.cc @@ -28,9 +28,9 @@ #include "service_inspectors/http_inspect/http_stream_splitter.h" #include "http2_data_cutter.h" -#include "http2_dummy_packet.h" #include "http2_flow_data.h" +using namespace snort; using namespace HttpCommon; using namespace Http2Enums; @@ -47,7 +47,7 @@ Http2Stream::~Http2Stream() } void Http2Stream::eval_frame(const uint8_t* header_buffer, uint32_t header_len, - const uint8_t* data_buffer, uint32_t data_len, SourceId source_id) + const uint8_t* data_buffer, uint32_t data_len, SourceId source_id, Packet* p) { assert(current_frame == nullptr); current_frame = Http2Frame::new_frame(header_buffer, header_len, data_buffer, @@ -56,7 +56,7 @@ void Http2Stream::eval_frame(const uint8_t* header_buffer, uint32_t header_len, { if (current_frame->valid_sequence(state[source_id])) { - current_frame->analyze_http1(); + current_frame->analyze_http1(p); current_frame->update_stream_state(); } else @@ -80,10 +80,10 @@ void Http2Stream::check_and_cleanup_completed() } } -void Http2Stream::clear_frame() +void Http2Stream::clear_frame(Packet* p) { assert(current_frame != nullptr); - current_frame->clear(); + current_frame->clear(p); delete current_frame; current_frame = nullptr; @@ -130,17 +130,14 @@ void Http2Stream::finish_msg_body(HttpCommon::SourceId source_id, bool expect_tr bool clear_partial_buffer) { uint32_t http_flush_offset = 0; - Http2DummyPacket dummy_pkt; - dummy_pkt.flow = session_data->flow; 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); if (clear_partial_buffer) { - uint32_t unused = 0; - const snort::StreamSplitter::Status scan_result = session_data->hi_ss[source_id]->scan( - &dummy_pkt, nullptr, 0, unused, &http_flush_offset); - assert(scan_result == snort::StreamSplitter::FLUSH); + const StreamSplitter::Status scan_result = session_data->hi_ss[source_id]->scan( + session_data->flow, nullptr, 0, &http_flush_offset); + assert(scan_result == StreamSplitter::FLUSH); UNUSED(scan_result); } } diff --git a/src/service_inspectors/http2_inspect/http2_stream.h b/src/service_inspectors/http2_inspect/http2_stream.h index efea49d93..d9071b8a7 100644 --- a/src/service_inspectors/http2_inspect/http2_stream.h +++ b/src/service_inspectors/http2_inspect/http2_stream.h @@ -38,14 +38,12 @@ public: ~Http2Stream(); uint32_t get_stream_id() const { return stream_id; } void eval_frame(const uint8_t* header_buffer, uint32_t header_len, const uint8_t* data_buffer, - uint32_t data_len, HttpCommon::SourceId source_id); + uint32_t data_len, HttpCommon::SourceId source_id, snort::Packet* p); void check_and_cleanup_completed(); - void clear_frame(); + void clear_frame(snort::Packet* p); const Field& get_buf(unsigned id); HttpFlowData* get_hi_flow_data() const { return hi_flow_data; } void set_hi_flow_data(HttpFlowData* flow_data); - uint32_t get_xtradata_mask() { return (current_frame != nullptr) ? - current_frame->get_xtradata_mask() : 0; } Http2Frame *get_current_frame() { return current_frame; } void set_state(HttpCommon::SourceId source_id, Http2Enums::StreamState new_state); diff --git a/src/service_inspectors/http2_inspect/http2_utils.cc b/src/service_inspectors/http2_inspect/http2_utils.cc index bc414e592..cdec8eeb0 100644 --- a/src/service_inspectors/http2_inspect/http2_utils.cc +++ b/src/service_inspectors/http2_inspect/http2_utils.cc @@ -25,7 +25,6 @@ #include -#include "http2_dummy_packet.h" #include "http2_enum.h" using namespace Http2Enums; diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index 60048cdb5..805fb54a1 100755 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -29,7 +29,6 @@ #include "detection/detection_engine.h" #include "detection/detection_util.h" -#include "service_inspectors/http2_inspect/http2_dummy_packet.h" #include "service_inspectors/http2_inspect/http2_flow_data.h" #include "log/unified2.h" #include "protocols/packet.h" @@ -489,9 +488,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) - p->disable_inspect = true; - else + if (!session_data->for_http2) { assert(p->context); DetectionEngine::disable_all(p); @@ -525,9 +522,14 @@ void HttpInspect::http_set_flow_data(Flow* flow, HttpFlowData* flow_data) void HttpInspect::eval(Packet* p) { - Profile profile(HttpModule::get_profile_stats()); - const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER; + eval(p, source_id, p->data, p->dsize); + return; +} + +void HttpInspect::eval(Packet* p, SourceId source_id, const uint8_t* data, uint16_t dsize) +{ + Profile profile(HttpModule::get_profile_stats()); HttpFlowData* session_data = http_get_flow_data(p->flow); if (session_data == nullptr) @@ -540,17 +542,17 @@ void HttpInspect::eval(Packet* p) // use due to calls to HttpInspect::eval on the raw stream_user packet if ((session_data->section_type[source_id] == SEC__NOT_COMPUTE) || (session_data->type_expected[source_id] == SEC_ABORT) || - (session_data->octets_reassembled[source_id] != p->dsize)) + (session_data->octets_reassembled[source_id] != dsize)) { //assert(session_data->type_expected[source_id] != SEC_ABORT); //assert(session_data->section_type[source_id] != SEC__NOT_COMPUTE); - //assert(session_data->octets_reassembled[source_id] == p->dsize); + //assert(session_data->octets_reassembled[source_id] == dsize); session_data->type_expected[source_id] = SEC_ABORT; return; } if (!session_data->for_http2) - HttpModule::increment_peg_counts(PEG_TOTAL_BYTES, p->dsize); + HttpModule::increment_peg_counts(PEG_TOTAL_BYTES, dsize); session_data->octets_reassembled[source_id] = STAT_NOT_PRESENT; @@ -562,26 +564,18 @@ void HttpInspect::eval(Packet* p) } // Limit alt_dsize of message body sections to request/response depth + // p->dsize is not a typo. The actual value on the reassembled packet is what matters for this purpose. if ((session_data->detect_depth_remaining[source_id] > 0) && (session_data->detect_depth_remaining[source_id] < p->dsize)) { p->set_detect_limit(session_data->detect_depth_remaining[source_id]); } - if (!process(p->data, p->dsize, p->flow, source_id, true)) - disable_detection(p); + process(data, dsize, p->flow, source_id, true, p); -#ifdef REG_TEST - else - { - if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP)) - { - fprintf(HttpTestManager::get_output_file(), "Sent to detection %hu octets\n\n", - p->dsize); - fflush(HttpTestManager::get_output_file()); - } - } -#endif + // Detection was done in process() + if (!session_data->for_http2) + disable_detection(p); // If current transaction is complete then we are done with it. This is strictly a memory // optimization not necessary for correct operation. @@ -600,8 +594,8 @@ void HttpInspect::eval(Packet* p) SetExtraData(p, xtra_jsnorm_id); } -bool HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow, - SourceId source_id, bool buf_owner) const +void HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow, SourceId source_id, + bool buf_owner, Packet* p) const { HttpMsgSection* current_section; HttpFlowData* session_data = http_get_flow_data(flow); @@ -651,7 +645,7 @@ bool HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const { delete[] data; } - return false; + return; } current_section->analyze(); @@ -675,7 +669,17 @@ bool HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const #endif current_section->publish(); - return current_section->detection_required(); + if (current_section->run_detection(p)) + { +#ifdef REG_TEST + if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP)) + { + fprintf(HttpTestManager::get_output_file(), "Sent to detection %hu octets\n\n", + dsize); + fflush(HttpTestManager::get_output_file()); + } +#endif + } } void HttpInspect::clear(Packet* p) diff --git a/src/service_inspectors/http_inspect/http_inspect.h b/src/service_inspectors/http_inspect/http_inspect.h index 0865fe96d..f247a0682 100644 --- a/src/service_inspectors/http_inspect/http_inspect.h +++ b/src/service_inspectors/http_inspect/http_inspect.h @@ -63,6 +63,7 @@ public: 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 clear(snort::Packet* p) override; HttpStreamSplitter* get_splitter(bool is_client_to_server) override @@ -90,8 +91,8 @@ private: HttpStreamSplitter splitter[2] = { { true, this }, { false, this } }; - bool process(const uint8_t* data, const uint16_t dsize, snort::Flow* const flow, - HttpCommon::SourceId source_id_, bool buf_owner) const; + void process(const uint8_t* data, const uint16_t dsize, snort::Flow* const flow, + HttpCommon::SourceId source_id_, bool buf_owner, snort::Packet* p) const; static HttpFlowData* http_get_flow_data(const snort::Flow* flow); static void http_set_flow_data(snort::Flow* flow, HttpFlowData* flow_data); diff --git a/src/service_inspectors/http_inspect/http_msg_section.cc b/src/service_inspectors/http_inspect/http_msg_section.cc index 9743732af..73acad3ce 100644 --- a/src/service_inspectors/http_inspect/http_msg_section.cc +++ b/src/service_inspectors/http_inspect/http_msg_section.cc @@ -131,6 +131,14 @@ void HttpMsgSection::update_depth() const } } +bool HttpMsgSection::run_detection(snort::Packet* p) +{ + if ((p == nullptr) || !detection_required()) + return false; + DetectionEngine::detect(p); + return true; +} + const Field& HttpMsgSection::classic_normalize(const Field& raw, Field& norm, bool do_path, const HttpParaList::UriParam& uri_param) { diff --git a/src/service_inspectors/http_inspect/http_msg_section.h b/src/service_inspectors/http_inspect/http_msg_section.h index 5c59d32d4..8b1a6fcdd 100644 --- a/src/service_inspectors/http_inspect/http_msg_section.h +++ b/src/service_inspectors/http_inspect/http_msg_section.h @@ -22,6 +22,7 @@ #include "detection/detection_util.h" #include "framework/cursor.h" +#include "protocols/packet.h" #include "http_buffer_info.h" #include "http_common.h" @@ -67,6 +68,12 @@ public: // Manages the splitter and communication between message sections virtual void update_flow() = 0; + // Publish an inspection event for other modules to consume + virtual void publish() {} + + // Call the detection engine to inspect the current packet + bool run_detection(snort::Packet* p); + const Field& get_classic_buffer(unsigned id, uint64_t sub_id, uint64_t form); const Field& get_classic_buffer(const HttpBufferInfo& buf); const Field& get_param_buffer(Cursor& c, const HttpParam& param); @@ -75,9 +82,6 @@ public: int32_t get_status_code_num() const { return status_code_num; } - // Publish an inspection event for other modules to consume. - virtual void publish() { } - void clear(); bool is_clear() { return cleared; } diff --git a/src/service_inspectors/http_inspect/http_stream_splitter.h b/src/service_inspectors/http_inspect/http_stream_splitter.h index e64bde152..ffa690d1b 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter.h +++ b/src/service_inspectors/http_inspect/http_stream_splitter.h @@ -39,6 +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); 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_scan.cc b/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc index 3209cfaed..71116ea9f 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc +++ b/src/service_inspectors/http_inspect/http_stream_splitter_scan.cc @@ -24,6 +24,7 @@ #include "http_stream_splitter.h" #include "packet_io/active.h" +#include "protocols/packet.h" #include "http_common.h" #include "http_cutter.h" @@ -128,9 +129,13 @@ StreamSplitter::Status HttpStreamSplitter::status_value(StreamSplitter::Status r StreamSplitter::Status HttpStreamSplitter::scan(Packet* pkt, const uint8_t* data, uint32_t length, uint32_t, uint32_t* flush_offset) { - Profile profile(HttpModule::get_profile_stats()); + return scan(pkt->flow, data, length, flush_offset); +} - Flow* const flow = pkt->flow; +StreamSplitter::Status HttpStreamSplitter::scan(Flow* flow, const uint8_t* data, uint32_t length, + uint32_t* flush_offset) +{ + Profile profile(HttpModule::get_profile_stats()); // 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 @@ -231,7 +236,7 @@ StreamSplitter::Status HttpStreamSplitter::scan(Packet* pkt, const uint8_t* data session_data->status_code_num = 200; HttpModule::increment_peg_counts(PEG_RESPONSE); prepare_flush(session_data, nullptr, SEC_HEADER, 0, 0, 0, false, 0, 0); - my_inspector->process((const uint8_t*)"", 0, flow, SRC_SERVER, false); + my_inspector->process((const uint8_t*)"", 0, flow, SRC_SERVER, false, nullptr); session_data->transaction[SRC_SERVER]->clear_section(); }