From: Tom Peters Date: Mon, 22 Sep 2014 19:07:59 +0000 (-0400) Subject: split out scan result into its own enum X-Git-Tag: 3.0.0-233~1406 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bbfdfa67f2fbf9c9269ccbc49483ec037d860ef8;p=thirdparty%2Fsnort3.git split out scan result into its own enum --- diff --git a/src/service_inspectors/nhttp_inspect/nhttp_enum.h b/src/service_inspectors/nhttp_inspect/nhttp_enum.h index 397c1357e..87a2098eb 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_enum.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_enum.h @@ -49,6 +49,9 @@ typedef enum { SRC__NOTCOMPUTE=-4, SRC_CLIENT=0, SRC_SERVER=1 } SourceId; typedef enum { SEC_DISCARD = -10, SEC_CLOSED = -9, SEC_ABORT = -8, SEC__NOTCOMPUTE=-4, SEC__NOTPRESENT=-1, SEC_REQUEST = 2, SEC_STATUS, SEC_HEADER, SEC_BODY, SEC_CHUNKHEAD, SEC_CHUNKBODY, SEC_TRAILER } SectionType; +// Result of scanning by splitter +typedef enum { SCAN_NOTFOUND, SCAN_FOUND, SCAN_DISCARD } ScanResult; + // Result of processing a message section--what needs to happen next typedef enum { RES_INSPECT, RES_IGNORE, RES_AGGREGATE, RES_FLUSHCHUNKS } ProcessResult; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc b/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc index eb184567e..b1eb274ce 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc @@ -30,7 +30,7 @@ using namespace NHttpEnums; -SectionType NHttpRequestSplitter::split(const uint8_t* buffer, uint32_t length) { +ScanResult NHttpRequestSplitter::split(const uint8_t* buffer, uint32_t length) { for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf == 0)) || @@ -46,13 +46,13 @@ SectionType NHttpRequestSplitter::split(const uint8_t* buffer, uint32_t length) } num_flush = k+1; // If the first two octets are CRLF then they must be discarded. - return ((octets_seen + k + 1) == 2) ? SEC_DISCARD : SEC_REQUEST; + return ((octets_seen + k + 1) == 2) ? SCAN_DISCARD : SCAN_FOUND; } octets_seen += length; - return SEC__NOTPRESENT; + return SCAN_NOTFOUND; } -SectionType NHttpStatusSplitter::split(const uint8_t* buffer, uint32_t length) { +ScanResult NHttpStatusSplitter::split(const uint8_t* buffer, uint32_t length) { for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf == 0)) || @@ -68,13 +68,13 @@ SectionType NHttpStatusSplitter::split(const uint8_t* buffer, uint32_t length) { } num_flush = k+1; // If the first two octets are CRLF then they must be discarded. - return ((octets_seen + k + 1) == 2) ? SEC_DISCARD : SEC_STATUS; + return ((octets_seen + k + 1) == 2) ? SCAN_DISCARD : SCAN_FOUND; } octets_seen += length; - return SEC__NOTPRESENT; + return SCAN_NOTFOUND; } -SectionType NHttpChunkHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { +ScanResult NHttpChunkHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf == 0)) || @@ -90,15 +90,15 @@ SectionType NHttpChunkHeaderSplitter::split(const uint8_t* buffer, uint32_t leng } num_flush = k+1; // If the first two octets are CRLF then they must be discarded. - return ((octets_seen + k + 1) == 2) ? SEC_DISCARD : SEC_CHUNKHEAD; + return ((octets_seen + k + 1) == 2) ? SCAN_DISCARD : SCAN_FOUND; } octets_seen += length; - return SEC__NOTPRESENT; + return SCAN_NOTFOUND; } -SectionType NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { - if (peek_status == SEC_HEADER) { - return SEC_HEADER; +ScanResult NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { + if (peek_status == SCAN_FOUND) { + return SCAN_FOUND; } buffer += peek_octets; length -= peek_octets; @@ -110,7 +110,7 @@ SectionType NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { num_crlf++; if ((num_crlf == 2) && (octets_seen + k + 1) == 2) { num_flush = k+1; - return SEC_HEADER; + return SCAN_FOUND; } if (num_crlf < 4) { continue; @@ -121,13 +121,13 @@ SectionType NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { continue; } num_flush = k + 1 + peek_octets; - return SEC_HEADER; + return SCAN_FOUND; } octets_seen += length; - return SEC__NOTPRESENT; + return SCAN_NOTFOUND; } -SectionType NHttpHeaderSplitter::peek(const uint8_t* buffer, uint32_t length) { +ScanResult NHttpHeaderSplitter::peek(const uint8_t* buffer, uint32_t length) { assert(octets_seen == 0); peek_status = split(buffer, length); peek_octets = length; @@ -135,7 +135,7 @@ SectionType NHttpHeaderSplitter::peek(const uint8_t* buffer, uint32_t length) { } -SectionType NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) { +ScanResult NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) { for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf%2 == 0)) || @@ -143,7 +143,7 @@ SectionType NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) num_crlf++; if ((num_crlf == 2) && (octets_seen + k + 1) == 2) { num_flush = k+1; - return SEC_TRAILER; + return SCAN_FOUND; } if (num_crlf < 4) { continue; @@ -154,10 +154,10 @@ SectionType NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) continue; } num_flush = k+1; - return SEC_TRAILER; + return SCAN_FOUND; } octets_seen += length; - return SEC__NOTPRESENT; + return SCAN_NOTFOUND; } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_splitter.h b/src/service_inspectors/nhttp_inspect/nhttp_splitter.h index d8d5d726d..24c819bd1 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_splitter.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_splitter.h @@ -40,8 +40,8 @@ class NHttpSplitter { public: virtual ~NHttpSplitter() = default; virtual void reset() { octets_seen = 0; num_crlf = 0; num_flush = 0; }; - virtual NHttpEnums::SectionType split(const uint8_t* buffer, uint32_t length) = 0; - virtual NHttpEnums::SectionType peek(const uint8_t*, uint32_t) { assert(0); return NHttpEnums::SEC_ABORT; }; + virtual NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length) = 0; + virtual NHttpEnums::ScanResult peek(const uint8_t*, uint32_t) { assert(0); return NHttpEnums::SCAN_NOTFOUND; }; uint32_t get_num_flush() { return num_flush; }; virtual uint32_t get_octets_seen() { return octets_seen; }; @@ -53,33 +53,33 @@ protected: class NHttpRequestSplitter : public NHttpSplitter { public: - NHttpEnums::SectionType split(const uint8_t* buffer, uint32_t length); + NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); }; class NHttpStatusSplitter : public NHttpSplitter { public: - NHttpEnums::SectionType split(const uint8_t* buffer, uint32_t length); + NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); }; class NHttpHeaderSplitter : public NHttpSplitter { public: - NHttpEnums::SectionType split(const uint8_t* buffer, uint32_t length); - NHttpEnums::SectionType peek(const uint8_t* buffer, uint32_t length); - void reset() { NHttpSplitter::reset(); peek_octets = 0; peek_status = NHttpEnums::SEC__NOTPRESENT; }; + NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); + NHttpEnums::ScanResult peek(const uint8_t* buffer, uint32_t length); + void reset() { NHttpSplitter::reset(); peek_octets = 0; peek_status = NHttpEnums::SCAN_NOTFOUND; }; uint32_t get_octets_seen() { return octets_seen - peek_octets; }; private: uint32_t peek_octets = 0; - NHttpEnums::SectionType peek_status = NHttpEnums::SEC__NOTPRESENT; + NHttpEnums::ScanResult peek_status = NHttpEnums::SCAN_NOTFOUND; }; class NHttpChunkHeaderSplitter : public NHttpSplitter { public: - NHttpEnums::SectionType split(const uint8_t* buffer, uint32_t length); + NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); }; class NHttpTrailerSplitter : public NHttpSplitter { public: - NHttpEnums::SectionType split(const uint8_t* buffer, uint32_t length); + NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); }; #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc index dcc10326d..5d3b8eda0 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc @@ -60,14 +60,32 @@ void NHttpStreamSplitter::prepare_flush(NHttpFlowData* session_data, uint32_t* f session_data->header_octets_visible[source_id] = 0; } -StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t, uint32_t* flush_offset) { +// Convenience function. Size buffer required to accommodate the current section plus possible aggregation. +uint32_t NHttpStreamSplitter::size_buffer_needed(unsigned total, NHttpEnums::SectionType type, + uint32_t possible_additional) { + switch (type) { + case SEC_CHUNKBODY: + return 16384; + case SEC_REQUEST: + case SEC_STATUS: + case SEC_HEADER: + return total + possible_additional; + default: + return total; + } +} + +StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t, + uint32_t* flush_offset) { + assert(length <= 63780); // When the system begins providing TCP connection close information this won't always be false. FIXIT-H 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. + // by a TCP connection. Since scan() 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); @@ -115,8 +133,8 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat const uint32_t max_length = (length <= (63780 - splitter->get_octets_seen())) ? length : (63780 - splitter->get_octets_seen()); - const SectionType split_result = splitter->split(data, max_length); - if (split_result == SEC__NOTPRESENT) { + const ScanResult split_result = splitter->split(data, max_length); + if (split_result == SCAN_NOTFOUND) { if (splitter->get_octets_seen() == 63780) { // FIXIT-M need to implement processing and detection instead of just discarding this data session_data->type_expected[source_id] = SEC_ABORT; @@ -131,7 +149,7 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat return StreamSplitter::FLUSH; } const uint32_t flush_octets = splitter->get_num_flush(); - if (split_result == SEC_DISCARD) { + if (split_result == SCAN_DISCARD) { prepare_flush(session_data, flush_offset, source_id, SEC_DISCARD, tcp_close && (flush_octets == length), 0, flush_octets, length); splitter->reset(); @@ -143,7 +161,7 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat if ((type == SEC_REQUEST) || (type == SEC_STATUS)) { // Look ahead to see if entire header section is already here so we can aggregate it for detection. const uint32_t peek_max_length = ((length - flush_octets <= 63780)) ? (length - flush_octets) : 63780; - if (session_data->header_splitter[source_id].peek(data + flush_octets, peek_max_length) == SEC_HEADER) { + if (session_data->header_splitter[source_id].peek(data + flush_octets, peek_max_length) == SCAN_FOUND) { session_data->header_octets_visible[source_id] = session_data->header_splitter[source_id].get_num_flush(); } } @@ -169,7 +187,7 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat } } -const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned /*total FIXIT-H */, unsigned offset, const uint8_t* data, +const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total, unsigned offset, const uint8_t* data, unsigned len, uint32_t flags, unsigned& copied) { static THREAD_LOCAL StreamBuffer nhttp_buf; @@ -191,8 +209,12 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned /*total } data = test_buffer; offset = 0; + total = len; } + assert(total <= 63780); + assert(offset+len <= total); + bool is_chunk_body = session_data->section_type[source_id] == SEC_CHUNKBODY; uint8_t*& chunk_buffer = session_data->chunk_buffer[source_id]; @@ -201,7 +223,8 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned /*total int32_t& buffer_length = !is_chunk_body ? session_data->section_buffer_length[source_id] : chunk_buffer_length; if (buffer == nullptr) { - buffer = new uint8_t[65536]; + buffer = new uint8_t[size_buffer_needed(total, session_data->section_type[source_id], + session_data->unused_octets_visible[source_id])]; } memcpy(buffer + buffer_length + offset, data, len); @@ -215,7 +238,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned /*total } else { // Because of aggregation chunk body sections do not go to Inspector on schedule or in chronological order - // with respect to otherchunks. That means NHttpMsgChunkBody::update_flow() cannot do it design-intended + // with respect to chunk header sections. That means NHttpMsgChunkBody::update_flow() cannot do it design-intended // job of updating type_expected in time for StreamSplitter to find the next chunk header. So we do it here. session_data->type_expected[source_id] = SEC_CHUNKHEAD; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h index 7cb89d5c2..3b312dad6 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h @@ -48,6 +48,7 @@ private: void prepare_flush(NHttpFlowData* session_data, uint32_t* flush_offset, NHttpEnums::SourceId source_id, NHttpEnums::SectionType section_type, bool tcp_close, uint64_t infractions, uint32_t num_octets, uint32_t length); void create_event(NHttpEnums::EventSid sid); + uint32_t size_buffer_needed(unsigned total, NHttpEnums::SectionType type, uint32_t possible_additional); NHttpInspect* const my_inspector;