From 7c5285e5e6d4434bd92d189aa368b8494911ba24 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 21 Jan 2026 10:08:27 +0100 Subject: [PATCH 01/20] doc/userguide: explain isdataat absolute vs relative difference Ticket: #8031. --- doc/userguide/rules/payload-keywords.rst | 32 ++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index 25f74d853eca..fdcd9f9869ed 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -271,6 +271,38 @@ You can also use the negation (!) before isdataat. .. image:: payload-keywords/isdataat1.png +absolute vs relative values +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The absolute ``isdataat`` checks will succeed if the offset used is +**less than** the size of the inspection buffer. + +For *relative* ``isdataat`` checks, there is a **1 byte difference** vs +the absolute handling. + +Matching will succeed if the relative offset is **less than or equal to** +the size of the inspection buffer. This is different from absolute +``isdataat`` checks. + +As an example, consider a 32 byte payload: + ++---------------------------+--------+ +| rule statement | Match? | ++---------------------------+--------+ +| ``isdataat:31;`` | Yes | ++---------------------------+--------+ +| ``isdataat:32;`` | No | ++---------------------------+--------+ +| ``isdataat:31,relative;`` | Yes | ++---------------------------+--------+ +| ``isdataat:32,relative;`` | Yes | ++---------------------------+--------+ +| ``isdataat:33,relative;`` | No | ++---------------------------+--------+ + +A discussion of this difference can be found at +https://redmine.openinfosecfoundation.org/issues/8031 + absent ------ From 2d662538e5f1b1e1270b61643d7a61b8d36606a9 Mon Sep 17 00:00:00 2001 From: Sven Cuyt Date: Sat, 31 Jan 2026 16:11:45 +0100 Subject: [PATCH 02/20] doc/userguide: add example with non-zero offset for relative isdataat Ticket: #8031. --- doc/userguide/rules/payload-keywords.rst | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index fdcd9f9869ed..ef83b64bfa4b 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -300,6 +300,36 @@ As an example, consider a 32 byte payload: | ``isdataat:33,relative;`` | No | +---------------------------+--------+ +Another example, consider the following payload: + + +-------------------------------+ +Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + +-------------------------------+ +Value | a | b | c | d | e | f | g | h | + +-------------------------------+ + +Then the following rules match the payload as follows: + ++----------------------------------------+--------+ +| Rule statement | Match? | ++----------------------------------------+--------+ +| ``isdataat:7;`` | Yes | ++----------------------------------------+--------+ +| ``isdataat:8;`` | No | ++----------------------------------------+--------+ +| ``isdataat:7,relative;`` | Yes | ++----------------------------------------+--------+ +| ``isdataat:8,relative;`` | Yes | ++----------------------------------------+--------+ +| ``isdataat:9,relative;`` | No | ++----------------------------------------+--------+ +| ``payload:"c"; isdataat:4,relative;`` | Yes | ++----------------------------------------+--------+ +| ``payload:"c"; isdataat:5,relative;`` | Yes | ++----------------------------------------+--------+ +| ``payload:"c"; isdataat:6,relative;`` | No | ++----------------------------------------+--------+ + A discussion of this difference can be found at https://redmine.openinfosecfoundation.org/issues/8031 From a0cc53447166af351e964c9345f2708d5288717b Mon Sep 17 00:00:00 2001 From: Sven Cuyt Date: Wed, 18 Feb 2026 18:15:50 +0100 Subject: [PATCH 03/20] doc/userguide: fix table showing example payload Ticket: #8031. --- doc/userguide/rules/payload-keywords.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index ef83b64bfa4b..ef40c07036a4 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -302,11 +302,11 @@ As an example, consider a 32 byte payload: Another example, consider the following payload: - +-------------------------------+ -Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | - +-------------------------------+ -Value | a | b | c | d | e | f | g | h | - +-------------------------------+ ++-------+---+---+---+---+---+---+---+---+ +| Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ++-------+---+---+---+---+---+---+---+---+ +| Value | a | b | c | d | e | f | g | h | ++-------+---+---+---+---+---+---+---+---+ Then the following rules match the payload as follows: From 1246f1cf8cb2edb4fd489b8290ff923569adab73 Mon Sep 17 00:00:00 2001 From: Sven Cuyt Date: Wed, 18 Feb 2026 18:16:29 +0100 Subject: [PATCH 04/20] doc/userguide: add link to differences-from-snort Ticket: #8031. --- doc/userguide/rules/payload-keywords.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/userguide/rules/payload-keywords.rst b/doc/userguide/rules/payload-keywords.rst index ef40c07036a4..c74f2e991dcd 100644 --- a/doc/userguide/rules/payload-keywords.rst +++ b/doc/userguide/rules/payload-keywords.rst @@ -330,6 +330,8 @@ Then the following rules match the payload as follows: | ``payload:"c"; isdataat:6,relative;`` | No | +----------------------------------------+--------+ +These differences are also discussed in :doc:`differences-from-snort`. + A discussion of this difference can be found at https://redmine.openinfosecfoundation.org/issues/8031 From b84ae80146c0fbd63ea88a431ebb78f0e08df7c9 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Feb 2026 15:51:21 +0100 Subject: [PATCH 05/20] affinity: address coverity warning CID 1667318: (#1 of 1): Structurally dead code (UNREACHABLE) unreachable: This code cannot be reached: hwloc_obj_t non_io_ancestor.... --- src/util-affinity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util-affinity.c b/src/util-affinity.c index 8be64253ca20..806310e3d941 100644 --- a/src/util-affinity.c +++ b/src/util-affinity.c @@ -660,8 +660,7 @@ static int HwLocDeviceNumaGet(hwloc_topology_t topo, hwloc_obj_t obj) return nodes[0]->logical_index; } return -1; -#endif /* HWLOC_VERSION_MAJOR >= 2 && HWLOC_VERSION_MINOR >= 5 */ - +#else hwloc_obj_t non_io_ancestor = hwloc_get_non_io_ancestor_obj(topo, obj); if (non_io_ancestor == NULL) { return -1; @@ -676,6 +675,7 @@ static int HwLocDeviceNumaGet(hwloc_topology_t topo, hwloc_obj_t obj) } return -1; +#endif /* ! HWLOC_VERSION_MAJOR >= 2 && HWLOC_VERSION_MINOR >= 5 */ } static hwloc_obj_t HwLocDeviceGetByKernelName(hwloc_topology_t topo, const char *interface_name) From e7c9be07e64fcb271189338c1f0377b4fb7b2a25 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 18 Feb 2026 16:10:52 +0100 Subject: [PATCH 06/20] af-xdp: add missing unlock in error path CID 1638288: (#1 of 1): Missing unlock (LOCK) 4. missing_unlock: Returning without unlocking xsk_protect.queue_protect. --- src/source-af-xdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/source-af-xdp.c b/src/source-af-xdp.c index 9fbb30ebf3d8..91bbd9e9720d 100644 --- a/src/source-af-xdp.c +++ b/src/source-af-xdp.c @@ -440,6 +440,7 @@ static TmEcode OpenXSKSocket(AFXDPThreadVars *ptv) if ((ret = xsk_socket__create(&ptv->xsk.xsk, ptv->livedev->dev, ptv->xsk.queue.queue_num, ptv->umem.umem, &ptv->xsk.rx, &ptv->xsk.tx, &ptv->xsk.cfg))) { SCLogError("Failed to create socket: %s", strerror(-ret)); + SCMutexUnlock(&xsk_protect.queue_protect); SCReturnInt(TM_ECODE_FAILED); } SCLogDebug("bind to %s on queue %u", ptv->iface, ptv->xsk.queue.queue_num); From 5edb5a5d1a9190c4936cb7b4cfbd835eb365d31f Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Tue, 10 Feb 2026 11:04:46 -0300 Subject: [PATCH 07/20] build-scopes: add QA_SIMULATION mode For qa-simulation scenarios, especially for testing purposes. Task #7885 --- configure.ac | 9 +++++++++ src/suricata.c | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/configure.ac b/configure.ac index f3909ed610c6..10bbc3f233f7 100644 --- a/configure.ac +++ b/configure.ac @@ -537,6 +537,14 @@ ]) AM_CONDITIONAL([DEBUG_VALIDATION], [test "x$enable_debug_validation" = "xyes"]) + # enable qa-simulation mode -- disabled by default + AC_ARG_ENABLE(qa-simulation, + AS_HELP_STRING([--enable-qa-simulation], [Enable qa-simulation mode])) + AS_IF([test "x$enable_qa_simulation" = "xyes"], [ + AC_DEFINE([QA_SIMULATION],[1],[Enable qa-simulation mode]) + ]) + AM_CONDITIONAL([QA_SIMULATION], [test "x$enable_qa_simulation" = "xyes"]) + # profiling support AC_ARG_ENABLE(profiling, AS_HELP_STRING([--enable-profiling], [Enable performance profiling]),[enable_profiling=$enableval],[enable_profiling=no]) @@ -2642,6 +2650,7 @@ Development settings: Unit tests enabled: ${enable_unittests} Debug output enabled: ${enable_debug} Debug validation enabled: ${enable_debug_validation} + QA-simulation enabled: ${enable_qa_simulation} Fuzz targets enabled: ${enable_fuzztargets} Generic build parameters: diff --git a/src/suricata.c b/src/suricata.c index 903d8abd05e6..a4830d431318 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -751,6 +751,7 @@ static void PrintBuildInfo(void) { const char *bits; const char *endian; + /* If all current features are enabled, features string would be 341 characters long */ char features[2048] = ""; const char *tls; @@ -761,6 +762,9 @@ static void PrintBuildInfo(void) #ifdef DEBUG_VALIDATION strlcat(features, "DEBUG_VALIDATION ", sizeof(features)); #endif +#ifdef QA_SIMULATION + strlcat(features, "QA_SIMULATION ", sizeof(features)); +#endif #ifdef UNITTESTS strlcat(features, "UNITTESTS ", sizeof(features)); #endif From dc4d8059087ae8f238149b71747df1bbaa5a56f5 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Tue, 10 Feb 2026 11:05:18 -0300 Subject: [PATCH 08/20] exceptions: s/DEBUG/QA_SIMULATION build flag Task #7885 --- src/app-layer-parser.c | 2 +- src/defrag-hash.c | 2 +- src/detect-engine-alert.c | 4 ++-- src/flow-hash.c | 2 +- src/source-pcap-file-helper.c | 2 +- src/stream-tcp-reassemble.c | 4 +++- src/stream-tcp.c | 13 +++++++------ src/util-exception-policy.c | 2 +- src/util-exception-policy.h | 2 +- 9 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 0ab84a8269de..84cbd222dc17 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1373,7 +1373,7 @@ int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow &stream_slice); HandleStreamFrames(f, stream_slice, input, input_len, flags); -#ifdef DEBUG +#ifdef QA_SIMULATION if (((stream_slice.flags & STREAM_TOSERVER) && stream_slice.offset >= g_eps_applayer_error_offset_ts)) { SCLogNotice("putting parser %s into an error state from toserver offset %" PRIu64, diff --git a/src/defrag-hash.c b/src/defrag-hash.c index 846c51d3dffd..d2028eb8f1b2 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -468,7 +468,7 @@ static void DefragExceptionPolicyStatsIncr( */ static DefragTracker *DefragTrackerGetNew(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p) { -#ifdef DEBUG +#ifdef QA_SIMULATION if (g_eps_defrag_memcap != UINT64_MAX && g_eps_defrag_memcap == PcapPacketCntGet(p)) { SCLogNotice("simulating memcap hit for packet %" PRIu64, PcapPacketCntGet(p)); ExceptionPolicyApply(p, defrag_config.memcap_policy, PKT_DROP_REASON_DEFRAG_MEMCAP); diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 15929a8eb3ac..568978159c85 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -29,7 +29,7 @@ #include "flow.h" #include "flow-private.h" -#ifdef DEBUG +#ifdef QA_SIMULATION #include "util-exception-policy.h" #endif @@ -283,7 +283,7 @@ static inline uint16_t AlertQueueExpandDo(DetectEngineThreadCtx *det_ctx, uint16 */ static uint16_t AlertQueueExpand(DetectEngineThreadCtx *det_ctx) { -#ifdef DEBUG +#ifdef QA_SIMULATION if (unlikely(g_eps_is_alert_queue_fail_mode)) return det_ctx->alert_queue_capacity; #endif diff --git a/src/flow-hash.c b/src/flow-hash.c index bd35848a1d13..3ac134f57ca7 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -694,7 +694,7 @@ static inline void NoFlowHandleIPS(ThreadVars *tv, FlowLookupStruct *fls, Packet static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, Packet *p) { const bool emerg = ((SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0); -#ifdef DEBUG +#ifdef QA_SIMULATION if (g_eps_flow_memcap != UINT64_MAX && g_eps_flow_memcap == PcapPacketCntGet(p)) { NoFlowHandleIPS(tv, fls, p); StatsCounterIncr(&tv->stats, fls->dtv->counter_flow_memcap); diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c index 0f3aac98f3f8..eb9d3a993abd 100644 --- a/src/source-pcap-file-helper.c +++ b/src/source-pcap-file-helper.c @@ -104,7 +104,7 @@ void CleanupPcapFileFileVars(PcapFileFileVars *pfv) void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { SCEnter(); -#ifdef DEBUG +#ifdef QA_SIMULATION if (unlikely((pcap_g.cnt + 1ULL) == g_eps_pcap_packet_loss)) { SCLogNotice("skipping packet %" PRIu64, g_eps_pcap_packet_loss); pcap_g.cnt++; diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 6d9efa249d32..59368b7315ac 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -75,6 +75,8 @@ static SCMutex segment_pool_memuse_mutex; static uint64_t segment_pool_memuse = 0; static uint64_t segment_pool_memcnt = 0; +#endif +#ifdef QA_SIMULATION thread_local uint64_t t_pcapcnt = UINT64_MAX; #endif @@ -162,7 +164,7 @@ uint64_t StreamTcpReassembleMemuseGlobalCounter(void) */ int StreamTcpReassembleCheckMemcap(uint64_t size) { -#ifdef DEBUG +#ifdef QA_SIMULATION if (unlikely((g_eps_stream_reassembly_memcap != UINT64_MAX && g_eps_stream_reassembly_memcap == t_pcapcnt))) { SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt); diff --git a/src/stream-tcp.c b/src/stream-tcp.c index c4bd1b800624..299e071d0fb1 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -221,9 +221,9 @@ extern int g_detect_disabled; PoolThread *ssn_pool = NULL; static SCMutex ssn_pool_mutex = SCMUTEX_INITIALIZER; /**< init only, protect initializing and growing pool */ -#ifdef DEBUG -extern thread_local uint64_t t_pcapcnt; +#if defined(DEBUG) || defined(QA_SIMULATION) static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */ +extern thread_local uint64_t t_pcapcnt; #endif TcpStreamCnf stream_config; @@ -950,12 +950,12 @@ static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Pac #endif StatsCounterIncr(&tv->stats, stt->counter_tcp_ssn_from_pool); } -#ifdef DEBUG +#if defined(DEBUG) || defined(QA_SIMULATION) SCMutexLock(&ssn_pool_mutex); if (p->flow->protoctx != NULL) ssn_pool_cnt++; SCMutexUnlock(&ssn_pool_mutex); - +#ifdef QA_SIMULATION if (unlikely((g_eps_stream_ssn_memcap != UINT64_MAX && g_eps_stream_ssn_memcap == t_pcapcnt))) { SCLogNotice("simulating memcap reached condition for packet %" PRIu64, t_pcapcnt); @@ -963,6 +963,7 @@ static TcpSession *StreamTcpNewSession(ThreadVars *tv, StreamTcpThread *stt, Pac StreamTcpSsnMemcapExceptionPolicyStatsIncr(tv, stt, stream_config.ssn_memcap_policy); return NULL; } +#endif #endif ssn = (TcpSession *)p->flow->protoctx; if (ssn == NULL) { @@ -6122,9 +6123,9 @@ TmEcode StreamTcp (ThreadVars *tv, Packet *p, void *data, PacketQueueNoLock *pq) : "noflow", PktSrcToString(p->pkt_src)); -#ifdef DEBUG +#ifdef QA_SIMULATION t_pcapcnt = PcapPacketCntGet(p); -#endif /* DEBUG */ +#endif if (!(PacketIsTCP(p))) { return TM_ECODE_OK; diff --git a/src/util-exception-policy.c b/src/util-exception-policy.c index 9befaf6c6b52..a233c778817a 100644 --- a/src/util-exception-policy.c +++ b/src/util-exception-policy.c @@ -390,7 +390,7 @@ void ExceptionPolicySetStatsCounters(ThreadVars *tv, ExceptionPolicyCounters *co } } -#ifndef DEBUG +#ifndef QA_SIMULATION int ExceptionSimulationCommandLineParser(const char *name, const char *arg) { diff --git a/src/util-exception-policy.h b/src/util-exception-policy.h index 9d3dcc4260d6..64edb279747f 100644 --- a/src/util-exception-policy.h +++ b/src/util-exception-policy.h @@ -38,7 +38,7 @@ void ExceptionPolicySetStatsCounters(ThreadVars *tv, ExceptionPolicyCounters *co const char *default_str, bool (*isExceptionPolicyValid)(enum ExceptionPolicy)); extern enum ExceptionPolicy g_eps_master_switch; -#ifdef DEBUG +#ifdef QA_SIMULATION extern uint64_t g_eps_applayer_error_offset_ts; extern uint64_t g_eps_applayer_error_offset_tc; extern uint64_t g_eps_pcap_packet_loss; From 723aa21e6f8c9c560b7792c723aec0b5a5bd467a Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Tue, 10 Feb 2026 12:46:00 -0300 Subject: [PATCH 09/20] misc: update copyright years For files edited during Task #7885 --- src/app-layer-parser.c | 2 +- src/defrag-hash.c | 2 +- src/detect-engine-alert.c | 2 +- src/flow-hash.c | 2 +- src/source-pcap-file-helper.c | 2 +- src/stream-tcp-reassemble.c | 2 +- src/util-exception-policy.c | 2 +- src/util-exception-policy.h | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 84cbd222dc17..812c467d6144 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2025 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/defrag-hash.c b/src/defrag-hash.c index d2028eb8f1b2..49dc2b5305fa 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2024 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 568978159c85..1dcc78f4c86b 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2022 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/flow-hash.c b/src/flow-hash.c index 3ac134f57ca7..664dce45dae9 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2024 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/source-pcap-file-helper.c b/src/source-pcap-file-helper.c index eb9d3a993abd..e88db6d51547 100644 --- a/src/source-pcap-file-helper.c +++ b/src/source-pcap-file-helper.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2020 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/stream-tcp-reassemble.c b/src/stream-tcp-reassemble.c index 59368b7315ac..06439827ff31 100644 --- a/src/stream-tcp-reassemble.c +++ b/src/stream-tcp-reassemble.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2024 Open Information Security Foundation +/* Copyright (C) 2007-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/util-exception-policy.c b/src/util-exception-policy.c index a233c778817a..4276636fb248 100644 --- a/src/util-exception-policy.c +++ b/src/util-exception-policy.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2022-2025 Open Information Security Foundation +/* Copyright (C) 2022-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free diff --git a/src/util-exception-policy.h b/src/util-exception-policy.h index 64edb279747f..7f94a9f8eda3 100644 --- a/src/util-exception-policy.h +++ b/src/util-exception-policy.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022-2025 Open Information Security Foundation +/* Copyright (C) 2022-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free From 278da4bc6a8ec0327a1a5ef302655d2253cdf721 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2026 11:28:30 +0100 Subject: [PATCH 10/20] npdi: fix null pointer deref in detect keywords Check for the existence of a flow before calling FlowGetStorageById() on it. Ticket: #8308. --- plugins/ndpi/ndpi.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/plugins/ndpi/ndpi.c b/plugins/ndpi/ndpi.c index 263225258a09..b52bd5a988ce 100644 --- a/plugins/ndpi/ndpi.c +++ b/plugins/ndpi/ndpi.c @@ -181,11 +181,21 @@ static void OnThreadInit(ThreadVars *tv, void *_data) static int DetectnDPIProtocolPacketMatch( DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { + SCEnter(); + const Flow *f = p->flow; + if (f == NULL) { + SCLogDebug("packet %" PRIu64 ": no flow", PcapPacketCntGet(p)); + SCReturnInt(0); + } + struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id); - const DetectnDPIProtocolData *data = (const DetectnDPIProtocolData *)ctx; + if (flowctx == NULL) { + SCLogDebug("packet %" PRIu64 ": no flowctx", PcapPacketCntGet(p)); + SCReturnInt(0); + } - SCEnter(); + const DetectnDPIProtocolData *data = (const DetectnDPIProtocolData *)ctx; /* if the sig is PD-only we only match when PD packet flags are set */ /* @@ -201,11 +211,6 @@ static int DetectnDPIProtocolPacketMatch( SCReturnInt(0); } - if (f == NULL) { - SCLogDebug("packet %" PRIu64 ": no flow", PcapPacketCntGet(p)); - SCReturnInt(0); - } - bool r = ndpi_is_proto_equals(flowctx->detected_l7_protocol.proto, data->l7_protocol, false); r = r ^ data->negated; @@ -311,22 +316,27 @@ static void DetectnDPIProtocolFree(DetectEngineCtx *de_ctx, void *ptr) static int DetectnDPIRiskPacketMatch( DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { + SCEnter(); + const Flow *f = p->flow; + if (f == NULL) { + SCLogDebug("packet %" PRIu64 ": no flow", PcapPacketCntGet(p)); + SCReturnInt(0); + } + struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id); - const DetectnDPIRiskData *data = (const DetectnDPIRiskData *)ctx; + if (flowctx == NULL) { + SCLogDebug("packet %" PRIu64 ": no flowctx", PcapPacketCntGet(p)); + SCReturnInt(0); + } - SCEnter(); + const DetectnDPIRiskData *data = (const DetectnDPIRiskData *)ctx; if (!flowctx->detection_completed) { SCLogDebug("packet %" PRIu64 ": ndpi risks not yet detected", PcapPacketCntGet(p)); SCReturnInt(0); } - if (f == NULL) { - SCLogDebug("packet %" PRIu64 ": no flow", PcapPacketCntGet(p)); - SCReturnInt(0); - } - bool r = ((flowctx->ndpi_flow->risk & data->risk_mask) == data->risk_mask); r = r ^ data->negated; From 28ba93e60c3ef9c593d72e58945603d8a715bc92 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Thu, 19 Feb 2026 11:31:48 +0100 Subject: [PATCH 11/20] ndpi: minor optimization Check protocol before doing more expensive work. --- plugins/ndpi/ndpi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/ndpi/ndpi.c b/plugins/ndpi/ndpi.c index b52bd5a988ce..bb35e01b3467 100644 --- a/plugins/ndpi/ndpi.c +++ b/plugins/ndpi/ndpi.c @@ -92,21 +92,21 @@ 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); + /* 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 = ThreadGetStorageById(tv, thread_storage_id); + struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id); 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; - } - if (PacketIsIPv4(p)) { const IPV4Hdr *ip4h = PacketGetIPv4(p); ip_len = IPV4_GET_RAW_IPLEN(ip4h); From 23032ebc65dec0c41b5ef2adf08698bc81210dc9 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 13:17:54 +0100 Subject: [PATCH 12/20] detect/ike: move ike spi keywords to rust Ticket: 8310 --- rust/src/ike/detect.rs | 118 ++++++++++++++++++------ rust/src/ike/ike.rs | 2 +- src/Makefile.am | 2 - src/detect-engine-register.c | 3 +- src/detect-engine-register.h | 2 - src/detect-ike-spi.c | 168 ----------------------------------- src/detect-ike-spi.h | 28 ------ 7 files changed, 92 insertions(+), 231 deletions(-) delete mode 100644 src/detect-ike-spi.c delete mode 100644 src/detect-ike-spi.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 40605decbd05..74677d524d90 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -17,12 +17,18 @@ // Author: Frank Honza +use super::ike::ALPROTO_IKE; use super::ipsec_parser::IkeV2Transform; +use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER}; +use crate::detect::{helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer}; use crate::ike::ike::*; use std::ffi::CStr; -use std::os::raw::c_void; +use std::os::raw::{c_char, c_int, c_void}; use std::ptr; -use suricata_sys::sys::DetectEngineThreadCtx; +use suricata_sys::sys::{ + DetectEngineCtx, DetectEngineThreadCtx, SCDetectBufferSetActiveList, + SCDetectHelperBufferMpmRegister, SCDetectSignatureSetAppProto, Signature, +}; #[no_mangle] pub extern "C" fn SCIkeStateGetExchType(tx: &IKETransaction, exch_type: *mut u8) -> u8 { @@ -45,32 +51,6 @@ pub extern "C" fn SCIkeStateGetExchType(tx: &IKETransaction, exch_type: *mut u8) return 0; } -#[no_mangle] -pub extern "C" fn SCIkeStateGetSpiInitiator( - tx: &IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { - debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); - - unsafe { - *buffer = tx.hdr.spi_initiator.as_ptr(); - *buffer_len = tx.hdr.spi_initiator.len() as u32; - } - return 1; -} - -#[no_mangle] -pub extern "C" fn SCIkeStateGetSpiResponder( - tx: &IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { - debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); - - unsafe { - *buffer = tx.hdr.spi_responder.as_ptr(); - *buffer_len = tx.hdr.spi_responder.len() as u32; - } - return 1; -} - #[no_mangle] pub extern "C" fn SCIkeStateGetNonce( tx: &IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, @@ -235,3 +215,85 @@ pub unsafe extern "C" fn SCIkeStateGetNoncePayloadLength( *value = 0; return 0; } + +unsafe extern "C" fn ike_tx_get_spi_initiator( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, IKETransaction); + *buffer = tx.hdr.spi_initiator.as_ptr(); + *buffer_len = tx.hdr.spi_initiator.len() as u32; + return true; +} + +unsafe extern "C" fn ike_tx_get_spi_responder( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, IKETransaction); + *buffer = tx.hdr.spi_responder.as_ptr(); + *buffer_len = tx.hdr.spi_responder.len() as u32; + return true; +} + +static mut G_IKE_SPI_INITIATOR_BUFFER_ID: c_int = 0; +static mut G_IKE_SPI_RESPONDER_BUFFER_ID: c_int = 0; + +#[no_mangle] +pub unsafe extern "C" fn SCDetectIkeRegister() { + let kw_initiator = SigTableElmtStickyBuffer { + name: String::from("ike.init_spi"), + desc: String::from("sticky buffer to match on the IKE spi initiator"), + url: String::from("/rules/ike-keywords.html#ike-init_spi"), + setup: ike_spi_initiator_setup, + }; + helper_keyword_register_sticky_buffer(&kw_initiator); + G_IKE_SPI_INITIATOR_BUFFER_ID = SCDetectHelperBufferMpmRegister( + b"ike_init_spi\0".as_ptr() as *const libc::c_char, + b"ike init spi\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER, + Some(ike_tx_get_spi_initiator), + ); + + let kw_responder = SigTableElmtStickyBuffer { + name: String::from("ike.resp_spi"), + desc: String::from("sticky buffer to match on the IKE spi responder"), + url: String::from("/rules/ike-keywords.html#ike-resp_spi"), + setup: ike_spi_responder_setup, + }; + helper_keyword_register_sticky_buffer(&kw_responder); + G_IKE_SPI_RESPONDER_BUFFER_ID = SCDetectHelperBufferMpmRegister( + b"ike_resp_spi\0".as_ptr() as *const libc::c_char, + b"ike resp spi\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOCLIENT, + Some(ike_tx_get_spi_responder), + ); +} + +unsafe extern "C" fn ike_spi_initiator_setup( + de_ctx: *mut DetectEngineCtx, s: *mut Signature, _str: *const c_char, +) -> c_int { + if SCDetectBufferSetActiveList(de_ctx, s, G_IKE_SPI_INITIATOR_BUFFER_ID) < 0 { + return -1; + } + + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0 { + return -1; + } + + return 0; +} + +unsafe extern "C" fn ike_spi_responder_setup( + de_ctx: *mut DetectEngineCtx, s: *mut Signature, _str: *const c_char, +) -> c_int { + if SCDetectBufferSetActiveList(de_ctx, s, G_IKE_SPI_RESPONDER_BUFFER_ID) < 0 { + return -1; + } + + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0 { + return -1; + } + + return 0; +} diff --git a/rust/src/ike/ike.rs b/rust/src/ike/ike.rs index 1d574b6b53c2..97d6b5e85dc7 100644 --- a/rust/src/ike/ike.rs +++ b/rust/src/ike/ike.rs @@ -360,7 +360,7 @@ extern "C" fn ike_tx_get_alstate_progress( return 1; } -static mut ALPROTO_IKE: AppProto = ALPROTO_UNKNOWN; +pub(super) static mut ALPROTO_IKE: AppProto = ALPROTO_UNKNOWN; // Parser name as a C style string. const PARSER_NAME: &[u8] = b"ike\0"; diff --git a/src/Makefile.am b/src/Makefile.am index 161061a2c136..1af5c3af5e21 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -233,7 +233,6 @@ noinst_HEADERS = \ detect-ike-key-exchange-payload.h \ detect-ike-nonce-payload-length.h \ detect-ike-nonce-payload.h \ - detect-ike-spi.h \ detect-ike-vendor.h \ detect-ipaddr.h \ detect-ipopts.h \ @@ -818,7 +817,6 @@ libsuricata_c_a_SOURCES = \ detect-ike-key-exchange-payload.c \ detect-ike-nonce-payload-length.c \ detect-ike-nonce-payload.c \ - detect-ike-spi.c \ detect-ike-vendor.c \ detect-ipaddr.c \ detect-ipopts.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 477247642b04..6c4bf063620e 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -232,7 +232,6 @@ #include "detect-modbus.h" #include "detect-dnp3.h" #include "detect-ike-exch-type.h" -#include "detect-ike-spi.h" #include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" #include "detect-ike-key-exchange-payload-length.h" @@ -591,7 +590,6 @@ void SigTableSetup(void) DetectDNP3Register(); DetectIkeExchTypeRegister(); - DetectIkeSpiRegister(); DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); DetectIkeKeyExchangePayloadLengthRegister(); @@ -774,6 +772,7 @@ void SigTableSetup(void) SCDetectSshRegister(); SCDetectQuicRegister(); SCDetectSmbRegister(); + SCDetectIkeRegister(); for (size_t i = 0; i < preregistered_callbacks_nb; i++) { PreregisteredCallbacks[i](); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index c07a26dd97a5..637cbd36b35f 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -282,8 +282,6 @@ enum DetectKeywordId { DETECT_TRANSFORM_LUAXFORM, DETECT_IKE_EXCH_TYPE, - DETECT_IKE_SPI_INITIATOR, - DETECT_IKE_SPI_RESPONDER, DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH, diff --git a/src/detect-ike-spi.c b/src/detect-ike-spi.c deleted file mode 100644 index 778ef10eaa90..000000000000 --- a/src/detect-ike-spi.c +++ /dev/null @@ -1,168 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-buffer.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ike-spi.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-ike.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME_INITIATOR "ike.init_spi" -#define KEYWORD_DOC_INITIATOR "ike-keywords.html#ike-init_spi"; -#define BUFFER_NAME_INITIATOR "ike.init_spi" -#define BUFFER_DESC_INITIATOR "ike init spi" - -#define KEYWORD_NAME_RESPONDER "ike.resp_spi" -#define KEYWORD_DOC_RESPONDER "ike-keywords.html#ike-resp_spi"; -#define BUFFER_NAME_RESPONDER "ike.resp_spi" -#define BUFFER_DESC_RESPONDER "ike resp spi" - -static int g_buffer_initiator_id = 0; -static int g_buffer_responder_id = 0; - -static int DetectSpiInitiatorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (SCDetectBufferSetActiveList(de_ctx, s, g_buffer_initiator_id) < 0) - return -1; - - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static int DetectSpiResponderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (SCDetectBufferSetActiveList(de_ctx, s, g_buffer_responder_id) < 0) - return -1; - - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetInitiatorData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (SCIkeStateGetSpiInitiator(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms); - } - - return buffer; -} - -static InspectionBuffer *GetResponderData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (SCIkeStateGetSpiResponder(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms); - } - - return buffer; -} - -void DetectIkeSpiRegister(void) -{ - // register initiator - sigmatch_table[DETECT_IKE_SPI_INITIATOR].name = KEYWORD_NAME_INITIATOR; - sigmatch_table[DETECT_IKE_SPI_INITIATOR].url = - "/rules/" KEYWORD_DOC_INITIATOR sigmatch_table[DETECT_IKE_SPI_INITIATOR].desc = - "sticky buffer to match on the IKE spi initiator"; - sigmatch_table[DETECT_IKE_SPI_INITIATOR].Setup = DetectSpiInitiatorSetup; - sigmatch_table[DETECT_IKE_SPI_INITIATOR].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME_INITIATOR, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetInitiatorData); - - DetectAppLayerMpmRegister(BUFFER_NAME_INITIATOR, SIG_FLAG_TOSERVER, 1, - PrefilterGenericMpmRegister, GetInitiatorData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_INITIATOR, BUFFER_DESC_INITIATOR); - - g_buffer_initiator_id = DetectBufferTypeGetByName(BUFFER_NAME_INITIATOR); - SCLogDebug("registering " BUFFER_NAME_INITIATOR " rule option"); - - // register responder - sigmatch_table[DETECT_IKE_SPI_RESPONDER].name = KEYWORD_NAME_RESPONDER; - sigmatch_table[DETECT_IKE_SPI_RESPONDER].url = - "/rules/" KEYWORD_DOC_RESPONDER sigmatch_table[DETECT_IKE_SPI_RESPONDER].desc = - "sticky buffer to match on the IKE spi responder"; - sigmatch_table[DETECT_IKE_SPI_RESPONDER].Setup = DetectSpiResponderSetup; - sigmatch_table[DETECT_IKE_SPI_RESPONDER].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME_RESPONDER, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetResponderData); - - DetectAppLayerMpmRegister(BUFFER_NAME_RESPONDER, SIG_FLAG_TOCLIENT, 1, - PrefilterGenericMpmRegister, GetResponderData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_RESPONDER, BUFFER_DESC_RESPONDER); - - g_buffer_responder_id = DetectBufferTypeGetByName(BUFFER_NAME_RESPONDER); - SCLogDebug("registering " BUFFER_NAME_RESPONDER " rule option"); -} diff --git a/src/detect-ike-spi.h b/src/detect-ike-spi.h deleted file mode 100644 index 11baf8d62f44..000000000000 --- a/src/detect-ike-spi.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_SPI_H -#define SURICATA_DETECT_IKE_SPI_H - -void DetectIkeSpiRegister(void); - -#endif /* SURICATA_DETECT_IKE_SPI_H */ From 841fe44f34851cd25ffaea7045bc6c4715164cd6 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 13:43:14 +0100 Subject: [PATCH 13/20] detect/ike: move ike.exchtype keyword to rust Ticket: 8310 --- rust/src/ike/detect.rs | 103 ++++++++++++++++++++------ src/Makefile.am | 2 - src/detect-engine-register.c | 2 - src/detect-engine-register.h | 1 - src/detect-ike-exch-type.c | 140 ----------------------------------- src/detect-ike-exch-type.h | 29 -------- 6 files changed, 80 insertions(+), 197 deletions(-) delete mode 100644 src/detect-ike-exch-type.c delete mode 100644 src/detect-ike-exch-type.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 74677d524d90..15f5d7e32026 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -20,37 +20,20 @@ use super::ike::ALPROTO_IKE; use super::ipsec_parser::IkeV2Transform; use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER}; -use crate::detect::{helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer}; +use crate::detect::uint::{detect_match_uint, DetectUintData, SCDetectU8Free, SCDetectU8Parse}; +use crate::detect::{ + helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT8, +}; use crate::ike::ike::*; use std::ffi::CStr; use std::os::raw::{c_char, c_int, c_void}; use std::ptr; use suricata_sys::sys::{ DetectEngineCtx, DetectEngineThreadCtx, SCDetectBufferSetActiveList, - SCDetectHelperBufferMpmRegister, SCDetectSignatureSetAppProto, Signature, + SCDetectHelperBufferMpmRegister, SCDetectHelperBufferRegister, SCDetectHelperKeywordRegister, + SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, SCSigTableAppLiteElmt, Signature, }; -#[no_mangle] -pub extern "C" fn SCIkeStateGetExchType(tx: &IKETransaction, exch_type: *mut u8) -> u8 { - debug_validate_bug_on!(exch_type.is_null()); - - if tx.ike_version == 1 { - if let Some(r) = tx.hdr.ikev1_header.exchange_type { - unsafe { - *exch_type = r; - } - return 1; - } - } else if tx.ike_version == 2 { - unsafe { - *exch_type = tx.hdr.ikev2_header.exch_type.0; - } - return 1; - } - - return 0; -} - #[no_mangle] pub extern "C" fn SCIkeStateGetNonce( tx: &IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, @@ -234,11 +217,85 @@ unsafe extern "C" fn ike_tx_get_spi_responder( return true; } +unsafe extern "C" fn ike_detect_exchtype_setup( + de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, +) -> c_int { + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0 { + return -1; + } + let ctx = SCDetectU8Parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SCSigMatchAppendSMToList( + de, + s, + G_IKE_EXCHTYPE_KW_ID, + ctx as *mut suricata_sys::sys::SigMatchCtx, + G_IKE_EXCHTYPE_BUFFER_ID, + ) + .is_null() + { + ike_detect_exchtype_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_exchtype_match( + _de: *mut DetectEngineThreadCtx, _f: *mut crate::flow::Flow, _flags: u8, _state: *mut c_void, + tx: *mut c_void, _sig: *const Signature, ctx: *const suricata_sys::sys::SigMatchCtx, +) -> c_int { + let tx = cast_pointer!(tx, IKETransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + let mut exch_type: u8 = 0; + let found = if tx.ike_version == 1 { + if let Some(r) = tx.hdr.ikev1_header.exchange_type { + exch_type = r; + true + } else { + false + } + } else if tx.ike_version == 2 { + exch_type = tx.hdr.ikev2_header.exch_type.0; + true + } else { + false + }; + if found && detect_match_uint(ctx, exch_type) { + return 1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_exchtype_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectUintData); + SCDetectU8Free(ctx); +} + static mut G_IKE_SPI_INITIATOR_BUFFER_ID: c_int = 0; static mut G_IKE_SPI_RESPONDER_BUFFER_ID: c_int = 0; +static mut G_IKE_EXCHTYPE_KW_ID: u16 = 0; +static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0; #[no_mangle] pub unsafe extern "C" fn SCDetectIkeRegister() { + // Inline registration for ike.exchtype keyword + let kw = SCSigTableAppLiteElmt { + name: b"ike.exchtype\0".as_ptr() as *const libc::c_char, + desc: b"match IKE exchange type\0".as_ptr() as *const libc::c_char, + url: b"/rules/ike-keywords.html#ike-exchtype\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(ike_detect_exchtype_match), + Setup: Some(ike_detect_exchtype_setup), + Free: Some(ike_detect_exchtype_free), + flags: SIGMATCH_INFO_UINT8, + }; + G_IKE_EXCHTYPE_KW_ID = SCDetectHelperKeywordRegister(&kw); + G_IKE_EXCHTYPE_BUFFER_ID = SCDetectHelperBufferRegister( + b"ike.exchtype\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER | STREAM_TOCLIENT, + ); let kw_initiator = SigTableElmtStickyBuffer { name: String::from("ike.init_spi"), desc: String::from("sticky buffer to match on the IKE spi initiator"), diff --git a/src/Makefile.am b/src/Makefile.am index 1af5c3af5e21..f0c911b5381c 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,7 +228,6 @@ noinst_HEADERS = \ detect-icode.h \ detect-id.h \ detect-ike-chosen-sa.h \ - detect-ike-exch-type.h \ detect-ike-key-exchange-payload-length.h \ detect-ike-key-exchange-payload.h \ detect-ike-nonce-payload-length.h \ @@ -812,7 +811,6 @@ libsuricata_c_a_SOURCES = \ detect-icode.c \ detect-id.c \ detect-ike-chosen-sa.c \ - detect-ike-exch-type.c \ detect-ike-key-exchange-payload-length.c \ detect-ike-key-exchange-payload.c \ detect-ike-nonce-payload-length.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 6c4bf063620e..6e4c618dc1a3 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -231,7 +231,6 @@ #include "detect-ssl-state.h" #include "detect-modbus.h" #include "detect-dnp3.h" -#include "detect-ike-exch-type.h" #include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" #include "detect-ike-key-exchange-payload-length.h" @@ -589,7 +588,6 @@ void SigTableSetup(void) DetectModbusRegister(); DetectDNP3Register(); - DetectIkeExchTypeRegister(); DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); DetectIkeKeyExchangePayloadLengthRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 637cbd36b35f..7f2169c6c6f0 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -281,7 +281,6 @@ enum DetectKeywordId { DETECT_TRANSFORM_PCREXFORM, DETECT_TRANSFORM_LUAXFORM, - DETECT_IKE_EXCH_TYPE, DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH, diff --git a/src/detect-ike-exch-type.c b/src/detect-ike-exch-type.c deleted file mode 100644 index 46fb1e1ac049..000000000000 --- a/src/detect-ike-exch-type.c +++ /dev/null @@ -1,140 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-exch-type.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "detect-engine-uint.h" - -#include "rust-bindings.h" - -/** - * [ike.exchtype]:[<|>|<=|>=]; - */ - -static int DetectIkeExchTypeSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeExchTypeFree(DetectEngineCtx *, void *); -static int g_ike_exch_type_buffer_id = 0; - -static int DetectIkeExchTypeMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); - -/** - * \brief Registration function for ike.exchtype keyword. - */ -void DetectIkeExchTypeRegister(void) -{ - sigmatch_table[DETECT_IKE_EXCH_TYPE].name = "ike.exchtype"; - sigmatch_table[DETECT_IKE_EXCH_TYPE].desc = "match IKE exchange type"; - sigmatch_table[DETECT_IKE_EXCH_TYPE].url = "/rules/ike-keywords.html#ike-exchtype"; - sigmatch_table[DETECT_IKE_EXCH_TYPE].Match = NULL; - sigmatch_table[DETECT_IKE_EXCH_TYPE].AppLayerTxMatch = DetectIkeExchTypeMatch; - sigmatch_table[DETECT_IKE_EXCH_TYPE].Setup = DetectIkeExchTypeSetup; - sigmatch_table[DETECT_IKE_EXCH_TYPE].Free = DetectIkeExchTypeFree; - sigmatch_table[DETECT_IKE_EXCH_TYPE].flags = SIGMATCH_INFO_UINT8; - - DetectAppLayerInspectEngineRegister("ike.exchtype", ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister("ike.exchtype", ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectGenericList, NULL); - - g_ike_exch_type_buffer_id = DetectBufferTypeGetByName("ike.exchtype"); -} - -/** - * \internal - * \brief Function to match exchange type of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU8Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeExchTypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint8_t exch_type; - if (!SCIkeStateGetExchType(txv, &exch_type)) - SCReturnInt(0); - - const DetectU8Data *du8 = (const DetectU8Data *)ctx; - SCReturnInt(DetectU8Match(exch_type, du8)); -} - -/** - * \brief Function to add the parsed IKE exchange type field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeExchTypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectU8Data *ike_exch_type = DetectU8Parse(rawstr); - if (ike_exch_type == NULL) - return -1; - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_IKE_EXCH_TYPE, (SigMatchCtx *)ike_exch_type, - g_ike_exch_type_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeExchTypeFree(de_ctx, ike_exch_type); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU8Data. - * - * \param de_ptr Pointer to DetectU8Data. - */ -static void DetectIkeExchTypeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCDetectU8Free(ptr); -} diff --git a/src/detect-ike-exch-type.h b/src/detect-ike-exch-type.h deleted file mode 100644 index ca2c8246804c..000000000000 --- a/src/detect-ike-exch-type.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_EXCH_TYPE_H -#define SURICATA_DETECT_IKE_EXCH_TYPE_H - -void DetectIkeExchTypeRegister(void); - -#endif /* SURICATA_DETECT_IKE_EXCH_TYPE_H */ From e85bf5be4ddeecfb01f0c152ebb6d6f659efff65 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 13:51:35 +0100 Subject: [PATCH 14/20] detect/ike: move ike.key_exchange_payload_length keyword to rust Ticket: 8310 --- rust/src/ike/detect.rs | 92 +++++++++--- src/Makefile.am | 2 - src/detect-engine-register.c | 2 - src/detect-engine-register.h | 1 - src/detect-ike-key-exchange-payload-length.c | 146 ------------------- src/detect-ike-key-exchange-payload-length.h | 28 ---- 6 files changed, 71 insertions(+), 200 deletions(-) delete mode 100644 src/detect-ike-key-exchange-payload-length.c delete mode 100644 src/detect-ike-key-exchange-payload-length.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 15f5d7e32026..187f4d00dd0e 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -20,9 +20,13 @@ use super::ike::ALPROTO_IKE; use super::ipsec_parser::IkeV2Transform; use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER}; -use crate::detect::uint::{detect_match_uint, DetectUintData, SCDetectU8Free, SCDetectU8Parse}; +use crate::detect::uint::{ + detect_match_uint, DetectUintData, SCDetectU32Free, SCDetectU32Parse, SCDetectU8Free, + SCDetectU8Parse, +}; use crate::detect::{ - helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT8, + helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT32, + SIGMATCH_INFO_UINT8, }; use crate::ike::ike::*; use std::ffi::CStr; @@ -31,7 +35,8 @@ use std::ptr; use suricata_sys::sys::{ DetectEngineCtx, DetectEngineThreadCtx, SCDetectBufferSetActiveList, SCDetectHelperBufferMpmRegister, SCDetectHelperBufferRegister, SCDetectHelperKeywordRegister, - SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, SCSigTableAppLiteElmt, Signature, + SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, SCSigTableAppLiteElmt, SigMatchCtx, + Signature, }; #[no_mangle] @@ -169,21 +174,6 @@ pub extern "C" fn SCIkeStateGetSaAttribute( return ret_code; } -#[no_mangle] -pub unsafe extern "C" fn SCIkeStateGetKeyExchangePayloadLength( - tx: &IKETransaction, value: *mut u32, -) -> u8 { - debug_validate_bug_on!(value.is_null()); - - if tx.ike_version == 1 && !tx.hdr.ikev1_header.key_exchange.is_empty() { - *value = tx.hdr.ikev1_header.key_exchange.len() as u32; - return 1; - } - - *value = 0; - return 0; -} - #[no_mangle] pub unsafe extern "C" fn SCIkeStateGetNoncePayloadLength( tx: &IKETransaction, value: *mut u32, @@ -231,7 +221,7 @@ unsafe extern "C" fn ike_detect_exchtype_setup( de, s, G_IKE_EXCHTYPE_KW_ID, - ctx as *mut suricata_sys::sys::SigMatchCtx, + ctx as *mut SigMatchCtx, G_IKE_EXCHTYPE_BUFFER_ID, ) .is_null() @@ -244,7 +234,7 @@ unsafe extern "C" fn ike_detect_exchtype_setup( unsafe extern "C" fn ike_detect_exchtype_match( _de: *mut DetectEngineThreadCtx, _f: *mut crate::flow::Flow, _flags: u8, _state: *mut c_void, - tx: *mut c_void, _sig: *const Signature, ctx: *const suricata_sys::sys::SigMatchCtx, + tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx, ) -> c_int { let tx = cast_pointer!(tx, IKETransaction); let ctx = cast_pointer!(ctx, DetectUintData); @@ -273,14 +263,58 @@ unsafe extern "C" fn ike_detect_exchtype_free(_de: *mut DetectEngineCtx, ctx: *m SCDetectU8Free(ctx); } +unsafe extern "C" fn ike_detect_payload_len_setup( + de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, +) -> c_int { + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0 { + return -1; + } + let ctx = SCDetectU32Parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SCSigMatchAppendSMToList( + de, + s, + G_IKE_PAYLOAD_LEN_KW_ID, + ctx as *mut SigMatchCtx, + G_IKE_PAYLOAD_LEN_BUFFER_ID, + ) + .is_null() + { + ike_detect_payload_len_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_payload_len_match( + _de: *mut DetectEngineThreadCtx, _f: *mut crate::flow::Flow, _flags: u8, _state: *mut c_void, + tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx, +) -> c_int { + let tx = cast_pointer!(tx, IKETransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + if tx.ike_version == 1 && !tx.hdr.ikev1_header.key_exchange.is_empty() + && detect_match_uint(ctx, tx.hdr.ikev1_header.key_exchange.len() as u32) { + return 1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_payload_len_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectUintData); + SCDetectU32Free(ctx); +} + static mut G_IKE_SPI_INITIATOR_BUFFER_ID: c_int = 0; static mut G_IKE_SPI_RESPONDER_BUFFER_ID: c_int = 0; static mut G_IKE_EXCHTYPE_KW_ID: u16 = 0; static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0; +static mut G_IKE_PAYLOAD_LEN_KW_ID: u16 = 0; +static mut G_IKE_PAYLOAD_LEN_BUFFER_ID: c_int = 0; #[no_mangle] pub unsafe extern "C" fn SCDetectIkeRegister() { - // Inline registration for ike.exchtype keyword let kw = SCSigTableAppLiteElmt { name: b"ike.exchtype\0".as_ptr() as *const libc::c_char, desc: b"match IKE exchange type\0".as_ptr() as *const libc::c_char, @@ -296,6 +330,22 @@ pub unsafe extern "C" fn SCDetectIkeRegister() { ALPROTO_IKE, STREAM_TOSERVER | STREAM_TOCLIENT, ); + let kw = SCSigTableAppLiteElmt { + name: b"ike.key_exchange_payload_length\0".as_ptr() as *const libc::c_char, + desc: b"match IKE key exchange payload length\0".as_ptr() as *const libc::c_char, + url: b"/rules/ike-keywords.html#ike-key-exchange-payload-length\0".as_ptr() + as *const libc::c_char, + AppLayerTxMatch: Some(ike_detect_payload_len_match), + Setup: Some(ike_detect_payload_len_setup), + Free: Some(ike_detect_payload_len_free), + flags: SIGMATCH_INFO_UINT32, + }; + G_IKE_PAYLOAD_LEN_KW_ID = SCDetectHelperKeywordRegister(&kw); + G_IKE_PAYLOAD_LEN_BUFFER_ID = SCDetectHelperBufferRegister( + b"ike.key_exchange_payload_length\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER | STREAM_TOCLIENT, + ); let kw_initiator = SigTableElmtStickyBuffer { name: String::from("ike.init_spi"), desc: String::from("sticky buffer to match on the IKE spi initiator"), diff --git a/src/Makefile.am b/src/Makefile.am index f0c911b5381c..527ba0cf0b33 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,7 +228,6 @@ noinst_HEADERS = \ detect-icode.h \ detect-id.h \ detect-ike-chosen-sa.h \ - detect-ike-key-exchange-payload-length.h \ detect-ike-key-exchange-payload.h \ detect-ike-nonce-payload-length.h \ detect-ike-nonce-payload.h \ @@ -811,7 +810,6 @@ libsuricata_c_a_SOURCES = \ detect-icode.c \ detect-id.c \ detect-ike-chosen-sa.c \ - detect-ike-key-exchange-payload-length.c \ detect-ike-key-exchange-payload.c \ detect-ike-nonce-payload-length.c \ detect-ike-nonce-payload.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 6e4c618dc1a3..dbbeda3a039e 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -233,7 +233,6 @@ #include "detect-dnp3.h" #include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" -#include "detect-ike-key-exchange-payload-length.h" #include "detect-ike-nonce-payload-length.h" #include "detect-ike-nonce-payload.h" #include "detect-ike-key-exchange-payload.h" @@ -590,7 +589,6 @@ void SigTableSetup(void) DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); - DetectIkeKeyExchangePayloadLengthRegister(); DetectIkeNoncePayloadLengthRegister(); DetectIkeNonceRegister(); DetectIkeKeyExchangeRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 7f2169c6c6f0..00030c83eae0 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -283,7 +283,6 @@ enum DetectKeywordId { DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, - DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH, DETECT_IKE_NONCE_PAYLOAD_LENGTH, DETECT_IKE_NONCE, DETECT_IKE_KEY_EXCHANGE, diff --git a/src/detect-ike-key-exchange-payload-length.c b/src/detect-ike-key-exchange-payload-length.c deleted file mode 100644 index 2264765db514..000000000000 --- a/src/detect-ike-key-exchange-payload-length.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-key-exchange-payload-length.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "detect-engine-uint.h" - -#include "rust-bindings.h" - -/** - * [ike.key_exchange_payload_length]:[=|<|>|<=|>=]; - */ -static int DetectIkeKeyExchangePayloadLengthSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeKeyExchangePayloadLengthFree(DetectEngineCtx *, void *); -static int g_ike_key_exch_payload_length_buffer_id = 0; - -static int DetectIkeKeyExchangePayloadLengthMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, - void *, const Signature *, const SigMatchCtx *); - -/** - * \brief Registration function for ike.key_exchange_payload_length keyword. - */ -void DetectIkeKeyExchangePayloadLengthRegister(void) -{ - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].name = "ike.key_exchange_payload_length"; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].desc = - "match IKE key exchange payload length"; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].url = - "/rules/ike-keywords.html#ike-key-exchange-payload-length"; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].AppLayerTxMatch = - DetectIkeKeyExchangePayloadLengthMatch; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].Setup = - DetectIkeKeyExchangePayloadLengthSetup; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].Free = - DetectIkeKeyExchangePayloadLengthFree; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH].flags = SIGMATCH_INFO_UINT32; - - DetectAppLayerInspectEngineRegister("ike.key_exchange_payload_length", ALPROTO_IKE, - SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister("ike.key_exchange_payload_length", ALPROTO_IKE, - SIG_FLAG_TOCLIENT, 1, DetectEngineInspectGenericList, NULL); - - g_ike_key_exch_payload_length_buffer_id = - DetectBufferTypeGetByName("ike.key_exchange_payload_length"); -} - -/** - * \internal - * \brief Function to match key exchange payload length of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeKeyExchangePayloadLengthMatch(DetectEngineThreadCtx *det_ctx, Flow *f, - uint8_t flags, void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint32_t length; - if (!SCIkeStateGetKeyExchangePayloadLength(txv, &length)) - SCReturnInt(0); - const DetectU32Data *du32 = (const DetectU32Data *)ctx; - return DetectU32Match(length, du32); -} - -/** - * \brief Function to add the parsed IKE key exchange payload length query into the current - * signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeKeyExchangePayloadLengthSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectU32Data *key_exchange_payload_length = DetectU32Parse(rawstr); - if (key_exchange_payload_length == NULL) - return -1; - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH, - (SigMatchCtx *)key_exchange_payload_length, - g_ike_key_exch_payload_length_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeKeyExchangePayloadLengthFree(de_ctx, key_exchange_payload_length); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -static void DetectIkeKeyExchangePayloadLengthFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCDetectU32Free(ptr); -} diff --git a/src/detect-ike-key-exchange-payload-length.h b/src/detect-ike-key-exchange-payload-length.h deleted file mode 100644 index 46671586338a..000000000000 --- a/src/detect-ike-key-exchange-payload-length.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH_H -#define SURICATA_DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH_H - -void DetectIkeKeyExchangePayloadLengthRegister(void); - -#endif /* SURICATA_DETECT_IKE_KEY_EXCHANGE_PAYLOAD_LENGTH_H */ From f23169c924b6a00b68e0e7ee588953199bc8f857 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 13:56:49 +0100 Subject: [PATCH 15/20] detect/ike: move ike.nonce_payload_length keyword to rust Ticket: 8310 --- rust/src/ike/detect.rs | 79 ++++++++++++--- src/Makefile.am | 2 - src/detect-engine-register.c | 2 - src/detect-engine-register.h | 1 - src/detect-ike-nonce-payload-length.c | 141 -------------------------- src/detect-ike-nonce-payload-length.h | 28 ----- 6 files changed, 64 insertions(+), 189 deletions(-) delete mode 100644 src/detect-ike-nonce-payload-length.c delete mode 100644 src/detect-ike-nonce-payload-length.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 187f4d00dd0e..60b475aec3b9 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -174,21 +174,6 @@ pub extern "C" fn SCIkeStateGetSaAttribute( return ret_code; } -#[no_mangle] -pub unsafe extern "C" fn SCIkeStateGetNoncePayloadLength( - tx: &IKETransaction, value: *mut u32, -) -> u8 { - debug_validate_bug_on!(value.is_null()); - - if tx.ike_version == 1 && !tx.hdr.ikev1_header.nonce.is_empty() { - *value = tx.hdr.ikev1_header.nonce.len() as u32; - return 1; - } - - *value = 0; - return 0; -} - unsafe extern "C" fn ike_tx_get_spi_initiator( tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, ) -> bool { @@ -263,6 +248,54 @@ unsafe extern "C" fn ike_detect_exchtype_free(_de: *mut DetectEngineCtx, ctx: *m SCDetectU8Free(ctx); } +static mut G_IKE_NONCE_PAYLOAD_LENGTH_KW_ID: u16 = 0; +static mut G_IKE_NONCE_PAYLOAD_LENGTH_BUFFER_ID: c_int = 0; + +unsafe extern "C" fn ike_detect_nonce_payload_length_setup( + de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, +) -> c_int { + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0 { + return -1; + } + let ctx = SCDetectU32Parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SCSigMatchAppendSMToList( + de, + s, + G_IKE_NONCE_PAYLOAD_LENGTH_KW_ID, + ctx as *mut SigMatchCtx, + G_IKE_NONCE_PAYLOAD_LENGTH_BUFFER_ID, + ) + .is_null() + { + ike_detect_nonce_payload_length_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_nonce_payload_length_match( + _de: *mut DetectEngineThreadCtx, _f: *mut crate::flow::Flow, _flags: u8, _state: *mut c_void, + tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx, +) -> c_int { + let tx = cast_pointer!(tx, IKETransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + if tx.ike_version == 1 && !tx.hdr.ikev1_header.nonce.is_empty() + && detect_match_uint(ctx, tx.hdr.ikev1_header.nonce.len() as u32) { + return 1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_nonce_payload_length_free( + _de: *mut DetectEngineCtx, ctx: *mut c_void, +) { + let ctx = cast_pointer!(ctx, DetectUintData); + SCDetectU32Free(ctx); +} + unsafe extern "C" fn ike_detect_payload_len_setup( de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, ) -> c_int { @@ -315,6 +348,22 @@ static mut G_IKE_PAYLOAD_LEN_BUFFER_ID: c_int = 0; #[no_mangle] pub unsafe extern "C" fn SCDetectIkeRegister() { + // Register ike.nonce_payload_length keyword + let kw = SCSigTableAppLiteElmt { + name: b"ike.nonce_payload_length\0".as_ptr() as *const libc::c_char, + desc: b"match IKE nonce payload length\0".as_ptr() as *const libc::c_char, + url: b"/rules/ike-keywords.html#ike-nonce-payload-length\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(ike_detect_nonce_payload_length_match), + Setup: Some(ike_detect_nonce_payload_length_setup), + Free: Some(ike_detect_nonce_payload_length_free), + flags: SIGMATCH_INFO_UINT32, + }; + G_IKE_NONCE_PAYLOAD_LENGTH_KW_ID = SCDetectHelperKeywordRegister(&kw); + G_IKE_NONCE_PAYLOAD_LENGTH_BUFFER_ID = SCDetectHelperBufferRegister( + b"ike.nonce_payload_length\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER | STREAM_TOCLIENT, + ); let kw = SCSigTableAppLiteElmt { name: b"ike.exchtype\0".as_ptr() as *const libc::c_char, desc: b"match IKE exchange type\0".as_ptr() as *const libc::c_char, diff --git a/src/Makefile.am b/src/Makefile.am index 527ba0cf0b33..b9adc9ccebd4 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -229,7 +229,6 @@ noinst_HEADERS = \ detect-id.h \ detect-ike-chosen-sa.h \ detect-ike-key-exchange-payload.h \ - detect-ike-nonce-payload-length.h \ detect-ike-nonce-payload.h \ detect-ike-vendor.h \ detect-ipaddr.h \ @@ -811,7 +810,6 @@ libsuricata_c_a_SOURCES = \ detect-id.c \ detect-ike-chosen-sa.c \ detect-ike-key-exchange-payload.c \ - detect-ike-nonce-payload-length.c \ detect-ike-nonce-payload.c \ detect-ike-vendor.c \ detect-ipaddr.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index dbbeda3a039e..03195e696057 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -233,7 +233,6 @@ #include "detect-dnp3.h" #include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" -#include "detect-ike-nonce-payload-length.h" #include "detect-ike-nonce-payload.h" #include "detect-ike-key-exchange-payload.h" #include "detect-vlan.h" @@ -589,7 +588,6 @@ void SigTableSetup(void) DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); - DetectIkeNoncePayloadLengthRegister(); DetectIkeNonceRegister(); DetectIkeKeyExchangeRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 00030c83eae0..9f23dc94a87d 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -283,7 +283,6 @@ enum DetectKeywordId { DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, - DETECT_IKE_NONCE_PAYLOAD_LENGTH, DETECT_IKE_NONCE, DETECT_IKE_KEY_EXCHANGE, diff --git a/src/detect-ike-nonce-payload-length.c b/src/detect-ike-nonce-payload-length.c deleted file mode 100644 index df9758607a19..000000000000 --- a/src/detect-ike-nonce-payload-length.c +++ /dev/null @@ -1,141 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-nonce-payload-length.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "detect-engine-uint.h" - -#include "rust-bindings.h" - -/** - * [ike.nonce_payload_length]:[=|<|>|<=|>=]; - */ -static int DetectIkeNoncePayloadLengthSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeNoncePayloadLengthFree(DetectEngineCtx *, void *); -static int g_ike_nonce_payload_length_buffer_id = 0; - -static int DetectIkeNoncePayloadLengthMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, - void *, const Signature *, const SigMatchCtx *); - -/** - * \brief Registration function for ike.nonce_payload_length keyword. - */ -void DetectIkeNoncePayloadLengthRegister(void) -{ - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].name = "ike.nonce_payload_length"; - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].desc = "match IKE nonce payload length"; - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].url = - "/rules/ike-keywords.html#ike-nonce-payload-length"; - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].AppLayerTxMatch = - DetectIkeNoncePayloadLengthMatch; - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].Setup = DetectIkeNoncePayloadLengthSetup; - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].Free = DetectIkeNoncePayloadLengthFree; - sigmatch_table[DETECT_IKE_NONCE_PAYLOAD_LENGTH].flags = SIGMATCH_INFO_UINT32; - - DetectAppLayerInspectEngineRegister("ike.nonce_payload_length", ALPROTO_IKE, SIG_FLAG_TOSERVER, - 1, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister("ike.nonce_payload_length", ALPROTO_IKE, SIG_FLAG_TOCLIENT, - 1, DetectEngineInspectGenericList, NULL); - - g_ike_nonce_payload_length_buffer_id = DetectBufferTypeGetByName("ike.nonce_payload_length"); -} - -/** - * \internal - * \brief Function to match nonce length of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectU32Data. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeNoncePayloadLengthMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - uint32_t length; - if (!SCIkeStateGetNoncePayloadLength(txv, &length)) - SCReturnInt(0); - const DetectU32Data *du32 = (const DetectU32Data *)ctx; - return DetectU32Match(length, du32); -} - -/** - * \brief Function to add the parsed IKE nonce length field into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeNoncePayloadLengthSetup( - DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectU32Data *nonce_payload_length = DetectU32Parse(rawstr); - if (nonce_payload_length == NULL) - return -1; - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_IKE_NONCE_PAYLOAD_LENGTH, - (SigMatchCtx *)nonce_payload_length, - g_ike_nonce_payload_length_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeNoncePayloadLengthFree(de_ctx, nonce_payload_length); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectU32Data. - * - * \param de_ptr Pointer to DetectU32Data. - */ -static void DetectIkeNoncePayloadLengthFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCDetectU32Free(ptr); -} diff --git a/src/detect-ike-nonce-payload-length.h b/src/detect-ike-nonce-payload-length.h deleted file mode 100644 index dd11cc1388ed..000000000000 --- a/src/detect-ike-nonce-payload-length.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_NONCE_PAYLOAD_LENGTH_H -#define SURICATA_DETECT_IKE_NONCE_PAYLOAD_LENGTH_H - -void DetectIkeNoncePayloadLengthRegister(void); - -#endif /* SURICATA_DETECT_IKE_NONCE_PAYLOAD_LENGTH_H */ From d1213e44407e2e44a58ab65b1be5d9d9cc399af0 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 14:09:41 +0100 Subject: [PATCH 16/20] detect/ike: move ike.key_exchange_payload keyword to rust Ticket: 8310 --- rust/src/ike/detect.rs | 55 ++++++++---- src/Makefile.am | 2 - src/detect-engine-register.c | 2 - src/detect-engine-register.h | 1 - src/detect-ike-key-exchange-payload.c | 118 -------------------------- src/detect-ike-key-exchange-payload.h | 28 ------ 6 files changed, 38 insertions(+), 168 deletions(-) delete mode 100644 src/detect-ike-key-exchange-payload.c delete mode 100644 src/detect-ike-key-exchange-payload.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 60b475aec3b9..678890c68ade 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -62,27 +62,20 @@ pub extern "C" fn SCIkeStateGetNonce( return 0; } -#[no_mangle] -pub extern "C" fn SCIkeStateGetKeyExchange( - tx: &IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { - debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); - +unsafe extern "C" fn ike_tx_get_key_exchange( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, IKETransaction); if tx.ike_version == 1 && !tx.hdr.ikev1_header.key_exchange.is_empty() { let p = &tx.hdr.ikev1_header.key_exchange; - unsafe { - *buffer = p.as_ptr(); - *buffer_len = p.len() as u32; - } - return 1; - } - - unsafe { - *buffer = ptr::null(); - *buffer_len = 0; + *buffer = p.as_ptr(); + *buffer_len = p.len() as u32; + return true; } - return 0; + *buffer = ptr::null(); + *buffer_len = 0; + return false; } #[no_mangle] @@ -341,6 +334,7 @@ unsafe extern "C" fn ike_detect_payload_len_free(_de: *mut DetectEngineCtx, ctx: static mut G_IKE_SPI_INITIATOR_BUFFER_ID: c_int = 0; static mut G_IKE_SPI_RESPONDER_BUFFER_ID: c_int = 0; +static mut G_IKE_KEY_EXCHANGE_BUFFER_ID: c_int = 0; static mut G_IKE_EXCHTYPE_KW_ID: u16 = 0; static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0; static mut G_IKE_PAYLOAD_LEN_KW_ID: u16 = 0; @@ -424,6 +418,21 @@ pub unsafe extern "C" fn SCDetectIkeRegister() { STREAM_TOCLIENT, Some(ike_tx_get_spi_responder), ); + + let kw = SigTableElmtStickyBuffer { + name: String::from("ike.key_exchange_payload"), + desc: String::from("sticky buffer to match on the IKE key_exchange_payload"), + url: String::from("/rules/ike-keywords.html#ike-key_exchange_payload"), + setup: ike_key_exchange_setup, + }; + helper_keyword_register_sticky_buffer(&kw); + G_IKE_KEY_EXCHANGE_BUFFER_ID = SCDetectHelperBufferMpmRegister( + b"ike.key_exchange_payload\0".as_ptr() as *const libc::c_char, + b"ike key_exchange payload\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER | STREAM_TOCLIENT, + Some(ike_tx_get_key_exchange), + ); } unsafe extern "C" fn ike_spi_initiator_setup( @@ -453,3 +462,15 @@ unsafe extern "C" fn ike_spi_responder_setup( return 0; } + +unsafe extern "C" fn ike_key_exchange_setup( + de_ctx: *mut DetectEngineCtx, s: *mut Signature, _str: *const c_char, +) -> c_int { + if SCDetectBufferSetActiveList(de_ctx, s, G_IKE_KEY_EXCHANGE_BUFFER_ID) < 0 { + return -1; + } + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0 { + return -1; + } + return 0; +} diff --git a/src/Makefile.am b/src/Makefile.am index b9adc9ccebd4..360d88a2d895 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,7 +228,6 @@ noinst_HEADERS = \ detect-icode.h \ detect-id.h \ detect-ike-chosen-sa.h \ - detect-ike-key-exchange-payload.h \ detect-ike-nonce-payload.h \ detect-ike-vendor.h \ detect-ipaddr.h \ @@ -809,7 +808,6 @@ libsuricata_c_a_SOURCES = \ detect-icode.c \ detect-id.c \ detect-ike-chosen-sa.c \ - detect-ike-key-exchange-payload.c \ detect-ike-nonce-payload.c \ detect-ike-vendor.c \ detect-ipaddr.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 03195e696057..424ed697dda9 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -234,7 +234,6 @@ #include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" #include "detect-ike-nonce-payload.h" -#include "detect-ike-key-exchange-payload.h" #include "detect-vlan.h" #include "detect-email.h" @@ -589,7 +588,6 @@ void SigTableSetup(void) DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); DetectIkeNonceRegister(); - DetectIkeKeyExchangeRegister(); DetectTlsSniRegister(); DetectTlsIssuerRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 9f23dc94a87d..8aaf77646fea 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -284,7 +284,6 @@ enum DetectKeywordId { DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, DETECT_IKE_NONCE, - DETECT_IKE_KEY_EXCHANGE, DETECT_JA4_HASH, diff --git a/src/detect-ike-key-exchange-payload.c b/src/detect-ike-key-exchange-payload.c deleted file mode 100644 index a4745ce60dc1..000000000000 --- a/src/detect-ike-key-exchange-payload.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-buffer.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ike-key-exchange-payload.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-ike.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME_KEY_EXCHANGE "ike.key_exchange_payload" -#define KEYWORD_DOC_KEY_EXCHANGE "ike-keywords.html#ike-key_exchange_payload"; -#define BUFFER_NAME_KEY_EXCHANGE "ike.key_exchange_payload" -#define BUFFER_DESC_KEY_EXCHANGE "ike key_exchange payload" - -static int g_buffer_key_exchange_id = 0; - -static int DetectKeyExchangeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (SCDetectBufferSetActiveList(de_ctx, s, g_buffer_key_exchange_id) < 0) - return -1; - - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetKeyExchangeData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (SCIkeStateGetKeyExchange(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms); - } - - return buffer; -} - -void DetectIkeKeyExchangeRegister(void) -{ - // register key_exchange - sigmatch_table[DETECT_IKE_KEY_EXCHANGE].name = KEYWORD_NAME_KEY_EXCHANGE; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE].url = - "/rules/" KEYWORD_DOC_KEY_EXCHANGE sigmatch_table[DETECT_IKE_KEY_EXCHANGE].desc = - "sticky buffer to match on the IKE key_exchange_payload"; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE].Setup = DetectKeyExchangeSetup; - sigmatch_table[DETECT_IKE_KEY_EXCHANGE].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME_KEY_EXCHANGE, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetKeyExchangeData); - - DetectAppLayerMpmRegister(BUFFER_NAME_KEY_EXCHANGE, SIG_FLAG_TOSERVER, 1, - PrefilterGenericMpmRegister, GetKeyExchangeData, ALPROTO_IKE, 1); - - DetectAppLayerInspectEngineRegister(BUFFER_NAME_KEY_EXCHANGE, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetKeyExchangeData); - - DetectAppLayerMpmRegister(BUFFER_NAME_KEY_EXCHANGE, SIG_FLAG_TOCLIENT, 1, - PrefilterGenericMpmRegister, GetKeyExchangeData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_KEY_EXCHANGE, BUFFER_DESC_KEY_EXCHANGE); - - g_buffer_key_exchange_id = DetectBufferTypeGetByName(BUFFER_NAME_KEY_EXCHANGE); - SCLogDebug("registering " BUFFER_NAME_KEY_EXCHANGE " rule option"); -} diff --git a/src/detect-ike-key-exchange-payload.h b/src/detect-ike-key-exchange-payload.h deleted file mode 100644 index 0732a8f600da..000000000000 --- a/src/detect-ike-key-exchange-payload.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_KEY_EXCHANGE_PAYLOAD_H -#define SURICATA_DETECT_IKE_KEY_EXCHANGE_PAYLOAD_H - -void DetectIkeKeyExchangeRegister(void); - -#endif /* SURICATA_DETECT_IKE_KEY_EXCHANGE_PAYLOAD_H */ From 14edd664946e3d6d4b7aac0f38546e3b9924e785 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 14:13:58 +0100 Subject: [PATCH 17/20] detect/ike: move ike.nonce_payload keyword to rust Ticket: 8310 --- rust/src/ike/detect.rs | 57 +++++++++++----- src/Makefile.am | 2 - src/detect-engine-register.c | 2 - src/detect-engine-register.h | 1 - src/detect-ike-nonce-payload.c | 118 --------------------------------- src/detect-ike-nonce-payload.h | 28 -------- 6 files changed, 40 insertions(+), 168 deletions(-) delete mode 100644 src/detect-ike-nonce-payload.c delete mode 100644 src/detect-ike-nonce-payload.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 678890c68ade..7afe9ab07f95 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -39,27 +39,20 @@ use suricata_sys::sys::{ Signature, }; -#[no_mangle] -pub extern "C" fn SCIkeStateGetNonce( - tx: &IKETransaction, buffer: *mut *const u8, buffer_len: *mut u32, -) -> u8 { - debug_validate_bug_on!(buffer.is_null() || buffer_len.is_null()); - +unsafe extern "C" fn ike_get_nonce_data( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, IKETransaction); if tx.ike_version == 1 && !tx.hdr.ikev1_header.nonce.is_empty() { let p = &tx.hdr.ikev1_header.nonce; - unsafe { - *buffer = p.as_ptr(); - *buffer_len = p.len() as u32; - } - return 1; - } - - unsafe { - *buffer = ptr::null(); - *buffer_len = 0; + *buffer = p.as_ptr(); + *buffer_len = p.len() as u32; + return true; } - return 0; + *buffer = ptr::null(); + *buffer_len = 0; + return false; } unsafe extern "C" fn ike_tx_get_key_exchange( @@ -332,6 +325,18 @@ unsafe extern "C" fn ike_detect_payload_len_free(_de: *mut DetectEngineCtx, ctx: SCDetectU32Free(ctx); } +unsafe extern "C" fn ike_nonce_payload_setup( + de_ctx: *mut DetectEngineCtx, s: *mut Signature, _str: *const c_char, +) -> c_int { + if SCDetectBufferSetActiveList(de_ctx, s, G_IKE_NONCE_PAYLOAD_BUFFER_ID) < 0 { + return -1; + } + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0 { + return -1; + } + return 0; +} + static mut G_IKE_SPI_INITIATOR_BUFFER_ID: c_int = 0; static mut G_IKE_SPI_RESPONDER_BUFFER_ID: c_int = 0; static mut G_IKE_KEY_EXCHANGE_BUFFER_ID: c_int = 0; @@ -339,9 +344,27 @@ static mut G_IKE_EXCHTYPE_KW_ID: u16 = 0; static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0; static mut G_IKE_PAYLOAD_LEN_KW_ID: u16 = 0; static mut G_IKE_PAYLOAD_LEN_BUFFER_ID: c_int = 0; +static mut G_IKE_NONCE_PAYLOAD_BUFFER_ID: c_int = 0; #[no_mangle] pub unsafe extern "C" fn SCDetectIkeRegister() { + // Register sticky buffer for ike.nonce_payload + let kw_nonce = SigTableElmtStickyBuffer { + name: String::from("ike.nonce_payload"), + desc: String::from("sticky buffer to match on the IKE nonce_payload"), + url: String::from("/rules/ike-keywords.html#ike-nonce_payload"), + setup: ike_nonce_payload_setup, + }; + helper_keyword_register_sticky_buffer(&kw_nonce); + + // Register buffer for both directions + G_IKE_NONCE_PAYLOAD_BUFFER_ID = SCDetectHelperBufferMpmRegister( + b"ike.nonce_payload\0".as_ptr() as *const libc::c_char, + b"ike nonce payload\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER | STREAM_TOCLIENT, + Some(ike_get_nonce_data), + ); // Register ike.nonce_payload_length keyword let kw = SCSigTableAppLiteElmt { name: b"ike.nonce_payload_length\0".as_ptr() as *const libc::c_char, diff --git a/src/Makefile.am b/src/Makefile.am index 360d88a2d895..bdd3154afca6 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,7 +228,6 @@ noinst_HEADERS = \ detect-icode.h \ detect-id.h \ detect-ike-chosen-sa.h \ - detect-ike-nonce-payload.h \ detect-ike-vendor.h \ detect-ipaddr.h \ detect-ipopts.h \ @@ -808,7 +807,6 @@ libsuricata_c_a_SOURCES = \ detect-icode.c \ detect-id.c \ detect-ike-chosen-sa.c \ - detect-ike-nonce-payload.c \ detect-ike-vendor.c \ detect-ipaddr.c \ detect-ipopts.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 424ed697dda9..3338199761b8 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -233,7 +233,6 @@ #include "detect-dnp3.h" #include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" -#include "detect-ike-nonce-payload.h" #include "detect-vlan.h" #include "detect-email.h" @@ -587,7 +586,6 @@ void SigTableSetup(void) DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); - DetectIkeNonceRegister(); DetectTlsSniRegister(); DetectTlsIssuerRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 8aaf77646fea..8398ffef5168 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -283,7 +283,6 @@ enum DetectKeywordId { DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, - DETECT_IKE_NONCE, DETECT_JA4_HASH, diff --git a/src/detect-ike-nonce-payload.c b/src/detect-ike-nonce-payload.c deleted file mode 100644 index a5ecdd2a20f8..000000000000 --- a/src/detect-ike-nonce-payload.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-buffer.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-urilen.h" - -#include "flow.h" -#include "flow-var.h" -#include "flow-util.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-unittest-helper.h" -#include "util-spm.h" - -#include "app-layer.h" -#include "app-layer-parser.h" - -#include "detect-ike-nonce-payload.h" -#include "stream-tcp.h" - -#include "rust.h" -#include "app-layer-ike.h" -#include "rust-bindings.h" - -#define KEYWORD_NAME_NONCE "ike.nonce_payload" -#define KEYWORD_DOC_NONCE "ike-keywords.html#ike-nonce_payload"; -#define BUFFER_NAME_NONCE "ike.nonce_payload" -#define BUFFER_DESC_NONCE "ike nonce payload" - -static int g_buffer_nonce_id = 0; - -static int DetectNonceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (SCDetectBufferSetActiveList(de_ctx, s, g_buffer_nonce_id) < 0) - return -1; - - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - - return 0; -} - -static InspectionBuffer *GetNonceData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *_f, const uint8_t _flow_flags, void *txv, - const int list_id) -{ - InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id); - if (buffer->inspect == NULL) { - const uint8_t *b = NULL; - uint32_t b_len = 0; - - if (SCIkeStateGetNonce(txv, &b, &b_len) != 1) - return NULL; - if (b == NULL || b_len == 0) - return NULL; - - InspectionBufferSetupAndApplyTransforms(det_ctx, list_id, buffer, b, b_len, transforms); - } - - return buffer; -} - -void DetectIkeNonceRegister(void) -{ - // register nonce - sigmatch_table[DETECT_IKE_NONCE].name = KEYWORD_NAME_NONCE; - sigmatch_table[DETECT_IKE_NONCE].url = - "/rules/" KEYWORD_DOC_NONCE sigmatch_table[DETECT_IKE_NONCE].desc = - "sticky buffer to match on the IKE nonce_payload"; - sigmatch_table[DETECT_IKE_NONCE].Setup = DetectNonceSetup; - sigmatch_table[DETECT_IKE_NONCE].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerInspectEngineRegister(BUFFER_NAME_NONCE, ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, - DetectEngineInspectBufferGeneric, GetNonceData); - - DetectAppLayerMpmRegister(BUFFER_NAME_NONCE, SIG_FLAG_TOSERVER, 1, PrefilterGenericMpmRegister, - GetNonceData, ALPROTO_IKE, 1); - - DetectAppLayerInspectEngineRegister(BUFFER_NAME_NONCE, ALPROTO_IKE, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectBufferGeneric, GetNonceData); - - DetectAppLayerMpmRegister(BUFFER_NAME_NONCE, SIG_FLAG_TOCLIENT, 1, PrefilterGenericMpmRegister, - GetNonceData, ALPROTO_IKE, 1); - - DetectBufferTypeSetDescriptionByName(BUFFER_NAME_NONCE, BUFFER_DESC_NONCE); - - g_buffer_nonce_id = DetectBufferTypeGetByName(BUFFER_NAME_NONCE); - SCLogDebug("registering " BUFFER_NAME_NONCE " rule option"); -} diff --git a/src/detect-ike-nonce-payload.h b/src/detect-ike-nonce-payload.h deleted file mode 100644 index f705c42395c9..000000000000 --- a/src/detect-ike-nonce-payload.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_NONCE_PAYLOAD_H -#define SURICATA_DETECT_IKE_NONCE_PAYLOAD_H - -void DetectIkeNonceRegister(void); - -#endif /* SURICATA_DETECT_IKE_NONCE_PAYLOAD_H */ From 55333a6ca0344dbef0d468a0c49a059fffd9fb94 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 14:30:06 +0100 Subject: [PATCH 18/20] detect/ike: move ike.vendor keyword to rust Ticket: 8310 --- rust/src/ike/detect.rs | 38 ++++++++++++++--- src/Makefile.am | 2 - src/detect-engine-register.c | 2 - src/detect-engine-register.h | 1 - src/detect-ike-vendor.c | 82 ------------------------------------ src/detect-ike-vendor.h | 29 ------------- 6 files changed, 32 insertions(+), 122 deletions(-) delete mode 100644 src/detect-ike-vendor.c delete mode 100644 src/detect-ike-vendor.h diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 7afe9ab07f95..1209bbbfa29c 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -25,8 +25,8 @@ use crate::detect::uint::{ SCDetectU8Parse, }; use crate::detect::{ - helper_keyword_register_sticky_buffer, SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT32, - SIGMATCH_INFO_UINT8, + helper_keyword_register_multi_buffer, helper_keyword_register_sticky_buffer, + SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT32, SIGMATCH_INFO_UINT8, }; use crate::ike::ike::*; use std::ffi::CStr; @@ -35,8 +35,8 @@ use std::ptr; use suricata_sys::sys::{ DetectEngineCtx, DetectEngineThreadCtx, SCDetectBufferSetActiveList, SCDetectHelperBufferMpmRegister, SCDetectHelperBufferRegister, SCDetectHelperKeywordRegister, - SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, SCSigTableAppLiteElmt, SigMatchCtx, - Signature, + SCDetectHelperMultiBufferMpmRegister, SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, + SCSigTableAppLiteElmt, SigMatchCtx, Signature, }; unsafe extern "C" fn ike_get_nonce_data( @@ -71,8 +71,7 @@ unsafe extern "C" fn ike_tx_get_key_exchange( return false; } -#[no_mangle] -pub unsafe extern "C" fn SCIkeTxGetVendor( +unsafe extern "C" fn ike_tx_get_vendor( _de: *mut DetectEngineThreadCtx, tx: *const c_void, _flags: u8, i: u32, buf: *mut *const u8, len: *mut u32, ) -> bool { @@ -340,6 +339,7 @@ unsafe extern "C" fn ike_nonce_payload_setup( static mut G_IKE_SPI_INITIATOR_BUFFER_ID: c_int = 0; static mut G_IKE_SPI_RESPONDER_BUFFER_ID: c_int = 0; static mut G_IKE_KEY_EXCHANGE_BUFFER_ID: c_int = 0; +static mut G_IKE_VENDOR_BUFFER_ID: c_int = 0; static mut G_IKE_EXCHTYPE_KW_ID: u16 = 0; static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0; static mut G_IKE_PAYLOAD_LEN_KW_ID: u16 = 0; @@ -456,6 +456,20 @@ pub unsafe extern "C" fn SCDetectIkeRegister() { STREAM_TOSERVER | STREAM_TOCLIENT, Some(ike_tx_get_key_exchange), ); + let kw = SigTableElmtStickyBuffer { + name: String::from("ike.vendor"), + desc: String::from("match IKE Vendor"), + url: String::from("/rules/ike-keywords.html#ike-vendor"), + setup: ike_vendor_setup, + }; + helper_keyword_register_multi_buffer(&kw); + G_IKE_VENDOR_BUFFER_ID = SCDetectHelperMultiBufferMpmRegister( + b"ike.vendor.dn\0".as_ptr() as *const libc::c_char, + b"Like vendor\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOSERVER, + Some(ike_tx_get_vendor), + ); } unsafe extern "C" fn ike_spi_initiator_setup( @@ -497,3 +511,15 @@ unsafe extern "C" fn ike_key_exchange_setup( } return 0; } + +unsafe extern "C" fn ike_vendor_setup( + de_ctx: *mut DetectEngineCtx, s: *mut Signature, _str: *const c_char, +) -> c_int { + if SCDetectBufferSetActiveList(de_ctx, s, G_IKE_VENDOR_BUFFER_ID) < 0 { + return -1; + } + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0 { + return -1; + } + return 0; +} diff --git a/src/Makefile.am b/src/Makefile.am index bdd3154afca6..1d9e8fe0159c 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -228,7 +228,6 @@ noinst_HEADERS = \ detect-icode.h \ detect-id.h \ detect-ike-chosen-sa.h \ - detect-ike-vendor.h \ detect-ipaddr.h \ detect-ipopts.h \ detect-ipproto.h \ @@ -807,7 +806,6 @@ libsuricata_c_a_SOURCES = \ detect-icode.c \ detect-id.c \ detect-ike-chosen-sa.c \ - detect-ike-vendor.c \ detect-ipaddr.c \ detect-ipopts.c \ detect-ipproto.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 3338199761b8..f07795f901bb 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -231,7 +231,6 @@ #include "detect-ssl-state.h" #include "detect-modbus.h" #include "detect-dnp3.h" -#include "detect-ike-vendor.h" #include "detect-ike-chosen-sa.h" #include "detect-vlan.h" #include "detect-email.h" @@ -584,7 +583,6 @@ void SigTableSetup(void) DetectModbusRegister(); DetectDNP3Register(); - DetectIkeVendorRegister(); DetectIkeChosenSaRegister(); DetectTlsSniRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 8398ffef5168..80986a41c254 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -281,7 +281,6 @@ enum DetectKeywordId { DETECT_TRANSFORM_PCREXFORM, DETECT_TRANSFORM_LUAXFORM, - DETECT_IKE_VENDOR, DETECT_IKE_CHOSEN_SA, DETECT_JA4_HASH, diff --git a/src/detect-ike-vendor.c b/src/detect-ike-vendor.c deleted file mode 100644 index d2c013ddd535..000000000000 --- a/src/detect-ike-vendor.c +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (C) 2020-2022 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-buffer.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-engine-mpm.h" -#include "detect-ike-vendor.h" -#include "rust.h" -#include "app-layer-parser.h" -#include "util-byte.h" - -#include "util-profiling.h" - -static int DetectIkeVendorSetup(DetectEngineCtx *, Signature *, const char *); - -static int g_ike_vendor_buffer_id = 0; - -/** - * \brief Registration function for ike.vendor keyword. - */ -void DetectIkeVendorRegister(void) -{ - sigmatch_table[DETECT_IKE_VENDOR].name = "ike.vendor"; - sigmatch_table[DETECT_IKE_VENDOR].desc = "match IKE Vendor"; - sigmatch_table[DETECT_IKE_VENDOR].url = "/rules/ike-keywords.html#ike-vendor"; - sigmatch_table[DETECT_IKE_VENDOR].Setup = DetectIkeVendorSetup; - sigmatch_table[DETECT_IKE_VENDOR].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_IKE_VENDOR].flags |= - SIGMATCH_INFO_STICKY_BUFFER | SIGMATCH_INFO_MULTI_BUFFER; - - DetectAppLayerMultiRegister( - "ike.vendor", ALPROTO_IKE, SIG_FLAG_TOSERVER, 1, SCIkeTxGetVendor, 1); - - g_ike_vendor_buffer_id = DetectBufferTypeGetByName("ike.vendor"); - - DetectBufferTypeSupportsMultiInstance("ike.vendor"); -} - -/** - * \brief setup the sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectIkeVendorSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (SCDetectBufferSetActiveList(de_ctx, s, g_ike_vendor_buffer_id) < 0) - return -1; - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) < 0) - return -1; - return 0; -} diff --git a/src/detect-ike-vendor.h b/src/detect-ike-vendor.h deleted file mode 100644 index 8b551c3ad87e..000000000000 --- a/src/detect-ike-vendor.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_VENDOR_H -#define SURICATA_DETECT_IKE_VENDOR_H - -void DetectIkeVendorRegister(void); - -#endif /* SURICATA_DETECT_IKE_VENDOR_H */ From d5ea973791699f743c6c205722aac077c5db90f4 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 19 Feb 2026 15:15:50 +0100 Subject: [PATCH 19/20] detect/ike: move ike.ike.chosen_sa_attribute keyword to rust Ticket: 8310 And increases expressivity on the way by supporting other modes than equality --- doc/userguide/rules/ike-keywords.rst | 1 + rust/src/ike/detect.rs | 251 +++++++++++++++++------- rust/src/ike/logger.rs | 3 +- rust/src/ike/parser.rs | 89 +++------ src/Makefile.am | 2 - src/detect-engine-register.c | 3 - src/detect-engine-register.h | 2 - src/detect-ike-chosen-sa.c | 274 --------------------------- src/detect-ike-chosen-sa.h | 29 --- src/output-json-ike.c | 2 +- 10 files changed, 210 insertions(+), 446 deletions(-) delete mode 100644 src/detect-ike-chosen-sa.c delete mode 100644 src/detect-ike-chosen-sa.h diff --git a/doc/userguide/rules/ike-keywords.rst b/doc/userguide/rules/ike-keywords.rst index 38d78954de74..568963a2c9aa 100644 --- a/doc/userguide/rules/ike-keywords.rst +++ b/doc/userguide/rules/ike-keywords.rst @@ -48,6 +48,7 @@ Match on an attribute value of the chosen Security Association (SA) by the Respo IKEv2 supports ``alg_enc``, ``alg_auth``, ``alg_prf`` and ``alg_dh``. If there is more than one chosen SA the event ``MultipleServerProposal`` is set. The attributes of the first SA are used for this keyword. +You can also use other modes than equality, as in :ref:`integer keywords `. Examples:: diff --git a/rust/src/ike/detect.rs b/rust/src/ike/detect.rs index 1209bbbfa29c..29a2b700093c 100644 --- a/rust/src/ike/detect.rs +++ b/rust/src/ike/detect.rs @@ -19,16 +19,20 @@ use super::ike::ALPROTO_IKE; use super::ipsec_parser::IkeV2Transform; +use super::parser::AttributeType; use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER}; use crate::detect::uint::{ - detect_match_uint, DetectUintData, SCDetectU32Free, SCDetectU32Parse, SCDetectU8Free, - SCDetectU8Parse, + detect_match_uint, detect_parse_uint, DetectUintData, SCDetectU32Free, SCDetectU32Parse, + SCDetectU8Free, SCDetectU8Parse, }; use crate::detect::{ - helper_keyword_register_multi_buffer, helper_keyword_register_sticky_buffer, + helper_keyword_register_multi_buffer, helper_keyword_register_sticky_buffer, EnumString, SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT32, SIGMATCH_INFO_UINT8, }; use crate::ike::ike::*; +use nom8::bytes::complete::take_while; +use nom8::combinator::map_opt; +use nom8::{AsChar, Parser}; use std::ffi::CStr; use std::os::raw::{c_char, c_int, c_void}; use std::ptr; @@ -88,93 +92,148 @@ unsafe extern "C" fn ike_tx_get_vendor( return false; } -#[no_mangle] -pub extern "C" fn SCIkeStateGetSaAttribute( - tx: &IKETransaction, sa_type: *const std::os::raw::c_char, value: *mut u32, -) -> u8 { - debug_validate_bug_on!(value.is_null()); - let mut ret_val = 0; - let mut ret_code = 0; - let sa_type_s: Result<_, _>; - - unsafe { sa_type_s = CStr::from_ptr(sa_type).to_str() } - SCLogDebug!("{:#?}", sa_type_s); - - if let Ok(sa) = sa_type_s { - if tx.ike_version == 1 { - if !tx.hdr.ikev1_transforms.is_empty() { - // there should be only one chosen server_transform, check event - if let Some(server_transform) = tx.hdr.ikev1_transforms.first() { - for attr in server_transform { - if attr.attribute_type.to_string() == sa { - if let Some(numeric_value) = attr.numeric_value { - ret_val = numeric_value; - ret_code = 1; - break; +unsafe extern "C" fn ike_tx_get_spi_initiator( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, IKETransaction); + *buffer = tx.hdr.spi_initiator.as_ptr(); + *buffer_len = tx.hdr.spi_initiator.len() as u32; + return true; +} + +unsafe extern "C" fn ike_tx_get_spi_responder( + tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, IKETransaction); + *buffer = tx.hdr.spi_responder.as_ptr(); + *buffer_len = tx.hdr.spi_responder.len() as u32; + return true; +} + +#[derive(Debug, PartialEq)] +struct DetectIkeChosenSa { + attribute: AttributeType, + value: DetectUintData, +} + +fn ike_detect_chosen_sa_parse_aux(i: &str) -> Option { + let (i, attribute) = map_opt( + take_while::<_, &str, nom8::error::Error<_>>(|c: char| c.is_alpha() || c == '_'), + |s: &str| AttributeType::from_str(s), + ) + .parse(i) + .ok()?; + let (_i, value) = detect_parse_uint(i).ok()?; + Some(DetectIkeChosenSa { attribute, value }) +} + +unsafe fn ike_detect_chosen_sa_parse( + str: *const std::os::raw::c_char, +) -> *mut std::os::raw::c_void { + let ft_name: &CStr = CStr::from_ptr(str); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Some(ctx) = ike_detect_chosen_sa_parse_aux(s) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + +unsafe extern "C" fn ike_detect_chosen_sa_setup( + de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, +) -> c_int { + if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0 { + return -1; + } + let ctx = ike_detect_chosen_sa_parse(raw); + if ctx.is_null() { + return -1; + } + if SCSigMatchAppendSMToList( + de, + s, + G_IKE_CHOSEN_SA_KW_ID, + ctx as *mut SigMatchCtx, + G_IKE_CHOSEN_SA_BUFFER_ID, + ) + .is_null() + { + ike_detect_chosen_sa_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn ike_detect_chosen_sa_match( + _de: *mut DetectEngineThreadCtx, _f: *mut crate::flow::Flow, _flags: u8, _state: *mut c_void, + tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx, +) -> c_int { + let tx = cast_pointer!(tx, IKETransaction); + let ctx = cast_pointer!(ctx, DetectIkeChosenSa); + + if tx.ike_version == 1 { + if !tx.hdr.ikev1_transforms.is_empty() { + // there should be only one chosen server_transform, check event + if let Some(server_transform) = tx.hdr.ikev1_transforms.first() { + for attr in server_transform { + if attr.attribute_type == ctx.attribute { + if let Some(numeric_value) = attr.numeric_value { + if detect_match_uint(&ctx.value, numeric_value) { + return 1; } + return 0; } } } } - } else if tx.ike_version == 2 { - for attr in tx.hdr.ikev2_transforms.iter() { - match attr { - IkeV2Transform::Encryption(e) => { - if sa == "alg_enc" { - ret_val = e.0 as u32; - ret_code = 1; - break; + } + } else if tx.ike_version == 2 { + for attr in tx.hdr.ikev2_transforms.iter() { + match attr { + IkeV2Transform::Encryption(e) => { + if ctx.attribute == AttributeType::AlgEnc { + if detect_match_uint(&ctx.value, e.0.into()) { + return 1; } + return 0; } - IkeV2Transform::Auth(e) => { - if sa == "alg_auth" { - ret_val = e.0 as u32; - ret_code = 1; - break; + } + IkeV2Transform::Auth(e) => { + if ctx.attribute == AttributeType::AlgAuth { + if detect_match_uint(&ctx.value, e.0.into()) { + return 1; } + return 0; } - IkeV2Transform::PRF(ref e) => { - if sa == "alg_prf" { - ret_val = e.0 as u32; - ret_code = 1; - break; + } + IkeV2Transform::PRF(ref e) => { + if ctx.attribute == AttributeType::AlgPrf { + if detect_match_uint(&ctx.value, e.0.into()) { + return 1; } + return 0; } - IkeV2Transform::DH(ref e) => { - if sa == "alg_dh" { - ret_val = e.0 as u32; - ret_code = 1; - break; + } + IkeV2Transform::DH(ref e) => { + if ctx.attribute == AttributeType::AlgDh { + if detect_match_uint(&ctx.value, e.0.into()) { + return 1; } + return 0; } - _ => (), } + _ => (), } } } - unsafe { - *value = ret_val; - } - return ret_code; -} - -unsafe extern "C" fn ike_tx_get_spi_initiator( - tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, -) -> bool { - let tx = cast_pointer!(tx, IKETransaction); - *buffer = tx.hdr.spi_initiator.as_ptr(); - *buffer_len = tx.hdr.spi_initiator.len() as u32; - return true; + return 0; } -unsafe extern "C" fn ike_tx_get_spi_responder( - tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32, -) -> bool { - let tx = cast_pointer!(tx, IKETransaction); - *buffer = tx.hdr.spi_responder.as_ptr(); - *buffer_len = tx.hdr.spi_responder.len() as u32; - return true; +unsafe extern "C" fn ike_detect_chosen_sa_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectIkeChosenSa); + std::mem::drop(Box::from_raw(ctx)); } unsafe extern "C" fn ike_detect_exchtype_setup( @@ -345,6 +404,8 @@ static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0; static mut G_IKE_PAYLOAD_LEN_KW_ID: u16 = 0; static mut G_IKE_PAYLOAD_LEN_BUFFER_ID: c_int = 0; static mut G_IKE_NONCE_PAYLOAD_BUFFER_ID: c_int = 0; +static mut G_IKE_CHOSEN_SA_KW_ID: u16 = 0; +static mut G_IKE_CHOSEN_SA_BUFFER_ID: c_int = 0; #[no_mangle] pub unsafe extern "C" fn SCDetectIkeRegister() { @@ -396,6 +457,21 @@ pub unsafe extern "C" fn SCDetectIkeRegister() { ALPROTO_IKE, STREAM_TOSERVER | STREAM_TOCLIENT, ); + let kw = SCSigTableAppLiteElmt { + name: b"ike.chosen_sa_attribute\0".as_ptr() as *const libc::c_char, + desc: b"match IKE chosen SA Attribute\0".as_ptr() as *const libc::c_char, + url: b"/rules/ike-keywords.html#ike-chosen_sa_attribute\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(ike_detect_chosen_sa_match), + Setup: Some(ike_detect_chosen_sa_setup), + Free: Some(ike_detect_chosen_sa_free), + flags: 0, + }; + G_IKE_CHOSEN_SA_KW_ID = SCDetectHelperKeywordRegister(&kw); + G_IKE_CHOSEN_SA_BUFFER_ID = SCDetectHelperBufferRegister( + b"ike.chosen_sa_attribute\0".as_ptr() as *const libc::c_char, + ALPROTO_IKE, + STREAM_TOCLIENT, + ); let kw = SCSigTableAppLiteElmt { name: b"ike.key_exchange_payload_length\0".as_ptr() as *const libc::c_char, desc: b"match IKE key exchange payload length\0".as_ptr() as *const libc::c_char, @@ -523,3 +599,38 @@ unsafe extern "C" fn ike_vendor_setup( } return 0; } + +#[cfg(test)] +mod tests { + + use super::*; + use crate::detect::uint::DetectUintMode; + + #[test] + fn test_ike_detect_chosen_sa_parse_aux() { + let r0 = ike_detect_chosen_sa_parse_aux("alg_hash=2").unwrap(); + assert_eq!( + r0, + DetectIkeChosenSa { + attribute: AttributeType::AlgHash, + value: DetectUintData:: { + mode: DetectUintMode::DetectUintModeEqual, + arg1: 2, + arg2: 0, + }, + } + ); + let r1 = ike_detect_chosen_sa_parse_aux("alg_hash!=2").unwrap(); + assert_eq!( + r1, + DetectIkeChosenSa { + attribute: AttributeType::AlgHash, + value: DetectUintData:: { + mode: DetectUintMode::DetectUintModeNe, + arg1: 2, + arg2: 0, + }, + } + ); + } +} diff --git a/rust/src/ike/logger.rs b/rust/src/ike/logger.rs index dcc33f5e178a..cb17c847a4ef 100644 --- a/rust/src/ike/logger.rs +++ b/rust/src/ike/logger.rs @@ -17,6 +17,7 @@ use super::ike::{IKEState, IKETransaction}; use super::ipsec_parser::IKEV2_FLAG_INITIATOR; +use crate::detect::EnumString; use crate::direction::Direction; use crate::ike::parser::{ExchangeType, IsakmpPayloadType, SaAttribute}; use crate::jsonbuilder::{JsonBuilder, JsonError}; @@ -37,7 +38,7 @@ const IKE_LOG_VERSION: u8 = 2; fn add_attributes(transform: &Vec, js: &mut JsonBuilder) -> Result<(), JsonError> { for attribute in transform { js.start_object()?; - js.set_string("key", &attribute.attribute_type.to_string())?; + js.set_string("key", attribute.attribute_type.to_str())?; js.set_string("value", &attribute.attribute_value.to_string())?; if let Some(v) = attribute.numeric_value { diff --git a/rust/src/ike/parser.rs b/rust/src/ike/parser.rs index f7f74a83cda7..1a45c8353520 100644 --- a/rust/src/ike/parser.rs +++ b/rust/src/ike/parser.rs @@ -16,6 +16,7 @@ */ use crate::common::to_hex; +use crate::detect::EnumString; use core::fmt; use nom8::bytes::streaming::take; use nom8::combinator::{complete, cond, map}; @@ -129,49 +130,25 @@ pub struct VendorPayload<'a> { } // Attributes inside Transform -#[derive(Debug, Clone)] +#[derive(Debug, Clone, EnumStringU16, PartialEq)] pub enum AttributeType { Unknown = 0, - EncryptionAlgorithm = 1, - HashAlgorithm = 2, - AuthenticationMethod = 3, - GroupDescription = 4, - GroupType = 5, - GroupPrime = 6, - GroupGeneratorOne = 7, - GroupGeneratorTwo = 8, - GroupCurveA = 9, - GroupCurveB = 10, - LifeType = 11, - LifeDuration = 12, - Prf = 13, - KeyLength = 14, - FieldSize = 15, - GroupOrder = 16, -} - -impl fmt::Display for AttributeType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - AttributeType::EncryptionAlgorithm => write!(f, "alg_enc"), - AttributeType::HashAlgorithm => write!(f, "alg_hash"), - AttributeType::AuthenticationMethod => write!(f, "alg_auth"), - AttributeType::GroupDescription => write!(f, "alg_dh"), - AttributeType::GroupType => write!(f, "sa_group_type"), - AttributeType::GroupPrime => write!(f, "sa_group_prime"), - AttributeType::GroupGeneratorOne => write!(f, "sa_group_generator_one"), - AttributeType::GroupGeneratorTwo => write!(f, "sa_group_generator_two"), - AttributeType::GroupCurveA => write!(f, "sa_group_curve_a"), - AttributeType::GroupCurveB => write!(f, "sa_group_curve_b"), - AttributeType::LifeType => write!(f, "sa_life_type"), - AttributeType::LifeDuration => write!(f, "sa_life_duration"), - AttributeType::Prf => write!(f, "alg_prf"), - AttributeType::KeyLength => write!(f, "sa_key_length"), - AttributeType::FieldSize => write!(f, "sa_field_size"), - AttributeType::GroupOrder => write!(f, "sa_group_order"), - _ => write!(f, "unknown"), - } - } + AlgEnc = 1, + AlgHash = 2, + AlgAuth = 3, + AlgDh = 4, + SaGroupType = 5, + SaGroupPrime = 6, + SaGroupGeneratorOne = 7, + SaGroupGeneratorTwo = 8, + SaGroupCurveA = 9, + SaGroupCurveB = 10, + SaLifeType = 11, + SaLifeDuration = 12, + AlgPrf = 13, + SaKeyLength = 14, + SaFieldSize = 15, + SaGroupOrder = 16, } #[derive(Debug, Clone)] @@ -337,28 +314,6 @@ pub fn parse_vendor_id(i: &[u8], length: u16) -> IResult<&[u8], VendorPayload<'_ map(take(length), |v| VendorPayload { vendor_id: v }).parse(i) } -fn get_attribute_type(v: u16) -> AttributeType { - match v { - 1 => AttributeType::EncryptionAlgorithm, - 2 => AttributeType::HashAlgorithm, - 3 => AttributeType::AuthenticationMethod, - 4 => AttributeType::GroupDescription, - 5 => AttributeType::GroupType, - 6 => AttributeType::GroupPrime, - 7 => AttributeType::GroupGeneratorOne, - 8 => AttributeType::GroupGeneratorTwo, - 9 => AttributeType::GroupCurveA, - 10 => AttributeType::GroupCurveB, - 11 => AttributeType::LifeType, - 12 => AttributeType::LifeDuration, - 13 => AttributeType::Prf, - 14 => AttributeType::KeyLength, - 15 => AttributeType::FieldSize, - 16 => AttributeType::GroupOrder, - _ => AttributeType::Unknown, - } -} - fn get_encryption_algorithm(v: u16) -> AttributeValue { match v { 1 => AttributeValue::EncDesCbc, @@ -449,9 +404,15 @@ pub fn parse_sa_attribute(i: &[u8]) -> IResult<&[u8], Vec> { format.0 == 0 && attribute_length_or_value != 4, take(attribute_length_or_value), ).parse(i)?; + let at = AttributeType::from_u(format.1); + let attribute_type = if let Some(a) = at { + a + } else { + AttributeType::Unknown + }; let attr = SaAttribute { attribute_format: format.0, - attribute_type: get_attribute_type(format.1), + attribute_type, attribute_value: match format.1 { 1 => get_encryption_algorithm(attribute_length_or_value), 2 => get_hash_algorithm(attribute_length_or_value), diff --git a/src/Makefile.am b/src/Makefile.am index 1d9e8fe0159c..502efd4f5220 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -227,7 +227,6 @@ noinst_HEADERS = \ detect-icmpv6hdr.h \ detect-icode.h \ detect-id.h \ - detect-ike-chosen-sa.h \ detect-ipaddr.h \ detect-ipopts.h \ detect-ipproto.h \ @@ -805,7 +804,6 @@ libsuricata_c_a_SOURCES = \ detect-icmpv6hdr.c \ detect-icode.c \ detect-id.c \ - detect-ike-chosen-sa.c \ detect-ipaddr.c \ detect-ipopts.c \ detect-ipproto.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index f07795f901bb..278b1347f108 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -231,7 +231,6 @@ #include "detect-ssl-state.h" #include "detect-modbus.h" #include "detect-dnp3.h" -#include "detect-ike-chosen-sa.h" #include "detect-vlan.h" #include "detect-email.h" @@ -583,8 +582,6 @@ void SigTableSetup(void) DetectModbusRegister(); DetectDNP3Register(); - DetectIkeChosenSaRegister(); - DetectTlsSniRegister(); DetectTlsIssuerRegister(); DetectTlsSubjectRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 80986a41c254..9e201123664d 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -281,8 +281,6 @@ enum DetectKeywordId { DETECT_TRANSFORM_PCREXFORM, DETECT_TRANSFORM_LUAXFORM, - DETECT_IKE_CHOSEN_SA, - DETECT_JA4_HASH, DETECT_FTP_COMMAND, diff --git a/src/detect-ike-chosen-sa.c b/src/detect-ike-chosen-sa.c deleted file mode 100644 index 40e6a798ed01..000000000000 --- a/src/detect-ike-chosen-sa.c +++ /dev/null @@ -1,274 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * - * \author Frank Honza - */ - -#include "suricata-common.h" -#include "conf.h" -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-content-inspection.h" -#include "detect-ike-chosen-sa.h" -#include "app-layer-parser.h" -#include "util-byte.h" -#include "util-unittest.h" - -#include "rust.h" - -/** - * [ike.chosen_sa_attribute]:=; - */ - -// support the basic attributes, which are parsed as integer and life_duration, if variable length -// is 4 it is stored as integer too -#define PARSE_REGEX \ - "^\\s*(alg_enc|alg_hash|alg_auth|alg_dh|\ -sa_group_type|sa_life_type|sa_life_duration|alg_prf|sa_key_length|sa_field_size)\ -\\s*=\\s*([0-9]+)\\s*$" - -static DetectParseRegex parse_regex; - -typedef struct { - char *sa_type; - uint32_t sa_value; -} DetectIkeChosenSaData; - -static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *); -static int DetectIkeChosenSaSetup(DetectEngineCtx *, Signature *s, const char *str); -static void DetectIkeChosenSaFree(DetectEngineCtx *, void *); -static int g_ike_chosen_sa_buffer_id = 0; - -static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *, - const Signature *, const SigMatchCtx *); -void IKEChosenSaRegisterTests(void); - -/** - * \brief Registration function for ike.ChosenSa keyword. - */ -void DetectIkeChosenSaRegister(void) -{ - sigmatch_table[DETECT_IKE_CHOSEN_SA].name = "ike.chosen_sa_attribute"; - sigmatch_table[DETECT_IKE_CHOSEN_SA].desc = "match IKE chosen SA Attribute"; - sigmatch_table[DETECT_IKE_CHOSEN_SA].url = "/rules/ike-keywords.html#ike-chosen_sa_attribute"; - sigmatch_table[DETECT_IKE_CHOSEN_SA].AppLayerTxMatch = DetectIkeChosenSaMatch; - sigmatch_table[DETECT_IKE_CHOSEN_SA].Setup = DetectIkeChosenSaSetup; - sigmatch_table[DETECT_IKE_CHOSEN_SA].Free = DetectIkeChosenSaFree; -#ifdef UNITTESTS - sigmatch_table[DETECT_IKE_CHOSEN_SA].RegisterTests = IKEChosenSaRegisterTests; -#endif - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); - - DetectAppLayerInspectEngineRegister("ike.chosen_sa_attribute", ALPROTO_IKE, SIG_FLAG_TOCLIENT, - 1, DetectEngineInspectGenericList, NULL); - - g_ike_chosen_sa_buffer_id = DetectBufferTypeGetByName("ike.chosen_sa_attribute"); -} - -/** - * \internal - * \brief Function to match SA attributes of a IKE state - * - * \param det_ctx Pointer to the pattern matcher thread. - * \param f Pointer to the current flow. - * \param flags Flags. - * \param state App layer state. - * \param txv Pointer to the Ike Transaction. - * \param s Pointer to the Signature. - * \param ctx Pointer to the sigmatch that we will cast into DetectIkeChosenSaData. - * - * \retval 0 no match. - * \retval 1 match. - */ -static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, - void *state, void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - SCEnter(); - - const DetectIkeChosenSaData *dd = (const DetectIkeChosenSaData *)ctx; - - uint32_t value; - if (!SCIkeStateGetSaAttribute(txv, dd->sa_type, &value)) - SCReturnInt(0); - if (value == dd->sa_value) - SCReturnInt(1); - SCReturnInt(0); -} - -/** - * \internal - * \brief Function to parse options passed via ike.chosen_sa_attribute keywords. - * - * \param rawstr Pointer to the user provided options. - * - * \retval dd pointer to DetectIkeChosenSaData on success. - * \retval NULL on failure. - */ -static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *rawstr) -{ - /* - * idea: do not implement one c file per type, invent an own syntax: - * ike.chosen_sa_attribute:"encryption_algorithm=4" - * ike.chosen_sa_attribute:"hash_algorithm=8" - */ - DetectIkeChosenSaData *dd = NULL; - int res = 0; - size_t pcre2len; - char attribute[100]; - char value[100]; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0); - if (ret < 3 || ret > 5) { - SCLogError( - "pcre match for ike.chosen_sa_attribute failed, should be: =, " - "but was: %s; error code %d", - rawstr, ret); - goto error; - } - - pcre2len = sizeof(attribute); - res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)attribute, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - pcre2len = sizeof(value); - res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)value, &pcre2len); - if (res < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - - dd = SCCalloc(1, sizeof(DetectIkeChosenSaData)); - if (unlikely(dd == NULL)) - goto error; - - dd->sa_type = SCStrdup(attribute); - if (dd->sa_type == NULL) - goto error; - - if (ByteExtractStringUint32(&dd->sa_value, 10, strlen(value), value) <= 0) { - SCLogError("invalid input as arg " - "to ike.chosen_sa_attribute keyword"); - goto error; - } - - pcre2_match_data_free(match); - return dd; - -error: - if (match) { - pcre2_match_data_free(match); - } - if (dd) { - if (dd->sa_type != NULL) - SCFree(dd->sa_type); - SCFree(dd); - } - return NULL; -} - -/** - * \brief Function to add the parsed IKE SA attribute query into the current signature. - * - * \param de_ctx Pointer to the Detection Engine Context. - * \param s Pointer to the Current Signature. - * \param rawstr Pointer to the user provided flags options. - * - * \retval 0 on Success. - * \retval -1 on Failure. - */ -static int DetectIkeChosenSaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr) -{ - if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0) - return -1; - - DetectIkeChosenSaData *dd = DetectIkeChosenSaParse(rawstr); - if (dd == NULL) { - SCLogError("Parsing \'%s\' failed", rawstr); - goto error; - } - - /* okay so far so good, lets get this into a SigMatch - * and put it in the Signature. */ - - if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_IKE_CHOSEN_SA, (SigMatchCtx *)dd, - g_ike_chosen_sa_buffer_id) == NULL) { - goto error; - } - return 0; - -error: - DetectIkeChosenSaFree(de_ctx, dd); - return -1; -} - -/** - * \internal - * \brief Function to free memory associated with DetectIkeChosenSaData. - * - * \param de_ptr Pointer to DetectIkeChosenSaData. - */ -static void DetectIkeChosenSaFree(DetectEngineCtx *de_ctx, void *ptr) -{ - DetectIkeChosenSaData *dd = (DetectIkeChosenSaData *)ptr; - if (dd == NULL) - return; - if (dd->sa_type != NULL) - SCFree(dd->sa_type); - - SCFree(ptr); -} - -/* - * ONLY TESTS BELOW THIS COMMENT - */ - -#ifdef UNITTESTS - -/** - * \test IKEChosenSaParserTest is a test for valid values - * - * \retval 1 on success - * \retval 0 on failure - */ -static int IKEChosenSaParserTest(void) -{ - DetectIkeChosenSaData *de = NULL; - de = DetectIkeChosenSaParse("alg_hash=2"); - - FAIL_IF_NULL(de); - FAIL_IF(de->sa_value != 2); - FAIL_IF(strcmp(de->sa_type, "alg_hash") != 0); - - DetectIkeChosenSaFree(NULL, de); - PASS; -} - -#endif /* UNITTESTS */ - -void IKEChosenSaRegisterTests(void) -{ -#ifdef UNITTESTS - UtRegisterTest("IKEChosenSaParserTest", IKEChosenSaParserTest); -#endif /* UNITTESTS */ -} diff --git a/src/detect-ike-chosen-sa.h b/src/detect-ike-chosen-sa.h deleted file mode 100644 index d5e107d22f6d..000000000000 --- a/src/detect-ike-chosen-sa.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2020 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Frank Honza - */ - -#ifndef SURICATA_DETECT_IKE_CHOSEN_SA_H -#define SURICATA_DETECT_IKE_CHOSEN_SA_H - -void DetectIkeChosenSaRegister(void); - -#endif /* SURICATA_DETECT_IKE_CHOSEN_SA_H */ diff --git a/src/output-json-ike.c b/src/output-json-ike.c index a990e72aa0b2..1021fa3fd87c 100644 --- a/src/output-json-ike.c +++ b/src/output-json-ike.c @@ -66,7 +66,7 @@ bool EveIKEAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *js) { IKEState *state = FlowGetAppState(f); if (state) { - IKETransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_IKE, state, tx_id); + void *tx = AppLayerParserGetTx(f->proto, ALPROTO_IKE, state, tx_id); if (tx) { return SCIkeLoggerLog(state, tx, LOG_IKE_EXTENDED, js); } From 926fde859e648b7cb435a1b22232f49ce6512757 Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Thu, 19 Feb 2026 13:06:04 -0300 Subject: [PATCH 20/20] userguide: fix Deprecations, warn about syslog The Deprecation note on Syslog was partly conveying the opposite message, and we were missing a deprecation notice on the Syslog output section. --- doc/userguide/output/syslog-alerting-comp.rst | 4 ++++ doc/userguide/upgrade.rst | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/userguide/output/syslog-alerting-comp.rst b/doc/userguide/output/syslog-alerting-comp.rst index e3db0b524a02..c9cd8b4d77ec 100644 --- a/doc/userguide/output/syslog-alerting-comp.rst +++ b/doc/userguide/output/syslog-alerting-comp.rst @@ -5,6 +5,10 @@ Suricata can alert via syslog which is a very handy feature for central log coll However, there are different syslog daemons and there can be parsing issues with the syslog format a SIEM expects and what syslog format Suricata sends. The syslog format from Suricata is dependent on the syslog daemon running on the Suricata sensor but often the format it sends is not the format the SIEM expects and cannot parse it properly. +.. attention:: The syslog output is deprecated in Suricata 8.0 and + will be removed in Suricata 9.0. Please migrate to the + ``eve`` output which has the ability to send to syslog. + Popular syslog daemons ---------------------- diff --git a/doc/userguide/upgrade.rst b/doc/userguide/upgrade.rst index 62d7f58ff943..cb72f6554cc4 100644 --- a/doc/userguide/upgrade.rst +++ b/doc/userguide/upgrade.rst @@ -251,7 +251,7 @@ Deprecations - The ``tls-log`` output is now deprecated and will be removed in Suricata 9.0. - The ``syslog`` output is now deprecated and will be removed in Suricata 9.0. Note that this is the standalone ``syslog`` output and - does affect the ``eve`` outputs ability to send to syslog. + does **not** affect the ``eve`` outputs ability to send to syslog. - The ``default`` option in ``app-layer.protocols.tls.encryption-handling`` is now deprecated and will be removed in Suricata 9.0. The ``track-only`` option should be used instead.