|
|
|
@ -2895,6 +2895,49 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
|
|
|
|
|
GetSessionSize(ssn, p);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Check if we have a gap at the start of the stream. 2 conditions:
|
|
|
|
|
* 1. no segments, but last_ack moved fwd
|
|
|
|
|
* 2. segments, but clearly some missing: if last_ack is
|
|
|
|
|
* bigger than the list start and the list start is bigger than
|
|
|
|
|
* next_seq, we know we are missing data that has been ack'd. That
|
|
|
|
|
* won't get retransmitted, so it's a data gap.
|
|
|
|
|
*/
|
|
|
|
|
if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
|
|
|
|
|
int ackadd = (ssn->state >= TCP_FIN_WAIT2) ? 2 : 1;
|
|
|
|
|
if ((stream->seg_list == NULL && /*1*/
|
|
|
|
|
stream->ra_app_base_seq == stream->isn &&
|
|
|
|
|
SEQ_GT(stream->last_ack, stream->isn + ackadd))
|
|
|
|
|
||
|
|
|
|
|
(stream->seg_list != NULL && /*2*/
|
|
|
|
|
SEQ_GT(stream->seg_list->seq, stream->ra_app_base_seq+1) &&
|
|
|
|
|
SEQ_LT(stream->seg_list->seq, stream->last_ack)))
|
|
|
|
|
{
|
|
|
|
|
if (stream->seg_list == NULL) {
|
|
|
|
|
SCLogDebug("no segs, last_ack moved fwd so GAP "
|
|
|
|
|
"(base %u, isn %u, last_ack %u => diff %u) p %"PRIu64,
|
|
|
|
|
stream->ra_app_base_seq, stream->isn, stream->last_ack,
|
|
|
|
|
stream->last_ack - (stream->isn + ackadd), p->pcap_cnt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* send gap signal */
|
|
|
|
|
AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
|
|
|
|
|
NULL, 0,
|
|
|
|
|
StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
|
|
|
|
|
AppLayerProfilingStore(ra_ctx->app_tctx, p);
|
|
|
|
|
|
|
|
|
|
/* set a GAP flag and make sure not bothering this stream anymore */
|
|
|
|
|
SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
|
|
|
|
|
stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
|
|
|
|
|
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
|
|
|
|
|
StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
dbg_app_layer_gap++;
|
|
|
|
|
#endif
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if no segments are in the list or all are already processed,
|
|
|
|
|
* and state is beyond established, we send an empty msg */
|
|
|
|
|
TcpSegment *seg_tail = stream->seg_list_tail;
|
|
|
|
@ -2941,32 +2984,6 @@ int StreamTcpReassembleAppLayer (ThreadVars *tv, TcpReassemblyThreadCtx *ra_ctx,
|
|
|
|
|
/* loop through the segments and fill one or more msgs */
|
|
|
|
|
TcpSegment *seg = stream->seg_list;
|
|
|
|
|
SCLogDebug("pre-loop seg %p", seg);
|
|
|
|
|
|
|
|
|
|
/* Check if we have a gap at the start of the list. If last_ack is
|
|
|
|
|
* bigger than the list start and the list start is bigger than
|
|
|
|
|
* next_seq, we know we are missing data that has been ack'd. That
|
|
|
|
|
* won't get retransmitted, so it's a data gap.
|
|
|
|
|
*/
|
|
|
|
|
if (!(ssn->flags & STREAMTCP_FLAG_APP_LAYER_DISABLED)) {
|
|
|
|
|
if (SEQ_GT(seg->seq, next_seq) && SEQ_LT(seg->seq, stream->last_ack)) {
|
|
|
|
|
/* send gap signal */
|
|
|
|
|
AppLayerHandleTCPData(tv, ra_ctx, p, p->flow, ssn, stream,
|
|
|
|
|
NULL, 0,
|
|
|
|
|
StreamGetAppLayerFlags(ssn, stream, p)|STREAM_GAP);
|
|
|
|
|
AppLayerProfilingStore(ra_ctx->app_tctx, p);
|
|
|
|
|
|
|
|
|
|
/* set a GAP flag and make sure not bothering this stream anymore */
|
|
|
|
|
SCLogDebug("STREAMTCP_STREAM_FLAG_GAP set");
|
|
|
|
|
stream->flags |= STREAMTCP_STREAM_FLAG_GAP;
|
|
|
|
|
|
|
|
|
|
StreamTcpSetEvent(p, STREAM_REASSEMBLY_SEQ_GAP);
|
|
|
|
|
StatsIncr(tv, ra_ctx->counter_tcp_reass_gap);
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
dbg_app_layer_gap++;
|
|
|
|
|
#endif
|
|
|
|
|
SCReturnInt(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#ifdef DEBUG_VALIDATION
|
|
|
|
|
uint64_t bytes = 0;
|
|
|
|
|
#endif
|
|
|
|
@ -5434,6 +5451,9 @@ static int StreamTcpReassembleTest30 (void)
|
|
|
|
|
th_flag = TH_ACK|TH_PUSH;
|
|
|
|
|
th_flags = TH_ACK;
|
|
|
|
|
|
|
|
|
|
ssn.client.last_ack = 2;
|
|
|
|
|
ssn.client.isn = 1;
|
|
|
|
|
|
|
|
|
|
ssn.server.last_ack = 22;
|
|
|
|
|
ssn.server.ra_raw_base_seq = ssn.server.ra_app_base_seq = 9;
|
|
|
|
|
ssn.server.isn = 9;
|
|
|
|
@ -6117,7 +6137,7 @@ static int StreamTcpReassembleTest38 (void)
|
|
|
|
|
ssn.server.last_ack = 60;
|
|
|
|
|
ssn.client.ra_raw_base_seq = ssn.client.ra_app_base_seq = 9;
|
|
|
|
|
ssn.client.isn = 9;
|
|
|
|
|
ssn.client.last_ack = 60;
|
|
|
|
|
ssn.client.last_ack = 9;
|
|
|
|
|
f.alproto = ALPROTO_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
f.flags |= FLOW_IPV4;
|
|
|
|
@ -7235,7 +7255,7 @@ static int StreamTcpReassembleTest45 (void)
|
|
|
|
|
ssn.server.last_ack = 60;
|
|
|
|
|
STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9);
|
|
|
|
|
ssn.client.isn = 9;
|
|
|
|
|
ssn.client.last_ack = 60;
|
|
|
|
|
ssn.client.last_ack = 9;
|
|
|
|
|
|
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
|
|
|
|
|
if (f == NULL)
|
|
|
|
@ -7354,7 +7374,7 @@ static int StreamTcpReassembleTest46 (void)
|
|
|
|
|
ssn.server.next_seq = ssn.server.isn;
|
|
|
|
|
STREAMTCP_SET_RA_BASE_SEQ(&ssn.client, 9);
|
|
|
|
|
ssn.client.isn = 9;
|
|
|
|
|
ssn.client.last_ack = 60;
|
|
|
|
|
ssn.client.last_ack = 9;
|
|
|
|
|
ssn.client.next_seq = ssn.client.isn;
|
|
|
|
|
|
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 200, 220);
|
|
|
|
@ -8422,6 +8442,9 @@ static int StreamTcpReassembleInlineTest10(void)
|
|
|
|
|
StreamTcpUTInitInline();
|
|
|
|
|
StreamTcpUTSetupSession(&ssn);
|
|
|
|
|
StreamTcpUTSetupStream(&ssn.server, 1);
|
|
|
|
|
ssn.server.last_ack = 2;
|
|
|
|
|
StreamTcpUTSetupStream(&ssn.client, 1);
|
|
|
|
|
ssn.client.last_ack = 2;
|
|
|
|
|
|
|
|
|
|
f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 80);
|
|
|
|
|
if (f == NULL)
|
|
|
|
|