tcp: streaming implementation

Make stream engine use the streaming buffer API for it's data storage.

This means that the data is stored in a single reassembled sliding
buffer. The subleties of the reassembly, e.g. overlap handling, are
taken care of at segment insertion.

The TcpSegments now have a StreamingBufferSegment that contains an
offset and a length. Using this the segment data can be retrieved
per segment.

Redo segment insertion. The insertion code is moved to it's own file
and is simplified a lot.

A major difference with the previous implementation is that the segment
list now contains overlapping segments if the traffic is that way.
Previously there could be more and smaller segments in the memory list
than what was seen on the wire.

Due to the matching of in memory segments and on the wire segments,
the overlap with different data detection (potential mots attacks)
is much more accurate.

Raw and App reassembly progress is no longer tracked per segment using
flags, but there is now a progress tracker in the TcpStream for each.

When pruning we make sure we don't slide beyond in-use segments. When
both app-layer and raw inspection are beyond the start of the segment
list, the segments might not be freed even though the data in the
streaming buffer is already gone. This is caused by the 'in-use' status
that the segments can implicitly have. This patch accounts for that
when calculating the 'left_edge' of the streaming window.

Raw reassembly still sets up 'StreamMsg' objects for content
inspection. They are set up based on either the full StreamingBuffer,
or based on the StreamingBufferBlocks if there are gaps in the data.

Reworked 'stream needs work' logic. When a flow times out the flow
engine checks whether a TCP flow still needs work. The
StreamNeedsReassembly function is used to test if a stream still has
unreassembled segments or uninspected stream chunks.

This patch updates the function to consider the app and/or raw
progress. It also cleans the function up and adds more meaningful
debug messages. Finally it makes it non-inline.

Unittests have been overhauled, and partly moved into their own files.

Remove lots of dead code.
pull/2673/head
Victor Julien 11 years ago
parent 3fa2e8689c
commit 8c9f521707

@ -337,6 +337,7 @@ source-pfring.c source-pfring.h \
stream.c stream.h \
stream-tcp.c stream-tcp.h stream-tcp-private.h \
stream-tcp-inline.c stream-tcp-inline.h \
stream-tcp-list.c stream-tcp-list.h \
stream-tcp-reassemble.c stream-tcp-reassemble.h \
stream-tcp-sack.c stream-tcp-sack.h \
stream-tcp-util.c stream-tcp-util.h \

@ -665,6 +665,8 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
ssn->toserver_smsg_tail = NULL;
SCLogDebug("to_server smsg %p at stream eof", smsg);
if (smsg)
SCLogDebug("to_server smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
} else {
smsg = ssn->toclient_smsg_head;
/* deref from the ssn */
@ -672,6 +674,8 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
ssn->toclient_smsg_tail = NULL;
SCLogDebug("to_client smsg %p at stream eof", smsg);
if (smsg)
SCLogDebug("to_client smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
}
} else {
if (p->flowflags & FLOW_PKT_TOSERVER) {
@ -694,7 +698,7 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
ssn->toserver_smsg_head = NULL;
ssn->toserver_smsg_tail = NULL;
SCLogDebug("to_server smsg %p", smsg);
SCLogDebug("to_server smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
} else {
StreamMsg *head = ssn->toclient_smsg_head;
if (unlikely(head == NULL))
@ -713,12 +717,22 @@ static StreamMsg *SigMatchSignaturesGetSmsg(Flow *f, Packet *p, uint8_t flags)
ssn->toclient_smsg_head = NULL;
ssn->toclient_smsg_tail = NULL;
SCLogDebug("to_client smsg %p", smsg);
SCLogDebug("to_client smsg %p, size %u, SEQ %u", smsg, smsg->data_len, smsg->seq);
}
}
}
end:
#ifdef DEBUG
if (SCLogDebugEnabled()) {
StreamMsg *m = smsg;
while(m) {
SCLogDebug("m %p size %u, SEQ %u", m, m->data_len, m->seq);
PrintRawDataFp(stdout, m->data, m->data_len);
m = m->next;
}
}
#endif
SCReturnPtr(smsg, "StreamMsg");
}

@ -1200,7 +1200,6 @@ static int FlowMgrTest02 (void)
struct timeval ts;
TcpSegment seg;
TcpStream client;
uint8_t payload[3] = {0x41, 0x41, 0x41};
FlowQueueInit(&flow_spare_q);
@ -1216,8 +1215,7 @@ static int FlowMgrTest02 (void)
f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE;
TimeGet(&ts);
seg.payload = payload;
seg.payload_len = 3;
TCP_SEG_LEN(&seg) = 3;
seg.next = NULL;
seg.prev = NULL;
client.seg_list = &seg;
@ -1308,7 +1306,6 @@ static int FlowMgrTest04 (void)
struct timeval ts;
TcpSegment seg;
TcpStream client;
uint8_t payload[3] = {0x41, 0x41, 0x41};
FlowQueueInit(&flow_spare_q);
@ -1324,8 +1321,7 @@ static int FlowMgrTest04 (void)
f.flags |= FLOW_TIMEOUT_REASSEMBLY_DONE;
TimeGet(&ts);
seg.payload = payload;
seg.payload_len = 3;
TCP_SEG_LEN(&seg) = 3;
seg.next = NULL;
seg.prev = NULL;
client.seg_list = &seg;

@ -220,7 +220,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p,
} else {
p->tcph->th_seq = htonl(ssn->client.next_seq);
p->tcph->th_ack = htonl(ssn->server.seg_list_tail->seq +
ssn->server.seg_list_tail->payload_len);
TCP_SEG_LEN(ssn->server.seg_list_tail));
}
/* to client */
@ -234,7 +234,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p,
} else {
p->tcph->th_seq = htonl(ssn->server.next_seq);
p->tcph->th_ack = htonl(ssn->client.seg_list_tail->seq +
ssn->client.seg_list_tail->payload_len);
TCP_SEG_LEN(ssn->client.seg_list_tail));
}
}

