Unexpected settings ACK.
+121:44
+
+SETTINGS_MAX_FRAME_SIZE value sent in HTTP/2 settings frame is greater than maximum value,
+as configured by settings_max_frame_size.
+
122:1
Basic one host to one host TCP portscan where multiple TCP ports are scanned on
flow. The default and minimum configurable value is 100. It can be configured up to a maximum of
1000.
+===== settings_max_frame_size
+This sets the maximum allowed value for settings frame SETTINGS_MAX_FRAME_SIZE.
+The default and max value is 16777215. The minimum configurable value is 16384.
+
==== Detection rules
Since HTTP/2 traffic is processed through the HTTP inspector, all of the rule options discussed
virtual const uint8_t* get_frame_data(uint32_t& length) const override;
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
#ifdef REG_TEST
void print_frame(FILE* output) override;
EVENT_INVALID_GOAWAY_FRAME = 41,
EVENT_SETTINGS_QUEUE_OVERFLOW = 42,
EVENT_SETTINGS_QUEUE_UNDERFLOW = 43,
+ EVENT_ABOVE_SETTINGS_MAX_FRAME_SIZE = 44,
EVENT__MAX_VALUE
};
INF_BAD_GOAWAY_FRAME_R_BIT = 54,
INF_SETTINGS_QUEUE_OVERFLOW = 55,
INF_SETTINGS_QUEUE_UNDERFLOW = 56,
+ INF_ABOVE_SETTINGS_MAX_FRAME_SIZE = 57,
INF__MAX_VALUE
};
Http2Frame* Http2Frame::new_frame(const uint8_t* header, const uint32_t header_len,
const uint8_t* data, const uint32_t data_len, Http2FlowData* session_data, SourceId source_id,
- Http2Stream* stream)
+ const Http2ParaList* params, Http2Stream* stream)
{
Http2Frame* frame = nullptr;
break;
case FT_SETTINGS:
frame = new Http2SettingsFrame(header, header_len, data, data_len, session_data,
- source_id, stream);
+ source_id, stream, params);
break;
case FT_DATA:
frame = new Http2DataFrame(header, header_len, data, data_len, session_data, source_id,
#include "service_inspectors/http_inspect/http_field.h"
#include "http2_enum.h"
+#include "http2_module.h"
/* This class is called Http2Frame, but an object of this class may not represent exactly one
* HTTP/2 frame as received on the wire. For HEADERS frames, the Http2Frame object contains the
virtual ~Http2Frame() = default;
static Http2Frame* new_frame(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);
+ HttpCommon::SourceId source_id, const Http2ParaList* params, Http2Stream* stream);
virtual bool valid_sequence(Http2Enums::StreamState) { return true; }
virtual void analyze_http1(snort::Packet*) { }
virtual void clear(snort::Packet*) { }
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool is_detection_required() const override { return false; }
private:
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool valid_sequence(Http2Enums::StreamState state) override;
void analyze_http1(snort::Packet*) override;
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool valid_sequence(Http2Enums::StreamState state) override;
void analyze_http1(snort::Packet*) override;
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, p);
+ session_data->frame_data[source_id], session_data->frame_data_size[source_id], source_id, p, params);
if (!stream->get_current_frame()->is_detection_required())
DetectionEngine::disable_all(p);
{
assert(params);
ConfigLogger::log_value("concurrent_streams_limit", params->concurrent_streams_limit);
+ ConfigLogger::log_value("settings_max_frame_size", params->settings_max_frame_size);
}
#ifdef REG_TEST
{
{ "concurrent_streams_limit", Parameter::PT_INT, "100:1000", "100",
"Maximum number of concurrent streams allowed in a single HTTP/2 flow" },
+ { "settings_max_frame_size", Parameter::PT_INT, "16384:16777215", "16777215",
+ "Maximum allowed value for settings frame SETTINGS_MAX_FRAME_SIZE" },
#ifdef REG_TEST
{ "test_input", Parameter::PT_BOOL, nullptr, "false",
"read HTTP/2 messages from text file" },
{
params->concurrent_streams_limit = val.get_uint32();
}
+ else if (val.is("settings_max_frame_size"))
+ {
+ params->settings_max_frame_size = val.get_uint32();
+ }
#ifdef REG_TEST
else if (val.is("test_input"))
{
{
public:
uint32_t concurrent_streams_limit;
+ uint32_t settings_max_frame_size;
#ifdef REG_TEST
bool test_input;
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool is_detection_required() const override { return false; }
private:
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool is_detection_required() const override { return false; }
private:
Http2Infractions* const infractions, const uint8_t* data_buffer, uint32_t data_len);
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
#ifdef REG_TEST
void print_frame(FILE* output) override;
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool is_detection_required() const override { return false; }
bool valid_sequence(Http2Enums::StreamState state) override;
void update_stream_state() override;
Http2SettingsFrame::Http2SettingsFrame(const uint8_t* header_buffer, const uint32_t header_len,
const uint8_t* data_buffer, const uint32_t data_len, Http2FlowData* ssn_data,
- HttpCommon::SourceId src_id, Http2Stream* stream_) : Http2Frame(header_buffer, header_len,
- data_buffer, data_len, ssn_data, src_id, stream_)
+ HttpCommon::SourceId src_id, Http2Stream* stream_, const Http2ParaList* params_) : Http2Frame(header_buffer, header_len,
+ data_buffer, data_len, ssn_data, src_id, stream_), params(params_)
{
if (!sanity_check())
{
session_data->events[source_id]->create_event(EVENT_BAD_SETTINGS_VALUE);
*session_data->infractions[source_id] += INF_BAD_SETTINGS_PUSH_VALUE;
}
+ else if (parameter_id == SFID_MAX_FRAME_SIZE and parameter_value > params->settings_max_frame_size)
+ {
+ session_data->events[source_id]->create_event(EVENT_ABOVE_SETTINGS_MAX_FRAME_SIZE);
+ *session_data->infractions[source_id] += INF_ABOVE_SETTINGS_MAX_FRAME_SIZE;
+ }
else
settings.set_param(parameter_id, parameter_value);
}
#define HTTP2_SETTINGS_FRAME_H
#include "http2_frame.h"
+#include "http2_module.h"
class Field;
class Http2ConnectionSettings;
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
#ifdef REG_TEST
void print_frame(FILE* output) override;
private:
Http2SettingsFrame(const uint8_t* header_buffer, const uint32_t header_len,
const uint8_t* data_buffer, const uint32_t data_len, Http2FlowData* ssn_data,
- HttpCommon::SourceId src_id, Http2Stream* stream);
+ HttpCommon::SourceId src_id, Http2Stream* stream, const Http2ParaList* params_);
void queue_settings();
bool sanity_check();
{ return Http2Enums::FLAG_ACK; }
bool bad_frame = false;
+ const Http2ParaList* params;
};
class Http2ConnectionSettings
}
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, Packet* p)
+ const uint8_t* data_buffer, uint32_t data_len, SourceId source_id, Packet* p,
+ const Http2ParaList* params)
{
assert(current_frame == nullptr);
current_frame = Http2Frame::new_frame(header_buffer, header_len, data_buffer,
- data_len, session_data, source_id, this);
+ data_len, session_data, source_id, params, this);
if (!session_data->abort_flow[source_id] && (get_state(source_id) != STREAM_ERROR))
{
if (current_frame->valid_sequence(state[source_id]))
class Http2FlowData;
class HttpFlowData;
class HttpMsgSection;
+struct Http2ParaList;
class Http2Stream
{
~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, snort::Packet* p);
+ uint32_t data_len, HttpCommon::SourceId source_id, snort::Packet* p, const Http2ParaList* params);
void check_and_cleanup_completed();
void clear_frame(snort::Packet* p);
const Field& get_buf(unsigned id);
{ EVENT_INVALID_GOAWAY_FRAME, "invalid HTTP/2 GOAWAY frame" },
{ EVENT_SETTINGS_QUEUE_OVERFLOW, "too many unacknowledged settings" },
{ EVENT_SETTINGS_QUEUE_UNDERFLOW, "setting acknowledgment without actual settings" },
+ { EVENT_ABOVE_SETTINGS_MAX_FRAME_SIZE, "settings frame size greater than settings_max_frame_size"},
{ 0, nullptr }
};
{
public:
friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*,
- const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
+ const uint32_t, Http2FlowData*, HttpCommon::SourceId, const Http2ParaList* params, Http2Stream* stream);
bool is_detection_required() const override { return false; }
bool valid_sequence(Http2Enums::StreamState state) override;