diff --git a/scripts/setup-simple-detect2.sh b/scripts/setup-simple-detect2.sh deleted file mode 100755 index 7790de0cde..0000000000 --- a/scripts/setup-simple-detect2.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env bash -# -# Script to setup a new 'simple' detect module. -# Written by Victor Julien -# - -set -e -#set -x - -function Usage { - echo - echo "$(basename $0) -- script to provision a detect module. The script" - echo "makes a copy of detect-template, sets the name and updates" - echo "the build system." - echo - echo "Call from the 'src' directory, with one argument: the detect module" - echo "name." - echo - echo "E.g. inside 'src': ../scripts/$(basename $0) helloworld" - echo -} - -function Done { - echo - echo "Detect module $NR has been set up in $FILE_C and $FILE_H" - echo "and the build system has been updated." - echo - echo "The detect module should now compile cleanly. Try running 'make'." - echo - echo "Next steps are to edit the files to implement the actual" - echo "detection logic of $NR." - echo -} - -# Make sure we are running from the correct directory. -set_dir() { - if [ -e ./suricata.c ]; then - # Do nothing. - true - elif [ -e ./src/suricata.c ]; then - cd src - else - echo "error: this does not appear to be a suricata source directory." - exit 1 - fi -} - -if [ $# -ne "1" ]; then - Usage - echo "ERROR: call with one argument" - exit 1 -fi - -INPUT=$1 -# lowercase -LC=${INPUT,,} -#echo $LC -# UPPERCASE -UC=${LC^^} -#echo $UC -# Normal -NR=${LC^} -#echo $NR - -FILE_C="detect-${LC}.c" -FILE_H="detect-${LC}.h" - -set_dir - -if [ ! -e detect-template2.c ] || [ ! -e detect-template2.h ]; then - Usage - echo "ERROR: input files detect-template.c and/or detect-template.h are missing" - exit 1 -fi -if [ -e $FILE_C ] || [ -e $FILE_H ]; then - Usage - echo "ERROR: file(s) $FILE_C and/or $FILE_H already exist, won't overwrite" - exit 1 -fi - -FILE_C="detect-${LC}.c" -FILE_H="detect-${LC}.h" -cp detect-template2.c $FILE_C -cp detect-template2.h $FILE_H - -# search and replaces -sed -i "s/TEMPLATE2/${UC}/g" $FILE_C -sed -i "s/TEMPLATE2/${UC}/g" $FILE_H -sed -i "s/Template2/${NR}/g" $FILE_C -sed -i "s/Template2/${NR}/g" $FILE_H -sed -i "s/template2/${LC}/g" $FILE_C -sed -i "s/template2/${LC}/g" $FILE_H -# add to Makefile.am -sed -i "s/detect-template2.c detect-template2.h \\\/detect-template2.c detect-template2.h \\\\\n${FILE_C} ${FILE_H} \\\/g" Makefile.am - -# update enum -sed -i "s/DETECT_TEMPLATE2,/DETECT_TEMPLATE2,\\n DETECT_${UC},/g" detect-engine-register.h - -# add include to detect-engine-register.c -sed -i "s/#include \"detect-template2.h\"/#include \"detect-template2.h\"\\n#include \"${FILE_H}\"/g" detect-engine-register.c - -# add reg func to detect-engine-register.c -sed -i "s/DetectTemplate2Register();/DetectTemplate2Register();\\n Detect${NR}Register();/g" detect-engine-register.c - -Done -exit 0 diff --git a/src/Makefile.am b/src/Makefile.am index 9baf63ebcc..f621901875 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -285,7 +285,6 @@ noinst_HEADERS = \ detect-tcphdr.h \ detect-tcpmss.h \ detect-template.h \ - detect-template2.h \ detect-threshold.h \ detect-tls-alpn.h \ detect-tls-cert-fingerprint.h \ @@ -866,7 +865,6 @@ libsuricata_c_a_SOURCES = \ detect-tcphdr.c \ detect-tcpmss.c \ detect-template.c \ - detect-template2.c \ detect-threshold.c \ detect-tls-alpn.c \ detect-tls-cert-fingerprint.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 536715c7f5..253be9dc57 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -187,7 +187,6 @@ #include "detect-geoip.h" #include "detect-app-layer-protocol.h" #include "detect-template.h" -#include "detect-template2.h" #include "detect-tcphdr.h" #include "detect-tcpmss.h" #include "detect-udphdr.h" @@ -692,7 +691,6 @@ void SigTableSetup(void) DetectBase64DecodeRegister(); DetectBase64DataRegister(); DetectTemplateRegister(); - DetectTemplate2Register(); DetectTcphdrRegister(); DetectUdphdrRegister(); DetectTcpmssRegister(); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index 84c904a395..4da0c7d002 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -265,7 +265,6 @@ enum DetectKeywordId { DETECT_SIP_METHOD, DETECT_SIP_URI, DETECT_TEMPLATE, - DETECT_TEMPLATE2, DETECT_ETHERHDR, DETECT_IPV4HDR, DETECT_IPV6HDR, diff --git a/src/detect-template.c b/src/detect-template.c index c8c32bdaf3..9c91d82a60 100644 --- a/src/detect-template.c +++ b/src/detect-template.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2015-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 @@ -18,166 +18,70 @@ /** * \file * - * \author XXX Yourname + * \author XXX * * XXX Short description of the purpose of this keyword */ #include "suricata-common.h" -#include "util-unittest.h" -#include "util-byte.h" +#include "detect.h" #include "detect-parse.h" -#include "detect-engine.h" +#include "detect-engine-prefilter-common.h" +#include "detect-engine-uint.h" #include "detect-template.h" -/** - * \brief Regex for parsing our keyword options - */ -#define PARSE_REGEX "^\\s*([0-9]+)?\\s*,s*([0-9]+)?\\s*$" -static DetectParseRegex parse_regex; - -/* Prototypes of functions registered in DetectTemplateRegister below */ -static int DetectTemplateMatch (DetectEngineThreadCtx *, - Packet *, const Signature *, const SigMatchCtx *); -static int DetectTemplateSetup (DetectEngineCtx *, Signature *, const char *); -static void DetectTemplateFree (DetectEngineCtx *, void *); #ifdef UNITTESTS static void DetectTemplateRegisterTests (void); #endif /** - * \brief Registration function for template: keyword - * - * This function is called once in the 'lifetime' of the engine. - */ -void DetectTemplateRegister(void) { - /* keyword name: this is how the keyword is used in a rule */ - sigmatch_table[DETECT_TEMPLATE].name = "template"; - /* description: listed in "suricata --list-keywords=all" */ - sigmatch_table[DETECT_TEMPLATE].desc = "give an introduction into how a detection module works"; - /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */ - sigmatch_table[DETECT_TEMPLATE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Developers_Guide"; - /* match function is called when the signature is inspected on a packet */ - sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch; - /* setup function is called during signature parsing, when the template - * keyword is encountered in the rule */ - sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup; - /* free function is called when the detect engine is freed. Normally at - * shutdown, but also during rule reloads. */ - sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree; -#ifdef UNITTESTS - /* registers unittests into the system */ - sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; -#endif - /* set up the PCRE for keyword parsing */ - DetectSetupParseRegexes(PARSE_REGEX, &parse_regex); -} - -/** - * \brief This function is used to match TEMPLATE rule option on a packet + * \brief This function is used to match TEMPLATE rule option on a packet with those passed via + * template: * * \param t pointer to thread vars * \param det_ctx pointer to the pattern matcher thread * \param p pointer to the current packet - * \param m pointer to the sigmatch with context that we will cast into DetectTemplateData + * \param m pointer to the sigmatch that we will cast into DetectU8Data * * \retval 0 no match * \retval 1 match */ -static int DetectTemplateMatch (DetectEngineThreadCtx *det_ctx, Packet *p, - const Signature *s, const SigMatchCtx *ctx) +static int DetectTemplateMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const Signature *s, const SigMatchCtx *ctx) { - int ret = 0; - const DetectTemplateData *templated = (const DetectTemplateData *) ctx; -#if 0 - if (PKT_IS_PSEUDOPKT(p)) { - /* fake pkt */ - } + DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p)); + /* TODO replace this */ + uint8_t ptemplate; if (PacketIsIPv4(p)) { - /* ipv4 pkt */ + const IPV4Hdr *ip4h = PacketGetIPv4(p); + ptemplate = IPV4_GET_RAW_IPTTL(ip4h); } else if (PacketIsIPv6(p)) { - /* ipv6 pkt */ + const IPV6Hdr *ip6h = PacketGetIPv6(p); + ptemplate = IPV6_GET_RAW_HLIM(ip6h); } else { - SCLogDebug("packet is of not IPv4 or IPv6"); - return ret; - } -#endif - /* packet payload access */ - if (p->payload != NULL && p->payload_len > 0) { - if (templated->arg1 == p->payload[0] && - templated->arg2 == p->payload[p->payload_len - 1]) - { - ret = 1; - } + SCLogDebug("Packet is of not IPv4 or IPv6"); + return 0; } - return ret; + const DetectU8Data *templated = (const DetectU8Data *)ctx; + return DetectU8Match(ptemplate, templated); } /** - * \brief This function is used to parse template options passed via template: keyword + * \brief this function will free memory associated with DetectU8Data * - * \param templatestr Pointer to the user provided template options - * - * \retval templated pointer to DetectTemplateData on success - * \retval NULL on failure + * \param ptr pointer to DetectU8Data */ -static DetectTemplateData *DetectTemplateParse (const char *templatestr) +static void DetectTemplateFree(DetectEngineCtx *de_ctx, void *ptr) { - char arg1[4] = ""; - char arg2[4] = ""; - - pcre2_match_data *match = NULL; - int ret = DetectParsePcreExec(&parse_regex, &match, templatestr, 0, 0); - if (ret != 3) { - SCLogError("parse error, ret %" PRId32 "", ret); - goto error; - } - - size_t pcre2len = sizeof(arg1); - ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("Arg1 \"%s\"", arg1); - - pcre2len = sizeof(arg2); - ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len); - if (ret < 0) { - SCLogError("pcre2_substring_copy_bynumber failed"); - goto error; - } - SCLogDebug("Arg2 \"%s\"", arg2); - - DetectTemplateData *templated = SCMalloc(sizeof (DetectTemplateData)); - if (unlikely(templated == NULL)) - goto error; - - if (ByteExtractStringUint8(&templated->arg1, 10, 0, (const char *)arg1) < 0) { - SCFree(templated); - goto error; - } - if (ByteExtractStringUint8(&templated->arg2, 10, 0, (const char *)arg2) < 0) { - SCFree(templated); - goto error; - } - pcre2_match_data_free(match); - return templated; - -error: - if (match) { - pcre2_match_data_free(match); - } - return NULL; + SCDetectU8Free(ptr); } /** - * \brief parse the options from the 'template' keyword in the rule into - * the Signature data structure. + * \brief this function is used to add the parsed template data into the current signature * * \param de_ctx pointer to the Detection Engine Context * \param s pointer to the Current Signature @@ -188,7 +92,7 @@ error: */ static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *templatestr) { - DetectTemplateData *templated = DetectTemplateParse(templatestr); + DetectU8Data *templated = DetectU8Parse(templatestr); if (templated == NULL) return -1; @@ -202,18 +106,82 @@ static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, const cha return 0; } -/** - * \brief this function will free memory associated with DetectTemplateData - * - * \param ptr pointer to DetectTemplateData - */ -static void DetectTemplateFree(DetectEngineCtx *de_ctx, void *ptr) +/* prefilter code */ + +static void PrefilterPacketTemplateMatch( + DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx) { - DetectTemplateData *templated = (DetectTemplateData *)ptr; + DEBUG_VALIDATE_BUG_ON(PKT_IS_PSEUDOPKT(p)); - /* do more specific cleanup here, if needed */ + uint8_t ptemplate; + /* TODO update */ + if (PacketIsIPv4(p)) { + const IPV4Hdr *ip4h = PacketGetIPv4(p); + ptemplate = IPV4_GET_RAW_IPTTL(ip4h); + } else if (PacketIsIPv6(p)) { + const IPV6Hdr *ip6h = PacketGetIPv6(p); + ptemplate = IPV6_GET_RAW_HLIM(ip6h); + } else { + SCLogDebug("Packet is of not IPv4 or IPv6"); + return; + } - SCFree(templated); + /* 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)) + return; + + DetectU8Data du8; + du8.mode = ctx->v1.u8[0]; + du8.arg1 = ctx->v1.u8[1]; + du8.arg2 = ctx->v1.u8[2]; + /* if we match, add all the sigs that use this prefilter. This means + * that these will be inspected further */ + if (DetectU8Match(ptemplate, &du8)) { + SCLogDebug("packet matches template/hl %u", ptemplate); + PrefilterAddSids(&det_ctx->pmq, ctx->sigs_array, ctx->sigs_cnt); + } +} + +static int PrefilterSetupTemplate(DetectEngineCtx *de_ctx, SigGroupHead *sgh) +{ + return PrefilterSetupPacketHeader(de_ctx, sgh, DETECT_TEMPLATE, SIG_MASK_REQUIRE_REAL_PKT, + PrefilterPacketU8Set, PrefilterPacketU8Compare, PrefilterPacketTemplateMatch); +} + +static bool PrefilterTemplateIsPrefilterable(const Signature *s) +{ + return PrefilterIsPrefilterableById(s, DETECT_TEMPLATE); +} + +/** + * \brief Registration function for template: keyword + */ + +void DetectTemplateRegister(void) +{ + /* keyword name: this is how the keyword is used in a rule */ + sigmatch_table[DETECT_TEMPLATE].name = "template"; + /* description: listed in "suricata --list-keywords=all" */ + sigmatch_table[DETECT_TEMPLATE].desc = "TODO describe the keyword"; + /* link to further documentation of the keyword. */ + sigmatch_table[DETECT_TEMPLATE].url = "/rules/header-keywords.html#template"; + /* match function is called when the signature is inspected on a packet */ + sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch; + /* setup function is called during signature parsing, when the template + * keyword is encountered in the rule */ + sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup; + /* free function is called when the detect engine is freed. Normally at + * shutdown, but also during rule reloads. */ + sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree; + sigmatch_table[DETECT_TEMPLATE].SupportsPrefilter = PrefilterTemplateIsPrefilterable; + sigmatch_table[DETECT_TEMPLATE].SetupPrefilter = PrefilterSetupTemplate; + sigmatch_table[DETECT_TEMPLATE].flags = SIGMATCH_INFO_UINT8; +#ifdef UNITTESTS + /* registers unittests into the system */ + sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests; +#endif } #ifdef UNITTESTS diff --git a/src/detect-template.h b/src/detect-template.h index 9d510804a3..26b0afc877 100644 --- a/src/detect-template.h +++ b/src/detect-template.h @@ -24,16 +24,6 @@ #ifndef SURICATA_DETECT_TEMPLATE_H #define SURICATA_DETECT_TEMPLATE_H -/** Per keyword data. This is set up by the DetectTemplateSetup() function. - * Each signature will have an instance of DetectTemplateData per occurrence - * of the keyword. - * The structure should be considered static/readonly after initialization. - */ -typedef struct DetectTemplateData_ { - uint8_t arg1; - uint8_t arg2; -} DetectTemplateData; - /** \brief registers the keyword into the engine. Called from * detect.c::SigTableSetup() */ void DetectTemplateRegister(void); diff --git a/src/detect-template2.h b/src/detect-template2.h deleted file mode 100644 index b7ea8af34a..0000000000 --- a/src/detect-template2.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright (C) 2007-2018 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 XXX - */ - -#ifndef _DETECT_TEMPLATE2_H -#define _DETECT_TEMPLATE2_H - - -void DetectTemplate2Register(void); - -#endif /* _DETECT_TEMPLATE2_H */ - diff --git a/src/tests/detect-template.c b/src/tests/detect-template.c index c91a463b19..2fa099642e 100644 --- a/src/tests/detect-template.c +++ b/src/tests/detect-template.c @@ -29,9 +29,9 @@ static int DetectTemplateParseTest01 (void) { - DetectTemplateData *templated = DetectTemplateParse("1,10"); + DetectU8Data *templated = DetectU8Parse("10"); FAIL_IF_NULL(templated); - FAIL_IF(!(templated->arg1 == 1 && templated->arg2 == 10)); + FAIL_IF(!(templated->arg1 == 10 && templated->mode == DetectUintModeEqual)); DetectTemplateFree(NULL, templated); PASS; } @@ -45,7 +45,8 @@ static int DetectTemplateSignatureTest01 (void) DetectEngineCtx *de_ctx = DetectEngineCtxInit(); FAIL_IF_NULL(de_ctx); - Signature *sig = DetectEngineAppendSig(de_ctx, "alert ip any any -> any any (template:1,10; sid:1; rev:1;)"); + Signature *sig = DetectEngineAppendSig( + de_ctx, "alert ip any any -> any any (template:<10; sid:1; rev:1;)"); FAIL_IF_NULL(sig); DetectEngineCtxFree(de_ctx);