suricata
detect-itype.c
Go to the documentation of this file.
1/* Copyright (C) 2007-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 Gerardo Iglesias <iglesiasg@gmail.com>
22 *
23 * Implements itype keyword support
24 */
25
26#include "suricata-common.h"
27#include "decode.h"
28
29#include "detect.h"
30#include "detect-parse.h"
32#include "detect-engine-build.h"
33
34#include "detect-itype.h"
35#include "detect-engine-uint.h"
36
37#include "util-byte.h"
38#include "util-unittest.h"
40#include "util-debug.h"
41
42
43static int DetectITypeMatch(DetectEngineThreadCtx *, Packet *,
44 const Signature *, const SigMatchCtx *);
45static int DetectITypeSetup(DetectEngineCtx *, Signature *, const char *);
46#ifdef UNITTESTS
47static void DetectITypeRegisterTests(void);
48#endif
49void DetectITypeFree(DetectEngineCtx *, void *);
50
51static int PrefilterSetupIType(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
52static bool PrefilterITypeIsPrefilterable(const Signature *s);
53
54/**
55 * \brief Registration function for itype: keyword
56 */
58{
60 sigmatch_table[DETECT_ITYPE].desc = "match on a specific ICMP type";
61 sigmatch_table[DETECT_ITYPE].url = "/rules/header-keywords.html#itype";
62 sigmatch_table[DETECT_ITYPE].Match = DetectITypeMatch;
63 sigmatch_table[DETECT_ITYPE].Setup = DetectITypeSetup;
66#ifdef UNITTESTS
67 sigmatch_table[DETECT_ITYPE].RegisterTests = DetectITypeRegisterTests;
68#endif
69 sigmatch_table[DETECT_ITYPE].SupportsPrefilter = PrefilterITypeIsPrefilterable;
70 sigmatch_table[DETECT_ITYPE].SetupPrefilter = PrefilterSetupIType;
71}
72
73/**
74 * \brief This function is used to match itype rule option set on a packet with those passed via
75 * itype:
76 *
77 * \param t pointer to thread vars
78 * \param det_ctx pointer to the pattern matcher thread
79 * \param p pointer to the current packet
80 * \param m pointer to the sigmatch that we will cast into DetectU8Data
81 *
82 * \retval 0 no match
83 * \retval 1 match
84 */
85static int DetectITypeMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
86 const Signature *s, const SigMatchCtx *ctx)
87{
89
90 uint8_t pitype;
91 if (PacketIsICMPv4(p)) {
92 pitype = p->icmp_s.type;
93 } else if (PacketIsICMPv6(p)) {
94 const ICMPV6Hdr *icmpv6h = PacketGetICMPv6(p);
95 pitype = ICMPV6_GET_TYPE(icmpv6h);
96 } else {
97 /* Packet not ICMPv4 nor ICMPv6 */
98 return 0;
99 }
100
101 const DetectU8Data *itd = (const DetectU8Data *)ctx;
102 return DetectU8Match(pitype, itd);
103}
104
105/**
106 * \brief this function is used to add the parsed itype data into the current signature
107 *
108 * \param de_ctx pointer to the Detection Engine Context
109 * \param s pointer to the Current Signature
110 * \param itypestr pointer to the user provided itype options
111 *
112 * \retval 0 on Success
113 * \retval -1 on Failure
114 */
115static int DetectITypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *itypestr)
116{
117
118 DetectU8Data *itd = NULL;
119
120 itd = DetectU8Parse(itypestr);
121 if (itd == NULL)
122 return -1;
123
125 de_ctx, s, DETECT_ITYPE, (SigMatchCtx *)itd, DETECT_SM_LIST_MATCH) == NULL) {
127 return -1;
128 }
130
131 return 0;
132}
133
134/**
135 * \brief this function will free memory associated with DetectU8Data
136 *
137 * \param ptr pointer to DetectU8Data
138 */
140{
141 DetectU8Data *itd = (DetectU8Data *)ptr;
142 SCDetectU8Free(itd);
143}
144
145/* prefilter code
146 *
147 * Prefilter uses the U8Hash logic, where we setup a 256 entry array
148 * for each ICMP type. Each array element has the list of signatures
149 * that need to be inspected. */
150
151static void PrefilterPacketITypeMatch(DetectEngineThreadCtx *det_ctx,
152 Packet *p, const void *pectx)
153{
155
156 uint8_t pitype;
157 if (PacketIsICMPv4(p)) {
158 pitype = p->icmp_s.type;
159 } else if (PacketIsICMPv6(p)) {
160 const ICMPV6Hdr *icmpv6h = PacketGetICMPv6(p);
161 pitype = ICMPV6_GET_TYPE(icmpv6h);
162 } else {
163 /* Packet not ICMPv4 nor ICMPv6 */
164 return;
165 }
166
167 const PrefilterPacketU8HashCtx *h = pectx;
168 const SigsArray *sa = h->array[pitype];
169 if (sa) {
170 PrefilterAddSids(&det_ctx->pmq, sa->sigs, sa->cnt);
171 }
172}
173
174static int PrefilterSetupIType(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
175{
177 PrefilterPacketU8Set, PrefilterPacketU8Compare, PrefilterPacketITypeMatch);
178}
179
180static bool PrefilterITypeIsPrefilterable(const Signature *s)
181{
182 const SigMatch *sm;
183 for (sm = s->init_data->smlists[DETECT_SM_LIST_MATCH] ; sm != NULL; sm = sm->next) {
184 switch (sm->type) {
185 case DETECT_ITYPE:
186 return true;
187 }
188 }
189 return false;
190}
191
192#ifdef UNITTESTS
193
194#include "detect-engine.h"
195#include "detect-engine-mpm.h"
196
197/**
198 * \test DetectITypeParseTest01 is a test for setting a valid itype value
199 */
200static int DetectITypeParseTest01(void)
201{
202 DetectU8Data *itd = NULL;
203 itd = DetectU8Parse("8");
204 FAIL_IF_NULL(itd);
205 FAIL_IF_NOT(itd->arg1 == 8);
206 FAIL_IF_NOT(itd->mode == DETECT_UINT_EQ);
207 DetectITypeFree(NULL, itd);
208
209 PASS;
210}
211
212/**
213 * \test DetectITypeParseTest02 is a test for setting a valid itype value
214 * with ">" operator
215 */
216static int DetectITypeParseTest02(void)
217{
218 DetectU8Data *itd = NULL;
219 itd = DetectU8Parse(">8");
220 FAIL_IF_NULL(itd);
221 FAIL_IF_NOT(itd->arg1 == 8);
222 FAIL_IF_NOT(itd->mode == DETECT_UINT_GT);
223 DetectITypeFree(NULL, itd);
224
225 PASS;
226}
227
228/**
229 * \test DetectITypeParseTest03 is a test for setting a valid itype value
230 * with "<" operator
231 */
232static int DetectITypeParseTest03(void)
233{
234 DetectU8Data *itd = NULL;
235 itd = DetectU8Parse("<8");
236 FAIL_IF_NULL(itd);
237 FAIL_IF_NOT(itd->arg1 == 8);
238 FAIL_IF_NOT(itd->mode == DETECT_UINT_LT);
239 DetectITypeFree(NULL, itd);
240
241 PASS;
242}
243
244/**
245 * \test DetectITypeParseTest04 is a test for setting a valid itype value
246 * with "<>" operator
247 */
248static int DetectITypeParseTest04(void)
249{
250 DetectU8Data *itd = NULL;
251 itd = DetectU8Parse("8<>20");
252 FAIL_IF_NULL(itd);
253 FAIL_IF_NOT(itd->arg1 == 8);
254 FAIL_IF_NOT(itd->arg2 == 20);
255 FAIL_IF_NOT(itd->mode == DETECT_UINT_RA);
256 DetectITypeFree(NULL, itd);
257
258 PASS;
259}
260
261/**
262 * \test DetectITypeParseTest05 is a test for setting a valid itype value
263 * with spaces all around
264 */
265static int DetectITypeParseTest05(void)
266{
267 DetectU8Data *itd = NULL;
268 itd = DetectU8Parse(" 8 ");
269 FAIL_IF_NULL(itd);
270 FAIL_IF_NOT(itd->arg1 == 8);
271 FAIL_IF_NOT(itd->mode == DETECT_UINT_EQ);
272 DetectITypeFree(NULL, itd);
273
274 PASS;
275}
276
277/**
278 * \test DetectITypeParseTest06 is a test for setting a valid itype value
279 * with ">" operator and spaces all around
280 */
281static int DetectITypeParseTest06(void)
282{
283 DetectU8Data *itd = NULL;
284 itd = DetectU8Parse(" > 8 ");
285 FAIL_IF_NULL(itd);
286 FAIL_IF_NOT(itd->arg1 == 8);
287 FAIL_IF_NOT(itd->mode == DETECT_UINT_GT);
288 DetectITypeFree(NULL, itd);
289
290 PASS;
291}
292
293/**
294 * \test DetectITypeParseTest07 is a test for setting a valid itype value
295 * with "<>" operator and spaces all around
296 */
297static int DetectITypeParseTest07(void)
298{
299 DetectU8Data *itd = NULL;
300 itd = DetectU8Parse(" 8 <> 20 ");
301 FAIL_IF_NULL(itd);
302 FAIL_IF_NOT(itd->arg1 == 8);
303 FAIL_IF_NOT(itd->arg2 == 20);
304 FAIL_IF_NOT(itd->mode == DETECT_UINT_RA);
305 DetectITypeFree(NULL, itd);
306
307 PASS;
308}
309
310/**
311 * \test DetectITypeParseTest08 is a test for setting an invalid itype value
312 */
313static int DetectITypeParseTest08(void)
314{
315 DetectU8Data *itd = NULL;
316 itd = DetectU8Parse("> 8 <> 20");
317 FAIL_IF_NOT_NULL(itd);
318
319 PASS;
320}
321
322/**
323 * \brief this function registers unit tests for DetectIType
324 */
325void DetectITypeRegisterTests(void)
326{
327 UtRegisterTest("DetectITypeParseTest01", DetectITypeParseTest01);
328 UtRegisterTest("DetectITypeParseTest02", DetectITypeParseTest02);
329 UtRegisterTest("DetectITypeParseTest03", DetectITypeParseTest03);
330 UtRegisterTest("DetectITypeParseTest04", DetectITypeParseTest04);
331 UtRegisterTest("DetectITypeParseTest05", DetectITypeParseTest05);
332 UtRegisterTest("DetectITypeParseTest06", DetectITypeParseTest06);
333 UtRegisterTest("DetectITypeParseTest07", DetectITypeParseTest07);
334 UtRegisterTest("DetectITypeParseTest08", DetectITypeParseTest08);
335}
336#endif /* UNITTESTS */
#define ICMPV6_GET_TYPE(icmp6h)
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition decode.h:1321
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))
DetectUintData_u8 * DetectU8Parse(const char *u8str)
This function is used to parse u8 options passed via some u8 keyword.
void PrefilterPacketU8Set(PrefilterPacketHeaderValue *v, void *smctx)
int DetectU8Match(const uint8_t parg, const DetectUintData_u8 *du8)
bool PrefilterPacketU8Compare(PrefilterPacketHeaderValue v, void *smctx)
#define DETECT_UINT_LT
#define DETECT_UINT_EQ
#define DETECT_UINT_GT
#define DETECT_UINT_RA
DetectUintData_u8 DetectU8Data
void DetectITypeFree(DetectEngineCtx *, void *)
this function will free memory associated with DetectU8Data
void DetectITypeRegister(void)
Registration function for itype: keyword.
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 SIG_FLAG_REQUIRE_PACKET
Definition detect.h:254
#define SIGMATCH_SUPPORT_FIREWALL
Definition detect.h:1682
#define SIG_MASK_REQUIRE_REAL_PKT
Definition detect.h:316
@ DETECT_SM_LIST_MATCH
Definition detect.h:117
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.
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
PrefilterRuleStore pmq
Definition detect.h:1349
struct Packet_::@33::@40 icmp_s
uint8_t type
Definition decode.h:511
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
const char * url
Definition detect.h:1462
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
const char * desc
Definition detect.h:1461
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
uint32_t flags
Definition detect.h:669
SignatureInitData * init_data
Definition detect.h:747
#define DEBUG_VALIDATE_BUG_ON(exp)