suricata
detect-ipopts.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 ipopts keyword
24 */
25
26#include "suricata-common.h"
27#include "suricata.h"
28
29#include "detect.h"
30#include "detect-parse.h"
31
32#include "detect-ipopts.h"
33#include "util-unittest.h"
35
36static int DetectIpOptsMatch (DetectEngineThreadCtx *, Packet *,
37 const Signature *, const SigMatchCtx *);
38static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, const char *);
39#ifdef UNITTESTS
40static void IpOptsRegisterTests(void);
41#endif
42void DetectIpOptsFree(DetectEngineCtx *, void *);
43
44/**
45 * \brief Registration function for ipopts: keyword
46 */
48{
50 sigmatch_table[DETECT_IPOPTS].desc = "check if a specific IP option is set";
51 sigmatch_table[DETECT_IPOPTS].url = "/rules/header-keywords.html#ipopts";
52 sigmatch_table[DETECT_IPOPTS].Match = DetectIpOptsMatch;
53 sigmatch_table[DETECT_IPOPTS].Setup = DetectIpOptsSetup;
55#ifdef UNITTESTS
56 sigmatch_table[DETECT_IPOPTS].RegisterTests = IpOptsRegisterTests;
57#endif
58}
59
60/**
61 * \struct DetectIpOptss_
62 * DetectIpOptss_ is used to store supported iptops values
63 */
64
66 const char *ipopt_name; /**< ip option name */
67 uint16_t code; /**< ip option flag value */
68} ipopts[] = {
69 {
70 "rr",
72 },
73 {
74 "lsrr",
76 },
77 {
78 "eol",
80 },
81 {
82 "nop",
84 },
85 {
86 "ts",
88 },
89 {
90 "sec",
92 },
93 {
94 "esec",
96 },
97 {
98 "ssrr",
100 },
101 {
102 "satid",
104 },
105 {
106 "any",
107 0xffff,
108 },
109 { NULL, 0 },
111
112/**
113 * \brief Return human readable value for ipopts flag
114 *
115 * \param flag uint16_t DetectIpOptsData ipopts flag value
116 */
117const char *IpOptsFlagToString(uint16_t flag)
118{
119 switch (flag) {
120 case IPV4_OPT_FLAG_RR:
121 return "rr";
123 return "lsrr";
125 return "eol";
127 return "nop";
128 case IPV4_OPT_FLAG_TS:
129 return "ts";
131 return "sec";
133 return "esec";
135 return "ssrr";
137 return "satid";
138 case 0xffff:
139 return "any";
140 default:
141 return NULL;
142 }
143}
144
145/**
146 * \internal
147 * \brief This function is used to match ip option on a packet with those passed via ipopts:
148 *
149 * \param t pointer to thread vars
150 * \param det_ctx pointer to the pattern matcher thread
151 * \param p pointer to the current packet
152 * \param s pointer to the Signature
153 * \param m pointer to the sigmatch
154 *
155 * \retval 0 no match
156 * \retval 1 match
157 */
158static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
159 const Signature *s, const SigMatchCtx *ctx)
160{
162
163 const DetectIpOptsData *de = (const DetectIpOptsData *)ctx;
164
165 if (!de || !PacketIsIPv4(p))
166 return 0;
167
168 return (p->l3.vars.ip4.opts_set & de->ipopt) == de->ipopt;
169}
170
171/**
172 * \internal
173 * \brief This function is used to parse ipopts options passed via ipopts: keyword
174 *
175 * \param rawstr Pointer to the user provided ipopts options
176 *
177 * \retval de pointer to DetectIpOptsData on success
178 * \retval NULL on failure
179 */
180static DetectIpOptsData *DetectIpOptsParse (const char *rawstr)
181{
182 if (rawstr == NULL || strlen(rawstr) == 0)
183 return NULL;
184
185 int i;
186 bool found = false;
187 for(i = 0; ipopts[i].ipopt_name != NULL; i++) {
188 if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) {
189 found = true;
190 break;
191 }
192 }
193
194 if (!found) {
195 SCLogError("unknown IP option specified \"%s\"", rawstr);
196 return NULL;
197 }
198
200 if (unlikely(de == NULL))
201 return NULL;
202
203 de->ipopt = ipopts[i].code;
204
205 return de;
206}
207
208/**
209 * \internal
210 * \brief this function is used to add the parsed ipopts into the current signature
211 *
212 * \param de_ctx pointer to the Detection Engine Context
213 * \param s pointer to the Current Signature
214 * \param rawstr pointer to the user provided ipopts options
215 *
216 * \retval 0 on Success
217 * \retval -1 on Failure
218 */
219static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
220{
221 DetectIpOptsData *de = DetectIpOptsParse(rawstr);
222 if (de == NULL)
223 goto error;
224
227 goto error;
228 }
230
231 return 0;
232
233error:
234 if (de)
235 SCFree(de);
236 return -1;
237}
238
239/**
240 * \internal
241 * \brief this function will free memory associated with DetectIpOptsData
242 *
243 * \param de pointer to DetectIpOptsData
244 */
246{
247 if (de_ptr) {
248 SCFree(de_ptr);
249 }
250}
251
252/*
253 * ONLY TESTS BELOW THIS COMMENT
254 */
255
256#ifdef UNITTESTS
257/**
258 * \test IpOptsTestParse01 is a test for a valid ipopts value
259 */
260static int IpOptsTestParse01 (void)
261{
262 DetectIpOptsData *de = DetectIpOptsParse("lsrr");
263
264 FAIL_IF_NULL(de);
265
266 DetectIpOptsFree(NULL, de);
267
268 PASS;
269}
270
271/**
272 * \test IpOptsTestParse02 is a test for an invalid ipopts value
273 */
274static int IpOptsTestParse02 (void)
275{
276 DetectIpOptsData *de = DetectIpOptsParse("invalidopt");
277
279
280 DetectIpOptsFree(NULL, de);
281
282 PASS;
283}
284
285/**
286 * \test IpOptsTestParse03 test the match function on a packet that needs to match
287 */
288static int IpOptsTestParse03 (void)
289{
291 FAIL_IF_NULL(p);
293 IPV4Hdr ip4h;
294
295 memset(&tv, 0, sizeof(ThreadVars));
296 memset(&ip4h, 0, sizeof(IPV4Hdr));
297
298 UTHSetIPV4Hdr(p, &ip4h);
300
301 DetectIpOptsData *de = DetectIpOptsParse("rr");
302 FAIL_IF_NULL(de);
303
304 SigMatch *sm = SigMatchAlloc();
305 FAIL_IF_NULL(sm);
306
307 sm->type = DETECT_IPOPTS;
308 sm->ctx = (SigMatchCtx *)de;
309
310 FAIL_IF_NOT(DetectIpOptsMatch(NULL, p, NULL, sm->ctx));
311
312 SCFree(de);
313 SCFree(sm);
314 SCFree(p);
315
316 PASS;
317}
318
319/**
320 * \test IpOptsTestParse04 test the match function on a packet that needs to not match
321 */
322static int IpOptsTestParse04 (void)
323{
325 FAIL_IF_NULL(p);
327 IPV4Hdr ip4h;
328
329 memset(&tv, 0, sizeof(ThreadVars));
330 memset(&ip4h, 0, sizeof(IPV4Hdr));
331
332 UTHSetIPV4Hdr(p, &ip4h);
334
335 DetectIpOptsData *de = DetectIpOptsParse("lsrr");
336 FAIL_IF_NULL(de);
337
338 SigMatch *sm = SigMatchAlloc();
339 FAIL_IF_NULL(sm);
340
341 sm->type = DETECT_IPOPTS;
342 sm->ctx = (SigMatchCtx *)de;
343
344 FAIL_IF(DetectIpOptsMatch(NULL, p, NULL, sm->ctx));
345
346 SCFree(de);
347 SCFree(sm);
348 SCFree(p);
349
350 PASS;
351}
352
353/**
354 * \test IpOptsTestParse05 tests the NULL and empty string
355 */
356static int IpOptsTestParse05(void)
357{
358 DetectIpOptsData *de = DetectIpOptsParse("");
360
361 de = DetectIpOptsParse(NULL);
363
364 PASS;
365}
366
367/**
368 * \brief this function registers unit tests for IpOpts
369 */
370void IpOptsRegisterTests(void)
371{
372 UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01);
373 UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02);
374 UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03);
375 UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04);
376 UtRegisterTest("IpOptsTestParse05", IpOptsTestParse05);
377}
378#endif /* UNITTESTS */
#define IPV4_OPT_FLAG_RR
#define IPV4_OPT_FLAG_LSRR
#define IPV4_OPT_FLAG_TS
#define IPV4_OPT_FLAG_SEC
#define IPV4_OPT_FLAG_EOL
#define IPV4_OPT_FLAG_ESEC
#define IPV4_OPT_FLAG_SID
#define IPV4_OPT_FLAG_SSRR
#define IPV4_OPT_FLAG_NOP
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition decode.h:1321
void DetectIpOptsRegister(void)
Registration function for ipopts: keyword.
void DetectIpOptsFree(DetectEngineCtx *, void *)
const char * IpOptsFlagToString(uint16_t flag)
Return human readable value for ipopts flag.
struct DetectIpOpts_ ipopts[]
SigMatch * SigMatchAlloc(void)
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
@ 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(expr)
Fail a test if expression evaluates to true.
#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
main detection engine ctx
Definition detect.h:932
const char * ipopt_name
uint16_t opts_set
union PacketL3::@31 vars
IPV4Vars ip4
Definition decode.h:445
struct PacketL3 l3
Definition decode.h:600
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
SigMatchCtx * ctx
Definition detect.h:359
const char * url
Definition detect.h:1462
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
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
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
Per thread variable structure.
Definition threadvars.h:58
#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)
void UTHSetIPV4Hdr(Packet *p, IPV4Hdr *ip4h)
#define DEBUG_VALIDATE_BUG_ON(exp)