static const int MAX_OCTETS = 63780;
static const int DATA_SECTION_SIZE = 16384;
static const int FRAME_HEADER_LENGTH = 9;
+static const uint32_t NO_STREAM_ID = 0xFFFFFFFF;
static const uint32_t HTTP2_GID = 121;
#include "http2_flow_data.h"
+#include "service_inspectors/http_inspect/http_inspect.h"
#include "service_inspectors/http_inspect/http_test_manager.h"
#include "http2_enum.h"
uint64_t Http2FlowData::instance_count = 0;
#endif
-Http2FlowData::Http2FlowData() : FlowData(inspector_id), stream(new Http2Stream(this))
+Http2FlowData::Http2FlowData(Flow* flow_) :
+ FlowData(inspector_id),
+ flow(flow_),
+ hi((HttpInspect*)(flow->assistant_gadget))
{
+ if (hi != nullptr)
+ {
+ hi_ss[SRC_CLIENT] = hi->get_splitter(true);
+ hi_ss[SRC_SERVER] = hi->get_splitter(false);
+ }
+
#ifdef REG_TEST
seq_num = ++instance_count;
if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP2) &&
{
delete infractions[k];
delete events[k];
+ delete hi_ss[k];
}
+}
+
+HttpFlowData* Http2FlowData::get_hi_flow_data() const
+{
+ assert(stream_in_hi != Http2Enums::NO_STREAM_ID);
+ Http2Stream* stream = get_hi_stream();
+ return stream->get_hi_flow_data();
+}
+
+void Http2FlowData::set_hi_flow_data(HttpFlowData* flow)
+{
+ assert(stream_in_hi != Http2Enums::NO_STREAM_ID);
+ Http2Stream* stream = get_hi_stream();
+ stream->set_hi_flow_data(flow);
+}
+
+HttpMsgSection* Http2FlowData::get_hi_msg_section() const
+{
+ Http2Stream* stream = get_hi_stream();
+ if (stream == nullptr)
+ return nullptr;
+ return stream->get_hi_msg_section();
+}
+
+void Http2FlowData::set_hi_msg_section(HttpMsgSection* section)
+{
+ assert(stream_in_hi != Http2Enums::NO_STREAM_ID);
+ Http2Stream* stream = get_hi_stream();
+ stream->set_hi_msg_section(section);
+}
- delete stream;
+class Http2Stream* Http2FlowData::find_stream(uint32_t key) const
+{
+ for (const StreamInfo& stream_info : streams)
+ {
+ if (stream_info.id == key)
+ return stream_info.stream;
+ }
+
+ return nullptr;
+}
+
+class Http2Stream* Http2FlowData::get_stream(uint32_t key)
+{
+ class Http2Stream* stream = find_stream(key);
+ if (!stream)
+ {
+ stream = new Http2Stream(key, this);
+ streams.emplace_front(key, stream);
+ }
+ return stream;
+}
+
+class Http2Stream* Http2FlowData::get_hi_stream() const
+{
+ return find_stream(stream_in_hi);
+}
+
+class Http2Stream* Http2FlowData::get_current_stream(const HttpCommon::SourceId source_id)
+{
+ return get_stream(current_stream[source_id]);
}
#include "http2_hpack_int_decode.h"
#include "http2_hpack_string_decode.h"
#include "http2_settings_frame.h"
+#include "http2_stream.h"
using Http2Infractions = Infractions<Http2Enums::INF__MAX_VALUE, Http2Enums::INF__NONE>;
using Http2EventGen = EventGen<Http2Enums::EVENT__MAX_VALUE, Http2Enums::EVENT__NONE,
Http2Enums::HTTP2_GID>;
+class HttpFlowData;
+class HttpMsgSection;
+class HttpInspect;
+class HttpStreamSplitter;
+
class Http2FlowData : public snort::FlowData
{
public:
- Http2FlowData();
+ Http2FlowData(snort::Flow* flow_);
~Http2FlowData() override;
static unsigned inspector_id;
static void init() { inspector_id = snort::FlowData::create_flow_data_id(); }
+ // Used by http_inspect to store its stuff
+ HttpFlowData* get_hi_flow_data() const;
+ void set_hi_flow_data(HttpFlowData* flow);
+ HttpMsgSection* get_hi_msg_section() const;
+ void set_hi_msg_section(HttpMsgSection* section);
+
friend class Http2Frame;
friend class Http2HeadersFrame;
friend class Http2Hpack;
size_t size_of() override
{ return sizeof(*this); }
+ // Stream access
+ class StreamInfo
+ {
+ public:
+ const uint32_t id;
+ class Http2Stream* stream;
+
+ StreamInfo(uint32_t _id, class Http2Stream* ptr) : id(_id), stream(ptr) { assert(ptr); }
+ ~StreamInfo() { delete stream; }
+ };
+ class Http2Stream* get_current_stream(const HttpCommon::SourceId source_id);
+
protected:
+ snort::Flow* flow;
+ HttpInspect* const hi;
+ HttpStreamSplitter* hi_ss[2] = { nullptr, nullptr };
+
// 0 element refers to client frame, 1 element refers to server frame
+ // Stream ID of the frame currently being read in and processed
+ uint32_t current_stream[2] = { Http2Enums::NO_STREAM_ID, Http2Enums::NO_STREAM_ID };
+ // At any given time there may be different streams going in each direction. But only one of
+ // them is the stream that http_inspect is actually processing at the moment.
+ uint32_t stream_in_hi = Http2Enums::NO_STREAM_ID;
+
// Reassemble() data to eval()
uint8_t* frame_header[2] = { nullptr, nullptr };
uint32_t frame_header_size[2] = { 0, 0 };
bool frame_in_detection = false;
Http2ConnectionSettings connection_settings[2];
Http2HpackDecoder hpack_decoder[2];
- class Http2Stream* stream;
+ std::list<class StreamInfo> streams;
// Internal to scan()
bool preface[2] = { true, false };
static uint64_t instance_count;
uint64_t seq_num;
#endif
+
+private:
+ class Http2Stream* find_stream(uint32_t key) const;
+ class Http2Stream* get_stream(uint32_t key);
+ class Http2Stream* get_hi_stream() const;
};
#endif
Http2Frame* Http2Frame::new_frame(const uint8_t* header, const int32_t header_len,
const uint8_t* data, const int32_t data_len, Http2FlowData* session_data, SourceId source_id)
{
- //FIXIT-H call the appropriate frame subclass constructor based on the type
+ // FIXIT-H call the appropriate frame subclass constructor based on the type
switch(session_data->frame_type[source_id])
{
case FT_HEADERS:
return new Http2HeadersFrame(header, header_len, data, data_len, session_data,
source_id);
- break;
case FT_SETTINGS:
return new Http2SettingsFrame(header, header_len, data, data_len, session_data,
source_id);
- break;
default:
return new Http2Frame(header, header_len, data, data_len, session_data, source_id);
- break;
}
}
static Http2Frame* new_frame(const uint8_t* header_buffer, const int32_t header_len,
const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
HttpCommon::SourceId source_id);
-
+ virtual void clear() { }
virtual const Field& get_buf(unsigned id);
#ifdef REG_TEST
virtual void print_frame(FILE* output);
#include "http2_headers_frame.h"
+#include "protocols/packet.h"
+
+#include "service_inspectors/http_inspect/http_inspect.h"
+#include "service_inspectors/http_inspect/http_stream_splitter.h"
+
#include "http2_enum.h"
#include "http2_flow_data.h"
#include "http2_hpack.h"
#include "http2_start_line.h"
+using namespace snort;
using namespace HttpCommon;
using namespace Http2Enums;
Http2HeadersFrame::Http2HeadersFrame(const uint8_t* header_buffer, const int32_t header_len,
- const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
- HttpCommon::SourceId src_id) : Http2Frame(header_buffer, header_len, data_buffer, data_len,
- ssn_data, src_id)
+ const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data_,
+ HttpCommon::SourceId source_id_) :
+ Http2Frame(header_buffer, header_len, data_buffer, data_len, session_data_, source_id_)
{
uint8_t hpack_headers_offset = 0;
hpack_headers_offset = 5;
// Set up the decoding context
- hpack_decoder = &session_data->hpack_decoder[source_id];
+ Http2HpackDecoder& hpack_decoder = session_data->hpack_decoder[source_id];
// Allocate stuff
decoded_headers = new uint8_t[MAX_OCTETS];
- decoded_headers_size = 0;
start_line_generator = Http2StartLine::new_start_line_generator(source_id,
session_data->events[source_id], session_data->infractions[source_id]);
// Decode headers
- if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
- hpack_headers_offset, decoded_headers, &decoded_headers_size, start_line_generator,
- session_data->events[source_id], session_data->infractions[source_id]))
+ if (!hpack_decoder.decode_headers((data.start() + hpack_headers_offset), data.length() -
+ hpack_headers_offset, decoded_headers,
+ start_line_generator, session_data->events[source_id],
+ session_data->infractions[source_id]))
{
session_data->frame_type[source_id] = FT__ABORT;
error_during_decode = true;
}
- start_line = hpack_decoder->get_start_line();
- http2_decoded_header = hpack_decoder->get_decoded_headers(decoded_headers);
+ start_line = hpack_decoder.get_start_line();
+ http1_header = hpack_decoder.get_decoded_headers(decoded_headers);
+
+ if ((error_during_decode) || (session_data->hi_ss[source_id] == nullptr))
+ return;
+
+ // http_inspect scan() of start line
+ session_data->stream_in_hi = session_data->current_stream[source_id];
+ {
+ uint32_t flush_offset;
+ Packet dummy_pkt(false);
+ dummy_pkt.flow = session_data->flow;
+ const uint32_t unused = 0;
+ const StreamSplitter::Status start_scan_result =
+ session_data->hi_ss[source_id]->scan(&dummy_pkt, start_line->start(),
+ start_line->length(), unused, &flush_offset);
+ assert(start_scan_result == StreamSplitter::FLUSH);
+ UNUSED(start_scan_result);
+ assert((int64_t)flush_offset == start_line->length());
+ }
+
+ StreamBuffer stream_buf;
+ // http_inspect reassemble() of start line
+ {
+ unsigned copied;
+ stream_buf = session_data->hi_ss[source_id]->reassemble(session_data->flow,
+ start_line->length(), 0, start_line->start(), start_line->length(), PKT_PDU_TAIL,
+ copied);
+ assert(stream_buf.data != nullptr);
+ assert(copied == (unsigned)start_line->length());
+ }
+
+ // http_inspect eval() and clear() of start line
+ {
+ Packet dummy_pkt(false);
+ 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->clear(&dummy_pkt);
+ }
+
+ // http_inspect scan() of headers
+ {
+ uint32_t flush_offset;
+ Packet dummy_pkt(false);
+ dummy_pkt.flow = session_data->flow;
+ const uint32_t unused = 0;
+ const StreamSplitter::Status header_scan_result =
+ session_data->hi_ss[source_id]->scan(&dummy_pkt, http1_header->start(),
+ http1_header->length(), unused, &flush_offset);
+ if (header_scan_result == StreamSplitter::ABORT)
+ {
+ // eval() aborted the start line?
+ hi_abort = true;
+ return;
+ }
+ assert(header_scan_result == StreamSplitter::FLUSH);
+ assert((int64_t)flush_offset == http1_header->length());
+ }
+
+ // http_inspect reassemble() of headers
+ {
+ unsigned copied;
+ stream_buf = session_data->hi_ss[source_id]->reassemble(session_data->flow,
+ http1_header->length(), 0, http1_header->start(), http1_header->length(), PKT_PDU_TAIL,
+ copied);
+ assert(stream_buf.data != nullptr);
+ assert(copied == (unsigned)http1_header->length());
+ }
+
+ // http_inspect eval() of headers
+ {
+ Packet dummy_pkt(false);
+ 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);
+ }
}
Http2HeadersFrame::~Http2HeadersFrame()
{
delete start_line;
delete start_line_generator;
- delete http2_decoded_header;
+ delete http1_header;
delete[] decoded_headers;
}
+void Http2HeadersFrame::clear()
+{
+ if (error_during_decode || hi_abort || (session_data->hi == nullptr))
+ return;
+ Packet dummy_pkt(false);
+ dummy_pkt.flow = session_data->flow;
+ session_data->hi->clear(&dummy_pkt);
+}
+
const Field& Http2HeadersFrame::get_buf(unsigned id)
{
switch (id)
{
+ // FIXIT-M need to add a buffer for the decoded start line
case HTTP2_BUFFER_DECODED_HEADER:
- return *http2_decoded_header;
+ return *http1_header;
default:
return Http2Frame::get_buf(id);
}
#ifdef REG_TEST
void Http2HeadersFrame::print_frame(FILE* output)
{
- fprintf(output, "\nHEADERS frame\n");
+ fprintf(output, "\nHeaders frame\n");
if (error_during_decode)
fprintf(output, "Error decoding headers.\n");
if (start_line)
start_line->print(output, "Decoded start-line");
- http2_decoded_header->print(output, "Decoded header");
+ http1_header->print(output, "Decoded header");
Http2Frame::print_frame(output);
}
#endif
{
public:
~Http2HeadersFrame() override;
+ void clear() override;
const Field& get_buf(unsigned id) override;
- friend Http2Frame* Http2Frame::new_frame(const uint8_t* header_buffer, const int32_t header_len,
- const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
- HttpCommon::SourceId source_id);
+ friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const int32_t, const uint8_t*,
+ const int32_t, Http2FlowData*, HttpCommon::SourceId);
#ifdef REG_TEST
void print_frame(FILE* output) override;
Http2StartLine* start_line_generator = nullptr;
uint8_t* decoded_headers = nullptr; // working buffer to store decoded headers
uint32_t decoded_headers_size = 0;
- const Field* http2_decoded_header = nullptr; // finalized headers to be passed to NHI
+ const Field* http1_header = nullptr; // finalized headers to be passed to NHI
const Field* start_line = nullptr;
bool error_during_decode = false;
- Http2HpackDecoder* hpack_decoder= nullptr;
+ bool hi_abort = false;
};
#endif
// not output the start line or decoded headers - this function must be followed by calls to
// get_start_line() and get_decoded_headers() to generate and obtain these fields.
bool Http2HpackDecoder::decode_headers(const uint8_t* encoded_headers,
- const uint32_t encoded_headers_length, uint8_t* decoded_headers, uint32_t* decoded_headers_len,
+ const uint32_t encoded_headers_length, uint8_t* decoded_headers,
Http2StartLine *start_line_generator, Http2EventGen* stream_events,
Http2Infractions* stream_infractions)
{
uint32_t line_bytes_written = 0;
bool success = true;
start_line = start_line_generator;
- decoded_headers_size = decoded_headers_len;
+ decoded_headers_size = 0;
events = stream_events;
infractions = stream_infractions;
pseudo_headers_fragment_size = 0;
{
success = decode_header_line(encoded_headers + total_bytes_consumed,
encoded_headers_length - total_bytes_consumed, line_bytes_consumed,
- decoded_headers + *decoded_headers_size, MAX_OCTETS - *decoded_headers_size,
+ decoded_headers + decoded_headers_size, MAX_OCTETS - decoded_headers_size,
line_bytes_written);
total_bytes_consumed += line_bytes_consumed;
- *decoded_headers_size += line_bytes_written;
+ decoded_headers_size += line_bytes_written;
}
// If there were only pseudo-headers, finalize never got called, so create the start-line
if (success)
{
success = write_decoded_headers((const uint8_t*)"\r\n", 2, decoded_headers +
- *decoded_headers_size, MAX_OCTETS - *decoded_headers_size, line_bytes_written);
- *decoded_headers_size += line_bytes_written;
+ decoded_headers_size, MAX_OCTETS - decoded_headers_size, line_bytes_written);
+ decoded_headers_size += line_bytes_written;
}
else
decode_error = true;
{
// Save the current position in the decoded buffer so we can set the pointer to the start
// of the regular headers
- pseudo_headers_fragment_size = *decoded_headers_size;
+ pseudo_headers_fragment_size = decoded_headers_size;
return start_line->finalize();
}
if (decode_error)
return new Field(STAT_NO_SOURCE);
else
- return new Field(*decoded_headers_size - pseudo_headers_fragment_size, decoded_headers +
+ return new Field(decoded_headers_size - pseudo_headers_fragment_size, decoded_headers +
pseudo_headers_fragment_size, false);
}
public:
Http2HpackDecoder() { }
bool decode_headers(const uint8_t* encoded_headers, const uint32_t encoded_headers_length,
- uint8_t* decoded_headers, uint32_t* decoded_headers_size, Http2StartLine* start_line,
+ uint8_t* decoded_headers, Http2StartLine* start_line,
Http2EventGen* stream_events, Http2Infractions* stream_infractions);
bool write_decoded_headers(const uint8_t* in_buffer, const uint32_t in_length,
uint8_t* decoded_header_buffer, uint32_t decoded_header_length, uint32_t& bytes_written);
private:
Http2StartLine* start_line = nullptr;
- uint32_t* decoded_headers_size;
+ uint32_t decoded_headers_size;
uint32_t pseudo_headers_fragment_size = 0;
bool decode_error = false;
Http2EventGen* events;
#endif
}
-bool Http2Inspect::configure(SnortConfig* )
+bool Http2Inspect::configure(SnortConfig*)
{
return true;
}
if (!session_data->frame_in_detection)
return false;
- const Field& buffer = session_data->stream->get_buf(id);
+ const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
+ Http2Stream* const stream = session_data->get_current_stream(source_id);
+ const Field& buffer = stream->get_buf(id);
if (buffer.length() <= 0)
return false;
if (session_data->frame_type[source_id] == FT__NONE)
return;
- session_data->stream->eval_frame(session_data->frame_header[source_id],
+ Http2Stream* stream = session_data->get_current_stream(source_id);
+
+ stream->eval_frame(session_data->frame_header[source_id],
session_data->frame_header_size[source_id], session_data->frame_data[source_id],
session_data->frame_data_size[source_id], source_id);
#ifdef REG_TEST
if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP2))
{
- session_data->stream->print_frame(HttpTestManager::get_output_file());
+ stream->print_frame(HttpTestManager::get_output_file());
if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2))
{
printf("Finished processing section from test %" PRIi64 "\n",
return;
session_data->frame_in_detection = false;
- session_data->stream->clear_frame();
+
+ const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
+ Http2Stream* stream = session_data->get_current_stream(source_id);
+ stream->clear_frame();
}
#ifdef REG_TEST
void Http2SettingsFrame::print_frame(FILE* output)
{
- fprintf(output, "SETTINGS frame:");
+ fprintf(output, "Settings frame:");
if (bad_frame)
fprintf(output, " Error in settings frame.");
class Http2SettingsFrame : public Http2Frame
{
public:
- friend Http2Frame* Http2Frame::new_frame(const uint8_t* header_buffer, const int32_t header_len,
- const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
- HttpCommon::SourceId source_id);
+ friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const int32_t, const uint8_t*,
+ const int32_t, Http2FlowData*, HttpCommon::SourceId);
#ifdef REG_TEST
void print_frame(FILE* output) override;
100, // Max concurrent Streams
65535, // Window size
16384, // Max frame size
- 4294967295 // Max header list size
+ 4294967295 // Max header list size
};
};
#endif
#include "http2_stream.h"
+#include "service_inspectors/http_inspect/http_flow_data.h"
+
using namespace HttpCommon;
-Http2Stream::Http2Stream(Http2FlowData* session_data_) : session_data(session_data_)
+Http2Stream::Http2Stream(uint32_t stream_id_, Http2FlowData* session_data_) :
+ stream_id(stream_id_),
+ session_data(session_data_)
{
}
Http2Stream::~Http2Stream()
{
delete current_frame;
+ delete hi_flow_data;
}
void Http2Stream::eval_frame(const uint8_t* header_buffer, int32_t header_len,
void Http2Stream::clear_frame()
{
+ if (current_frame != nullptr) // FIXIT-M why is this needed?
+ current_frame->clear();
delete current_frame;
current_frame = nullptr;
}
#include "service_inspectors/http_inspect/http_common.h"
#include "service_inspectors/http_inspect/http_field.h"
-#include "http2_flow_data.h"
#include "http2_frame.h"
+class HttpFlowData;
+class Http2FlowData;
+class HttpMsgSection;
+
class Http2Stream
{
public:
- Http2Stream(Http2FlowData* session_data_);
+ Http2Stream(uint32_t stream_id, Http2FlowData* session_data_);
~Http2Stream();
+ uint32_t get_stream_id() { return stream_id; }
void eval_frame(const uint8_t* header_buffer, int32_t header_len, const uint8_t* data_buffer,
int32_t data_len, HttpCommon::SourceId source_id);
void clear_frame();
const Field& get_buf(unsigned id);
+ HttpFlowData* get_hi_flow_data() const { return hi_flow_data; }
+ void set_hi_flow_data(HttpFlowData* flow_data)
+ { assert(hi_flow_data == nullptr); hi_flow_data = flow_data; }
+ HttpMsgSection* get_hi_msg_section() const { return hi_msg_section; }
+ void set_hi_msg_section(HttpMsgSection* section) { hi_msg_section = section; }
#ifdef REG_TEST
void print_frame(FILE* output);
#endif
private:
+ const uint32_t stream_id;
Http2FlowData* const session_data;
Http2Frame* current_frame = nullptr;
+ HttpFlowData* hi_flow_data = nullptr;
+ HttpMsgSection* hi_msg_section = nullptr;
};
#endif
if (session_data == nullptr)
{
- pkt->flow->set_flow_data(session_data = new Http2FlowData);
- Http2Module::increment_peg_counts(PEG_FLOW);
AssistantGadgetEvent event(pkt, "http");
DataBus::publish(FLOW_ASSISTANT_GADGET_EVENT, event);
+ pkt->flow->set_flow_data(session_data = new Http2FlowData(pkt->flow));
+ Http2Module::increment_peg_counts(PEG_FLOW);
}
// General mechanism to abort using scan
return NO_HEADER;
}
+static uint8_t get_stream_id(const uint8_t* frame_buffer)
+{
+ const uint8_t stream_id_index = 5;
+ assert(frame_buffer != nullptr);
+ return ((frame_buffer[stream_id_index] & 0x7f) << 24) +
+ (frame_buffer[stream_id_index + 1] << 16) +
+ (frame_buffer[stream_id_index + 2] << 8) +
+ frame_buffer[stream_id_index + 3];
+}
+
StreamSplitter::Status implement_scan(Http2FlowData* session_data, const uint8_t* data,
uint32_t length, uint32_t* flush_offset, HttpCommon::SourceId source_id)
{
// The first nine bytes are the frame header. But all nine might not all be present in
// the first TCP segment we receive.
- uint32_t remaining_header = FRAME_HEADER_LENGTH -
+ const uint32_t remaining_header = FRAME_HEADER_LENGTH -
session_data->scan_octets_seen[source_id];
- uint32_t remaining_header_in_data = remaining_header > length - data_offset ?
+ const uint32_t remaining_header_in_data = remaining_header > length - data_offset ?
length - data_offset : remaining_header;
memcpy(session_data->scan_frame_header[source_id] +
session_data->scan_octets_seen[source_id], data + data_offset,
// We have the full frame header, compute some variables
const uint32_t frame_length = get_frame_length(session_data->
scan_frame_header[source_id]);
- uint8_t type = get_frame_type(session_data->scan_frame_header[source_id]);
+ const uint8_t type = get_frame_type(session_data->scan_frame_header[source_id]);
+ session_data->current_stream[source_id] =
+ get_stream_id(session_data->scan_frame_header[source_id]);
// Compute frame section length once per frame
if (session_data->scan_remaining_frame_octets[source_id] == 0)
#include "http_msg_section.h"
#include "protocols/packet.h"
+#include "service_inspectors/http2_inspect/http2_flow_data.h"
using namespace snort;
HttpMsgSection* HttpContextData::get_snapshot(const Packet* p)
{
+ if (Http2FlowData::inspector_id != 0)
+ {
+ const Http2FlowData* const h2i_flow_data =
+ (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
+ if (h2i_flow_data != nullptr)
+ return h2i_flow_data->get_hi_msg_section();
+ }
+
IpsContext* context = p ? p->context : nullptr;
HttpContextData* hcd = (HttpContextData*)DetectionEngine::get_data(HttpContextData::ips_id,
context);
if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP) &&
!HttpTestManager::use_test_input(HttpTestManager::IN_HTTP))
{
- printf("Flow Data construct %" PRIu64 "\n", seq_num);
- fflush(nullptr);
+ fprintf(HttpTestManager::get_output_file(), "Flow Data construct %" PRIu64 "\n", seq_num);
+ fflush(HttpTestManager::get_output_file());
}
#endif
HttpModule::increment_peg_counts(PEG_CONCURRENT_SESSIONS);
if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP) &&
!HttpTestManager::use_test_input(HttpTestManager::IN_HTTP))
{
- printf("Flow Data destruct %" PRIu64 "\n", seq_num);
- fflush(nullptr);
+ fprintf(HttpTestManager::get_output_file(), "Flow Data destruct %" PRIu64 "\n", seq_num);
+ fflush(HttpTestManager::get_output_file());
}
#endif
if (HttpModule::get_peg_counts(PEG_CONCURRENT_SESSIONS) > 0)
#endif
private:
+ bool for_http2 = false;
+
// Convenience routines
void half_reset(HttpCommon::SourceId source_id);
void trailer_prep(HttpCommon::SourceId source_id);
#include "detection/detection_engine.h"
#include "detection/detection_util.h"
+#include "service_inspectors/http2_inspect/http2_flow_data.h"
#include "log/unified2.h"
#include "protocols/packet.h"
#include "stream/stream.h"
return 1;
}
+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);
+ else
+ return h2i_flow_data->get_hi_flow_data();
+}
+
+void HttpInspect::http_set_flow_data(Flow* flow, HttpFlowData* flow_data)
+{
+ 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)
+ flow->set_flow_data(flow_data);
+ else
+ {
+ flow_data->for_http2 = true;
+ h2i_flow_data->set_hi_flow_data(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;
- HttpFlowData* session_data =
- (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* session_data = http_get_flow_data(p->flow);
// FIXIT-H Workaround for unexpected eval() calls
if (session_data->section_type[source_id] == SEC__NOT_COMPUTE)
const bool buf_owner = !session_data->partial_flush[source_id];
if (!process(p->data, p->dsize, p->flow, source_id, buf_owner))
{
- DetectionEngine::disable_content(p);
+ if (!session_data->for_http2)
+ DetectionEngine::disable_content(p);
}
#ifdef REG_TEST
SourceId source_id, bool buf_owner) const
{
HttpMsgSection* current_section;
- HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* session_data = http_get_flow_data(flow);
assert(session_data != nullptr);
if (!session_data->partial_flush[source_id])
{
Profile profile(HttpModule::get_profile_stats());
- HttpFlowData* const session_data =
- (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* const session_data = http_get_flow_data(p->flow);
if ( session_data == nullptr )
return;
- HttpMsgSection* current_section = HttpContextData::clear_snapshot(p->context);
+ Http2FlowData* h2i_flow_data = nullptr;
+ if (Http2FlowData::inspector_id != 0)
+ {
+ h2i_flow_data = (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
+ }
+
+ HttpMsgSection* current_section = nullptr;
+ if (h2i_flow_data != nullptr)
+ {
+ current_section = h2i_flow_data->get_hi_msg_section();
+ h2i_flow_data->set_hi_msg_section(nullptr);
+ }
+ else
+ current_section = HttpContextData::clear_snapshot(p->context);
// FIXIT-M This test is necessary because sometimes we get extra clears
// Convert to assert when that gets fixed.
bool process(const uint8_t* data, const uint16_t dsize, snort::Flow* const flow,
HttpCommon::SourceId source_id_, bool buf_owner) const;
+ static HttpFlowData* http_get_flow_data(const snort::Flow* flow);
+ static void http_set_flow_data(snort::Flow* flow, HttpFlowData* flow_data);
const HttpParaList* const params;
#include "config.h"
#endif
+#include "service_inspectors/http2_inspect/http2_flow_data.h"
+
#include "http_msg_section.h"
#include "http_context_data.h"
tcp_close(session_data->tcp_close[source_id])
{
assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
+
+ if (Http2FlowData::inspector_id != 0)
+ {
+ Http2FlowData* const h2i_flow_data = (Http2FlowData*)flow->get_flow_data(Http2FlowData::inspector_id);
+ if (h2i_flow_data != nullptr)
+ {
+ h2i_flow_data->set_hi_msg_section(this);
+ return;
+ }
+ }
+
HttpContextData::save_snapshot(this);
}
#include "http_common.h"
#include "http_cutter.h"
#include "http_enum.h"
+#include "http_inspect.h"
#include "http_module.h"
#include "http_msg_request.h"
#include "http_stream_splitter.h"
{
Profile profile(HttpModule::get_profile_stats());
- HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* session_data = HttpInspect::http_get_flow_data(flow);
// FIXIT-M - this assert has been changed to check for null session data and return false if so
// due to lack of reliable feedback to stream that scan has been called...if that is
// addressed in stream reassembly rewrite this can be reverted to an assert
}
else
{
- printf("Finish from flow data %" PRIu64 " direction %d\n", session_data->seq_num,
+ fprintf(HttpTestManager::get_output_file(),
+ "Finish from flow data %" PRIu64 " direction %d\n", session_data->seq_num,
source_id);
- fflush(stdout);
+ fflush(HttpTestManager::get_output_file());
}
}
#endif
return false;
}
- HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* session_data = HttpInspect::http_get_flow_data(flow);
assert(session_data != nullptr);
if ((session_data->type_expected[source_id] != SEC_BODY_CL) &&
(session_data->type_expected[source_id] != SEC_BODY_OLD) &&
if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP) &&
!HttpTestManager::use_test_input(HttpTestManager::IN_HTTP))
{
- printf("Partial flush from flow data %" PRIu64 "\n", session_data->seq_num);
- fflush(stdout);
+ fprintf(HttpTestManager::get_output_file(), "Partial flush from flow data %" PRIu64 "\n",
+ session_data->seq_num);
+ fflush(HttpTestManager::get_output_file());
}
#endif
copied = len;
- HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* session_data = HttpInspect::http_get_flow_data(flow);
assert(session_data != nullptr);
#ifdef REG_TEST
}
else
{
- printf("Reassemble from flow data %" PRIu64
+ fprintf(HttpTestManager::get_output_file(), "Reassemble from flow data %" PRIu64
" direction %d total %u length %u partial %d\n", session_data->seq_num, source_id,
total, len, session_data->partial_flush[source_id]);
- fflush(stdout);
+ fflush(HttpTestManager::get_output_file());
}
}
#endif
// 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 = (HttpFlowData*)flow->get_flow_data(HttpFlowData::inspector_id);
+ HttpFlowData* session_data = HttpInspect::http_get_flow_data(flow);
if (session_data == nullptr)
{
- flow->set_flow_data(session_data = new HttpFlowData);
+ HttpInspect::http_set_flow_data(flow, session_data = new HttpFlowData);
HttpModule::increment_peg_counts(PEG_FLOW);
}
if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP) &&
!HttpTestManager::use_test_input(HttpTestManager::IN_HTTP))
{
- printf("Scan from flow data %" PRIu64
+ fprintf(HttpTestManager::get_output_file(), "Scan from flow data %" PRIu64
" direction %d length %u client port %hu server port %hu\n", session_data->seq_num,
source_id, length, flow->client_port, flow->server_port);
- fflush(stdout);
+ fflush(HttpTestManager::get_output_file());
if (HttpTestManager::get_show_scan())
{
- Field(length, data).print(stdout, "Scan segment");
+ Field(length, data).print(HttpTestManager::get_output_file(), "Scan segment");
}
}
#endif
#include "hash/hashfcn.h"
#include "log/messages.h"
#include "protocols/packet.h"
+#include "service_inspectors/http2_inspect/http2_flow_data.h"
#include "http_common.h"
#include "http_enum.h"
if (!section_match)
return NO_MATCH;
+ const Http2FlowData* const h2i_flow_data =
+ (Http2FlowData*)p->flow->get_flow_data(Http2FlowData::inspector_id);
+
+ HttpInspect* const hi = (h2i_flow_data != nullptr) ?
+ (HttpInspect*)(p->flow->assistant_gadget) : (HttpInspect*)(p->flow->gadget);
+
InspectionBuffer hb;
- if (! ((HttpInspect*)(p->flow->gadget))->
- http_get_buf((unsigned)buffer_index, sub_id, form, p, hb))
+ if (! (hi->http_get_buf((unsigned)buffer_index, sub_id, form, p, hb)))
return NO_MATCH;
c.set(key, hb.data, hb.len);