suricata
detect-replace.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-2014 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  * Replace part of the detection engine.
24  *
25  * If previous filter is of content type, replace can be used to change
26  * the matched part to a new value.
27  */
28 
29 #include "suricata-common.h"
30 
31 #include "runmodes.h"
32 
33 extern int run_mode;
34 
35 #include "decode.h"
36 
37 #include "detect.h"
38 #include "detect-parse.h"
39 #include "detect-content.h"
40 #include "detect-uricontent.h"
41 #include "detect-byte-extract.h"
42 #include "detect-replace.h"
43 #include "app-layer.h"
44 
45 #include "detect-engine-mpm.h"
46 #include "detect-engine.h"
47 #include "detect-engine-state.h"
48 
49 #include "util-checksum.h"
50 
51 #include "util-unittest.h"
52 #include "util-unittest-helper.h"
53 
54 #include "flow-var.h"
55 
56 #include "util-debug.h"
57 
58 #include "pkt-var.h"
59 #include "host.h"
60 #include "util-profiling.h"
61 
62 static int DetectReplaceSetup(DetectEngineCtx *, Signature *, const char *);
64 
65 static int DetectReplacePostMatch(ThreadVars *tv,
66  DetectEngineThreadCtx *det_ctx,
67  Packet *p, const Signature *s, const SigMatchCtx *ctx);
68 
70 {
71  sigmatch_table[DETECT_REPLACE].name = "replace";
72  sigmatch_table[DETECT_REPLACE].Match = DetectReplacePostMatch;
73  sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup;
77 }
78 
79 static int DetectReplacePostMatch(ThreadVars *tv,
80  DetectEngineThreadCtx *det_ctx,
81  Packet *p, const Signature *s, const SigMatchCtx *ctx)
82 {
83  if (det_ctx->replist) {
85  det_ctx->replist = NULL;
86  }
87  return 1;
88 }
89 
90 int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *replacestr)
91 {
92  uint8_t *content = NULL;
93  uint16_t len = 0;
94 
95  if (s->init_data->negated) {
96  SCLogError(SC_ERR_INVALID_VALUE, "Can't negate replacement string: %s",
97  replacestr);
98  return -1;
99  }
100 
101  switch (run_mode) {
102  case RUNMODE_NFQ:
103  case RUNMODE_IPFW:
104  break;
105  default:
107  "Can't use 'replace' keyword in non IPS mode: %s",
108  s->sig_str);
109  /* this is a success, having the alert is interesting */
110  return 0;
111  }
112 
113  int ret = DetectContentDataParse("replace", replacestr, &content, &len);
114  if (ret == -1)
115  return -1;
116 
117  /* add to the latest "content" keyword from pmatch */
119  DETECT_CONTENT, -1);
120  if (pm == NULL) {
122  "preceding content option for raw sig");
123  SCFree(content);
124  return -1;
125  }
126 
127  /* we can remove this switch now with the unified structure */
129  if (ud == NULL) {
130  SCLogError(SC_ERR_INVALID_ARGUMENT, "invalid argument");
131  SCFree(content);
132  return -1;
133  }
134  if (ud->flags & DETECT_CONTENT_NEGATED) {
135  SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a relative "
136  "negated keyword set along with a replacement");
137  goto error;
138  }
139  if (ud->content_len != len) {
140  SCLogError(SC_ERR_INVALID_SIGNATURE, "can't have a content "
141  "length different from replace length");
142  goto error;
143  }
144 
145  ud->replace = SCMalloc(len);
146  if (ud->replace == NULL) {
147  goto error;
148  }
149  memcpy(ud->replace, content, len);
150  ud->replace_len = len;
152  /* want packet matching only won't be able to replace data with
153  * a flow.
154  */
156  SCFree(content);
157  content = NULL;
158 
159  SigMatch *sm = SigMatchAlloc();
160  if (unlikely(sm == NULL)) {
161  SCFree(ud->replace);
162  ud->replace = NULL;
163  goto error;
164  }
165  sm->type = DETECT_REPLACE;
166  sm->ctx = NULL;
168  return 0;
169 
170 error:
171  SCFree(ud->replace);
172  ud->replace = NULL;
173  SCFree(content);
174  return -1;
175 }
176 
177 /* Add to the head of the replace-list.
178  *
179  * The first to add to the replace-list has the highest priority. So,
180  * adding the the head of the list results in the newest modifications
181  * of content being applied first, so later changes can over ride
182  * earlier changes. Thus the highest priority modifications should be
183  * applied last.
184  */
186  uint8_t *found,
187  DetectContentData *cd)
188 {
189  DetectReplaceList *newlist;
190 
191  if (cd->content_len != cd->replace_len)
192  return NULL;
193  SCLogDebug("replace: Adding match");
194 
195  newlist = SCMalloc(sizeof(DetectReplaceList));
196  if (unlikely(newlist == NULL))
197  return replist;
198  newlist->found = found;
199  newlist->cd = cd;
200  /* Push new value onto the front of the list. */
201  newlist->next = replist;
202 
203  return newlist;
204 }
205 
206 
208 {
209  DetectReplaceList *tlist = NULL;
210 
211  SCLogDebug("replace: Executing match");
212  while (replist) {
213  memcpy(replist->found, replist->cd->replace, replist->cd->replace_len);
214  SCLogDebug("replace: injecting '%s'", replist->cd->replace);
217  tlist = replist;
218  replist = replist->next;
219  SCFree(tlist);
220  }
221 }
222 
223 
225 {
226  DetectReplaceList *tlist = NULL;
227  while (replist) {
228  SCLogDebug("replace: Freeing match");
229  tlist = replist;
230  replist = replist->next;
231  SCFree(tlist);
232  }
233 }
234 
235 #ifdef UNITTESTS /* UNITTESTS */
236 
237 /**
238  * \test Test packet Matches
239  * \param raw_eth_pkt pointer to the ethernet packet
240  * \param pktsize size of the packet
241  * \param sig pointer to the signature to test
242  * \param sid sid number of the signature
243  * \retval return 1 if match
244  * \retval return 0 if not
245  */
246 static
247 int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize,
248  const char *sig, uint32_t sid, uint8_t *pp,
249  uint16_t *len)
250 {
251  int result = 0;
252 
253  Packet *p = NULL;
254  p = PacketGetFromAlloc();
255  if (unlikely(p == NULL))
256  return 0;
257 
258  DecodeThreadVars dtv;
259 
260  ThreadVars th_v;
261  DetectEngineThreadCtx *det_ctx = NULL;
262 
263  if (pp == NULL) {
264  SCLogDebug("replace: looks like a second run");
265  }
266 
267  PacketCopyData(p, raw_eth_pkt, pktsize);
268  memset(&dtv, 0, sizeof(DecodeThreadVars));
269  memset(&th_v, 0, sizeof(th_v));
270  dtv.app_tctx = AppLayerGetCtxThread(&th_v);
271 
273  DecodeEthernet(&th_v, &dtv, p, GET_PKT_DATA(p), pktsize, NULL);
274 
276  if (de_ctx == NULL) {
277  goto end;
278  }
279  de_ctx->flags |= DE_QUIET;
280 
281  de_ctx->sig_list = SigInit(de_ctx, sig);
282  if (de_ctx->sig_list == NULL) {
283  goto end;
284  }
285  de_ctx->sig_list->next = NULL;
286 
287  if (de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->type == DETECT_CONTENT) {
288  DetectContentData *co = (DetectContentData *)de_ctx->sig_list->sm_lists_tail[DETECT_SM_LIST_PMATCH]->ctx;
290  printf("relative next flag set on final match which is content: ");
291  goto end;
292  }
293  }
294 
295  SigGroupBuild(de_ctx);
296  DetectEngineAddToMaster(de_ctx);
297  DetectEngineThreadCtxInit(&th_v, NULL, (void *)&det_ctx);
298 
299  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
301 
302  if (PacketAlertCheck(p, sid) != 1) {
303  SCLogDebug("replace: no alert on sig %d", sid);
304  goto end;
305  }
306 
307  if (pp) {
308  memcpy(pp, GET_PKT_DATA(p), GET_PKT_LEN(p));
309  *len = pktsize;
310  SCLogDebug("replace: copying %d on %p", *len, pp);
311  }
312 
313 
314  result = 1;
315 end:
316  if (dtv.app_tctx != NULL)
318  if (det_ctx != NULL)
319  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
321  PACKET_RECYCLE(p);
322  FlowShutdown();
323  SCFree(p);
324 
325 
326  return result;
327 }
328 
329 
330 /**
331  * \brief Wrapper for DetectContentLongPatternMatchTest
332  */
333 static int DetectReplaceLongPatternMatchTestWrp(const char *sig, uint32_t sid, const char *sig_rep, uint32_t sid_rep)
334 {
335  int ret;
336  /** Real packet with the following tcp data:
337  * "Hi, this is a big test to check content matches of splitted"
338  * "patterns between multiple chunks!"
339  * (without quotes! :) )
340  */
341  uint8_t raw_eth_pkt[] = {
342  0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
343  0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00,
344  0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06,
345  0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00,
346  0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00,
347  0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02,
348  0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69,
349  0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69,
350  0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20,
351  0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20,
352  0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f,
353  0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61,
354  0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66,
355  0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65,
356  0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
357  0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65,
358  0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69,
359  0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e,
360  0x6b,0x73,0x21 }; /* end raw_eth_pkt */
361  uint8_t p[sizeof(raw_eth_pkt)];
362  uint16_t psize = sizeof(raw_eth_pkt);
363 
364  /* would be unittest */
365  int run_mode_backup = run_mode;
367  ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
368  sig, sid, p, &psize);
369  if (ret == 1) {
370  SCLogDebug("replace: test1 phase1");
371  ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL);
372  }
373  run_mode = run_mode_backup;
374  return ret;
375 }
376 
377 
378 /**
379  * \brief Wrapper for DetectContentLongPatternMatchTest
380  */
381 static int DetectReplaceLongPatternMatchTestUDPWrp(const char *sig, uint32_t sid, const char *sig_rep, uint32_t sid_rep)
382 {
383  int ret;
384  /** Real UDP DNS packet with a request A to a1.twimg.com
385  */
386  uint8_t raw_eth_pkt[] = {
387  0x8c, 0xa9, 0x82, 0x75, 0x5d, 0x62, 0xb4, 0x07,
388  0xf9, 0xf3, 0xc7, 0x0a, 0x08, 0x00, 0x45, 0x00,
389  0x00, 0x3a, 0x92, 0x4f, 0x40, 0x00, 0x40, 0x11,
390  0x31, 0x1a, 0xc0, 0xa8, 0x00, 0x02, 0xc1, 0xbd,
391  0xf4, 0xe1, 0x3b, 0x7e, 0x00, 0x35, 0x00, 0x26,
392  0xcb, 0x81, 0x37, 0x62, 0x01, 0x00, 0x00, 0x01,
393  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x61,
394  0x31, 0x05, 0x74, 0x77, 0x69, 0x6d, 0x67, 0x03,
395  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 };
396 
397  uint8_t p[sizeof(raw_eth_pkt)];
398  uint16_t psize = sizeof(raw_eth_pkt);
399 
400  int run_mode_backup = run_mode;
402  ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
403  sig, sid, p, &psize);
404  if (ret == 1) {
405  SCLogDebug("replace: test1 phase1 ok: %" PRIuMAX" vs %d",(uintmax_t)sizeof(raw_eth_pkt),psize);
406  ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL);
407  }
408  run_mode = run_mode_backup;
409  return ret;
410 }
411 
412 /**
413  * \test Check if replace is working
414  */
415 static int DetectReplaceMatchTest01(void)
416 {
417  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
418  " content:\"big\"; replace:\"pig\"; sid:1;)";
419  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
420  " content:\"this is a pig test\"; sid:2;)";
421  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
422 }
423 
424 /**
425  * \test Check if replace is working with offset
426  */
427 static int DetectReplaceMatchTest02(void)
428 {
429  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
430  " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)";
431  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
432  " content:\"THis\"; offset:4; sid:2;)";
433  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
434 }
435 
436 /**
437  * \test Check if replace is working with offset and keyword inversion
438  */
439 static int DetectReplaceMatchTest03(void)
440 {
441  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
442  " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)";
443  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
444  " content:\"THis\"; offset:4; sid:2;)";
445  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
446 }
447 
448 /**
449  * \test Check if replace is working with second content
450  */
451 static int DetectReplaceMatchTest04(void)
452 {
453  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
454  " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)";
455  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
456  " content:\"THis\"; content:\"matterns\"; sid:2;)";
457  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
458 }
459 
460 /**
461  * \test Check if replace is not done when second content don't match
462  */
463 static int DetectReplaceMatchTest05(void)
464 {
465  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
466  " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)";
467  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
468  " content:\"TH\"; sid:2;)";
469  return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
470 }
471 
472 /**
473  * \test Check if replace is not done when second content match and not
474  * first
475  */
476 static int DetectReplaceMatchTest06(void)
477 {
478  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
479  " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)";
480  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
481  " content:\"commode\"; sid:2;)";
482  return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
483 }
484 
485 /**
486  * \test Check if replace is working when nocase used
487  */
488 static int DetectReplaceMatchTest07(void)
489 {
490  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
491  " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)";
492  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
493  " content:\"this is a pig test\"; sid:2;)";
494  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
495 }
496 
497 /**
498  * \test Check if replace is working when depth is used
499  */
500 static int DetectReplaceMatchTest08(void)
501 {
502  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
503  " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)";
504  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
505  " content:\"this is a pig test\"; sid:2;)";
506  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
507 }
508 
509 /**
510  * \test Check if replace is working when depth block match used
511  */
512 static int DetectReplaceMatchTest09(void)
513 {
514  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
515  " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)";
516  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
517  " content:\"this is a pig test\"; sid:2;)";
518  return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
519 }
520 
521 /**
522  * \test Check if replace is working when depth block match used
523  */
524 static int DetectReplaceMatchTest10(void)
525 {
526  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
527  " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)";
528  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
529  " content:\"pig\"; depth:17; offset:14; sid:2;)";
530  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
531 }
532 
533 /**
534  * \test Check if replace is working with within
535  */
536 static int DetectReplaceMatchTest11(void)
537 {
538  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
539  " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)";
540  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
541  " content:\"pig\"; depth:17; offset:14; sid:2;)";
542  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
543 }
544 
545 /**
546  * \test Check if replace is working with within
547  */
548 static int DetectReplaceMatchTest12(void)
549 {
550  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
551  " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)";
552  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
553  " content:\"pig\"; depth:17; offset:14; sid:2;)";
554  return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
555 }
556 
557 /**
558  * \test Check if replace is working with within
559  */
560 static int DetectReplaceMatchTest13(void)
561 {
562  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
563  " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; sid:1;)";
564  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
565  " content:\"pig\"; depth:17; offset:14; sid:2;)";
566  return DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
567 }
568 
569 /**
570  * \test Check if replace is working with within
571  */
572 static int DetectReplaceMatchTest14(void)
573 {
574  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
575  " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)";
576  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
577  " content:\"pig\"; depth:17; offset:14; sid:2;)";
578  return !DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2);
579 }
580 
581 /**
582  * \test Check if replace is working with within
583  */
584 static int DetectReplaceMatchTest15(void)
585 {
586  const char *sig = "alert udp any any -> any any (msg:\"Nothing..\";"
587  " content:\"com\"; replace:\"org\"; sid:1;)";
588  const char *sig_rep = "alert udp any any -> any any (msg:\"replace worked\";"
589  " content:\"twimg|03|org\"; sid:2;)";
590  return DetectReplaceLongPatternMatchTestUDPWrp(sig, 1, sig_rep, 2);
591 }
592 
593 
594 /**
595  * \test Parsing test
596  */
597 static int DetectReplaceParseTest01(void)
598 {
599  int run_mode_backup = run_mode;
601 
602  DetectEngineCtx *de_ctx = NULL;
603  int result = 1;
604 
605  de_ctx = DetectEngineCtxInit();
606  if (de_ctx == NULL)
607  goto end;
608 
609  de_ctx->flags |= DE_QUIET;
610  de_ctx->sig_list = SigInit(de_ctx,
611  "alert udp any any -> any any "
612  "(msg:\"test\"; content:\"doh\"; replace:\"; sid:238012;)");
613  if (de_ctx->sig_list != NULL) {
614  result = 0;
615  goto end;
616  }
617 
618  end:
619  run_mode = run_mode_backup;
620 
621  SigGroupCleanup(de_ctx);
622  SigCleanSignatures(de_ctx);
623  DetectEngineCtxFree(de_ctx);
624 
625  return result;
626 }
627 
628 /**
629  * \test Parsing test: non valid because of http protocol
630  */
631 static int DetectReplaceParseTest02(void)
632 {
633  int run_mode_backup = run_mode;
635 
636  DetectEngineCtx *de_ctx = NULL;
637  int result = 1;
638 
639  de_ctx = DetectEngineCtxInit();
640  if (de_ctx == NULL)
641  goto end;
642 
643  de_ctx->flags |= DE_QUIET;
644  de_ctx->sig_list = SigInit(de_ctx,
645  "alert http any any -> any any "
646  "(msg:\"test\"; content:\"doh\"; replace:\"bon\"; sid:238012;)");
647  if (de_ctx->sig_list == NULL) {
648  result = 0;
649  goto end;
650  }
651 
652  end:
653  run_mode = run_mode_backup;
654 
655  SigGroupCleanup(de_ctx);
656  SigCleanSignatures(de_ctx);
657  DetectEngineCtxFree(de_ctx);
658 
659  return result;
660 }
661 
662 /**
663  * \test Parsing test: non valid because of http_header on same content
664  * as replace keyword
665  */
666 static int DetectReplaceParseTest03(void)
667 {
668  int run_mode_backup = run_mode;
670 
671  DetectEngineCtx *de_ctx = NULL;
672  int result = 1;
673 
674  de_ctx = DetectEngineCtxInit();
675  if (de_ctx == NULL)
676  goto end;
677 
678  de_ctx->flags |= DE_QUIET;
679  de_ctx->sig_list = SigInit(de_ctx,
680  "alert tcp any any -> any any "
681  "(msg:\"test\"; content:\"doh\"; replace:\"don\"; http_header; sid:238012;)");
682  if (de_ctx->sig_list != NULL) {
683  result = 0;
684  goto end;
685  }
686 
687  end:
688  run_mode = run_mode_backup;
689 
690  SigGroupCleanup(de_ctx);
691  SigCleanSignatures(de_ctx);
692  DetectEngineCtxFree(de_ctx);
693 
694  return result;
695 }
696 
697 /**
698  * \test Parsing test no content
699  */
700 static int DetectReplaceParseTest04(void)
701 {
702  int run_mode_backup = run_mode;
704 
705  DetectEngineCtx *de_ctx = NULL;
706  int result = 1;
707 
708  de_ctx = DetectEngineCtxInit();
709  if (de_ctx == NULL)
710  goto end;
711 
712  de_ctx->flags |= DE_QUIET;
713  de_ctx->sig_list = SigInit(de_ctx,
714  "alert tcp any any -> any any "
715  "(msg:\"test\"; replace:\"don\"; sid:238012;)");
716  if (de_ctx->sig_list != NULL) {
717  result = 0;
718  goto end;
719  }
720 
721  end:
722  run_mode = run_mode_backup;
723 
724  SigGroupCleanup(de_ctx);
725  SigCleanSignatures(de_ctx);
726  DetectEngineCtxFree(de_ctx);
727 
728  return result;
729 }
730 
731 /**
732  * \test Parsing test content after replace
733  */
734 static int DetectReplaceParseTest05(void)
735 {
736  int run_mode_backup = run_mode;
738 
739  DetectEngineCtx *de_ctx = NULL;
740  int result = 1;
741 
742  de_ctx = DetectEngineCtxInit();
743  if (de_ctx == NULL)
744  goto end;
745 
746  de_ctx->flags |= DE_QUIET;
747  de_ctx->sig_list = SigInit(de_ctx,
748  "alert tcp any any -> any any "
749  "(msg:\"test\"; replace:\"don\"; content:\"doh\"; sid:238012;)");
750  if (de_ctx->sig_list != NULL) {
751  result = 0;
752  goto end;
753  }
754 
755  end:
756  run_mode = run_mode_backup;
757 
758  SigGroupCleanup(de_ctx);
759  SigCleanSignatures(de_ctx);
760  DetectEngineCtxFree(de_ctx);
761 
762  return result;
763 }
764 
765 /**
766  * \test Parsing test content and replace length differ
767  */
768 static int DetectReplaceParseTest06(void)
769 {
770  int run_mode_backup = run_mode;
772 
773  DetectEngineCtx *de_ctx = NULL;
774  int result = 1;
775 
776  de_ctx = DetectEngineCtxInit();
777  if (de_ctx == NULL)
778  goto end;
779 
780  de_ctx->flags |= DE_QUIET;
781  de_ctx->sig_list = SigInit(de_ctx,
782  "alert tcp any any -> any any "
783  "(msg:\"test\"; content:\"don\"; replace:\"donut\"; sid:238012;)");
784  if (de_ctx->sig_list != NULL) {
785  result = 0;
786  goto end;
787  }
788 
789  end:
790  run_mode = run_mode_backup;
791 
792  SigGroupCleanup(de_ctx);
793  SigCleanSignatures(de_ctx);
794  DetectEngineCtxFree(de_ctx);
795 
796  return result;
797 }
798 
799 /**
800  * \test Parsing test content and replace length differ
801  */
802 static int DetectReplaceParseTest07(void)
803 {
804  int run_mode_backup = run_mode;
806 
807  DetectEngineCtx *de_ctx = NULL;
808  int result = 1;
809 
810  de_ctx = DetectEngineCtxInit();
811  if (de_ctx == NULL)
812  goto end;
813 
814  de_ctx->flags |= DE_QUIET;
815  de_ctx->sig_list = SigInit(de_ctx,
816  "alert tcp any any -> any any "
817  "(msg:\"test\"; content:\"don\"; replace:\"dou\"; content:\"jpg\"; http_header; sid:238012;)");
818  if (de_ctx->sig_list != NULL) {
819  result = 0;
820  goto end;
821  }
822 
823  end:
824  run_mode = run_mode_backup;
825 
826  SigGroupCleanup(de_ctx);
827  SigCleanSignatures(de_ctx);
828  DetectEngineCtxFree(de_ctx);
829 
830  return result;
831 }
832 
833 
834 
835 #endif /* UNITTESTS */
836 
837 /**
838  * \brief this function registers unit tests for DetectContent
839  */
841 {
842 #ifdef UNITTESTS /* UNITTESTS */
843 /* matching */
844  UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01);
845  UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02);
846  UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03);
847  UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04);
848  UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05);
849  UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06);
850  UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07);
851  UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08);
852  UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09);
853  UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10);
854  UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11);
855  UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12);
856  UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13);
857  UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14);
858  UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15);
859 /* parsing */
860  UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01);
861  UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02);
862  UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03);
863  UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04);
864  UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05);
865  UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06);
866  UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07);
867 #endif /* UNITTESTS */
868 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1409
SignatureInitData * init_data
Definition: detect.h:564
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1150
#define SCLogDebug(...)
Definition: util-debug.h:335
void DetectEnginePruneFreeList(void)
SigMatch * DetectGetLastSMByListId(const Signature *s, int list_id,...)
Returns the sm with the largest index (added last) from the list passed to us as an id...
Definition: detect-parse.c:479
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
uint32_t flags
Definition: detect.h:497
void DetectReplaceFreeInternal(DetectReplaceList *replist)
#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
int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen)
Parse a content string, ie "abc|DE|fgh".
#define FLOW_QUIET
Definition: flow.h:38
DetectReplaceList * replist
Definition: detect.h:1078
void SigCleanSignatures(DetectEngineCtx *de_ctx)
#define PACKET_RECYCLE(p)
Definition: decode.h:817
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:228
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
const char * name
Definition: detect.h:1164
int DetectEngineAddToMaster(DetectEngineCtx *de_ctx)
Signature container.
Definition: detect.h:496
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:317
DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, DetectContentData *cd)
main detection engine ctx
Definition: detect.h:724
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
#define DE_QUIET
Definition: detect.h:296
void DetectReplaceRegisterTests(void)
this function registers unit tests for DetectContent
AppLayerThreadCtx * AppLayerGetCtxThread(ThreadVars *tv)
Creates a new app layer thread context.
Definition: app-layer.c:803
uint8_t flags
Definition: detect.h:725
Data structures and function prototypes for keeping state for the detection engine.
void(* Free)(void *)
Definition: detect.h:1155
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq)
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
AppLayerThreadCtx * app_tctx
Definition: decode.h:635
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.
#define PKT_STREAM_MODIFIED
Definition: decode.h:1094
Structure to hold thread specific data for all decode modules.
Definition: decode.h:632
void SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1742
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1348
void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist)
uint8_t * found
Definition: detect.h:606
int ReCalculateChecksum(Packet *p)
Definition: util-checksum.c:30
int SigGroupCleanup(DetectEngineCtx *de_ctx)
void DetectReplaceRegister(void)
struct Signature_ * next
Definition: detect.h:567
uint8_t type
Definition: detect.h:323
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
void SigMatchAppendSMToList(Signature *s, SigMatch *new, int list)
Append a SigMatch to the list type.
Definition: detect-parse.c:288
SigMatchCtx * ctx
Definition: detect.h:325
#define SCMalloc(a)
Definition: util-mem.h:166
#define DETECT_CONTENT_NEGATED
char * sig_str
Definition: detect.h:562
#define SCFree(a)
Definition: util-mem.h:228
#define DETECT_CONTENT_REPLACE
void AppLayerDestroyCtxThread(AppLayerThreadCtx *app_tctx)
Destroys the context created by AppLayeGetCtxThread().
Definition: app-layer.c:825
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:667
int(* Match)(ThreadVars *, DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1133
struct DetectContentData_ * cd
Definition: detect.h:605
#define GET_PKT_DATA(p)
Definition: decode.h:223
int run_mode
Definition: suricata.c:204
#define DETECT_CONTENT_RELATIVE_NEXT
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:232
uint8_t len
Per thread variable structure.
Definition: threadvars.h:57
#define GET_PKT_LEN(p)
Definition: decode.h:222
uint32_t flags
Definition: decode.h:441
#define SIGMATCH_HANDLE_NEGATION
Definition: detect.h:1352
struct DetectReplaceList_ * next
Definition: detect.h:607
uint16_t flags
Definition: detect.h:1158
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
int PacketCopyData(Packet *p, uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:258
void(* RegisterTests)(void)
Definition: detect.h:1156
a single match condition for a signature
Definition: detect.h:322
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:140
DetectEngineCtx * DetectEngineCtxInit(void)
void FlowInitConfig(char quiet)
initialize the configuration
Definition: flow.c:512