app-layer: disruption flags

Stream GAPs and stream reassembly depth are tracked per direction. In
many cases they will happen in one direction, but not in the other.

Example:
HTTP requests a generally smaller than responses. So on the response
side we may hit the depth limit, but not on the request side.

The asynchronious 'disruption' has a side effect in the transaction
engine. The 'progress' tracking would never mark such transactions
as complete, and thus some inspection and logging wouldn't happen
until the very last moment: when EOF's are passed around.

Especially in proxy environments with _very_ many transactions in a
single TCP connection, this could lead to serious resource issues. The
EOF handling would suddenly have to handle thousands or more
transactions. These transactions would have been stored for a long time.

This patch introduces the concept of disruption flags. Flags passed to
the tx progress logic that are and indication of disruptions in the
traffic or the traffic handling. The idea is that the progress is
marked as complete on disruption, even if a tx is not complete. This
allows the detection and logging engines to process the tx after which
it can be cleaned up.
pull/1606/head
Victor Julien 11 years ago
parent 8125e04b39
commit ea571add73

@ -725,13 +725,26 @@ static void AppLayerParserTransactionsCleanup(Flow *f)
}
}
#define IS_DISRUPTED(flags) \
((flags) & (STREAM_DEPTH|STREAM_GAP))
/**
* \brief get the progress value for a tx/protocol
*
* If the stream is disrupted, we return the 'completion' value.
*/
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto,
void *alstate, uint8_t direction)
void *alstate, uint8_t flags)
{
SCEnter();
int r = 0;
r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
StateGetProgress(alstate, direction);
if (unlikely(IS_DISRUPTED(flags))) {
r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
StateGetProgressCompletionStatus(flags);
} else {
r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
StateGetProgress(alstate, flags);
}
SCReturnInt(r);
}

