hstate->cfg = htp_cfg_rec;
SCLogDebug("New hstate->connp %p", hstate->connp);
+
+ StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOSERVER,
+ htp_cfg_rec->request.inspect_min_size);
+ StreamTcpReassemblySetMinInspectDepth(f->protoctx, STREAM_TOCLIENT,
+ htp_cfg_rec->response.inspect_min_size);
}
/* the code block above should make sure connp is never NULL here */
struct StreamMpmData stream_mpm_data = { det_ctx, mpm_ctx };
StreamReassembleRaw(p->flow->protoctx, p,
StreamMpmFunc, &stream_mpm_data,
- &det_ctx->raw_stream_progress);
+ &det_ctx->raw_stream_progress,
+ false /* mpm doesn't use min inspect depth */);
SCLogDebug("det_ctx->raw_stream_progress %"PRIu64,
det_ctx->raw_stream_progress);
} else {
struct StreamContentInspectData inspect_data = { de_ctx, det_ctx, s, f };
int r = StreamReassembleRaw(f->protoctx, p,
StreamContentInspectFunc, &inspect_data,
- &unused);
+ &unused, ((s->flags & SIG_FLAG_FLUSH) != 0));
return r;
}
struct StreamContentInspectEngineData inspect_data = { de_ctx, det_ctx, s, smd, f };
int match = StreamReassembleRaw(f->protoctx, p,
StreamContentInspectEngineFunc, &inspect_data,
- &unused);
+ &unused, ((s->flags & SIG_FLAG_FLUSH) != 0));
bool is_last = false;
if (flags & STREAM_TOSERVER) {
raw_progress -= (uint64_t)chunk_size;
}
}
+
+ /* apply min inspect depth: if it is set we need to keep data
+ * before the raw progress. */
+ if (use_app && stream->min_inspect_depth) {
+ if (raw_progress < stream->min_inspect_depth)
+ raw_progress = 0;
+ else
+ raw_progress -= stream->min_inspect_depth;
+
+ SCLogDebug("stream->min_inspect_depth %u, raw_progress %"PRIu64,
+ stream->min_inspect_depth, raw_progress);
+ }
+
if (use_app) {
left_edge = MIN(STREAM_APP_PROGRESS(stream), raw_progress);
SCLogDebug("left_edge %"PRIu64", using both app:%"PRIu64", raw:%"PRIu64,
uint32_t raw_progress_rel; /**< raw reassembly progress relative to STREAM_BASE_OFFSET */
uint32_t log_progress_rel; /**< streaming logger progress relative to STREAM_BASE_OFFSET */
+ uint32_t min_inspect_depth; /**< min inspect size set by the app layer, to make sure enough data
+ * remains available for inspection together with app layer buffers */
+
StreamingBuffer sb;
TcpSegment *seg_list; /**< list of TCP segments that are not yet (fully) used in reassembly */
* \param[in] progress_in progress to work from
* \param[out] progress_out absolute progress value of the data this
* call handled.
+ * \param eof we're wrapping up so inspect all data we have, incl unACKd
+ * \param respect_inspect_depth use Stream::min_inspect_depth if set
+ *
+ * `respect_inspect_depth` is used to avoid useless inspection of too
+ * much data.
*/
static int StreamReassembleRawDo(TcpSession *ssn, TcpStream *stream,
StreamReassembleRawFunc Callback, void *cb_data,
const uint64_t progress_in,
- uint64_t *progress_out, bool eof)
+ uint64_t *progress_out, bool eof,
+ bool respect_inspect_depth)
{
SCEnter();
int r = 0;
uint64_t progress = progress_in;
uint64_t last_ack_abs = STREAM_BASE_OFFSET(stream); /* absolute right edge of ack'd data */
+ /* if the app layer triggered a flush, and we're supposed to
+ * use a minimal inspect depth, we actually take the app progress
+ * as that is the right edge of the data. Then we take the window
+ * of 'min_inspect_depth' before that. */
+ if (respect_inspect_depth &&
+ (stream->flags & STREAMTCP_STREAM_FLAG_TRIGGER_RAW)
+ && stream->min_inspect_depth)
+ {
+ progress = STREAM_APP_PROGRESS(stream);
+ if (stream->min_inspect_depth >= progress) {
+ progress = 0;
+ } else {
+ progress -= stream->min_inspect_depth;
+ }
+ SCLogDebug("applied min inspect depth due to STREAMTCP_STREAM_FLAG_TRIGGER_RAW: progress %"PRIu64, progress);
+
+ SCLogDebug("stream app %"PRIu64", raw %"PRIu64, STREAM_APP_PROGRESS(stream), STREAM_RAW_PROGRESS(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);
int StreamReassembleRaw(TcpSession *ssn, const Packet *p,
StreamReassembleRawFunc Callback, void *cb_data,
- uint64_t *progress_out)
+ uint64_t *progress_out, bool respect_inspect_depth)
{
/* handle inline seperately as the logic is very different */
if (StreamTcpInlineMode() == TRUE) {
return StreamReassembleRawDo(ssn, stream, Callback, cb_data,
STREAM_RAW_PROGRESS(stream), progress_out,
- (p->flags & PKT_PSEUDO_STREAM_END));
+ (p->flags & PKT_PSEUDO_STREAM_END), respect_inspect_depth);
}
int StreamReassembleLog(TcpSession *ssn, TcpStream *stream,
return 0;
return StreamReassembleRawDo(ssn, stream, Callback, cb_data,
- progress_in, progress_out, eof);
+ progress_in, progress_out, eof, false);
}
/** \internal
}
}
+void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth)
+{
+#ifdef DEBUG
+ BUG_ON(ssn == NULL);
+#endif
+
+ if (ssn != NULL) {
+ if (direction == STREAM_TOSERVER) {
+ ssn->client.min_inspect_depth = depth;
+ SCLogDebug("ssn %p: set client.min_inspect_depth to %u", ssn, depth);
+ } else {
+ ssn->server.min_inspect_depth = depth;
+ SCLogDebug("ssn %p: set server.min_inspect_depth to %u", ssn, depth);
+ }
+ }
+}
+
#ifdef UNITTESTS
/** unit tests and it's support functions below */
#endif
bool StreamReassembleRawHasDataReady(TcpSession *ssn, Packet *p);
+void StreamTcpReassemblySetMinInspectDepth(TcpSession *ssn, int direction, uint32_t depth);
static inline bool STREAM_LASTACK_GT_BASESEQ(const TcpStream *stream)
{
uint64_t progress_in,
uint64_t *progress_out, bool eof);
int StreamReassembleRaw(TcpSession *ssn, const Packet *p,
- StreamReassembleRawFunc Callback, void *cb_data, uint64_t *progress_out);
+ StreamReassembleRawFunc Callback, void *cb_data,
+ uint64_t *progress_out, bool respect_inspect_depth);
void StreamReassembleRawUpdateProgress(TcpSession *ssn, Packet *p, uint64_t progress);
void StreamTcpDetectLogFlush(ThreadVars *tv, StreamTcpThread *stt, Flow *f, Packet *p, PacketQueue *pq);
{
struct TestReassembleRawCallbackData cb = { data, data_len };
uint64_t progress = 0;
- int r = StreamReassembleRaw(ssn, p, TestReassembleRawCallback, &cb, &progress);
+ int r = StreamReassembleRaw(ssn, p, TestReassembleRawCallback, &cb, &progress, false);
if (r == 1) {
StreamReassembleRawUpdateProgress(ssn, p, progress);
}