]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
split out scan result into its own enum
authorTom Peters <thopeter@cisco.com>
Mon, 22 Sep 2014 19:07:59 +0000 (15:07 -0400)
committerTom Peters <thopeter@cisco.com>
Mon, 22 Sep 2014 19:07:59 +0000 (15:07 -0400)
src/service_inspectors/nhttp_inspect/nhttp_enum.h
src/service_inspectors/nhttp_inspect/nhttp_splitter.cc
src/service_inspectors/nhttp_inspect/nhttp_splitter.h
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h

index 397c1357e3e46a9dfe4c11c4f8c59757bbaf0bdc..87a2098ebbf6d057401c108fca59195b2b5bffad 100644 (file)
@@ -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;
 
index eb184567ed509f5dfc1b316756c6018096da9da8..b1eb274ce61e7733aac4a9f583d5993ecd7b61d5 100644 (file)
@@ -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 <CR> and <LF> 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 <CR> and <LF> 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 <CR> and <LF> 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 <CR> and <LF> 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;
 }
 
 
index d8d5d726da135437659e5fe7b6dabe8b837a82f0..24c819bd125c9a96e4e1a6f230c25c90c9e3f368 100644 (file)
@@ -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
index dcc10326de3b7481f04bf93bfc7c85e2d2bcd777..5d3b8eda0119b3371e9348c7a3e8cbd5637f7004 100644 (file)
@@ -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;
 
index 7cb89d5c2ccb1483f9d85ef5ede30b97fd6359b0..3b312dad6a177fff3552b4597667eef85629bc22 100644 (file)
@@ -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;