detect: allow rule which need both directions to match

Ticket: 5665

This is done with `alert ip any any => any any`
The => operator means that we will need both directions
pull/12875/head
Philippe Antoine 1 year ago committed by Victor Julien
parent 81915548de
commit 3a092f3027

@ -228,11 +228,14 @@ Direction
The directional arrow indicates which way the signature will be evaluated.
In most signatures an arrow to the right (``->``) is used. This means that only
packets with the same direction can match. However, it is also possible to
have a rule match both directions (``<>``)::
packets with the same direction can match.
There is also the double arrow (``=>``), which respects the directionality as ``->``,
but allows matching on bidirectional transactions, used with keywords matching each direction.
Finally, it is also possible to have a rule match either directions (``<>``)::
source -> destination
source <> destination (both directions)
source => destination
source <> destination (either directions)
The following example illustrates direction. In this example there is a client
with IP address 1.2.3.4 using port 1024. A server with IP address 5.6.7.8,
@ -248,10 +251,56 @@ Now, let's say we have a rule with the following header::
Only the traffic from the client to the server will be matched by this rule,
as the direction specifies that we do not want to evaluate the response packet.
Now, if we have a rule with the following header::
alert tcp 1.2.3.4 any <> 5.6.7.8 80
Suricata will duplicate it and use the same rule with headers in both directions :
alert tcp 1.2.3.4 any -> 5.6.7.8 80
alert tcp 5.6.7.8 80 -> 1.2.3.4 any
.. warning::
There is no 'reverse' style direction, i.e. there is no ``<-``.
Transactional rules
~~~~~~~~~~~~~~~~~~~
Here is an example of a transactional rule:
.. container:: example-rule
alert http any any :example-rule-emphasis:`=>` 5.6.7.8 80 (msg:"matching both uri and status"; sid: 1; http.uri; content: "/download"; http.stat_code; content: "200";)
It will match on flows to 5.6.7.8 and port 80.
And it will match on a full transaction, using both the uri from the request,
and the stat_code from the response.
As such, it will match only when Suricata got both request and response.
Transactional rules can use direction-ambiguous keywords, by specifying the direction.
.. container:: example-rule
alert http any any => 5.6.7.8 80 (msg:"matching json to server and xml to client"; sid: 1; http.content_type: :example-rule-emphasis:`to_server`; content: "json"; http.content_type: :example-rule-emphasis:`to_client`; content: "xml";)
Transactional rules have some limitations :
* They cannot use direction-ambiguous keywords
* They are only meant to work on transactions with first a request to the server,
and then a response to the client, and not the other way around (not tested).
* They cannot have ``fast_pattern`` or ``prefilter`` the direction to client
if they also have a streaming buffer on the direction to server, see example below.
* They will refuse to load if a single directional rule is enough.
This rule cannot have the ``fast_pattern`` to client, as ``file.data`` is a streaming buffer and will refuse to load.
.. container:: example-rule
alert http any any => any any (file.data: to_server; content: "123"; http.stat_code; content: "500"; fast_patten;)
If not explicit, a transactional rule will choose a fast_pattern to server by default
Rule options
------------
The rest of the rule consists of options. These are enclosed by parenthesis

