Coverage Report

Created: 2025-07-23 07:29

/src/suricata7/src/detect-template.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2015-2020 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author XXX Yourname <youremail@yourdomain>
22
 *
23
 * XXX Short description of the purpose of this keyword
24
 */
25
26
#include "suricata-common.h"
27
#include "util-unittest.h"
28
#include "util-byte.h"
29
30
#include "detect-parse.h"
31
#include "detect-engine.h"
32
33
#include "detect-template.h"
34
35
/**
36
 * \brief Regex for parsing our keyword options
37
 */
38
73
#define PARSE_REGEX  "^\\s*([0-9]+)?\\s*,s*([0-9]+)?\\s*$"
39
static DetectParseRegex parse_regex;
40
41
/* Prototypes of functions registered in DetectTemplateRegister below */
42
static int DetectTemplateMatch (DetectEngineThreadCtx *,
43
        Packet *, const Signature *, const SigMatchCtx *);
44
static int DetectTemplateSetup (DetectEngineCtx *, Signature *, const char *);
45
static void DetectTemplateFree (DetectEngineCtx *, void *);
46
#ifdef UNITTESTS
47
static void DetectTemplateRegisterTests (void);
48
#endif
49
50
/**
51
 * \brief Registration function for template: keyword
52
 *
53
 * This function is called once in the 'lifetime' of the engine.
54
 */
55
73
void DetectTemplateRegister(void) {
56
    /* keyword name: this is how the keyword is used in a rule */
57
73
    sigmatch_table[DETECT_TEMPLATE].name = "template";
58
    /* description: listed in "suricata --list-keywords=all" */
59
73
    sigmatch_table[DETECT_TEMPLATE].desc = "give an introduction into how a detection module works";
60
    /* link to further documentation of the keyword. Normally on the Suricata redmine/wiki */
61
73
    sigmatch_table[DETECT_TEMPLATE].url = "https://redmine.openinfosecfoundation.org/projects/suricata/wiki/Suricata_Developers_Guide";
62
    /* match function is called when the signature is inspected on a packet */
63
73
    sigmatch_table[DETECT_TEMPLATE].Match = DetectTemplateMatch;
64
    /* setup function is called during signature parsing, when the template
65
     * keyword is encountered in the rule */
66
73
    sigmatch_table[DETECT_TEMPLATE].Setup = DetectTemplateSetup;
67
    /* free function is called when the detect engine is freed. Normally at
68
     * shutdown, but also during rule reloads. */
69
73
    sigmatch_table[DETECT_TEMPLATE].Free = DetectTemplateFree;
70
#ifdef UNITTESTS
71
    /* registers unittests into the system */
72
    sigmatch_table[DETECT_TEMPLATE].RegisterTests = DetectTemplateRegisterTests;
73
#endif
74
    /* set up the PCRE for keyword parsing */
75
73
    DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
76
73
}
77
78
/**
79
 * \brief This function is used to match TEMPLATE rule option on a packet
80
 *
81
 * \param t pointer to thread vars
82
 * \param det_ctx pointer to the pattern matcher thread
83
 * \param p pointer to the current packet
84
 * \param m pointer to the sigmatch with context that we will cast into DetectTemplateData
85
 *
86
 * \retval 0 no match
87
 * \retval 1 match
88
 */
89
static int DetectTemplateMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
90
                                const Signature *s, const SigMatchCtx *ctx)
91
0
{
92
0
    int ret = 0;
93
0
    const DetectTemplateData *templated = (const DetectTemplateData *) ctx;
94
#if 0
95
    if (PKT_IS_PSEUDOPKT(p)) {
96
        /* fake pkt */
97
    }
98
99
    if (PKT_IS_IPV4(p)) {
100
        /* ipv4 pkt */
101
    } else if (PKT_IS_IPV6(p)) {
102
        /* ipv6 pkt */
103
    } else {
104
        SCLogDebug("packet is of not IPv4 or IPv6");
105
        return ret;
106
    }
107
#endif
108
    /* packet payload access */
109
0
    if (p->payload != NULL && p->payload_len > 0) {
110
0
        if (templated->arg1 == p->payload[0] &&
111
0
            templated->arg2 == p->payload[p->payload_len - 1])
112
0
        {
113
0
            ret = 1;
114
0
        }
115
0
    }
116
117
0
    return ret;
118
0
}
119
120
/**
121
 * \brief This function is used to parse template options passed via template: keyword
122
 *
123
 * \param templatestr Pointer to the user provided template options
124
 *
125
 * \retval templated pointer to DetectTemplateData on success
126
 * \retval NULL on failure
127
 */
