suricata
detect-engine-event.c
Go to the documentation of this file.
1/* Copyright (C) 2007-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 Breno Silva <breno.silva@gmail.com>
22 *
23 * Implements the decode-event keyword
24 */
25
26#include "suricata-common.h"
27#include "suricata.h"
28#include "decode.h"
29#include "detect.h"
30#include "detect-parse.h"
32#include "detect-engine-uint.h"
33
34#include "flow-var.h"
35#include "decode-events.h"
36
37#include "util-debug.h"
38
39#include "stream-tcp.h"
40
41
42/* Need to get the DEvents[] array */
43
44#include "detect-engine-event.h"
45#include "util-unittest.h"
46
47#define PARSE_REGEX "\\S[0-9A-z_]+[.][A-z0-9_+.]+$"
48
49static DetectParseRegex parse_regex;
50
51static int DetectEngineEventMatch (DetectEngineThreadCtx *,
52 Packet *, const Signature *, const SigMatchCtx *);
53static int DetectEngineEventSetup (DetectEngineCtx *, Signature *, const char *);
54static int DetectDecodeEventSetup (DetectEngineCtx *, Signature *, const char *);
55static int DetectStreamEventSetup (DetectEngineCtx *, Signature *, const char *);
56static void DetectEngineEventFree (DetectEngineCtx *, void *);
57#ifdef UNITTESTS
59#endif
60
61static bool PrefilterEventIsPrefilterable(const Signature *s, int smtype)
62{
63 const SigMatch *sm;
64 for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
65 if (sm->type == smtype) {
66 return true;
67 }
68 }
69 return false;
70}
71static bool PrefilterStreamEventIsPrefilterable(const Signature *s)
72{
73 return PrefilterEventIsPrefilterable(s, DETECT_STREAM_EVENT);
74}
75
76static bool PrefilterDecodeEventIsPrefilterable(const Signature *s)
77{
78 return PrefilterEventIsPrefilterable(s, DETECT_DECODE_EVENT);
79}
80
81static void PrefilterPacketEventSet(PrefilterPacketHeaderValue *v, void *smctx)
82{
83 const DetectEngineEventData *a = smctx;
85 v->u8[1] = a->event; // arg1
86 v->u8[2] = 0; // arg2
87}
88
89static bool PrefilterPacketEventCompare(PrefilterPacketHeaderValue v, void *smctx)
90{
91 const DetectEngineEventData *a = smctx;
92 DetectUintData_u8 du8;
93 du8.mode = DETECT_UINT_EQ;
94 du8.arg1 = a->event;
95 du8.arg2 = 0;
96 return PrefilterPacketU8Compare(v, &du8);
97}
98
99static void PrefilterPacketEventMatch(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx)
100{
101 const PrefilterPacketU8HashCtx *h = pectx;
102 for (uint8_t u = 0; u < p->events.cnt; u++) {
103 const SigsArray *sa = h->array[p->events.events[u]];
104 if (sa) {
105 PrefilterAddSids(&det_ctx->pmq, sa->sigs, sa->cnt);
106 }
107 }
108}
109
110static int PrefilterSetupStreamEvent(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
111{
113 SIG_MASK_REQUIRE_ENGINE_EVENT, PrefilterPacketEventSet, PrefilterPacketEventCompare,
114 PrefilterPacketEventMatch);
115}
116
117static int PrefilterSetupDecodeEvent(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
118{
120 SIG_MASK_REQUIRE_ENGINE_EVENT, PrefilterPacketEventSet, PrefilterPacketEventCompare,
121 PrefilterPacketEventMatch);
122}
123
124/**
125 * \brief Registration function for decode-event: keyword
126 */
128{
129 sigmatch_table[DETECT_ENGINE_EVENT].name = "engine-event";
130 sigmatch_table[DETECT_ENGINE_EVENT].Match = DetectEngineEventMatch;
131 sigmatch_table[DETECT_ENGINE_EVENT].Setup = DetectEngineEventSetup;
132 sigmatch_table[DETECT_ENGINE_EVENT].Free = DetectEngineEventFree;
133#ifdef UNITTESTS
135#endif
136
137 sigmatch_table[DETECT_DECODE_EVENT].name = "decode-event";
138 sigmatch_table[DETECT_DECODE_EVENT].Match = DetectEngineEventMatch;
139 sigmatch_table[DETECT_DECODE_EVENT].Setup = DetectDecodeEventSetup;
140 sigmatch_table[DETECT_DECODE_EVENT].Free = DetectEngineEventFree;
142 sigmatch_table[DETECT_DECODE_EVENT].SupportsPrefilter = PrefilterDecodeEventIsPrefilterable;
143 sigmatch_table[DETECT_DECODE_EVENT].SetupPrefilter = PrefilterSetupDecodeEvent;
144
145 sigmatch_table[DETECT_STREAM_EVENT].name = "stream-event";
146 sigmatch_table[DETECT_STREAM_EVENT].Match = DetectEngineEventMatch;
147 sigmatch_table[DETECT_STREAM_EVENT].Setup = DetectStreamEventSetup;
148 sigmatch_table[DETECT_STREAM_EVENT].Free = DetectEngineEventFree;
149 sigmatch_table[DETECT_STREAM_EVENT].SupportsPrefilter = PrefilterStreamEventIsPrefilterable;
150 sigmatch_table[DETECT_STREAM_EVENT].SetupPrefilter = PrefilterSetupStreamEvent;
151
153}
154
155/**
156 * \brief This function is used to match decoder event flags set on a packet with those passed via decode-event:
157 *
158 * \param t pointer to thread vars
159 * \param det_ctx pointer to the pattern matcher thread
160 * \param p pointer to the current packet
161 * \param s pointer to the Signature
162 * \param m pointer to the sigmatch
163 *
164 * \retval 0 no match
165 * \retval 1 match
166 */
167static int DetectEngineEventMatch (DetectEngineThreadCtx *det_ctx,
168 Packet *p, const Signature *s, const SigMatchCtx *ctx)
169{
170 SCEnter();
171
173
174 if (ENGINE_ISSET_EVENT(p, de->event)) {
175 SCLogDebug("de->event matched %u", de->event);
176 SCReturnInt(1);
177 }
178
179 SCReturnInt(0);
180}
181
182static bool OutdatedEvent(const char *raw)
183{
184 if (strcmp(raw, "decoder.udp.hlen_invalid") == 0) {
185 return true;
186 }
187 return false;
188}
189
190/**
191 * \brief This function is used to parse decoder events options passed via decode-event: keyword
192 *
193 * \param rawstr Pointer to the user provided decode-event options
194 *
195 * \retval de pointer to DetectFlowData on success
196 * \retval NULL on failure
197 */
198static DetectEngineEventData *DetectEngineEventParse (const char *rawstr)
199{
200 int i;
201 DetectEngineEventData *de = NULL;
202 int res = 0, found = 0;
203 size_t pcre2len;
204 pcre2_match_data *match = NULL;
205
206 int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
207 if (ret < 1) {
208 SCLogError("pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
209 goto error;
210 }
211
212 char copy_str[128] = "";
213 pcre2len = sizeof(copy_str);
214 res = pcre2_substring_copy_bynumber(match, 0, (PCRE2_UCHAR8 *)copy_str, &pcre2len);
215
216 if (res < 0) {
217 SCLogError("pcre2_substring_copy_bynumber failed");
218 goto error;
219 }
220
221 for (i = 0; DEvents[i].event_name != NULL; i++) {
222 if (strcasecmp(DEvents[i].event_name,copy_str) == 0) {
223 found = 1;
224 break;
225 }
226 }
227
228 if (found == 0) {
229 SCLogError("unknown decode event \"%s\"", copy_str);
230 goto error;
231 }
232
233 de = SCMalloc(sizeof(DetectEngineEventData));
234 if (unlikely(de == NULL))
235 goto error;
236
237 de->event = DEvents[i].code;
238
241 }
242
243 if (OutdatedEvent(rawstr)) {
245 SCLogError("decode-event keyword no longer supports event \"%s\"", rawstr);
246 goto error;
247 } else {
248 SCLogWarning("decode-event keyword no longer supports event \"%s\"", rawstr);
249 }
250 }
251
252 pcre2_match_data_free(match);
253 return de;
254
255error:
256 if (de)
257 SCFree(de);
258 if (match) {
259 pcre2_match_data_free(match);
260 }
261 return NULL;
262}
263
264/**
265 * \brief this function is used to add the parsed decode-event into the current signature
266 *
267 * \param de_ctx pointer to the Detection Engine Context
268 * \param s pointer to the Current Signature
269 * \param rawstr pointer to the user provided decode-event options
270 *
271 * \retval 0 on Success
272 * \retval -1 on Failure
273 */
274static int DetectEngineEventSetupDo(
275 DetectEngineCtx *de_ctx, Signature *s, const char *rawstr, uint16_t smtype)
276{
277 DetectEngineEventData *de = DetectEngineEventParse(rawstr);
278 if (de == NULL)
279 return -1;
280
281 SCLogDebug("rawstr %s %u", rawstr, de->event);
282
284 NULL) {
285 SCFree(de);
286 return -1;
287 }
288 return 0;
289}
290
291
292static int DetectEngineEventSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
293{
294 return DetectEngineEventSetupDo (de_ctx, s, rawstr, DETECT_ENGINE_EVENT);
295}
296
297/**
298 * \brief this function will free memory associated with DetectEngineEventData
299 *
300 * \param de pointer to DetectEngineEventData
301 */
302static void DetectEngineEventFree(DetectEngineCtx *de_ctx, void *ptr)
303{
305 if (de)
306 SCFree(de);
307}
308
309
310/**
311 * \brief this function Setup the 'decode-event' keyword by setting the correct
312 * signature type
313*/
314static int DetectDecodeEventSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
315{
316 char drawstr[64] = "decoder.";
317
318 /* decoder:$EVENT alias command develop as decode-event:decoder.$EVENT */
319 strlcat(drawstr, rawstr, sizeof(drawstr));
320
321 return DetectEngineEventSetupDo(de_ctx, s, drawstr, DETECT_DECODE_EVENT);
322}
323
324/**
325 * \brief this function Setup the 'stream-event' keyword by resolving the alias
326*/
327static int DetectStreamEventSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
328{
329 char srawstr[64] = "stream.";
330
331 if (strcmp(rawstr, "est_synack_resend_with_different_ack") == 0) {
332 rawstr = "est_synack_resend_with_diff_ack";
333 } else if (strcmp(rawstr, "3whs_synack_resend_with_different_ack") == 0) {
334 rawstr = "3whs_synack_resend_with_diff_ack";
335 }
336
337 /* stream:$EVENT alias command develop as decode-event:stream.$EVENT */
338 strlcat(srawstr, rawstr, sizeof(srawstr));
339
340 return DetectEngineEventSetupDo(de_ctx, s, srawstr, DETECT_STREAM_EVENT);
341}
342
343/*
344 * ONLY TESTS BELOW THIS COMMENT
345 */
346#ifdef UNITTESTS
347
348/**
349 * \test EngineEventTestParse01 is a test for a valid decode-event value
350 */
351static int EngineEventTestParse01 (void)
352{
353 DetectEngineEventData *de = DetectEngineEventParse("decoder.ipv4.pkt_too_small");
354
355 FAIL_IF_NULL(de);
356
357 DetectEngineEventFree(NULL, de);
358
359 PASS;
360}
361
362
363/**
364 * \test EngineEventTestParse02 is a test for a valid upper + lower case decode-event value
365 */
366static int EngineEventTestParse02 (void)
367{
368 DetectEngineEventData *de = DetectEngineEventParse("decoder.PPP.pkt_too_small");
369
370 FAIL_IF_NULL(de);
371
372 DetectEngineEventFree(NULL, de);
373
374 PASS;
375}
376
377/**
378 * \test EngineEventTestParse03 is a test for a valid upper case decode-event value
379 */
380static int EngineEventTestParse03 (void)
381{
382 DetectEngineEventData *de = DetectEngineEventParse("decoder.IPV6.PKT_TOO_SMALL");
383
384 FAIL_IF_NULL(de);
385
386 DetectEngineEventFree(NULL, de);
387
388 PASS;
389}
390
391/**
392 * \test EngineEventTestParse04 is a test for an invalid upper case decode-event value
393 */
394static int EngineEventTestParse04 (void)
395{
396 DetectEngineEventData *de = DetectEngineEventParse("decoder.IPV6.INVALID_EVENT");
397
399
400 DetectEngineEventFree(NULL, de);
401
402 PASS;
403}
404
405/**
406 * \test EngineEventTestParse05 is a test for an invalid char into the decode-event value
407 */
408static int EngineEventTestParse05 (void)
409{
410 DetectEngineEventData *de = DetectEngineEventParse("decoder.IPV-6,INVALID_CHAR");
411
413
414 DetectEngineEventFree(NULL, de);
415
416 PASS;
417}
418
419/**
420 * \test EngineEventTestParse06 is a test for match function with valid decode-event value
421 */
422static int EngineEventTestParse06 (void)
423{
425 FAIL_IF_NULL(p);
426
428
429 memset(&tv, 0, sizeof(ThreadVars));
430
432
433 DetectEngineEventData *de = DetectEngineEventParse("decoder.ppp.pkt_too_small");
434 FAIL_IF_NULL(de);
435
437
438 SigMatch *sm = SigMatchAlloc();
439 FAIL_IF_NULL(sm);
440
442 sm->ctx = (SigMatchCtx *)de;
443
444 FAIL_IF_NOT(DetectEngineEventMatch(NULL, p, NULL, sm->ctx));
445
446 SCFree(p);
447 SCFree(de);
448 SCFree(sm);
449
450 PASS;
451}
452
453/**
454 * \brief this function registers unit tests for EngineEvent
455 */
457{
458 UtRegisterTest("EngineEventTestParse01", EngineEventTestParse01);
459 UtRegisterTest("EngineEventTestParse02", EngineEventTestParse02);
460 UtRegisterTest("EngineEventTestParse03", EngineEventTestParse03);
461 UtRegisterTest("EngineEventTestParse04", EngineEventTestParse04);
462 UtRegisterTest("EngineEventTestParse05", EngineEventTestParse05);
463 UtRegisterTest("EngineEventTestParse06", EngineEventTestParse06);
464}
465#endif /* UNITTESTS */
const struct DecodeEvents_ DEvents[]
@ STREAM_REASSEMBLY_OVERLAP_DIFFERENT_DATA
@ PPP_PKT_TOO_SMALL
#define ENGINE_ISSET_EVENT(p, e)
Definition decode.h:1199
#define ENGINE_SET_EVENT(p, e)
Definition decode.h:1186
void EngineEventRegisterTests(void)
this function registers unit tests for EngineEvent
#define PARSE_REGEX
void DetectEngineEventRegister(void)
Registration function for decode-event: keyword.
int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, SignatureMask mask, void(*Set)(PrefilterPacketHeaderValue *v, void *), bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
#define PREFILTER_U8HASH_MODE_EQ
@ DETECT_STREAM_EVENT
@ DETECT_ENGINE_EVENT
@ DETECT_DECODE_EVENT
bool PrefilterPacketU8Compare(PrefilterPacketHeaderValue v, void *smctx)
#define DETECT_UINT_EQ
bool SigMatchStrictEnabled(const enum DetectKeywordId id)
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
SigMatch * SigMatchAlloc(void)
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
#define SIGMATCH_DEONLY_COMPAT
Definition detect.h:1655
#define SIG_MASK_REQUIRE_ENGINE_EVENT
Definition detect.h:318
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
ThreadVars * tv
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 FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition decode.c:258
struct Thresholds ctx
void StreamTcpReassembleConfigEnableOverlapCheck(void)
const char * event_name
main detection engine ctx
Definition detect.h:932
PrefilterRuleStore pmq
Definition detect.h:1349
uint8_t events[PACKET_ENGINE_EVENT_MAX]
Definition decode.h:308
PacketEngineEvents events
Definition decode.h:630
Container for matching data for a signature group.
Definition detect.h:1629
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
a single match condition for a signature
Definition detect.h:356
uint16_t type
Definition detect.h:357
struct SigMatch_ * next
Definition detect.h:360
SigMatchCtx * ctx
Definition detect.h:359
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
int(* SetupPrefilter)(DetectEngineCtx *de_ctx, struct SigGroupHead_ *sgh)
Definition detect.h:1444
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
uint16_t flags
Definition detect.h:1450
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
bool(* SupportsPrefilter)(const Signature *s)
Definition detect.h:1443
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition detect.h:642
Signature container.
Definition detect.h:668
SignatureInitData * init_data
Definition detect.h:747
Per thread variable structure.
Definition threadvars.h:58
size_t strlcat(char *, const char *src, size_t siz)
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#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)