@ -266,7 +266,7 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t
continue;
}
if (SEQ_GT(seg->seq + seg->payload_len, stream->last_ack)) {
if (SEQ_GT(seg->seq + TCP_SEG_LEN(seg), stream->last_ack)) {
SCLogDebug("seg not (fully) acked yet");
break;
}
@ -278,7 +278,11 @@ int StreamIterator(Flow *f, TcpStream *stream, int close, void *cbdata, uint8_t
if (close && seg->next == NULL)
flags |= OUTPUT_STREAMING_FLAG_CLOSE;
Streamer(cbdata, f, seg->payload, (uint32_t)seg->payload_len, 0, flags);
const uint8_t *seg_data;
uint32_t seg_datalen;
StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
Streamer(cbdata, f, seg_data, seg_datalen, 0, flags);
seg->flags |= SEGMENTTCP_FLAG_LOGAPI_PROCESSED;

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2011 Open Information Security Foundation
/* Copyright (C) 2007-2016 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -24,6 +24,7 @@
*/
#include "suricata-common.h"
#include "stream-tcp-private.h"
#include "stream-tcp-inline.h"
#include "util-memcmp.h"
@ -57,66 +58,52 @@ int StreamTcpInlineMode(void)
* \retval 0 shared data is the same (or no data is shared)
* \retval 1 shared data is different
*/
int StreamTcpInlineSegmentCompare(TcpSegment *seg1, TcpSegment *seg2)
int StreamTcpInlineSegmentCompare(TcpStream *stream, Packet *p, TcpSegment *seg)
{
SCEnter();
if (seg1 == NULL || seg2 == NULL) {
if (p == NULL || seg == NULL) {
SCReturnInt(0);
}
if (SEQ_EQ(seg1->seq, seg2->seq) && seg1->payload_len == seg2->payload_len) {
int r = SCMemcmp(seg1->payload, seg2->payload, seg1->payload_len);
#if 0
if (r) {
PrintRawDataFp(stdout,seg1->payload,seg1->payload_len);
PrintRawDataFp(stdout,seg2->payload,seg2->payload_len);
}
#endif
const uint8_t *seg_data;
uint32_t seg_datalen;
StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
const uint32_t pkt_seq = TCP_GET_SEQ(p);
if (SEQ_EQ(pkt_seq, seg->seq) && p->payload_len == seg_datalen) {
int r = SCMemcmp(p->payload, seg_data, seg_datalen);
SCReturnInt(r);
} else if (SEQ_GT(seg1->seq, (seg2->seq + seg2->payload_len))) {
} else if (SEQ_GT(pkt_seq, (seg->seq + seg_datalen))) {
SCReturnInt(0);
} else if (SEQ_GT(seg2->seq, (seg1->seq + seg1->payload_len))) {
} else if (SEQ_GT(seg->seq, (pkt_seq + p->payload_len))) {
SCReturnInt(0);
} else {
SCLogDebug("seg1 %u (%u), seg2 %u (%u)", seg1->seq,
seg1->payload_len, seg2->seq, seg2->payload_len);
uint32_t seg1_end = seg1->seq + seg1->payload_len;
uint32_t seg2_end = seg2->seq + seg2->payload_len;
SCLogDebug("seg1_end %u, seg2_end %u", seg1_end, seg2_end);
#if 0
SCLogDebug("seg1");
PrintRawDataFp(stdout,seg1->payload,seg1->payload_len);
SCLogDebug("seg2");
PrintRawDataFp(stdout,seg2->payload,seg2->payload_len);
#endif
SCLogDebug("p %u (%u), seg2 %u (%u)", pkt_seq,
p->payload_len, seg->seq, seg_datalen);
uint32_t pkt_end = pkt_seq + p->payload_len;
uint32_t seg_end = seg->seq + seg_datalen;
SCLogDebug("pkt_end %u, seg_end %u", pkt_end, seg_end);
/* get the minimal seg*_end */
uint32_t end = (SEQ_GT(seg1_end, seg2_end)) ? seg2_end : seg1_end;
uint32_t end = (SEQ_GT(pkt_end, seg_end)) ? seg_end : pkt_end;
/* and the max seq */
uint32_t seq = (SEQ_LT(seg1->seq, seg2->seq)) ? seg2->seq : seg1->seq;
uint32_t seq = (SEQ_LT(pkt_seq, seg->seq)) ? seg->seq : pkt_seq;
SCLogDebug("seq %u, end %u", seq, end);
uint16_t seg1_off = seq - seg1->seq;
uint16_t seg2_off = seq - seg2->seq;
SCLogDebug("seg1_off %u, seg2_off %u", seg1_off, seg2_off);
uint16_t pkt_off = seq - pkt_seq;
uint16_t seg_off = seq - seg->seq;
SCLogDebug("pkt_off %u, seg_off %u", pkt_off, seg_off);
uint32_t range = end - seq;
SCLogDebug("range %u", range);
BUG_ON(range > 65536);
if (range) {
int r = SCMemcmp(seg1->payload+seg1_off, seg2->payload+seg2_off, range);
#if 0
if (r) {
PrintRawDataFp(stdout,seg1->payload+seg1_off,range);
PrintRawDataFp(stdout,seg2->payload+seg2_off,range);
PrintRawDataFp(stdout,seg1->payload,seg1->payload_len);
PrintRawDataFp(stdout,seg2->payload,seg2->payload_len);
}
#endif
int r = SCMemcmp(p->payload + pkt_off, seg_data + seg_off, range);
SCReturnInt(r);
}
SCReturnInt(0);
@ -133,7 +120,7 @@ int StreamTcpInlineSegmentCompare(TcpSegment *seg1, TcpSegment *seg2)
* \todo What about reassembled fragments?
* \todo What about unwrapped tunnel packets?
*/
void StreamTcpInlineSegmentReplacePacket(Packet *p, TcpSegment *seg)
void StreamTcpInlineSegmentReplacePacket(TcpStream *stream, Packet *p, TcpSegment *seg)
{
SCEnter();
@ -141,505 +128,169 @@ void StreamTcpInlineSegmentReplacePacket(Packet *p, TcpSegment *seg)
uint32_t tseq = seg->seq;
/* check if segment is within the packet */
if (tseq + seg->payload_len < pseq) {
if (tseq + TCP_SEG_LEN(seg) < pseq) {
SCReturn;
} else if (pseq + p->payload_len < tseq) {
SCReturn;
} else {
/** \todo review logic */
uint32_t pend = pseq + p->payload_len;
uint32_t tend = tseq + seg->payload_len;
SCLogDebug("pend %u, tend %u", pend, tend);
}
//SCLogDebug("packet");
//PrintRawDataFp(stdout,p->payload,p->payload_len);
//SCLogDebug("seg");
//PrintRawDataFp(stdout,seg->payload,seg->payload_len);
const uint8_t *seg_data;
uint32_t seg_datalen;
StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
/* get the minimal seg*_end */
uint32_t end = (SEQ_GT(pend, tend)) ? tend : pend;
/* and the max seq */
uint32_t seq = (SEQ_LT(pseq, tseq)) ? tseq : pseq;
uint32_t pend = pseq + p->payload_len;
uint32_t tend = tseq + seg_datalen;
SCLogDebug("pend %u, tend %u", pend, tend);
SCLogDebug("seq %u, end %u", seq, end);
/* get the minimal seg*_end */
uint32_t end = (SEQ_GT(pend, tend)) ? tend : pend;
/* and the max seq */
uint32_t seq = (SEQ_LT(pseq, tseq)) ? tseq : pseq;
SCLogDebug("seq %u, end %u", seq, end);
uint16_t poff = seq - pseq;
uint16_t toff = seq - tseq;
SCLogDebug("poff %u, toff %u", poff, toff);
uint16_t poff = seq - pseq;
uint16_t toff = seq - tseq;
SCLogDebug("poff %u, toff %u", poff, toff);
uint32_t range = end - seq;
SCLogDebug("range %u", range);
BUG_ON(range > 65536);
uint32_t range = end - seq;
SCLogDebug("range %u", range);
BUG_ON(range > 65536);
if (range) {
/* update the packets payload. As payload is a ptr to either
* p->pkt or p->ext_pkt that is updated as well */
memcpy(p->payload+poff, seg->payload+toff, range);
if (range) {
/* update the packets payload. As payload is a ptr to either
* p->pkt or p->ext_pkt that is updated as well */
memcpy(p->payload+poff, seg_data+toff, range);
/* flag as modified so we can reinject / replace after
* recalculating the checksum */
p->flags |= PKT_STREAM_MODIFIED;
}
/* flag as modified so we can reinject / replace after
* recalculating the checksum */
p->flags |= PKT_STREAM_MODIFIED;
}
}
#ifdef UNITTESTS
/** \test full overlap */
static int StreamTcpInlineTest01(void)
{
SCEnter();
uint8_t payload1[] = "AAC"; /* packet */
uint8_t payload2[] = "ABC"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000000UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000000UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (!(p->flags & PKT_STREAM_MODIFIED)) {
printf("PKT_STREAM_MODIFIED pkt flag not set: ");
goto end;
}
#include "stream-tcp-util.h"
if (memcmp(p->payload, t->payload, p->payload_len) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Segment:\n");
PrintRawDataFp(stdout,t->payload,t->payload_len);
printf("payloads didn't match: ");
goto end;
static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
{
if (StreamingBufferCompareRawData(stream->sb,
data, data_len) == 0)
{
SCReturnInt(0);
}
SCLogInfo("OK");
PrintRawDataFp(stdout, data, data_len);
return 1;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
if (memcmp(pkt,payload2,sizeof(payload2)-1) != 0) {
PrintRawDataFp(stdout,pkt,3);
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
goto end;
}
#define INLINE_START(isn) \
Packet *p; \
TcpReassemblyThreadCtx *ra_ctx = NULL; \
TcpSession ssn; \
ThreadVars tv; \
memset(&tv, 0, sizeof(tv)); \
\
StreamTcpUTInit(&ra_ctx); \
StreamTcpUTInitInline(); \
\
StreamTcpUTSetupSession(&ssn); \
StreamTcpUTSetupStream(&ssn.server, (isn)); \
StreamTcpUTSetupStream(&ssn.client, (isn)); \
\
TcpStream *stream = &ssn.client;
#define INLINE_END \
StreamTcpUTClearSession(&ssn); \
StreamTcpUTDeinit(ra_ctx); \
PASS
#define INLINE_STEP(rseq, seg, seglen, buf, buflen, packet, packetlen) \
p = UTHBuildPacketReal((uint8_t *)(seg), (seglen), IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80); \
FAIL_IF(p == NULL); \
p->tcph->th_seq = htonl(stream->isn + (rseq)); \
p->tcph->th_ack = htonl(31); \
FAIL_IF (StreamTcpReassembleHandleSegmentHandleData(&tv, ra_ctx, &ssn, stream, p) < 0); \
FAIL_IF (memcmp(p->payload, packet, MIN((packetlen),p->payload_len)) != 0); \
UTHFreePacket(p); \
FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
/** \test full overlap */
static int StreamTcpInlineTest01(void)
{
INLINE_START(0);
INLINE_STEP(1, "AAC", 3, "AAC", 3, "AAC", 3);
INLINE_STEP(1, "ABC", 3, "AAC", 3, "AAC", 3);
INLINE_END;
}
/** \test full overlap */
static int StreamTcpInlineTest02(void)
{
SCEnter();
uint8_t payload1[] = "xxx"; /* packet */
uint8_t payload2[] = "ABCDE"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000001UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000000UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (!(p->flags & PKT_STREAM_MODIFIED)) {
printf("PKT_STREAM_MODIFIED pkt flag not set: ");
goto end;
}
if (memcmp(p->payload, t->payload+1, p->payload_len) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Segment:\n");
PrintRawDataFp(stdout,t->payload,t->payload_len);
printf("payloads didn't match: ");
goto end;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
if (memcmp(pkt,payload2+1,sizeof(payload2)-3) != 0) {
printf("Segment:\n");
PrintRawDataFp(stdout,payload2+1,sizeof(payload2)-3);
printf("Packet:\n");
PrintRawDataFp(stdout,pkt,3);
printf("Packet (full):\n");
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
printf("packet data doesn't match: ");
goto end;
}
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
INLINE_START(0);
INLINE_STEP(1, "ABCDE", 5, "ABCDE", 5, "ABCDE", 5);
INLINE_STEP(2, "xxx", 3, "ABCDE", 5, "BCD", 3);
INLINE_END;
}
/** \test partial overlap */
static int StreamTcpInlineTest03(void)
{
SCEnter();
uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
uint8_t payload2[] = "ABCDE"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000000UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000003UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (!(p->flags & PKT_STREAM_MODIFIED)) {
printf("PKT_STREAM_MODIFIED pkt flag not set: ");
goto end;
}
if (memcmp(p->payload+3, t->payload, t->payload_len) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Segment:\n");
PrintRawDataFp(stdout,t->payload,t->payload_len);
printf("payloads didn't match: ");
goto end;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1 + 3);
if (memcmp(pkt,payload2,sizeof(payload2)-1) != 0) {
printf("Segment:\n");
PrintRawDataFp(stdout,payload2+1,sizeof(payload2)-3);
printf("Packet:\n");
PrintRawDataFp(stdout,pkt,3);
printf("Packet (full):\n");
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
printf("packet data doesn't match: ");
goto end;
}
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
INLINE_START(0);
INLINE_STEP(1, "ABCDE", 5, "ABCDE", 5, "ABCDE", 5);
INLINE_STEP(3, "xxxxx", 5, "ABCDExx", 7, "CDExx", 5);
INLINE_END;
}
/** \test partial overlap */
static int StreamTcpInlineTest04(void)
{
SCEnter();
uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
uint8_t payload2[] = "ABCDE"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000003UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000000UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (!(p->flags & PKT_STREAM_MODIFIED)) {
printf("PKT_STREAM_MODIFIED pkt flag not set: ");
goto end;
}
if (memcmp(p->payload, t->payload+3, 2) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Segment:\n");
PrintRawDataFp(stdout,t->payload,t->payload_len);
printf("payloads didn't match: ");
goto end;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
if (memcmp(pkt,payload2+3,2) != 0) {
printf("Segment:\n");
PrintRawDataFp(stdout,payload2+3,2);
printf("Packet:\n");
PrintRawDataFp(stdout,pkt,3);
printf("Packet (full):\n");
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
printf("packet data doesn't match: ");
goto end;
}
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
INLINE_START(0);
INLINE_STEP(3, "ABCDE", 5, "\0\0ABCDE", 7, "ABCDE", 5);
INLINE_STEP(1, "xxxxx", 5, "xxABCDE", 7, "xxABC", 5);
INLINE_END;
}
/** \test partial overlap */
/** \test no overlap */
static int StreamTcpInlineTest05(void)
{
SCEnter();
uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
uint8_t payload2[] = "ABCDE"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000000UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000010UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (!(p->flags & PKT_STREAM_MODIFIED)) {
printf("PKT_STREAM_MODIFIED pkt flag not set: ");
goto end;
}
if (memcmp(p->payload+10, t->payload, 2) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Segment:\n");
PrintRawDataFp(stdout,t->payload,t->payload_len);
printf("payloads didn't match: ");
goto end;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
if (memcmp(pkt+10,payload2,2) != 0) {
printf("Segment:\n");
PrintRawDataFp(stdout,payload2,2);
printf("Packet:\n");
PrintRawDataFp(stdout,pkt,3);
printf("Packet (full):\n");
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
printf("packet data doesn't match: ");
goto end;
}
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
INLINE_START(0);
INLINE_STEP(8, "ABCDE", 5, "\0\0\0\0\0\0\0ABCDE", 12, "ABCDE", 5);
INLINE_STEP(1, "xxxxx", 5, "xxxxx\0\0ABCDE", 12, "xxxxx", 5);
INLINE_END;
}
/** \test no overlap */
/** \test multiple overlaps */
static int StreamTcpInlineTest06(void)
{
SCEnter();
uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
uint8_t payload2[] = "ABCDE"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000020UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000000UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (p->flags & PKT_STREAM_MODIFIED) {
printf("PKT_STREAM_MODIFIED pkt flag set, but it shouldn't: ");
goto end;
}
if (memcmp(p->payload, payload1, sizeof(payload1)-1) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Original payload:\n");
PrintRawDataFp(stdout,payload1,sizeof(payload1)-1);
printf("payloads didn't match: ");
goto end;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
if (memcmp(pkt,payload1,sizeof(payload1)-1) != 0) {
printf("Segment:\n");
PrintRawDataFp(stdout,payload2,2);
printf("Packet:\n");
PrintRawDataFp(stdout,pkt,3);
printf("Packet (full):\n");
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
printf("packet data doesn't match: ");
goto end;
}
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
INLINE_START(0);
INLINE_STEP(2, "A", 1, "\0A", 2, "A", 1);
INLINE_STEP(4, "A", 1, "\0A\0A", 4, "A", 1);
INLINE_STEP(6, "A", 1, "\0A\0A\0A", 6, "A", 1);
INLINE_STEP(8, "A", 1, "\0A\0A\0A\0A", 8, "A", 1);
INLINE_STEP(1, "xxxxxxxxx", 9, "xAxAxAxAx", 9, "xAxAxAxAx", 9);
INLINE_END;
}
/** \test no overlap */
/** \test overlap, data not different */
static int StreamTcpInlineTest07(void)
{
SCEnter();
uint8_t payload1[] = "xxxxxxxxxxxx"; /* packet */
uint8_t payload2[] = "ABCDE"; /* segment */
int result = 0;
TcpSegment *t = NULL;
Packet *p = UTHBuildPacketSrcDstPorts(payload1, sizeof(payload1)-1, IPPROTO_TCP, 1024, 80);
if (p == NULL || p->tcph == NULL) {
printf("generating test packet failed: ");
goto end;
}
p->tcph->th_seq = htonl(10000000UL);
t = SCMalloc(sizeof(TcpSegment));
if (unlikely(t == NULL)) {
printf("alloc TcpSegment failed: ");
goto end;
}
memset(t, 0x00, sizeof(TcpSegment));
t->payload = payload2;
t->payload_len = sizeof(payload2)-1;
t->seq = 10000020UL;
StreamTcpInlineSegmentReplacePacket(p, t);
if (p->flags & PKT_STREAM_MODIFIED) {
printf("PKT_STREAM_MODIFIED pkt flag set, but it shouldn't: ");
goto end;
}
if (memcmp(p->payload, payload1, sizeof(payload1)-1) != 0) {
printf("Packet:\n");
PrintRawDataFp(stdout,p->payload,p->payload_len);
printf("Original payload:\n");
PrintRawDataFp(stdout,payload1,sizeof(payload1)-1);
printf("payloads didn't match: ");
goto end;
}
uint8_t *pkt = GET_PKT_DATA(p)+(GET_PKT_LEN(p)-sizeof(payload1)+1);
if (memcmp(pkt,payload1,sizeof(payload1)-1) != 0) {
printf("Segment:\n");
PrintRawDataFp(stdout,payload2,2);
printf("Packet:\n");
PrintRawDataFp(stdout,pkt,3);
printf("Packet (full):\n");
PrintRawDataFp(stdout,GET_PKT_DATA(p),GET_PKT_LEN(p));
printf("packet data doesn't match: ");
goto end;
}
INLINE_START(0);
INLINE_STEP(3, "ABCDE", 5, "\0\0ABCDE", 7, "ABCDE", 5);
INLINE_STEP(1, "XXABC", 5, "XXABCDE", 7, "XXABC", 5);
INLINE_END;
}
result = 1;
end:
if (p != NULL) {
UTHFreePacket(p);
}
if (t != NULL) {
SCFree(t);
}
SCReturnInt(result);
static int StreamTcpInlineTest08(void)
{
INLINE_START(0);
INLINE_STEP(1, "AAAAA", 5, "AAAAA", 5, "AAAAA", 5);
INLINE_STEP(1, "BBBBB", 5, "AAAAA", 5, "AAAAA", 5);
INLINE_STEP(1, "CCCCCCCCCC", 10, "AAAAACCCCC", 10, "AAAAACCCCC", 10);
INLINE_STEP(10, "X", 1, "AAAAACCCCC", 10, "C", 1);
INLINE_STEP(11, "X", 1, "AAAAACCCCCX", 11, "X", 1);
INLINE_END;
}
#endif /* UNITTESTS */
void StreamTcpInlineRegisterTests(void)
@ -652,6 +303,7 @@ void StreamTcpInlineRegisterTests(void)
UtRegisterTest("StreamTcpInlineTest05", StreamTcpInlineTest05);
UtRegisterTest("StreamTcpInlineTest06", StreamTcpInlineTest06);
UtRegisterTest("StreamTcpInlineTest07", StreamTcpInlineTest07);
UtRegisterTest("StreamTcpInlineTest08", StreamTcpInlineTest08);
#endif /* UNITTESTS */
}

@ -1,4 +1,4 @@
/* Copyright (C) 2007-2011 Open Information Security Foundation
/* Copyright (C) 2007-2016 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -27,8 +27,8 @@
#include "stream-tcp-private.h"
int StreamTcpInlineMode(void);
int StreamTcpInlineSegmentCompare(TcpSegment *, TcpSegment *);
void StreamTcpInlineSegmentReplacePacket(Packet *, TcpSegment *);
int StreamTcpInlineSegmentCompare(TcpStream *, Packet *, TcpSegment *);
void StreamTcpInlineSegmentReplacePacket(TcpStream *, Packet *, TcpSegment *);
void StreamTcpInlineRegisterTests(void);

@ -0,0 +1,883 @@
/* Copyright (C) 2007-2016 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/** \file
*
* Segment list functions for insertions, overlap handling, removal and
* more.
*/
#include "suricata-common.h"
#include "stream-tcp-private.h"
#include "stream-tcp.h"
#include "stream-tcp-reassemble.h"
#include "stream-tcp-inline.h"
#include "stream-tcp-list.h"
#include "util-streaming-buffer.h"
#include "util-print.h"
//static void PrintList2(TcpSegment *seg);
static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg);
static int check_overlap_different_data = 0;
void StreamTcpReassembleConfigEnableOverlapCheck(void)
{
check_overlap_different_data = 1;
}
/*
* Inserts and overlap handling
*/
/** \internal
* \brief insert segment data into the streaming buffer
* \param seg segment to store stream offset in
* \param data segment data after overlap handling (if any)
* \param data_len data length
*/
static inline int InsertSegmentDataCustom(TcpStream *stream, TcpSegment *seg, uint8_t *data, uint16_t data_len)
{
uint64_t stream_offset;
uint16_t data_offset;
if (likely(SEQ_GEQ(seg->seq, stream->base_seq))) {
stream_offset = stream->base_seq_offset + (seg->seq - stream->base_seq);
data_offset = 0;
} else {
/* segment is partly before base_seq */
data_offset = stream->base_seq - seg->seq;
stream_offset = stream->base_seq_offset;
}
SCLogDebug("stream %p buffer %p, stream_offset %"PRIu64", "
"data_offset %"PRIu16", SEQ %u BASE %u, data_len %u",
stream, stream->sb, stream_offset,
data_offset, seg->seq, stream->base_seq, data_len);
BUG_ON(data_offset > data_len);
if (data_len == data_offset) {
SCReturnInt(0);
}
if (StreamingBufferInsertAt(stream->sb, &seg->sbseg,
data + data_offset,
data_len - data_offset,
stream_offset) != 0) {
SCReturnInt(-1);
}
#ifdef DEBUG
{
const uint8_t *mydata;
uint32_t mydata_len;
uint64_t mydata_offset;
StreamingBufferGetData(stream->sb, &mydata, &mydata_len, &mydata_offset);
SCLogDebug("stream %p seg %p data in buffer %p of len %u and offset %u",
stream, seg, stream->sb, mydata_len, (uint)mydata_offset);
//PrintRawDataFp(stdout, mydata, mydata_len);
}
#endif
SCReturnInt(0);
}
/** \internal
* \brief insert the segment into the proper place in the list
* don't worry about the data or overlaps
*
* If seq is equal to list seq, keep sorted by insert time.
* 1. seg 123 len 12
* 2. seg 123 len 14
* 3. seg 124 len 1
*
* \retval 1 inserted with overlap detected
* \retval 0 inserted, no overlap
* \retval -1 error
*/
static int DoInsertSegment (TcpStream *stream, TcpSegment *seg, Packet *p)
{
if (unlikely(stream->sb == NULL)) {
stream->sb = StreamingBufferInit(&stream_config.sbcnf);
if (stream->sb == NULL) {
return -1;
}
}
/* before our base_seq we don't insert it in our list */
if (SEQ_LEQ((seg->seq + TCP_SEG_LEN(seg)), stream->base_seq))
{
SCLogDebug("not inserting: SEQ+payload %"PRIu32", last_ack %"PRIu32", "
"base_seq %"PRIu32, (seg->seq + TCP_SEG_LEN(seg)),
stream->last_ack, stream->base_seq);
StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEGMENT_BEFORE_BASE_SEQ);
return -1;
}
/* fast track */
if (stream->seg_list == NULL) {
SCLogDebug("empty list, inserting seg %p seq %" PRIu32 ", "
"len %" PRIu32 "", seg, seg->seq, TCP_SEG_LEN(seg));
stream->seg_list = seg;
seg->prev = NULL;
stream->seg_list_tail = seg;
return 0;
}
/* 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 +
TCP_SEG_LEN(stream->seg_list_tail))))
{
SCLogDebug("seg beyond list tail, append");
stream->seg_list_tail->next = seg;
seg->prev = stream->seg_list_tail;
stream->seg_list_tail = seg;
return 0;
}
/* walk the list to see where we can insert the segment.
* Check if a segment overlaps with us, if so we return 1 to indicate
* to the caller that we need to handle overlaps. */
TcpSegment *list_seg;
for (list_seg = stream->seg_list; list_seg != NULL; list_seg = list_seg->next)
{
if (SEQ_LT(seg->seq, list_seg->seq)) {
if (list_seg->prev != NULL) {
list_seg->prev->next = seg;
} else {
stream->seg_list = seg;
}
seg->prev = list_seg->prev;
seg->next = list_seg;
list_seg->prev = seg;
SCLogDebug("inserted %u before %p seq %u", seg->seq, list_seg, list_seg->seq);
if (seg->prev != NULL) {
SCLogDebug("previous %u", seg->prev->seq);
}
if (seg->next != NULL) {
SCLogDebug("next %u", seg->next->seq);
}
if (seg->prev != NULL && SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg->prev), seg->seq)) {
SCLogDebug("seg inserted with overlap (before)");
return 1;
}
else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), seg->next->seq)) {
SCLogDebug("seg inserted with overlap (after)");
return 1;
}
return 0;
}
}
/* if we got here we didn't insert. Append */
seg->prev = stream->seg_list_tail;
stream->seg_list_tail->next = seg;
stream->seg_list_tail = seg;
if (seg->prev != NULL && SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg->prev), seg->seq)) {
SCLogDebug("seg inserted with overlap (before)");
return 1;
}
SCLogDebug("default: append");
return 0;
}
/** \internal
* \brief handle overlap per list segment
*
* For a list segment handle the overlap according to the policy.
*
* The 'buf' parameter points to the memory that will be inserted into
* the stream after the overlap checks are complete. As it will
* unconditionally overwrite whats in the stream now, the overlap
* policies are applied to this buffer. It starts with the 'new' data,
* so when the policy states 'old' data has to be used, 'buf' is
* updated to contain the 'old' data here.
*
* \param buf stack allocated buffer sized p->payload_len that will be
* inserted into the stream buffer
*/
static int DoHandleDataOverlap(TcpStream *stream, TcpSegment *list, TcpSegment *seg, uint8_t *buf, Packet *p)
{
SCLogDebug("handle overlap for segment %p seq %u len %u re %u, "
"list segment %p seq %u len %u re %u", seg, seg->seq, p->payload_len, SEG_SEQ_RIGHT_EDGE(seg),
list, list->seq, TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list));
int data_is_different = 0;
int use_new_data = 0;
if (StreamTcpInlineMode()) {
SCLogDebug("inline mode");
if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) {
SCLogDebug("already accepted data not the same as packet data, rewrite packet");
StreamTcpInlineSegmentReplacePacket(stream, p, list);
data_is_different = 1;
/* in inline mode we check for different data unconditionally,
* but setting events still depends on config */
if (check_overlap_different_data) {
StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
}
}
/* IDS mode */
} else {
if (check_overlap_different_data) {
if (StreamTcpInlineSegmentCompare(stream, p, list) != 0) {
SCLogDebug("data is different from what is in the list");
data_is_different = 1;
StreamTcpSetEvent(p, STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA);
}
} else {
/* if we're not checking, assume it's different */
data_is_different = 1;
}
/* apply overlap policies */
if (stream->os_policy == OS_POLICY_LAST) {
/* buf will start with LAST data (from the segment),
* so if policy is LAST we're now done here. */
return 0;
}
/* start at the same seq */
if (SEQ_EQ(seg->seq, list->seq)) {
SCLogDebug("seg starts at list segment");
if (SEQ_LT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
SCLogDebug("seg ends before list end, end overlapped by list");
} else {
if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
SCLogDebug("seg ends beyond list end, list overlapped and more");
switch (stream->os_policy) {
case OS_POLICY_LINUX:
if (data_is_different) {
use_new_data = 1;
}
break;
}
} else {
SCLogDebug("full overlap");
}
switch (stream->os_policy) {
case OS_POLICY_OLD_LINUX:
case OS_POLICY_SOLARIS:
case OS_POLICY_HPUX11:
if (data_is_different) {
use_new_data = 1;
}
break;
}
}
/* new seg starts before list segment */
} else if (SEQ_LT(seg->seq, list->seq)) {
SCLogDebug("seg starts before list segment");
if (SEQ_LT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
SCLogDebug("seg ends before list end, end overlapped by list");
} else {
if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
SCLogDebug("seg starts before and fully overlaps list and beyond");
} else {
SCLogDebug("seg starts before and fully overlaps list");
}
switch (stream->os_policy) {
case OS_POLICY_SOLARIS:
case OS_POLICY_HPUX11:
if (data_is_different) {
use_new_data = 1;
}
break;
}
}
switch (stream->os_policy) {
case OS_POLICY_BSD:
case OS_POLICY_HPUX10:
case OS_POLICY_IRIX:
case OS_POLICY_WINDOWS:
case OS_POLICY_WINDOWS2K3:
case OS_POLICY_OLD_LINUX:
case OS_POLICY_LINUX:
case OS_POLICY_MACOS:
if (data_is_different) {
use_new_data = 1;
}
break;
}
/* new seg starts after list segment */
} else { //if (SEQ_GT(seg->seq, list->seq)) {
SCLogDebug("seg starts after list segment");
if (SEQ_EQ(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
SCLogDebug("seg after and is fully overlapped by list");
} else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(seg), SEG_SEQ_RIGHT_EDGE(list))) {
SCLogDebug("seg starts after list and ends after list");
switch (stream->os_policy) {
case OS_POLICY_SOLARIS:
case OS_POLICY_HPUX11:
if (data_is_different) {
use_new_data = 1;
}
break;
}
} else {
SCLogDebug("seg starts after list and ends before list end");
}
}
}
SCLogDebug("data_is_different %s, use_new_data %s",
data_is_different ? "yes" : "no",
use_new_data ? "yes" : "no");
/* if the data is different and we don't want to use the new (seg)
* data, we have to update buf with the list data */
if (data_is_different && !use_new_data) {
/* we need to copy list into seg */
uint16_t list_offset = 0;
uint16_t seg_offset = 0;
uint32_t list_len;
uint16_t seg_len = p->payload_len;
uint32_t list_seq = list->seq;
const uint8_t *list_data;
StreamingBufferSegmentGetData(stream->sb, &list->sbseg, &list_data, &list_len);
if (list_data == NULL || list_len == 0)
return 0;
BUG_ON(list_len > USHRT_MAX);
/* if list seg is partially before base_seq, list_len (from stream) and
* TCP_SEG_LEN(list) will not be the same */
if (SEQ_GEQ(list->seq, stream->base_seq)) {
;
} else {
list_seq = stream->base_seq;
list_len = SEG_SEQ_RIGHT_EDGE(list) - stream->base_seq;
}
if (SEQ_LT(seg->seq, list_seq)) {
seg_offset = list_seq - seg->seq;
seg_len -= seg_offset;
} else if (SEQ_GT(seg->seq, list_seq)) {
list_offset = seg->seq - list_seq;
list_len -= list_offset;
}
if (SEQ_LT(seg->seq + seg_offset + seg_len, list_seq + list_offset + list_len)) {
list_len -= (list_seq + list_offset + list_len) - (seg->seq + seg_offset + seg_len);
}
SCLogDebug("here goes nothing: list %u %u, seg %u %u", list_offset, list_len, seg_offset, seg_len);
//PrintRawDataFp(stdout, list_data + list_offset, list_len);
//PrintRawDataFp(stdout, buf + seg_offset, seg_len);
memcpy(buf + seg_offset, list_data + list_offset, list_len);
//PrintRawDataFp(stdout, buf, p->payload_len);
}
return 0;
}
#define MAX_IP_DATA (uint32_t)(65536 - 40) // min ip header and min tcp header
/** \internal
* \brief walk segment list backwards to see if there are overlaps
*
* Walk back from the current segment which is already in the list.
* We walk until we can't possibly overlap anymore.
*/
static int DoHandleDataCheckBackwards(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p)
{
SCLogDebug("check list backwards: insert data for segment %p seq %u len %u re %u",
seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
TcpSegment *list = seg->prev;
do {
int overlap = 0;
if (SEQ_LEQ(SEG_SEQ_RIGHT_EDGE(list), stream->base_seq)) {
// segment entirely before base_seq
;
} else if (SEQ_LEQ(list->seq + MAX_IP_DATA, seg->seq)) {
SCLogDebug("list segment too far to the left, no more overlap will be found");
break;
} else if (SEQ_GT(SEG_SEQ_RIGHT_EDGE(list), seg->seq)) {
overlap = 1;
}
SCLogDebug("(back) list seg %u len %u re %u overlap? %s", list->seq, TCP_SEG_LEN(list),
SEG_SEQ_RIGHT_EDGE(list), overlap ? "yes" : "no");
if (overlap) {
DoHandleDataOverlap(stream, list, seg, buf, p);
}
list = list->prev;
} while (list != NULL);
return 0;
}
/** \internal
* \brief walk segment list in forward direction to see if there are overlaps
*
* Walk forward from the current segment which is already in the list.
* We walk until the next segs start with a SEQ beyond our right edge.
*/
static int DoHandleDataCheckForward(TcpStream *stream, TcpSegment *seg, uint8_t *buf, Packet *p)
{
uint32_t seg_re = SEG_SEQ_RIGHT_EDGE(seg);
SCLogDebug("check list forward: insert data for segment %p seq %u len %u re %u",
seg, seg->seq, TCP_SEG_LEN(seg), seg_re);
TcpSegment *list = seg->next;
do {
int overlap = 0;
if (SEQ_GT(seg_re, list->seq))
overlap = 1;
else if (SEQ_LEQ(seg_re, list->seq)) {
SCLogDebug("list segment %u too far ahead, "
"no more overlaps can happen", list->seq);
break;
}
SCLogDebug("(fwd) list seg %u len %u re %u overlap? %s", list->seq,
TCP_SEG_LEN(list), SEG_SEQ_RIGHT_EDGE(list), overlap ? "yes" : "no");
if (overlap) {
DoHandleDataOverlap(stream, list, seg, buf, p);
}
list = list->next;
} while (list != NULL);
return 0;
}
static int DoHandleData(TcpStream *stream, TcpSegment *seg, Packet *p)
{
SCLogDebug("insert data for segment %p seq %u len %u re %u",
seg, seg->seq, TCP_SEG_LEN(seg), SEG_SEQ_RIGHT_EDGE(seg));
/* create temporary buffer to contain the data we will insert. Overlap
* handling may update it. By using this we don't have to track whether
* parts of the data are already inserted or not. */
uint8_t buf[p->payload_len];
memcpy(buf, p->payload, p->payload_len);
/* new list head */
if (seg->next != NULL && seg->prev == NULL) {
DoHandleDataCheckForward(stream, seg, buf, p);
/* new list tail */
} else if (seg->next == NULL && seg->prev != NULL) {
DoHandleDataCheckBackwards(stream, seg, buf, p);
/* middle of the list */
} else if (seg->next != NULL && seg->prev != NULL) {
DoHandleDataCheckBackwards(stream, seg, buf, p);
DoHandleDataCheckForward(stream, seg, buf, p);
}
/* insert the temp buffer now that we've (possibly) updated
* it to account for the overlap policies */
if (InsertSegmentDataCustom(stream, seg, buf, p->payload_len) < 0) {
return -1;
}
return 0;
}
/**
* \retval -1 segment not inserted
*
* \param seg segment, this function takes total ownership
*
* In case of error, this function returns the segment to the pool
*/
int StreamTcpReassembleInsertSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
TcpStream *stream, TcpSegment *seg, Packet *p, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen)
{
/* insert segment into list. Note: doesn't handle the data */
#ifdef DEBUG
SCLogDebug("pre insert");
PrintList(stream->seg_list);
#endif
int r = DoInsertSegment (stream, seg, p);
#ifdef DEBUG
SCLogDebug("post insert");
PrintList(stream->seg_list);
#endif
if (likely(r == 0)) {
/* no overlap, straight data insert */
int res = InsertSegmentDataCustom(stream, seg, pkt_data, pkt_datalen);
if (res < 0) {
StreamTcpRemoveSegmentFromStream(stream, seg);
StreamTcpSegmentReturntoPool(seg);
SCReturnInt(-1);
}
} else if (r == 1) {
/* now let's consider the data in the overlap case */
int res = DoHandleData(stream, seg, p);
if (res < 0) {
StreamTcpRemoveSegmentFromStream(stream, seg);
StreamTcpSegmentReturntoPool(seg);
SCReturnInt(-1);
}
} else if (r < 0) {
StreamTcpSegmentReturntoPool(seg);
SCReturnInt(-1);
}
SCReturnInt(0);
}
/*
* Pruning & removal
*/
static inline int SegmentInUse(TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
{
if (stream == &ssn->client && ssn->toserver_smsg_head != NULL) {
/* not (seg is entirely before first smsg, skip) */
if (!(SEQ_LEQ(seg->seq + TCP_SEG_LEN(seg), ssn->toserver_smsg_head->seq))) {
SCReturnInt(1);
}
} else if (stream == &ssn->server && ssn->toclient_smsg_head != NULL) {
/* not (seg is entirely before first smsg, skip) */
if (!(SEQ_LEQ(seg->seq + TCP_SEG_LEN(seg), ssn->toclient_smsg_head->seq))) {
SCReturnInt(1);
}
}
/* if proto detect isn't done, we're not returning */
if (!(stream->flags & STREAMTCP_STREAM_FLAG_GAP)) {
if (!(StreamTcpIsSetStreamFlagAppProtoDetectionCompleted(stream))) {
SCReturnInt(1);
}
}
SCReturnInt(0);
}
/** \internal
* \brief check if we can remove a segment from our segment list
*
* If a segment is entirely before the oldest smsg, we can discard it. Otherwise
* we keep it around to be able to log it.
*
* \retval 1 yes
* \retval 0 no
*/
static inline int StreamTcpReturnSegmentCheck(const Flow *f, TcpSession *ssn, TcpStream *stream, TcpSegment *seg)
{
if (SegmentInUse(ssn, stream, seg)) {
SCReturnInt(0);
}
if (!(StreamingBufferSegmentIsBeforeWindow(stream->sb, &seg->sbseg))) {
SCReturnInt(0);
}
SCReturnInt(1);
}
static inline uint64_t GetLeftEdge(TcpSession *ssn, TcpStream *stream)
{
int use_app = 1;
int use_raw = 1;
uint64_t left_edge = 0;
if ((ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED) ||
(stream->flags & STREAMTCP_STREAM_FLAG_GAP))
{
// app is dead
use_app = 0;
}
if (ssn->flags & STREAMTCP_FLAG_DISABLE_RAW) {
// raw is dead
use_raw = 0;
}
if (use_app && use_raw) {
left_edge = MIN(stream->app_progress, stream->raw_progress);
SCLogDebug("left_edge %"PRIu64", using both app:%"PRIu64", raw:%"PRIu64,
left_edge, stream->app_progress, stream->raw_progress);
} else if (use_app) {
left_edge = stream->app_progress;
SCLogDebug("left_edge %"PRIu64", using app:%"PRIu64,
left_edge, stream->app_progress);
} else if (use_raw) {
left_edge = stream->raw_progress;
SCLogDebug("left_edge %"PRIu64", using raw:%"PRIu64,
left_edge, stream->raw_progress);
} else {
SCLogDebug("left_edge 0, none");
}
if (left_edge > 0) {
/* we know left edge based on the progress values now,
* lets adjust it to make sure in-use segments still have
* data */
TcpSegment *seg;
for (seg = stream->seg_list; seg != NULL; seg = seg->next)
{
if (TCP_SEG_OFFSET(seg) > left_edge) {
SCLogDebug("seg beyond left_edge, we're done");
break;
}
if (SegmentInUse(ssn, stream, seg)) {
left_edge = TCP_SEG_OFFSET(seg);
SCLogDebug("in-use seg before left_edge, adjust to %"PRIu64" and bail", left_edge);
break;
}
}
}
return left_edge;
}
static void StreamTcpRemoveSegmentFromStream(TcpStream *stream, TcpSegment *seg)
{
if (seg->prev == NULL) {
stream->seg_list = seg->next;
if (stream->seg_list != NULL)
stream->seg_list->prev = NULL;
} else {
seg->prev->next = seg->next;
if (seg->next != NULL)
seg->next->prev = seg->prev;
}
if (stream->seg_list_tail == seg)
stream->seg_list_tail = seg->prev;
}
/** \brief Remove idle TcpSegments from TcpSession
*
* \param f flow
* \param flags direction flags
*/
void StreamTcpPruneSession(Flow *f, uint8_t flags)
{
SCEnter();
if (f == NULL || f->protoctx == NULL) {
SCReturn;
}
TcpSession *ssn = f->protoctx;
TcpStream *stream = NULL;
if (flags & STREAM_TOSERVER) {
stream = &ssn->client;
} else if (flags & STREAM_TOCLIENT) {
stream = &ssn->server;
} else {
SCReturn;
}
uint64_t left_edge = GetLeftEdge(ssn, stream);
if (left_edge) {
/* in IPS mode we consider the chunk_size when sliding */
if (StreamTcpInlineMode() == TRUE) {
uint32_t chunk_size = (flags & STREAM_TOSERVER) ?
stream_config.reassembly_toserver_chunk_size :
stream_config.reassembly_toclient_chunk_size;
if ((uint64_t)chunk_size >= left_edge) {
left_edge = 0;
} else {
left_edge -= chunk_size;
}
}
if (left_edge > stream->base_seq_offset) {
uint32_t slide = left_edge - stream->base_seq_offset;
SCLogDebug("buffer sliding %u to offset %"PRIu64, slide, left_edge);
StreamingBufferSlideToOffset(stream->sb, left_edge);
stream->base_seq_offset += slide;
stream->base_seq += slide;
SCLogDebug("stream base_seq %u at stream offset %"PRIu64,
stream->base_seq, stream->base_seq_offset);
}
}
/* loop through the segments and fill one or more msgs */
TcpSegment *seg = stream->seg_list;
while (seg != NULL)
{
SCLogDebug("seg %p, SEQ %"PRIu32", LEN %"PRIu16", SUM %"PRIu32", FLAGS %02x",
seg, seg->seq, TCP_SEG_LEN(seg),
(uint32_t)(seg->seq + TCP_SEG_LEN(seg)), seg->flags);
if (StreamTcpReturnSegmentCheck(f, ssn, stream, seg) == 0) {
SCLogDebug("not removing segment");
break;
}
TcpSegment *next_seg = seg->next;
StreamTcpRemoveSegmentFromStream(stream, seg);
StreamTcpSegmentReturntoPool(seg);
seg = next_seg;
SCLogDebug("removed segment");
continue;
}
#ifdef DEBUG
PrintList(stream->seg_list);
#endif
SCReturn;
}
/*
* Utils
*/
#if 0
void PrintList2(TcpSegment *seg)
{
TcpSegment *prev_seg = NULL;
if (seg == NULL)
return;
uint32_t next_seq = seg->seq;
while (seg != NULL) {
if (SEQ_LT(next_seq,seg->seq)) {
SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
(seg->seq - next_seq));
}
SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p",
seg->seq, TCP_SEG_LEN(seg), seg, seg->prev, seg->next);
if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
/* check for SEQ_LT cornercase where a - b is exactly 2147483648,
* which makes the marco return TRUE in both directions. This is
* a hack though, we're going to check next how we end up with
* a segment list with seq differences that big */
if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) =="
" TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 ""
"", seg->seq, seg->prev->seq);
}
}
if (SEQ_LT(seg->seq,next_seq)) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
"seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
next_seq);
}
if (prev_seg != seg->prev) {
SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
prev_seg, seg->prev);
}
next_seq = seg->seq + TCP_SEG_LEN(seg);
SCLogDebug("next_seq is now %"PRIu32"", next_seq);
prev_seg = seg;
seg = seg->next;
}
}
#endif
void PrintList(TcpSegment *seg)
{
TcpSegment *prev_seg = NULL;
// TcpSegment *head_seg = seg;
if (seg == NULL)
return;
uint32_t next_seq = seg->seq;
while (seg != NULL) {
if (SEQ_LT(next_seq,seg->seq)) {
SCLogDebug("missing segment(s) for %" PRIu32 " bytes of data",
(seg->seq - next_seq));
}
SCLogDebug("seg %10"PRIu32" len %" PRIu16 ", seg %p, prev %p, next %p, flags 0x%02x",
seg->seq, TCP_SEG_LEN(seg), seg, seg->prev, seg->next, seg->flags);
if (seg->prev != NULL && SEQ_LT(seg->seq,seg->prev->seq)) {
/* check for SEQ_LT cornercase where a - b is exactly 2147483648,
* which makes the marco return TRUE in both directions. This is
* a hack though, we're going to check next how we end up with
* a segment list with seq differences that big */
if (!(SEQ_LT(seg->prev->seq,seg->seq))) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,seg->prev->seq)) == "
"TRUE, seg->seq %" PRIu32 ", seg->prev->seq %" PRIu32 "",
seg->seq, seg->prev->seq);
// PrintList2(head_seg);
// abort();
}
}
if (SEQ_LT(seg->seq,next_seq)) {
SCLogDebug("inconsistent list: SEQ_LT(seg->seq,next_seq)) == TRUE, "
"seg->seq %" PRIu32 ", next_seq %" PRIu32 "", seg->seq,
next_seq);
// PrintList2(head_seg);
// abort();
}
if (prev_seg != seg->prev) {
SCLogDebug("inconsistent list: prev_seg %p != seg->prev %p",
prev_seg, seg->prev);
// PrintList2(head_seg);
abort();
}
next_seq = seg->seq + TCP_SEG_LEN(seg);
SCLogDebug("next_seq is now %"PRIu32"", next_seq);
prev_seg = seg;
seg = seg->next;
}
}
/*
* unittests
*/
#ifdef UNITTESTS
#include "tests/stream-tcp-list.c"
#endif

