diff --git a/src/Makefile.am b/src/Makefile.am index 2bc3c58d50..325d6d12d0 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -231,6 +231,7 @@ noinst_HEADERS = \ detect-sctphdr.h \ detect-sctp-chunk-cnt.h \ detect-sctp-chunk-type.h \ + detect-sctp-vtag.h \ detect-ipaddr.h \ detect-ipopts.h \ detect-ipproto.h \ @@ -810,6 +811,7 @@ libsuricata_c_a_SOURCES = \ detect-sctphdr.c \ detect-sctp-chunk-cnt.c \ detect-sctp-chunk-type.c \ + detect-sctp-vtag.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 135795d358..d73076ae9f 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -158,6 +158,7 @@ #include "detect-sctphdr.h" #include "detect-sctp-chunk-type.h" #include "detect-sctp-chunk-cnt.h" +#include "detect-sctp-vtag.h" #include "detect-urilen.h" #include "detect-bsize.h" #include "detect-detection-filter.h" @@ -682,6 +683,7 @@ void SigTableSetup(void) DetectSCTPHdrRegister(); DetectSCTPChunkTypeRegister(); DetectSCTPChunkCntRegister(); + DetectSCTPVtagRegister(); DetectTlsRegister(); DetectTlsValidityRegister(); DetectTlsVersionRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 814643b04e..d8e3e11515 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -54,6 +54,7 @@ enum DetectKeywordId { DETECT_SCTPHDR, DETECT_SCTP_CHUNK_TYPE, DETECT_SCTP_CHUNK_CNT, + DETECT_SCTP_VTAG, DETECT_DSIZE, DETECT_FLOW, diff --git a/src/detect-sctp-vtag.c b/src/detect-sctp-vtag.c new file mode 100644 index 0000000000..f0a1983f8f --- /dev/null +++ b/src/detect-sctp-vtag.c @@ -0,0 +1,129 @@ +/* Copyright (C) 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 + * 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 + * + * Implements sctp.vtag keyword + * + * Author: Giuseppe Longo + */ + +#include "suricata-common.h" +#include "decode.h" + +#include "detect.h" +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-prefilter.h" +#include "detect-engine-prefilter-common.h" +#include "detect-engine-build.h" +#include "detect-engine-uint.h" + +#include "detect-sctp-vtag.h" + +#include "util-debug.h" + +static int DetectSCTPVtagSetup(DetectEngineCtx *, Signature *, const char *); +static int DetectSCTPVtagMatch( + DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *); +static void DetectSCTPVtagFree(DetectEngineCtx *, void *); +static int PrefilterSetupSCTPVtag(DetectEngineCtx *de_ctx, SigGroupHead *sgh); +static bool PrefilterSCTPVtagIsPrefilterable(const Signature *s); + +#ifdef UNITTESTS +void DetectSCTPVtagRegisterTests(void); +#endif + +void DetectSCTPVtagRegister(void) +{ + sigmatch_table[DETECT_SCTP_VTAG].name = "sctp.vtag"; + sigmatch_table[DETECT_SCTP_VTAG].desc = "match on the SCTP verification tag"; + sigmatch_table[DETECT_SCTP_VTAG].url = "/rules/sctp-keywords.html#sctp-vtag"; + sigmatch_table[DETECT_SCTP_VTAG].Match = DetectSCTPVtagMatch; + sigmatch_table[DETECT_SCTP_VTAG].Setup = DetectSCTPVtagSetup; + sigmatch_table[DETECT_SCTP_VTAG].Free = DetectSCTPVtagFree; + sigmatch_table[DETECT_SCTP_VTAG].flags = SIGMATCH_INFO_UINT32; + sigmatch_table[DETECT_SCTP_VTAG].SupportsPrefilter = PrefilterSCTPVtagIsPrefilterable; + sigmatch_table[DETECT_SCTP_VTAG].SetupPrefilter = PrefilterSetupSCTPVtag; +} + +static int DetectSCTPVtagMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) +{ + const DetectU32Data *data = (const DetectU32Data *)ctx; + + DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p)); + + if (!(PacketIsSCTP(p))) { + return 0; + } + + return DetectU32Match(SCTP_GET_RAW_VTAG(PacketGetSCTP(p)), data); +} + +static int DetectSCTPVtagSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr) +{ + DetectU32Data *data = SCDetectU32Parse(optstr); + if (data == NULL) + return -1; + + if (SCSigMatchAppendSMToList( + de_ctx, s, DETECT_SCTP_VTAG, (SigMatchCtx *)data, DETECT_SM_LIST_MATCH) == NULL) { + DetectSCTPVtagFree(de_ctx, data); + return -1; + } + s->flags |= SIG_FLAG_REQUIRE_PACKET; + return 0; +} + +static void DetectSCTPVtagFree(DetectEngineCtx *de_ctx, void *ptr) +{ + SCDetectU32Free(ptr); +} + +static void PrefilterPacketSCTPVtagMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) +{ + const PrefilterPacketHeaderCtx *ctx = pectx; + + DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p)); + if (!PrefilterPacketHeaderExtraMatch(ctx, p)) + return; + + if (p->proto == IPPROTO_SCTP && PacketIsSCTP(p)) { + DetectU32Data du32; + du32.mode = ctx->v1.u8[0]; + du32.arg1 = ctx->v1.u32[1]; + du32.arg2 = ctx->v1.u32[2]; + if (DetectU32Match(SCTP_GET_RAW_VTAG(PacketGetSCTP(p)), &du32)) { + SCLogDebug("packet matches SCTP vtag %u", ctx->v1.u32[0]); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } + } +} + +static int PrefilterSetupSCTPVtag(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_SCTP_VTAG, SIG_MASK_REQUIRE_REAL_PKT, + PrefilterPacketU32Set, PrefilterPacketU32Compare, PrefilterPacketSCTPVtagMatch); +} + +static bool PrefilterSCTPVtagIsPrefilterable(const Signature *s) +{ + return PrefilterIsPrefilterableById(s, DETECT_SCTP_VTAG); +} diff --git a/src/detect-sctp-vtag.h b/src/detect-sctp-vtag.h new file mode 100644 index 0000000000..a9decaa122 --- /dev/null +++ b/src/detect-sctp-vtag.h @@ -0,0 +1,27 @@ +/* Copyright (C) 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 + * 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 + */ + +#ifndef SURICATA_DETECT_SCTP_VTAG_H +#define SURICATA_DETECT_SCTP_VTAG_H + +void DetectSCTPVtagRegister(void); + +#endif /* SURICATA_DETECT_SCTP_VTAG_H */