diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 8159c613df..1e901b3b0e 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -2095,339 +2095,6 @@ static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg) stream->seg_list_tail = seg->prev; } -/** - * \brief Update the stream reassembly upon receiving a data segment - * - * Reassembly is in the same direction of the packet. - * - * One of the utilities called by this function AppLayerHandleTCPData(), - * has a feature where it will call this very same function for the - * stream opposing the stream it is called with. This shouldn't cause - * any issues, since processing of each stream is independent of the - * other stream. - * - * \todo this function is too long, we need to break it up. It needs it BAD - */ -int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p) -{ - SCEnter(); - - /* this function can be directly called by app layer protocol - * detection. */ - if (stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) { - SCLogDebug("stream no reassembly flag set. Mostly called via " - "app proto detection."); - SCReturnInt(0); - } - - SCLogDebug("pcap_cnt %"PRIu64", len %u", p->pcap_cnt, p->payload_len); - - SCLogDebug("stream->seg_list %p", stream->seg_list); -#ifdef DEBUG - PrintList(stream->seg_list); - //PrintRawDataFp(stdout, p->payload, p->payload_len); -#endif - - if (stream->seg_list == NULL) { - /* send an empty EOF msg if we have no segments but TCP state - * is beyond ESTABLISHED */ - if (ssn->state > TCP_ESTABLISHED) { - SCLogDebug("sending empty eof message"); - /* send EOF to app layer */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, NULL, 0, - StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - } else { - SCLogDebug("no segments in the list to reassemble"); - } - - SCReturnInt(0); - } - - if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) { - SCReturnInt(0); - } - - /* stream->ra_app_base_seq remains at stream->isn until protocol is - * detected. */ - uint32_t ra_base_seq = stream->ra_app_base_seq; - uint8_t data[4096]; - uint32_t data_len = 0; - uint16_t payload_offset = 0; - uint16_t payload_len = 0; - uint32_t next_seq = ra_base_seq + 1; - uint32_t data_sent = 0; - TcpSegment *seg = stream->seg_list; - - SCLogDebug("ra_base_seq %u", ra_base_seq); - - /* Check if we have a gap at the start of the list. If last_ack is - * bigger than the list start and the list start is bigger than - * next_seq, we know we are missing data that has been ack'd. That - * won't get retransmitted, so it's a data gap. - */ - if (!(p->flow->flags & FLOW_NO_APPLAYER_INSPECTION)) { - if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) { - /* send gap signal */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - SCReturnInt(0); - } - } - - /* loop through the segments and fill one or more msgs */ - SCLogDebug("pre-loop seg %p", seg); - for (; seg != NULL;) { - SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32, - seg, seg->seq, seg->payload_len, - (uint32_t)(seg->seq + seg->payload_len)); - - if (p->flow->flags & FLOW_NO_APPLAYER_INSPECTION) { - SCLogDebug("FLOW_NO_APPLAYER_INSPECTION set, breaking out"); - break; - } - - if (StreamTcpReturnSegmentCheck(p->flow, ssn, stream, seg) == 1) { - SCLogDebug("removing segment"); - TcpSegment *next_seg = seg->next; - StreamTcpRemoveSegmentFromStream(stream, seg); - 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 */ - if (SEQ_GT(seg->seq, next_seq)) { - SCLogDebug("GAP: we expected %u, got %u. Diff %u", next_seq, seg->seq, seg->seq - next_seq); - - /* don't conclude it's a gap until we see that the data - * that is missing was acked. */ - if (SEQ_GT(seg->seq,stream->last_ack) && ssn->state != TCP_CLOSED) - break; - - /* first, pass on data before the gap */ - if (data_len > 0) { - SCLogDebug("pre GAP data"); - - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_len = 0; - } - - /* see what the length of the gap is, gap length is seg->seq - - * (ra_base_seq +1) */ -#ifdef DEBUG - uint32_t gap_len = seg->seq - next_seq; - SCLogDebug("expected next_seq %" PRIu32 ", got %" PRIu32 " , " - "stream->last_ack %" PRIu32 ". Seq gap %" PRIu32"", - next_seq, seg->seq, stream->last_ack, gap_len); -#endif - /* We have missed the packet and end host has ack'd it, so - * IDS should advance it's ra_base_seq and should not consider this - * packet any longer, even if it is retransmitted, as end host will - * drop it anyway */ - ra_base_seq = seg->seq - 1; - - /* send gap signal */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - - /* set a GAP flag and make sure not bothering this stream anymore */ - SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set"); - stream->flags |= STREAMTCP_STREAM_FLAG_GAP; - - StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP); - SCPerfCounterIncr(ra_ctx->counter_tcp_reass_gap, tv->sc_perf_pca); -#ifdef DEBUG - dbg_app_layer_gap++; -#endif - break; - } - - /* if the segment ends beyond ra_base_seq we need to consider it */ - if (SEQ_GT((seg->seq + seg->payload_len), (ra_base_seq + 1))) { - SCLogDebug("seg->seq %" PRIu32 ", seg->payload_len %" PRIu32 ", " - "ra_base_seq %" PRIu32 "", seg->seq, - seg->payload_len, ra_base_seq); - - /* handle segments partly before ra_base_seq */ - if (SEQ_GT(ra_base_seq, seg->seq)) { - payload_offset = ra_base_seq - seg->seq - 1; - payload_len = seg->payload_len - payload_offset; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - BUG_ON((payload_len + payload_offset) > seg->payload_len); - } - } else { - payload_offset = 0; - payload_len = seg->payload_len; - } - SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" - " and stream->next_win is %"PRIu32"", payload_offset, - payload_len, stream->next_win); - - if (payload_len == 0) { - SCLogDebug("no payload_len, so bail out"); - break; - } - - /* copy the data into the smsg */ - uint16_t copy_size = sizeof(data) - data_len; - if (copy_size > payload_len) { - copy_size = payload_len; - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - SCLogDebug("copy_size is %"PRIu16"", copy_size); - memcpy(data + data_len, seg->payload + payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32", data_len %"PRIu32, ra_base_seq, data_len); - - /* queue the smsg if it's full */ - if (data_len == sizeof(data)) { - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - data_len = 0; - } - - /* if the payload len is bigger than what we copied, we handle the - * rest of the payload next... */ - if (copy_size < payload_len) { - SCLogDebug("copy_size %" PRIu32 " < %" PRIu32 "", copy_size, - payload_len); - - payload_offset += copy_size; - payload_len -= copy_size; - SCLogDebug("payload_offset is %"PRIu16", seg->payload_len is " - "%"PRIu16" and stream->last_ack is %"PRIu32"", - payload_offset, seg->payload_len, stream->last_ack); - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - - /* we need a while loop here as the packets theoretically can be - * 64k */ - char segment_done = FALSE; - while (segment_done == FALSE) { - SCLogDebug("new msg at offset %" PRIu32 ", payload_len " - "%" PRIu32 "", payload_offset, payload_len); - data_len = 0; - - copy_size = sizeof(data) - data_len; - if (copy_size > (seg->payload_len - payload_offset)) { - copy_size = (seg->payload_len - payload_offset); - } - if (SCLogDebugEnabled()) { - BUG_ON(copy_size > sizeof(data)); - } - - SCLogDebug("copy payload_offset %" PRIu32 ", data_len " - "%" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - memcpy(data + data_len, seg->payload + - payload_offset, copy_size); - data_len += copy_size; - ra_base_seq += copy_size; - SCLogDebug("ra_base_seq %"PRIu32, ra_base_seq); - SCLogDebug("copied payload_offset %" PRIu32 ", " - "data_len %" PRIu32 ", copy_size %" PRIu32 "", - payload_offset, data_len, copy_size); - - if (data_len == sizeof(data)) { - /* process what we have so far */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - data_len = 0; - } - - /* see if we have segment payload left to process */ - if ((copy_size + payload_offset) < seg->payload_len) { - payload_offset += copy_size; - payload_len -= copy_size; - - if (SCLogDebugEnabled()) { - BUG_ON(payload_offset > seg->payload_len); - } - } else { - payload_offset = 0; - segment_done = TRUE; - } - } - } - } - - /* done with this segment, return it to the pool */ - TcpSegment *next_seg = seg->next; - next_seq = seg->seq + seg->payload_len; - seg->flags |= SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - seg = next_seg; - } - - /* put the partly filled smsg in the queue to the l7 handler */ - if (data_len > 0) { - SCLogDebug("data_len > 0, %u", data_len); - /* process what we have so far */ - BUG_ON(data_len > sizeof(data)); - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - data, data_len, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - data_sent += data_len; - } - - if (data_sent == 0 && ssn->state > TCP_ESTABLISHED) { - SCLogDebug("sending empty eof message"); - /* send EOF to app layer */ - AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream, - NULL, 0, StreamGetAppLayerFlags(ssn, stream, p)); - AppLayerProfilingStore(ra_ctx->app_tctx, p); - } - - /* store ra_base_seq in the stream */ - if (StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream)) { - stream->ra_app_base_seq = ra_base_seq; - } else { - TcpSegment *tmp_seg = stream->seg_list; - while (tmp_seg != NULL) { - tmp_seg->flags &= ~SEGMENTTCP_FLAG_APPLAYER_PROCESSED; - tmp_seg = tmp_seg->next; - } - } - - SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq); - SCReturnInt(0); -} - /** * \brief Update the stream reassembly upon receiving a data segment * diff --git a/src/stream-tcp-reassemble.h b/src/stream-tcp-reassemble.h index 7eca5cf683..b66334a999 100644 --- a/src/stream-tcp-reassemble.h +++ b/src/stream-tcp-reassemble.h @@ -79,10 +79,6 @@ void StreamTcpReassembleFreeThreadCtx(TcpReassemblyThreadCtx *); int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx, TcpSession *ssn, TcpStream *stream, Packet *p); -int StreamTcpReassembleInlineAppLayer(ThreadVars *tv, - TcpReassemblyThreadCtx *ra_ctx, - TcpSession *ssn, TcpStream *stream, - Packet *p); void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);