@ -0,0 +1,35 @@
/* Copyright (C) 2007-2016 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Victor Julien <victor@inliniac.net>
*/
#ifndef __STREAM_TCP_LIST_H__
#define __STREAM_TCP_LIST_H__
#include "stream-tcp-private.h"
void PrintList(TcpSegment *);
#ifdef UNITTESTS
void StreamTcpListRegisterTests(void);
#endif
#endif /* __STREAM_TCP_LIST_H__ */

@ -27,6 +27,7 @@
#include "decode.h"
#include "util-pool.h"
#include "util-pool-thread.h"
#include "util-streaming-buffer.h"
#define STREAMTCP_QUEUE_FLAG_TS 0x01
#define STREAMTCP_QUEUE_FLAG_WS 0x02
@ -51,7 +52,7 @@ typedef struct StreamTcpSackRecord_ {
} StreamTcpSackRecord;
typedef struct TcpSegment_ {
uint8_t *payload;
StreamingBufferSegment sbseg;
uint16_t payload_len; /**< actual size of the payload */
uint16_t pool_size; /**< size of the memory */
uint32_t seq;
@ -61,6 +62,11 @@ typedef struct TcpSegment_ {
uint8_t flags;
} TcpSegment;
#define TCP_SEG_LEN(seg) (seg)->payload_len
#define TCP_SEG_OFFSET(seg) (seg)->sbseg.stream_offset
#define SEG_SEQ_RIGHT_EDGE(seg) ((seg)->seq + TCP_SEG_LEN((seg)))
typedef struct TcpStream_ {
uint16_t flags:12; /**< Flag specific to the stream e.g. Timestamp */
/* coccinelle: TcpStream:flags:STREAMTCP_STREAM_FLAG_ */
@ -79,8 +85,12 @@ typedef struct TcpStream_ {
This will be used to validate the last_ts, when connection has been idle for
longer time.(RFC 1323)*/
/* reassembly */
uint32_t ra_app_base_seq; /**< reassembled seq. We've reassembled up to this point. */
uint32_t ra_raw_base_seq; /**< reassembled seq. We've reassembled up to this point. */
uint32_t base_seq; /**< seq where we are left with reassebly */
uint64_t base_seq_offset; /**< offset from the start of the stream (== 0) of the current
* base seq */
StreamingBuffer *sb;
uint64_t app_progress;
uint64_t raw_progress;
TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */
TcpSegment *seg_list_tail; /**< Last segment in the reassembled stream seg list*/
@ -176,12 +186,6 @@ enum
/*
* Per SEGMENT flags
*/
/** Flag to indicate that the current segment has been processed by the
* reassembly code and should be deleted after app layer protocol has been
* detected. */
#define SEGMENTTCP_FLAG_RAW_PROCESSED 0x01
/** App Layer reassembly code is done with this segment */
#define SEGMENTTCP_FLAG_APPLAYER_PROCESSED 0x02
/** Log API (streaming) has processed this segment */
#define SEGMENTTCP_FLAG_LOGAPI_PROCESSED 0x04
@ -203,8 +207,7 @@ enum
#define STREAMTCP_SET_RA_BASE_SEQ(stream, seq) { \
do { \
(stream)->ra_raw_base_seq = (seq); \
(stream)->ra_app_base_seq = (seq); \
(stream)->base_seq = (seq) + 1; \
} while(0); \
}

File diff suppressed because it is too large Load Diff

@ -90,7 +90,7 @@ int StreamTcpCheckStreamContents(uint8_t *, uint16_t , TcpStream *);
int StreamTcpReassembleHandleSegmentHandleData(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
TcpSession *ssn, TcpStream *stream, Packet *p);
int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, Packet *);
int StreamTcpReassembleInsertSegment(ThreadVars *, TcpReassemblyThreadCtx *, TcpStream *, TcpSegment *, Packet *, uint32_t pkt_seq, uint8_t *pkt_data, uint16_t pkt_datalen);
TcpSegment* StreamTcpGetSegment(ThreadVars *, TcpReassemblyThreadCtx *, uint16_t);
void StreamTcpReturnStreamSegments(TcpStream *);

@ -77,6 +77,7 @@ void StreamTcpUTSetupStream(TcpStream *s, uint32_t isn)
s->isn = isn;
STREAMTCP_SET_RA_BASE_SEQ(s, isn);
s->base_seq = isn+1;
}
void StreamTcpUTClearStream(TcpStream *s)
@ -109,16 +110,15 @@ int StreamTcpUTAddSegmentWithPayload(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
}
s->seq = seq;
s->payload_len = len;
memcpy(s->payload, payload, len);
TCP_SEG_LEN(s) = len;
Packet *p = UTHBuildPacketReal(s->payload, s->payload_len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
Packet *p = UTHBuildPacketReal(payload, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
if (p == NULL) {
return -1;
}
p->tcph->th_seq = htonl(seq);
if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p) < 0)
if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0)
return -1;
UTHFreePacket(p);
@ -133,16 +133,17 @@ int StreamTcpUTAddSegmentWithByte(ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx
}
s->seq = seq;
s->payload_len = len;
memset(s->payload, byte, len);
TCP_SEG_LEN(s) = len;
uint8_t buf[len];
memset(buf, byte, len);
Packet *p = UTHBuildPacketReal(s->payload, s->payload_len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
Packet *p = UTHBuildPacketReal(buf, len, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
if (p == NULL) {
return -1;
}
p->tcph->th_seq = htonl(seq);
if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p) < 0)
if (StreamTcpReassembleInsertSegment(tv, ra_ctx, stream, s, p, TCP_GET_SEQ(p), p->payload, p->payload_len) < 0)
return -1;
UTHFreePacket(p);
return 0;

