From: Mike Stepanek (mstepane) Date: Mon, 9 Dec 2019 17:08:40 +0000 (+0000) Subject: Merge pull request #1882 in SNORT/snort3 from ~THOPETER/snort3:h2i_streams to master X-Git-Tag: 3.0.0-267~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4f75735ed9db637acb2ceca66abf453e0137b036;p=thirdparty%2Fsnort3.git Merge pull request #1882 in SNORT/snort3 from ~THOPETER/snort3:h2i_streams to master Squashed commit of the following: commit 3b164411655f7ec11e66c424a3783f74c11cf11e Author: Tom Peters Date: Mon Dec 2 14:59:20 2019 -0500 http2_inspect: add Stream class --- diff --git a/src/service_inspectors/http2_inspect/CMakeLists.txt b/src/service_inspectors/http2_inspect/CMakeLists.txt index a1ddd7c8f..3d11259a0 100644 --- a/src/service_inspectors/http2_inspect/CMakeLists.txt +++ b/src/service_inspectors/http2_inspect/CMakeLists.txt @@ -22,7 +22,6 @@ set (FILE_LIST http2_huffman_state_machine.cc http2_huffman_state_machine.h http2_inspect.cc - http2_inspect_impl.cc http2_inspect.h http2_module.cc http2_module.h @@ -34,6 +33,8 @@ set (FILE_LIST http2_start_line.h http2_status_line.cc http2_status_line.h + http2_stream.cc + http2_stream.h http2_stream_splitter.cc http2_stream_splitter_impl.cc http2_stream_splitter.h diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.cc b/src/service_inspectors/http2_inspect/http2_flow_data.cc index 66be2c2d9..57540a803 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_frame.h" #include "http2_module.h" #include "http2_start_line.h" +#include "http2_stream.h" using namespace snort; using namespace Http2Enums; @@ -40,7 +41,7 @@ unsigned Http2FlowData::inspector_id = 0; uint64_t Http2FlowData::instance_count = 0; #endif -Http2FlowData::Http2FlowData() : FlowData(inspector_id) +Http2FlowData::Http2FlowData() : FlowData(inspector_id), stream(new Http2Stream(this)) { #ifdef REG_TEST seq_num = ++instance_count; @@ -74,17 +75,8 @@ Http2FlowData::~Http2FlowData() { delete infractions[k]; delete events[k]; - delete current_frame[k]; } -} -void Http2FlowData::clear_frame_data(HttpCommon::SourceId source_id) -{ - frame_in_detection = false; - continuation_expected[source_id] = false; - num_frame_headers[source_id] = 0; - scan_octets_seen[source_id] = 0; - total_bytes_in_split[source_id] = 0; - delete current_frame[source_id]; - current_frame[source_id] = nullptr; + delete stream; } + diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.h b/src/service_inspectors/http2_inspect/http2_flow_data.h index 671956df2..ff488ecc5 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.h +++ b/src/service_inspectors/http2_inspect/http2_flow_data.h @@ -57,10 +57,8 @@ public: friend class Http2SettingsFrame; friend class Http2StartLine; friend class Http2StatusLine; + friend class Http2Stream; friend class Http2StreamSplitter; - friend void implement_eval(Http2FlowData* session_data, HttpCommon::SourceId source_id); - friend bool implement_get_buf(unsigned id, Http2FlowData*, HttpCommon::SourceId, - snort::InspectionBuffer&); friend const snort::StreamBuffer implement_reassemble(Http2FlowData*, unsigned, unsigned, const uint8_t*, unsigned, uint32_t, HttpCommon::SourceId); friend snort::StreamSplitter::Status implement_scan(Http2FlowData*, const uint8_t*, uint32_t, @@ -72,7 +70,7 @@ public: protected: // 0 element refers to client frame, 1 element refers to server frame - // Reassemble() signals to eval() + // Reassemble() data to eval() uint8_t* frame_header[2] = { nullptr, nullptr }; uint32_t frame_header_size[2] = { 0, 0 }; uint8_t* frame_data[2] = { nullptr, nullptr }; @@ -80,9 +78,9 @@ protected: // Used in eval() bool frame_in_detection = false; - class Http2Frame* current_frame[2] = { nullptr, nullptr }; Http2ConnectionSettings connection_settings[2]; Http2HpackDecoder hpack_decoder[2]; + class Http2Stream* stream; // Internal to scan() bool preface[2] = { true, false }; @@ -113,8 +111,6 @@ protected: Http2Infractions* infractions[2] = { new Http2Infractions, new Http2Infractions }; Http2EventGen* events[2] = { new Http2EventGen, new Http2EventGen }; - void clear_frame_data(HttpCommon::SourceId source_id); - #ifdef REG_TEST static uint64_t instance_count; uint64_t seq_num; diff --git a/src/service_inspectors/http2_inspect/http2_inspect.cc b/src/service_inspectors/http2_inspect/http2_inspect.cc index a241bdc1b..ac04e98bf 100644 --- a/src/service_inspectors/http2_inspect/http2_inspect.cc +++ b/src/service_inspectors/http2_inspect/http2_inspect.cc @@ -22,6 +22,7 @@ #endif #include "http2_inspect.h" + #include "detection/detection_engine.h" #include "protocols/packet.h" #include "service_inspectors/http_inspect/http_common.h" @@ -30,6 +31,7 @@ #include "stream/stream.h" #include "http2_frame.h" +#include "http2_stream.h" using namespace snort; using namespace HttpCommon; @@ -79,9 +81,13 @@ bool Http2Inspect::get_buf(unsigned id, Packet* p, InspectionBuffer& b) if (!session_data->frame_in_detection) return false; - const SourceId source_id = p->is_from_client() ? SRC_CLIENT : SRC_SERVER; + const Field& buffer = session_data->stream->get_buf(id); + if (buffer.length() <= 0) + return false; - return implement_get_buf(id, session_data, source_id, b); + b.data = buffer.start(); + b.len = buffer.length(); + return true; } bool Http2Inspect::get_fp_buf(InspectionBuffer::Type /*ibt*/, Packet* /*p*/, @@ -105,14 +111,20 @@ void Http2Inspect::eval(Packet* p) if (session_data->frame_type[source_id] == FT__NONE) return; - implement_eval(session_data, source_id); + session_data->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); + + // The current frame now owns these buffers, clear them from the flow data + session_data->frame_header[source_id] = nullptr; + session_data->frame_data[source_id] = nullptr; session_data->frame_in_detection = true; #ifdef REG_TEST if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP2)) { - session_data->current_frame[source_id]->print_frame(HttpTestManager::get_output_file()); + session_data->stream->print_frame(HttpTestManager::get_output_file()); if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2)) { printf("Finished processing section from test %" PRIi64 "\n", @@ -130,8 +142,7 @@ void Http2Inspect::clear(Packet* p) if (session_data == nullptr) return; - const SourceId source_id = (p->is_from_client()) ? SRC_CLIENT : SRC_SERVER; - - session_data->clear_frame_data(source_id); + session_data->frame_in_detection = false; + session_data->stream->clear_frame(); } diff --git a/src/service_inspectors/http2_inspect/http2_inspect_impl.cc b/src/service_inspectors/http2_inspect/http2_inspect_impl.cc deleted file mode 100644 index 82a1e362a..000000000 --- a/src/service_inspectors/http2_inspect/http2_inspect_impl.cc +++ /dev/null @@ -1,55 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2018-2019 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_inspect_impl.cc author Tom Peters - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "http2_inspect.h" -#include "http2_enum.h" -#include "http2_flow_data.h" -#include "http2_frame.h" -#include "service_inspectors/http_inspect/http_common.h" - -using namespace snort; -using namespace HttpCommon; -using namespace Http2Enums; - -bool implement_get_buf(unsigned id, Http2FlowData* session_data, SourceId source_id, - InspectionBuffer& b) -{ - const Field& buffer = session_data->current_frame[source_id]->get_buf(id); - if (buffer.length() <= 0) - return false; - b.data = buffer.start(); - b.len = buffer.length(); - return true; -} - -void implement_eval(Http2FlowData* session_data, SourceId source_id) -{ - // Construct the appropriate frame class - session_data->current_frame[source_id] = Http2Frame::new_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], - session_data, source_id); - // The current frame now owns these buffers, clear them from the flow data - session_data->frame_header[source_id] = nullptr; - session_data->frame_data[source_id] = nullptr; -} diff --git a/src/service_inspectors/http2_inspect/http2_stream.cc b/src/service_inspectors/http2_inspect/http2_stream.cc new file mode 100644 index 000000000..6fed50c9c --- /dev/null +++ b/src/service_inspectors/http2_inspect/http2_stream.cc @@ -0,0 +1,65 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2019-2019 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_stream.cc author Tom Peters + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "http2_stream.h" + +using namespace HttpCommon; + +Http2Stream::Http2Stream(Http2FlowData* session_data_) : session_data(session_data_) +{ +} + +Http2Stream::~Http2Stream() +{ + delete current_frame; +} + +void Http2Stream::eval_frame(const uint8_t* header_buffer, int32_t header_len, + const uint8_t* data_buffer, int32_t data_len, SourceId source_id) +{ + delete current_frame; + current_frame = Http2Frame::new_frame(header_buffer, header_len, data_buffer, + data_len, session_data, source_id); +} + +void Http2Stream::clear_frame() +{ + delete current_frame; + current_frame = nullptr; +} + +const Field& Http2Stream::get_buf(unsigned id) +{ + if (current_frame != nullptr) + return current_frame->get_buf(id); + return Field::FIELD_NULL; +} + +#ifdef REG_TEST +void Http2Stream::print_frame(FILE* output) +{ + if (current_frame != nullptr) + current_frame->print_frame(output); +} +#endif + diff --git a/src/service_inspectors/http2_inspect/http2_stream.h b/src/service_inspectors/http2_inspect/http2_stream.h new file mode 100644 index 000000000..9e82fef4b --- /dev/null +++ b/src/service_inspectors/http2_inspect/http2_stream.h @@ -0,0 +1,47 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2019-2019 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_stream.h author Tom Peters + +#ifndef HTTP2_STREAM_H +#define HTTP2_STREAM_H + +#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 Http2Stream +{ +public: + Http2Stream(Http2FlowData* session_data_); + ~Http2Stream(); + 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); +#ifdef REG_TEST + void print_frame(FILE* output); +#endif + +private: + Http2FlowData* const session_data; + Http2Frame* current_frame = nullptr; +}; + +#endif 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 8f3142b7e..c84229519 100644 --- a/src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc +++ b/src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc @@ -220,8 +220,8 @@ StreamSplitter::Status implement_scan(Http2FlowData* session_data, const uint8_t } else { - // FIXIT-M CONTINUATION frames can also follow PUSH_PROMISE frames, which is - // not currently supported + // FIXIT-M 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); @@ -352,11 +352,16 @@ const StreamBuffer implement_reassemble(Http2FlowData* session_data, unsigned to if (flags & PKT_PDU_TAIL) { + session_data->total_bytes_in_split[source_id] = 0; + session_data->num_frame_headers[source_id] = 0; + session_data->scan_octets_seen[source_id] = 0; + // Return 0-length non-null buffer to stream which signals detection required, but don't // create pkt_data buffer frame_buf.data = (const uint8_t*)""; } session_data->frame_type[source_id] = get_frame_type(session_data->frame_header[source_id]); + return frame_buf; } diff --git a/src/service_inspectors/http2_inspect/test/CMakeLists.txt b/src/service_inspectors/http2_inspect/test/CMakeLists.txt index b2e42b223..0e166380f 100644 --- a/src/service_inspectors/http2_inspect/test/CMakeLists.txt +++ b/src/service_inspectors/http2_inspect/test/CMakeLists.txt @@ -1,13 +1,3 @@ -add_cpputest( http2_stream_splitter_impl_test - SOURCES - ../http2_flow_data.cc - ../http2_hpack_dynamic_table.cc - ../http2_hpack_table.cc - ../http2_stream_splitter_impl.cc - ../http2_module.cc - ../http2_tables.cc - ../../../framework/module.cc -) add_cpputest( http2_hpack_int_decode_test SOURCES ../http2_hpack_int_decode.cc diff --git a/src/service_inspectors/http2_inspect/test/http2_flow_data_test.h b/src/service_inspectors/http2_inspect/test/http2_flow_data_test.h deleted file mode 100644 index ab902d2cc..000000000 --- a/src/service_inspectors/http2_inspect/test/http2_flow_data_test.h +++ /dev/null @@ -1,74 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2018-2019 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_flow_data_test.h author Tom Peters - -#ifndef HTTP2_FLOW_DATA_TEST_H -#define HTTP2_FLOW_DATA_TEST_H - -#include "service_inspectors/http_inspect/http_common.h" -//#include "service_inspectors/http2_inspect/http2_enum.h" -#include "service_inspectors/http2_inspect/http2_flow_data.h" -#include "service_inspectors/http2_inspect/http2_module.h" - -// Stubs whose sole purpose is to make the test code link -snort::FlowData::FlowData(unsigned u, Inspector* ph) : next(nullptr), prev(nullptr), handler(ph), id(u) {} -snort::FlowData::~FlowData() = default; -unsigned snort::FlowData::flow_data_id = 0; -void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { } -void show_stats(PegCount*, const PegInfo*, const IndexVec&, const char*, FILE*) { } - -class Http2FlowDataTest : public Http2FlowData -{ -public: - bool get_preface(HttpCommon::SourceId source_id) { return preface[source_id]; } - void set_preface(bool value, HttpCommon::SourceId source_id) { preface[source_id] = value; } - bool get_num_frame_headers(HttpCommon::SourceId source_id) { return num_frame_headers[source_id]; } - void set_num_frame_headers(bool value, HttpCommon::SourceId source_id) - { num_frame_headers[source_id] = value; } - uint8_t* get_frame_header(HttpCommon::SourceId source_id) { return frame_header[source_id]; } - void set_frame_header(uint8_t* value, uint32_t length, HttpCommon::SourceId source_id) - { frame_header[source_id] = value; frame_header_size[source_id] = length; } - uint8_t* get_scan_frame_header(HttpCommon::SourceId source_id) - { return scan_frame_header[source_id]; } - uint8_t* get_frame_data(HttpCommon::SourceId source_id) { return frame_data[source_id]; } - void set_frame_data(uint8_t* value, HttpCommon::SourceId source_id) - { frame_data[source_id] = value; } - uint32_t get_frame_data_size(HttpCommon::SourceId source_id) - { return frame_data_offset[source_id]; } - void set_frame_data_size(uint32_t value, HttpCommon::SourceId source_id) - { frame_data_size[source_id] = value; } - uint32_t get_leftover_data(HttpCommon::SourceId source_id) { return leftover_data[source_id]; } - void set_leftover_data(uint32_t value, HttpCommon::SourceId source_id) - { leftover_data[source_id] = value; } - void set_total_bytes_in_split(uint32_t value, HttpCommon::SourceId source_id) - { total_bytes_in_split[source_id] = value; } - void set_octets_before_first_header(uint32_t value, HttpCommon::SourceId source_id) - { octets_before_first_header[source_id] = value; } - void cleanup() - { - for (int k = 0; k < 2; k++) - { - delete[] frame_header[k]; - delete[] frame_data[k]; - } - } -}; - -#endif - diff --git a/src/service_inspectors/http2_inspect/test/http2_stream_splitter_impl_test.cc b/src/service_inspectors/http2_inspect/test/http2_stream_splitter_impl_test.cc deleted file mode 100644 index 1b825720a..000000000 --- a/src/service_inspectors/http2_inspect/test/http2_stream_splitter_impl_test.cc +++ /dev/null @@ -1,288 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2018-2019 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_stream_splitter_test.cc author Tom Peters -// unit test main - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - - -#include "protocols/packet.h" -#include "service_inspectors/http_inspect/http_common.h" -#include "service_inspectors/http_inspect/http_test_manager.h" -#include "service_inspectors/http2_inspect/http2_enum.h" -#include "service_inspectors/http2_inspect/http2_flow_data.h" -#include "service_inspectors/http2_inspect/http2_stream_splitter.h" - -#include "http2_flow_data_test.h" - -#include -#include -#include - -using namespace snort; -using namespace HttpCommon; -using namespace Http2Enums; - -// Stubs whose sole purpose is to make the test code link -unsigned HttpTestManager::test_input = IN_NONE; -unsigned HttpTestManager::test_output = IN_NONE; -FILE* HttpTestManager::test_out = nullptr ; -int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; } -void Field::set(int, unsigned char const*, bool) {} - -#ifdef REG_TEST -void Field::print(_IO_FILE*, char const*) const {} -#endif - -TEST_GROUP(http2_scan_test) -{ - Http2FlowDataTest* session_data = nullptr; - uint32_t flush_offset = 0; - - void setup() override - { - session_data = new Http2FlowDataTest(); - CHECK(session_data != nullptr); - } - - void teardown() override - { - delete session_data; - } -}; - -TEST(http2_scan_test, basic_with_header) -{ - session_data->set_preface(false, SRC_CLIENT); - const StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00" "0123456789ABCDEFG", - 26, &flush_offset, SRC_CLIENT); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 19); - CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 1); -} - -TEST(http2_scan_test, basic_with_header_s2c) -{ - const StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00" "0123456789ABCDEFG", - 26, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 19); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1); -} - -TEST(http2_scan_test, header_without_data) -{ - session_data->set_preface(false, SRC_CLIENT); - const StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00", - 9, &flush_offset, SRC_CLIENT); - CHECK(result == StreamSplitter::SEARCH); - CHECK(flush_offset == 0); - CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 1); -} - -TEST(http2_scan_test, preface_and_more) -{ - const StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\nABCDEFGHIJKLMNOPQRSTUVWXYZ", - 50, &flush_offset, SRC_CLIENT); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 24); - CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 0); -} - -TEST(http2_scan_test, preface_exactly) -{ - const StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", - 24, &flush_offset, SRC_CLIENT); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 24); - CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 0); -} - -TEST(http2_scan_test, short_input) -{ - session_data->set_preface(false, SRC_SERVER); - StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"\x00\x00\x10", - 3, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::SEARCH); - result = implement_scan(session_data, (const uint8_t*)"\x04\x05\x06", 3, &flush_offset, - SRC_SERVER); - CHECK(result == StreamSplitter::SEARCH); - result = implement_scan(session_data, (const uint8_t*)"\x07\x08\x09" "0123456789ABCDEF", 19, &flush_offset, - SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 19); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1); - CHECK(memcmp(session_data->get_scan_frame_header(SRC_SERVER), - "\x00\x00\x10\x04\x05\x06\x07\x08\x09", 9) == 0); -} - -TEST(http2_scan_test, oversize_non_data_frame) -{ - session_data->set_preface(false, SRC_CLIENT); - const StreamSplitter::Status result = implement_scan(session_data, - (const uint8_t*)"\x00\xF9\x1C\x01" "12345678901234567", - 21, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::ABORT); -} - -TEST(http2_scan_test, maximum_frame) -{ - uint8_t data[63870] = { 'A' }; - memcpy(data,"\x00\xF9\x1B\x04", 4); - const StreamSplitter::Status result = implement_scan(session_data, - data, 63780, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 63780); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1); -} - -TEST(http2_scan_test, data_sections) -{ - uint8_t data[DATA_SECTION_SIZE+9] ={ 'A' }; - memcpy(data,"\x01\x21\x3C\x00\x00\x00\x00\x00\x00", 9); - StreamSplitter::Status result = implement_scan(session_data, - data, DATA_SECTION_SIZE + 9, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == DATA_SECTION_SIZE + 9); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1); - CHECK(session_data->get_leftover_data(SRC_SERVER) == 0xE13C); - result = implement_scan(session_data, - data, DATA_SECTION_SIZE, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == DATA_SECTION_SIZE); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0); - result = implement_scan(session_data, - data, DATA_SECTION_SIZE, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == DATA_SECTION_SIZE); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0); - result = implement_scan(session_data, - data, DATA_SECTION_SIZE, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == DATA_SECTION_SIZE); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0); - result = implement_scan(session_data, - data, 8508, &flush_offset, SRC_SERVER); - CHECK(result == StreamSplitter::FLUSH); - CHECK(flush_offset == 8508); - CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0); - CHECK(session_data->get_leftover_data(SRC_SERVER) == 0); -} - -TEST_GROUP(http2_reassemble_test) -{ - Http2FlowDataTest* session_data = nullptr; - - void setup() override - { - session_data = new Http2FlowDataTest(); - CHECK(session_data != nullptr); - } - - void teardown() override - { - session_data->cleanup(); - delete session_data; - } -}; - -TEST(http2_reassemble_test, basic_with_header) -{ - session_data->set_num_frame_headers(1, SRC_CLIENT); - session_data->set_total_bytes_in_split(19, SRC_CLIENT); - implement_reassemble(session_data, 19, 0, - (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00" "0123456789", - 19, PKT_PDU_TAIL, SRC_CLIENT); - CHECK(session_data->get_frame_data_size(SRC_CLIENT) == 10); - CHECK(memcmp(session_data->get_frame_data(SRC_CLIENT), "0123456789", 10) == 0); -} - -TEST(http2_reassemble_test, basic_with_header_s2c) -{ - session_data->set_num_frame_headers(1, SRC_SERVER); - session_data->set_total_bytes_in_split(19, SRC_SERVER); - implement_reassemble(session_data, 19, 0, - (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00" "0123456789", - 19, PKT_PDU_TAIL, SRC_SERVER); - CHECK(session_data->get_frame_data_size(SRC_SERVER) == 10); - CHECK(memcmp(session_data->get_frame_data(SRC_SERVER), "0123456789", 10) == 0); -} - -TEST(http2_reassemble_test, basic_without_header) -{ - session_data->set_num_frame_headers(0, SRC_CLIENT); - session_data->set_octets_before_first_header(24, SRC_CLIENT); - session_data->set_total_bytes_in_split(24, SRC_CLIENT); - implement_reassemble(session_data, 24, 0, - (const uint8_t*)"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", - 24, PKT_PDU_TAIL, SRC_CLIENT); - CHECK(session_data->get_frame_data_size(SRC_CLIENT) == 24); - CHECK(memcmp(session_data->get_frame_data(SRC_CLIENT), "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0); -} - -TEST(http2_reassemble_test, basic_three_pieces) -{ - session_data->set_num_frame_headers(1, SRC_CLIENT); - session_data->set_total_bytes_in_split(19, SRC_CLIENT); - StreamBuffer buffer = implement_reassemble(session_data, 19, 0, - (const uint8_t*)"\x00\x00\x0A\x02\x00\x00", - 6, 0, SRC_CLIENT); - CHECK(buffer.length == 0); - CHECK(session_data->get_frame_data_size(SRC_CLIENT) == 0); - implement_reassemble(session_data, 19, 6, - (const uint8_t*)"\x00\x00\x00" "01234", - 8, 0, SRC_CLIENT); - buffer = implement_reassemble(session_data, 19, 14, - (const uint8_t*)"56789", - 5, PKT_PDU_TAIL, SRC_CLIENT); - CHECK(buffer.length == 0); - CHECK(session_data->get_frame_data_size(SRC_CLIENT) == 10); - CHECK(memcmp(session_data->get_frame_data(SRC_CLIENT), "0123456789", 10) == 0); -} - -TEST(http2_reassemble_test, basic_without_header_two_pieces) -{ - session_data->set_num_frame_headers(0, SRC_CLIENT); - session_data->set_octets_before_first_header(24, SRC_CLIENT); - session_data->set_total_bytes_in_split(24, SRC_CLIENT); - implement_reassemble(session_data, 24, 0, - (const uint8_t*)"P", - 1, 0, SRC_CLIENT); - CHECK(session_data->get_frame_data_size(SRC_CLIENT) == 1); - CHECK(memcmp(session_data->get_frame_data(SRC_CLIENT), "P", 1) == 0); - implement_reassemble(session_data, 24, 1, - (const uint8_t*)"RI * HTTP/2.0\r\n\r\nSM\r\n\r\n", - 23, PKT_PDU_TAIL, SRC_CLIENT); - CHECK(session_data->get_frame_data_size(SRC_CLIENT) == 24); - CHECK(memcmp(session_data->get_frame_data(SRC_CLIENT), "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", 24) == 0); -} - -int main(int argc, char** argv) -{ - return CommandLineTestRunner::RunAllTests(argc, argv); -} -