From 05539d7357feb1833420364986af10f680626e64 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 25 Jan 2011 18:16:57 +0100 Subject: [PATCH] Fix a reassembly overlap issue. Fix a inline reassembly gap handling issue. --- src/stream-tcp-reassemble.c | 133 +++++++++++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 1 deletion(-) diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 4abb1b019f..b261c6e98d 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -897,6 +897,46 @@ static int HandleSegmentStartsBeforeListSegment(ThreadVars *tv, TcpReassemblyThr } } } else if (end_after == TRUE) { + if (list_seg->prev != NULL && SEQ_LT((list_seg->prev->seq + list_seg->prev->payload_len), list_seg->seq)) { + SCLogDebug("GAP to fill before list segment, size %u", list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len)); + + packet_length = list_seg->seq - (list_seg->prev->seq + list_seg->prev->payload_len); + if (packet_length > seg->payload_len) { + packet_length = seg->payload_len; + } + + TcpSegment *new_seg = StreamTcpGetSegment(tv, ra_ctx, packet_length); + if (new_seg == NULL) { + SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[packet_length]); + + StreamTcpSetEvent(p, STREAM_REASSEMBLY_NO_SEGMENT); + SCReturnInt(-1); + } + new_seg->payload_len = packet_length; + + if (SEQ_GT((list_seg->prev->seq + + list_seg->prev->payload_len), seg->seq)) + { + new_seg->seq = (list_seg->prev->seq + + list_seg->prev->payload_len); + } else { + new_seg->seq = seg->seq; + } + + SCLogDebug("new_seg->seq %"PRIu32" and new->payload_len " + "%" PRIu16"", new_seg->seq, new_seg->payload_len); + + new_seg->next = list_seg; + new_seg->prev = list_seg->prev; + list_seg->prev->next = new_seg; + list_seg->prev = new_seg; + + /* create a new seg, copy the list_seg data over */ + StreamTcpSegmentDataCopy(new_seg, seg); + + PrintList(stream->seg_list); + } + if (list_seg->next != NULL) { if (SEQ_LEQ((seg->seq + seg->payload_len), list_seg->next->seq)) { @@ -1944,6 +1984,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx, stream->ra_app_base_seq = ra_base_seq; } data_sent += data_len; + data_len = 0; } /* don't conclude it's a gap straight away. If ra_base_seq is lower @@ -3554,7 +3595,9 @@ void StreamTcpSegmentDataCopy(TcpSegment *dst_seg, TcpSegment *src_seg) dst_pos = dst_seg->seq - src_seg->seq; SCLogDebug("Copying data from dst_pos %"PRIu16"", dst_pos); - for (i = src_seg->seq; SEQ_LT(i, (src_seg->seq + src_seg->payload_len)); i++) + for (i = src_seg->seq; + (SEQ_LT(i, (src_seg->seq + src_seg->payload_len)) && + SEQ_LT(i, (dst_seg->seq + dst_seg->payload_len))); i++) { dst_seg->payload[dst_pos] = src_seg->payload[src_pos]; @@ -8831,6 +8874,92 @@ end: return ret; } +/** \test test insert with overlap + */ +static int StreamTcpReassembleInsertTest01(void) { + int ret = 0; + TcpReassemblyThreadCtx *ra_ctx = NULL; + ThreadVars tv; + TcpSession ssn; + Flow f; + + memset(&tv, 0x00, sizeof(tv)); + + StreamTcpUTInit(&ra_ctx); + StreamTcpUTSetupSession(&ssn); + StreamTcpUTSetupStream(&ssn.client, 1); + FLOW_INITIALIZE(&f); + + uint8_t stream_payload1[] = "AAAAABBBBBCCCCCDDDDD"; + uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' }; + Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); + if (p == NULL) { + printf("couldn't get a packet: "); + goto end; + } + p->tcph->th_seq = htonl(12); + p->flow = &f; + + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) { + printf("failed to add segment 1: "); + goto end; + } + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) { + printf("failed to add segment 2: "); + goto end; + } + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 14, 'D', 2) == -1) { + printf("failed to add segment 3: "); + goto end; + } + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 16, 'D', 6) == -1) { + printf("failed to add segment 4: "); + goto end; + } + if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) { + printf("failed to add segment 5: "); + goto end; + } + ssn.client.next_seq = 21; + + int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p); + if (r < 0) { + printf("StreamTcpReassembleInlineRaw failed: "); + goto end; + } + + if (ra_ctx->stream_q->len != 1) { + printf("expected a single stream message, got %u: ", ra_ctx->stream_q->len); + goto end; + } + + StreamMsg *smsg = ra_ctx->stream_q->top; + if (smsg->data.data_len != 20) { + printf("expected data length to be 20, got %u: ", smsg->data.data_len); + goto end; + } + + if (!(memcmp(stream_payload1, smsg->data.data, 20) == 0)) { + printf("data is not what we expected:\nExpected:\n"); + PrintRawDataFp(stdout, stream_payload1, 20); + printf("Got:\n"); + PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len); + goto end; + } + + if (ssn.client.ra_raw_base_seq != 21) { + printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq); + goto end; + } + ret = 1; +end: + FLOW_DESTROY(&f); + UTHFreePacket(p); + StreamTcpUTClearSession(&ssn); + StreamTcpUTDeinit(ra_ctx); + return ret; +} + #endif /* UNITTESTS */ /** \brief The Function Register the Unit tests to test the reassembly engine @@ -8899,6 +9028,8 @@ void StreamTcpReassembleRegisterTests(void) { UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1); + UtRegisterTest("StreamTcpReassembleInsertTest01 -- insert with overlap", StreamTcpReassembleInsertTest01, 1); + StreamTcpInlineRegisterTests(); StreamTcpUtilRegisterTests(); #endif /* UNITTESTS */