diff --git a/src/stream-tcp-private.h b/src/stream-tcp-private.h index d15ea90cd8..617dc4479f 100644 --- a/src/stream-tcp-private.h +++ b/src/stream-tcp-private.h @@ -28,6 +28,7 @@ typedef struct TcpStream_ { TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */ uint8_t os_policy; /**< target based OS policy used for reassembly and handling packets*/ uint8_t flags; /**< Flag specific to the stream e.g. Timestamp */ + TcpSegment *seg_list_tail; /**< Last segment in the reassembled stream seg list*/ } TcpStream; /* from /usr/include/netinet/tcp.h */ diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 3eeef90203..6cfd9bbf4a 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -274,9 +274,22 @@ static int ReassembleInsertSegment(TcpStream *stream, TcpSegment *seg) { seg, seg->seq, seg->payload_len); stream->seg_list = seg; seg->prev = NULL; + stream->seg_list_tail = seg; goto end; } + /* insert the segment in the stream list using this fast track, if seg->seq + is equal or higher than stream->seg_list_tail.*/ + if (SEQ_GEQ(seg->seq, (stream->seg_list_tail->seq + + stream->seg_list_tail->payload_len))) { + + stream->seg_list_tail->next = seg; + seg->prev = stream->seg_list_tail; + stream->seg_list_tail = seg; + + return 0; + } + for (; list_seg != NULL; list_seg = list_seg->next) { SCLogDebug("seg %p, list_seg %p, list_prev %p list_seg->next %p, segment length %" PRIu32 "", seg, list_seg, list_seg->prev, list_seg->next, seg->payload_len); @@ -441,6 +454,10 @@ static int HandleSegmentStartsBeforeListSegment(TcpStream *stream, TcpSegment *l StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->seq + list_seg->payload_len), (uint16_t) (((seg->seq + seg->payload_len) - (list_seg->seq + list_seg->payload_len)))); } + /*update the stream last_seg in case of removal of list_seg*/ + if (stream->seg_list_tail == list_seg) + stream->seg_list_tail = new_seg; + StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; if (new_seg->prev != NULL) { @@ -476,6 +493,10 @@ static int HandleSegmentStartsBeforeListSegment(TcpStream *stream, TcpSegment *l SCLogDebug("copy_len %" PRIu32 " (%" PRIu32 " - %" PRIu32 ")", copy_len, list_seg->seq, (list_seg->prev->seq + list_seg->prev->payload_len)); StreamTcpSegmentDataReplace(new_seg, seg, (list_seg->prev->seq + list_seg->prev->payload_len), copy_len); + /*update the stream last_seg in case of removal of list_seg*/ + if (stream->seg_list_tail == list_seg) + stream->seg_list_tail = new_seg; + StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; if (new_seg->prev != NULL) { @@ -524,6 +545,10 @@ static int HandleSegmentStartsBeforeListSegment(TcpStream *stream, TcpSegment *l if (new_seg->next != NULL) { new_seg->next->prev = new_seg; } + /*update the stream last_seg in case of removal of list_seg*/ + if (stream->seg_list_tail == list_seg) + stream->seg_list_tail = new_seg; + StreamTcpSegmentReturntoPool(list_seg); list_seg = new_seg; } @@ -658,6 +683,10 @@ static int HandleSegmentStartsAtSameListSegment(TcpStream *stream, TcpSegment *l list_seg->next = new_seg; SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, list_seg->next %p", new_seg, new_seg->next, new_seg->prev, list_seg->next); StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, new_seg->payload_len); + + /*update the stream last_seg in case of removal of list_seg*/ + if (stream->seg_list_tail == list_seg) + stream->seg_list_tail = new_seg; } } switch (os_policy) { @@ -809,6 +838,10 @@ static int HandleSegmentStartsAfterListSegment(TcpStream *stream, TcpSegment *li SCLogDebug("new_seg %p, new_seg->next %p, new_seg->prev %p, list_seg->next %p", new_seg, new_seg->next, new_seg->prev, list_seg->next); StreamTcpSegmentDataReplace(new_seg, seg, new_seg->seq, new_seg->payload_len); + + /*update the stream last_seg in case of removal of list_seg*/ + if (stream->seg_list_tail == list_seg) + stream->seg_list_tail = new_seg; } } switch (os_policy) { @@ -982,6 +1015,7 @@ int StreamTcpReassembleHandleSegmentUpdateACK (TcpReassemblyThreadCtx *ra_ctx, T SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32" len %"PRIu16"", stream->ra_base_seq, seg, seg->seq, seg->payload_len); TcpSegment *next_seg = seg->next; + if (seg->prev == NULL) { stream->seg_list = seg->next; if (stream->seg_list != NULL) @@ -992,6 +1026,8 @@ int StreamTcpReassembleHandleSegmentUpdateACK (TcpReassemblyThreadCtx *ra_ctx, T seg->next->prev = seg->prev; } + if (stream->seg_list_tail == seg) + stream->seg_list_tail = next_seg; StreamTcpSegmentReturntoPool(seg); seg = next_seg; continue; @@ -1160,6 +1196,10 @@ int StreamTcpReassembleHandleSegmentUpdateACK (TcpReassemblyThreadCtx *ra_ctx, T if (stream->seg_list != NULL) stream->seg_list->prev = NULL; + /* Update seg_list_tail, in case it also points to this segment*/ + if (stream->seg_list_tail == seg) + stream->seg_list_tail = next_seg; + StreamTcpSegmentReturntoPool(seg); seg = next_seg; } @@ -2601,7 +2641,7 @@ static int StreamTcpReassembleTest25 (void) { printf("failed in segments reassembly: "); goto end; } - + stream.next_seq = 14; StreamTcpCreateTestPacket(payload, 0x41, 3); /*AAA*/ seq = 7; if (StreamTcpTestMissedPacket (ra_ctx, &stream, seq, ack, payload, 3, th_flag, flowflags, TCP_ESTABLISHED) == -1) { @@ -2989,6 +3029,87 @@ end: StreamTcpReassembleFreeThreadCtx(ra_ctx); return ret; } + +/** + * \test Test to reassemble the packets using the fast track method, as most + * packets arrives in order. + * + * \retval On success it returns 1 and on failure 0. + */ + +static int StreamTcpReassembleTest31 (void) { + int ret = 0; + uint8_t payload[4]; + uint32_t seq; + uint32_t ack; + uint8_t th_flag; + uint8_t th_flags; + uint8_t flowflags; + uint8_t check_contents[5] = {0x41, 0x41, 0x42, 0x42, 0x42}; + TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(); + TcpStream stream; + memset(&stream, 0, sizeof (TcpStream)); + + flowflags = FLOW_PKT_TOSERVER; + th_flag = TH_ACK|TH_PUSH; + th_flags = TH_ACK; + + stream.ra_base_seq = 9; + stream.isn = 9; + StreamTcpInitConfig(TRUE); + + StreamTcpCreateTestPacket(payload, 0x41, 2); /*AA*/ + seq = 10; + ack = 20; + if (StreamTcpTestMissedPacket (ra_ctx, &stream, seq, ack, payload, 2, th_flag, flowflags, TCP_ESTABLISHED) == -1){ + printf("failed in segments reassembly: "); + goto end; + } + + flowflags = FLOW_PKT_TOSERVER; + StreamTcpCreateTestPacket(payload, 0x42, 1); /*B*/ + seq = 15; + ack = 20; + if (StreamTcpTestMissedPacket (ra_ctx, &stream, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { + printf("failed in segments reassembly: "); + goto end; + } + + flowflags = FLOW_PKT_TOSERVER; + StreamTcpCreateTestPacket(payload, 0x42, 1); /*B*/ + seq = 12; + ack = 20; + if (StreamTcpTestMissedPacket (ra_ctx, &stream, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { + printf("failed in segments reassembly: "); + goto end; + } + + flowflags = FLOW_PKT_TOSERVER; + StreamTcpCreateTestPacket(payload, 0x42, 1); /*B*/ + seq = 16; + ack = 20; + if (StreamTcpTestMissedPacket (ra_ctx, &stream, seq, ack, payload, 1, th_flag, flowflags, TCP_ESTABLISHED) == -1) { + printf("failed in segments reassembly: "); + goto end; + } + + if (StreamTcpCheckStreamContents(check_contents, 5, &stream) == 0) { + printf("failed in stream matching: "); + goto end; + } + + if (stream.seg_list_tail->seq != 16) { + printf("failed in fast track handling: "); + goto end; + } + + ret = 1; +end: + StreamTcpFreeConfig(TRUE); + StreamTcpReassembleFreeThreadCtx(ra_ctx); + return ret; +} + #endif /* UNITTESTS */ /** \brief The Function Register the Unit tests to test the reassembly engine @@ -3027,5 +3148,6 @@ void StreamTcpReassembleRegisterTests(void) { UtRegisterTest("StreamTcpReassembleTest28 -- Gap at Start IDS missed packet Reassembly Test", StreamTcpReassembleTest28, 1); UtRegisterTest("StreamTcpReassembleTest29 -- Gap at Middle IDS missed packet Reassembly Test", StreamTcpReassembleTest29, 1); UtRegisterTest("StreamTcpReassembleTest30 -- Gap at End IDS missed packet Reassembly Test", StreamTcpReassembleTest30, 1); + UtRegisterTest("StreamTcpReassembleTest31 -- Fast Track Reassembly Test", StreamTcpReassembleTest31, 1); #endif /* UNITTESTS */ }