From: Mike Stepanek (mstepane) Date: Thu, 6 Jun 2019 20:12:26 +0000 (-0400) Subject: Merge pull request #1629 in SNORT/snort3 from ~THOPETER/snort3:nhttp121 to master X-Git-Tag: 3.0.0-257~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7d24c3d3f33f81f52a277998aedbd56835aaf88a;p=thirdparty%2Fsnort3.git Merge pull request #1629 in SNORT/snort3 from ~THOPETER/snort3:nhttp121 to master Squashed commit of the following: commit 1d76e71bc035d419559cdb56b39eee2c3309f39b Author: Tom Peters Date: Tue Jun 4 16:49:41 2019 -0400 http_inspect: test tool enhancement --- diff --git a/src/service_inspectors/http_inspect/dev_notes.txt b/src/service_inspectors/http_inspect/dev_notes.txt index 2cd87e624..3443b90a1 100644 --- a/src/service_inspectors/http_inspect/dev_notes.txt +++ b/src/service_inspectors/http_inspect/dev_notes.txt @@ -179,7 +179,7 @@ lines in the middle of a paragraph. Commands: @break resets HTTP Inspect data structures and begins a new test. Use it liberally to prevent unrelated tests from interfering with each other. - @tcpclose simulates a half-duplex TCP close following the next paragraph of data. + @tcpclose simulates a half-duplex TCP close. @request and @response set the message direction. Applies to subsequent paragraphs until changed. The initial direction is always request and the break command resets the direction to request. @fill create a paragraph consisting of octets of auto-fill data diff --git a/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc b/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc index 259e075c5..81d3dcab1 100644 --- a/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc +++ b/src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc @@ -258,7 +258,8 @@ const snort::StreamBuffer HttpStreamSplitter::reassemble(snort::Flow* flow, unsi if (test_buffer == nullptr) { // Source ID does not match test data, no test data was flushed, preparing for a - // partial flush, or there is no more test data + // partial flush, preparing for a TCP connection close, or there is no more test + // data return http_buf; } data = test_buffer; diff --git a/src/service_inspectors/http_inspect/http_test_input.cc b/src/service_inspectors/http_inspect/http_test_input.cc index 867845102..64fb798f5 100644 --- a/src/service_inspectors/http_inspect/http_test_input.cc +++ b/src/service_inspectors/http_inspect/http_test_input.cc @@ -61,9 +61,6 @@ void HttpTestInput::reset() just_flushed = true; tcp_closed = false; flush_octets = 0; - close_pending = false; - close_notified = false; - finish_expected = false; need_break = false; for (int k = 0; k <= 1; k++) @@ -218,6 +215,11 @@ void HttpTestInput::scan(uint8_t*& data, uint32_t& length, SourceId source_id, u "tcpclose", strlen("tcpclose"))) { tcp_closed = true; + if (!skip_to_break) + { + length = 0; + return; + } } else if ((command_length > strlen("fill")) && !memcmp(command_value, "fill", strlen("fill"))) @@ -449,74 +451,34 @@ void HttpTestInput::reassemble(uint8_t** buffer, unsigned& length, SourceId sour bool& tcp_close, bool& partial_flush) { *buffer = nullptr; - tcp_close = false; partial_flush = false; + tcp_close = false; // Only piggyback on data moving in the same direction. - // Need flushed data unless the connection is closing. - if ((source_id != last_source_id) || (!flushed && !tcp_closed && !partial)) + if (source_id != last_source_id) + return; + + if (tcp_closed) { + // Give the caller a chance to call finish() + tcp_close = true; return; } - if (partial) + // Need flushed data unless it's a partial flush. + if (!flushed && !partial) { - // Give the caller a chance to set up for a partial flush before giving him the data - partial_flush = true; - partial = false; return; } - // How we process TCP close situations depends on the size of the flush relative to the data - // buffer. - // 1. less than whole buffer - not the final flush, ignore pending close - // 2. exactly equal - process data now and signal the close next time around - // 3. there was no flush - signal the close now and send the leftovers next time around - if (tcp_closed && (!flushed || (flush_octets == end_offset[last_source_id]))) + if (partial) { - if (close_pending) - { - // There is no more data. Clean up and notify caller about close. - just_flushed = true; - flushed = false; - end_offset[last_source_id] = 0; - previous_offset[last_source_id] = 0; - close_pending = false; - tcp_closed = false; - tcp_close = true; - finish_expected = true; - } - else if (!flushed) - { - // Failure to flush means scan() reached end of paragraph and returned PAF_SEARCH. - // Notify caller about close and they will do a zero-length flush(). - previous_offset[last_source_id] = end_offset[last_source_id]; - tcp_close = true; - close_notified = true; - finish_expected = true; - } - else - { - // The flush point is the end of the paragraph. Supply the data now and if necessary - // notify the caller about close next time or otherwise just clean up. - *buffer = msg_buf[last_source_id]; - length = flush_octets; - if (close_notified) - { - just_flushed = true; - flushed = false; - close_notified = false; - tcp_closed = false; - } - else - { - close_pending = true; - } - } + // Give the caller a chance to set up for a partial flush before giving him the data + partial_flush = true; + partial = false; return; } - // Normal case with no TCP close or at least not yet *buffer = msg_buf[last_source_id]; length = flush_octets; just_flushed = true; @@ -525,13 +487,12 @@ void HttpTestInput::reassemble(uint8_t** buffer, unsigned& length, SourceId sour bool HttpTestInput::finish() { - if (finish_expected) + if (tcp_closed) { - finish_expected = false; + tcp_closed = false; return true; } return false; } - #endif diff --git a/src/service_inspectors/http_inspect/http_test_input.h b/src/service_inspectors/http_inspect/http_test_input.h index 3b3cb2026..2fe100f96 100644 --- a/src/service_inspectors/http_inspect/http_test_input.h +++ b/src/service_inspectors/http_inspect/http_test_input.h @@ -43,10 +43,10 @@ private: uint8_t msg_buf[2][2 * HttpEnums::MAX_OCTETS]; FILE* include_file[2] = { nullptr, nullptr }; - // break command has been read and we are waiting for a new flow to start + // break command has been read and we are waiting for a new underlying flow to start bool need_break = false; - // Sequence number of the flow we are currently piggybacking on + // Sequence number of the underlying flow we are currently piggybacking on uint64_t curr_seq_num = 0; // data has been flushed and must be sent by reassemble() before more data may be given to @@ -59,7 +59,7 @@ private: // reassemble() just completed and all flushed octets forwarded, time to resume scan() bool just_flushed = true; - // TCP connection directional close at end of current paragraph + // TCP connection directional close bool tcp_closed = false; // partial flush requested, useful for testing accelerated blocking @@ -74,15 +74,6 @@ private: // number of characters in the buffer uint32_t end_offset[2] = { 0, 0 }; - // Need to send close with next pass through reassemble() - bool close_pending = false; - - // Close notification already provided - bool close_notified = false; - - // tcp_close notification given and we are waiting for a HttpStreamSplitter::finish() call. - bool finish_expected = false; - void reset(); };