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