From: Philippe Antoine Date: Thu, 5 Mar 2020 21:18:57 +0000 (+0100) Subject: detect: adds icmpv6.mtu keyword X-Git-Tag: suricata-6.0.0-beta1~628 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1cd314c500d684b382feb55c3d297b00665d630b;p=thirdparty%2Fsuricata.git detect: adds icmpv6.mtu keyword --- diff --git a/doc/userguide/rules/header-keywords.rst b/doc/userguide/rules/header-keywords.rst index a5d9fba724..d84009b71e 100644 --- a/doc/userguide/rules/header-keywords.rst +++ b/doc/userguide/rules/header-keywords.rst @@ -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:-; + icmpv6.mtu:[<|>]; + icmpv6.mtu:; + +Example rule: + +.. container:: example-rule + + alert ip $EXTERNAL_NET any -> $HOME_NET any (:example-rule-emphasis:`icmpv6.mtu:<1280;` sid:1234; rev:5;) diff --git a/src/Makefile.am b/src/Makefile.am index 82e59aa776..282861d36d 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/decode-icmpv6.h b/src/decode-icmpv6.h index 2da2767ec4..39b2e3d478 100644 --- a/src/decode-icmpv6.h +++ b/src/decode-icmpv6.h @@ -117,6 +117,9 @@ #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) diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 21e436d71b..35e5b21009 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -174,6 +174,7 @@ #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(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 55e6603907..f6ca2e1e4e 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -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 index 0000000000..916f7e8e6d --- /dev/null +++ b/src/detect-icmpv6-mtu.c @@ -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 + * + */ + +#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 index 0000000000..1c5eb97070 --- /dev/null +++ b/src/detect-icmpv6-mtu.h @@ -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 + */ + +#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 index 0000000000..241a221d72 --- /dev/null +++ b/src/tests/detect-icmpv6-mtu.c @@ -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); +}