From: Mike Stepanek (mstepane) Date: Fri, 16 Oct 2020 13:27:27 +0000 (+0000) Subject: Merge pull request #2540 in SNORT/snort3 from ~KATHARVE/snort3:h2i_pp1 to master X-Git-Tag: 3.0.3-3~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81d98c8385a3e4144df45e560146bc0a2f862e81;p=thirdparty%2Fsnort3.git Merge pull request #2540 in SNORT/snort3 from ~KATHARVE/snort3:h2i_pp1 to master Squashed commit of the following: commit 27d03d91f9629cd4565cfb17ebaf3b85fac978d0 Author: Katura Harvey Date: Fri Oct 9 10:00:19 2020 -0400 http2_inspect: handle stream creation for push promise frames --- diff --git a/src/service_inspectors/http2_inspect/CMakeLists.txt b/src/service_inspectors/http2_inspect/CMakeLists.txt index c44b395ea..8ac11eef3 100644 --- a/src/service_inspectors/http2_inspect/CMakeLists.txt +++ b/src/service_inspectors/http2_inspect/CMakeLists.txt @@ -33,6 +33,8 @@ set (FILE_LIST http2_inspect.h http2_module.cc http2_module.h + http2_push_promise_frame.cc + http2_push_promise_frame.h http2_request_line.cc http2_request_line.h http2_settings_frame.cc diff --git a/src/service_inspectors/http2_inspect/http2_enum.h b/src/service_inspectors/http2_inspect/http2_enum.h index d30ab3771..6ee57d3ed 100644 --- a/src/service_inspectors/http2_inspect/http2_enum.h +++ b/src/service_inspectors/http2_inspect/http2_enum.h @@ -75,6 +75,14 @@ enum EventSid EVENT_TRAILERS_NOT_END = 20, EVENT_PADDING_ON_INVALID_FRAME = 21, EVENT_PADDING_ON_EMPTY_FRAME = 22, + EVENT_C2S_PUSH = 23, + EVENT_INVALID_PUSH_FRAME = 24, + EVENT_BAD_PUSH_SEQUENCE = 25, + EVENT_BAD_SETTINGS_VALUE = 26, + EVENT_PUSH_WHEN_PROHIBITED = 27, + EVENT_INVALID_PROMISED_STREAM = 28, + EVENT_INVALID_STREAM_ID = 29, + EVENT_INVALID_FLAG = 30, EVENT__MAX_VALUE }; @@ -94,7 +102,7 @@ enum Infraction INF_HUFFMAN_INCOMPLETE_CODE_PADDING = 9, INF_MISSING_CONTINUATION = 10, INF_UNEXPECTED_CONTINUATION = 11, - INF_UNUSED_1 = 12, + INF_C2S_PUSH = 12, INF_INVALID_PSEUDO_HEADER = 13, INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER = 14, INF_PSEUDO_HEADER_URI_FORM_MISMATCH = 15, @@ -110,11 +118,17 @@ enum Infraction INF_INVALID_STARTLINE = 25, INF_INVALID_HEADER = 26, INF_PADDING_LEN = 27, - INF_UNUSED_2 = 28, + INF_PUSH_FRAME_TOO_SHORT = 28, INF_PSEUDO_HEADER_IN_TRAILERS = 29, INF_TRAILERS_NOT_END = 30, INF_PADDING_ON_INVALID_FRAME = 31, INF_PADDING_ON_EMPTY_FRAME = 32, + INF_BAD_PUSH_SEQUENCE = 33, + INF_BAD_SETTINGS_PUSH_VALUE = 34, + INF_PUSH_WHEN_PROHIBITED = 35, + INF_INVALID_PROMISED_STREAM = 36, + INF_INVALID_STREAM_ID = 37, + INF_INVALID_FLAG = 38, INF__MAX_VALUE }; diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.cc b/src/service_inspectors/http2_inspect/http2_flow_data.cc index 89d8d0551..e8cbd0d88 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.cc +++ b/src/service_inspectors/http2_inspect/http2_flow_data.cc @@ -29,6 +29,7 @@ #include "http2_enum.h" #include "http2_frame.h" #include "http2_module.h" +#include "http2_push_promise_frame.h" #include "http2_start_line.h" #include "http2_stream.h" @@ -156,6 +157,22 @@ class Http2Stream* Http2FlowData::get_current_stream(const HttpCommon::SourceId return get_stream(current_stream[source_id]); } +// processing stream is the current stream except for push promise frames with properly formatted +// promised stream IDs +class Http2Stream* Http2FlowData::get_processing_stream(const HttpCommon::SourceId source_id) +{ + if (processing_stream_id[source_id] == NO_STREAM_ID) + { + if (frame_type[source_id] == FT_PUSH_PROMISE) + processing_stream_id[source_id] = Http2PushPromiseFrame::get_promised_stream_id( + events[source_id], infractions[source_id], frame_data[source_id], + frame_data_size[source_id]); + if (processing_stream_id[source_id] == NO_STREAM_ID) + processing_stream_id[source_id] = current_stream[source_id]; + } + return get_stream(processing_stream_id[source_id]); +} + uint32_t Http2FlowData::get_current_stream_id(const HttpCommon::SourceId source_id) { return current_stream[source_id]; diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.h b/src/service_inspectors/http2_inspect/http2_flow_data.h index f3e5f4972..b38e354d1 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.h +++ b/src/service_inspectors/http2_inspect/http2_flow_data.h @@ -69,6 +69,7 @@ public: friend class Http2HeadersFrameTrailer; friend class Http2Hpack; friend class Http2Inspect; + friend class Http2PushPromiseFrame; friend class Http2RequestLine; friend class Http2SettingsFrame; friend class Http2StartLine; @@ -92,11 +93,14 @@ public: }; class Http2Stream* get_current_stream(const HttpCommon::SourceId source_id); uint32_t get_current_stream_id(const HttpCommon::SourceId source_id); + class Http2Stream* get_processing_stream(const HttpCommon::SourceId source_id); Http2HpackDecoder* get_hpack_decoder(const HttpCommon::SourceId source_id) { return &hpack_decoder[source_id]; } - Http2ConnectionSettings* get_connection_settings(const HttpCommon::SourceId source_id) + Http2ConnectionSettings* get_my_connection_settings(const HttpCommon::SourceId source_id) { return &connection_settings[source_id]; } + Http2ConnectionSettings* get_recipient_connection_settings(const HttpCommon::SourceId source_id) + { return &connection_settings[1 - source_id]; } bool is_mid_frame(const HttpCommon::SourceId source_id = HttpCommon::SRC_SERVER) { return (continuation_expected[source_id] || reading_frame[source_id]); } @@ -120,8 +124,12 @@ protected: Http2Infractions* const infractions[2] = { new Http2Infractions, new Http2Infractions }; Http2EventGen* const events[2] = { new Http2EventGen, new Http2EventGen }; - // Stream ID of the frame currently being read in and processed + // Stream ID of the frame currently being processed was sent on (i.e. the stream in the frame + // header). This is set in scan(). uint32_t current_stream[2] = { Http2Enums::NO_STREAM_ID, Http2Enums::NO_STREAM_ID }; + // Stream ID of the stream responsible for processing the current frame. This will be the same + // as current_stream except when processing a push_promise frame. This is set in eval(). + uint32_t processing_stream_id[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; diff --git a/src/service_inspectors/http2_inspect/http2_frame.cc b/src/service_inspectors/http2_inspect/http2_frame.cc index fd1ec4159..eb6cfea3d 100644 --- a/src/service_inspectors/http2_inspect/http2_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_frame.cc @@ -28,6 +28,7 @@ #include "http2_flow_data.h" #include "http2_headers_frame_header.h" #include "http2_headers_frame_trailer.h" +#include "http2_push_promise_frame.h" #include "http2_settings_frame.h" #include "http2_stream.h" #include "service_inspectors/http_inspect/http_field.h" @@ -67,6 +68,9 @@ Http2Frame* Http2Frame::new_frame(const uint8_t* header, const uint32_t header_l case FT_DATA: return new Http2DataFrame(header, header_len, data, data_len, session_data, source_id, stream); + case FT_PUSH_PROMISE: + return new Http2PushPromiseFrame(header, header_len, data, data_len, session_data, + source_id, stream); default: return new Http2Frame(header, header_len, data, data_len, session_data, source_id, stream); 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 4739e65a3..442a59e7a 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc @@ -66,7 +66,14 @@ Http2HeadersFrameTrailer::Http2HeadersFrameTrailer(const uint8_t* header_buffer, bool Http2HeadersFrameTrailer::valid_sequence(Http2Enums::StreamState state) { - return (state == Http2Enums::STREAM_EXPECT_BODY) || (state == Http2Enums::STREAM_BODY); + if ((state == STREAM_EXPECT_BODY) || (state == STREAM_BODY)) + return true; + if (state == STREAM_COMPLETE) + { + *session_data->infractions[source_id] += INF_FRAME_SEQUENCE; + session_data->events[source_id]->create_event(EVENT_FRAME_SEQUENCE); + } + return false; } void Http2HeadersFrameTrailer::analyze_http1() diff --git a/src/service_inspectors/http2_inspect/http2_hpack_table.cc b/src/service_inspectors/http2_inspect/http2_hpack_table.cc index e5b03d0d0..93e33682a 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack_table.cc +++ b/src/service_inspectors/http2_inspect/http2_hpack_table.cc @@ -138,7 +138,7 @@ void HpackIndexTable::settings_table_size_update(uint32_t new_size) bool HpackIndexTable::hpack_table_size_update(uint32_t new_size) { encoder_set_max_size = true; - if (new_size <= session_data->get_connection_settings((HttpCommon::SourceId)(1 - source_id))-> + if (new_size <= session_data->get_recipient_connection_settings(source_id)-> get_param(HEADER_TABLE_SIZE)) { dynamic_table.update_size(new_size); diff --git a/src/service_inspectors/http2_inspect/http2_inspect.cc b/src/service_inspectors/http2_inspect/http2_inspect.cc index cdd35e94c..fb8508782 100644 --- a/src/service_inspectors/http2_inspect/http2_inspect.cc +++ b/src/service_inspectors/http2_inspect/http2_inspect.cc @@ -130,7 +130,9 @@ void Http2Inspect::eval(Packet* p) return; } - Http2Stream* stream = session_data->get_current_stream(source_id); + Http2Stream* stream = session_data->get_processing_stream(source_id); + assert(session_data->processing_stream_id[source_id] != NO_STREAM_ID); + assert(stream); session_data->stream_in_hi = stream->get_stream_id(); stream->eval_frame(session_data->frame_header[source_id], @@ -183,9 +185,10 @@ void Http2Inspect::clear(Packet* p) const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER; - Http2Stream* stream = session_data->get_current_stream(source_id); + Http2Stream* stream = session_data->get_processing_stream(source_id); stream->clear_frame(); session_data->stream_in_hi = NO_STREAM_ID; + session_data->processing_stream_id[source_id] = NO_STREAM_ID; } #ifdef REG_TEST diff --git a/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc b/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc new file mode 100644 index 000000000..e1b994e14 --- /dev/null +++ b/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc @@ -0,0 +1,130 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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_push_promise_frame.cc author Katura Harvey + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "http2_push_promise_frame.h" + +#include "http2_flow_data.h" +#include "http2_stream.h" +#include "http2_utils.h" + +using namespace HttpCommon; +using namespace Http2Enums; + +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_) +{ + // If this was a short frame, it's being processed by the stream that sent it. We've already + // alerted + if (data_len < PROMISED_ID_LENGTH) + return; + + // Server-initiated streams must be even + if (source_id == SRC_SERVER and stream->get_stream_id() % 2 != 0) + { + *session_data->infractions[source_id] += INF_INVALID_STREAM_ID; + session_data->events[source_id]->create_event(EVENT_INVALID_STREAM_ID); + } + + if (session_data->get_recipient_connection_settings(source_id)->get_param(ENABLE_PUSH) == 0) + { + session_data->events[source_id]->create_event(EVENT_PUSH_WHEN_PROHIBITED); + *session_data->infractions[source_id] += INF_PUSH_WHEN_PROHIBITED; + } + + // Push_promise frames only define the padded and end_headers flags + if (get_flags() & ~PADDED & ~END_HEADERS) + { + session_data->events[source_id]->create_event(EVENT_INVALID_FLAG); + *session_data->infractions[source_id] += INF_INVALID_FLAG; + } +} + +bool Http2PushPromiseFrame::valid_sequence(Http2Enums::StreamState) +{ + if (data.length() < PROMISED_ID_LENGTH) + return false; + + if (source_id == SRC_CLIENT) + { + *session_data->infractions[source_id] += INF_C2S_PUSH; + session_data->events[source_id]->create_event(EVENT_C2S_PUSH); + return false; + } + + // Promised stream must not be already in use + if (stream->get_state(SRC_CLIENT) != STREAM_EXPECT_HEADERS or + stream->get_state(SRC_SERVER) != STREAM_EXPECT_HEADERS) + { + *session_data->infractions[source_id] += INF_INVALID_PROMISED_STREAM; + session_data->events[source_id]->create_event(EVENT_INVALID_PROMISED_STREAM); + return false; + } + + // Alert but continue processing if invalid sequence on stream push_promise was sent on + Http2Stream* const stream_sent_on = session_data->get_current_stream(source_id); + if (stream_sent_on->get_state(SRC_CLIENT) == STREAM_EXPECT_HEADERS or + stream_sent_on->get_state(SRC_SERVER) >= STREAM_COMPLETE) + { + *session_data->infractions[source_id] += INF_BAD_PUSH_SEQUENCE; + session_data->events[source_id]->create_event(EVENT_BAD_PUSH_SEQUENCE); + } + return true; +} + +void Http2PushPromiseFrame::update_stream_state() +{ + switch (stream->get_state(source_id)) + { + 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); + } +} + +uint32_t Http2PushPromiseFrame::get_promised_stream_id(Http2EventGen* const events, + Http2Infractions* const infractions, const uint8_t* data_buffer, uint32_t data_len) +{ + if (data_len < PROMISED_ID_LENGTH) + { + events->create_event(EVENT_INVALID_PUSH_FRAME); + *infractions += INF_PUSH_FRAME_TOO_SHORT; + return NO_STREAM_ID; + } + + // the first four bytes of the push_promise frame are the pushed stream ID + return get_stream_id_from_buffer(data_buffer); +} + +#ifdef REG_TEST +void Http2PushPromiseFrame::print_frame(FILE* output) +{ + fprintf(output, "Push_Promise frame\n"); + Http2Frame::print_frame(output); +} +#endif diff --git a/src/service_inspectors/http2_inspect/http2_push_promise_frame.h b/src/service_inspectors/http2_inspect/http2_push_promise_frame.h new file mode 100644 index 000000000..8b3f96281 --- /dev/null +++ b/src/service_inspectors/http2_inspect/http2_push_promise_frame.h @@ -0,0 +1,60 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2020-2020 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_push_promise_frame.h author Katura Harvey + +#ifndef HTTP2_PUSH_PROMISE_FRAME_H +#define HTTP2_PUSH_PROMISE_FRAME_H + +#include "service_inspectors/http_inspect/http_common.h" +#include "utils/event_gen.h" +#include "utils/infractions.h" + +#include "http2_enum.h" +#include "http2_frame.h" + +class Field; +class Http2Frame; +class Http2Stream; +class HttpFlowData; + +using Http2Infractions = Infractions; +using Http2EventGen = EventGen; + +class Http2PushPromiseFrame : public Http2Frame +{ +public: + bool valid_sequence(Http2Enums::StreamState state) 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); + + friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const uint32_t, const uint8_t*, + const uint32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream); + +#ifdef REG_TEST + void print_frame(FILE* output) override; +#endif + +private: + Http2PushPromiseFrame(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); + static const int32_t PROMISED_ID_LENGTH = 4; +}; +#endif diff --git a/src/service_inspectors/http2_inspect/http2_settings_frame.cc b/src/service_inspectors/http2_inspect/http2_settings_frame.cc index c8409ae9b..8d794de18 100644 --- a/src/service_inspectors/http2_inspect/http2_settings_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_settings_frame.cc @@ -82,8 +82,8 @@ void Http2SettingsFrame::parse_settings_frame() continue; } - handle_update(parameter_id, parameter_value); - session_data->connection_settings[source_id].set_param(parameter_id, parameter_value); + if (handle_update(parameter_id, parameter_value)) + session_data->connection_settings[source_id].set_param(parameter_id, parameter_value); } } @@ -102,7 +102,7 @@ bool Http2SettingsFrame::sanity_check() return !(bad_frame); } -void Http2SettingsFrame::handle_update(uint16_t id, uint32_t value) +bool Http2SettingsFrame::handle_update(uint16_t id, uint32_t value) { switch (id) { @@ -112,9 +112,19 @@ void Http2SettingsFrame::handle_update(uint16_t id, uint32_t value) session_data->get_hpack_decoder((HttpCommon::SourceId) (1 - source_id))-> get_decode_table()->settings_table_size_update(value); break; + case ENABLE_PUSH: + // Only values of 0 or 1 are allowed + if (!(value == 0 or value == 1)) + { + session_data->events[source_id]->create_event(EVENT_BAD_SETTINGS_VALUE); + *session_data->infractions[source_id] += INF_BAD_SETTINGS_PUSH_VALUE; + return false; + } + break; default: break; } + return true; } #ifdef REG_TEST diff --git a/src/service_inspectors/http2_inspect/http2_settings_frame.h b/src/service_inspectors/http2_inspect/http2_settings_frame.h index 544d91f75..8ebecff11 100644 --- a/src/service_inspectors/http2_inspect/http2_settings_frame.h +++ b/src/service_inspectors/http2_inspect/http2_settings_frame.h @@ -44,7 +44,7 @@ private: void parse_settings_frame(); bool sanity_check(); - void handle_update(uint16_t id, uint32_t value); + bool handle_update(uint16_t id, uint32_t value); bool bad_frame = false; static const uint8_t SfAck = 0x01; diff --git a/src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc b/src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc index b2e7abec8..9162d3a06 100644 --- a/src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc +++ b/src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc @@ -120,8 +120,6 @@ StreamSplitter::Status Http2StreamSplitter::non_data_frame_header_checks( if (type == FT_CONTINUATION and !session_data->continuation_expected[source_id]) { - // FIXIT-E CONTINUATION frames can also follow PUSH_PROMISE frames, which - // are not currently supported *session_data->infractions[source_id] += INF_UNEXPECTED_CONTINUATION; session_data->events[source_id]->create_event( EVENT_UNEXPECTED_CONTINUATION); @@ -153,6 +151,7 @@ StreamSplitter::Status Http2StreamSplitter::non_data_scan(Http2FlowData* session switch (type) { case FT_HEADERS: + case FT_PUSH_PROMISE: if (!(frame_flags & END_HEADERS)) { session_data->continuation_expected[source_id] = true; @@ -294,7 +293,7 @@ StreamSplitter::Status Http2StreamSplitter::implement_scan(Http2FlowData* sessio scan_frame_header[source_id]); const uint32_t old_stream = session_data->current_stream[source_id]; session_data->current_stream[source_id] = - get_stream_id(session_data->scan_frame_header[source_id]); + get_stream_id_from_header(session_data->scan_frame_header[source_id]); if (session_data->continuation_expected[source_id] && type != FT_CONTINUATION) { diff --git a/src/service_inspectors/http2_inspect/http2_tables.cc b/src/service_inspectors/http2_inspect/http2_tables.cc index 4574cb114..e3265a1c2 100644 --- a/src/service_inspectors/http2_inspect/http2_tables.cc +++ b/src/service_inspectors/http2_inspect/http2_tables.cc @@ -53,6 +53,14 @@ const RuleMap Http2Module::http2_events[] = { EVENT_TRAILERS_NOT_END, "HTTP/2 trailers without END_STREAM bit" }, { EVENT_PADDING_ON_INVALID_FRAME, "padding flag set on invalid HTTP/2 frame type" }, { EVENT_PADDING_ON_EMPTY_FRAME, "padding flag set on HTTP/2 frame with zero length" }, + { EVENT_C2S_PUSH, "HTTP/2 push promise frame in c2s direction" }, + { EVENT_INVALID_PUSH_FRAME, "invalid HTTP/2 push promise frame" }, + { EVENT_BAD_PUSH_SEQUENCE, "HTTP/2 push promise frame sent at invalid time" }, + { EVENT_BAD_SETTINGS_VALUE, "invalid parameter value sent in HTTP/2 settings frame" }, + { EVENT_PUSH_WHEN_PROHIBITED, "HTTP/2 push promise frame sent when prohibited by receiver" }, + { EVENT_INVALID_PROMISED_STREAM, "HTTP/2 push promise frame with invalid promised stream id" }, + { EVENT_INVALID_STREAM_ID, "HTTP/2 stream initiated with invalid stream id" }, + { EVENT_INVALID_FLAG, "invalid flag set on HTTP/2 frame" }, { 0, nullptr } }; diff --git a/src/service_inspectors/http2_inspect/http2_utils.cc b/src/service_inspectors/http2_inspect/http2_utils.cc index f8cb32ae9..bfad7ab98 100644 --- a/src/service_inspectors/http2_inspect/http2_utils.cc +++ b/src/service_inspectors/http2_inspect/http2_utils.cc @@ -50,13 +50,15 @@ uint8_t get_frame_flags(const uint8_t* frame_header_buffer) return NO_HEADER; } -uint8_t get_stream_id(const uint8_t* frame_header_buffer) +uint32_t get_stream_id_from_header(const uint8_t* frame_header_buffer) { const uint8_t stream_id_index = 5; assert(frame_header_buffer != nullptr); - return ((frame_header_buffer[stream_id_index] & 0x7f) << 24) + - (frame_header_buffer[stream_id_index + 1] << 16) + - (frame_header_buffer[stream_id_index + 2] << 8) + - frame_header_buffer[stream_id_index + 3]; + return get_stream_id_from_buffer(frame_header_buffer + stream_id_index); + } +uint32_t get_stream_id_from_buffer(const uint8_t* buffer) +{ + return ((buffer[0] & 0x7f) << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]; +} diff --git a/src/service_inspectors/http2_inspect/http2_utils.h b/src/service_inspectors/http2_inspect/http2_utils.h index 351682c7f..0657dc896 100644 --- a/src/service_inspectors/http2_inspect/http2_utils.h +++ b/src/service_inspectors/http2_inspect/http2_utils.h @@ -35,6 +35,7 @@ uint32_t get_frame_length(const uint8_t* frame_header_buffer); uint8_t get_frame_type(const uint8_t* frame_header_buffer); uint8_t get_frame_flags(const uint8_t* frame_header_buffer); -uint8_t get_stream_id(const uint8_t* frame_header_buffer); +uint32_t get_stream_id_from_header(const uint8_t* frame_header_buffer); +uint32_t get_stream_id_from_buffer(const uint8_t* buffer); #endif