detect/entropy: Add calculated entropy value to flowvars

When the entropy keyword is used, record the calculated entropy value to
a flow variable for logging use.
pull/13396/head
Jeff Lucovsky 1 year ago committed by Victor Julien
parent 62e3c02914
commit a292670443

@ -2921,6 +2921,14 @@
"type": "object",
"additionalProperties": false,
"properties": {
"entropy": {
"type": "object",
"suricata": {
"keywords": [
"entropy"
]
}
},
"flowbits": {
"type": "array",
"minItems": 1,

@ -27,13 +27,15 @@ use nom7::sequence::preceded;
use nom7::{Err, IResult};
use std::ffi::CStr;
use std::os::raw::{c_char, c_void};
use std::os::raw::{c_double, c_char, c_void};
use std::slice;
#[repr(C)]
#[derive(Debug)]
pub struct DetectEntropyData {
offset: i32,
nbytes: i32,
fv_idx: i32,
value: DetectFloatData<f64>,
}
@ -42,6 +44,7 @@ impl Default for DetectEntropyData {
DetectEntropyData {
offset: 0,
nbytes: 0,
fv_idx: 0,
value: DetectFloatData::<f64>::default(),
}
}
@ -166,6 +169,7 @@ fn calculate_entropy(data: &[u8]) -> f64 {
#[no_mangle]
pub unsafe extern "C" fn SCDetectEntropyMatch(
c_data: *const c_void, length: i32, ctx: &DetectEntropyData,
calculated_entropy: *mut c_double,
) -> bool {
if c_data.is_null() {
return false;
@ -200,7 +204,11 @@ pub unsafe extern "C" fn SCDetectEntropyMatch(
let entropy = calculate_entropy(data_slice);
SCLogDebug!("entropy is {}", entropy);
// Use a hypothetical `detect_entropy_match` function to check entropy
// Return entropy on request
if !calculated_entropy.is_null() {
*calculated_entropy = entropy;
}
detect_match_float::<f64>(&ctx.value, entropy)
}
@ -250,6 +258,7 @@ mod tests {
let ded = DetectEntropyData {
offset,
nbytes,
fv_idx: 0,
value: ctx,
};

@ -23,6 +23,8 @@
#include "detect-engine-buffer.h"
#include "detect-entropy.h"
#include "util-var-name.h"
#include "flow-var.h"
#include "rust.h"
@ -39,6 +41,8 @@ static int DetectEntropySetup(DetectEngineCtx *de_ctx, Signature *s, const char
goto error;
sm_list = s->init_data->list;
ded->fv_idx = VarNameStoreRegister(
DetectEngineBufferTypeGetNameById(de_ctx, sm_list), VAR_TYPE_FLOW_FLOAT);
}
if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_ENTROPY, (SigMatchCtx *)ded, sm_list) != NULL) {
@ -57,13 +61,25 @@ error:
static void DetectEntropyFree(DetectEngineCtx *de_ctx, void *ptr)
{
SCDetectEntropyFree(ptr);
if (ptr) {
DetectEntropyData *ded = (DetectEntropyData *)ptr;
VarNameStoreUnregister(ded->fv_idx, VAR_TYPE_FLOW_FLOAT);
SCDetectEntropyFree(ptr);
}
}
bool DetectEntropyDoMatch(DetectEngineThreadCtx *det_ctx, const Signature *s,
const SigMatchCtx *ctx, const uint8_t *buffer, const uint32_t buffer_len)
{
return SCDetectEntropyMatch(buffer, buffer_len, (const DetectEntropyData *)ctx);
double entropy = -1.0;
bool rc = SCDetectEntropyMatch(buffer, buffer_len, (const DetectEntropyData *)ctx, &entropy);
if (entropy != -1.0) {
DetectEntropyData *ded = (DetectEntropyData *)ctx;
FlowVarAddFloat(det_ctx->p->flow, ded->fv_idx, entropy);
}
return rc;
}
void DetectEntropyRegister(void)

@ -47,6 +47,12 @@ static void FlowVarUpdateInt(FlowVar *fv, uint32_t value)
fv->data.fv_int.value = value;
}
/* puts a new value into a flowvar */
static void FlowVarUpdateFloat(FlowVar *fv, double value)
{
fv->data.fv_float.value = value;
}
/** \brief get the flowvar with index 'idx' from the flow
* \note flow is not locked by this function, caller is
* responsible
@ -132,6 +138,26 @@ void FlowVarAddIdValue(Flow *f, uint32_t idx, uint8_t *value, uint16_t size)
}
}
/* add a flowvar to the flow, or update it */
void FlowVarAddFloat(Flow *f, uint32_t idx, double value)
{
FlowVar *fv = FlowVarGet(f, idx);
if (fv == NULL) {
fv = SCMalloc(sizeof(FlowVar));
if (unlikely(fv == NULL))
return;
fv->type = DETECT_FLOWVAR;
fv->datatype = FLOWVAR_TYPE_FLOAT;
fv->idx = idx;
fv->data.fv_float.value = value;
fv->next = NULL;
GenericVarAppend(&f->flowvar, (GenericVar *)fv);
} else {
FlowVarUpdateFloat(fv, value);
}
}
/* add a flowvar to the flow, or update it */
void FlowVarAddIntNoLock(Flow *f, uint32_t idx, uint32_t value)
{

@ -32,6 +32,7 @@
#define FLOWVAR_TYPE_STR 1
#define FLOWVAR_TYPE_INT 2
#define FLOWVAR_TYPE_FLOAT 3
typedef uint8_t FlowVarKeyLenType;
/** Struct used to hold the string data type for flowvars */
@ -45,6 +46,11 @@ typedef struct FlowVarTypeInt_ {
uint32_t value;
} FlowVarTypeInt;
/** Struct used to hold the integer data type for flowvars */
typedef struct FlowVarTypeFloat_ {
double value;
} FlowVarTypeFloat;
/** Generic Flowvar Structure */
typedef struct FlowVar_ {
uint16_t type; /* type, DETECT_FLOWVAR in this case */
@ -57,6 +63,7 @@ typedef struct FlowVar_ {
union {
FlowVarTypeStr fv_str;
FlowVarTypeInt fv_int;
FlowVarTypeFloat fv_float;
} data;
uint8_t *key;
} FlowVar;
@ -69,6 +76,7 @@ void FlowVarAddKeyValue(
void FlowVarAddIntNoLock(Flow *, uint32_t, uint32_t);
void FlowVarAddInt(Flow *, uint32_t, uint32_t);
void FlowVarAddFloat(Flow *, uint32_t, double);
FlowVar *FlowVarGet(Flow *, uint32_t);
FlowVar *FlowVarGetByKey(Flow *f, const uint8_t *key, FlowVarKeyLenType keylen);
void FlowVarFree(FlowVar *);

@ -247,6 +247,7 @@ static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder
SCJsonBuilder *js_traffic_id = NULL;
SCJsonBuilder *js_traffic_label = NULL;
SCJsonBuilder *js_flowints = NULL;
SCJsonBuilder *js_entropyvals = NULL;
SCJsonBuilder *js_flowbits = NULL;
GenericVar *gv = f->flowvar;
while (gv != NULL) {
@ -292,6 +293,17 @@ static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder
SCJbStartObject(js_flowvars);
SCJbSetString(js_flowvars, (const char *)keybuf, (char *)printable_buf);
SCJbClose(js_flowvars);
} else if (fv->datatype == FLOWVAR_TYPE_FLOAT) {
const char *varname = VarNameStoreLookupById(fv->idx, VAR_TYPE_FLOW_FLOAT);
if (varname) {
if (js_entropyvals == NULL) {
js_entropyvals = SCJbNewObject();
if (js_entropyvals == NULL)
break;
}
SCJbSetFloat(js_entropyvals, varname, fv->data.fv_float.value);
}
} else if (fv->datatype == FLOWVAR_TYPE_INT) {
const char *varname = VarNameStoreLookupById(fv->idx,
VAR_TYPE_FLOW_INT);
@ -303,7 +315,6 @@ static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder
}
SCJbSetUint(js_flowints, varname, fv->data.fv_int.value);
}
}
} else if (gv->type == DETECT_FLOWBITS) {
FlowBit *fb = (FlowBit *)gv;
@ -348,6 +359,11 @@ static void EveAddFlowVars(const Flow *f, SCJsonBuilder *js_root, SCJsonBuilder
SCJbSetObject(js_root, "flowints", js_flowints);
SCJbFree(js_flowints);
}
if (js_entropyvals) {
SCJbClose(js_entropyvals);
SCJbSetObject(js_root, "entropy", js_entropyvals);
SCJbFree(js_entropyvals);
}
if (js_flowvars) {
SCJbClose(js_flowvars);
SCJbSetObject(js_root, "flowvars", js_flowvars);

@ -35,6 +35,7 @@ enum VarTypes {
VAR_TYPE_FLOW_BIT,
VAR_TYPE_FLOW_INT,
VAR_TYPE_FLOW_FLOAT,
VAR_TYPE_FLOW_VAR,
VAR_TYPE_HOST_BIT,

Loading…
Cancel
Save