diff --git a/plugins/ndpi/ndpi.c b/plugins/ndpi/ndpi.c index ad6cd78b7d26..27e34ca08066 100644 --- a/plugins/ndpi/ndpi.c +++ b/plugins/ndpi/ndpi.c @@ -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); @@ -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); @@ -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); @@ -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); @@ -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; @@ -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); @@ -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); } diff --git a/src/source-dpdk.c b/src/source-dpdk.c index f0068f3edc6f..2072af8f48ea 100644 --- a/src/source-dpdk.c +++ b/src/source-dpdk.c @@ -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); @@ -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; } diff --git a/src/suricata.c b/src/suricata.c index c5e51a4714ad..be32df8cd3f4 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -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)