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"
34 #include "util-unittest-helper.h"
35 
36 static int DetectIpOptsMatch (DetectEngineThreadCtx *, Packet *,
37  const Signature *, const SigMatchCtx *);
38 static int DetectIpOptsSetup (DetectEngineCtx *, Signature *, const char *);
39 #ifdef UNITTESTS
40 static void IpOptsRegisterTests(void);
41 #endif
42 void DetectIpOptsFree(DetectEngineCtx *, void *);
43 
44 /**
45  * \brief Registration function for ipopts: keyword
46  */
48 {
49  sigmatch_table[DETECT_IPOPTS].name = "ipopts";
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 
65 struct DetectIpOpts_ {
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 },
110 };
111 
112 /**
113  * \brief Return human readable value for ipopts flag
114  *
115  * \param flag uint16_t DetectIpOptsData ipopts flag value
116  */
117 const char *IpOptsFlagToString(uint16_t flag)
118 {
119  switch (flag) {
120  case IPV4_OPT_FLAG_RR:
121  return "rr";
122  case IPV4_OPT_FLAG_LSRR:
123  return "lsrr";
124  case IPV4_OPT_FLAG_EOL:
125  return "eol";
126  case IPV4_OPT_FLAG_NOP:
127  return "nop";
128  case IPV4_OPT_FLAG_TS:
129  return "ts";
130  case IPV4_OPT_FLAG_SEC:
131  return "sec";
132  case IPV4_OPT_FLAG_ESEC:
133  return "esec";
134  case IPV4_OPT_FLAG_SSRR:
135  return "ssrr";
136  case IPV4_OPT_FLAG_SID:
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  */
158 static 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  */
180 static 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  */
219 static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
220 {
221  DetectIpOptsData *de = DetectIpOptsParse(rawstr);
222  if (de == NULL)
223  goto error;
224 
226  NULL) {
227  goto error;
228  }
230 
231  return 0;
232 
233 error:
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  */
260 static 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  */
274 static 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  */
288 static int IpOptsTestParse03 (void)
289 {
290  Packet *p = PacketGetFromAlloc();
291  FAIL_IF_NULL(p);
292  ThreadVars tv;
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  */
322 static int IpOptsTestParse04 (void)
323 {
324  Packet *p = PacketGetFromAlloc();
325  FAIL_IF_NULL(p);
326  ThreadVars tv;
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  */
356 static 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  */
370 void 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 */
DetectIpOpts_::ipopt_name
const char * ipopt_name
Definition: detect-ipopts.c:66
DetectIpOpts_
Definition: detect-ipopts.c:65
PacketL3::vars
union PacketL3::@27 vars
SigTableElmt_::url
const char * url
Definition: detect.h:1307
IPV4_OPT_FLAG_NOP
#define IPV4_OPT_FLAG_NOP
Definition: decode-ipv4.h:117
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SigTableElmt_::desc
const char * desc
Definition: detect.h:1306
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:127
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1294
SigTableElmt_::name
const char * name
Definition: detect.h:1304
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1317
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
IPV4_OPT_FLAG_SSRR
#define IPV4_OPT_FLAG_SSRR
Definition: decode-ipv4.h:122
UTHSetIPV4Hdr
void UTHSetIPV4Hdr(Packet *p, IPV4Hdr *ip4h)
Definition: util-unittest-helper.c:126
DETECT_IPOPTS
@ DETECT_IPOPTS
Definition: detect-engine-register.h:39
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:841
IPV4_OPT_FLAG_TS
#define IPV4_OPT_FLAG_TS
Definition: decode-ipv4.h:119
IPV4_OPT_FLAG_SEC
#define IPV4_OPT_FLAG_SEC
Definition: decode-ipv4.h:124
DetectIpOptsRegister
void DetectIpOptsRegister(void)
Registration function for ipopts: keyword.
Definition: detect-ipopts.c:47
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1289
util-unittest.h
IPV4_OPT_FLAG_ESEC
#define IPV4_OPT_FLAG_ESEC
Definition: decode-ipv4.h:127
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
ipopts
struct DetectIpOpts_ ipopts[]
IPV4_OPT_FLAG_LSRR
#define IPV4_OPT_FLAG_LSRR
Definition: decode-ipv4.h:121
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
IpOptsFlagToString
const char * IpOptsFlagToString(uint16_t flag)
Return human readable value for ipopts flag.
Definition: detect-ipopts.c:117
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1093
de
uint8_t de
Definition: app-layer-htp.c:554
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:114
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:352
Signature_::flags
uint32_t flags
Definition: detect.h:602
Packet_
Definition: decode.h:473
IPV4_OPT_FLAG_RR
#define IPV4_OPT_FLAG_RR
Definition: decode-ipv4.h:118
PacketL3::ip4
IPV4Vars ip4
Definition: decode.h:417
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1272
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:322
DetectIpOptsFree
void DetectIpOptsFree(DetectEngineCtx *, void *)
Definition: detect-ipopts.c:245
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:344
IPV4Hdr_
Definition: decode-ipv4.h:72
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h
SigMatch_::type
uint16_t type
Definition: detect.h:350
DetectIpOptsData_
Definition: detect-ipopts.h:37
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:232
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
Packet_::l3
struct PacketL3 l3
Definition: decode.h:566
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
IPV4_OPT_FLAG_EOL
#define IPV4_OPT_FLAG_EOL
Definition: decode-ipv4.h:116
detect-parse.h
Signature_
Signature container.
Definition: detect.h:601
SigMatch_
a single match condition for a signature
Definition: detect.h:349
IPV4_OPT_FLAG_SID
#define IPV4_OPT_FLAG_SID
Definition: decode-ipv4.h:123
detect-ipopts.h
suricata.h
IPV4Vars_::opts_set
uint16_t opts_set
Definition: decode-ipv4.h:132
SigMatchAppendSMToList
SigMatch * SigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:436
DetectIpOpts_::code
uint16_t code
Definition: detect-ipopts.c:67
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1296
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:250