diff --git a/doc/userguide/configuration/exception-policies.rst b/doc/userguide/configuration/exception-policies.rst index 561cbe6ad6..de878bd63c 100644 --- a/doc/userguide/configuration/exception-policies.rst +++ b/doc/userguide/configuration/exception-policies.rst @@ -227,12 +227,22 @@ Flow Event When an Exception Policy is triggered, this will be indicated in the flow log event for the associated flow, also indicating which target triggered that, and -what policy was applied. If no exception policy is triggered, that field won't -be present in the logs. +what policy was applied. **This is a configurable option, disabled by default.** +If no exception policy is triggered, that field won't be present in the logs. Note that this is true even if the policy is applied only to certain packets from a flow. +To enable logging of the triggered exception policies for a given flow, enable +the yaml option:: + + output: + - eve-log: + enabled: yes + types: + - flow: + exception-policy: true + .. Note:: As exception policies targetting ``flow memcap`` and ``defrag memcap`` act on a per-packet level, these are not shown in the flow logs. Ticket #7884 (https://redmine.openinfosecfoundation.org/issues/7884) diff --git a/src/output-json-flow.c b/src/output-json-flow.c index 08b6e731eb..316237c0c9 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -52,6 +52,103 @@ #include "flow-storage.h" #include "util-exception-policy.h" +typedef struct LogFlowCtx_ { + bool log_exception_policies; + OutputJsonCtx *eve_ctx; +} LogFlowCtx; + +typedef struct LogFlowLogThread_ { + LogFlowCtx *flowlog_ctx; + OutputJsonThreadCtx *output_ctx; +} LogFlowLogThread; + +static void OutputFlowLogDeInitCtxSub(OutputCtx *output_ctx) +{ + LogFlowCtx *flow_ctx = output_ctx->data; + SCFree(flow_ctx); + SCFree(output_ctx); +} + +static void JsonFlowLogParseConfig(ConfNode *conf, LogFlowCtx *flow_ctx) +{ + /* by default, don't log exception policies */ + flow_ctx->log_exception_policies = false; + + if (conf != NULL) { + if (ConfNodeChildValueIsTrue(conf, "exception-policy")) { + flow_ctx->log_exception_policies = true; + } + } + SCLogDebug("Exception policy logging for flow %s", + flow_ctx->log_exception_policies ? "enabled" : "disabled"); +} + +static OutputInitResult OutputFlowLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) +{ + OutputInitResult result = { NULL, false }; + OutputJsonCtx *ojc = parent_ctx->data; + + LogFlowCtx *flow_ctx = SCCalloc(1, sizeof(LogFlowCtx)); + if (unlikely(flow_ctx == NULL)) { + return result; + } + + OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); + if (unlikely(output_ctx == NULL)) { + SCFree(flow_ctx); + return result; + } + + flow_ctx->eve_ctx = ojc; + + output_ctx->data = flow_ctx; + output_ctx->DeInit = OutputFlowLogDeInitCtxSub; + JsonFlowLogParseConfig(conf, flow_ctx); + + result.ctx = output_ctx; + result.ok = true; + + return result; +} + +static TmEcode JsonFlowLogThreadInit(ThreadVars *tv, const void *initdata, void **data) +{ + LogFlowLogThread *thread = SCCalloc(1, sizeof(LogFlowLogThread)); + if (unlikely(thread == NULL)) { + return TM_ECODE_FAILED; + } + + if (initdata == NULL) { + SCLogDebug("Error getting context for EveLogFlow. \"initdata\" argument NULL"); + goto error_exit; + } + + thread->flowlog_ctx = ((OutputCtx *)initdata)->data; + thread->output_ctx = CreateEveThreadCtx(tv, thread->flowlog_ctx->eve_ctx); + if (!thread->output_ctx) { + goto error_exit; + } + + *data = (void *)thread; + return TM_ECODE_OK; + +error_exit: + SCFree(thread); + return TM_ECODE_FAILED; +} + +static TmEcode JsonFlowLogThreadDeInit(ThreadVars *tv, void *data) +{ + LogFlowLogThread *thread = (LogFlowLogThread *)data; + if (thread == NULL) { + return TM_ECODE_FAILED; + } + + FreeEveThreadCtx(thread->output_ctx); + SCFree(thread); + return TM_ECODE_OK; +} + static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) { char timebuf[64]; @@ -275,7 +372,7 @@ static void EveExceptionPolicyLog(JsonBuilder *js, uint16_t flag) } /* Eve format logging */ -static void EveFlowLogJSON(OutputJsonThreadCtx *aft, JsonBuilder *jb, Flow *f) +static void EveFlowLogJSON(LogFlowLogThread *ft, JsonBuilder *jb, Flow *f) { EveAddAppProto(f, jb); jb_open_object(jb, "flow"); @@ -337,7 +434,7 @@ static void EveFlowLogJSON(OutputJsonThreadCtx *aft, JsonBuilder *jb, Flow *f) } else if (f->flags & FLOW_ACTION_PASS) { JB_SET_STRING(jb, "action", "pass"); } - if (f->applied_exception_policy != 0) { + if (f->applied_exception_policy != 0 && ft->flowlog_ctx->log_exception_policies) { jb_open_array(jb, "exception_policy"); EveExceptionPolicyLog(jb, f->applied_exception_policy); jb_close(jb); /* close array */ @@ -346,7 +443,7 @@ static void EveFlowLogJSON(OutputJsonThreadCtx *aft, JsonBuilder *jb, Flow *f) /* Close flow. */ jb_close(jb); - EveAddCommonOptions(&aft->ctx->cfg, NULL, f, jb, LOG_DIR_FLOW); + EveAddCommonOptions(&ft->output_ctx->ctx->cfg, NULL, f, jb, LOG_DIR_FLOW); /* TCP */ if (f->proto == IPPROTO_TCP) { @@ -397,10 +494,7 @@ static void EveFlowLogJSON(OutputJsonThreadCtx *aft, JsonBuilder *jb, Flow *f) static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) { SCEnter(); - OutputJsonThreadCtx *thread = thread_data; - - /* reset */ - MemBufferReset(thread->buffer); + LogFlowLogThread *thread = thread_data; JsonBuilder *jb = CreateEveHeaderFromFlow(f); if (unlikely(jb == NULL)) { @@ -409,7 +503,7 @@ static int JsonFlowLogger(ThreadVars *tv, void *thread_data, Flow *f) EveFlowLogJSON(thread, jb, f); - OutputJsonBuilderBuffer(jb, thread); + OutputJsonBuilderBuffer(jb, thread->output_ctx); jb_free(jb); SCReturnInt(TM_ECODE_OK); @@ -419,5 +513,6 @@ void JsonFlowLogRegister (void) { /* register as child of eve-log */ OutputRegisterFlowSubModule(LOGGER_JSON_FLOW, "eve-log", "JsonFlowLog", "eve-log.flow", - OutputJsonLogInitSub, JsonFlowLogger, JsonLogThreadInit, JsonLogThreadDeinit, NULL); + OutputFlowLogInitSub, JsonFlowLogger, JsonFlowLogThreadInit, JsonFlowLogThreadDeInit, + NULL); } diff --git a/suricata.yaml.in b/suricata.yaml.in index 6ef9becfc1..caa3b99014 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -323,7 +323,9 @@ outputs: threads: no # per thread stats deltas: no # include delta values # bi-directional flows - - flow + - flow: + # Log exception policies triggered by this flow. Disabled by default. + # exception-policy: false # uni-directional flows #- netflow