]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect: adds icmpv6.mtu keyword
authorPhilippe Antoine <contact@catenacyber.fr>
Thu, 5 Mar 2020 21:18:57 +0000 (22:18 +0100)
committerVictor Julien <victor@inliniac.net>
Thu, 19 Mar 2020 08:31:22 +0000 (09:31 +0100)
doc/userguide/rules/header-keywords.rst
src/Makefile.am
src/decode-icmpv6.h
src/detect-engine-register.c
src/detect-engine-register.h
src/detect-icmpv6-mtu.c [new file with mode: 0644]
src/detect-icmpv6-mtu.h [new file with mode: 0644]
src/tests/detect-icmpv6-mtu.c [new file with mode: 0644]

index a5d9fba7247a297858fad216fc068ea6111095df..d84009b71e5edbb46bcf1e69a7624121871b70c9 100644 (file)
@@ -626,3 +626,21 @@ icmpv6.hdr
 ^^^^^^^^^^
 
 Sticky buffer to match on the whole ICMPv6 header.
+
+icmpv6.mtu
+^^^^^^^^^^
+
+Match on the ICMPv6 MTU optional value. Will not match if the MTU is not
+present.
+
+The format of the keyword::
+
+  icmpv6.mtu:<min>-<max>;
+  icmpv6.mtu:[<|>]<number>;
+  icmpv6.mtu:<value>;
+
+Example rule:
+
+.. container:: example-rule
+
+    alert ip $EXTERNAL_NET any -> $HOME_NET any (:example-rule-emphasis:`icmpv6.mtu:<1280;` sid:1234; rev:5;)
index 82e59aa7760ea7a1321540e67402817497997b02..282861d36d1da3402602a2fe8cc68717a0a41f1a 100755 (executable)
@@ -200,6 +200,7 @@ detect-http-uri.c detect-http-uri.h \
 detect-icmp-id.c detect-icmp-id.h \
 detect-icmp-seq.c detect-icmp-seq.h \
 detect-icmpv6hdr.c detect-icmpv6hdr.h \
+detect-icmpv6-mtu.c detect-icmpv6-mtu.h \
 detect-icode.c detect-icode.h \
 detect-id.c detect-id.h \
 detect-ipopts.c detect-ipopts.h \
index 2da2767ec4c280fed150503a27cbb6f52165a0e9..39b2e3d47879f73843fedbe149987c95ce5b9e27 100644 (file)
 #define ICMPV6_GET_UNUSED(p)       (p)->icmpv6h->icmpv6b.icmpv6e.unused
 /** macro for icmpv6 "error_ptr" access */
 #define ICMPV6_GET_ERROR_PTR(p)    (p)->icmpv6h->icmpv6b.icmpv6e.error_ptr
+/** macro for icmpv6 "mtu" accessibility */
+// ICMPv6 has MTU only for type too big
+#define ICMPV6_HAS_MTU(p)          ((p)->icmpv6h->type == ICMP6_PACKET_TOO_BIG)
 /** macro for icmpv6 "mtu" access */
 #define ICMPV6_GET_MTU(p)          SCNtohl((p)->icmpv6h->icmpv6b.icmpv6e.mtu)
 
index 21e436d71b39bc2ede9504fff75c20308c7af495..35e5b21009818b191a7dfdb0b9ef0d6b7fd9b909 100644 (file)
 #include "detect-tcpmss.h"
 #include "detect-udphdr.h"
 #include "detect-icmpv6hdr.h"
+#include "detect-icmpv6-mtu.h"
 #include "detect-ipv4hdr.h"
 #include "detect-ipv6hdr.h"
 #include "detect-krb5-cname.h"
@@ -547,6 +548,7 @@ void SigTableSetup(void)
     DetectUdphdrRegister();
     DetectTcpmssRegister();
     DetectICMPv6hdrRegister();
+    DetectICMPv6mtuRegister();
     DetectIpv4hdrRegister();
     DetectIpv6hdrRegister();
     DetectKrb5CNameRegister();
