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
/** \internal
* \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)
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 */
if (PKT_IS_TOSERVER(p)) {
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
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);
}
}
if (chunk_size <= diff) {
SCReturnInt(1);
} else {
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
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_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);
}
}
SCLogDebug("%s min chunk len not yet reached: "
"last_ack %" PRIu32 ", ra_raw_base_seq %" PRIu32 ", %" PRIu32 " < "
"%" PRIi64,
PKT_IS_TOSERVER(p) ? "toserver" : "toclient", stream->last_ack, stream->base_seq,
(stream->last_ack - stream->base_seq), chunk_size);
SCReturnInt(0);
}
SCReturnInt(0);
@ -904,16 +890,6 @@ static StreamingBufferBlock *GetBlock(StreamingBuffer *sb, const uint64_t offset
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)
{
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)
{
const uint64_t app_progress = STREAM_APP_PROGRESS(stream);
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream);
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
/* get window of data that is acked */
const uint32_t delta = stream->last_ack - stream->base_seq;
/* get max absolute offset */
last_ack_abs += delta;
const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
last_ack_abs -= ackadded;
SCLogDebug("last_ack %u abs %"PRIu64, stream->last_ack, last_ack_abs);
SCLogDebug("next_seq %u", stream->next_seq);
/* if last_ack_abs is beyond the app_progress data that we haven't seen
* has been ack'd. This looks like a GAP. */
if (last_ack_abs > app_progress) {
/* 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
* already have data beyond the gap. */
if (SEQ_GT(stream->last_ack, stream->next_seq)) {
if (RB_EMPTY(&stream->sb.sbb_tree)) {
SCLogDebug("packet %"PRIu64": no GAP. "
"next_seq %u < last_ack %u, but no data in list",
const int ackadded = (ssn->state >= TCP_FIN_WAIT1) ? 1 : 0;
const uint64_t last_ack_abs = GetAbsLastAck(stream) - (uint64_t)ackadded;
SCLogDebug("last_ack %u abs %" PRIu64, stream->last_ack, last_ack_abs);
SCLogDebug("next_seq %u", stream->next_seq);
/* if last_ack_abs is beyond the app_progress data that we haven't seen
* has been ack'd. This looks like a GAP. */
if (last_ack_abs > app_progress) {
/* 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
* already have data beyond the gap. */
if (SEQ_GT(stream->last_ack, stream->next_seq)) {
if (RB_EMPTY(&stream->sb.sbb_tree)) {
SCLogDebug("packet %" PRIu64 ": no GAP. "
"next_seq %u < last_ack %u, but no data in list",
p->pcap_cnt, stream->next_seq, stream->last_ack);
return false;
} 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 false;
} 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;
}
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. "
"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))) {
// fall through, we use all available data
} else {
uint64_t last_ack_abs = STREAM_BASE_OFFSET(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;
}
const uint64_t last_ack_abs = GetAbsLastAck(stream);
DEBUG_VALIDATE_BUG_ON(app_progress > last_ack_abs);
/* 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
* our block.
*/
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream);
if (STREAM_LASTACK_GT_BASESEQ(stream)) {
uint32_t delta = stream->last_ack - stream->base_seq;
/* get max absolute offset */
last_ack_abs += delta;
}
const uint64_t last_ack_abs = GetAbsLastAck(stream);
SCLogDebug("last_ack_abs %"PRIu64, 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;
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
* 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)");
/* 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
* iteration. On missing data we'll walk the blocks */
while (1) {

Loading…
Cancel
Save