Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 81 additions & 20 deletions plugins/ndpi/ndpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,31 +58,72 @@ typedef struct DetectnDPIRiskData_ {
bool negated;
} DetectnDPIRiskData;

/**
* Safe helper to get nDPI thread context. Returns NULL if storage
* is not available (e.g. thread storage not yet initialized).
*/
static inline struct NdpiThreadContext *NdpiGetThreadContext(ThreadVars *tv)
{
if (unlikely(tv == NULL || thread_storage_id.id < 0))
return NULL;
return ThreadGetStorageById(tv, thread_storage_id);
}

/**
* Safe helper to get nDPI flow context. Returns NULL if the flow
* or its storage is not available. Guards against the case where
* f->storage is NULL (uninitialized flow) which would crash inside
* StorageGetById.
*/
static inline struct NdpiFlowContext *NdpiGetFlowContext(const Flow *f)
{
if (unlikely(f == NULL || flow_storage_id.id < 0 || f->storage == NULL))
return NULL;
return FlowGetStorageById(f, flow_storage_id);
}

static void ThreadStorageFree(void *ptr)
{
SCLogDebug("Free'ing nDPI thread storage");
struct NdpiThreadContext *context = ptr;
ndpi_exit_detection_module(context->ndpi);
if (context == NULL)
return;
if (context->ndpi != NULL)
ndpi_exit_detection_module(context->ndpi);
SCFree(context);
}

static void FlowStorageFree(void *ptr)
{
struct NdpiFlowContext *ctx = ptr;
ndpi_flow_free(ctx->ndpi_flow);
if (ctx == NULL)
return;
if (ctx->ndpi_flow != NULL)
ndpi_flow_free(ctx->ndpi_flow);
SCFree(ctx);
}

