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 
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  "rr",
71  },
72  {
73  "lsrr",
75  },
76  {
77  "eol",
79  },
80  {
81  "nop",
83  },
84  {
85  "ts",
87  },
88  {
89  "sec",
91  },
92  {
93  "esec",
95  },
96  {
97  "ssrr",
99  },
100  {
101  "satid",
103  },
104  {
105  "any",
106  0xffff,
107  },
108  { NULL, 0 },
109 };
110 
111 /**
112  * \brief Return human readable value for ipopts flag
113  *
114  * \param flag uint16_t DetectIpOptsData ipopts flag value
115  */
116 const char *IpOptsFlagToString(uint16_t flag)
117 {
118  switch (flag) {
119  case IPV4_OPT_FLAG_RR:
120  return "rr";
121  case IPV4_OPT_FLAG_LSRR:
122  return "lsrr";
123  case IPV4_OPT_FLAG_EOL:
124  return "eol";
125  case IPV4_OPT_FLAG_NOP:
126  return "nop";
127  case IPV4_OPT_FLAG_TS:
128  return "ts";
129  case IPV4_OPT_FLAG_SEC:
130  return "sec";
131  case IPV4_OPT_FLAG_ESEC:
132  return "esec";
133  case IPV4_OPT_FLAG_SSRR:
134  return "ssrr";
135  case IPV4_OPT_FLAG_SID:
136  return "satid";
137  case 0xffff:
138  return "any";
139  default:
140  return NULL;
141  }
142 }
143 
144 /**
145  * \internal
146  * \brief This function is used to match ip option on a packet with those passed via ipopts:
147  *
148  * \param t pointer to thread vars
149  * \param det_ctx pointer to the pattern matcher thread
150  * \param p pointer to the current packet
151  * \param s pointer to the Signature
152  * \param m pointer to the sigmatch
153  *
154  * \retval 0 no match
155  * \retval 1 match
156  */
157 static int DetectIpOptsMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
158  const Signature *s, const SigMatchCtx *ctx)
159 {
160  const DetectIpOptsData *de = (const DetectIpOptsData *)ctx;
161 
162  if (!de || !PKT_IS_IPV4(p) || PKT_IS_PSEUDOPKT(p))
163  return 0;
164 
165  return (p->ip4vars.opts_set & de->ipopt) == de->ipopt;
166 }
167 
168 /**
169  * \internal
170  * \brief This function is used to parse ipopts options passed via ipopts: keyword
171  *
172  * \param rawstr Pointer to the user provided ipopts options
173  *
174  * \retval de pointer to DetectIpOptsData on success
175  * \retval NULL on failure
176  */
177 static DetectIpOptsData *DetectIpOptsParse (const char *rawstr)
178 {
179  if (rawstr == NULL || strlen(rawstr) == 0)
180  return NULL;
181 
182  int i;
183  bool found = false;
184  for(i = 0; ipopts[i].ipopt_name != NULL; i++) {
185  if((strcasecmp(ipopts[i].ipopt_name,rawstr)) == 0) {
186  found = true;
187  break;
188  }
189  }
190 
191  if (!found) {
192  SCLogError("unknown IP option specified \"%s\"", rawstr);
193  return NULL;
194  }
195 
197  if (unlikely(de == NULL))
198  return NULL;
199 
200  de->ipopt = ipopts[i].code;
201 
202  return de;
203 }
204 
205 /**
206  * \internal
207  * \brief this function is used to add the parsed ipopts into the current signature
208  *
209  * \param de_ctx pointer to the Detection Engine Context
210  * \param s pointer to the Current Signature
211  * \param rawstr pointer to the user provided ipopts options
212  *
213  * \retval 0 on Success
214  * \retval -1 on Failure
215  */
216 static int DetectIpOptsSetup (DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
217 {
218  DetectIpOptsData *de = DetectIpOptsParse(rawstr);
219  if (de == NULL)
220  goto error;
221 
223  NULL) {
224  goto error;
225  }
227 
228  return 0;
229 
230 error:
231  if (de)
232  SCFree(de);
233  return -1;
234 }
235 
236 /**
237  * \internal
238  * \brief this function will free memory associated with DetectIpOptsData
239  *
240  * \param de pointer to DetectIpOptsData
241  */
243 {
244  if (de_ptr) {
245  SCFree(de_ptr);
246  }
247 }
248 
249 /*
250  * ONLY TESTS BELOW THIS COMMENT
251  */
252 
253 #ifdef UNITTESTS
254 /**
255  * \test IpOptsTestParse01 is a test for a valid ipopts value
256  */
257 static int IpOptsTestParse01 (void)
258 {
259  DetectIpOptsData *de = DetectIpOptsParse("lsrr");
260 
261  FAIL_IF_NULL(de);
262 
263  DetectIpOptsFree(NULL, de);
264 
265  PASS;
266 }
267 
268 /**
269  * \test IpOptsTestParse02 is a test for an invalid ipopts value
270  */
271 static int IpOptsTestParse02 (void)
272 {
273  DetectIpOptsData *de = DetectIpOptsParse("invalidopt");
274 
276 
277  DetectIpOptsFree(NULL, de);
278 
279  PASS;
280 }
281 
282 /**
283  * \test IpOptsTestParse03 test the match function on a packet that needs to match
284  */
285 static int IpOptsTestParse03 (void)
286 {
287  Packet *p = PacketGetFromAlloc();
288  FAIL_IF_NULL(p);
289  ThreadVars tv;
290  IPV4Hdr ip4h;
291 
292  memset(&tv, 0, sizeof(ThreadVars));
293  memset(&ip4h, 0, sizeof(IPV4Hdr));
294 
295  p->ip4h = &ip4h;
297 
298  DetectIpOptsData *de = DetectIpOptsParse("rr");
299  FAIL_IF_NULL(de);
300 
301  SigMatch *sm = SigMatchAlloc();
302  FAIL_IF_NULL(sm);
303 
304  sm->type = DETECT_IPOPTS;
305  sm->ctx = (SigMatchCtx *)de;
306 
307  FAIL_IF_NOT(DetectIpOptsMatch(NULL, p, NULL, sm->ctx));
308 
309  SCFree(de);
310  SCFree(sm);
311  SCFree(p);
312 
313  PASS;
314 }
315 
316 /**
317  * \test IpOptsTestParse04 test the match function on a packet that needs to not match
318  */
319 static int IpOptsTestParse04 (void)
320 {
321  Packet *p = PacketGetFromAlloc();
322  FAIL_IF_NULL(p);
323  ThreadVars tv;
324  IPV4Hdr ip4h;
325 
326  memset(&tv, 0, sizeof(ThreadVars));
327  memset(&ip4h, 0, sizeof(IPV4Hdr));
328 
329  p->ip4h = &ip4h;
331 
332  DetectIpOptsData *de = DetectIpOptsParse("lsrr");
333  FAIL_IF_NULL(de);
334 
335  SigMatch *sm = SigMatchAlloc();
336  FAIL_IF_NULL(sm);
337 
338  sm->type = DETECT_IPOPTS;
339  sm->ctx = (SigMatchCtx *)de;
340 
341  FAIL_IF(DetectIpOptsMatch(NULL, p, NULL, sm->ctx));
342 
343  SCFree(de);
344  SCFree(sm);
345  SCFree(p);
346 
347  PASS;
348 }
349 
350 /**
351  * \test IpOptsTestParse05 tests the NULL and empty string
352  */
353 static int IpOptsTestParse05(void)
354 {
355  DetectIpOptsData *de = DetectIpOptsParse("");
357 
358  de = DetectIpOptsParse(NULL);
360 
361  PASS;
362 }
363 
364 /**
365  * \brief this function registers unit tests for IpOpts
366  */
367 void IpOptsRegisterTests(void)
368 {
369  UtRegisterTest("IpOptsTestParse01", IpOptsTestParse01);
370  UtRegisterTest("IpOptsTestParse02", IpOptsTestParse02);
371  UtRegisterTest("IpOptsTestParse03", IpOptsTestParse03);
372  UtRegisterTest("IpOptsTestParse04", IpOptsTestParse04);
373  UtRegisterTest("IpOptsTestParse05", IpOptsTestParse05);
374 }
375 #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:1299
IPV4_OPT_FLAG_NOP
#define IPV4_OPT_FLAG_NOP
Definition: decode-ipv4.h:158
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:1298
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1286
SigTableElmt_::name
const char * name
Definition: detect.h:1296
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1075
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:163
DETECT_IPOPTS
@ DETECT_IPOPTS
Definition: detect-engine-register.h:39
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:839
IPV4_OPT_FLAG_TS
#define IPV4_OPT_FLAG_TS
Definition: decode-ipv4.h:160
Packet_::ip4vars
IPV4Vars ip4vars
Definition: decode.h:551
IPV4_OPT_FLAG_SEC
#define IPV4_OPT_FLAG_SEC
Definition: decode-ipv4.h:165
DetectIpOptsRegister
void DetectIpOptsRegister(void)
Registration function for ipopts: keyword.
Definition: detect-ipopts.c:46
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1281
util-unittest.h
IPV4_OPT_FLAG_ESEC
#define IPV4_OPT_FLAG_ESEC
Definition: decode-ipv4.h:168
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:162
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:116
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:1095
de
uint8_t de
Definition: app-layer-htp.c:581
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:114
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:353
Signature_::flags
uint32_t flags
Definition: detect.h:597
Packet_
Definition: decode.h:437
IPV4_OPT_FLAG_RR
#define IPV4_OPT_FLAG_RR
Definition: decode-ipv4.h:159
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:545
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1264
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:333
DetectIpOptsFree
void DetectIpOptsFree(DetectEngineCtx *, void *)
Definition: detect-ipopts.c:242
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:345
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:351
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:127
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:229
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
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:157
detect-parse.h
Signature_
Signature container.
Definition: detect.h:596
SigMatch_
a single match condition for a signature
Definition: detect.h:350
IPV4_OPT_FLAG_SID
#define IPV4_OPT_FLAG_SID
Definition: decode-ipv4.h:164
detect-ipopts.h
suricata.h
IPV4Vars_::opts_set
uint16_t opts_set
Definition: decode-ipv4.h:173
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:447
DetectIpOpts_::code
uint16_t code
Definition: detect-ipopts.c:66
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:246
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1288
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:249