@ -160,7 +160,7 @@ static uint8_t *DetectEngineHCBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id,
if ((htp_state->cfg->request_body_limit == 0 ||
htud->request_body.content_len_so_far < htp_state->cfg->request_body_limit) &&
htud->request_body.content_len_so_far < htp_state->cfg->request_inspect_min_size &&
!(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_BODY) &&
!(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY) &&
!(flags & STREAM_EOF)) {
SCLogDebug("we still haven't seen the entire request body. "
"Let's defer body inspection till we see the "
@ -274,7 +274,7 @@ int DetectEngineInspectHttpClientBody(ThreadVars *tv,
end:
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_BODY)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_BODY)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -142,10 +142,10 @@ int DetectEngineInspectHttpCookie(ThreadVars *tv,
end:
if (flags & STREAM_TOSERVER) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
} else {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
}
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -143,11 +143,11 @@ static uint8_t *DetectEngineHHDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id,
htp_table_t *headers;
if (flags & STREAM_TOSERVER) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_REQUEST_HEADERS)
goto end;
headers = tx->request_headers;
} else {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) <= HTP_RESPONSE_HEADERS)
goto end;
headers = tx->response_headers;
}
@ -263,10 +263,10 @@ int DetectEngineInspectHttpHeader(ThreadVars *tv,
end:
if (flags & STREAM_TOSERVER) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
} else {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
}
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -118,7 +118,7 @@ int DetectEngineInspectHttpHH(ThreadVars *tv,
return DETECT_ENGINE_INSPECT_SIG_MATCH;
end:
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -96,7 +96,7 @@ int DetectEngineInspectHttpMethod(ThreadVars *tv,
{
htp_tx_t *tx = (htp_tx_t *)txv;
if (tx->request_method == NULL) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_LINE)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -71,7 +71,7 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f,
SCReturnInt(cnt);
if (flags & STREAM_TOSERVER) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS)
SCReturnInt(cnt);
if (tx_ud->request_headers_raw != NULL) {
@ -81,7 +81,7 @@ int DetectEngineRunHttpRawHeaderMpm(DetectEngineThreadCtx *det_ctx, Flow *f,
flags);
}
} else {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS)
SCReturnInt(cnt);
if (tx_ud->response_headers_raw != NULL) {
@ -120,10 +120,10 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv,
uint32_t headers_raw_len = 0;
if (flags & STREAM_TOSERVER) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) <= HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
} else {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) <= HTP_RESPONSE_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) <= HTP_RESPONSE_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
@ -154,10 +154,10 @@ int DetectEngineInspectHttpRawHeader(ThreadVars *tv,
end:
if (flags & STREAM_TOSERVER) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
} else {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOCLIENT) > HTP_RESPONSE_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_RESPONSE_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
}
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -145,7 +145,7 @@ int DetectEngineInspectHttpHRH(ThreadVars *tv,
return DETECT_ENGINE_INSPECT_SIG_MATCH;
end:
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -72,7 +72,7 @@ int DetectEngineInspectHttpRequestLine(ThreadVars *tv,
htp_tx_t *tx = (htp_tx_t *)txv;
if (tx->request_line == NULL) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_LINE)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -102,7 +102,7 @@ int DetectEngineInspectHttpRawUri(ThreadVars *tv,
{
htp_tx_t *tx = (htp_tx_t *)txv;
if (tx->request_uri == NULL) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_LINE)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_LINE)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -286,7 +286,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id,
htud->response_body.content_len_so_far,
htp_state->cfg->response_inspect_min_size,
flags & STREAM_EOF ? "true" : "false",
(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) ? "true" : "false");
(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) ? "true" : "false");
if (!htp_state->cfg->http_body_inline) {
/* inspect the body if the transfer is complete or we have hit
@ -294,7 +294,7 @@ static uint8_t *DetectEngineHSBDGetBufferForTX(htp_tx_t *tx, uint64_t tx_id,
if ((htp_state->cfg->response_body_limit == 0 ||
htud->response_body.content_len_so_far < htp_state->cfg->response_body_limit) &&
htud->response_body.content_len_so_far < htp_state->cfg->response_inspect_min_size &&
!(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY) &&
!(AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY) &&
!(flags & STREAM_EOF)) {
SCLogDebug("we still haven't seen the entire response body. "
"Let's defer body inspection till we see the "
@ -368,7 +368,7 @@ int DetectEngineInspectHttpServerBody(ThreadVars *tv,
return DETECT_ENGINE_INSPECT_SIG_MATCH;
end:
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_BODY)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_BODY)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -100,7 +100,7 @@ int DetectEngineInspectHttpStatCode(ThreadVars *tv,
{
htp_tx_t *tx = (htp_tx_t *)txv;
if (tx->response_status == NULL) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_LINE)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -100,7 +100,7 @@ int DetectEngineInspectHttpStatMsg(ThreadVars *tv,
{
htp_tx_t *tx = (htp_tx_t *)txv;
if (tx->response_message == NULL) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOCLIENT) > HTP_RESPONSE_LINE)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_RESPONSE_LINE)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -122,7 +122,7 @@ int DetectEngineInspectHttpUA(ThreadVars *tv,
return DETECT_ENGINE_INSPECT_SIG_MATCH;
end:
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER) > HTP_REQUEST_HEADERS)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, flags) > HTP_REQUEST_HEADERS)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -73,7 +73,7 @@ int DetectEngineInspectPacketUris(ThreadVars *tv,
HtpTxUserData *tx_ud = htp_tx_get_user_data(txv);
if (tx_ud == NULL || tx_ud->request_uri_normalized == NULL) {
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, STREAM_TOSERVER) > HTP_REQUEST_LINE)
if (AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, txv, flags) > HTP_REQUEST_LINE)
return DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
else
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;

@ -1335,6 +1335,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
(p->proto == IPPROTO_UDP) ||
(p->proto == IPPROTO_SCTP && (p->flowflags & FLOW_PKT_ESTABLISHED)))
{
/* update flow flags with knowledge on disruptions */
flow_flags = FlowGetDisruptionFlags(pflow, flow_flags);
has_state = (FlowGetAppState(pflow) != NULL);
alproto = FlowGetAppProtocol(pflow);
alversion = AppLayerParserGetStateVersion(pflow->alparser);

@ -870,6 +870,37 @@ void *FlowGetAppState(const Flow *f)
return f->alstate;
}
/**
* \brief get 'disruption' flags: GAP/DEPTH/PASS
* \param f locked flow
* \param flags existing flags to be ammended
* \retval flags original flags + disrupt flags (if any)
* \TODO handle UDP
*/
uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags)
{
if (f->proto != IPPROTO_TCP) {
return flags;
}
if (f->protoctx == NULL) {
return flags;
}
uint8_t newflags = flags;
TcpSession *ssn = f->protoctx;
TcpStream *stream = flags & STREAM_TOSERVER ? &ssn->client : &ssn->server;
if (stream->flags & STREAMTCP_STREAM_FLAG_DEPTH_REACHED) {
newflags |= STREAM_DEPTH;
}
if (stream->flags & STREAMTCP_STREAM_FLAG_GAP) {
newflags |= STREAM_GAP;
}
/* todo: handle pass case (also for UDP!) */
return newflags;
}
/************************************Unittests*******************************/
#ifdef UNITTESTS

@ -568,6 +568,7 @@ int FlowClearMemory(Flow *,uint8_t );
AppProto FlowGetAppProtocol(const Flow *f);
void *FlowGetAppState(const Flow *f);
uint8_t FlowGetDisruptionFlags(const Flow *f, uint8_t flags);
void FlowHandlePacketUpdateRemove(Flow *f, Packet *p);
void FlowHandlePacketUpdate(Flow *f, Packet *p);

Loading…
Cancel
Save