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  "ts",
72  },
73  {
74  "rr",
76  },
77  {
78  "qs",
80  },
81  {
82  "sec",
84  },
85  {
86  "lsrr",
88  },
89  {
90  "esec",
92  },
93  {
94  "cipso",
96  },
97  {
98  "satid",
100  },
101  {
102  "ssrr",
104  },
105  {
106  "rtralt",
108  },
109  {
110  "eol",
112  },
113  {
114  "nop",
116  },
117  {
118  "any",
119  0xffff,
120  },
121  { NULL, 0 },
122 };
123 
124 /**
125  * \brief Return human readable value for ipopts flag
126  *
127  * \param flag uint16_t DetectIpOptsData ipopts flag value
128  */
129 const char *IpOptsFlagToString(uint16_t flag)
130 {
131  switch (flag) {
132  case IPV4_OPT_FLAG_TS:
133  return "ts";
134  case IPV4_OPT_FLAG_RR:
135  return "rr";
136  case IPV4_OPT_FLAG_QS:
137  return "qs";
138  case IPV4_OPT_FLAG_SEC:
139  return "sec";
140  case IPV4_OPT_FLAG_LSRR:
141  return "lsrr";
142  case IPV4_OPT_FLAG_ESEC:
143  return "esec";
144  case IPV4_OPT_FLAG_CIPSO:
145  return "cipso";
146  case IPV4_OPT_FLAG_SID:
147  return "satid";
148  case IPV4_OPT_FLAG_SSRR:
149  return "ssrr";
151  return "rtralt";
152  case IPV4_OPT_FLAG_EOL:
153  return "eol";
154  case IPV4_OPT_FLAG_NOP:
155  return "nop";
156  case 0xffff:
157  return "any";
158  default:
159  return NULL;
160  }
161 }
162 
163 /**
164  * \internal
165  * \brief This function is used to match ip option on a packet with those passed via ipopts:
166  *
167  * \param t pointer to thread vars
168  * \param det_ctx pointer to the pattern matcher thread
169  * \param p pointer to the current packet
170  * \param s pointer to the Signature
171  * \param m pointer to the sigmatch
172  *
173  * \retval 0 no match
174  * \retval 1 match
175  */
176 static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
177  const Signature *s, const SigMatchCtx *ctx)
178 {
180 
181  const DetectIpOptsData *de = (const DetectIpOptsData *)ctx;
182 
183  if (!de || !PacketIsIPv4(p))
184  return 0;
185 
186  return (p->l3.vars.ip4.opts_set & de->ipopt) == de->ipopt;
187 }
188 
189 /**
190  * \internal
191  * \brief This function is used to parse ipopts options passed via ipopts: keyword
192  *
193  * \param rawstr Pointer to the user provided ipopts options
194  *
195  * \retval de pointer to DetectIpOptsData on success
196  * \retval NULL on failure
197  */
198 static DetectIpOptsData *DetectIpOptsParse (const char *rawstr)
199 {
200  if (rawstr == NULL || strlen(rawstr) == 0)
201  return NULL;
202 
203  int i;
204  bool found = false;
205  for(i = 0; ipopts[i].ipopt_name != NULL; i++) {
206  if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) {
207  found = true;
208  break;
209  }
210  }
211 
212  if (!found) {
213  SCLogError("unknown IP option specified \"%s\"", rawstr);
214  return NULL;
215  }
216 
218  if (unlikely(de == NULL))
219  return NULL;
220 
221  de->ipopt = ipopts[i].code;
222 
223  return de;
224 }
225 
226 /**
227  * \internal
228  * \brief this function is used to add the parsed ipopts into the current signature
229  *
230  * \param de_ctx pointer to the Detection Engine Context
231  * \param s pointer to the Current Signature
232  * \param rawstr pointer to the user provided ipopts options
233  *
234  * \retval 0 on Success
235  * \retval -1 on Failure
236  */
237 static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
238 {
239  DetectIpOptsData *de = DetectIpOptsParse(rawstr);
240  if (de == NULL)
241  goto error;
242 
244  de_ctx, s, DETECT_IPOPTS, (SigMatchCtx *)de, DETECT_SM_LIST_MATCH) == NULL) {
245  goto error;
246  }
248 
249  return 0;
250 
251 error:
252  if (de)
253  SCFree(de);
254  return -1;
255 }
256 
257 /**
258  * \internal
259  * \brief this function will free memory associated with DetectIpOptsData
260  *
261  * \param de pointer to DetectIpOptsData
262  */
264 {
265  if (de_ptr) {
266  SCFree(de_ptr);
267  }
268 }
269 
270 /*
271  * ONLY TESTS BELOW THIS COMMENT
272  */
273 
274 #ifdef UNITTESTS
275 /**
276  * \test IpOptsTestParse01 is a test for a valid ipopts value
277  */
278 static int IpOptsTestParse01 (void)
279 {
280  DetectIpOptsData *de = DetectIpOptsParse("lsrr");
281 
282  FAIL_IF_NULL(de);
283 
284  DetectIpOptsFree(NULL, de);
285 
286  PASS;
287 }
288 
289 /**
290  * \test IpOptsTestParse02 is a test for an invalid ipopts value
291  */
292 static int IpOptsTestParse02 (void)
293 {
294  DetectIpOptsData *de = DetectIpOptsParse("invalidopt");
295 
296  FAIL_IF_NOT_NULL(de);
297 
298  DetectIpOptsFree(NULL, de);
299 
300  PASS;
301 }
302 
303 /**
304  * \test IpOptsTestParse03 test the match function on a packet that needs to match
305  */
306 static int IpOptsTestParse03 (void)
307 {
308  Packet *p = PacketGetFromAlloc();
309  FAIL_IF_NULL(p);
310  ThreadVars tv;
311  IPV4Hdr ip4h;
312 
313  memset(&tv, 0, sizeof(ThreadVars));
314  memset(&ip4h, 0, sizeof(IPV4Hdr));
315 
316  UTHSetIPV4Hdr(p, &ip4h);
318 
319  DetectIpOptsData *de = DetectIpOptsParse("rr");
320  FAIL_IF_NULL(de);
321 
322  SigMatch *sm = SigMatchAlloc();
323  FAIL_IF_NULL(sm);
324 
325  sm->type = DETECT_IPOPTS;
326  sm->ctx = (SigMatchCtx *)de;
327 
328  FAIL_IF_NOT(DetectIpOptsMatch(NULL, p, NULL, sm->ctx));
329 
330  SCFree(de);
331  SCFree(sm);
332  PacketFree(p);
333 
334  PASS;
335 }
336 
337 /**
338  * \test IpOptsTestParse04 test the match function on a packet that needs to not match
339  */
340 static int IpOptsTestParse04 (void)
341 {
342  Packet *p = PacketGetFromAlloc();
343  FAIL_IF_NULL(p);
344  ThreadVars tv;
345  IPV4Hdr ip4h;
346 
347  memset(&tv, 0, sizeof(ThreadVars));
348  memset(&ip4h, 0, sizeof(IPV4Hdr));
349 
350  UTHSetIPV4Hdr(p, &ip4h);
352 
353  DetectIpOptsData *de = DetectIpOptsParse("lsrr");
354  FAIL_IF_NULL(de);
355 
356  SigMatch *sm = SigMatchAlloc();
357  FAIL_IF_NULL(sm);
358 
359  sm->type = DETECT_IPOPTS;
360  sm->ctx = (SigMatchCtx *)de;
361 
362  FAIL_IF(DetectIpOptsMatch(NULL, p, NULL, sm->ctx));
363 
364  SCFree(de);
365  SCFree(sm);
366  PacketFree(p);
367 
368  PASS;
369 }
370 
371 /**
372  * \test IpOptsTestParse05 tests the NULL and empty string
373  */
374 static int IpOptsTestParse05(void)
375 {
376  DetectIpOptsData *de = DetectIpOptsParse("");
377  FAIL_IF_NOT_NULL(de);
378 
379  de = DetectIpOptsParse(NULL);
380  FAIL_IF_NOT_NULL(de);
381 
382  PASS;
383 }
384 
385 /**
386  * \brief this function registers unit tests for IpOpts
387  */
388 void IpOptsRegisterTests(void)
389 {
390  UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01);
391  UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02);
392  UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03);
393  UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04);
394  UtRegisterTest("IpOptsTestParse05", IpOptsTestParse05);
395 }
396 #endif /* UNITTESTS */
DetectIpOpts_::ipopt_name
const char * ipopt_name
Definition: detect-ipopts.c:66
DetectIpOpts_
Definition: detect-ipopts.c:65
SigTableElmt_::url
const char * url
Definition: detect.h:1464
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:1463
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1448
SigTableElmt_::name
const char * name
Definition: detect.h:1461
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1348
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
PacketL3::vars
union PacketL3::@30 vars
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:933
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
IPV4_OPT_FLAG_QS
#define IPV4_OPT_FLAG_QS
Definition: decode-ipv4.h:120
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1443
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:129
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
DetectEngineThreadCtx_
Definition: detect.h:1245
DetectIpOptsData_::ipopt
uint16_t ipopt
Definition: detect-ipopts.h:38
SCSigMatchAppendSMToList
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:387
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:225
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:117
IPV4_OPT_FLAG_CIPSO
#define IPV4_OPT_FLAG_CIPSO
Definition: decode-ipv4.h:125
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:358
IPV4_OPT_FLAG_RTRALT
#define IPV4_OPT_FLAG_RTRALT
Definition: decode-ipv4.h:126
Signature_::flags
uint32_t flags
Definition: detect.h:669
Packet_
Definition: decode.h:505
IPV4_OPT_FLAG_RR
#define IPV4_OPT_FLAG_RR
Definition: decode-ipv4.h:118
PacketL3::ip4
IPV4Vars ip4
Definition: decode.h:446
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1423
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:274
DetectIpOptsFree
void DetectIpOptsFree(DetectEngineCtx *, void *)
Definition: detect-ipopts.c:263
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:350
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:356
DetectIpOptsData_
Definition: detect-ipopts.h:37
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:33
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:264
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
Packet_::l3
struct PacketL3 l3
Definition: decode.h:604
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
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:668
SigMatch_
a single match condition for a signature
Definition: detect.h:355
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
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:1450
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:253