@ -1071,6 +1071,26 @@ static SigMatch *GetMpmForList(const Signature *s, SigMatch *list, SigMatch *mpm
int g_skip_prefilter = 0;
// tells if a buffer id is only used to client
bool DetectBufferToClient(const DetectEngineCtx *de_ctx, int buf_id, AppProto alproto)
{
bool r = false;
const DetectEngineAppInspectionEngine *app = de_ctx->app_inspect_engines;
for (; app != NULL; app = app->next) {
if (app->sm_list == buf_id &&
(AppProtoEquals(alproto, app->alproto) || alproto == ALPROTO_UNKNOWN)) {
if (app->dir == 1) {
// do not return yet in case we have app engines on both sides
r = true;
} else {
// ambiguous keywords have a app-engine to server
return false;
}
}
}
return r;
}
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
{
if (g_skip_prefilter)
@ -1168,6 +1188,7 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
memset(&final_sm_list, 0, (nlists * sizeof(int)));
int count_final_sm_list = 0;
int count_txbidir_toclient_sm_list = 0;
int priority;
const SCFPSupportSMList *tmp = de_ctx->fp_support_smlist_list;
@ -1181,6 +1202,17 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
continue;
if (curr_sm_list[tmp->list_id] == 0)
continue;
if (s->flags & SIG_FLAG_TXBOTHDIR) {
// prefer to choose a fast_pattern to server by default
if (DetectBufferToClient(de_ctx, tmp->list_id, s->alproto)) {
if (count_final_sm_list == 0) {
// still put it in in the case we do not have toserver buffer
final_sm_list[count_txbidir_toclient_sm_list++] = tmp->list_id;
}
continue;
}
}
// we may erase tx bidir toclient buffers here as intended if we have a better choice
final_sm_list[count_final_sm_list++] = tmp->list_id;
SCLogDebug("tmp->list_id %d", tmp->list_id);
}
@ -1188,6 +1220,10 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
break;
}
if ((s->flags & SIG_FLAG_TXBOTHDIR) && count_final_sm_list == 0) {
// forced to pick a fast_pattern to client for tx bidir signature
count_final_sm_list = count_txbidir_toclient_sm_list;
}
BUG_ON(count_final_sm_list == 0);
SCLogDebug("count_final_sm_list %d skip_negated_content %d", count_final_sm_list,
skip_negated_content);
@ -1211,7 +1247,12 @@ void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
}
} else {
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].only_tc) {
// prefer to choose a fast_pattern to server by default
continue;
}
const int list_id = s->init_data->buffers[x].id;
if (final_sm_list[i] == list_id) {
SCLogDebug("%u: list_id %d: %s", s->id, list_id,
DetectEngineBufferTypeGetNameById(de_ctx, list_id));

@ -131,4 +131,6 @@ struct MpmListIdDataArgs {
void EngineAnalysisAddAllRulePatterns(DetectEngineCtx *de_ctx, const Signature *s);
bool DetectBufferToClient(const DetectEngineCtx *de_ctx, int buf_id, AppProto alproto);
#endif /* SURICATA_DETECT_ENGINE_MPM_H */

@ -231,6 +231,11 @@ void DetectRunStoreStateTx(
SCLogDebug("destate created for %"PRIu64, tx_id);
}
DeStateSignatureAppend(tx_data->de_state, s, inspect_flags, flow_flags);
if (s->flags & SIG_FLAG_TXBOTHDIR) {
// add also in the other DetectEngineStateDirection
DeStateSignatureAppend(tx_data->de_state, s, inspect_flags,
flow_flags ^ (STREAM_TOSERVER | STREAM_TOCLIENT));
}
StoreStateTxHandleFiles(sgh, f, tx_data->de_state, flow_flags, tx, tx_id, file_no_match);
SCLogDebug("Stored for TX %"PRIu64, tx_id);

@ -784,6 +784,15 @@ int DetectEngineAppInspectionEngine2Signature(DetectEngineCtx *de_ctx, Signature
for (const DetectEngineAppInspectionEngine *t = de_ctx->app_inspect_engines; t != NULL;
t = t->next) {
if (t->sm_list == s->init_data->buffers[x].id) {
if (s->flags & SIG_FLAG_TXBOTHDIR) {
// ambiguous keywords have app engines in both directions
// so we skip the wrong direction for this buffer
if (s->init_data->buffers[x].only_tc && t->dir == 0) {
continue;
} else if (s->init_data->buffers[x].only_ts && t->dir == 1) {
continue;
}
}
AppendAppInspectEngine(
de_ctx, t, s, smd, mpm_list, files_id, &last_id, &head_is_mpm);
}
@ -1412,7 +1421,12 @@ int DetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int l
} else if (DetectEngineBufferTypeSupportsMultiInstanceGetById(de_ctx, list)) {
// fall through
} else if (!b->only_ts && (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOSERVER)) {
// fall through
} else if (!b->only_tc && (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOCLIENT)) {
// fall through
} else {
// we create a new buffer for the same id but forced different direction
SCLogWarning("duplicate instance for %s in '%s'",
DetectEngineBufferTypeGetNameById(de_ctx, list), s->sig_str);
s->init_data->curbuf = b;
@ -1436,6 +1450,13 @@ int DetectBufferSetActiveList(DetectEngineCtx *de_ctx, Signature *s, const int l
s->init_data->curbuf->tail = NULL;
s->init_data->curbuf->multi_capable =
DetectEngineBufferTypeSupportsMultiInstanceGetById(de_ctx, list);
if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOCLIENT) {
s->init_data->curbuf->only_tc = true;
}
if (s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOSERVER) {
s->init_data->curbuf->only_ts = true;
}
SCLogDebug("new: idx %u list %d set up curbuf %p", s->init_data->buffer_index - 1, list,
s->init_data->curbuf);

@ -237,6 +237,18 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, const c
pm = pm2;
}
if (s->flags & SIG_FLAG_TXBOTHDIR && s->init_data->curbuf != NULL) {
if (DetectBufferToClient(de_ctx, s->init_data->curbuf->id, s->alproto)) {
if (s->init_data->init_flags & SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER) {
SCLogError("fast_pattern cannot be used on to_client keyword for "
"transactional rule with a streaming buffer to server %u",
s->id);
goto error;
}
s->init_data->init_flags |= SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT;
}
}
cd = (DetectContentData *)pm->ctx;
if ((cd->flags & DETECT_CONTENT_NEGATED) &&
((cd->flags & DETECT_CONTENT_DISTANCE) ||

@ -78,7 +78,7 @@ void DetectFiledataRegister(void)
#ifdef UNITTESTS
sigmatch_table[DETECT_FILE_DATA].RegisterTests = DetectFiledataRegisterTests;
#endif
sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_NOOPT;
sigmatch_table[DETECT_FILE_DATA].flags = SIGMATCH_OPTIONAL_OPT;
filehandler_table[DETECT_FILE_DATA].name = "file_data";
filehandler_table[DETECT_FILE_DATA].priority = 2;
@ -140,6 +140,11 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, const cha
return -1;
}
if (DetectSetupDirection(s, str) < 0) {
SCLogError("file.data failed to setup direction");
return -1;
}
if (s->alproto == ALPROTO_SMTP && (s->init_data->init_flags & SIG_FLAG_INIT_FLOW) &&
!(s->flags & SIG_FLAG_TOSERVER) && (s->flags & SIG_FLAG_TOCLIENT)) {
SCLogError("The 'file-data' keyword cannot be used with SMTP flow:to_client or "
@ -151,6 +156,19 @@ static int DetectFiledataSetup (DetectEngineCtx *de_ctx, Signature *s, const cha
return -1;
s->init_data->init_flags |= SIG_FLAG_INIT_FILEDATA;
if ((s->init_data->init_flags & SIG_FLAG_INIT_FORCE_TOCLIENT) == 0) {
// we cannot use a transactional rule with a fast pattern to client and this
if (s->init_data->init_flags & SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT) {
SCLogError("fast_pattern cannot be used on to_client keyword for "
"transactional rule with a streaming buffer to server %u",
s->id);
return -1;
}
s->init_data->init_flags |= SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER;
}
s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
SetupDetectEngineConfig(de_ctx);
return 0;
}

@ -113,7 +113,7 @@ void DetectFilemagicRegister(void)
sigmatch_table[DETECT_FILE_MAGIC].desc = "sticky buffer to match on the file magic";
sigmatch_table[DETECT_FILE_MAGIC].url = "/rules/file-keywords.html#filemagic";
sigmatch_table[DETECT_FILE_MAGIC].Setup = DetectFilemagicSetupSticky;
sigmatch_table[DETECT_FILE_MAGIC].flags = SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER;
sigmatch_table[DETECT_FILE_MAGIC].flags = SIGMATCH_OPTIONAL_OPT | SIGMATCH_INFO_STICKY_BUFFER;
filehandler_table[DETECT_FILE_MAGIC].name = "file.magic",
filehandler_table[DETECT_FILE_MAGIC].priority = 2;
@ -249,6 +249,10 @@ static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, const ch
*/
static int DetectFilemagicSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
if (DetectSetupDirection(s, str) < 0) {
SCLogError("file.magic failed to setup direction");
return -1;
}
if (DetectBufferSetActiveList(de_ctx, s, g_file_magic_buffer_id) < 0)
return -1;

@ -99,7 +99,7 @@ void DetectFilenameRegister(void)
sigmatch_table[DETECT_FILE_NAME].desc = "sticky buffer to match on the file name";
sigmatch_table[DETECT_FILE_NAME].url = "/rules/file-keywords.html#filename";
sigmatch_table[DETECT_FILE_NAME].Setup = DetectFilenameSetupSticky;
sigmatch_table[DETECT_FILE_NAME].flags = SIGMATCH_NOOPT|SIGMATCH_INFO_STICKY_BUFFER;
sigmatch_table[DETECT_FILE_NAME].flags = SIGMATCH_OPTIONAL_OPT | SIGMATCH_INFO_STICKY_BUFFER;
DetectBufferTypeSetDescriptionByName("file.name", "file name");
@ -207,6 +207,10 @@ static int DetectFilenameSetup (DetectEngineCtx *de_ctx, Signature *s, const cha
*/
static int DetectFilenameSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
if (DetectSetupDirection(s, str) < 0) {
SCLogError("file.name failed to setup direction");
return -1;
}
if (DetectBufferSetActiveList(de_ctx, s, g_file_name_buffer_id) < 0)
return -1;
s->file_flags |= (FILE_SIG_NEED_FILE | FILE_SIG_NEED_FILENAME);

@ -391,8 +391,18 @@ int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, const char *flowstr)
bool appendsm = true;
/* set the signature direction flags */
if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
if (s->flags & SIG_FLAG_TXBOTHDIR) {
SCLogError(
"rule %u means to use both directions, cannot specify a flow direction", s->id);
goto error;
}
s->flags |= SIG_FLAG_TOSERVER;
} else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
if (s->flags & SIG_FLAG_TXBOTHDIR) {
SCLogError(
"rule %u means to use both directions, cannot specify a flow direction", s->id);
goto error;
}
s->flags |= SIG_FLAG_TOCLIENT;
} else {
s->flags |= SIG_FLAG_TOSERVER;

@ -168,6 +168,14 @@ static int DetectHttpClientBodySetupSticky(DetectEngineCtx *de_ctx, Signature *s
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
return -1;
// we cannot use a transactional rule with a fast pattern to client and this
if (s->init_data->init_flags & SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT) {
SCLogError("fast_pattern cannot be used on to_client keyword for "
"transactional rule with a streaming buffer to server %u",
s->id);
return -1;
}
s->init_data->init_flags |= SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER;
return 0;
}

@ -162,9 +162,17 @@ static InspectionBuffer *GetResponseData2(DetectEngineThreadCtx *det_ctx,
*/
static int DetectHttpHeadersSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
if (DetectSetupDirection(s, str) < 0) {
SCLogError(KEYWORD_NAME " failed to setup direction");
return -1;
}
if (DetectBufferSetActiveList(de_ctx, s, g_buffer_id) < 0)
return -1;
s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOSERVER;
s->init_data->init_flags &= ~SIG_FLAG_INIT_FORCE_TOCLIENT;
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP) < 0)
return -1;
@ -180,7 +188,11 @@ static void DetectHttpHeadersRegisterStub(void)
sigmatch_table[KEYWORD_ID].desc = KEYWORD_NAME " sticky buffer for the " BUFFER_DESC;
sigmatch_table[KEYWORD_ID].url = "/rules/" KEYWORD_DOC;
sigmatch_table[KEYWORD_ID].Setup = DetectHttpHeadersSetupSticky;
#if defined(KEYWORD_TOSERVER) && defined(KEYWORD_TOSERVER)
sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_OPTIONAL_OPT | SIGMATCH_INFO_STICKY_BUFFER;
#else
sigmatch_table[KEYWORD_ID].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
#endif
#ifdef KEYWORD_TOSERVER
DetectAppLayerMpmRegister(BUFFER_NAME, SIG_FLAG_TOSERVER, 2, PrefilterGenericMpmRegister,

@ -1418,6 +1418,8 @@ static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sig
if (strcmp(parser->direction, "<>") == 0) {
s->init_data->init_flags |= SIG_FLAG_INIT_BIDIREC;
} else if (strcmp(parser->direction, "=>") == 0) {
s->flags |= SIG_FLAG_TXBOTHDIR;
} else if (strcmp(parser->direction, "->") != 0) {
SCLogError("\"%s\" is not a valid direction modifier, "
"\"->\" and \"<>\" are supported.",
@ -2142,6 +2144,9 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
} bufdir[nlists + 1];
memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
int ts_excl = 0;
int tc_excl = 0;
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
SignatureInitDataBuffer *b = &s->init_data->buffers[x];
const DetectBufferType *bt = DetectEngineBufferTypeGetById(de_ctx, b->id);
@ -2179,8 +2184,16 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
DetectEngineBufferTypeGetNameById(de_ctx, app->sm_list), app->dir,
app->alproto);
SCLogDebug("b->id %d nlists %d", b->id, nlists);
bufdir[b->id].ts += (app->dir == 0);
bufdir[b->id].tc += (app->dir == 1);
if (b->only_tc) {
if (app->dir == 1)
tc_excl++;
} else if (b->only_ts) {
if (app->dir == 0)
ts_excl++;
} else {
bufdir[b->id].ts += (app->dir == 0);
bufdir[b->id].tc += (app->dir == 1);
}
}
}
@ -2196,8 +2209,6 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
}
}
int ts_excl = 0;
int tc_excl = 0;
int dir_amb = 0;
for (int x = 0; x < nlists; x++) {
if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
@ -2209,8 +2220,22 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
bufdir[x].tc);
}
if (ts_excl && tc_excl) {
SCLogError("rule %u mixes keywords with conflicting directions", s->id);
if (s->flags & SIG_FLAG_TXBOTHDIR) {
if (!ts_excl || !tc_excl) {
SCLogError("rule %u should use both directions, but does not", s->id);
SCReturnInt(0);
}
if (dir_amb) {
SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
"directions",
s->id);
SCReturnInt(0);
}
} else if (ts_excl && tc_excl) {
SCLogError(
"rule %u mixes keywords with conflicting directions, a transactional rule with => "
"should be used",
s->id);
SCReturnInt(0);
} else if (ts_excl) {
SCLogDebug("%u: implied rule direction is toserver", s->id);
@ -3006,6 +3031,42 @@ void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_par
}
}
/**
* \brief Parse and setup a direction
*
* \param s siganture
* \param str argument to the keyword
*
* \retval 0 on success, -1 on failure
*/
int DetectSetupDirection(Signature *s, const char *str)
{
if (str) {
if (strcmp(str, "to_client") == 0) {
s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOCLIENT;
if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
if (s->flags & SIG_FLAG_TOSERVER) {
SCLogError("contradictory directions");
return -1;
}
s->flags |= SIG_FLAG_TOCLIENT;
}
} else if (strcmp(str, "to_server") == 0) {
s->init_data->init_flags |= SIG_FLAG_INIT_FORCE_TOSERVER;
if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
if (s->flags & SIG_FLAG_TOCLIENT) {
SCLogError("contradictory directions");
return -1;
}
s->flags |= SIG_FLAG_TOSERVER;
}
} else {
SCLogError("unknown option: only accepts to_server or to_client");
return -1;
}
}
return 0;
}
/*
* TESTS

@ -121,4 +121,6 @@ int SC_Pcre2SubstringCopy(
int SC_Pcre2SubstringGet(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr,
PCRE2_SIZE *bufflen);
int DetectSetupDirection(Signature *s, const char *str);
#endif /* SURICATA_DETECT_PARSE_H */

