#include "http2_enum.h"
#include "http2_flow_data.h"
#include "http2_hpack.h"
+#include "http2_request_line.h"
#include "http2_start_line.h"
+#include "http2_status_line.h"
#include "http2_stream.h"
using namespace snort;
if (!process_frame)
return;
- start_line_generator = Http2StartLine::new_start_line_generator(source_id,
- session_data->events[source_id], session_data->infractions[source_id]);
+ if (source_id == SRC_CLIENT)
+ start_line_generator = new Http2RequestLine(session_data->events[source_id],
+ session_data->infractions[source_id]);
+ else
+ start_line_generator = new Http2StatusLine(session_data->events[source_id],
+ session_data->infractions[source_id]);
// Decode headers
if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
return false;
const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER;
- Http2Stream* const stream = session_data->get_current_stream(source_id);
+ Http2Stream* const stream = session_data->get_processing_stream(source_id);
const Field& buffer = stream->get_buf(id);
if (buffer.length() <= 0)
return false;
#include "http2_push_promise_frame.h"
#include "http2_flow_data.h"
+#include "http2_hpack.h"
+#include "http2_request_line.h"
+#include "http2_start_line.h"
#include "http2_stream.h"
#include "http2_utils.h"
Http2PushPromiseFrame::Http2PushPromiseFrame(const uint8_t* header_buffer,
const uint32_t header_len, const uint8_t* data_buffer, const uint32_t data_len,
Http2FlowData* session_data_, HttpCommon::SourceId source_id_, Http2Stream* stream_) :
- Http2Frame(header_buffer, header_len, data_buffer, data_len, session_data_, source_id_, stream_)
+ Http2HeadersFrame(header_buffer, header_len, data_buffer, data_len, session_data_, source_id_,
+ stream_)
{
// If this was a short frame, it's being processed by the stream that sent it. We've already
// alerted
session_data->events[source_id]->create_event(EVENT_INVALID_FLAG);
*session_data->infractions[source_id] += INF_INVALID_FLAG;
}
+
+ start_line_generator = new Http2RequestLine(session_data->events[source_id],
+ session_data->infractions[source_id]);
+
+ hpack_headers_offset += PROMISED_ID_LENGTH;
+
+ // Decode headers
+ if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
+ hpack_headers_offset, decoded_headers, start_line_generator, false))
+ {
+ session_data->abort_flow[source_id] = true;
+ session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+ return;
+ }
+}
+
+Http2PushPromiseFrame::~Http2PushPromiseFrame()
+{
+ delete start_line_generator;
}
bool Http2PushPromiseFrame::valid_sequence(Http2Enums::StreamState)
return true;
}
-void Http2PushPromiseFrame::update_stream_state()
+// FIXIT-E current implementation for testing purposes only. Headers are not yet being sent to
+// http_inspect.
+void Http2PushPromiseFrame::analyze_http1()
{
- switch (stream->get_state(source_id))
+ if (session_data->abort_flow[source_id])
+ return;
+
+ detection_required = true;
+
+ if (!start_line_generator->generate_start_line(start_line))
{
- case STREAM_EXPECT_HEADERS:
- stream->set_state(SRC_CLIENT, STREAM_COMPLETE);
- break;
- default:
- //only STREAM_EXPECT_HEADERS is valid so should never get here
- assert(false);
- stream->set_state(source_id, STREAM_ERROR);
+ // can't send request or push-promise headers to http_inspect, but response will still
+ // be processed
+ stream->set_state(SRC_CLIENT, STREAM_ERROR);
+ return;
}
+
+ http1_header = hpack_decoder->get_decoded_headers(decoded_headers);
+}
+
+void Http2PushPromiseFrame::update_stream_state()
+{
+ if (stream->get_state(SRC_CLIENT) == STREAM_EXPECT_HEADERS)
+ stream->set_state(SRC_CLIENT, STREAM_COMPLETE);
+
+ assert(stream->get_state(SRC_SERVER) == STREAM_EXPECT_HEADERS);
+ assert((stream->get_state(SRC_CLIENT) == STREAM_COMPLETE) or
+ (stream->get_state(SRC_CLIENT) == STREAM_ERROR));
}
uint32_t Http2PushPromiseFrame::get_promised_stream_id(Http2EventGen* const events,
void Http2PushPromiseFrame::print_frame(FILE* output)
{
fprintf(output, "Push_Promise frame\n");
- Http2Frame::print_frame(output);
+ start_line.print(output, "Decoded start-line");
+ Http2HeadersFrame::print_frame(output);
}
#endif
#include "http2_enum.h"
#include "http2_frame.h"
+#include "http2_headers_frame.h"
class Field;
class Http2Frame;
using Http2EventGen = EventGen<Http2Enums::EVENT__MAX_VALUE, Http2Enums::EVENT__NONE,
Http2Enums::HTTP2_GID>;
-class Http2PushPromiseFrame : public Http2Frame
+class Http2PushPromiseFrame : public Http2HeadersFrame
{
public:
+ ~Http2PushPromiseFrame() override;
bool valid_sequence(Http2Enums::StreamState state) override;
+ void analyze_http1() 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);
const uint8_t* data_buffer, const uint32_t data_len, Http2FlowData* ssn_data,
HttpCommon::SourceId src_id, Http2Stream* stream);
static const int32_t PROMISED_ID_LENGTH = 4;
+ Http2StartLine* start_line_generator = nullptr;
+ Field start_line;
};
#endif
field->set(value.length(), value_str, true);
}
-// This is called on the first non-pseudo-header. Select the appropriate URI form based on the
-// provided pseudo-headers and generate the start line
+// Select the appropriate URI form based on the provided pseudo-headers and generate the start line
bool Http2RequestLine::generate_start_line(Field& start_line)
{
uint32_t bytes_written = 0;
{
// FIXIT-E May want to be more lenient than RFC on generating start line
*infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
- events->create_event(EVENT_MISFORMATTED_HTTP2);
+ events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
return false;
}
class Http2RequestLine : public Http2StartLine
{
public:
+ Http2RequestLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
+ Http2StartLine(evs, infrs) { }
void process_pseudo_header(const Field& name, const Field& value) override;
bool generate_start_line(Field& start_line) override;
- friend Http2StartLine* Http2StartLine::new_start_line_generator(HttpCommon::SourceId source_id,
- Http2EventGen* const events, Http2Infractions* const infractions);
-
private:
- Http2RequestLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
- Http2StartLine(evs, infrs) { }
-
Field method;
Field path;
Field scheme;
{
delete[] start_line_buffer;
}
-
-Http2StartLine* Http2StartLine::new_start_line_generator(SourceId source_id,
- Http2EventGen* const events, Http2Infractions* const infractions)
-{
- if (source_id == SRC_CLIENT)
- return new Http2RequestLine(events, infractions);
- else
- return new Http2StatusLine(events, infractions);
-}
-
class Http2StartLine
{
public:
- static Http2StartLine* new_start_line_generator(HttpCommon::SourceId source_id,
- Http2EventGen* const events, Http2Infractions* const infractions);
-
virtual ~Http2StartLine();
friend class Http2Hpack;
}
}
-// This is called on the first non-pseudo-header.
bool Http2StatusLine::generate_start_line(Field& start_line)
{
uint32_t bytes_written = 0;
class Http2StatusLine : public Http2StartLine
{
public:
+ Http2StatusLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
+ Http2StartLine(evs, infrs) { }
+
void process_pseudo_header(const Field& name, const Field& value) override;
bool generate_start_line(Field& start_line) override;
- friend Http2StartLine* Http2StartLine::new_start_line_generator(HttpCommon::SourceId source_id,
- Http2EventGen* const events, Http2Infractions* const infractions);
-
private:
- Http2StatusLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
- Http2StartLine(evs, infrs) { }
-
Field status;
static const char* STATUS_NAME;