From: Mike Stepanek (mstepane) Date: Thu, 19 Nov 2020 14:18:01 +0000 (+0000) Subject: Merge pull request #2613 in SNORT/snort3 from ~KATHARVE/snort3:h2i_headers_close... X-Git-Tag: 3.0.3-6~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=388fad6a00d1802d78c10269de8310047ceee607;p=thirdparty%2Fsnort3.git Merge pull request #2613 in SNORT/snort3 from ~KATHARVE/snort3:h2i_headers_close to master Squashed commit of the following: commit 85d3938fcd179b22ee2bceac441be1b1d9049738 Author: Katura Harvey Date: Thu Oct 29 12:39:05 2020 -0400 http2_inspect: handle connection close during headers frames --- diff --git a/src/service_inspectors/http2_inspect/http2_enum.h b/src/service_inspectors/http2_inspect/http2_enum.h index 3ece39745..938a56c9b 100644 --- a/src/service_inspectors/http2_inspect/http2_enum.h +++ b/src/service_inspectors/http2_inspect/http2_enum.h @@ -53,21 +53,21 @@ enum PEG_COUNT { PEG_FLOW = 0, PEG_CONCURRENT_SESSIONS, PEG_MAX_CONCURRENT_SESSI enum EventSid { EVENT__NONE = -1, - EVENT_INT_DECODE_FAILURE = 1, + EVENT_INVALID_FLAG = 1, EVENT_INT_LEADING_ZEROS = 2, - EVENT_STRING_DECODE_FAILURE = 3, + EVENT_INVALID_STREAM_ID = 3, EVENT_MISSING_CONTINUATION = 4, EVENT_UNEXPECTED_CONTINUATION = 5, EVENT_MISFORMATTED_HTTP2 = 6, EVENT_PREFACE_MATCH_FAILURE = 7, EVENT_REQUEST_WITHOUT_REQUIRED_FIELD = 8, EVENT_RESPONSE_WITHOUT_STATUS = 9, - EVENT_INVALID_HEADER = 10, + EVENT_CONNECT_WITH_SCHEME_OR_PATH = 10, EVENT_SETTINGS_FRAME_ERROR = 11, EVENT_SETTINGS_FRAME_UNKN_PARAM = 12, EVENT_FRAME_SEQUENCE = 13, EVENT_DYNAMIC_TABLE_OVERFLOW = 14, - EVENT_INVALID_STARTLINE = 15, + EVENT_INVALID_PROMISED_STREAM = 15, EVENT_PADDING_LEN = 16, EVENT_PSEUDO_HEADER_AFTER_REGULAR_HEADER = 17, EVENT_PSEUDO_HEADER_IN_TRAILERS = 18, @@ -80,9 +80,6 @@ enum EventSid 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 }; @@ -105,7 +102,7 @@ enum Infraction INF_C2S_PUSH = 12, INF_INVALID_PSEUDO_HEADER = 13, INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER = 14, - INF_PSEUDO_HEADER_URI_FORM_MISMATCH = 15, + INF_REQUEST_WITHOUT_REQUIRED_FIELD = 15, INF_RESPONSE_WITHOUT_STATUS = 16, INF_HPACK_INDEX_OUT_OF_BOUNDS = 17, INF_INVALID_SETTINGS_FRAME = 18, @@ -129,6 +126,10 @@ enum Infraction INF_INVALID_PROMISED_STREAM = 36, INF_INVALID_STREAM_ID = 37, INF_INVALID_FLAG = 38, + INF_TRUNCATED_HEADER_LINE = 39, + INF_REQUEST_WITHOUT_METHOD = 40, + INF_CONNECT_WITHOUT_AUTHORITY = 41, + INF_CONNECT_WITH_SCHEME_OR_PATH = 42, INF__MAX_VALUE }; diff --git a/src/service_inspectors/http2_inspect/http2_flow_data.h b/src/service_inspectors/http2_inspect/http2_flow_data.h index 72b11bcb9..da25a60d4 100644 --- a/src/service_inspectors/http2_inspect/http2_flow_data.h +++ b/src/service_inspectors/http2_inspect/http2_flow_data.h @@ -99,6 +99,7 @@ public: class Http2Stream* get_processing_stream(); uint32_t get_processing_stream_id() const; void set_processing_stream_id(const HttpCommon::SourceId source_id); + bool is_processing_partial_header() const { return processing_partial_header; } Http2HpackDecoder* get_hpack_decoder(const HttpCommon::SourceId source_id) { return &hpack_decoder[source_id]; } @@ -172,6 +173,7 @@ protected: uint8_t frame_type[2] = { Http2Enums::FT__NONE, Http2Enums::FT__NONE }; bool abort_flow[2] = { false, false }; std::queue frame_lengths[2]; + bool processing_partial_header = false; // Internal to reassemble() uint32_t frame_header_offset[2] = { 0, 0 }; diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame.cc b/src/service_inspectors/http2_inspect/http2_headers_frame.cc index 69f32b586..70d0b1f75 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame.cc @@ -84,7 +84,14 @@ void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceI http1_header = hpack_decoder->get_decoded_headers(decoded_headers); StreamBuffer stream_buf; + // http_inspect scan() of headers + // If we're processing a header truncated immediately after the start line, http1_header will + // be empty. Don't call scan on the empty buffer because it will create a cutter and the check + // for this condition in HI::finish() will fail. Truncated headers with non-empty http1_header + // buffers are still sent to HI::scan(). + assert ((http1_header.length() > 0) or session_data->is_processing_partial_header()); + if (http1_header.length() > 0) { uint32_t flush_offset; Http2DummyPacket dummy_pkt; @@ -93,11 +100,19 @@ void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceI const StreamSplitter::Status header_scan_result = session_data->hi_ss[hi_source_id]->scan(&dummy_pkt, http1_header.start(), http1_header.length(), unused, &flush_offset); - assert(header_scan_result == StreamSplitter::FLUSH); + assert((session_data->is_processing_partial_header() and + (header_scan_result == StreamSplitter::SEARCH)) or + ((!session_data->is_processing_partial_header() and + (header_scan_result == StreamSplitter::FLUSH)))); + assert(session_data->is_processing_partial_header() ^ + ((int64_t)flush_offset == http1_header.length())); UNUSED(header_scan_result); - assert((int64_t)flush_offset == http1_header.length()); } + // If this is a truncated headers frame, call http_inspect finish() + if (session_data->is_processing_partial_header()) + session_data->hi_ss[hi_source_id]->finish(session_data->flow); + // http_inspect reassemble() of headers { unsigned copied; @@ -117,15 +132,10 @@ void Http2HeadersFrame::process_decoded_headers(HttpFlowData* http_flow, SourceI dummy_pkt.data = stream_buf.data; dummy_pkt.xtradata_mask = 0; session_data->hi->eval(&dummy_pkt); - // Following if condition won't get exercised until finish() (during Headers) is - // implemented for H2I. Without finish() H2I will only flush complete header blocks. Below - // ABORT is only possible if tcp connection closes unexpectedly in middle of a header. if (http_flow->get_type_expected(hi_source_id) == HttpEnums::SEC_ABORT) { - *session_data->infractions[source_id] += INF_INVALID_HEADER; - session_data->events[source_id]->create_event(EVENT_INVALID_HEADER); - stream->set_state(source_id, STREAM_ERROR); - return; + assert(session_data->is_processing_partial_header()); + stream->set_state(hi_source_id, STREAM_ERROR); } detection_required = dummy_pkt.is_detection_required(); xtradata_mask = dummy_pkt.xtradata_mask; diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc b/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc index f28db8f3c..af059d423 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_header.cc @@ -57,17 +57,18 @@ Http2HeadersFrameHeader::Http2HeadersFrameHeader(const uint8_t* header_buffer, 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; + if (!(*session_data->infractions[source_id] & INF_TRUNCATED_HEADER_LINE)) + { + session_data->abort_flow[source_id] = true; + session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2); + return; + } } // process start line - if (!start_line_generator->generate_start_line(start_line)) + if (!start_line_generator->generate_start_line(start_line, are_pseudo_headers_complete())) { - // FIXIT-E should only be a stream error - session_data->abort_flow[source_id] = true; - session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2); + stream->set_state(source_id, STREAM_ERROR); } } 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 b73796400..df4315b7b 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_trailer.cc @@ -59,8 +59,11 @@ Http2HeadersFrameTrailer::Http2HeadersFrameTrailer(const uint8_t* header_buffer, if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() - hpack_headers_offset, decoded_headers, nullptr, true)) { - session_data->abort_flow[source_id] = true; - session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2); + if (!(*session_data->infractions[source_id] & INF_TRUNCATED_HEADER_LINE)) + { + session_data->abort_flow[source_id] = true; + session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2); + } } } @@ -86,9 +89,8 @@ void Http2HeadersFrameTrailer::analyze_http1() if (http_flow->get_type_expected(source_id) != HttpEnums::SEC_TRAILER) { - // If there was no unflushed data on this stream when the trailers arrived, http_inspect - // will not yet be expecting trailers. Flush empty buffer through scan, reassemble, and - // eval to prepare http_inspect for trailers. + // http_inspect is not yet expecting trailers. Flush empty buffer through scan, reassemble, + // and eval to prepare http_inspect for trailers. assert(http_flow->get_type_expected(source_id) == HttpEnums::SEC_BODY_H2); stream->finish_msg_body(source_id, true, true); // calls http_inspect scan() diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc index 646fcbbe9..5ce237eb4 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc @@ -92,8 +92,6 @@ bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow session_data->hi->eval(&dummy_pkt); if (http_flow->get_type_expected(hi_source_id) != HttpEnums::SEC_HEADER) { - *session_data->infractions[source_id] += INF_INVALID_STARTLINE; - session_data->events[source_id]->create_event(EVENT_INVALID_STARTLINE); stream->set_state(hi_source_id, STREAM_ERROR); return false; } @@ -102,6 +100,14 @@ bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow return true; } +// If we are not processing a truncated headers frame or we have seen a non-pseudoheader, we know +// we've seen all the (valid) pseudoheaders in the frame. Otherwise we could be missing some due +// to truncation +bool Http2HeadersFrameWithStartline::are_pseudo_headers_complete() +{ + return !session_data->is_processing_partial_header() or + !hpack_decoder->are_pseudo_headers_allowed(); +} #ifdef REG_TEST void Http2HeadersFrameWithStartline::print_frame(FILE* output) diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h index f759496b7..845a20898 100644 --- a/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h +++ b/src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.h @@ -47,6 +47,7 @@ protected: Http2HeadersFrame(header_buffer, header_len, data_buffer, data_len, ssn_data, src_id, stream_) { } bool process_start_line(HttpFlowData*& http_flow, HttpCommon::SourceId hi_source_id); + bool are_pseudo_headers_complete(); Http2StartLine* start_line_generator = nullptr; Field start_line; diff --git a/src/service_inspectors/http2_inspect/http2_hpack.cc b/src/service_inspectors/http2_inspect/http2_hpack.cc index 1b2841c60..5f15828a9 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack.cc +++ b/src/service_inspectors/http2_inspect/http2_hpack.cc @@ -27,6 +27,7 @@ #include "service_inspectors/http_inspect/http_test_manager.h" #include "http2_enum.h" +#include "http2_flow_data.h" #include "http2_start_line.h" using namespace HttpCommon; @@ -66,7 +67,8 @@ bool Http2HpackDecoder::decode_string_literal(const uint8_t* encoded_header_buff bytes_consumed = 0; if (!decode_string.translate(encoded_header_buffer, encoded_header_length, bytes_consumed, - decoded_header_buffer, decoded_header_length, bytes_written, events, infractions)) + decoded_header_buffer, decoded_header_length, bytes_written, events, infractions, + session_data->is_processing_partial_header())) { return false; } @@ -84,7 +86,7 @@ const HpackTableEntry* Http2HpackDecoder::get_hpack_table_entry( bytes_consumed = 0; if (!decode_int.translate(encoded_header_buffer, encoded_header_length, bytes_consumed, - index, events, infractions)) + index, events, infractions, session_data->is_processing_partial_header())) { return nullptr; } @@ -235,7 +237,8 @@ bool Http2HpackDecoder::handle_dynamic_size_update(const uint8_t* encoded_header bytes_consumed = 0; if (!decode_int5.translate(encoded_header_buffer, encoded_header_length, - encoded_bytes_consumed, decoded_int, events, infractions)) + encoded_bytes_consumed, decoded_int, events, infractions, + session_data->is_processing_partial_header())) { return false; } @@ -365,8 +368,10 @@ bool Http2HpackDecoder::decode_headers(const uint8_t* encoded_headers, decoded_headers_size += line_bytes_written; } - // Write the last CRLF to end the header - if (success) + // Write the last CRLF to end the header. A truncated header may not have encountered an error + // if the truncation is between header lines, but still shouldn't complete the header block + // with the final CRLF. + if (success and !session_data->is_processing_partial_header()) { success = write_decoded_headers((const uint8_t*)"\r\n", 2, decoded_headers + decoded_headers_size, MAX_OCTETS - decoded_headers_size, line_bytes_written); diff --git a/src/service_inspectors/http2_inspect/http2_hpack.h b/src/service_inspectors/http2_inspect/http2_hpack.h index e7f2a5f6f..aa95855a8 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack.h +++ b/src/service_inspectors/http2_inspect/http2_hpack.h @@ -21,6 +21,8 @@ #define HTTP2_HPACK_H #include "service_inspectors/http_inspect/http_common.h" +#include "utils/event_gen.h" +#include "utils/infractions.h" #include "http2_hpack_int_decode.h" #include "http2_hpack_string_decode.h" @@ -30,6 +32,10 @@ class Field; class Http2FlowData; class Http2StartLine; +using Http2Infractions = Infractions; +using Http2EventGen = EventGen; + // This class implements HPACK decompression. One instance is required in each direction for each // HTTP/2 flow class Http2HpackDecoder @@ -37,7 +43,8 @@ class Http2HpackDecoder public: Http2HpackDecoder(Http2FlowData* flow_data, HttpCommon::SourceId src_id, Http2EventGen* const _events, Http2Infractions* const _infractions) : - events(_events), infractions(_infractions), decode_table(flow_data, src_id) { } + session_data(flow_data), events(_events), infractions(_infractions), + decode_table(flow_data, src_id) { } bool decode_headers(const uint8_t* encoded_headers, const uint32_t encoded_headers_length, uint8_t* decoded_headers, Http2StartLine* start_line, bool trailers); bool write_decoded_headers(const uint8_t* in_buffer, const uint32_t in_length, @@ -76,11 +83,13 @@ public: const Field* get_start_line(); Field get_decoded_headers(const uint8_t* const decoded_headers); HpackIndexTable* get_decode_table() { return &decode_table; } + bool are_pseudo_headers_allowed() { return pseudo_headers_allowed; } private: Http2StartLine* start_line; bool pseudo_headers_allowed; uint32_t decoded_headers_size; + Http2FlowData* session_data; Http2EventGen* const events; Http2Infractions* const infractions; diff --git a/src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc b/src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc index 289698cc0..8ac3f52ba 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc +++ b/src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc @@ -37,15 +37,17 @@ Http2HpackIntDecode::Http2HpackIntDecode(uint8_t prefix) : prefix_mask(((uint16_ bool Http2HpackIntDecode::translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed, uint64_t& result, Http2EventGen* const events, - Http2Infractions* const infractions) const + Http2Infractions* const infractions, bool partial_header) const { bytes_consumed = 0; result = 0; if (in_len == 0) { - *infractions += INF_INT_EMPTY_BUFF; - events->create_event(EVENT_INT_DECODE_FAILURE); + if (!partial_header) + *infractions += INF_INT_EMPTY_BUFF; + else + *infractions += INF_TRUNCATED_HEADER_LINE; return false; } @@ -62,8 +64,10 @@ bool Http2HpackIntDecode::translate(const uint8_t* in_buff, const uint32_t in_le { if (bytes_consumed >= in_len) { - *infractions += INF_INT_MISSING_BYTES; - events->create_event(EVENT_INT_DECODE_FAILURE); + if (!partial_header) + *infractions += INF_INT_MISSING_BYTES; + else + *infractions += INF_TRUNCATED_HEADER_LINE; return false; } byte = in_buff[bytes_consumed++]; @@ -75,7 +79,6 @@ bool Http2HpackIntDecode::translate(const uint8_t* in_buff, const uint32_t in_le ((result + ((uint64_t)(byte & VAL_MASK) << multiplier) + prefix_mask) < result)) { *infractions += INF_INT_OVERFLOW; - events->create_event(EVENT_INT_DECODE_FAILURE); return false; } } diff --git a/src/service_inspectors/http2_inspect/http2_hpack_int_decode.h b/src/service_inspectors/http2_inspect/http2_hpack_int_decode.h index f4ae9732a..0966ff553 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack_int_decode.h +++ b/src/service_inspectors/http2_inspect/http2_hpack_int_decode.h @@ -35,7 +35,8 @@ class Http2HpackIntDecode public: Http2HpackIntDecode(uint8_t prefix); bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed, - uint64_t& result, Http2EventGen* const events, Http2Infractions* const infractions) const; + uint64_t& result, Http2EventGen* const events, Http2Infractions* const infractions, + bool partial_header) const; private: const uint8_t prefix_mask; diff --git a/src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc b/src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc index 7dabf1428..e9c7e33d5 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc +++ b/src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc @@ -38,15 +38,17 @@ static const uint8_t min_decode_len[HUFFMAN_LOOKUP_MAX + 1] = bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, - Http2EventGen* const events, Http2Infractions* const infractions) const + Http2EventGen* const events, Http2Infractions* const infractions, bool partial_header) const { bytes_consumed = 0; bytes_written = 0; if (in_len == 0) { - *infractions += INF_STRING_EMPTY_BUFF; - events->create_event(EVENT_STRING_DECODE_FAILURE); + if (!partial_header) + *infractions += INF_STRING_EMPTY_BUFF; + else + *infractions += INF_TRUNCATED_HEADER_LINE; return false; } @@ -54,13 +56,16 @@ bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in // Get length uint64_t encoded_len; - if (!decode7.translate(in_buff, in_len, bytes_consumed, encoded_len, events, infractions)) + if (!decode7.translate(in_buff, in_len, bytes_consumed, encoded_len, events, infractions, + partial_header)) return false; if (encoded_len > (uint64_t)(in_len - bytes_consumed)) { - *infractions += INF_STRING_MISSING_BYTES; - events->create_event(EVENT_STRING_DECODE_FAILURE); + if (!partial_header) + *infractions += INF_STRING_MISSING_BYTES; + else + *infractions += INF_TRUNCATED_HEADER_LINE; return false; } @@ -69,20 +74,19 @@ bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in if (!isHuffman) return get_string(in_buff, encoded_len, bytes_consumed, out_buff, out_len, bytes_written, - events, infractions); + infractions); return get_huffman_string(in_buff, encoded_len, bytes_consumed, out_buff, out_len, - bytes_written, events, infractions); + bytes_written, infractions); } bool Http2HpackStringDecode::get_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, - Http2EventGen* const events, Http2Infractions* const infractions) const + Http2Infractions* const infractions) const { if (encoded_len > out_len) { *infractions += INF_DECODED_HEADER_BUFF_OUT_OF_SPACE; - events->create_event(EVENT_MISFORMATTED_HTTP2); return false; } @@ -141,7 +145,7 @@ bool Http2HpackStringDecode::get_next_byte(const uint8_t* in_buff, const uint32_ bool Http2HpackStringDecode::get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, - Http2EventGen* const events, Http2Infractions* const infractions) const + Http2Infractions* const infractions) const { const uint32_t last_encoded_byte = bytes_consumed + encoded_len; uint8_t byte; @@ -155,7 +159,6 @@ bool Http2HpackStringDecode::get_huffman_string(const uint8_t* in_buff, const ui if (max_length > out_len) { *infractions += INF_DECODED_HEADER_BUFF_OUT_OF_SPACE; - events->create_event(EVENT_STRING_DECODE_FAILURE); return false; } @@ -190,9 +193,7 @@ bool Http2HpackStringDecode::get_huffman_string(const uint8_t* in_buff, const ui case HUFFMAN_FAILURE: *infractions += INF_HUFFMAN_DECODED_EOS; - events->create_event(EVENT_STRING_DECODE_FAILURE); return false; - break; default: break; @@ -229,14 +230,12 @@ bool Http2HpackStringDecode::get_huffman_string(const uint8_t* in_buff, const ui if (byte != 0xff) { *infractions += INF_HUFFMAN_BAD_PADDING; - events->create_event(EVENT_STRING_DECODE_FAILURE); return false; } } else if (result.state != HUFFMAN_MATCH) { *infractions += INF_HUFFMAN_INCOMPLETE_CODE_PADDING; - events->create_event(EVENT_STRING_DECODE_FAILURE); return false; } diff --git a/src/service_inspectors/http2_inspect/http2_hpack_string_decode.h b/src/service_inspectors/http2_inspect/http2_hpack_string_decode.h index 7869ec377..7e5a2934a 100644 --- a/src/service_inspectors/http2_inspect/http2_hpack_string_decode.h +++ b/src/service_inspectors/http2_inspect/http2_hpack_string_decode.h @@ -33,15 +33,16 @@ public: Http2HpackStringDecode() : decode7(7) { } bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, - Http2EventGen* const events, Http2Infractions* const infractions) const; + Http2EventGen* const events, Http2Infractions* const infractions, + bool partial_header) const; private: bool get_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed, - uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, Http2EventGen* const - events, Http2Infractions* const infractions) const; + uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, + Http2Infractions* const infractions) const; bool get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& - bytes_written, Http2EventGen* const events, Http2Infractions* const infractions) const; + bytes_written, Http2Infractions* const infractions) const; bool get_next_byte(const uint8_t* in_buff, const uint32_t last_byte, uint32_t& bytes_consumed, uint8_t& cur_bit, uint8_t match_len, uint8_t& byte, bool& another_search) const; diff --git a/src/service_inspectors/http2_inspect/http2_inspect.cc b/src/service_inspectors/http2_inspect/http2_inspect.cc index 8d4bbd7a2..b812a80bb 100644 --- a/src/service_inspectors/http2_inspect/http2_inspect.cc +++ b/src/service_inspectors/http2_inspect/http2_inspect.cc @@ -184,6 +184,7 @@ void Http2Inspect::clear(Packet* p) stream->clear_frame(); session_data->stream_in_hi = NO_STREAM_ID; session_data->processing_stream_id = NO_STREAM_ID; + session_data->processing_partial_header = false; } #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 index 46c23e73a..35222c756 100644 --- a/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc +++ b/src/service_inspectors/http2_inspect/http2_push_promise_frame.cc @@ -76,9 +76,11 @@ Http2PushPromiseFrame::Http2PushPromiseFrame(const uint8_t* header_buffer, 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; + if (!(*session_data->infractions[source_id] & INF_TRUNCATED_HEADER_LINE)) + { + session_data->abort_flow[source_id] = true; + session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2); + } } } @@ -116,7 +118,7 @@ bool Http2PushPromiseFrame::valid_sequence(Http2Enums::StreamState) void Http2PushPromiseFrame::analyze_http1() { - if (!start_line_generator->generate_start_line(start_line)) + if (!start_line_generator->generate_start_line(start_line, are_pseudo_headers_complete())) { // can't send request or push-promise headers to http_inspect, but response will still // be processed diff --git a/src/service_inspectors/http2_inspect/http2_request_line.cc b/src/service_inspectors/http2_inspect/http2_request_line.cc index b1351502f..7e3fb9e2a 100644 --- a/src/service_inspectors/http2_inspect/http2_request_line.cc +++ b/src/service_inspectors/http2_inspect/http2_request_line.cc @@ -77,19 +77,23 @@ void Http2RequestLine::process_pseudo_header(const Field& name, const Field& val } // Select the appropriate URI form based on the provided pseudo-headers and generate the start line -bool Http2RequestLine::generate_start_line(Field& start_line) +bool Http2RequestLine::generate_start_line(Field& start_line, bool pseudo_headers_complete) { uint32_t bytes_written = 0; - // Asterisk form - used for OPTIONS requests - if (path.length() > 0 and path.start()[0] == '*') + if (method.length() <= 0) { - if (method.length() <= 0) + if (pseudo_headers_complete) { - *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH; + *infractions += INF_REQUEST_WITHOUT_METHOD; events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD); - return false; } + return false; + } + + // Asterisk form - used for OPTIONS requests + if (path.length() > 0 and path.start()[0] == '*') + { start_line_length = method.length() + path.length() + http_version_length + NUM_REQUEST_LINE_EXTRA_CHARS; start_line_buffer = new uint8_t[start_line_length]; @@ -113,15 +117,18 @@ bool Http2RequestLine::generate_start_line(Field& start_line) // FIXIT-L May want to be more lenient than RFC on generating start line if (authority.length() <= 0) { - *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH; - events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD); + if (pseudo_headers_complete) + { + *infractions += INF_CONNECT_WITHOUT_AUTHORITY; + events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD); + } return false; } // Should not have a scheme or path if ( scheme.length() > 0 or path.length() > 0) { - *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH; - events->create_event(EVENT_INVALID_HEADER); + *infractions += INF_CONNECT_WITH_SCHEME_OR_PATH; + events->create_event(EVENT_CONNECT_WITH_SCHEME_OR_PATH); } start_line_length = method.length() + authority.length() + http_version_length + NUM_REQUEST_LINE_EXTRA_CHARS; @@ -139,7 +146,7 @@ bool Http2RequestLine::generate_start_line(Field& start_line) bytes_written += http_version_length; } // HTTP/2 requests with URIs in absolute or origin form must have a method, scheme, and length - else if (method.length() > 0 and scheme.length() > 0 and path.length() > 0) + else if (scheme.length() > 0 and path.length() > 0) { // If there is an authority, the URI is in absolute form if (authority.length() > 0) @@ -188,8 +195,11 @@ bool Http2RequestLine::generate_start_line(Field& start_line) else { // 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_REQUEST_WITHOUT_REQUIRED_FIELD); + if (pseudo_headers_complete) + { + *infractions += INF_REQUEST_WITHOUT_REQUIRED_FIELD; + events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD); + } return false; } diff --git a/src/service_inspectors/http2_inspect/http2_request_line.h b/src/service_inspectors/http2_inspect/http2_request_line.h index 32d9460c2..565dc5bcb 100644 --- a/src/service_inspectors/http2_inspect/http2_request_line.h +++ b/src/service_inspectors/http2_inspect/http2_request_line.h @@ -32,7 +32,7 @@ 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; + bool generate_start_line(Field& start_line, bool pseudo_headers_complete) override; private: Field method; diff --git a/src/service_inspectors/http2_inspect/http2_start_line.h b/src/service_inspectors/http2_inspect/http2_start_line.h index c453169d7..3d116727c 100644 --- a/src/service_inspectors/http2_inspect/http2_start_line.h +++ b/src/service_inspectors/http2_inspect/http2_start_line.h @@ -40,7 +40,7 @@ public: friend class Http2Hpack; - virtual bool generate_start_line(Field& start_line) = 0; + virtual bool generate_start_line(Field& start_line, bool pseudo_headers_complete) = 0; virtual void process_pseudo_header(const Field& name, const Field& value) = 0; protected: diff --git a/src/service_inspectors/http2_inspect/http2_status_line.cc b/src/service_inspectors/http2_inspect/http2_status_line.cc index 6d0c8b03c..433f98b09 100644 --- a/src/service_inspectors/http2_inspect/http2_status_line.cc +++ b/src/service_inspectors/http2_inspect/http2_status_line.cc @@ -52,7 +52,7 @@ void Http2StatusLine::process_pseudo_header(const Field& name, const Field& valu } } -bool Http2StatusLine::generate_start_line(Field& start_line) +bool Http2StatusLine::generate_start_line(Field& start_line, bool pseudo_headers_complete) { uint32_t bytes_written = 0; @@ -61,8 +61,11 @@ bool Http2StatusLine::generate_start_line(Field& start_line) if (status.length() <= 0) { - *infractions += INF_RESPONSE_WITHOUT_STATUS; - events->create_event(EVENT_RESPONSE_WITHOUT_STATUS); + if (pseudo_headers_complete) + { + *infractions += INF_RESPONSE_WITHOUT_STATUS; + events->create_event(EVENT_RESPONSE_WITHOUT_STATUS); + } return false; } diff --git a/src/service_inspectors/http2_inspect/http2_status_line.h b/src/service_inspectors/http2_inspect/http2_status_line.h index 0ccdc14cc..ca3a61fc3 100644 --- a/src/service_inspectors/http2_inspect/http2_status_line.h +++ b/src/service_inspectors/http2_inspect/http2_status_line.h @@ -32,7 +32,7 @@ public: Http2StartLine(evs, infrs) { } void process_pseudo_header(const Field& name, const Field& value) override; - bool generate_start_line(Field& start_line) override; + bool generate_start_line(Field& start_line, bool pseudo_headers_complete) override; private: Field status; diff --git a/src/service_inspectors/http2_inspect/http2_stream_splitter.cc b/src/service_inspectors/http2_inspect/http2_stream_splitter.cc index 03ad730ea..e92f352aa 100644 --- a/src/service_inspectors/http2_inspect/http2_stream_splitter.cc +++ b/src/service_inspectors/http2_inspect/http2_stream_splitter.cc @@ -215,15 +215,33 @@ bool Http2StreamSplitter::finish(Flow* flow) } #endif - // Loop through all nonzero streams and call NHI finish() bool need_reassemble = false; + + // First check if there is a partial header that needs to be processed. If we have a partial + // trailer don't call finish on that stream below + if (((session_data->frame_type[source_id] == FT_HEADERS) or + (session_data->frame_type[source_id] == FT_PUSH_PROMISE)) and + ((session_data->scan_remaining_frame_octets[source_id] > 0) or + (session_data->continuation_expected[source_id]))) + { + session_data->processing_partial_header = true; + need_reassemble = true; +#ifdef REG_TEST + if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2)) + HttpTestManager::get_test_input_source()->flush(0); +#endif + } + + // Loop through all nonzero streams with open message bodies and call NHI finish() for (const Http2FlowData::StreamInfo& stream_info : session_data->streams) { if ((stream_info.id == 0) || (stream_info.stream->get_state(source_id) >= STREAM_COMPLETE) || (stream_info.stream->get_hi_flow_data() == nullptr) || (stream_info.stream->get_hi_flow_data()->get_type_expected(source_id) - != HttpEnums::SEC_BODY_H2)) + != HttpEnums::SEC_BODY_H2) || + (session_data->processing_partial_header && + (stream_info.id == session_data->current_stream[source_id]))) { continue; } diff --git a/src/service_inspectors/http2_inspect/http2_tables.cc b/src/service_inspectors/http2_inspect/http2_tables.cc index e3265a1c2..f4573b81c 100644 --- a/src/service_inspectors/http2_inspect/http2_tables.cc +++ b/src/service_inspectors/http2_inspect/http2_tables.cc @@ -31,21 +31,21 @@ using namespace snort; const RuleMap Http2Module::http2_events[] = { - { EVENT_INT_DECODE_FAILURE, "error in HPACK integer value" }, + { EVENT_INVALID_FLAG, "invalid flag set on HTTP/2 frame" }, { EVENT_INT_LEADING_ZEROS, "HPACK integer value has leading zeros" }, - { EVENT_STRING_DECODE_FAILURE, "error in HPACK string value" }, + { EVENT_INVALID_STREAM_ID, "HTTP/2 stream initiated with invalid stream id" }, { EVENT_MISSING_CONTINUATION, "missing HTTP/2 continuation frame" }, { EVENT_UNEXPECTED_CONTINUATION, "unexpected HTTP/2 continuation frame" }, { EVENT_MISFORMATTED_HTTP2, "misformatted HTTP/2 traffic" }, { EVENT_PREFACE_MATCH_FAILURE, "HTTP/2 connection preface does not match" }, { EVENT_REQUEST_WITHOUT_REQUIRED_FIELD, "HTTP/2 request missing required header field" }, { EVENT_RESPONSE_WITHOUT_STATUS, "HTTP/2 response has no status code" }, - { EVENT_INVALID_HEADER, "HTTP/2 invalid header field" }, + { EVENT_CONNECT_WITH_SCHEME_OR_PATH, "HTTP/2 CONNECT request with scheme or path" }, { EVENT_SETTINGS_FRAME_ERROR, "error in HTTP/2 settings frame" }, { EVENT_SETTINGS_FRAME_UNKN_PARAM, "unknown parameter in HTTP/2 settings frame" }, { EVENT_FRAME_SEQUENCE, "invalid HTTP/2 frame sequence" }, { EVENT_DYNAMIC_TABLE_OVERFLOW, "HTTP/2 dynamic table size limit exceeded" }, - { EVENT_INVALID_STARTLINE, "invalid HTTP/2 start line" }, + { EVENT_INVALID_PROMISED_STREAM, "HTTP/2 push promise frame with invalid promised stream id" }, { EVENT_PADDING_LEN, "HTTP/2 padding length is bigger than frame data size" }, { EVENT_PSEUDO_HEADER_AFTER_REGULAR_HEADER, "HTTP/2 pseudo-header after regular header" }, { EVENT_PSEUDO_HEADER_IN_TRAILERS, "HTTP/2 pseudo-header in trailers" }, @@ -58,9 +58,6 @@ const RuleMap Http2Module::http2_events[] = { 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/test/http2_hpack_int_decode_test.cc b/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc index ed23e3516..8eec00d41 100644 --- a/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc +++ b/src/service_inspectors/http2_inspect/test/http2_hpack_int_decode_test.cc @@ -61,7 +61,7 @@ TEST(http2_hpack_int_decode_success, 10_using_5_bits) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf); + bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 10); @@ -75,7 +75,7 @@ TEST(http2_hpack_int_decode_success, 10_using_5_bits_wtail) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf); + bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 10); @@ -89,7 +89,7 @@ TEST(http2_hpack_int_decode_success, 1337_using_5_bits) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode->translate(buf, 3, bytes_processed, res, &events, &inf); + bool success = decode->translate(buf, 3, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 1337); @@ -105,7 +105,7 @@ TEST(http2_hpack_int_decode_success, 42_using_8_bits) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode_8.translate(&buf, 1, bytes_processed, res, &events, &inf); + bool success = decode_8.translate(&buf, 1, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 42); @@ -119,7 +119,7 @@ TEST(http2_hpack_int_decode_success, max_val_using_5_bit) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode->translate(buf, 11, bytes_processed, res, &events, &inf); + bool success = decode->translate(buf, 11, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 0xFFFFFFFFFFFFFFFF); @@ -133,7 +133,7 @@ TEST(http2_hpack_int_decode_success, 31_using_5_bits) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf); + bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 31); @@ -147,7 +147,7 @@ TEST(http2_hpack_int_decode_success, 0_using_5_bits) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf); + bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == 0); @@ -163,7 +163,7 @@ TEST(http2_hpack_int_decode_success, MAX_UINT32_using_7_bits) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode_7.translate(buf, 6, bytes_processed, res, &events, &inf); + bool success = decode_7.translate(buf, 6, bytes_processed, res, &events, &inf, false); // check results CHECK(success == true); CHECK(res == UINT32_MAX); @@ -188,12 +188,12 @@ TEST(http2_hpack_int_decode_failure, 0_len_field) // decode uint32_t bytes_processed = 0; uint64_t res = 0; - bool success = decode_8.translate(&buf, 0, bytes_processed, res, &local_events, &local_inf); + bool success = decode_8.translate(&buf, 0, bytes_processed, res, &local_events, &local_inf, + false); // check results CHECK(success == false); CHECK(bytes_processed == 0); CHECK(local_inf.get_raw() == (1<translate(buf, 11, bytes_processed, res, 10, bytes_written, &events, &inf); + bool success = decode->translate(buf, 11, bytes_processed, res, 10, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(memcmp(res, "custom-key", 10) == 0); @@ -80,7 +81,8 @@ TEST(http2_hpack_string_decode_success, custom_key_len_10_wtail) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[12]; - bool success = decode->translate(buf, 12, bytes_processed, res, 12, bytes_written, &events, &inf); + bool success = decode->translate(buf, 12, bytes_processed, res, 12, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(memcmp(res, "custom-key", 10) == 0); @@ -98,7 +100,8 @@ TEST(http2_hpack_string_decode_success, int_is_more_than_1_byte) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[130]; - bool success = decode->translate(buf, 130, bytes_processed, res, 130, bytes_written, &events, &inf); + bool success = decode->translate(buf, 130, bytes_processed, res, 130, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 130); @@ -113,7 +116,8 @@ TEST(http2_hpack_string_decode_success, empty_string) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res = 10; // random value, just to check it wasn't overwritten - bool success = decode->translate(&buf, 1, bytes_processed, &res, 1, bytes_written, &events, &inf); + bool success = decode->translate(&buf, 1, bytes_processed, &res, 1, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 1); @@ -128,7 +132,8 @@ TEST(http2_hpack_string_decode_success, string_len_1) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res = 0; - bool success = decode->translate(buf, 2, bytes_processed, &res, 1, bytes_written, &events, &inf); + bool success = decode->translate(buf, 2, bytes_processed, &res, 1, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 2); @@ -149,7 +154,7 @@ TEST(http2_hpack_string_decode_success, max_field_length) uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[MAX_OCTETS]; bool success = decode->translate(buf, MAX_OCTETS, bytes_processed, res, - MAX_OCTETS, bytes_written, &events, &inf); + MAX_OCTETS, bytes_written, &events, &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == MAX_OCTETS); @@ -164,7 +169,8 @@ TEST(http2_hpack_string_decode_success, huffman_1_byte) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[1]; - bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf); + bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 2); @@ -179,7 +185,8 @@ TEST(http2_hpack_string_decode_success, huffman_1_byte_star) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[1]; - bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf); + bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 2); @@ -194,7 +201,8 @@ TEST(http2_hpack_string_decode_success, huffman_2_bytes_aligned) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[3]; - bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf); + bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 3); @@ -209,7 +217,8 @@ TEST(http2_hpack_string_decode_success, huffman_2_bytes_unaligned) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[3]; - bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf); + bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 3); @@ -224,7 +233,8 @@ TEST(http2_hpack_string_decode_success, huffman_rfc_example1) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[19]; - bool success = decode->translate(buf, 13, bytes_processed, res, 19, bytes_written, &events, &inf); + bool success = decode->translate(buf, 13, bytes_processed, res, 19, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 13); @@ -239,7 +249,8 @@ TEST(http2_hpack_string_decode_success, huffman_rfc_example2) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[9]; - bool success = decode->translate(buf, 7, bytes_processed, res, 9, bytes_written, &events, &inf); + bool success = decode->translate(buf, 7, bytes_processed, res, 9, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 7); @@ -254,7 +265,8 @@ TEST(http2_hpack_string_decode_success, huffman_rfc_example3) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[12]; - bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events, &inf); + bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 9); @@ -269,7 +281,8 @@ TEST(http2_hpack_string_decode_success, huffman_rfc_example4) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[14]; - bool success = decode->translate(buf, 10, bytes_processed, res, 14, bytes_written, &events, &inf); + bool success = decode->translate(buf, 10, bytes_processed, res, 14, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 10); @@ -285,7 +298,8 @@ TEST(http2_hpack_string_decode_success, huffman_rfc_example5) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[35]; - bool success = decode->translate(buf, 23, bytes_processed, res, 35, bytes_written, &events, &inf); + bool success = decode->translate(buf, 23, bytes_processed, res, 35, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 23); @@ -303,7 +317,8 @@ TEST(http2_hpack_string_decode_success, huffman_rfc_example6) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[73]; - bool success = decode->translate(buf, 46, bytes_processed, res, 73, bytes_written, &events, &inf); + bool success = decode->translate(buf, 46, bytes_processed, res, 73, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 46); @@ -318,7 +333,8 @@ TEST(http2_hpack_string_decode_success, huffman_unaligned_then_aligned) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[6]; - bool success = decode->translate(buf, 5, bytes_processed, res, 6, bytes_written, &events, &inf); + bool success = decode->translate(buf, 5, bytes_processed, res, 6, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 5); @@ -334,7 +350,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_1) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[32]; - bool success = decode->translate(buf, 21, bytes_processed, res, 32, bytes_written, &events, &inf); + bool success = decode->translate(buf, 21, bytes_processed, res, 32, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 21); @@ -350,7 +367,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_2) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[36]; - bool success = decode->translate(buf, 24, bytes_processed, res, 36, bytes_written, &events, &inf); + bool success = decode->translate(buf, 24, bytes_processed, res, 36, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 24); @@ -365,7 +383,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_3) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[12]; - bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events, &inf); + bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 9); @@ -382,7 +401,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_4) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[70]; - bool success = decode->translate(buf, 45, bytes_processed, res, 70, bytes_written, &events, &inf); + bool success = decode->translate(buf, 45, bytes_processed, res, 70, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 45); @@ -401,7 +421,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[88]; uint8_t expected[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; - bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events, &inf); + bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 55); @@ -420,7 +441,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[93]; uint8_t expected[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; - bool success = decode->translate(buf, 58, bytes_processed, res, 93, bytes_written, &events, &inf); + bool success = decode->translate(buf, 58, bytes_processed, res, 93, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 58); @@ -439,7 +461,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[79]; uint8_t expected[17] = {0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F}; - bool success = decode->translate(buf, 49, bytes_processed, res, 79, bytes_written, &events, &inf); + bool success = decode->translate(buf, 49, bytes_processed, res, 79, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 49); @@ -458,7 +481,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[76]; uint8_t expected[16] = {0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F}; - bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events, &inf); + bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 47); @@ -476,7 +500,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[74]; uint8_t expected[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF}; - bool success = decode->translate(buf, 46, bytes_processed, res, 74, bytes_written, &events, &inf); + bool success = decode->translate(buf, 46, bytes_processed, res, 74, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 46); @@ -495,7 +520,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[73]; uint8_t expected[16] = {0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF}; - bool success = decode->translate(buf, 45, bytes_processed, res, 73, bytes_written, &events, &inf); + bool success = decode->translate(buf, 45, bytes_processed, res, 73, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 45); @@ -515,7 +541,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[80]; uint8_t expected[16] = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF}; - bool success = decode->translate(buf, 50, bytes_processed, res, 80, bytes_written, &events, &inf); + bool success = decode->translate(buf, 50, bytes_processed, res, 80, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 50); @@ -535,7 +562,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[82]; uint8_t expected[16] = {0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF}; - bool success = decode->translate(buf, 51, bytes_processed, res, 82, bytes_written, &events, &inf); + bool success = decode->translate(buf, 51, bytes_processed, res, 82, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 51); @@ -554,7 +582,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[76]; uint8_t expected[16] = {0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF}; - bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events, &inf); + bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 47); @@ -574,7 +603,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_all_possible_symbols_he uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[88]; uint8_t expected[16] = {0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF}; - bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events, &inf); + bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events, + &inf, false); // check results CHECK(success == true); CHECK(bytes_processed == 55); @@ -590,7 +620,8 @@ TEST(http2_hpack_string_decode_success, huffman_decoding_tail_lookup_unsucessful // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res[3]; - bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf); + bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf, + false); // check results CHECK(success == true); CHECK(bytes_processed == 3); @@ -615,13 +646,13 @@ TEST(http2_hpack_string_decode_infractions, 0_len_field) // decode uint32_t bytes_processed = 0, bytes_written = 0; uint8_t res; - bool success = local_decode.translate(&buf, 0, bytes_processed, &res, 1, bytes_written, &local_events, &local_inf); + bool success = local_decode.translate(&buf, 0, bytes_processed, &res, 1, bytes_written, + &local_events, &local_inf, false); // check results CHECK(success == false); CHECK(bytes_processed == 0); CHECK(bytes_written == 0); CHECK(local_inf.get_raw() == (1<cutter[source_id] == nullptr) && (session_data->section_type[source_id] == SEC__NOT_COMPUTE)) { - assert(!session_data->for_http2); // Set up to process empty header section uint32_t not_used; prepare_flush(session_data, ¬_used, SEC_HEADER, 0, 0, 0, false, 0, 0);