static void OnFlowInit(ThreadVars *tv, Flow *f, const Packet *p, void *_data)
{
if (unlikely(f == NULL))
return;

if (unlikely(f->storage == NULL)) {
SCLogDebug("Flow %p has no storage, skipping nDPI init", f);
return;
}

struct NdpiFlowContext *flowctx = SCCalloc(1, sizeof(*flowctx));
if (flowctx == NULL) {
FatalError("Failed to allocate nDPI flow context");
SCLogDebug("Failed to allocate nDPI flow context");
return;
}

flowctx->ndpi_flow = ndpi_flow_malloc(SIZEOF_FLOW_STRUCT);
if (flowctx->ndpi_flow == NULL) {
FatalError("Failed to allocate nDPI flow");
SCLogDebug("Failed to allocate nDPI flow");
SCFree(flowctx);
return;
}

memset(flowctx->ndpi_flow, 0, SIZEOF_FLOW_STRUCT);
Expand All @@ -92,21 +133,22 @@ static void OnFlowInit(ThreadVars *tv, Flow *f, const Packet *p, void *_data)

static void OnFlowUpdate(ThreadVars *tv, Flow *f, Packet *p, void *_data)
{
struct NdpiThreadContext *threadctx = ThreadGetStorageById(tv, thread_storage_id);
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
uint16_t ip_len = 0;
void *ip_ptr = NULL;

if (!threadctx->ndpi || !flowctx->ndpi_flow) {
return;
}

/* Ignore packets that have a different protocol than the
* flow. This can happen with ICMP unreachable packets. */
if (p->proto != f->proto) {
return;
}

uint16_t ip_len = 0;
void *ip_ptr = NULL;
struct NdpiThreadContext *threadctx = NdpiGetThreadContext(tv);
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);

if (threadctx == NULL || threadctx->ndpi == NULL)
return;
if (flowctx == NULL || flowctx->ndpi_flow == NULL)
return;

if (PacketIsIPv4(p)) {
const IPV4Hdr *ip4h = PacketGetIPv4(p);
ip_len = IPV4_GET_RAW_IPLEN(ip4h);
Expand Down Expand Up @@ -189,7 +231,7 @@ static int DetectnDPIProtocolPacketMatch(
SCReturnInt(0);
}

struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (flowctx == NULL) {
SCLogDebug("packet %" PRIu64 ": no flowctx", PcapPacketCntGet(p));
SCReturnInt(0);
Expand Down Expand Up @@ -324,7 +366,7 @@ static int DetectnDPIRiskPacketMatch(
SCReturnInt(0);
}

struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (flowctx == NULL) {
SCLogDebug("packet %" PRIu64 ": no flowctx", p->pcap_cnt);
SCReturnInt(0);
Expand All @@ -337,6 +379,11 @@ static int DetectnDPIRiskPacketMatch(
SCReturnInt(0);
}

if (flowctx->ndpi_flow == NULL) {
SCLogDebug("packet %" PRIu64 ": ndpi_flow is NULL", PcapPacketCntGet(p));
SCReturnInt(0);
}

bool r = ((flowctx->ndpi_flow->risk & data->risk_mask) == data->risk_mask);
r = r ^ data->negated;

Expand Down Expand Up @@ -382,6 +429,7 @@ static DetectnDPIRiskData *DetectnDPIRiskParse(const char *arg, bool negate)
SCLogError("unrecognized risk '%s', "
"please check ndpiReader -H for valid risk codes",
token);
SCFree(dup);
return NULL;
}
NDPI_SET_BIT(risk_mask, risk_id);
Expand Down Expand Up @@ -454,23 +502,36 @@ static void EveCallback(ThreadVars *tv, const Packet *p, Flow *f, SCJsonBuilder
return;
}

struct NdpiThreadContext *threadctx = ThreadGetStorageById(tv, thread_storage_id);
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
struct NdpiThreadContext *threadctx = NdpiGetThreadContext(tv);
if (threadctx == NULL || threadctx->ndpi == NULL) {
return;
}

struct NdpiFlowContext *flowctx = NdpiGetFlowContext(f);
if (flowctx == NULL || flowctx->ndpi_flow == NULL) {
return;
}

ndpi_serializer serializer;
char *buffer;
uint32_t buffer_len;

SCLogDebug("EveCallback: tv=%p, p=%p, f=%p", tv, p, f);

ndpi_init_serializer(&serializer, ndpi_serialization_format_inner_json);
if (ndpi_init_serializer(&serializer, ndpi_serialization_format_inner_json) != 0) {
SCLogDebug("Failed to initialize nDPI serializer");
return;
}

/* Use ndpi_dpi2json to get a JSON with nDPI metadata */
ndpi_dpi2json(threadctx->ndpi, flowctx->ndpi_flow, flowctx->detected_l7_protocol, &serializer);

buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len);

/* Inject the nDPI JSON to the JsonBuilder */
SCJbSetFormatted(jb, buffer);
if (buffer != NULL && buffer_len > 0) {
/* Inject the nDPI JSON to the JsonBuilder */
SCJbSetFormatted(jb, buffer);
}

ndpi_term_serializer(&serializer);
}
Expand Down
5 changes: 4 additions & 1 deletion src/source-dpdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
SCEnter();
DPDKThreadVars *ptv = (DPDKThreadVars *)data;
ptv->slot = ((TmSlot *)slot)->slot_next;
uint32_t mp_sz = ptv->livedev->dpdk_vars->pkt_mp[ptv->queue_id]->size;
uint16_t burst_size = (uint16_t)MIN(BURST_SIZE, mp_sz);

TmEcode ret = ReceiveDPDKLoopInit(tv, ptv);
if (ret != TM_ECODE_OK) {
SCReturnInt(ret);
Expand All @@ -584,7 +587,7 @@ static TmEcode ReceiveDPDKLoop(ThreadVars *tv, void *data, void *slot)
}

uint16_t nb_rx =
rte_eth_rx_burst(ptv->port_id, ptv->queue_id, ptv->received_mbufs, BURST_SIZE);
rte_eth_rx_burst(ptv->port_id, ptv->queue_id, ptv->received_mbufs, burst_size);
if (RXPacketCountHeuristic(tv, ptv, nb_rx)) {
continue;
}
Expand Down
8 changes: 7 additions & 1 deletion src/suricata.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,13 @@ void EngineModeSetFirewall(void)

void EngineModeSetIPS(void)
{
g_engine_mode = ENGINE_MODE_IPS;
#ifndef UNITTESTS
if (g_engine_mode == ENGINE_MODE_UNKNOWN)
g_engine_mode = ENGINE_MODE_IPS;
#else
if (RunmodeIsUnittests() || g_engine_mode == ENGINE_MODE_UNKNOWN)
g_engine_mode = ENGINE_MODE_IPS;
#endif
}

void EngineModeSetIDS(void)
Expand Down
Loading