128
static DetectTemplateData *DetectTemplateParse (const char *templatestr)
129
381
{
130
381
    char arg1[4] = "";
131
381
    char arg2[4] = "";
132
133
381
    pcre2_match_data *match = NULL;
134
381
    int ret = DetectParsePcreExec(&parse_regex, &match, templatestr, 0, 0);
135
381
    if (ret != 3) {
136
65
        SCLogError("parse error, ret %" PRId32 "", ret);
137
65
        goto error;
138
65
    }
139
140
316
    size_t pcre2len = sizeof(arg1);
141
316
    ret = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)arg1, &pcre2len);
142
316
    if (ret < 0) {
143
33
        SCLogError("pcre2_substring_copy_bynumber failed");
144
33
        goto error;
145
33
    }
146
283
    SCLogDebug("Arg1 \"%s\"", arg1);
147
148
283
    pcre2len = sizeof(arg2);
149
283
    ret = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)arg2, &pcre2len);
150
283
    if (ret < 0) {
151
5
        SCLogError("pcre2_substring_copy_bynumber failed");
152
5
        goto error;
153
5
    }
154
278
    SCLogDebug("Arg2 \"%s\"", arg2);
155
156
278
    DetectTemplateData *templated = SCMalloc(sizeof (DetectTemplateData));
157
278
    if (unlikely(templated == NULL))
158
0
        goto error;
159
160
278
    if (ByteExtractStringUint8(&templated->arg1, 10, 0, (const char *)arg1) < 0) {
161
93
        SCFree(templated);
162
93
        goto error;
163
93
    }
164
185
    if (ByteExtractStringUint8(&templated->arg2, 10, 0, (const char *)arg2) < 0) {
165
3
        SCFree(templated);
166
3
        goto error;
167
3
    }
168
182
    pcre2_match_data_free(match);
169
182
    return templated;
170
171
199
error:
172
199
    if (match) {
173
199
        pcre2_match_data_free(match);
174
199
    }
175
199
    return NULL;
176
185
}
177
178
/**
179
 * \brief parse the options from the 'template' keyword in the rule into
180
 *        the Signature data structure.
181
 *
182
 * \param de_ctx pointer to the Detection Engine Context
183
 * \param s pointer to the Current Signature
184
 * \param templatestr pointer to the user provided template options
185
 *
186
 * \retval 0 on Success
187
 * \retval -1 on Failure
188
 */
189
static int DetectTemplateSetup (DetectEngineCtx *de_ctx, Signature *s, const char *templatestr)
190
381
{
191
381
    DetectTemplateData *templated = DetectTemplateParse(templatestr);
192
381
    if (templated == NULL)
193
199
        return -1;
194
195
182
    SigMatch *sm = SigMatchAlloc();
196
182
    if (sm == NULL) {
197
0
        DetectTemplateFree(de_ctx, templated);
198
0
        return -1;
199
0
    }
200
201
182
    sm->type = DETECT_TEMPLATE;
202
182
    sm->ctx = (void *)templated;
203
204
182
    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
205
182
    s->flags |= SIG_FLAG_REQUIRE_PACKET;
206
207
182
    return 0;
208
182
}
209
210
/**
211
 * \brief this function will free memory associated with DetectTemplateData
212
 *
213
 * \param ptr pointer to DetectTemplateData
214
 */
215
static void DetectTemplateFree(DetectEngineCtx *de_ctx, void *ptr)
216
182
{
217
182
    DetectTemplateData *templated = (DetectTemplateData *)ptr;
218
219
    /* do more specific cleanup here, if needed */
220
221
182
    SCFree(templated);
222
182
}
223
224
#ifdef UNITTESTS
225
#include "tests/detect-template.c"
226
#endif