suricata
detect-mark.c
Go to the documentation of this file.
1/* Copyright (C) 2011-2021 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 Eric Leblond <eric@regit.org>
22 *
23 * Implements the mark keyword. Based on detect-gid
24 * by Breno Silva <breno.silva@gmail.com>
25 */
26
27#include "suricata-common.h"
28#include "suricata.h"
29#include "decode.h"
30#include "detect.h"
31#include "flow-var.h"
32#include "decode-events.h"
33
34#include "detect-mark.h"
35#include "detect-parse.h"
36
37#include "util-unittest.h"
38#include "util-byte.h"
39#include "util-debug.h"
40
41#define PARSE_REGEX "([0x]*[0-9a-f]+)/([0x]*[0-9a-f]+)"
42
43static DetectParseRegex parse_regex;
44
45static int DetectMarkSetup (DetectEngineCtx *, Signature *, const char *);
46static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p,
47 const Signature *s, const SigMatchCtx *ctx);
48void DetectMarkDataFree(DetectEngineCtx *, void *ptr);
49#if defined UNITTESTS && defined NFQ
50static void MarkRegisterTests(void);
51#endif
52
53/**
54 * \brief Registration function for nfq_set_mark: keyword
55 */
56
58{
59 sigmatch_table[DETECT_MARK].name = "nfq_set_mark";
60 sigmatch_table[DETECT_MARK].Match = DetectMarkPacket;
61 sigmatch_table[DETECT_MARK].Setup = DetectMarkSetup;
63#if defined UNITTESTS && defined NFQ
64 sigmatch_table[DETECT_MARK].RegisterTests = MarkRegisterTests;
65#endif
67}
68
69#ifdef NFQ
70/**
71 * \internal
72 * \brief This function is used to parse mark options passed via mark: keyword
73 *
74 * \param rawstr Pointer to the user provided mark options
75 *
76 * \retval 0 on success
77 * \retval < 0 on failure
78 */
79static void * DetectMarkParse (const char *rawstr)
80{
81 int res = 0;
82 size_t pcre2_len;
83 const char *str_ptr = NULL;
84 char *ptr = NULL;
85 uint32_t mark;
86 uint32_t mask;
87 DetectMarkData *data;
88
89 pcre2_match_data *match = NULL;
90 int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
91 if (ret < 1) {
92 SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
93 pcre2_match_data_free(match);
94 return NULL;
95 }
96
97 res = pcre2_substring_get_bynumber(match, 1, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
98 if (res < 0) {
99 SCLogError("pcre2_substring_get_bynumber failed");
100 goto error;
101 }
102
103 ptr = (char *)str_ptr;
104
105 if (ptr == NULL)
106 goto error;
107
108 if (ByteExtractStringUint32(&mark, 0, strlen(ptr), ptr) <= 0) {
109 SCLogError("invalid input as arg to nfq_set_mark keyword");
110 pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
111 goto error;
112 }
113
114 res = pcre2_substring_get_bynumber(match, 2, (PCRE2_UCHAR8 **)&str_ptr, &pcre2_len);
115 if (res < 0) {
116 SCLogError("pcre2_substring_get_bynumber failed");
117 goto error;
118 }
119
120 pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
121 ptr = (char *)str_ptr;
122
123 if (ptr == NULL) {
124 data = SCMalloc(sizeof(DetectMarkData));
125 if (unlikely(data == NULL)) {
126 goto error;
127 }
128 data->mark = mark;
129 data->mask = 0xffff;
130 pcre2_match_data_free(match);
131 return data;
132 }
133
134 if (ByteExtractStringUint32(&mask, 0, strlen(ptr), ptr) <= 0) {
135 SCLogError("invalid input as arg to nfq_set_mark keyword");
136 pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
137 goto error;
138 }
139
140 SCLogDebug("Rule will set mark 0x%x with mask 0x%x", mark, mask);
141 pcre2_substring_free((PCRE2_UCHAR8 *)ptr);
142
143 data = SCMalloc(sizeof(DetectMarkData));
144 if (unlikely(data == NULL)) {
145 goto error;
146 }
147 data->mark = mark;
148 data->mask = mask;
149 pcre2_match_data_free(match);
150 return data;
151
152error:
153 if (match) {
154 pcre2_match_data_free(match);
155 }
156 return NULL;
157}
158
159#endif /* NFQ */
160
161/**
162 * \internal
163 * \brief this function is used to add the parsed mark into the current signature
164 *
165 * \param de_ctx pointer to the Detection Engine Context
166 * \param s pointer to the Current Signature
167 * \param rawstr pointer to the user provided mark options
168 *
169 * \retval 0 on Success
170 * \retval -1 on Failure
171 */
172static int DetectMarkSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
173{
174#ifndef NFQ
175 return 0;
176#else
177 DetectMarkData *data = DetectMarkParse(rawstr);
178 if (data == NULL) {
179 return -1;
180 }
181
182 /* Append it to the list of post match, so the mark is set if the
183 * full signature matches. */
187 return -1;
188 }
189 return 0;
190#endif
191}
192
194{
195 DetectMarkData *data = (DetectMarkData *)ptr;
196 SCFree(data);
197}
198
199
200static int DetectMarkPacket(DetectEngineThreadCtx *det_ctx, Packet *p,
201 const Signature *s, const SigMatchCtx *ctx)
202{
203#ifdef NFQ
204 const DetectMarkData *nf_data = (const DetectMarkData *)ctx;
205 if (nf_data->mask) {
206 if (PacketIsNotTunnel(p)) {
207 /* for a non-tunnel packet we don't need a lock,
208 * and if we're here we can't turn into a tunnel
209 * packet anymore. */
210
211 /* coverity[missing_lock] */
212 p->nfq_v.mark = (nf_data->mark & nf_data->mask)
213 | (p->nfq_v.mark & ~(nf_data->mask));
214 /* coverity[missing_lock] */
215 p->nfq_v.mark_modified = true;
216 } else {
217 /* real tunnels may have multiple flows inside them, so marking
218 * might 'mark' too much. Rebuilt packets from IP fragments
219 * are fine. */
220 if (p->flags & PKT_REBUILT_FRAGMENT) {
221 Packet *tp = p->root ? p->root : p;
223 tp->nfq_v.mark = (nf_data->mark & nf_data->mask)
224 | (tp->nfq_v.mark & ~(nf_data->mask));
225 tp->nfq_v.mark_modified = true;
227 }
228 }
229 }
230#endif
231 return 1;
232}
233
234/*
235 * ONLY TESTS BELOW THIS COMMENT
236 */
237
238#if defined UNITTESTS && defined NFQ
239/**
240 * \test MarkTestParse01 is a test for a valid mark value
241 *
242 */
243static int MarkTestParse01 (void)
244{
245 DetectMarkData *data;
246
247 data = DetectMarkParse("1/1");
248
249 FAIL_IF_NULL(data);
250 FAIL_IF(data->mark != 1);
251 FAIL_IF(data->mask != 1);
252
253 DetectMarkDataFree(NULL, data);
254 PASS;
255}
256
257/**
258 * \test MarkTestParse02 is a test for an invalid mark value
259 *
260 */
261static int MarkTestParse02 (void)
262{
263 DetectMarkData *data;
264
265 data = DetectMarkParse("4");
266
267 FAIL_IF_NOT_NULL(data);
268
269 DetectMarkDataFree(NULL, data);
270 PASS;
271}
272
273/**
274 * \test MarkTestParse03 is a test for a valid mark value
275 *
276 */
277static int MarkTestParse03 (void)
278{
279 DetectMarkData *data;
280
281 data = DetectMarkParse("0x10/0xff");
282 FAIL_IF(data->mark != 0x10);
283 FAIL_IF(data->mask != 0xff);
284
285 FAIL_IF_NULL(data);
286
287 DetectMarkDataFree(NULL, data);
288 PASS;
289}
290
291/**
292 * \test MarkTestParse04 is a test for a invalid mark value
293 *
294 */
295static int MarkTestParse04 (void)
296{
297 DetectMarkData *data;
298
299 data = DetectMarkParse("0x1g/0xff");
300
301 FAIL_IF_NOT_NULL(data);
302
303 DetectMarkDataFree(NULL, data);
304 PASS;
305}
306
307/**
308 * \brief this function registers unit tests for Mark
309 */
310static void MarkRegisterTests(void)
311{
312 UtRegisterTest("MarkTestParse01", MarkTestParse01);
313 UtRegisterTest("MarkTestParse02", MarkTestParse02);
314 UtRegisterTest("MarkTestParse03", MarkTestParse03);
315 UtRegisterTest("MarkTestParse04", MarkTestParse04);
316}
317#endif /* UNITTESTS */
#define PKT_REBUILT_FRAGMENT
Definition decode.h:1302
void DetectMarkRegister(void)
Registration function for nfq_set_mark: keyword.
Definition detect-mark.c:57
void DetectMarkDataFree(DetectEngineCtx *, void *ptr)
#define PARSE_REGEX
Definition detect-mark.c:41
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
@ DETECT_SM_LIST_POSTMATCH
Definition detect.h:127
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
uint32_t mark
Definition source-nfq.h:46
SCSpinlock tunnel_lock
Definition decode.h:683
struct Packet_::@39 persistent
struct Packet_ * root
Definition decode.h:653
uint32_t flags
Definition decode.h:544
NFQPacketVars nfq_v
Definition decode.h:563
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
void(* RegisterTests)(void)
Definition detect.h:1448
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
Signature container.
Definition detect.h:668
#define SCSpinUnlock
#define SCSpinLock
int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:239
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define unlikely(expr)