diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index dbf9c71eb7..a947fab351 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -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)