From: Tom Peters Date: Tue, 19 Aug 2014 17:52:51 +0000 (-0400) Subject: stop using flags to determine splitter direction and a new test case X-Git-Tag: 3.0.0-233~1423 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b82b165fee4cfc748dbabb4d148339054d132e4f;p=thirdparty%2Fsnort3.git stop using flags to determine splitter direction and a new test case --- diff --git a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc index cfe57b96f..856ad7b7f 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc @@ -41,7 +41,7 @@ using namespace NHttpEnums; unsigned NHttpFlowData::nhttp_flow_id = 0; -NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id) {} +NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id) { } NHttpFlowData::~NHttpFlowData() { delete request_line; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc index 97f5c2c22..e4a2cdb3a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc @@ -136,7 +136,9 @@ void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* cons msg_section->legacy_clients(); if (test_output) { - if (!NHttpTestInput::test_input) msg_section->print_section(stdout); + if (!NHttpTestInput::test_input) { + msg_section->print_section(stdout); + } else { if (NHttpTestInput::test_input_source->get_test_number() != file_test_number) { if (test_out) fclose (test_out); @@ -148,6 +150,7 @@ void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* cons msg_section->print_section(test_out); printf("Finished processing section from test %" PRIi64 "\n", file_test_number); } + fflush(nullptr); } } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc index 4bc7c347b..5d8bc042a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc @@ -65,7 +65,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned /*total section_buffer = new uint8_t[65536]; } - SourceId source_id = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER; + SourceId source_id = to_server() ? SRC_CLIENT : SRC_SERVER; copied = len; @@ -97,23 +97,27 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned /*total return nullptr; } -PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flush_offset) { +PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t, uint32_t* flush_offset) { // When the system begins providing TCP connection close information this won't always be false. &&& bool tcp_close = false; - // This is the session state information we share with HTTP Inspect and store with stream. A session is defined by a TCP connection. - // Since PAF is the first to see a new TCP connection the new flow data object is created here. + // This is the session state information we share with HTTP Inspect and store with stream. A session is defined + // by a TCP connection. Since PAF is the first to see a new TCP connection the new flow data object is created here. NHttpFlowData* session_data = (NHttpFlowData*)flow->get_application_data(NHttpFlowData::nhttp_flow_id); if (session_data == nullptr) flow->set_application_data(session_data = new NHttpFlowData); assert(session_data != nullptr); - SourceId source_id = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER; + SourceId source_id = to_server() ? SRC_CLIENT : SRC_SERVER; if (NHttpTestInput::test_input) { + // This block substitutes a completely new data buffer supplied by the test tool in place of the "real" data. + // It also rewrites the buffer length, source ID, and TCP close indicator. *flush_offset = length; bool need_break; - NHttpTestInput::test_input_source->scan((uint8_t*&)data, length, source_id, tcp_close, need_break); + uint8_t* test_data = nullptr; + NHttpTestInput::test_input_source->scan(test_data, length, source_id, tcp_close, need_break); if (length == 0) return PAF_FLUSH; + data = test_data; if (need_break) flow->set_application_data(session_data = new NHttpFlowData); } @@ -177,9 +181,13 @@ PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t case SEC_BODY: case SEC_CHUNKBODY: paf_max = 16384; - prepare_flush(session_data, flush_offset, source_id, type, - tcp_close && (session_data->octets_expected[source_id] >= length), - 0, session_data->octets_expected[source_id]); + if ((!tcp_close) || (length > session_data->octets_expected[source_id])) { + prepare_flush(session_data, flush_offset, source_id, type, false, 0, session_data->octets_expected[source_id]); + } + else { + // The TCP connection has closed and this is the possibly incomplete final section + prepare_flush(session_data, flush_offset, source_id, type, true, 0, length); + } return PAF_FLUSH; case SEC_ABORT: return PAF_ABORT; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h index 29b5e35c8..0afec8c47 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h @@ -37,9 +37,9 @@ class NHttpInspect; class NHttpStreamSplitter : public StreamSplitter { public: NHttpStreamSplitter(bool is_client_to_server, NHttpInspect* my_inspector_) : StreamSplitter(is_client_to_server), - my_inspector(my_inspector_) {}; + my_inspector(my_inspector_) { }; ~NHttpStreamSplitter() { delete[] section_buffer; }; - PAF_Status scan(Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flush_offset); + PAF_Status scan(Flow* flow, const uint8_t* data, uint32_t length, uint32_t not_used, uint32_t* flush_offset); const StreamBuffer* reassemble(Flow* flow, unsigned total, unsigned offset, const uint8_t* data, unsigned len, uint32_t flags, unsigned& copied); bool is_paf() { return true; }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc index c8fb6f2ce..a85c6d9e0 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc @@ -75,11 +75,11 @@ void NHttpTestInput::scan(uint8_t*& data, uint32_t &length, SourceId &source_id, // Must present unflushed leftovers to PAF again. // If we don't take this opportunity to left justify our data in the buffer we may "walk" to the right until we run out of buffer space memmove(msg_buf, msg_buf+flush_octets, length); - tcp_close = tcp_already_closed; + tcp_close = tcp_closed; return; } // If we reach here then PAF has already flushed all the data we have read so far. - tcp_already_closed = false; + tcp_closed = false; } else { // The data we gave PAF last time was not flushed @@ -136,6 +136,10 @@ void NHttpTestInput::scan(uint8_t*& data, uint32_t &length, SourceId &source_id, else if ((command_length == strlen("break")) && !memcmp(command_value, "break", strlen("break"))) { need_break = true; } + else if ((command_length == strlen("tcpclose")) && !memcmp(command_value, "tcpclose", strlen("tcpclose"))) { + tcp_close = true; + tcp_closed = true; + } else if ((command_length == strlen("bodyend")) && !memcmp(command_value, "bodyend", strlen("bodyend"))) { term_bytes[0] = 'x'; term_bytes[1] = 'y'; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_input.h b/src/service_inspectors/nhttp_inspect/nhttp_test_input.h index 94e507cfe..911e55a3c 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_input.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_input.h @@ -44,7 +44,7 @@ private: FILE *test_data_file; uint8_t msg_buf[2 * NHttpEnums::MAXOCTETS]; bool just_flushed = true; // all octets sent to inspection and must resume reading the file - bool tcp_already_closed = false; // so we can keep presenting a TCP close to PAF until all the remaining octets are consumed and flushed + bool tcp_closed = false; // so we can keep presenting a TCP close to PAF until all the remaining octets are consumed and flushed uint32_t flush_octets = 0; // number of octets that have been flushed and must go to inspection uint32_t previous_offset = 0; // last character in the buffer shown to PAF but not flushed yet uint32_t end_offset = 0; // last read character in the buffer diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt b/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt index 256b01856..242b0cdf9 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt @@ -4,6 +4,12 @@ # Within a paragraph the placement of new lines does not have any effect. Format a paragraph any way you are comfortable. Extra blank lines # between paragraphs also do not have any effect. # +# Each paragraph represents a TCP segment. The splitter can be tested by putting multiple sections in the same paragraph (splitter must split) +# or continuing a section in the next paragraph (splitter must search and reassamble). +# +# It is not necessary to specify complete body and chunk body sections. Specify at least one octet that will begin the section and the +# remainder will be autofilled in 16384-octet sections up to the length flushed. +# # Lines beginning with # are comments. Lines beginning with @ are commands. This does not apply to lines in the middle of a paragraph. # # Command lines are left justified, lower case, with no whitespace: @@ -683,6 +689,19 @@ Accept-Language: is\r\n @break @request +POST /basic/request/response/pair/with/large/bodies/both/ways HTTP/1.1\r\n +Host: www.testcase.com\r\n +Content-Length: 50000\r\n +\r\n + +body1-start + +@response + +HTTP/1.1 200 OK\r\n +Content-Length: 60000\r\n +\r\n +body2-start # ***********************************************************************************************