Improve Inline reassembly wrt to GAP handling. Add more tests.

remotes/origin/master-1.1.x
Victor Julien 14 years ago
parent 29e02abc94
commit 2db06cc79e

@ -1642,7 +1642,9 @@ static void StreamTcpSetupMsg(TcpSession *ssn, TcpStream *stream, Packet *p,
smsg->flags |= STREAM_EOF; smsg->flags |= STREAM_EOF;
} }
if (p->flowflags & FLOW_PKT_TOSERVER) { if ((!StreamTcpInlineMode() && p->flowflags & FLOW_PKT_TOSERVER) ||
( StreamTcpInlineMode() && p->flowflags & FLOW_PKT_TOCLIENT))
{
COPY_ADDRESS(&p->flow->src,&smsg->data.src_ip); COPY_ADDRESS(&p->flow->src,&smsg->data.src_ip);
COPY_ADDRESS(&p->flow->dst,&smsg->data.dst_ip); COPY_ADDRESS(&p->flow->dst,&smsg->data.dst_ip);
COPY_PORT(p->flow->sp,smsg->data.src_port); COPY_PORT(p->flow->sp,smsg->data.src_port);
@ -1809,6 +1811,8 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
uint8_t flags = 0; uint8_t flags = 0;
SCLogDebug("pcap_cnt %"PRIu64", len %u", p->pcap_cnt, p->payload_len);
/* check if toserver reassembly has started before reassembling toclient. */ /* check if toserver reassembly has started before reassembling toclient. */
if (PKT_IS_TOCLIENT(p) && if (PKT_IS_TOCLIENT(p) &&
!(ssn->flags & STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED)) !(ssn->flags & STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED))
@ -1856,8 +1860,6 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
SCReturnInt(0); SCReturnInt(0);
} }
uint32_t ra_base_seq;
/* check if we have detected the app layer protocol or not. If it has been /* check if we have detected the app layer protocol or not. If it has been
detected then, process data normally, as we have sent one smsg from detected then, process data normally, as we have sent one smsg from
toserver side already to the app layer */ toserver side already to the app layer */
@ -1871,42 +1873,23 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
"yet, so not doing toclient reassembling"); "yet, so not doing toclient reassembling");
SCReturnInt(0); SCReturnInt(0);
} }
/* initialize the tmp_ra_base_seq for each new run */
stream->tmp_ra_app_base_seq = stream->ra_app_base_seq;
ra_base_seq = stream->tmp_ra_app_base_seq;
/* if app layer protocol has been detected, then restore the reassembled
seq. to the value till reassembling has been done and unset the queue
init flag permanently for this tcp session */
} else if (SEQ_GT(stream->tmp_ra_app_base_seq, stream->ra_app_base_seq)) {
stream->ra_app_base_seq = stream->tmp_ra_app_base_seq;
ra_base_seq = stream->ra_app_base_seq;
SCLogDebug("the app layer protocol has been detected");
} else {
ra_base_seq = stream->ra_app_base_seq;
}
/* set the ra_bas_seq to stream->ra_base_seq as now app layer protocol
has been detected */
} else {
if (SEQ_GT(stream->tmp_ra_app_base_seq, stream->ra_app_base_seq)) {
stream->ra_app_base_seq = stream->tmp_ra_app_base_seq;
ra_base_seq = stream->ra_app_base_seq;
} else {
ra_base_seq = stream->ra_app_base_seq;
} }
} }
SCLogDebug("ra_base_seq %u", ra_base_seq); uint32_t ra_base_seq = stream->ra_app_base_seq;
uint8_t data[4096]; uint8_t data[4096];
uint32_t data_len = 0; uint32_t data_len = 0;
uint16_t payload_offset = 0; uint16_t payload_offset = 0;
uint16_t payload_len = 0; uint16_t payload_len = 0;
uint32_t next_seq = ra_base_seq + 1; uint32_t next_seq = ra_base_seq + 1;
uint32_t data_sent = 0;
SCLogDebug("ra_base_seq %u", ra_base_seq);
/* loop through the segments and fill one or more msgs */ /* loop through the segments and fill one or more msgs */
TcpSegment *seg = stream->seg_list; TcpSegment *seg = stream->seg_list;
SCLogDebug("pre-loop seg %p", seg); SCLogDebug("pre-loop seg %p", seg);
for (; seg != NULL && SEQ_LT(seg->seq, stream->next_seq);) { for (; seg != NULL;) {
SCLogDebug("seg %p", seg); SCLogDebug("seg %p", seg);
/* if app layer protocol has been detected, then remove all the segments /* if app layer protocol has been detected, then remove all the segments
@ -1932,27 +1915,6 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
"%"PRIu32"", ra_base_seq, seg, seg->seq, "%"PRIu32"", ra_base_seq, seg, seg->seq,
seg->payload_len, seg->seq+seg->payload_len, stream->last_ack); seg->payload_len, seg->seq+seg->payload_len, stream->last_ack);
/* Remove the segments which are either completely before the
ra_base_seq or if they are beyond ra_base_seq, but the segment offset
from which we need to copy in to smsg is beyond the stream->last_ack.
As we are copying until the stream->last_ack only */
/** \todo we should probably not even insert them into the seglist */
if ((SEQ_LEQ((seg->seq + seg->payload_len), (ra_base_seq+1)) ||
SEQ_LEQ(stream->last_ack, (ra_base_seq + (ra_base_seq - seg->seq)))) &&
(seg->flags & SEGMENTTCP_FLAG_RAW_PROCESSED) &&
StreamTcpAppLayerSegmentProcessed(stream, seg))
{
SCLogDebug("removing pre ra_base_seq %"PRIu32" seg %p seq %"PRIu32
" len %"PRIu16"", ra_base_seq, seg, seg->seq, seg->payload_len);
TcpSegment *next_seg = seg->next;
StreamTcpRemoveSegmentFromStream(stream, seg);
StreamTcpSegmentReturntoPool(seg);
seg = next_seg;
continue;
}
/* we've run into a sequence gap */ /* we've run into a sequence gap */
if (SEQ_GT(seg->seq, next_seq)) { if (SEQ_GT(seg->seq, next_seq)) {
@ -1981,12 +1943,12 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
stream->ra_app_base_seq = ra_base_seq; stream->ra_app_base_seq = ra_base_seq;
} }
data_sent += data_len;
} }
/* don't conclude it's a gap straight away. If ra_base_seq is lower /* don't conclude it's a gap straight away. If ra_base_seq is lower
* than last_ack - the window, we consider it a gap. */ * than last_ack - the window, we consider it a gap. */
if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq) || if (SEQ_GT((stream->last_ack - stream->window), ra_base_seq))
ssn->state > TCP_ESTABLISHED)
{ {
/* see what the length of the gap is, gap length is seg->seq - /* see what the length of the gap is, gap length is seg->seq -
* (ra_base_seq +1) */ * (ra_base_seq +1) */
@ -2022,6 +1984,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
data_len = 0; data_len = 0;
/* set a GAP flag and make sure not bothering this stream anymore */ /* set a GAP flag and make sure not bothering this stream anymore */
SCLogDebug("set STREAMTCP_STREAM_FLAG_GAP flag");
stream->flags |= STREAMTCP_STREAM_FLAG_GAP; stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
/* flag reassembly as started, so the to_client part can start */ /* flag reassembly as started, so the to_client part can start */
ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED; ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED;
@ -2044,17 +2007,8 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
/* handle segments partly before ra_base_seq */ /* handle segments partly before ra_base_seq */
if (SEQ_GT(ra_base_seq, seg->seq)) { if (SEQ_GT(ra_base_seq, seg->seq)) {
payload_offset = ra_base_seq - seg->seq -1; payload_offset = ra_base_seq - seg->seq - 1;
payload_len = seg->payload_len - payload_offset;
if (SEQ_LT(stream->next_seq, (seg->seq + seg->payload_len))) {
if (SEQ_LT(stream->next_seq, ra_base_seq)) {
payload_len = (stream->next_seq - seg->seq);
} else {
payload_len = (stream->next_seq - seg->seq) - payload_offset;
}
} else {
payload_len = seg->payload_len - payload_offset;
}
if (SCLogDebugEnabled()) { if (SCLogDebugEnabled()) {
BUG_ON(payload_offset > seg->payload_len); BUG_ON(payload_offset > seg->payload_len);
@ -2062,16 +2016,11 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
} }
} else { } else {
payload_offset = 0; payload_offset = 0;
payload_len = seg->payload_len;
if (SEQ_LT(stream->next_seq, (seg->seq + seg->payload_len))) {
payload_len = stream->next_seq - seg->seq;
} else {
payload_len = seg->payload_len;
}
} }
SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16"" SCLogDebug("payload_offset is %"PRIu16", payload_len is %"PRIu16""
" and stream->next_seq is %"PRIu32"", payload_offset, " and stream->next_win is %"PRIu32"", payload_offset,
payload_len, stream->next_seq); payload_len, stream->next_win);
if (payload_len == 0) { if (payload_len == 0) {
SCLogDebug("no payload_len, so bail out"); SCLogDebug("no payload_len, so bail out");
@ -2105,6 +2054,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
BUG_ON(data_len > sizeof(data)); BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags); data, data_len, flags);
data_sent += data_len;
data_len = 0; data_len = 0;
stream->tmp_ra_app_base_seq = ra_base_seq; stream->tmp_ra_app_base_seq = ra_base_seq;
@ -2114,6 +2064,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
BUG_ON(data_len > sizeof(data)); BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags); data, data_len, flags);
data_sent += data_len;
data_len = 0; data_len = 0;
stream->ra_app_base_seq = ra_base_seq; stream->ra_app_base_seq = ra_base_seq;
@ -2175,6 +2126,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
BUG_ON(data_len > sizeof(data)); BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags); data, data_len, flags);
data_sent += data_len;
data_len = 0; data_len = 0;
stream->tmp_ra_app_base_seq = ra_base_seq; stream->tmp_ra_app_base_seq = ra_base_seq;
@ -2184,6 +2136,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
BUG_ON(data_len > sizeof(data)); BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags); data, data_len, flags);
data_sent += data_len;
data_len = 0; data_len = 0;
stream->ra_app_base_seq = ra_base_seq; stream->ra_app_base_seq = ra_base_seq;
@ -2224,6 +2177,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
BUG_ON(data_len > sizeof(data)); BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags); data, data_len, flags);
data_sent += data_len;
stream->tmp_ra_app_base_seq = ra_base_seq; stream->tmp_ra_app_base_seq = ra_base_seq;
} else { } else {
/* process what we have so far */ /* process what we have so far */
@ -2231,7 +2185,7 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
BUG_ON(data_len > sizeof(data)); BUG_ON(data_len > sizeof(data));
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn, AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
data, data_len, flags); data, data_len, flags);
data_sent += data_len;
stream->ra_app_base_seq = ra_base_seq; stream->ra_app_base_seq = ra_base_seq;
} }
} }
@ -2239,10 +2193,24 @@ static int StreamTcpReassembleInlineAppLayer (TcpReassemblyThreadCtx *ra_ctx,
if (ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) { if (ssn->flags & STREAMTCP_FLAG_APPPROTO_DETECTION_COMPLETED) {
SCLogDebug("proto detection already completed"); SCLogDebug("proto detection already completed");
ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED; ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED;
stream->ra_app_base_seq = ra_base_seq;
} else { } else {
SCLogDebug("protocol detection not yet completed"); SCLogDebug("protocol detection not yet completed");
} }
if (data_sent == 0 && ssn->state > TCP_ESTABLISHED) {
SCLogDebug("sending empty eof message");
/* send EOF to app layer */
STREAM_SET_INLINE_FLAGS(ssn, stream, p, flags);
AppLayerHandleTCPData(&ra_ctx->dp_ctx, p->flow, ssn,
NULL, 0, flags|STREAM_EOF);
/* even if app layer detection failed, we will now move on to
* release reassembly for both directions. */
ssn->flags |= STREAMTCP_FLAG_TOSERVER_REASSEMBLY_STARTED;
}
SCLogDebug("stream->ra_app_base_seq %u", stream->ra_app_base_seq);
SCReturnInt(0); SCReturnInt(0);
} }
@ -2567,6 +2535,7 @@ static int StreamTcpReassembleInlineRaw (TcpReassemblyThreadCtx *ra_ctx,
break; break;
} }
} }
SCLogDebug("stream->ra_raw_base_seq %u", stream->ra_raw_base_seq);
SCReturnInt(0); SCReturnInt(0);
} }
@ -3479,33 +3448,28 @@ int StreamTcpReassembleHandleSegment(ThreadVars *tv, TcpReassemblyThreadCtx *ra_
/* If no stream reassembly/application layer protocol inspection, then /* If no stream reassembly/application layer protocol inspection, then
simple return */ simple return */
if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) { if (p->payload_len > 0 && !(stream->flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
if (!(StreamTcpInlineMode())) { SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) { if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) {
SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error"); SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error");
SCReturnInt(-1); SCReturnInt(-1);
} }
} else {
SCLogDebug("calling StreamTcpReassembleHandleSegmentHandleData");
if (StreamTcpReassembleHandleSegmentHandleData(tv, ra_ctx, ssn, stream, p) != 0) { p->flags |= PKT_STREAM_ADD;
SCLogDebug("StreamTcpReassembleHandleSegmentHandleData error"); }
SCReturnInt(-1);
}
int r = 0; /* in stream inline mode even if we have no data we call the reassembly
if (StreamTcpReassembleInlineAppLayer(ra_ctx, ssn, stream, p) < 0) * functions to handle EOF */
r = -1; if (StreamTcpInlineMode()) {
if (StreamTcpReassembleInlineAppLayer(ra_ctx, ssn, stream, p) < 0) int r = 0;
r = -1; if (StreamTcpReassembleInlineAppLayer(ra_ctx, ssn, stream, p) < 0)
r = -1;
if (StreamTcpReassembleInlineRaw(ra_ctx, ssn, stream, p) < 0)
r = -1;
if (r < 0) { if (r < 0) {
SCReturnInt(-1); SCReturnInt(-1);
}
} }
p->flags |= PKT_STREAM_ADD;
} }
SCReturnInt(0); SCReturnInt(0);
@ -5090,8 +5054,8 @@ static int StreamTcpReassembleTest25 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -5147,8 +5111,8 @@ static int StreamTcpReassembleTest26 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -5204,8 +5168,8 @@ static int StreamTcpReassembleTest27 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -5293,8 +5257,8 @@ static int StreamTcpReassembleTest28 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -5377,8 +5341,8 @@ static int StreamTcpReassembleTest29 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -5487,8 +5451,8 @@ static int StreamTcpReassembleTest30 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -5567,8 +5531,8 @@ static int StreamTcpReassembleTest31 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
return ret; return ret;
} }
@ -6236,8 +6200,8 @@ static int StreamTcpReassembleTest38 (void) {
#endif #endif
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -6454,8 +6418,8 @@ static int StreamTcpReassembleTest39 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -6710,8 +6674,8 @@ static int StreamTcpReassembleTest40 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -6908,8 +6872,8 @@ static int StreamTcpReassembleTest41 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -7075,8 +7039,8 @@ static int StreamTcpReassembleTest42 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -7306,8 +7270,8 @@ static int StreamTcpReassembleTest43 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -7484,8 +7448,8 @@ static int StreamTcpReassembleTest45 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -7626,8 +7590,8 @@ static int StreamTcpReassembleTest46 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -7752,8 +7716,8 @@ static int StreamTcpReassembleTest47 (void) {
ret = 1; ret = 1;
end: end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx); StreamTcpReassembleFreeThreadCtx(ra_ctx);
StreamTcpFreeConfig(TRUE);
SCFree(p); SCFree(p);
return ret; return ret;
} }
@ -8635,6 +8599,230 @@ end:
return ret; return ret;
} }
/** \test 3 in order segments, then reassemble, add one more and reassemble again.
* test the sliding window reassembly with a small window size so that we
* cutting off at the start (left edge). Test if the first segment is
* removed from the list.
*/
static int StreamTcpReassembleInlineTest09(void) {
int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpSession ssn;
Flow f;
memset(&tv, 0x00, sizeof(tv));
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupSession(&ssn);
StreamTcpUTSetupStream(&ssn.client, 1);
FLOW_INITIALIZE(&f);
stream_config.reassembly_inline_window = 20;
ssn.client.flags |= STREAMTCP_STREAM_FLAG_GAP;
uint8_t stream_payload1[] = "AAAAABBBBBCCCCC";
uint8_t stream_payload2[] = "DDDDD";
uint8_t stream_payload3[] = "AAAAABBBBBCCCCCDDDDD";
uint8_t payload[] = { 'C', 'C', 'C', 'C', 'C' };
Packet *p = UTHBuildPacketReal(payload, 5, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
if (p == NULL) {
printf("couldn't get a packet: ");
goto end;
}
p->tcph->th_seq = htonl(17);
p->flow = &f;
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 2, 'A', 5) == -1) {
printf("failed to add segment 1: ");
goto end;
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 7, 'B', 5) == -1) {
printf("failed to add segment 2: ");
goto end;
}
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 17, 'D', 5) == -1) {
printf("failed to add segment 3: ");
goto end;
}
ssn.client.next_seq = 12;
int r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed: ");
goto end;
}
if (ra_ctx->stream_q->len != 2) {
printf("expected 2 stream message2, got %u: ", ra_ctx->stream_q->len);
goto end;
}
StreamMsg *smsg = ra_ctx->stream_q->bot;
if (smsg->data.data_len != 10) {
printf("expected data length to be 10, got %u (bot): ", smsg->data.data_len);
goto end;
}
if (!(memcmp(stream_payload1, smsg->data.data, 10) == 0)) {
printf("data is not what we expected:\nExpected:\n");
PrintRawDataFp(stdout, stream_payload1, 10);
printf("Got:\n");
PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len);
goto end;
}
smsg = ra_ctx->stream_q->top;
if (smsg->data.data_len != 5) {
printf("expected data length to be 5, got %u (top): ", smsg->data.data_len);
goto end;
}
if (!(memcmp(stream_payload2, smsg->data.data, 5) == 0)) {
printf("data is not what we expected:\nExpected:\n");
PrintRawDataFp(stdout, stream_payload2, 5);
printf("Got:\n");
PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len);
goto end;
}
if (ssn.client.ra_raw_base_seq != 11) {
printf("ra_raw_base_seq %"PRIu32", expected 11: ", ssn.client.ra_raw_base_seq);
goto end;
}
/* close the GAP and see if we properly reassemble and update ra_base_seq */
if (StreamTcpUTAddSegmentWithByte(&tv, ra_ctx, &ssn.client, 12, 'C', 5) == -1) {
printf("failed to add segment 4: ");
goto end;
}
ssn.client.next_seq = 22;
p->tcph->th_seq = htonl(12);
r = StreamTcpReassembleInlineRaw(ra_ctx, &ssn, &ssn.client, p);
if (r < 0) {
printf("StreamTcpReassembleInlineRaw failed 2: ");
goto end;
}
if (ra_ctx->stream_q->len != 3) {
printf("expected 3 stream messages, got %u: ", ra_ctx->stream_q->len);
goto end;
}
smsg = ra_ctx->stream_q->top;
if (smsg->data.data_len != 20) {
printf("expected data length to be 20, got %u: ", smsg->data.data_len);
goto end;
}
if (!(memcmp(stream_payload3, smsg->data.data, 20) == 0)) {
printf("data is not what we expected:\nExpected:\n");
PrintRawDataFp(stdout, stream_payload3, 20);
printf("Got:\n");
PrintRawDataFp(stdout, smsg->data.data, smsg->data.data_len);
goto end;
}
if (ssn.client.ra_raw_base_seq != 21) {
printf("ra_raw_base_seq %"PRIu32", expected 21: ", ssn.client.ra_raw_base_seq);
goto end;
}
if (ssn.client.seg_list->seq != 2) {
printf("expected segment 1 (seq 2) to be first in the list, got seq %"PRIu32": ", ssn.client.seg_list->seq);
goto end;
}
ret = 1;
end:
FLOW_DESTROY(&f);
UTHFreePacket(p);
StreamTcpUTClearSession(&ssn);
StreamTcpUTDeinit(ra_ctx);
return ret;
}
/** \test App Layer reassembly.
*/
static int StreamTcpReassembleInlineTest10(void) {
int ret = 0;
TcpReassemblyThreadCtx *ra_ctx = NULL;
ThreadVars tv;
TcpSession ssn;
Flow f;
memset(&tv, 0x00, sizeof(tv));
StreamTcpUTInit(&ra_ctx);
StreamTcpUTSetupSession(&ssn);
StreamTcpUTSetupStream(&ssn.server, 1);
FLOW_INITIALIZE(&f);
f.src.family = f.dst.family = AF_INET;
uint8_t stream_payload1[] = "GE";
uint8_t stream_payload2[] = "T /";
uint8_t stream_payload3[] = "HTTP/1.0\r\n\r\n";
Packet *p = UTHBuildPacketReal(stream_payload3, 12, IPPROTO_TCP, "1.1.1.1", "2.2.2.2", 1024, 80);
if (p == NULL) {
printf("couldn't get a packet: ");
goto end;
}
p->tcph->th_seq = htonl(7);
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 2, stream_payload1, 2) == -1) {
printf("failed to add segment 1: ");
goto end;
}
ssn.server.next_seq = 4;
int r = StreamTcpReassembleInlineAppLayer(ra_ctx, &ssn, &ssn.server, p);
if (r < 0) {
printf("StreamTcpReassembleInlineAppLayer failed: ");
goto end;
}
if (ssn.server.tmp_ra_app_base_seq != 3) {
printf("expected tmp_ra_app_base_seq 3, got %u: ", ssn.server.tmp_ra_app_base_seq);
goto end;
}
if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 4, stream_payload2, 3) == -1) {
printf("failed to add segment 2: ");
goto end;
}
if (StreamTcpUTAddSegmentWithPayload(&tv, ra_ctx, &ssn.server, 7, stream_payload3, 12) == -1) {
printf("failed to add segment 3: ");
goto end;
}
ssn.server.next_seq = 19;
r = StreamTcpReassembleInlineAppLayer(ra_ctx, &ssn, &ssn.server, p);
if (r < 0) {
printf("StreamTcpReassembleInlineAppLayer failed: ");
goto end;
}
if (ssn.server.ra_app_base_seq != 18) {
printf("expected ra_app_base_seq 18, got %u: ", ssn.server.ra_app_base_seq);
goto end;
}
ret = 1;
end:
#if 0
FLOW_DESTROY(&f);
UTHFreePacket(p);
StreamTcpUTClearSession(&ssn);
StreamTcpUTDeinit(ra_ctx);
#endif
return ret;
}
#endif /* UNITTESTS */ #endif /* UNITTESTS */
/** \brief The Function Register the Unit tests to test the reassembly engine /** \brief The Function Register the Unit tests to test the reassembly engine
@ -8699,6 +8887,9 @@ void StreamTcpReassembleRegisterTests(void) {
UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", StreamTcpReassembleInlineTest06, 1); UtRegisterTest("StreamTcpReassembleInlineTest06 -- inline RAW ra 6 GAP", StreamTcpReassembleInlineTest06, 1);
UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", StreamTcpReassembleInlineTest07, 1); UtRegisterTest("StreamTcpReassembleInlineTest07 -- inline RAW ra 7 GAP", StreamTcpReassembleInlineTest07, 1);
UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", StreamTcpReassembleInlineTest08, 1); UtRegisterTest("StreamTcpReassembleInlineTest08 -- inline RAW ra 8 cleanup", StreamTcpReassembleInlineTest08, 1);
UtRegisterTest("StreamTcpReassembleInlineTest09 -- inline RAW ra 9 GAP cleanup", StreamTcpReassembleInlineTest09, 1);
UtRegisterTest("StreamTcpReassembleInlineTest10 -- inline APP ra 10", StreamTcpReassembleInlineTest10, 1);
StreamTcpInlineRegisterTests(); StreamTcpInlineRegisterTests();
StreamTcpUtilRegisterTests(); StreamTcpUtilRegisterTests();

Loading…
Cancel
Save