suricata
detect-replace.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-2022 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 #include "decode.h"
34 
35 #include "detect.h"
36 #include "detect-parse.h"
37 #include "detect-content.h"
38 #include "detect-replace.h"
39 #include "app-layer.h"
40 
41 #include "detect-engine-mpm.h"
42 #include "detect-engine.h"
43 #include "detect-engine-build.h"
44 
45 #include "util-checksum.h"
46 
47 #include "util-unittest.h"
48 
49 #include "util-debug.h"
50 
51 static int DetectReplaceSetup(DetectEngineCtx *, Signature *, const char *);
52 #ifdef UNITTESTS
53 static void DetectReplaceRegisterTests(void);
54 #endif
55 static int DetectReplacePostMatch(DetectEngineThreadCtx *det_ctx,
56  Packet *p, const Signature *s, const SigMatchCtx *ctx);
57 
59 {
60  sigmatch_table[DETECT_REPLACE].name = "replace";
61  sigmatch_table[DETECT_REPLACE].desc = "only to be used in IPS-mode. Change the following content into another";
62  sigmatch_table[DETECT_REPLACE].url = "/rules/payload-keywords.html#replace";
63  sigmatch_table[DETECT_REPLACE].Match = DetectReplacePostMatch;
64  sigmatch_table[DETECT_REPLACE].Setup = DetectReplaceSetup;
65 #ifdef UNITTESTS
66  sigmatch_table[DETECT_REPLACE].RegisterTests = DetectReplaceRegisterTests;
67 #endif
69 }
70 
71 static int DetectReplacePostMatch(DetectEngineThreadCtx *det_ctx,
72  Packet *p, const Signature *s, const SigMatchCtx *ctx)
73 {
74  if (det_ctx->replist) {
76  det_ctx->replist = NULL;
77  }
78  return 1;
79 }
80 
81 int DetectReplaceSetup(DetectEngineCtx *de_ctx, Signature *s, const char *replacestr)
82 {
83  uint8_t *content = NULL;
84  uint16_t len = 0;
85 
86  if (s->init_data->negated) {
87  SCLogError("Can't negate replacement string: %s", replacestr);
88  return -1;
89  }
90 
91  switch (SCRunmodeGet()) {
92  case RUNMODE_NFQ:
93  case RUNMODE_IPFW:
94  break;
95  default:
96  SCLogWarning("Can't use 'replace' keyword in non IPS mode: %s", s->sig_str);
97  /* this is a success, having the alert is interesting */
98  return 0;
99  }
100 
101  int ret = DetectContentDataParse("replace", replacestr, &content, &len);
102  if (ret == -1)
103  return -1;
104 
105  /* add to the latest "content" keyword from pmatch */
107  DETECT_CONTENT, -1);
108  if (pm == NULL) {
109  SCLogError("replace needs"
110  "preceding content option for raw sig");
111  SCFree(content);
112  return -1;
113  }
114 
115  /* we can remove this switch now with the unified structure */
117  if (ud == NULL) {
118  SCLogError("invalid argument");
119  SCFree(content);
120  return -1;
121  }
122  if (ud->flags & DETECT_CONTENT_NEGATED) {
123  SCLogError("can't have a relative "
124  "negated keyword set along with a replacement");
125  goto error;
126  }
127  if (ud->content_len != len) {
128  SCLogError("can't have a content "
129  "length different from replace length");
130  goto error;
131  }
132 
133  ud->replace = SCMalloc(len);
134  if (ud->replace == NULL) {
135  goto error;
136  }
137  memcpy(ud->replace, content, len);
138  ud->replace_len = len;
140  /* want packet matching only won't be able to replace data with
141  * a flow.
142  */
144  SCFree(content);
145  content = NULL;
146 
148  NULL) {
149  goto error;
150  }
151  return 0;
152 
153 error:
154  SCFree(ud->replace);
155  ud->replace = NULL;
156  SCFree(content);
157  return -1;
158 }
159 
160 /* Add to the head of the replace-list.
161  *
162  * The first to add to the replace-list has the highest priority. So,
163  * adding the head of the list results in the newest modifications
164  * of content being applied first, so later changes can over ride
165  * earlier changes. Thus the highest priority modifications should be
166  * applied last.
167  */
169  DetectReplaceList *replist, uint8_t *found, const DetectContentData *cd)
170 {
171  if (cd->content_len != cd->replace_len)
172  return NULL;
173  SCLogDebug("replace: Adding match");
174 
175  DetectReplaceList *newlist = SCMalloc(sizeof(DetectReplaceList));
176  if (unlikely(newlist == NULL))
177  return replist;
178  newlist->found = found;
179  newlist->cd = cd;
180  /* Push new value onto the front of the list. */
181  newlist->next = replist;
182  return newlist;
183 }
184 
186 {
187  DetectReplaceList *tlist = NULL;
188 
189  SCLogDebug("replace: Executing match");
190  while (replist) {
191  memcpy(replist->found, replist->cd->replace, replist->cd->replace_len);
192  SCLogDebug("replace: replaced data");
195  tlist = replist;
196  replist = replist->next;
197  SCFree(tlist);
198  }
199 }
200 
201 
203 {
204  DetectReplaceList *tlist = NULL;
205  while (replist) {
206  SCLogDebug("replace: Freeing match");
207  tlist = replist;
208  replist = replist->next;
209  SCFree(tlist);
210  }
211 }
212 
213 #ifdef UNITTESTS /* UNITTESTS */
214 #include "detect-engine-alert.h"
215 #include "packet.h"
216 
217 /**
218  * \test Test packet Matches
219  * \param raw_eth_pkt pointer to the ethernet packet
220  * \param pktsize size of the packet
221  * \param sig pointer to the signature to test
222  * \param sid sid number of the signature
223  * \retval return 1 if match
224  * \retval return 0 if not
225  */
226 static
227 int DetectReplaceLongPatternMatchTest(uint8_t *raw_eth_pkt, uint16_t pktsize,
228  const char *sig, uint32_t sid, uint8_t *pp,
229  uint16_t *len)
230 {
231  int result = 0;
232 
233  Packet *p = PacketGetFromAlloc();
234  if (unlikely(p == NULL))
235  return 0;
236 
238  ThreadVars th_v;
239  memset(&dtv, 0, sizeof(DecodeThreadVars));
240  memset(&th_v, 0, sizeof(th_v));
241  DetectEngineThreadCtx *det_ctx = NULL;
242 
243  if (pp == NULL) {
244  SCLogDebug("replace: looks like a second run");
245  }
246 
247  PacketCopyData(p, raw_eth_pkt, pktsize);
250  DecodeEthernet(&th_v, &dtv, p, GET_PKT_DATA(p), pktsize);
251 
253  if (de_ctx == NULL) {
254  goto end;
255  }
256  de_ctx->flags |= DE_QUIET;
257 
259  if (s == NULL) {
260  goto end;
261  }
262 
264  DetectContentData *co =
267  printf("relative next flag set on final match which is content: ");
268  goto end;
269  }
270  }
271 
274  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
275  BUG_ON(det_ctx == NULL);
276 
277  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
279 
280  if (PacketAlertCheck(p, sid) != 1) {
281  SCLogDebug("replace: no alert on sig %d", sid);
282  goto end;
283  }
284 
285  if (pp) {
286  memcpy(pp, GET_PKT_DATA(p), GET_PKT_LEN(p));
287  *len = pktsize;
288  SCLogDebug("replace: copying %d on %p", *len, pp);
289  }
290 
291  result = 1;
292 end:
293  if (dtv.app_tctx != NULL)
295  if (det_ctx != NULL)
296  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
298  PacketFree(p);
299  FlowShutdown();
300  StatsThreadCleanup(&th_v);
301  return result;
302 }
303 
304 
305 /**
306  * \brief Wrapper for DetectContentLongPatternMatchTest
307  */
308 static int DetectReplaceLongPatternMatchTestWrp(const char *sig, uint32_t sid, const char *sig_rep, uint32_t sid_rep)
309 {
310  int ret;
311  /** Real packet with the following tcp data:
312  * "Hi, this is a big test to check content matches of splitted"
313  * "patterns between multiple chunks!"
314  * (without quotes! :) )
315  */
316  uint8_t raw_eth_pkt[] = {
317  0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
318  0x00,0x00,0x00,0x00,0x08,0x00,0x45,0x00,
319  0x00,0x85,0x00,0x01,0x00,0x00,0x40,0x06,
320  0x7c,0x70,0x7f,0x00,0x00,0x01,0x7f,0x00,
321  0x00,0x01,0x00,0x14,0x00,0x50,0x00,0x00,
322  0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x02,
323  0x20,0x00,0xc9,0xad,0x00,0x00,0x48,0x69,
324  0x2c,0x20,0x74,0x68,0x69,0x73,0x20,0x69,
325  0x73,0x20,0x61,0x20,0x62,0x69,0x67,0x20,
326  0x74,0x65,0x73,0x74,0x20,0x74,0x6f,0x20,
327  0x63,0x68,0x65,0x63,0x6b,0x20,0x63,0x6f,
328  0x6e,0x74,0x65,0x6e,0x74,0x20,0x6d,0x61,
329  0x74,0x63,0x68,0x65,0x73,0x20,0x6f,0x66,
330  0x20,0x73,0x70,0x6c,0x69,0x74,0x74,0x65,
331  0x64,0x20,0x70,0x61,0x74,0x74,0x65,0x72,
332  0x6e,0x73,0x20,0x62,0x65,0x74,0x77,0x65,
333  0x65,0x6e,0x20,0x6d,0x75,0x6c,0x74,0x69,
334  0x70,0x6c,0x65,0x20,0x63,0x68,0x75,0x6e,
335  0x6b,0x73,0x21 }; /* end raw_eth_pkt */
336  uint8_t p[sizeof(raw_eth_pkt)];
337  uint16_t psize = sizeof(raw_eth_pkt);
338 
339  /* would be unittest */
340  int run_mode_backup = SCRunmodeGet();
342  ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
343  sig, sid, p, &psize);
344  if (ret == 1) {
345  SCLogDebug("replace: test1 phase1");
346  ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL);
347  }
348  SCRunmodeSet(run_mode_backup);
349  return ret;
350 }
351 
352 
353 /**
354  * \brief Wrapper for DetectContentLongPatternMatchTest
355  */
356 static int DetectReplaceLongPatternMatchTestUDPWrp(const char *sig, uint32_t sid, const char *sig_rep, uint32_t sid_rep)
357 {
358  int ret;
359  /** Real UDP DNS packet with a request A to a1.twimg.com
360  */
361  uint8_t raw_eth_pkt[] = {
362  0x8c, 0xa9, 0x82, 0x75, 0x5d, 0x62, 0xb4, 0x07,
363  0xf9, 0xf3, 0xc7, 0x0a, 0x08, 0x00, 0x45, 0x00,
364  0x00, 0x3a, 0x92, 0x4f, 0x40, 0x00, 0x40, 0x11,
365  0x31, 0x1a, 0xc0, 0xa8, 0x00, 0x02, 0xc1, 0xbd,
366  0xf4, 0xe1, 0x3b, 0x7e, 0x00, 0x35, 0x00, 0x26,
367  0xcb, 0x81, 0x37, 0x62, 0x01, 0x00, 0x00, 0x01,
368  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x61,
369  0x31, 0x05, 0x74, 0x77, 0x69, 0x6d, 0x67, 0x03,
370  0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01 };
371 
372  uint8_t p[sizeof(raw_eth_pkt)];
373  uint16_t psize = sizeof(raw_eth_pkt);
374 
375  int run_mode_backup = SCRunmodeGet();
377  ret = DetectReplaceLongPatternMatchTest(raw_eth_pkt, (uint16_t)sizeof(raw_eth_pkt),
378  sig, sid, p, &psize);
379  if (ret == 1) {
380  SCLogDebug("replace: test1 phase1 ok: %" PRIuMAX" vs %d",(uintmax_t)sizeof(raw_eth_pkt),psize);
381  ret = DetectReplaceLongPatternMatchTest(p, psize, sig_rep, sid_rep, NULL, NULL);
382  }
383  SCRunmodeSet(run_mode_backup);
384  return ret;
385 }
386 
387 /**
388  * \test Check if replace is working
389  */
390 static int DetectReplaceMatchTest01(void)
391 {
392  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
393  " content:\"big\"; replace:\"pig\"; sid:1;)";
394  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
395  " content:\"this is a pig test\"; sid:2;)";
396  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
397  PASS;
398 }
399 
400 /**
401  * \test Check if replace is working with offset
402  */
403 static int DetectReplaceMatchTest02(void)
404 {
405  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
406  " content:\"th\"; offset: 4; replace:\"TH\"; sid:1;)";
407  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
408  " content:\"THis\"; offset:4; sid:2;)";
409  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
410  PASS;
411 }
412 
413 /**
414  * \test Check if replace is working with offset and keyword inversion
415  */
416 static int DetectReplaceMatchTest03(void)
417 {
418  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
419  " content:\"th\"; replace:\"TH\"; offset: 4; sid:1;)";
420  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
421  " content:\"THis\"; offset:4; sid:2;)";
422  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
423  PASS;
424 }
425 
426 /**
427  * \test Check if replace is working with second content
428  */
429 static int DetectReplaceMatchTest04(void)
430 {
431  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
432  " content:\"th\"; replace:\"TH\"; content:\"patter\"; replace:\"matter\"; sid:1;)";
433  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
434  " content:\"THis\"; content:\"matterns\"; sid:2;)";
435  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
436  PASS;
437 }
438 
439 /**
440  * \test Check if replace is not done when second content don't match
441  */
442 static int DetectReplaceMatchTest05(void)
443 {
444  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
445  " content:\"th\"; replace:\"TH\"; content:\"nutella\"; sid:1;)";
446  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
447  " content:\"TH\"; sid:2;)";
448  FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
449  PASS;
450 }
451 
452 /**
453  * \test Check if replace is not done when second content match and not
454  * first
455  */
456 static int DetectReplaceMatchTest06(void)
457 {
458  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
459  " content:\"nutella\"; replace:\"commode\"; content:\"this is\"; sid:1;)";
460  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
461  " content:\"commode\"; sid:2;)";
462  FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
463  PASS;
464 }
465 
466 /**
467  * \test Check if replace is working when nocase used
468  */
469 static int DetectReplaceMatchTest07(void)
470 {
471  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
472  " content:\"BiG\"; nocase; replace:\"pig\"; sid:1;)";
473  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
474  " content:\"this is a pig test\"; sid:2;)";
475  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
476  PASS;
477 }
478 
479 /**
480  * \test Check if replace is working when depth is used
481  */
482 static int DetectReplaceMatchTest08(void)
483 {
484  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
485  " content:\"big\"; depth:17; replace:\"pig\"; sid:1;)";
486  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
487  " content:\"this is a pig test\"; sid:2;)";
488  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
489  PASS;
490 }
491 
492 /**
493  * \test Check if replace is working when depth block match used
494  */
495 static int DetectReplaceMatchTest09(void)
496 {
497  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
498  " content:\"big\"; depth:16; replace:\"pig\"; sid:1;)";
499  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
500  " content:\"this is a pig test\"; sid:2;)";
501  FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
502  PASS;
503 }
504 
505 /**
506  * \test Check if replace is working when depth block match used
507  */
508 static int DetectReplaceMatchTest10(void)
509 {
510  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
511  " content:\"big\"; depth:17; replace:\"pig\"; offset: 14; sid:1;)";
512  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
513  " content:\"pig\"; depth:17; offset:14; sid:2;)";
514  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
515  PASS;
516 }
517 
518 /**
519  * \test Check if replace is working with within
520  */
521 static int DetectReplaceMatchTest11(void)
522 {
523  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
524  " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 11; sid:1;)";
525  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
526  " content:\"pig\"; depth:17; offset:14; sid:2;)";
527 
528  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
529  PASS;
530 }
531 
532 /**
533  * \test Check if replace is working with within
534  */
535 static int DetectReplaceMatchTest12(void)
536 {
537  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
538  " content:\"big\"; replace:\"pig\"; content:\"to\"; within: 4; sid:1;)";
539  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
540  " content:\"pig\"; depth:17; offset:14; sid:2;)";
541  FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
542  PASS;
543 }
544 
545 /**
546  * \test Check if replace is working with within
547  */
548 static int DetectReplaceMatchTest13(void)
549 {
550  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
551  " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 1; 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  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
555  PASS;
556 }
557 
558 /**
559  * \test Check if replace is working with within
560  */
561 static int DetectReplaceMatchTest14(void)
562 {
563  const char *sig = "alert tcp any any -> any any (msg:\"Nothing..\";"
564  " content:\"big\"; replace:\"pig\"; content:\"test\"; distance: 2; sid:1;)";
565  const char *sig_rep = "alert tcp any any -> any any (msg:\"replace worked\";"
566  " content:\"pig\"; depth:17; offset:14; sid:2;)";
567  FAIL_IF(DetectReplaceLongPatternMatchTestWrp(sig, 1, sig_rep, 2));
568  PASS;
569 }
570 
571 /**
572  * \test Check if replace is working with within
573  */
574 static int DetectReplaceMatchTest15(void)
575 {
576  const char *sig = "alert udp any any -> any any (msg:\"Nothing..\";"
577  " content:\"com\"; replace:\"org\"; sid:1;)";
578  const char *sig_rep = "alert udp any any -> any any (msg:\"replace worked\";"
579  " content:\"twimg|03|org\"; sid:2;)";
580  FAIL_IF_NOT(DetectReplaceLongPatternMatchTestUDPWrp(sig, 1, sig_rep, 2));
581  PASS;
582 }
583 
584 
585 /**
586  * \test Parsing test
587  */
588 static int DetectReplaceParseTest01(void)
589 {
590  int run_mode_backup = SCRunmodeGet();
592 
595 
596  de_ctx->flags |= DE_QUIET;
598  "alert udp any any -> any any "
599  "(msg:\"test\"; content:\"doh\"; replace:\"; sid:238012;)"));
600 
601  SCRunmodeSet(run_mode_backup);
603  PASS;
604 }
605 
606 /**
607  * \test Parsing test: non valid because of http protocol
608  */
609 static int DetectReplaceParseTest02(void)
610 {
611  int run_mode_backup = SCRunmodeGet();
613 
616 
617  de_ctx->flags |= DE_QUIET;
619  "alert http any any -> any any "
620  "(msg:\"test\"; content:\"doh\"; replace:\"bon\"; sid:238012;)"));
621 
622  SCRunmodeSet(run_mode_backup);
624  PASS;
625 }
626 
627 /**
628  * \test Parsing test: non valid because of http_header on same content
629  * as replace keyword
630  */
631 static int DetectReplaceParseTest03(void)
632 {
633  int run_mode_backup = SCRunmodeGet();
635 
637 
639 
640  de_ctx->flags |= DE_QUIET;
642  "alert tcp any any -> any any "
643  "(msg:\"test\"; content:\"doh\"; replace:\"don\"; http_header; sid:238012;)"));
644 
645  SCRunmodeSet(run_mode_backup);
647  PASS;
648 }
649 
650 /**
651  * \test Parsing test no content
652  */
653 static int DetectReplaceParseTest04(void)
654 {
655  int run_mode_backup = SCRunmodeGet();
657 
660 
661  de_ctx->flags |= DE_QUIET;
662  FAIL_IF_NOT_NULL(DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
663  "(msg:\"test\"; replace:\"don\"; sid:238012;)"));
664 
665  SCRunmodeSet(run_mode_backup);
667  PASS;
668 }
669 
670 /**
671  * \test Parsing test content after replace
672  */
673 static int DetectReplaceParseTest05(void)
674 {
675  int run_mode_backup = SCRunmodeGet();
677 
680 
681  de_ctx->flags |= DE_QUIET;
683  "alert tcp any any -> any any "
684  "(msg:\"test\"; replace:\"don\"; content:\"doh\"; sid:238012;)"));
685 
686  SCRunmodeSet(run_mode_backup);
688  PASS;
689 }
690 
691 /**
692  * \test Parsing test content and replace length differ
693  */
694 static int DetectReplaceParseTest06(void)
695 {
696  int run_mode_backup = SCRunmodeGet();
698 
701 
702  de_ctx->flags |= DE_QUIET;
704  "alert tcp any any -> any any "
705  "(msg:\"test\"; content:\"don\"; replace:\"donut\"; sid:238012;)"));
706 
707  SCRunmodeSet(run_mode_backup);
709  PASS;
710 }
711 
712 /**
713  * \test Parsing test content and replace length differ
714  */
715 static int DetectReplaceParseTest07(void)
716 {
717  int run_mode_backup = SCRunmodeGet();
719 
722 
723  de_ctx->flags |= DE_QUIET;
725  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any "
726  "(msg:\"test\"; content:\"don\"; replace:\"dou\"; "
727  "content:\"jpg\"; http_header; sid:238012;)"));
728 
729  SCRunmodeSet(run_mode_backup);
731  PASS;
732 }
733 
734 /**
735  * \brief this function registers unit tests for DetectContent
736  */
737 void DetectReplaceRegisterTests(void)
738 {
739 /* matching */
740  UtRegisterTest("DetectReplaceMatchTest01", DetectReplaceMatchTest01);
741  UtRegisterTest("DetectReplaceMatchTest02", DetectReplaceMatchTest02);
742  UtRegisterTest("DetectReplaceMatchTest03", DetectReplaceMatchTest03);
743  UtRegisterTest("DetectReplaceMatchTest04", DetectReplaceMatchTest04);
744  UtRegisterTest("DetectReplaceMatchTest05", DetectReplaceMatchTest05);
745  UtRegisterTest("DetectReplaceMatchTest06", DetectReplaceMatchTest06);
746  UtRegisterTest("DetectReplaceMatchTest07", DetectReplaceMatchTest07);
747  UtRegisterTest("DetectReplaceMatchTest08", DetectReplaceMatchTest08);
748  UtRegisterTest("DetectReplaceMatchTest09", DetectReplaceMatchTest09);
749  UtRegisterTest("DetectReplaceMatchTest10", DetectReplaceMatchTest10);
750  UtRegisterTest("DetectReplaceMatchTest11", DetectReplaceMatchTest11);
751  UtRegisterTest("DetectReplaceMatchTest12", DetectReplaceMatchTest12);
752  UtRegisterTest("DetectReplaceMatchTest13", DetectReplaceMatchTest13);
753  UtRegisterTest("DetectReplaceMatchTest14", DetectReplaceMatchTest14);
754  UtRegisterTest("DetectReplaceMatchTest15", DetectReplaceMatchTest15);
755 /* parsing */
756  UtRegisterTest("DetectReplaceParseTest01", DetectReplaceParseTest01);
757  UtRegisterTest("DetectReplaceParseTest02", DetectReplaceParseTest02);
758  UtRegisterTest("DetectReplaceParseTest03", DetectReplaceParseTest03);
759  UtRegisterTest("DetectReplaceParseTest04", DetectReplaceParseTest04);
760  UtRegisterTest("DetectReplaceParseTest05", DetectReplaceParseTest05);
761  UtRegisterTest("DetectReplaceParseTest06", DetectReplaceParseTest06);
762  UtRegisterTest("DetectReplaceParseTest07", DetectReplaceParseTest07);
763 }
764 #endif /* UNITTESTS */
SigTableElmt_::url
const char * url
Definition: detect.h:1460
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
detect-content.h
DetectReplaceList_::cd
const struct DetectContentData_ * cd
Definition: detect.h:816
len
uint8_t len
Definition: app-layer-dnp3.h:2
detect-engine.h
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:119
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:1459
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:745
PacketCopyData
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:381
SigTableElmt_::name
const char * name
Definition: detect.h:1457
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:644
DetectEnginePruneFreeList
void DetectEnginePruneFreeList(void)
Definition: detect-engine.c:4729
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
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:69
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1448
PKT_STREAM_MODIFIED
#define PKT_STREAM_MODIFIED
Definition: decode.h:1273
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:279
util-checksum.h
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:142
Packet_::flags
uint32_t flags
Definition: decode.h:544
DETECT_REPLACE
@ DETECT_REPLACE
Definition: detect-engine-register.h:78
RUNMODE_NFQ
@ RUNMODE_NFQ
Definition: runmodes.h:31
DetectReplaceList_::found
uint8_t * found
Definition: detect.h:817
ctx
struct Thresholds ctx
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2634
DetectEngineAddToMaster
int DetectEngineAddToMaster(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:4659
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
DetectReplaceList_
Definition: detect.h:815
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2416
DetectContentData_
Definition: detect-content.h:93
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3439
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1439
util-unittest.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
DetectGetLastSMByListId
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:658
SCRunmodeSet
void SCRunmodeSet(SCRunMode run_mode)
Set the current run mode.
Definition: suricata.c:284
DetectReplaceAddToList
DetectReplaceList * DetectReplaceAddToList(DetectReplaceList *replist, uint8_t *found, const DetectContentData *cd)
Definition: detect-replace.c:168
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1666
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:549
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:127
SCRunmodeGet
SCRunMode SCRunmodeGet(void)
Get the current run mode.
Definition: suricata.c:279
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
DetectEngineMoveToFreeList
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:4719
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectReplaceRegister
void DetectReplaceRegister(void)
Definition: detect-replace.c:58
DetectEngineThreadCtx_
Definition: detect.h:1244
DetectReplaceList_::next
struct DetectReplaceList_ * next
Definition: detect.h:818
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:209
detect-engine-mpm.h
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:388
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3364
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:223
DETECT_CONTENT_NEGATED
#define DETECT_CONTENT_NEGATED
Definition: detect-content.h:40
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:259
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
Signature_::flags
uint32_t flags
Definition: detect.h:669
Packet_
Definition: decode.h:501
detect-engine-build.h
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:208
DecodeThreadVars_::app_tctx
AppLayerThreadCtx * app_tctx
Definition: decode.h:965
detect-engine-alert.h
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DetectContentData_::replace_len
uint16_t replace_len
Definition: detect-content.h:96
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect.h:1670
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:747
AppLayerGetCtxThread
AppLayerThreadCtx * AppLayerGetCtxThread(void)
Creates a new app layer thread context.
Definition: app-layer.c:1104
SignatureInitData_::negated
bool negated
Definition: detect.h:597
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1419
detect-replace.h
DetectContentData_::replace
uint8_t * replace
Definition: detect-content.h:113
runmodes.h
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2194
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
ReCalculateChecksum
int ReCalculateChecksum(Packet *p)
Definition: util-checksum.c:29
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
DetectContentDataParse
int DetectContentDataParse(const char *keyword, const char *contentstr, uint8_t **pstr, uint16_t *plen)
Parse a content string, ie "abc|DE|fgh".
Definition: detect-content.c:85
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:357
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:693
packet.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3596
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:262
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:271
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:963
AppLayerDestroyCtxThread
void AppLayerDestroyCtxThread(AppLayerThreadCtx *app_tctx)
Destroys the context created by AppLayerGetCtxThread().
Definition: app-layer.c:1125
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
SigMatch_
a single match condition for a signature
Definition: detect.h:356
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2595
DetectReplaceFreeInternal
void DetectReplaceFreeInternal(DetectReplaceList *replist)
Definition: detect-replace.c:202
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectContentData_::content_len
uint16_t content_len
Definition: detect-content.h:95
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:934
DetectEngineThreadCtx_::replist
DetectReplaceList * replist
Definition: detect.h:1350
DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_REPLACE
Definition: detect-content.h:51
DetectReplaceExecuteInternal
void DetectReplaceExecuteInternal(Packet *p, DetectReplaceList *replist)
Definition: detect-replace.c:185
StatsThreadCleanup
void StatsThreadCleanup(ThreadVars *tv)
Definition: counters.c:1324
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
RUNMODE_IPFW
@ RUNMODE_IPFW
Definition: runmodes.h:33
SigTableElmt_::RegisterTests
void(* RegisterTests)(void)
Definition: detect.h:1446
app-layer.h
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:254