stream: unify ack'd right edge handling

Use util function in all code needing the ack'd data.
pull/6705/head
Victor Julien 4 years ago
parent ac11502629
commit 258415b23f

@ -322,6 +322,15 @@ void StreamTcpReturnStreamSegments (TcpStream *stream)
} }
} }
static inline uint64_t GetAbsLastAck(const TcpStream *stream)
{
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
return STREAM_BASE_OFFSET(stream) + (stream->last_ack - stream->base_seq);
} else {
return STREAM_BASE_OFFSET(stream);
}
}
#ifdef UNITTESTS #ifdef UNITTESTS
/** \internal /** \internal
* \brief check if segments falls before stream 'offset' */ * \brief check if segments falls before stream 'offset' */
@ -754,44 +763,21 @@ static int StreamTcpReassembleRawCheckLimit(const TcpSession *ssn,
if (p->flags & PKT_PSEUDO_STREAM_END) if (p->flags & PKT_PSEUDO_STREAM_END)
SCReturnInt(1); SCReturnInt(1);
const uint64_t last_ack_abs = GetAbsLastAck(stream);
int64_t diff = last_ack_abs - STREAM_RAW_PROGRESS(stream);
int64_t chunk_size = PKT_IS_TOSERVER(p) ? (int64_t)stream_config.reassembly_toserver_chunk_size
: (int64_t)stream_config.reassembly_toclient_chunk_size;
/* check if we have enough data to do raw reassembly */ /* check if we have enough data to do raw reassembly */
if (PKT_IS_TOSERVER(p)) { if (chunk_size <= diff) {
if (STREAM_LASTACK_GT_BASESEQ(stream)) { SCReturnInt(1);
uint32_t delta = stream->last_ack - stream->base_seq;
/* get max absolute offset */
uint64_t max_offset = STREAM_BASE_OFFSET(stream) + delta;
int64_t diff = max_offset - STREAM_RAW_PROGRESS(stream);
if ((int64_t)stream_config.reassembly_toserver_chunk_size <= diff) {
SCReturnInt(1);
} else {
SCLogDebug("toserver min chunk len not yet reached: "
"last_ack %"PRIu32", ra_raw_base_seq %"PRIu32", %"PRIu32" < "
"%"PRIu32"", stream->last_ack, stream->base_seq,
(stream->last_ack - stream->base_seq),
stream_config.reassembly_toserver_chunk_size);
SCReturnInt(0);
}
}
} else { } else {
if (STREAM_LASTACK_GT_BASESEQ(stream)) { SCLogDebug("%s min chunk len not yet reached: "
uint32_t delta = stream->last_ack - stream->base_seq; "last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
/* get max absolute offset */ "%" PRIi64,
uint64_t max_offset = STREAM_BASE_OFFSET(stream) + delta; PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
(stream->last_ack - stream->base_seq), chunk_size);
int64_t diff = max_offset - STREAM_RAW_PROGRESS(stream); SCReturnInt(0);
if ((int64_t)stream_config.reassembly_toclient_chunk_size <= diff) {
SCReturnInt(1);
} else {
SCLogDebug("toclient min chunk len not yet reached: "
"last_ack %"PRIu32", base_seq %"PRIu32", %"PRIu32" < "
"%"PRIu32"", stream->last_ack, stream->base_seq,
(stream->last_ack - stream->base_seq),
stream_config.reassembly_toclient_chunk_size);
SCReturnInt(0);
}
}
} }
SCReturnInt(0); SCReturnInt(0);
@ -904,16 +890,6 @@ static StreamingBufferBlock *GetBlock(StreamingBuffer *sb, const uint64_t offset
return NULL; return NULL;
} }
static inline uint64_t GetAbsLastAck(const TcpStream *stream)
{
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
return STREAM_BASE_OFFSET(stream) +
(stream->last_ack - stream->base_seq);
} else {
return STREAM_BASE_OFFSET(stream);
}
}
static inline bool GapAhead(TcpStream *stream, StreamingBufferBlock *cur_blk) static inline bool GapAhead(TcpStream *stream, StreamingBufferBlock *cur_blk)
{ {
StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk); StreamingBufferBlock *nblk = SBB_RB_NEXT(cur_blk);
@ -995,51 +971,43 @@ static bool GetAppBuffer(TcpStream *stream, const uint8_t **data, uint32_t *data
static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p) static inline bool CheckGap(TcpSession *ssn, TcpStream *stream, Packet *p)
{ {
const uint64_t app_progress = STREAM_APP_PROGRESS(stream); const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream); const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
/* get window of data that is acked */ SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
const uint32_t delta = stream->last_ack - stream->base_seq; SCLogDebug("next_seq %u", stream->next_seq);
/* get max absolute offset */
last_ack_abs += delta; /* if last_ack_abs is beyond the app_progress data that we haven't seen
* has been ack'd. This looks like a GAP. */
const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0; if (last_ack_abs > app_progress) {
last_ack_abs -= ackadded; /* however, we can accept ACKs a bit too liberally. If last_ack
* is beyond next_seq, we only consider it a gap now if we do
SCLogDebug("last_ack %u abs %"PRIu64, stream->last_ack, last_ack_abs); * already have data beyond the gap. */
SCLogDebug("next_seq %u", stream->next_seq); if (SEQ_GT(stream->last_ack, stream->next_seq)) {
if (RB_EMPTY(&stream->sb.sbb_tree)) {
/* if last_ack_abs is beyond the app_progress data that we haven't seen SCLogDebug("packet %" PRIu64 ": no GAP. "
* has been ack'd. This looks like a GAP. */ "next_seq %u < last_ack %u, but no data in list",
if (last_ack_abs > app_progress) { p->pcap_cnt, stream->next_seq, stream->last_ack);
/* however, we can accept ACKs a bit too liberally. If last_ack return false;
* is beyond next_seq, we only consider it a gap now if we do } else {
* already have data beyond the gap. */ const uint64_t next_seq_abs =
if (SEQ_GT(stream->last_ack, stream->next_seq)) { STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
if (RB_EMPTY(&stream->sb.sbb_tree)) { const StreamingBufferBlock *blk = stream->sb.head;
SCLogDebug("packet %"PRIu64": no GAP. " if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
"next_seq %u < last_ack %u, but no data in list", /* ack'd data after the gap */
SCLogDebug("packet %" PRIu64 ": GAP. "
"next_seq %u < last_ack %u, but ACK'd data beyond gap.",
p->pcap_cnt, stream->next_seq, stream->last_ack); p->pcap_cnt, stream->next_seq, stream->last_ack);
return false; return true;
} else {
const uint64_t next_seq_abs = STREAM_BASE_OFFSET(stream) + (stream->next_seq - stream->base_seq);
const StreamingBufferBlock *blk = stream->sb.head;
if (blk->offset > next_seq_abs && blk->offset < last_ack_abs) {
/* ack'd data after the gap */
SCLogDebug("packet %"PRIu64": GAP. "
"next_seq %u < last_ack %u, but ACK'd data beyond gap.",
p->pcap_cnt, stream->next_seq, stream->last_ack);
return true;
}
} }
} }
SCLogDebug("packet %"PRIu64": GAP! "
"last_ack_abs %"PRIu64" > app_progress %"PRIu64", "
"but we have no data.",
p->pcap_cnt, last_ack_abs, app_progress);
return true;
} }
SCLogDebug("packet %" PRIu64 ": GAP! "
"last_ack_abs %" PRIu64 " > app_progress %" PRIu64 ", "
"but we have no data.",
p->pcap_cnt, last_ack_abs, app_progress);
return true;
} }
SCLogDebug("packet %"PRIu64": no GAP. " SCLogDebug("packet %"PRIu64": no GAP. "
"last_ack_abs %"PRIu64" <= app_progress %"PRIu64, "last_ack_abs %"PRIu64" <= app_progress %"PRIu64,
@ -1062,13 +1030,7 @@ static inline uint32_t AdjustToAcked(const Packet *p,
(p->flags & PKT_PSEUDO_STREAM_END))) { (p->flags & PKT_PSEUDO_STREAM_END))) {
// fall through, we use all available data // fall through, we use all available data
} else { } else {
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream); const uint64_t last_ack_abs = GetAbsLastAck(stream);
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
/* get window of data that is acked */
uint32_t delta = stream->last_ack - stream->base_seq;
/* get max absolute offset */
last_ack_abs += delta;
}
DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs); DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
/* see if the buffer contains unack'd data as well */ /* see if the buffer contains unack'd data as well */
@ -1590,12 +1552,7 @@ static int StreamReassembleRawInline(TcpSession *ssn, const Packet *p,
* - if our block matches or starts before last ack, return right edge of * - if our block matches or starts before last ack, return right edge of
* our block. * our block.
*/ */
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream); const uint64_t last_ack_abs = GetAbsLastAck(stream);
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
uint32_t delta = stream->last_ack - stream->base_seq;
/* get max absolute offset */
last_ack_abs += delta;
}
SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs); SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) { if (STREAM_RAW_PROGRESS(stream) < last_ack_abs) {
@ -1654,7 +1611,9 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream,
StreamingBufferBlock *iter = NULL; StreamingBufferBlock *iter = NULL;
uint64_t progress = progress_in; uint64_t progress = progress_in;
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream); /* absolute right edge of ack'd data */ /* absolute right edge of ack'd data */
const uint64_t last_ack_abs = GetAbsLastAck(stream);
SCLogDebug("last_ack_abs %" PRIu64, last_ack_abs);
/* if the app layer triggered a flush, and we're supposed to /* if the app layer triggered a flush, and we're supposed to
* use a minimal inspect depth, we actually take the app progress * use a minimal inspect depth, we actually take the app progress
@ -1685,15 +1644,6 @@ static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream,
SCLogDebug("progress %"PRIu64", min inspect depth %u %s", progress, stream->min_inspect_depth, stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW":"(no trigger)"); SCLogDebug("progress %"PRIu64", min inspect depth %u %s", progress, stream->min_inspect_depth, stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW ? "STREAMTCP_STREAM_FLAG_TRIGGER_RAW":"(no trigger)");
/* get window of data that is acked */
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
SCLogDebug("last_ack %u, base_seq %u", stream->last_ack, stream->base_seq);
uint32_t delta = stream->last_ack - stream->base_seq;
/* get max absolute offset */
last_ack_abs += delta;
SCLogDebug("last_ack_abs %"PRIu64, last_ack_abs);
}
/* loop through available buffers. On no packet loss we'll have a single /* loop through available buffers. On no packet loss we'll have a single
* iteration. On missing data we'll walk the blocks */ * iteration. On missing data we'll walk the blocks */
while (1) { while (1) {

Loading…
Cancel
Save