]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
stream: use reassembly fast path after proto detect
authorVictor Julien <victor@inliniac.net>
Mon, 31 Aug 2015 16:50:06 +0000 (18:50 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 18 Sep 2015 14:55:18 +0000 (16:55 +0200)
Use the reassembly fast paths only after protocol detection has completed.
In some corner cases the sending of smaller segments lead to protocol
detection failing.

src/stream-tcp-reassemble.c

index 912a446d3cb7d63eeb93670c8d5a4fbfdda79037..632b966fc0f91e146387ceee2ae3dd4a6e976457 100644 (file)
@@ -2620,51 +2620,58 @@ static inline int DoReassemble(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
                  TcpSession *ssn, TcpStream *stream, TcpSegment *seg, ReassembleData *rd,
                  Packet *p)
 {
-    /* fast path 1: segment is exactly what we need */
-    if (likely(rd->data_len == 0 &&
-               SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
-               SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len))))
-    {
-        /* process single segment directly */
-        AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                seg->payload, seg->payload_len,
-                StreamGetAppLayerFlags(ssn, stream, p));
-        AppLayerProfilingStore(ra_ctx->app_tctx, p);
-        rd->data_sent += seg->payload_len;
-        rd->ra_base_seq += seg->payload_len;
+    /* fast paths: send data directly into the app layer, w/o first doing
+     * a copy step. However, don't use the fast path until protocol detection
+     * has been completed
+     * TODO if initial data is big enough for proto detect, we could do the
+     *      fast path anyway. */
+    if (stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED) {
+        /* fast path 1: segment is exactly what we need */
+        if (likely(rd->data_len == 0 &&
+                    SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
+                    SEQ_EQ(stream->last_ack, (seg->seq + seg->payload_len))))
+        {
+            /* process single segment directly */
+            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+                    seg->payload, seg->payload_len,
+                    StreamGetAppLayerFlags(ssn, stream, p));
+            AppLayerProfilingStore(ra_ctx->app_tctx, p);
+            rd->data_sent += seg->payload_len;
+            rd->ra_base_seq += seg->payload_len;
 #ifdef DEBUG
-        ra_ctx->fp1++;
+            ra_ctx->fp1++;
 #endif
-        /* if after the first data chunk we have no alproto yet,
-         * there is no point in continueing here. */
-        if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-            SCLogDebug("no alproto after first data chunk");
-            return 0;
-        }
-        return 1;
-    /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */
-    } else if (rd->data_len == 0 &&
-               SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
-               SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) &&
-               seg->payload_len >= stream_config.zero_copy_size)
-    {
-        /* process single segment directly */
-        AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
-                seg->payload, seg->payload_len,
-                StreamGetAppLayerFlags(ssn, stream, p));
-        AppLayerProfilingStore(ra_ctx->app_tctx, p);
-        rd->data_sent += seg->payload_len;
-        rd->ra_base_seq += seg->payload_len;
+            /* if after the first data chunk we have no alproto yet,
+             * there is no point in continueing here. */
+            if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
+                SCLogDebug("no alproto after first data chunk");
+                return 0;
+            }
+            return 1;
+            /* fast path 2: segment acked completely, meets minimal size req for 0copy processing */
+        } else if (rd->data_len == 0 &&
+                SEQ_EQ(seg->seq, rd->ra_base_seq+1) &&
+                SEQ_GT(stream->last_ack, (seg->seq + seg->payload_len)) &&
+                seg->payload_len >= stream_config.zero_copy_size)
+        {
+            /* process single segment directly */
+            AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
+                    seg->payload, seg->payload_len,
+                    StreamGetAppLayerFlags(ssn, stream, p));
+            AppLayerProfilingStore(ra_ctx->app_tctx, p);
+            rd->data_sent += seg->payload_len;
+            rd->ra_base_seq += seg->payload_len;
 #ifdef DEBUG
-        ra_ctx->fp2++;
+            ra_ctx->fp2++;
 #endif
-        /* if after the first data chunk we have no alproto yet,
-         * there is no point in continueing here. */
-        if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
-            SCLogDebug("no alproto after first data chunk");
-            return 0;
+            /* if after the first data chunk we have no alproto yet,
+             * there is no point in continueing here. */
+            if (!StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) {
+                SCLogDebug("no alproto after first data chunk");
+                return 0;
+            }
+            return 1;
         }
-        return 1;
     }
 #ifdef DEBUG
     ra_ctx->sp++;