You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/detect-template.c

218 lines
6.8 KiB
C

/* Copyright (C) 2015-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 XXX Yourname <youremail@yourdomain>
*
* XXX Short description of the purpose of this keyword
*/
#include "suricata-common.h"
#include "util-unittest.h"
#include "util-byte.h"
#include "detect-parse.h"
#include "detect-engine.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
*
* \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
*
* \retval 0 no match
* \retval 1 match
*/
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 */
}
if (PKT_IS_IPV4(p)) {
/* ipv4 pkt */
} else if (PKT_IS_IPV6(p)) {
/* ipv6 pkt */
} 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;
}
}
return ret;
}
/**
* \brief This function is used to parse template options passed via template: keyword
*
* \param templatestr Pointer to the user provided template options
*
* \retval templated pointer to DetectTemplateData on success
* \retval NULL on failure
*/
static DetectTemplateData *DetectTemplateParse (const char *templatestr)
{
char arg1[4] = "";
char arg2[4] = "";
int ov[MAX_SUBSTRINGS];
int ret = DetectParsePcreExec(&parse_regex, templatestr, 0, 0, ov, MAX_SUBSTRINGS);
if (ret != 3) {
SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
return NULL;
}
ret = pcre_copy_substring((char *) templatestr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1));
if (ret < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
return NULL;
}
SCLogDebug("Arg1 \"%s\"", arg1);
ret = pcre_copy_substring((char *) templatestr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2));
if (ret < 0) {
SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
return NULL;
}
SCLogDebug("Arg2 \"%s\"", arg2);
DetectTemplateData *templated = SCMalloc(sizeof (DetectTemplateData));
if (unlikely(templated == NULL))
return NULL;
if (ByteExtractStringUint8(&templated->arg1, 10, 0, (const char *)arg1) < 0) {
SCFree(templated);
return NULL;
}
if (ByteExtractStringUint8(&templated->arg2, 10, 0, (const char *)arg2) < 0) {
SCFree(templated);
return NULL;
}
return templated;
}
/**
* \brief parse the options from the 'template' keyword in the rule into
* the Signature data structure.
*
* \param de_ctx pointer to the Detection Engine Context
* \param s pointer to the Current Signature
* \param templatestr pointer to the user provided template options
*
* \retval 0 on Success
* \retval -1 on Failure
*/
static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *templatestr)
{
DetectTemplateData *templated = DetectTemplateParse(templatestr);
if (templated == NULL)
return -1;
SigMatch *sm = SigMatchAlloc();
if (sm == NULL) {
DetectTemplateFree(de_ctx, templated);
return -1;
}
sm->type = DETECT_TEMPLATE;
sm->ctx = (void *)templated;
SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
s->flags |= SIG_FLAG_REQUIRE_PACKET;
return 0;
}
/**
* \brief this function will free memory associated with DetectTemplateData
*
* \param ptr pointer to DetectTemplateData
*/
static void DetectTemplateFree(DetectEngineCtx *de_ctx, void *ptr)
{
DetectTemplateData *templated = (DetectTemplateData *)ptr;
/* do more specific cleanup here, if needed */
SCFree(templated);
}
#ifdef UNITTESTS
#include "tests/detect-template.c"
#endif