suricata
detect-l3proto.c
Go to the documentation of this file.
1 /* Copyright (C) 2012-2013 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 Eric Leblond <eric@regit.org>
22  *
23  *
24  * Implements the l3_proto keyword
25  */
26 
27 #include "suricata-common.h"
28 #include "debug.h"
29 #include "decode.h"
30 #include "detect.h"
31 
32 #include "detect-ipproto.h"
33 
34 #include "detect-parse.h"
35 #include "detect-engine.h"
36 #include "detect-engine-mpm.h"
37 
38 #include "detect-engine-siggroup.h"
39 #include "detect-engine-address.h"
40 
41 #include "detect-l3proto.h"
42 
43 #include "util-byte.h"
44 #include "util-unittest.h"
45 #include "util-unittest-helper.h"
46 
47 #include "util-debug.h"
48 
49 static int DetectL3ProtoSetup(DetectEngineCtx *, Signature *, const char *);
50 
52 
54 {
55  sigmatch_table[DETECT_L3PROTO].name = "l3_proto";
57  sigmatch_table[DETECT_L3PROTO].Setup = DetectL3ProtoSetup;
60 
61  return;
62 }
63 /**
64  * \internal
65  * \brief Setup l3_proto keyword.
66  *
67  * \param de_ctx Detection engine context
68  * \param s Signature
69  * \param optstr Options string
70  *
71  * \return Non-zero on error
72  */
73 static int DetectL3ProtoSetup(DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
74 {
75  const char *str = optstr;
76 
77  /* reset possible any value */
78  if (s->proto.flags & DETECT_PROTO_ANY) {
80  }
81 
82  /* authorized value, ip, any, ip4, ipv4, ip6, ipv6 */
83  if (strcasecmp(str,"ipv4") == 0 ||
84  strcasecmp(str,"ip4") == 0 ) {
85  if (s->proto.flags & DETECT_PROTO_IPV6) {
86  SCLogError(SC_ERR_INVALID_SIGNATURE, "Conflicting l3 proto specified");
87  goto error;
88  }
90  SCLogDebug("IPv4 protocol detected");
91  } else if (strcasecmp(str,"ipv6") == 0 ||
92  strcasecmp(str,"ip6") == 0 ) {
93  if (s->proto.flags & DETECT_PROTO_IPV6) {
94  SCLogError(SC_ERR_INVALID_SIGNATURE, "Conflicting l3 proto specified");
95  goto error;
96  }
98  SCLogDebug("IPv6 protocol detected");
99  } else {
100  SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid l3 proto: \"%s\"", str);
101  goto error;
102  }
103 
104  return 0;
105 error:
106  return -1;
107 }
108 
109 #ifdef UNITTESTS
110 
111 /**
112  * \test DetectL3protoTestSig01 is a test for checking the working of ttl keyword
113  * by setting up the signature and later testing its working by matching
114  * the received packet against the sig.
115  */
116 
117 static int DetectL3protoTestSig1(void)
118 {
119 
120  Packet *p = PacketGetFromAlloc();
121  if (unlikely(p == NULL))
122  return 0;
123  Signature *s = NULL;
124  ThreadVars th_v;
125  DetectEngineThreadCtx *det_ctx;
126  int result = 0;
127  IPV4Hdr ip4h;
128 
129  memset(&th_v, 0, sizeof(th_v));
130 
131  p->src.family = AF_INET;
132  p->dst.family = AF_INET;
133  p->proto = IPPROTO_TCP;
134  p->ip4h = &ip4h;
135 
137  if (de_ctx == NULL) {
138  goto end;
139  }
140 
141  de_ctx->flags |= DE_QUIET;
142 
143  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv4\"; l3_proto:ipv4; sid:1;)");
144  if (s == NULL) {
145  goto end;
146  }
147 
148  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6\"; l3_proto:ipv6; sid:2;)");
149  if (s == NULL) {
150  goto end;
151  }
152 
153  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip4\"; l3_proto:ip4; sid:3;)");
154  if (s == NULL) {
155  goto end;
156  }
157 
158  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip6\"; l3_proto:ip6; sid:2;)");
159  if (s == NULL) {
160  goto end;
161  }
162 
163  SigGroupBuild(de_ctx);
164  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
165 
166  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
167  if (PacketAlertCheck(p, 1) == 0) {
168  printf("sid 1 did not alert, but should have: ");
169  goto cleanup;
170  } else if (PacketAlertCheck(p, 2)) {
171  printf("sid 2 alerted, but should not have: ");
172  goto cleanup;
173  } else if (PacketAlertCheck(p, 3) == 0) {
174  printf("sid 3 did not alert, but should have: ");
175  goto cleanup;
176  } else if (PacketAlertCheck(p, 4)) {
177  printf("sid 4 alerted, but should not have: ");
178  goto cleanup;
179  }
180 
181  result = 1;
182 
183 cleanup:
184  SigGroupCleanup(de_ctx);
185  SigCleanSignatures(de_ctx);
186 
187  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
188  DetectEngineCtxFree(de_ctx);
189 
190 end:
191  SCFree(p);
192  return result;
193 }
194 
195 /**
196  * \test DetectL3protoTestSig02 is a test for checking the working of l3proto keyword
197  * by setting up the signature and later testing its working by matching
198  * the received IPv6 packet against the sig.
199  */
200 
201 static int DetectL3protoTestSig2(void)
202 {
203 
204  Packet *p = PacketGetFromAlloc();
205  if (unlikely(p == NULL))
206  return 0;
207  Signature *s = NULL;
208  ThreadVars th_v;
209  DetectEngineThreadCtx *det_ctx;
210  int result = 0;
211  IPV6Hdr ip6h;
212 
213  memset(&th_v, 0, sizeof(th_v));
214 
215  p->src.family = AF_INET6;
216  p->dst.family = AF_INET6;
217  p->proto = IPPROTO_TCP;
218  p->ip6h = &ip6h;
219 
221  if (de_ctx == NULL) {
222  goto end;
223  }
224 
225  de_ctx->flags |= DE_QUIET;
226 
227  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv4\"; l3_proto:ipv4; sid:1;)");
228  if (s == NULL) {
229  goto end;
230  }
231 
232  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6\"; l3_proto:ipv6; sid:2;)");
233  if (s == NULL) {
234  goto end;
235  }
236 
237  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip4\"; l3_proto:ip4; sid:3;)");
238  if (s == NULL) {
239  goto end;
240  }
241 
242  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip6\"; l3_proto:ip6; sid:4;)");
243  if (s == NULL) {
244  goto end;
245  }
246 
247  SigGroupBuild(de_ctx);
248  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
249 
250  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
251  if (PacketAlertCheck(p, 1)) {
252  printf("sid 1 alerted, but should not have: ");
253  goto cleanup;
254  } else if (PacketAlertCheck(p, 2) == 0) {
255  printf("sid 2 did not alert, but should have: ");
256  goto cleanup;
257  } else if (PacketAlertCheck(p, 3)) {
258  printf("sid 3 alerted, but should not have: ");
259  goto cleanup;
260  } else if (PacketAlertCheck(p, 4) == 0) {
261  printf("sid 4 did not alert, but should have: ");
262  goto cleanup;
263  }
264 
265  result = 1;
266 
267 cleanup:
268  SigGroupCleanup(de_ctx);
269  SigCleanSignatures(de_ctx);
270 
271  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
272  DetectEngineCtxFree(de_ctx);
273 
274 end:
275  SCFree(p);
276  return result;
277 }
278 
279 /**
280  * \test DetectL3protoTestSig03 is a test for checking the working of l3proto keyword
281  * in conjonction with ip_proto keyword.
282  */
283 
284 static int DetectL3protoTestSig3(void)
285 {
286 
287  Packet *p = PacketGetFromAlloc();
288  if (unlikely(p == NULL))
289  return 0;
290  Signature *s = NULL;
291  ThreadVars th_v;
292  DetectEngineThreadCtx *det_ctx;
293  int result = 0;
294  IPV6Hdr ip6h;
295 
296  memset(&th_v, 0, sizeof(th_v));
297 
298  p->src.family = AF_INET6;
299  p->dst.family = AF_INET6;
300  p->proto = IPPROTO_TCP;
301  p->ip6h = &ip6h;
302 
304  if (de_ctx == NULL) {
305  goto end;
306  }
307 
308  de_ctx->flags |= DE_QUIET;
309 
310  s = de_ctx->sig_list = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv4 and ip_proto udp\"; l3_proto:ipv4; ip_proto:17; sid:1;)");
311  if (s == NULL) {
312  goto end;
313  }
314 
315  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6 and ip_proto udp\"; l3_proto:ipv6; ip_proto:17; sid:2;)");
316  if (s == NULL) {
317  goto end;
318  }
319 
320  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ip4 and ip_proto tcp\"; l3_proto:ipv4; ip_proto:6; sid:3;)");
321  if (s == NULL) {
322  goto end;
323  }
324 
325  s = s->next = SigInit(de_ctx,"alert ip any any -> any any (msg:\"l3proto ipv6 and ip_proto tcp\"; l3_proto:ipv6; ip_proto:6; sid:4;)");
326  if (s == NULL) {
327  goto end;
328  }
329 
330  SigGroupBuild(de_ctx);
331  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
332 
333  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
334  if (PacketAlertCheck(p, 1)) {
335  printf("sid 1 alerted, but should not have: ");
336  goto cleanup;
337  } else if (PacketAlertCheck(p, 2)) {
338  printf("sid 2 alerted, but should not have: ");
339  goto cleanup;
340  } else if (PacketAlertCheck(p, 3)) {
341  printf("sid 3 alerted, but should not have: ");
342  goto cleanup;
343  } else if (PacketAlertCheck(p, 4) == 0) {
344  printf("sid 4 did not alert, but should have: ");
345  goto cleanup;
346  }
347 
348  result = 1;
349 
350 cleanup:
351  SigGroupCleanup(de_ctx);
352  SigCleanSignatures(de_ctx);
353 
354  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
355  DetectEngineCtxFree(de_ctx);
356 
357 end:
358  SCFree(p);
359  return result;
360 }
361 
362 
363 #endif /* UNITTESTS */
364 
365 /**
366  * \brief this function registers unit tests for DetectL3proto
367  */
369 {
370 #ifdef UNITTESTS
371  UtRegisterTest("DetectL3protoTestSig1", DetectL3protoTestSig1);
372  UtRegisterTest("DetectL3protoTestSig2", DetectL3protoTestSig2);
373  UtRegisterTest("DetectL3protoTestSig3", DetectL3protoTestSig3);
374 #endif /* UNITTESTS */
375 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1409
DetectProto proto
Definition: detect.h:513
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1150
#define DETECT_PROTO_IPV6
#define SCLogDebug(...)
Definition: util-debug.h:335
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
#define DETECT_PROTO_ANY
#define unlikely(expr)
Definition: util-optimize.h:35
Signature * SigInit(DetectEngineCtx *, const char *)
Parses a signature and adds it to the Detection Engine Context.
Signature * sig_list
Definition: detect.h:730
void DetectL3ProtoRegister(void)
Registration function for ip_proto keyword.
Address dst
Definition: decode.h:411
void SigCleanSignatures(DetectEngineCtx *de_ctx)
void DetectL3protoRegisterTests(void)
this function registers unit tests for DetectL3proto
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
const char * name
Definition: detect.h:1164
Signature container.
Definition: detect.h:496
main detection engine ctx
Definition: detect.h:724
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
#define DE_QUIET
Definition: detect.h:296
#define str(s)
IPV6Hdr * ip6h
Definition: decode.h:500
char family
Definition: decode.h:109
uint8_t proto
Definition: decode.h:428
uint8_t flags
Definition: detect.h:725
void(* Free)(void *)
Definition: detect.h:1155
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1742
int SigGroupCleanup(DetectEngineCtx *de_ctx)
struct Signature_ * next
Definition: detect.h:567
#define DETECT_PROTO_IPV4
IPV4Hdr * ip4h
Definition: decode.h:498
#define SCFree(a)
Definition: util-mem.h:228
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1133
Per thread variable structure.
Definition: threadvars.h:57
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
void(* RegisterTests)(void)
Definition: detect.h:1156
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:141
Address src
Definition: decode.h:410
DetectEngineCtx * DetectEngineCtxInit(void)