From: Victor Julien Date: Thu, 24 Apr 2014 08:48:37 +0000 (+0200) Subject: stream: implement raw reassembly stop api X-Git-Tag: suricata-2.0.1rc1~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3543150f42572742ed6554a90ff35e8abdf316a0;p=thirdparty%2Fsuricata.git stream: implement raw reassembly stop api Implement StreamTcpSetDisableRawReassemblyFlag() which stops raw reassembly for _NEW_ segments in a stream direction. It is used only by TLS/SSL now, to flag the streams as encrypted. Existing segments will still be reassembled and inspected, while new segments won't be. This allows for pattern based inspection of the TLS handshake. Like is the case with completely disabled 'raw' reassembly, the logic is that the segments are flagged as completed for 'raw' right away. So they are not considered in raw reassembly anymore. As no new segments will be considered, the chunk limit check will return true on the next call. --- diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 24c22d9a75..75bfc9f477 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -850,9 +850,18 @@ int AppLayerParserParse(AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alp } /* In cases like HeartBleed for TLS we need to inspect AppLayer but not Payload */ - if (pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) { + if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION) && pstate->flags & APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD) { FlowSetNoPayloadInspectionFlag(f); - AppLayerParserTriggerRawStreamReassembly(f); + /* Set the no reassembly flag for both the stream in this TcpSession */ + if (f->proto == IPPROTO_TCP) { + /* Used only if it's TCP */ + TcpSession *ssn = f->protoctx; + if (ssn != NULL) { + StreamTcpSetDisableRawReassemblyFlag(ssn, 0); + StreamTcpSetDisableRawReassemblyFlag(ssn, 1); + AppLayerParserTriggerRawStreamReassembly(f); + } + } } /* next, see if we can get rid of transactions now */ diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index 7f576396c1..e8635c8750 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -165,6 +165,8 @@ enum #define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_COMPLETED 0x0080 /** App proto detection skipped */ #define STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED 0x0100 +/** Raw reassembly disabled for new segments */ +#define STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED 0x0200 /* * Per SEGMENT flags diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 53a740ffe1..7dc7b7696a 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1882,6 +1882,14 @@ int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThre seg->payload_len = size; seg->seq = TCP_GET_SEQ(p); + /* if raw reassembly is disabled for new segments, flag each + * segment as complete for raw before insert */ + if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) { + seg->flags |= SEGMENTTCP_FLAG_RAW_PROCESSED; + SCLogDebug("segment %p flagged with SEGMENTTCP_FLAG_RAW_PROCESSED, " + "flags %02x", seg, seg->flags); + } + /* proto detection skipped, but now we do get data. Set event. */ if (stream->seg_list == NULL && stream->flags & STREAMTCP_STREAM_FLAG_APPPROTO_DETECTION_SKIPPED) { @@ -1965,6 +1973,12 @@ static int StreamTcpReassembleRawCheckLimit(TcpSession *ssn, TcpStream *stream, SCReturnInt(1); } + if (stream->flags & STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) { + SCLogDebug("reassembling now as STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED is set, " + "so no new segments will be considered"); + SCReturnInt(1); + } + /* some states mean we reassemble no matter how much data we have */ if (ssn->state >= TCP_TIME_WAIT) SCReturnInt(1); @@ -2725,10 +2739,8 @@ static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, Tc } /* check raw reassembly conditions */ - if (!(f->flags & FLOW_NOPAYLOAD_INSPECTION)) { - if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { - SCReturnInt(0); - } + if (!(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED)) { + SCReturnInt(0); } SCReturnInt(1); @@ -2935,6 +2947,10 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; + } else if (StreamTcpAppLayerSegmentProcessed(stream, seg)) { + TcpSegment *next_seg = seg->next; + seg = next_seg; + continue; } /* we've run into a sequence gap */ @@ -3235,11 +3251,6 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, seg, seg->seq, seg->payload_len, (uint32_t)(seg->seq + seg->payload_len), seg->flags); - if (p->flow->flags & FLOW_NOPAYLOAD_INSPECTION) { - SCLogDebug("FLOW_NOPAYLOAD_INSPECTION set, breaking out"); - break; - } - if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { SCLogDebug("removing segment"); TcpSegment *next_seg = seg->next; @@ -3247,6 +3258,10 @@ static int StreamTcpReassembleRaw (TcpReassemblyThreadCtx *ra_ctx, StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; + } else if(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) { + TcpSegment *next_seg = seg->next; + seg = next_seg; + continue; } /* we've run into a sequence gap */ diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index dd2dc6574a..7eca5cf683 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -87,6 +87,7 @@ int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t); void StreamTcpSetSessionNoReassemblyFlag (TcpSession *, char ); +void StreamTcpSetDisableRawReassemblyFlag (TcpSession *ssn, char direction); void StreamTcpSetOSPolicy(TcpStream *, Packet *); void StreamTcpReassemblePause (TcpSession *, char ); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 3fc268c041..5034156989 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -5223,6 +5223,18 @@ void StreamTcpSetSessionNoReassemblyFlag (TcpSession *ssn, char direction) (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NOREASSEMBLY); } +/** \brief Set the No reassembly flag for the given direction in given TCP + * session. + * + * \param ssn TCP Session to set the flag in + * \param direction direction to set the flag in: 0 toserver, 1 toclient + */ +void StreamTcpSetDisableRawReassemblyFlag (TcpSession *ssn, char direction) +{ + direction ? (ssn->server.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED) : + (ssn->client.flags |= STREAMTCP_STREAM_FLAG_NEW_RAW_DISABLED); +} + #define PSEUDO_PKT_SET_IPV4HDR(nipv4h,ipv4h) do { \ IPV4_SET_RAW_VER(nipv4h, IPV4_GET_RAW_VER(ipv4h)); \ IPV4_SET_RAW_HLEN(nipv4h, IPV4_GET_RAW_HLEN(ipv4h)); \