@ -29,6 +29,7 @@
#include "detect.h"
#include "detect-parse.h"
#include "detect-content.h"
#include "detect-engine-mpm.h"
#include "detect-prefilter.h"
#include "util-debug.h"
@ -75,6 +76,19 @@ static int DetectPrefilterSetup (DetectEngineCtx *de_ctx, Signature *s, const ch
/* if the sig match is content, prefilter should act like
* 'fast_pattern' w/o options. */
if (sm->type == DETECT_CONTENT) {
if (s->flags & SIG_FLAG_TXBOTHDIR && s->init_data->curbuf != NULL) {
if (s->init_data->init_flags & SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER) {
if (DetectBufferToClient(de_ctx, s->init_data->curbuf->id, s->alproto)) {
SCLogError("prefilter cannot be used on to_client keyword for "
"transactional rule %u",
s->id);
SCReturnInt(-1);
} else {
s->init_data->init_flags |= SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT;
}
}
}
DetectContentData *cd = (DetectContentData *)sm->ctx;
if ((cd->flags & DETECT_CONTENT_NEGATED) &&
((cd->flags & DETECT_CONTENT_DISTANCE) ||

@ -1166,9 +1166,11 @@ static bool DetectRunTxInspectRule(ThreadVars *tv,
const DetectEngineAppInspectionEngine *engine = s->app_inspect;
do {
TRACE_SID_TXS(s->id, tx, "engine %p inspect_flags %x", engine, inspect_flags);
// also if it is not the same direction, but
// this is a transactional signature, and we are toclient
if (!(inspect_flags & BIT_U32(engine->id)) &&
direction == engine->dir)
{
(direction == engine->dir || ((s->flags & SIG_FLAG_TXBOTHDIR) && direction == 1))) {
void *tx_ptr = DetectGetInnerTx(tx->tx_ptr, f->alproto, engine->alproto, flow_flags);
if (tx_ptr == NULL) {
if (engine->alproto != ALPROTO_UNKNOWN) {
@ -1204,6 +1206,10 @@ static bool DetectRunTxInspectRule(ThreadVars *tv,
}
}
uint8_t engine_flags = flow_flags;
if (direction != engine->dir) {
engine_flags = flow_flags ^ (STREAM_TOCLIENT | STREAM_TOSERVER);
}
/* run callback: but bypass stream callback if we can */
uint8_t match;
if (unlikely(engine->stream && can->stream_stored)) {
@ -1213,7 +1219,7 @@ static bool DetectRunTxInspectRule(ThreadVars *tv,
KEYWORD_PROFILING_SET_LIST(det_ctx, engine->sm_list);
DEBUG_VALIDATE_BUG_ON(engine->v2.Callback == NULL);
match = engine->v2.Callback(
de_ctx, det_ctx, engine, s, f, flow_flags, alstate, tx_ptr, tx->tx_id);
de_ctx, det_ctx, engine, s, f, engine_flags, alstate, tx_ptr, tx->tx_id);
TRACE_SID_TXS(s->id, tx, "engine %p match %d", engine, match);
if (engine->stream) {
can->stream_stored = true;
@ -1247,7 +1253,19 @@ static bool DetectRunTxInspectRule(ThreadVars *tv,
inspect_flags |= BIT_U32(engine->id);
}
break;
} else if (!(inspect_flags & BIT_U32(engine->id)) && s->flags & SIG_FLAG_TXBOTHDIR &&
direction != engine->dir) {
// for transactional rules, the engines on the opposite direction
// are ordered by progress on the different side
// so we have a two mixed-up lists, and we skip the elements
if (direction == 0 && engine->next == NULL) {
// do not match yet on request only
break;
}
engine = engine->next;
continue;
}
engine = engine->next;
} while (engine != NULL);
TRACE_SID_TXS(s->id, tx, "inspect_flags %x, total_matches %u, engine %p",

@ -246,6 +246,7 @@ typedef struct DetectPort_ {
#define SIG_FLAG_DSIZE BIT_U32(5) /**< signature has a dsize setting */
#define SIG_FLAG_APPLAYER BIT_U32(6) /**< signature applies to app layer instead of packets */
#define SIG_FLAG_TXBOTHDIR BIT_U32(7) /**< signature needs tx with both directions to match */
// vacancy
@ -295,7 +296,14 @@ typedef struct DetectPort_ {
#define SIG_FLAG_INIT_NEED_FLUSH BIT_U32(7)
#define SIG_FLAG_INIT_PRIO_EXPLICIT \
BIT_U32(8) /**< priority is explicitly set by the priority keyword */
#define SIG_FLAG_INIT_FILEDATA BIT_U32(9) /**< signature has filedata keyword */
#define SIG_FLAG_INIT_FILEDATA BIT_U32(9) /**< signature has filedata keyword */
#define SIG_FLAG_INIT_FORCE_TOCLIENT BIT_U32(10) /**< signature now takes keywords toclient */
#define SIG_FLAG_INIT_FORCE_TOSERVER BIT_U32(11) /**< signature now takes keywords toserver */
// Two following flags are meant to be mutually exclusive
#define SIG_FLAG_INIT_TXDIR_STREAMING_TOSERVER \
BIT_U32(12) /**< transactional signature uses a streaming buffer to server */
#define SIG_FLAG_INIT_TXDIR_FAST_TOCLIENT \
BIT_U32(13) /**< transactional signature uses a fast pattern to client */
/* signature mask flags */
/** \note: additions should be added to the rule analyzer as well */
@ -534,6 +542,8 @@ typedef struct SignatureInitDataBuffer_ {
set up. */
bool multi_capable; /**< true if we can have multiple instances of this buffer, so e.g. for
http.uri. */
bool only_tc; /**< true if we can only used toclient. */
bool only_ts; /**< true if we can only used toserver. */
/* sig match list */
SigMatch *head;
SigMatch *tail;

Loading…
Cancel
Save