index 55e66039075b5b2d26708883286841b02d45ded2..f6ca2e1e4e2f4db8c4da490249bf20b265c6751d 100644 (file)
@@ -239,6 +239,7 @@ enum DetectKeywordId {
     DETECT_IPV4HDR,
     DETECT_IPV6HDR,
     DETECT_ICMPV6HDR,
+    DETECT_ICMPV6MTU,
     DETECT_TCPHDR,
     DETECT_UDPHDR,
     DETECT_TCPMSS,
diff --git a/src/detect-icmpv6-mtu.c b/src/detect-icmpv6-mtu.c
new file mode 100644 (file)
index 0000000..916f7e8
--- /dev/null
@@ -0,0 +1,189 @@
+/* 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 Philippe Antoine <p.antoine@catenacyber.fr>
+ *
+ */
+
+#include "suricata-common.h"
+
+#include "detect.h"
+#include "detect-parse.h"
+
+#include "detect-icmpv6-mtu.h"
+#include "detect-engine-uint.h"
+
+/* prototypes */
+static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *, Packet *,
+        const Signature *, const SigMatchCtx *);
+static int DetectICMPv6mtuSetup (DetectEngineCtx *, Signature *, const char *);
+void DetectICMPv6mtuFree (void *);
+#ifdef UNITTESTS
+void DetectICMPv6mtuRegisterTests (void);
+#endif
+static int PrefilterSetupIcmpv6mtu(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
+static bool PrefilterIcmpv6mtuIsPrefilterable(const Signature *s);
+
+/**
+ * \brief Registration function for icmpv6.mtu: keyword
+ */
+
+void DetectICMPv6mtuRegister(void)
+{
+    sigmatch_table[DETECT_ICMPV6MTU].name = "icmpv6.mtu";
+    sigmatch_table[DETECT_ICMPV6MTU].desc = "match on ICMPv6 MTU field";
+    sigmatch_table[DETECT_ICMPV6MTU].url = DOC_URL DOC_VERSION "/rules/header-keywords.html#icmpv6mtu";
+    sigmatch_table[DETECT_ICMPV6MTU].Match = DetectICMPv6mtuMatch;
+    sigmatch_table[DETECT_ICMPV6MTU].Setup = DetectICMPv6mtuSetup;
+    sigmatch_table[DETECT_ICMPV6MTU].Free = DetectICMPv6mtuFree;
+#ifdef UNITTESTS
+    sigmatch_table[DETECT_ICMPV6MTU].RegisterTests = DetectICMPv6mtuRegisterTests;
+#endif
+    sigmatch_table[DETECT_ICMPV6MTU].SupportsPrefilter = PrefilterIcmpv6mtuIsPrefilterable;
+    sigmatch_table[DETECT_ICMPV6MTU].SetupPrefilter = PrefilterSetupIcmpv6mtu;
+
+    DetectU32Register();
+    return;
+}
+
+// returns 0 on no mtu, and 1 if mtu
+static inline int DetectICMPv6mtuGetValue(Packet *p, uint32_t *picmpv6mtu)
+{
+    if (!(PKT_IS_ICMPV6(p)) || PKT_IS_PSEUDOPKT(p))
+        return 0;
+    if (ICMPV6_GET_CODE(p) != 0)
+        return 0;
+    if (!(ICMPV6_HAS_MTU(p)))
+        return 0;
+
+    *picmpv6mtu = ICMPV6_GET_MTU(p);
+    return 1;
+}
+
+/**
+ * \brief This function is used to match ICMPV6 MTU rule option on a packet with those passed via icmpv6.mtu:
+ *
+ * \param det_ctx pointer to the pattern matcher thread
+ * \param p pointer to the current packet
+ * \param s pointer to the signature unused
+ * \param ctx pointer to the signature match context
+ *
+ * \retval 0 no match
+ * \retval 1 match
+ */
+static int DetectICMPv6mtuMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
+        const Signature *s, const SigMatchCtx *ctx)
+{
+    uint32_t picmpv6mtu;
+    if (DetectICMPv6mtuGetValue(p, &picmpv6mtu) == 0) {
+        return 0;
+    }
+
+    const DetectU32Data *du32 = (const DetectU32Data *)ctx;
+    return DetectU32Match(picmpv6mtu, du32);
+}
+
+/**
+ * \brief this function is used to attach the parsed icmpv6.mtu data into the current signature
+ *
+ * \param de_ctx pointer to the Detection Engine Context
+ * \param s pointer to the Current Signature
+ * \param icmpv6mtustr pointer to the user provided icmpv6.mtu options
+ *
+ * \retval 0 on Success
+ * \retval -1 on Failure
+ */
+static int DetectICMPv6mtuSetup (DetectEngineCtx *de_ctx, Signature *s, const char *icmpv6mtustr)
+{
+    DetectU32Data *icmpv6mtud = DetectU32Parse(icmpv6mtustr);
+    if (icmpv6mtud == NULL)
+        return -1;
+
+    SigMatch *sm = SigMatchAlloc();
+    if (sm == NULL) {
+        DetectICMPv6mtuFree(icmpv6mtud);
+        return -1;
+    }
+
+    sm->type = DETECT_ICMPV6MTU;
+    sm->ctx = (SigMatchCtx *)icmpv6mtud;
+
+    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
+    s->flags |= SIG_FLAG_REQUIRE_PACKET;
+    s->proto.flags |= DETECT_PROTO_IPV6;
+
+    return 0;
+}
+
+/**
+ * \brief this function will free memory associated with DetectU32Data
+ *
+ * \param ptr pointer to DetectU32Data
+ */
+void DetectICMPv6mtuFree(void *ptr)
+{
+    SCFree(ptr);
+}
+
+/* prefilter code */
+
+static void
+PrefilterPacketIcmpv6mtuMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
+{
+    uint32_t picmpv6mtu;
+    if (DetectICMPv6mtuGetValue(p, &picmpv6mtu) == 0) {
+        return;
+    }
+
+    /* during setup Suricata will automatically see if there is another
+     * check that can be added: alproto, sport or dport */
+    const PrefilterPacketHeaderCtx *ctx = pectx;
+    if (PrefilterPacketHeaderExtraMatch(ctx, p) == FALSE)
+        return;
+
+    /* if we match, add all the sigs that use this prefilter. This means
+     * that these will be inspected further */
+    DetectU32Data du32;
+    du32.mode = ctx->v1.u8[0];
+    du32.arg1 = ctx->v1.u32[1];
+    du32.arg2 = ctx->v1.u32[2];
+    if (DetectU32Match(picmpv6mtu, &du32))
+    {
+        SCLogDebug("packet matches icmpv6.mtu/hl %u", picmpv6mtu);
+        PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt);
+    }
+}
+
+static int PrefilterSetupIcmpv6mtu(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
+{
+    return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_ICMPV6MTU,
+            PrefilterPacketU32Set,
+            PrefilterPacketU32Compare,
+            PrefilterPacketIcmpv6mtuMatch);
+}
+
+static bool PrefilterIcmpv6mtuIsPrefilterable(const Signature *s)
+{
+    return PrefilterIsPrefilterableById(s, DETECT_ICMPV6MTU);
+}
+
+#ifdef UNITTESTS
+#include "tests/detect-icmpv6-mtu.c"
+#endif
diff --git a/src/detect-icmpv6-mtu.h b/src/detect-icmpv6-mtu.h
new file mode 100644 (file)
index 0000000..1c5eb97
--- /dev/null
@@ -0,0 +1,29 @@
+/* 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 Philippe Antoine <p.antoine@catenacyber.fr>
+ */
+
+#ifndef _DETECT_ICPMV6_MTU_H
+#define _DETECT_ICPMV6_MTU_H
+
+void DetectICMPv6mtuRegister(void);
+
+#endif /* _DETECT_ICPMV6_MTU_H */
diff --git a/src/tests/detect-icmpv6-mtu.c b/src/tests/detect-icmpv6-mtu.c
new file mode 100644 (file)
index 0000000..241a221
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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.
+ */
+
+#include "../suricata-common.h"
+
+#include "../detect-engine.h"
+
+#include "../detect-icmpv6-mtu.h"
+
+#include "../util-unittest.h"
+
+/**
+ * \test signature with a valid icmpv6.mtu value.
+ */
+
+static int DetectICMPv6mtuParseTest01 (void)
+{
+    DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+    FAIL_IF_NULL(de_ctx);
+
+    Signature *sig = DetectEngineAppendSig(de_ctx,
+            "alert ip any any -> any any (icmpv6.mtu:<1280; sid:1; rev:1;)");
+    FAIL_IF_NULL(sig);
+
+    DetectEngineCtxFree(de_ctx);
+    PASS;
+
+}
+
+/**
+ * \brief this function registers unit tests for DetectICMPv6mtu
+ */
+void DetectICMPv6mtuRegisterTests(void)
+{
+    UtRegisterTest("DetectICMPv6mtuParseTest01", DetectICMPv6mtuParseTest01);
+}