@ -25,6 +25,7 @@
#define __STREAM_TCP_UTIL_H__
#include "stream-tcp-private.h"
#include "stream-tcp-reassemble.h"
void StreamTcpUTInit(TcpReassemblyThreadCtx **);
void StreamTcpUTDeinit(TcpReassemblyThreadCtx *);

@ -154,6 +154,8 @@ void StreamTcpStreamCleanup(TcpStream *stream)
if (stream != NULL) {
StreamTcpSackFreeList(stream);
StreamTcpReturnStreamSegments(stream);
StreamingBufferFree(stream->sb);
stream->sb = NULL;
}
}
@ -570,7 +572,8 @@ void StreamTcpInitConfig(char quiet)
if (ConfGetBool("stream.reassembly.raw", &enable_raw) == 1) {
if (!enable_raw) {
stream_config.ssn_init_flags = STREAMTCP_FLAG_DISABLE_RAW;
stream_config.segment_init_flags = SEGMENTTCP_FLAG_RAW_PROCESSED;
// TODO how to handle this now?
// stream_config.segment_init_flags = SEGMENTTCP_FLAG_RAW_PROCESSED;
}
} else {
enable_raw = 1;
@ -2262,9 +2265,9 @@ static inline uint32_t StreamTcpResetGetMaxAck(TcpStream *stream, uint32_t seq)
uint32_t ack = seq;
if (stream->seg_list_tail != NULL) {
if (SEQ_GT((stream->seg_list_tail->seq + stream->seg_list_tail->payload_len), ack))
if (SEQ_GT((stream->seg_list_tail->seq + TCP_SEG_LEN(stream->seg_list_tail)), ack))
{
ack = stream->seg_list_tail->seq + stream->seg_list_tail->payload_len;
ack = stream->seg_list_tail->seq + TCP_SEG_LEN(stream->seg_list_tail);
}
}
@ -5791,7 +5794,11 @@ int StreamTcpSegmentForEach(const Packet *p, uint8_t flag, StreamSegmentCallback
for (; seg != NULL &&
(stream_inline || SEQ_LT(seg->seq, stream->last_ack));)
{
ret = CallbackFunc(p, data, seg->payload, seg->payload_len);
const uint8_t *seg_data;
uint32_t seg_datalen;
StreamingBufferSegmentGetData(stream->sb, &seg->sbseg, &seg_data, &seg_datalen);
ret = CallbackFunc(p, data, seg_data, seg_datalen);
if (ret != 1) {
SCLogDebug("Callback function has failed");
return -1;
@ -5818,6 +5825,10 @@ void TcpSessionSetReassemblyDepth(TcpSession *ssn, uint32_t size)
#ifdef UNITTESTS
#define SET_ISN(stream, setseq) \
(stream)->isn = (setseq); \
(stream)->base_seq = (setseq) + 1
/**
* \test Test the allocation of TCP session for a given packet from the
* ssn_pool.
@ -5878,28 +5889,32 @@ static int StreamTcpTest02 (void)
Packet *p = SCMalloc(SIZE_OF_PACKET);
if (unlikely(p == NULL))
return 0;
int ret = 0;
Flow f;
ThreadVars tv;
StreamTcpThread stt;
uint8_t payload[4];
TcpReassemblyThreadCtx *ra_ctx = NULL;;
TCPHdr tcph;
TcpReassemblyThreadCtx ra_ctx;
PacketQueue pq;
memset(&pq,0,sizeof(PacketQueue));
memset(&ra_ctx, 0, sizeof(TcpReassemblyThreadCtx));
memset(p, 0, SIZE_OF_PACKET);
memset (&f, 0, sizeof(Flow));
memset(&tv, 0, sizeof (ThreadVars));
memset(&stt, 0, sizeof (StreamTcpThread));
memset(&tcph, 0, sizeof (TCPHdr));
ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
if (ra_ctx == NULL) {
goto end;
}
FLOW_INITIALIZE(&f);
p->flow = &f;
tcph.th_win = htons(5480);
tcph.th_flags = TH_SYN;
p->tcph = &tcph;
p->flowflags = FLOW_PKT_TOSERVER;
int ret = 0;
stt.ra_ctx = &ra_ctx;
stt.ra_ctx = ra_ctx;
StreamTcpInitConfig(TRUE);
@ -8225,12 +8240,10 @@ static int StreamTcpTest23(void)
TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
uint8_t packet[1460] = "";
ThreadVars tv;
int result = 1;
PacketQueue pq;
Packet *p = SCMalloc(SIZE_OF_PACKET);
if (unlikely(p == NULL))
return 0;
FAIL_IF(p == NULL);
memset(&pq,0,sizeof(PacketQueue));
memset(&ssn, 0, sizeof (TcpSession));
@ -8257,54 +8270,35 @@ static int StreamTcpTest23(void)
p->tcph = &tcph;
p->flowflags = FLOW_PKT_TOSERVER;
p->payload = packet;
ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
SET_ISN(&ssn.client, 3184324452UL);
p->tcph->th_seq = htonl(3184324453UL);
p->tcph->th_ack = htonl(3373419609UL);
p->payload_len = 2;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
printf("failed in segment reassmebling: ");
result &= 0;
goto end;
}
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
p->tcph->th_seq = htonl(3184324455UL);
p->tcph->th_ack = htonl(3373419621UL);
p->payload_len = 2;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
printf("failed in segment reassmebling: ");
result &= 0;
goto end;
}
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
p->tcph->th_seq = htonl(3184324453UL);
p->tcph->th_ack = htonl(3373419621UL);
p->payload_len = 6;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
printf("failed in segment reassmebling: ");
result &= 0;
// goto end;
}
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 4) {
printf("failed in segment reassmebling: ");
result &= 0;
}
FAIL_IF(ssn.client.seg_list_tail == NULL);
FAIL_IF(TCP_SEG_LEN(ssn.client.seg_list_tail) != 2);
end:
StreamTcpReturnStreamSegments(&ssn.client);
StreamTcpFreeConfig(TRUE);
if (SC_ATOMIC_GET(st_memuse) == 0) {
result &= 1;
} else {
printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse));
}
FAIL_IF(SC_ATOMIC_GET(st_memuse) > 0);
SCFree(p);
FLOW_DESTROY(&f);
return result;
PASS;
}
/** \test Test the stream mem leaks conditions. */
@ -8312,14 +8306,12 @@ static int StreamTcpTest24(void)
{
TcpSession ssn;
Packet *p = SCMalloc(SIZE_OF_PACKET);
if (unlikely(p == NULL))
return 0;
FAIL_IF (p == NULL);
Flow f;
TCPHdr tcph;
TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx(NULL);
uint8_t packet[1460] = "";
ThreadVars tv;
int result = 1;
PacketQueue pq;
memset(&pq,0,sizeof(PacketQueue));
@ -8346,54 +8338,36 @@ static int StreamTcpTest24(void)
p->tcph = &tcph;
p->flowflags = FLOW_PKT_TOSERVER;
p->payload = packet;
ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
//ssn.client.ra_app_base_seq = ssn.client.ra_raw_base_seq = ssn.client.last_ack = 3184324453UL;
SET_ISN(&ssn.client, 3184324453UL);
p->tcph->th_seq = htonl(3184324455UL);
p->tcph->th_ack = htonl(3373419621UL);
p->payload_len = 4;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
printf("failed in segment reassmebling\n");
result &= 0;
goto end;
}
FAIL_IF (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
p->tcph->th_seq = htonl(3184324459UL);
p->tcph->th_ack = htonl(3373419633UL);
p->payload_len = 2;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
printf("failed in segment reassmebling\n");
result &= 0;
goto end;
}
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
p->tcph->th_seq = htonl(3184324459UL);
p->tcph->th_ack = htonl(3373419657UL);
p->payload_len = 4;
if (StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1) {
printf("failed in segment reassmebling\n");
result &= 0;
goto end;
}
FAIL_IF(StreamTcpReassembleHandleSegment(&tv, ra_ctx,&ssn, &ssn.client, p, &pq) == -1);
if(ssn.client.seg_list_tail != NULL && ssn.client.seg_list_tail->payload_len != 2) {
printf("failed in segment reassmebling\n");
result &= 0;
}
FAIL_IF(ssn.client.seg_list_tail == NULL);
FAIL_IF(TCP_SEG_LEN(ssn.client.seg_list_tail) != 4);
end:
StreamTcpReturnStreamSegments(&ssn.client);
StreamTcpFreeConfig(TRUE);
if (SC_ATOMIC_GET(st_memuse) == 0) {
result &= 1;
} else {
printf("smemuse.stream_memuse %"PRIu64"\n", SC_ATOMIC_GET(st_memuse));
}
FAIL_IF(SC_ATOMIC_GET(st_memuse) > 0);
SCFree(p);
FLOW_DESTROY(&f);
return result;
PASS;
}
/**
@ -9708,9 +9682,9 @@ static int StreamTcpTest37(void)
goto end;
}
if (((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq != 3) {
printf("the ssn->client.next_seq should be 3, but it is %"PRIu32"\n",
((TcpSession *)p->flow->protoctx)->client.ra_raw_base_seq);
if (((TcpSession *)p->flow->protoctx)->client.raw_progress != 3) {
printf("the ssn->client.raw_progress should be 3, but it is %"PRIu64"\n",
((TcpSession *)p->flow->protoctx)->client.raw_progress);
goto end;
}

@ -67,6 +67,8 @@ typedef struct TcpStreamCnf_ {
uint8_t flags;
uint8_t max_synack_queued;
StreamingBufferConfig sbcnf;
} TcpStreamCnf;
typedef struct StreamTcpThread_ {
@ -185,34 +187,8 @@ enum {
STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION = 2,
};
static inline int StreamNeedsReassembly(TcpSession *ssn, int direction)
{
/* server tcp state */
if (direction) {
if (ssn->server.seg_list != NULL &&
(!(ssn->server.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) ||
!(ssn->server.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) ) {
return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
} else if (ssn->toclient_smsg_head != NULL) {
return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
} else {
return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
}
} else {
if (ssn->client.seg_list != NULL &&
(!(ssn->client.seg_list_tail->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) ||
!(ssn->client.seg_list_tail->flags & SEGMENTTCP_FLAG_APPLAYER_PROCESSED)) ) {
return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_REASSEMBLY;
} else if (ssn->toserver_smsg_head != NULL) {
return STREAM_HAS_UNPROCESSED_SEGMENTS_NEED_ONLY_DETECTION;
} else {
return STREAM_HAS_UNPROCESSED_SEGMENTS_NONE;
}
}
}
TmEcode StreamTcp (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
void StreamTcpExitPrintStats(ThreadVars *, void *);
int StreamNeedsReassembly(TcpSession *ssn, int direction);
TmEcode StreamTcpThreadInit(ThreadVars *, void *, void **);
TmEcode StreamTcpThreadDeinit(ThreadVars *tv, void *data);
void StreamTcpRegisterTests (void);

@ -0,0 +1,733 @@
/* Copyright (C) 2007-2016 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "../suricata-common.h"
#include "../stream-tcp-private.h"
#include "../stream-tcp.h"
#include "../stream-tcp-reassemble.h"
#include "../stream-tcp-inline.h"
#include "../stream-tcp-list.h"
#include "../stream-tcp-util.h"
#include "../util-streaming-buffer.h"
#include "../util-print.h"
#include "../util-unittest.h"
static int VALIDATE(TcpStream *stream, uint8_t *data, uint32_t data_len)
{
if (StreamingBufferCompareRawData(stream->sb,
data, data_len) == 0)
{
SCReturnInt(0);
}
SCLogInfo("OK");
PrintRawDataFp(stdout, data, data_len);
return 1;
}
#define OVERLAP_START(isn, policy) \
TcpReassemblyThreadCtx *ra_ctx = NULL; \
TcpSession ssn; \
ThreadVars tv; \
memset(&tv, 0, sizeof(tv)); \
\
StreamTcpUTInit(&ra_ctx); \
\
StreamTcpUTSetupSession(&ssn); \
StreamTcpUTSetupStream(&ssn.server, (isn)); \
StreamTcpUTSetupStream(&ssn.client, (isn)); \
\
TcpStream *stream = &ssn.client; \
stream->os_policy = (policy);
#define OVERLAP_END \
StreamTcpUTClearSession(&ssn); \
StreamTcpUTDeinit(ra_ctx); \
PASS
#define OVERLAP_STEP(rseq, seg, seglen, buf, buflen) \
StreamTcpUTAddPayload(&tv, ra_ctx, &ssn, stream, stream->isn + (rseq), (uint8_t *)(seg), (seglen)); \
FAIL_IF(!(VALIDATE(stream, (uint8_t *)(buf), (buflen))));
static int OverlapBSD(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_BSD);
OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
/* AA not overwritten, gap filled and B overwritten because 'starts before' */
OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
/* no-op, overlaps CCC which takes precedence */
OVERLAP_STEP(8, "KKK", 3, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
/* LLL fills gaps and replaces D as it starts before */
OVERLAP_STEP(11, "LLL", 3, "\0AAAJJBCCCLLL\0EEFFFGGHHI", 24);
/* MMM fills gap and replaces EE as it starts before */
OVERLAP_STEP(14, "MMM", 3, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(18, "N", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(21, "O", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(22, "P", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no replace of I as it starts the same */
OVERLAP_STEP(24, "QQ", 2, "\0AAAJJBCCCLLLMMMFFFGGHHIQ", 25);
OVERLAP_STEP(1, "0", 1, "0AAAJJBCCCLLLMMMFFFGGHHIQ", 25);
OVERLAP_END;
}
static int OverlapBSDBefore(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_BSD);
OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
OVERLAP_END;
}
static int OverlapBSDSame(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_BSD);
OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
/* ignored as 'starts the same' */
OVERLAP_STEP(1, "KKK", 3, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
/* original data not overwritten as it starts on the same seq */
OVERLAP_STEP(1, "LLLL", 4, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "P", 1, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "QQ", 2, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_END;
}
static int OverlapBSDAfter(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_BSD);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_END;
}
static int OverlapVISTA(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_VISTA);
OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
/* AA not overwritten, gap filled and B not overwritten */
OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJBBCCC\0D\0\0EEFFFGGHHI", 24);
/* no-op, overlaps CCC which takes precedence */
OVERLAP_STEP(8, "KKK", 3, "\0AAAJBBCCC\0D\0\0EEFFFGGHHI", 24);
/* LLL fills gaps only */
OVERLAP_STEP(11, "LLL", 3, "\0AAAJBBCCCLDL\0EEFFFGGHHI", 24);
/* MMM fills gap only */
OVERLAP_STEP(14, "MMM", 3, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(18, "N", 1, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(21, "O", 1, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(22, "P", 1, "\0AAAJBBCCCLDLMEEFFFGGHHI", 24);
/* no replace of I */
OVERLAP_STEP(24, "QQ", 2, "\0AAAJBBCCCLDLMEEFFFGGHHIQ", 25);
OVERLAP_STEP(1, "0", 1, "0AAAJBBCCCLDLMEEFFFGGHHIQ", 25);
OVERLAP_END;
}
static int OverlapVISTABefore(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_VISTA);
OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(2, "AA", 2, "\0AB\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(1, "JJJJ", 4, "JABJ\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(8, "LLL", 3, "JABJ\0\0\0LDL\0EE", 13);
OVERLAP_STEP(11,"MMM", 3, "JABJ\0\0\0LDLMEE", 13);
OVERLAP_END;
}
static int OverlapVISTASame(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_VISTA);
OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "KKK", 3, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "LLLL", 4, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "P", 1, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "QQ", 2, "CCCL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_END;
}
static int OverlapVISTAAfter(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_VISTA);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_END;
}
static int OverlapLINUX(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LINUX);
OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
/* AA not overwritten, gap filled and B not overwritten */
OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
/* no-op, overlaps CCC which takes precedence */
OVERLAP_STEP(8, "KKK", 3, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
/* LLL fills gaps and replaces as begins before */
OVERLAP_STEP(11, "LLL", 3, "\0AAAJJBCCCLLL\0EEFFFGGHHI", 24);
/* MMM fills gap and replaces EE as it begins before */
OVERLAP_STEP(14, "MMM", 3, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(18, "N", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(21, "O", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(22, "P", 1, "\0AAAJJBCCCLLLMMMFFFGGHHI", 24);
/* replaces of I as begins the same, ends after*/
OVERLAP_STEP(24, "QQ", 2, "\0AAAJJBCCCLLLMMMFFFGGHHQQ", 25);
OVERLAP_STEP(1, "0", 1, "0AAAJJBCCCLLLMMMFFFGGHHQQ", 25);
OVERLAP_END;
}
static int OverlapLINUXBefore(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LINUX);
OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
OVERLAP_END;
}
static int OverlapLINUXSame(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LINUX);
OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "KKK", 3, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_END;
}
static int OverlapLINUXAfter(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LINUX);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_END;
}
static int OverlapLINUXOLD(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
/* AA not overwritten as it starts before, gap filled and B overwritten */
OVERLAP_STEP(3, "JJJJ", 4, "\0AAAJJBCCC\0D\0\0EEFFFGGHHI", 24);
/* replace CCC */
OVERLAP_STEP(8, "KKK", 3, "\0AAAJJBKKK\0D\0\0EEFFFGGHHI", 24);
/* LLL fills gaps and replaces as begins before */
OVERLAP_STEP(11, "LLL", 3, "\0AAAJJBKKKLLL\0EEFFFGGHHI", 24);
/* MMM fills gap and replaces EE as it begins before */
OVERLAP_STEP(14, "MMM", 3, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(18, "N", 1, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(21, "O", 1, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(22, "P", 1, "\0AAAJJBKKKLLLMMMFFFGGHHI", 24);
/* replaces of I as begins the same, ends after*/
OVERLAP_STEP(24, "QQ", 2, "\0AAAJJBKKKLLLMMMFFFGGHHQQ", 25);
OVERLAP_STEP(1, "0", 1, "0AAAJJBKKKLLLMMMFFFGGHHQQ", 25);
OVERLAP_END;
}
static int OverlapLINUXOLDBefore(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
OVERLAP_END;
}
static int OverlapLINUXOLDSame(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "KKK", 3, "KKK\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0QQII", 18);
OVERLAP_END;
}
static int OverlapLINUXOLDAfter(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_OLD_LINUX);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(2, "JJ", 2, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(20, "O", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(17, "N", 1, "AAJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_END;
}
static int OverlapSOLARIS(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_SOLARIS);
OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
OVERLAP_STEP(3, "JJJJ", 4, "\0AJJJBBCCC\0D\0\0EEFFFGGHHI", 24);
/* replace CCC */
OVERLAP_STEP(8, "KKK", 3, "\0AJJJBBKKK\0D\0\0EEFFFGGHHI", 24);
/* LLL fills gaps and replaces as begins before */
OVERLAP_STEP(11, "LLL", 3, "\0AJJJBBKKKLLL\0EEFFFGGHHI", 24);
/* MMM fills gap and replaces EE as it begins before */
OVERLAP_STEP(14, "MMM", 3, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(18, "N", 1, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(21, "O", 1, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
/* no op */
OVERLAP_STEP(22, "P", 1, "\0AJJJBBKKKLLLMMMFFFGGHHI", 24);
/* replaces of I as begins the same, ends after*/
OVERLAP_STEP(24, "QQ", 2, "\0AJJJBBKKKLLLMMMFFFGGHHQQ", 25);
OVERLAP_STEP(1, "0", 1, "0AJJJBBKKKLLLMMMFFFGGHHQQ", 25);
OVERLAP_END;
}
static int OverlapSOLARISBefore(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_SOLARIS);
OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
OVERLAP_END;
}
static int OverlapSOLARISSame(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_SOLARIS);
OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "KKK", 3, "KKK\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0QQII", 18);
OVERLAP_END;
}
static int OverlapSOLARISAfter(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_SOLARIS);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(2, "JJ", 2, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(20, "O", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(17, "N", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_END;
}
static int OverlapLAST(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LAST);
OVERLAP_STEP(2, "AAA", 3, "\0AAA", 4);
OVERLAP_STEP(6, "BB", 2, "\0AAA\0BB", 7);
OVERLAP_STEP(8, "CCC", 3, "\0AAA\0BBCCC", 10);
OVERLAP_STEP(12, "D", 1, "\0AAA\0BBCCC\0D", 12);
OVERLAP_STEP(15, "EE", 2, "\0AAA\0BBCCC\0D\0\0EE", 16);
OVERLAP_STEP(17, "FFF", 3, "\0AAA\0BBCCC\0D\0\0EEFFF", 19);
OVERLAP_STEP(20, "GG", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGG", 21);
OVERLAP_STEP(22, "HH", 2, "\0AAA\0BBCCC\0D\0\0EEFFFGGHH", 23);
OVERLAP_STEP(24, "I", 1, "\0AAA\0BBCCC\0D\0\0EEFFFGGHHI", 24);
OVERLAP_STEP(3, "JJJJ", 4, "\0AJJJJBCCC\0D\0\0EEFFFGGHHI", 24);
OVERLAP_STEP(8, "KKK", 3, "\0AJJJJBKKK\0D\0\0EEFFFGGHHI", 24);
OVERLAP_STEP(11, "LLL", 3, "\0AJJJJBKKKLLL\0EEFFFGGHHI", 24);
OVERLAP_STEP(14, "MMM", 3, "\0AJJJJBKKKLLLMMMFFFGGHHI", 24);
OVERLAP_STEP(18, "N", 1, "\0AJJJJBKKKLLLMMMFNFGGHHI", 24);
OVERLAP_STEP(21, "O", 1, "\0AJJJJBKKKLLLMMMFNFGOHHI", 24);
OVERLAP_STEP(22, "P", 1, "\0AJJJJBKKKLLLMMMFNFGOPHI", 24);
OVERLAP_STEP(24, "QQ", 2, "\0AJJJJBKKKLLLMMMFNFGOPHQQ", 25);
OVERLAP_STEP(1, "0", 1, "0AJJJJBKKKLLLMMMFNFGOPHQQ", 25);
OVERLAP_END;
}
static int OverlapLASTBefore(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LAST);
OVERLAP_STEP(3, "B", 1, "\0\0B", 3);
OVERLAP_STEP(9, "D", 1, "\0\0B\0\0\0\0\0D", 9);
OVERLAP_STEP(12, "EE", 2, "\0\0B\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(2, "AA", 2, "\0AA\0\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(1, "JJJJ", 4, "JJJJ\0\0\0\0D\0\0EE", 13);
OVERLAP_STEP(8, "LLL", 3, "JJJJ\0\0\0LLL\0EE", 13);
OVERLAP_STEP(11,"MMM", 3, "JJJJ\0\0\0LLLMMM", 13);
OVERLAP_END;
}
static int OverlapLASTSame(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LAST);
OVERLAP_STEP(1, "CCC", 3, "CCC", 3);
OVERLAP_STEP(15, "HH", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HH", 16);
OVERLAP_STEP(17, "II", 2, "CCC\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "KKK", 3, "KKK\0\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(1, "LLLL", 4, "LLLL\0\0\0\0\0\0\0\0\0\0HHII", 18);
OVERLAP_STEP(15, "P", 1, "LLLL\0\0\0\0\0\0\0\0\0\0PHII", 18);
OVERLAP_STEP(15, "QQ", 2, "LLLL\0\0\0\0\0\0\0\0\0\0QQII", 18);
OVERLAP_END;
}
static int OverlapLASTAfter(uint32_t isn)
{
OVERLAP_START(isn, OS_POLICY_LAST);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(16, "FFF", 3, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFF", 18);
OVERLAP_STEP(19, "GG", 2, "AA\0\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(2, "JJ", 2, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGG", 20);
OVERLAP_STEP(20, "O", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FFFGO", 20);
OVERLAP_STEP(17, "N", 1, "AJJ\0\0\0\0\0\0\0\0\0\0\0\0FNFGO", 20);
OVERLAP_END;
}
/** \test BSD policy
*/
static int StreamTcpReassembleTest01(void)
{
FAIL_IF(OverlapBSD(0) == 0);
OverlapBSDBefore(0);
OverlapBSDSame(0);
OverlapBSDAfter(0);
OverlapBSD(1);
OverlapBSDBefore(1);
OverlapBSDSame(1);
OverlapBSDAfter(1);
OverlapBSD(UINT_MAX);
OverlapBSDBefore(UINT_MAX);
OverlapBSDSame(UINT_MAX);
OverlapBSDAfter(UINT_MAX);
OverlapBSD(UINT_MAX - 10);
OverlapBSDBefore(UINT_MAX - 10);
OverlapBSDSame(UINT_MAX - 10);
OverlapBSDAfter(UINT_MAX - 10);
return 1;
}
/** \test Vista Policy
*/
static int StreamTcpReassembleTest02(void)
{
OverlapVISTA(0);
OverlapVISTABefore(0);
OverlapVISTASame(0);
OverlapVISTAAfter(0);
OverlapVISTA(1);
OverlapVISTABefore(1);
OverlapVISTASame(1);
OverlapVISTAAfter(1);
OverlapVISTA(UINT_MAX);
OverlapVISTABefore(UINT_MAX);
OverlapVISTASame(UINT_MAX);
OverlapVISTAAfter(UINT_MAX);
OverlapVISTA(UINT_MAX - 10);
OverlapVISTABefore(UINT_MAX - 10);
OverlapVISTASame(UINT_MAX - 10);
OverlapVISTAAfter(UINT_MAX - 10);
return 1;
}
/** \test Linux policy
*/
static int StreamTcpReassembleTest03(void)
{
OverlapLINUX(0);
OverlapLINUXBefore(0);
OverlapLINUXSame(0);
OverlapLINUXAfter(0);
OverlapLINUX(1);
OverlapLINUXBefore(1);
OverlapLINUXSame(1);
OverlapLINUXAfter(1);
OverlapLINUX(UINT_MAX);
OverlapLINUXBefore(UINT_MAX);
OverlapLINUXSame(UINT_MAX);
OverlapLINUXAfter(UINT_MAX);
OverlapLINUX(UINT_MAX - 10);
OverlapLINUXBefore(UINT_MAX - 10);
OverlapLINUXSame(UINT_MAX - 10);
OverlapLINUXAfter(UINT_MAX - 10);
return 1;
}
/** \test policy Linux old
*/
static int StreamTcpReassembleTest04(void)
{
OverlapLINUXOLD(0);
OverlapLINUXOLDBefore(0);
OverlapLINUXOLDSame(0);
OverlapLINUXOLDAfter(0);
OverlapLINUXOLD(1);
OverlapLINUXOLDBefore(1);
OverlapLINUXOLDSame(1);
OverlapLINUXOLDAfter(1);
OverlapLINUXOLD(UINT_MAX);
OverlapLINUXOLDBefore(UINT_MAX);
OverlapLINUXOLDSame(UINT_MAX);
OverlapLINUXOLDAfter(UINT_MAX);
OverlapLINUXOLD(UINT_MAX - 10);
OverlapLINUXOLDBefore(UINT_MAX - 10);
OverlapLINUXOLDSame(UINT_MAX - 10);
OverlapLINUXOLDAfter(UINT_MAX - 10);
return 1;
}
/** \test Solaris policy
*/
static int StreamTcpReassembleTest05(void)
{
OverlapSOLARIS(0);
OverlapSOLARISBefore(0);
OverlapSOLARISSame(0);
OverlapSOLARISAfter(0);
OverlapSOLARIS(1);
OverlapSOLARISBefore(1);
OverlapSOLARISSame(1);
OverlapSOLARISAfter(1);
OverlapSOLARIS(UINT_MAX);
OverlapSOLARISBefore(UINT_MAX);
OverlapSOLARISSame(UINT_MAX);
OverlapSOLARISAfter(UINT_MAX);
OverlapSOLARIS(UINT_MAX - 10);
OverlapSOLARISBefore(UINT_MAX - 10);
OverlapSOLARISSame(UINT_MAX - 10);
OverlapSOLARISAfter(UINT_MAX - 10);
return 1;
}
/** \test policy 'last'
*/
static int StreamTcpReassembleTest06(void)
{
OverlapLAST(0);
OverlapLASTBefore(0);
OverlapLASTSame(0);
OverlapLASTAfter(0);
OverlapLAST(1);
OverlapLASTBefore(1);
OverlapLASTSame(1);
OverlapLASTAfter(1);
OverlapLAST(UINT_MAX);
OverlapLASTBefore(UINT_MAX);
OverlapLASTSame(UINT_MAX);
OverlapLASTAfter(UINT_MAX);
OverlapLAST(UINT_MAX - 10);
OverlapLASTBefore(UINT_MAX - 10);
OverlapLASTSame(UINT_MAX - 10);
OverlapLASTAfter(UINT_MAX - 10);
return 1;
}
static int StreamTcpReassembleTest30 (void)
{
OVERLAP_START(9, OS_POLICY_BSD);
OVERLAP_STEP(3, "BBB", 3, "\0\0BBB", 5);
OVERLAP_STEP(1, "AA", 2, "AABBB", 5);
OVERLAP_END;
}
static int StreamTcpReassembleTest31 (void)
{
OVERLAP_START(9, OS_POLICY_BSD);
OVERLAP_STEP(1, "AA", 2, "AA", 2);
OVERLAP_STEP(3, "BBB", 3, "AABBB", 5);
OVERLAP_END;
}
static int StreamTcpReassembleTest32(void)
{
OVERLAP_START(0, OS_POLICY_BSD);
OVERLAP_STEP(11, "AAAAAAAAAA", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAA", 20);
OVERLAP_STEP(21, "BBBBBBBBBB", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB", 30);
OVERLAP_STEP(41, "CCCCCCCCCC", 10, "\0\0\0\0\0\0\0\0\0\0AAAAAAAAAABBBBBBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50);
OVERLAP_STEP(6, "aaaaaaaaaaaaaaaaaaaa", 20, "\0\0\0\0\0aaaaaaaaaaaaaaaaaaaaBBBBB\0\0\0\0\0\0\0\0\0\0CCCCCCCCCC", 50);
OVERLAP_STEP(1, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 50);
OVERLAP_END;
}
void StreamTcpListRegisterTests(void)
{
UtRegisterTest("StreamTcpReassembleTest01 -- BSD policy",
StreamTcpReassembleTest01);
UtRegisterTest("StreamTcpReassembleTest02 -- VISTA policy",
StreamTcpReassembleTest02);
UtRegisterTest("StreamTcpReassembleTest03 -- LINUX policy",
StreamTcpReassembleTest03);
UtRegisterTest("StreamTcpReassembleTest04 -- LINUX-OLD policy",
StreamTcpReassembleTest04);
UtRegisterTest("StreamTcpReassembleTest05 -- SOLARIS policy",
StreamTcpReassembleTest05);
UtRegisterTest("StreamTcpReassembleTest06 -- LAST policy",
StreamTcpReassembleTest06);
UtRegisterTest("StreamTcpReassembleTest30",
StreamTcpReassembleTest30);
UtRegisterTest("StreamTcpReassembleTest31",
StreamTcpReassembleTest31);
UtRegisterTest("StreamTcpReassembleTest32",
StreamTcpReassembleTest32);
}
Loading…
Cancel
Save