"type": "object",
"additionalProperties": false,
"properties": {
+ "entropy": {
+ "type": "object",
+ "suricata": {
+ "keywords": [
+ "entropy"
+ ]
+ }
+ },
"flowbits": {
"type": "array",
"minItems": 1,
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>,
}
DetectEntropyData {
offset: 0,
nbytes: 0,
+ fv_idx: 0,
value: DetectFloatData::<f64>::default(),
}
}
#[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;
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)
}
let ded = DetectEntropyData {
offset,
nbytes,
+ fv_idx: 0,
value: ctx,
};
#include "detect-engine-buffer.h"
#include "detect-entropy.h"
+#include "util-var-name.h"
+#include "flow-var.h"
#include "rust.h"
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) {
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)
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
}
}
+/* 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)
{
#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 */
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 */
union {
FlowVarTypeStr fv_str;
FlowVarTypeInt fv_int;
+ FlowVarTypeFloat fv_float;
} data;
uint8_t *key;
} FlowVar;
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 *);
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) {
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);
}
SCJbSetUint(js_flowints, varname, fv->data.fv_int.value);
}
-
}
} else if (gv->type == DETECT_FLOWBITS) {
FlowBit *fb = (FlowBit *)gv;
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);
VAR_TYPE_FLOW_BIT,
VAR_TYPE_FLOW_INT,
+ VAR_TYPE_FLOW_FLOAT,
VAR_TYPE_FLOW_VAR,
VAR_TYPE_HOST_BIT,