suricata
detect-parse.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 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 Victor Julien <victor@inliniac.net>
22  *
23  * signature parser
24  */
25 
26 #include "suricata-common.h"
27 
28 #include "detect.h"
29 #include "detect-engine.h"
30 #include "detect-engine-address.h"
31 #include "detect-engine-port.h"
32 #include "detect-engine-mpm.h"
33 #include "detect-engine-state.h"
34 #include "detect-engine-build.h"
35 
36 #include "detect-content.h"
37 #include "detect-bsize.h"
38 #include "detect-isdataat.h"
39 #include "detect-pcre.h"
40 #include "detect-uricontent.h"
41 #include "detect-reference.h"
42 #include "detect-ipproto.h"
43 #include "detect-flow.h"
45 #include "detect-lua.h"
46 #include "detect-app-layer-event.h"
47 #include "detect-http-method.h"
48 
49 #include "pkt-var.h"
50 #include "host.h"
51 #include "util-profiling.h"
52 #include "decode.h"
53 
54 #include "flow.h"
55 
56 #include "util-rule-vars.h"
57 #include "conf.h"
58 #include "conf-yaml-loader.h"
59 
60 #include "app-layer.h"
61 #include "app-layer-protos.h"
62 #include "app-layer-parser.h"
63 #include "app-layer-htp.h"
64 
66 #include "util-unittest.h"
67 #include "util-unittest-helper.h"
68 #include "util-debug.h"
69 #include "string.h"
70 #include "detect-parse.h"
71 #include "detect-engine-iponly.h"
72 #include "detect-engine-file.h"
73 #include "app-layer-detect-proto.h"
74 
75 #include "action-globals.h"
76 #include "util-validate.h"
77 
78 /* Table with all SigMatch registrations */
80 
81 extern bool sc_set_caps;
82 
83 static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
84  SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
85  SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail);
86 
87 /**
88  * \brief Registration table for file handlers
89  */
90 /**
91  * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table.
92  */
93 typedef struct SigDuplWrapper_ {
94  /* the signature we want to wrap */
96  /* the signature right before the above signature in the det_ctx->sig_list */
99 
100 /** helper structure for sig parsing */
101 typedef struct SignatureParser_ {
111 
112 const char *DetectListToHumanString(int list)
113 {
114 #define CASE_CODE_STRING(E, S) case E: return S; break
115  switch (list) {
123  CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
124  }
125 #undef CASE_CODE_STRING
126  return "unknown";
127 }
128 
129 #define CASE_CODE(E) case E: return #E
130 const char *DetectListToString(int list)
131 {
132  switch (list) {
141  }
142  return "unknown";
143 }
144 
145 /** \param arg NULL or empty string */
147  Signature *s, const char *arg, int sm_type, int sm_list,
148  AppProto alproto)
149 {
150  SigMatch *sm = NULL;
151  int ret = -1;
152 
153  if (arg != NULL && strcmp(arg, "") != 0) {
154  SCLogError("%s shouldn't be supplied "
155  "with an argument",
156  sigmatch_table[sm_type].name);
157  goto end;
158  }
159 
160  if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
161  SCLogError("\"%s\" keyword seen "
162  "with a sticky buffer still set. Reset sticky buffer "
163  "with pkt_data before using the modifier.",
164  sigmatch_table[sm_type].name);
165  goto end;
166  }
167  if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
168  SCLogError("rule contains conflicting "
169  "alprotos set");
170  goto end;
171  }
172 
175  if (sm == NULL) {
176  SCLogError("\"%s\" keyword "
177  "found inside the rule without a content context. "
178  "Please use a \"content\" keyword before using the "
179  "\"%s\" keyword",
180  sigmatch_table[sm_type].name, sigmatch_table[sm_type].name);
181  goto end;
182  }
184  if (cd->flags & DETECT_CONTENT_RAWBYTES) {
185  SCLogError("%s rule can not "
186  "be used with the rawbytes rule keyword",
187  sigmatch_table[sm_type].name);
188  goto end;
189  }
190  if (cd->flags & DETECT_CONTENT_REPLACE) {
191  SCLogError("%s rule can not "
192  "be used with the replace rule keyword",
193  sigmatch_table[sm_type].name);
194  goto end;
195  }
199  if (pm != NULL) {
200  if (pm->type == DETECT_CONTENT) {
201  DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
203  } else {
204  DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
205  tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT;
206  }
207  }
208 
209  if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id == sm_list) {
212  if (pm != NULL) {
213  if (pm->type == DETECT_CONTENT) {
214  DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
216  } else {
217  DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
218  tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
219  }
220  }
221  }
222  }
223  s->alproto = alproto;
224  s->flags |= SIG_FLAG_APPLAYER;
225 
226  if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
227  if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
228  SCLogError("no matches for previous buffer");
229  return -1;
230  }
231  bool reuse_buffer = false;
232  if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
233  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
234  if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
235  s->init_data->curbuf = &s->init_data->buffers[x];
236  reuse_buffer = true;
237  break;
238  }
239  }
240  }
241 
242  if (!reuse_buffer) {
244  SCLogError("failed to expand rule buffer array");
245  return -1;
246  }
247 
248  /* initialize a new buffer */
250  s->init_data->curbuf->id = sm_list;
251  s->init_data->curbuf->head = NULL;
252  s->init_data->curbuf->tail = NULL;
253  SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u",
254  s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf,
255  s->init_data->buffer_index);
256  }
257  }
258 
259  /* transfer the sm from the pmatch list to sm_list */
260  SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH],
262  &s->init_data->curbuf->tail);
263 
264  if (sm->type == DETECT_CONTENT) {
266  MAX(s->init_data->max_content_list_id, (uint32_t)sm_list);
267  }
268 
269  ret = 0;
270  end:
271  return ret;
272 }
273 
275 {
276  SigMatch *sm = SCCalloc(1, sizeof(SigMatch));
277  if (unlikely(sm == NULL))
278  return NULL;
279 
280  sm->prev = NULL;
281  sm->next = NULL;
282  return sm;
283 }
284 
285 /** \brief free a SigMatch
286  * \param sm SigMatch to free.
287  */
289 {
290  if (sm == NULL)
291  return;
292 
293  /** free the ctx, for that we call the Free func */
294  if (sm->ctx != NULL) {
295  if (sigmatch_table[sm->type].Free != NULL) {
296  sigmatch_table[sm->type].Free(de_ctx, sm->ctx);
297  }
298  }
299  SCFree(sm);
300 }
301 
302 static enum DetectKeywordId SigTableGetIndex(const SigTableElmt *e)
303 {
304  const SigTableElmt *table = &sigmatch_table[0];
305  ptrdiff_t offset = e - table;
307  return (enum DetectKeywordId)offset;
308 }
309 
310 /* Get the detection module by name */
311 static SigTableElmt *SigTableGet(char *name)
312 {
313  SigTableElmt *st = NULL;
314  int i = 0;
315 
316  for (i = 0; i < DETECT_TBLSIZE; i++) {
317  st = &sigmatch_table[i];
318 
319  if (st->name != NULL) {
320  if (strcasecmp(name,st->name) == 0)
321  return st;
322  if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
323  return st;
324  }
325  }
326 
327  return NULL;
328 }
329 
331  const enum DetectKeywordId id)
332 {
334 }
335 
337 {
338  if ((int)id < DETECT_TBLSIZE) {
339  return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0);
340  }
341  return false;
342 }
343 
345 {
346  if (str == NULL) {
347  /* nothing to be done */
348  return;
349  }
350 
351  /* "all" just sets the flag for each keyword */
352  if (strcmp(str, "all") == 0) {
353  for (int i = 0; i < DETECT_TBLSIZE; i++) {
354  SigTableElmt *st = &sigmatch_table[i];
356  }
357  return;
358  }
359 
360  char *copy = SCStrdup(str);
361  if (copy == NULL)
362  FatalError("could not duplicate opt string");
363 
364  char *xsaveptr = NULL;
365  char *key = strtok_r(copy, ",", &xsaveptr);
366  while (key != NULL) {
367  SigTableElmt *st = SigTableGet(key);
368  if (st != NULL) {
370  } else {
371  SCLogWarning("'strict' command line "
372  "argument '%s' not found",
373  key);
374  }
375  key = strtok_r(NULL, ",", &xsaveptr);
376  }
377 
378  SCFree(copy);
379 }
380 
381 /**
382  * \brief Append a SigMatch to the list type.
383  *
384  * \param s Signature.
385  * \param new The sig match to append.
386  * \param list The list to append to.
387  */
389  DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
390 {
391  SigMatch *new = SigMatchAlloc();
392  if (new == NULL)
393  return NULL;
394 
395  new->type = type;
396  new->ctx = ctx;
397 
398  if (new->type == DETECT_CONTENT) {
400  }
401 
402  SCLogDebug("s:%p new:%p list:%d: %s, s->init_data->list_set %s s->init_data->list %d", s, new,
403  list, sigmatch_table[new->type].name, BOOL2STR(s->init_data->list_set),
404  s->init_data->list);
405 
406  if (list < DETECT_SM_LIST_MAX) {
407  if (s->init_data->smlists[list] == NULL) {
408  s->init_data->smlists[list] = new;
409  s->init_data->smlists_tail[list] = new;
410  new->next = NULL;
411  new->prev = NULL;
412  } else {
413  SigMatch *cur = s->init_data->smlists_tail[list];
414  cur->next = new;
415  new->prev = cur;
416  new->next = NULL;
417  s->init_data->smlists_tail[list] = new;
418  }
419  new->idx = s->init_data->sm_cnt;
420  s->init_data->sm_cnt++;
421 
422  } else {
423  /* app-layer-events (and possibly others?) can get here w/o a "list"
424  * already set up. */
425 
426  /* unset any existing list if it isn't the same as the new */
427  if (s->init_data->list != DETECT_SM_LIST_NOTSET && list != s->init_data->list) {
428  SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
430  }
431 
432  if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) {
433  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
434  if (s->init_data->buffers[x].id == (uint32_t)list &&
435  !s->init_data->buffers[x].multi_capable) {
436  SCLogDebug("reusing buffer %u as it isn't multi-capable", x);
437  s->init_data->curbuf = &s->init_data->buffers[x];
438  break;
439  }
440  }
441  }
442 
443  if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
444  s->init_data->curbuf == NULL) {
446  SCLogError("failed to expand rule buffer array");
447  new->ctx = NULL;
448  SigMatchFree(de_ctx, new);
449  return NULL;
450  } else {
451  /* initialize new buffer */
453  s->init_data->curbuf->id = list;
454  /* buffer set up by sigmatch is tracked in case we add a stickybuffer for the
455  * same list. */
456  s->init_data->curbuf->sm_init = true;
458  s->init_data->curbuf->only_tc = true;
459  }
461  s->init_data->curbuf->only_ts = true;
462  }
463  SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
464  }
465  }
466  BUG_ON(s->init_data->curbuf == NULL);
467 
468  new->prev = s->init_data->curbuf->tail;
469  if (s->init_data->curbuf->tail)
470  s->init_data->curbuf->tail->next = new;
471  if (s->init_data->curbuf->head == NULL)
472  s->init_data->curbuf->head = new;
473  s->init_data->curbuf->tail = new;
474  new->idx = s->init_data->sm_cnt;
475  s->init_data->sm_cnt++;
476  SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)",
477  sigmatch_table[new->type].name, list, new->idx, s->init_data->list);
478 
479  for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
480  SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
481  sigmatch_table[sm->type].name, sm->idx);
482  }
483  }
484  return new;
485 }
486 
487 void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
488 {
489  if (sm == s->init_data->smlists[sm_list]) {
490  s->init_data->smlists[sm_list] = sm->next;
491  }
492  if (sm == s->init_data->smlists_tail[sm_list]) {
493  s->init_data->smlists_tail[sm_list] = sm->prev;
494  }
495  if (sm->prev != NULL)
496  sm->prev->next = sm->next;
497  if (sm->next != NULL)
498  sm->next->prev = sm->prev;
499 }
500 
501 /**
502  * \brief Returns a pointer to the last SigMatch instance of a particular type
503  * in a Signature of the payload list.
504  *
505  * \param s Pointer to the tail of the sigmatch list
506  * \param type SigMatch type which has to be searched for in the Signature.
507  *
508  * \retval match Pointer to the last SigMatch instance of type 'type'.
509  */
510 static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type)
511 {
512  while (sm != NULL) {
513  if (sm->type == type) {
514  return sm;
515  }
516  sm = sm->prev;
517  }
518 
519  return NULL;
520 }
521 
522 /** \brief get the last SigMatch from lists that support
523  * MPM.
524  * \note only supports the lists that are registered through
525  * DetectBufferTypeSupportsMpm().
526  */
528 {
529  SigMatch *sm_last = NULL;
530  SigMatch *sm_new;
531  uint32_t sm_type;
532 
533  for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
534  const int id = s->init_data->buffers[i].id;
537  if (sm_new == NULL)
538  continue;
539  if (sm_last == NULL || sm_new->idx > sm_last->idx)
540  sm_last = sm_new;
541  }
542  }
543  /* otherwise brute force it */
544  for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
546  continue;
547  SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
548  sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT);
549  if (sm_new == NULL)
550  continue;
551  if (sm_last == NULL || sm_new->idx > sm_last->idx)
552  sm_last = sm_new;
553  }
554 
555  return sm_last;
556 }
557 
558 /**
559  * \brief Returns the sm with the largest index (added latest) from the lists
560  * passed to us.
561  *
562  * \retval Pointer to Last sm.
563  */
565 {
566  SigMatch *sm_last = NULL;
567  SigMatch *sm_new;
568 
569  SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
570  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
571  if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
572  s->init_data->list != (int)s->init_data->buffers[x].id) {
573  SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
574  s->init_data->list, (int)s->init_data->buffers[x].id);
575 
576  continue;
577  }
578  int sm_type;
579  va_list ap;
580  va_start(ap, s);
581 
582  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
583  sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
584  if (sm_new == NULL)
585  continue;
586  if (sm_last == NULL || sm_new->idx > sm_last->idx)
587  sm_last = sm_new;
588  }
589  va_end(ap);
590  }
591 
592  for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
593  if (s->init_data->smlists[buf_type] == NULL)
594  continue;
595  if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
596  buf_type != s->init_data->list)
597  continue;
598 
599  int sm_type;
600  va_list ap;
601  va_start(ap, s);
602 
603  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
604  {
605  sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
606  if (sm_new == NULL)
607  continue;
608  if (sm_last == NULL || sm_new->idx > sm_last->idx)
609  sm_last = sm_new;
610  }
611  va_end(ap);
612  }
613 
614  return sm_last;
615 }
616 
617 /**
618  * \brief Returns the sm with the largest index (added last) from the list
619  * passed to us as a pointer.
620  *
621  * \param sm_list pointer to the SigMatch we should look before
622  * \param va_args list of keyword types terminated by -1
623  *
624  * \retval sm_last to last sm.
625  */
627 {
628  SigMatch *sm_last = NULL;
629  SigMatch *sm_new;
630  int sm_type;
631 
632  va_list ap;
633  va_start(ap, sm_list);
634 
635  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
636  {
637  sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
638  if (sm_new == NULL)
639  continue;
640  if (sm_last == NULL || sm_new->idx > sm_last->idx)
641  sm_last = sm_new;
642  }
643 
644  va_end(ap);
645 
646  return sm_last;
647 }
648 
649 /**
650  * \brief Returns the sm with the largest index (added last) from the list
651  * passed to us as an id.
652  *
653  * \param list_id id of the list to be searched
654  * \param va_args list of keyword types terminated by -1
655  *
656  * \retval sm_last to last sm.
657  */
658 SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
659 {
660  SigMatch *sm_last = NULL;
661  SigMatch *sm_new;
662  int sm_type;
663 
664  if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
665  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
666  sm_new = s->init_data->buffers[x].tail;
667  if (sm_new == NULL)
668  continue;
669 
670  va_list ap;
671  va_start(ap, list_id);
672 
673  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
674  sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
675  if (sm_new == NULL)
676  continue;
677  if (sm_last == NULL || sm_new->idx > sm_last->idx)
678  sm_last = sm_new;
679  }
680 
681  va_end(ap);
682  }
683  } else {
684  SigMatch *sm_list = s->init_data->smlists_tail[list_id];
685  if (sm_list == NULL)
686  return NULL;
687 
688  va_list ap;
689  va_start(ap, list_id);
690 
691  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
692  sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
693  if (sm_new == NULL)
694  continue;
695  if (sm_last == NULL || sm_new->idx > sm_last->idx)
696  sm_last = sm_new;
697  }
698 
699  va_end(ap);
700  }
701  return sm_last;
702 }
703 
704 /**
705  * \brief Returns the sm with the largest index (added latest) from this sig
706  *
707  * \retval sm_last Pointer to last sm
708  */
710 {
711  SigMatch *sm_last = NULL;
712  SigMatch *sm_new;
713 
714  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
715  sm_new = s->init_data->buffers[x].tail;
716  if (sm_new == NULL)
717  continue;
718  if (sm_last == NULL || sm_new->idx > sm_last->idx)
719  sm_last = sm_new;
720  }
721 
722  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
723  sm_new = s->init_data->smlists_tail[i];
724  if (sm_new == NULL)
725  continue;
726  if (sm_last == NULL || sm_new->idx > sm_last->idx)
727  sm_last = sm_new;
728  }
729 
730  return sm_last;
731 }
732 
733 static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
734  SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
735  SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail)
736 {
737  /* we won't do any checks for args */
738 
739  if (sm->prev != NULL)
740  sm->prev->next = sm->next;
741  if (sm->next != NULL)
742  sm->next->prev = sm->prev;
743 
744  if (sm == *src_sm_list)
745  *src_sm_list = sm->next;
746  if (sm == *src_sm_list_tail)
747  *src_sm_list_tail = sm->prev;
748 
749  if (*dst_sm_list == NULL) {
750  *dst_sm_list = sm;
751  *dst_sm_list_tail = sm;
752  sm->next = NULL;
753  sm->prev = NULL;
754  } else {
755  SigMatch *cur = *dst_sm_list_tail;
756  cur->next = sm;
757  sm->prev = cur;
758  sm->next = NULL;
759  *dst_sm_list_tail = sm;
760  }
761 }
762 
763 int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
764 {
765  if (key_sm == NULL)
766  return -1;
767 
768  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
769  const SigMatch *sm = s->init_data->buffers[x].head;
770  while (sm != NULL) {
771  if (sm == key_sm)
772  return s->init_data->buffers[x].id;
773  sm = sm->next;
774  }
775  }
776 
777  for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
778  const SigMatch *sm = s->init_data->smlists[list];
779  while (sm != NULL) {
780  if (sm == key_sm)
781  return list;
782  sm = sm->next;
783  }
784  }
785 
786  SCLogError("Unable to find the sm in any of the "
787  "sm lists");
788  return -1;
789 }
790 
791 /**
792  * \brief Parse and setup a direction
793  *
794  * \param s signature
795  * \param str argument to the keyword
796  * \param only_dir argument wether the keyword only accepts a direction
797  *
798  * \retval 0 on success, -1 on failure
799  */
800 static int DetectSetupDirection(Signature *s, char **str, bool only_dir)
801 {
802  char *orig = *str;
803  if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
804  *str += strlen("to_client");
805  // skip space
806  while (**str && isblank(**str)) {
807  (*str)++;
808  }
809  // check comma or nothing
810  if (**str) {
811  if (only_dir) {
812  SCLogError("unknown option: only accepts to_server or to_client");
813  return -1;
814  }
815  if (**str != ',') {
816  // leave to_client_something for next parser if not only_dir
817  *str = orig;
818  return 0;
819  } else {
820  (*str)++;
821  }
822  while (**str && isblank(**str)) {
823  (*str)++;
824  }
825  }
827  if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
828  if (s->flags & SIG_FLAG_TOSERVER) {
829  SCLogError("contradictory directions");
830  return -1;
831  }
832  s->flags |= SIG_FLAG_TOCLIENT;
833  }
834  } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
835  *str += strlen("to_server");
836  // skip space
837  while (**str && isblank(**str)) {
838  (*str)++;
839  }
840  // check comma or nothing
841  if (**str) {
842  if (only_dir) {
843  SCLogError("unknown option: only accepts to_server or to_client");
844  return -1;
845  }
846  if (**str != ',') {
847  // leave to_client_something for next parser if not only_dir
848  *str = orig;
849  return 0;
850  } else {
851  (*str)++;
852  }
853  while (**str && isblank(**str)) {
854  (*str)++;
855  }
856  }
858  if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
859  if (s->flags & SIG_FLAG_TOCLIENT) {
860  SCLogError("contradictory directions");
861  return -1;
862  }
863  s->flags |= SIG_FLAG_TOSERVER;
864  }
865  } else if (only_dir) {
866  SCLogError("unknown option: only accepts to_server or to_client");
867  return -1;
868  }
869  return 0;
870 }
871 
872 static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output,
873  size_t output_size, bool requires)
874 {
875  SigTableElmt *st = NULL;
876  char *optname = NULL;
877  char *optvalue = NULL;
878 
879  /* Trim leading space. */
880  while (isblank(*optstr)) {
881  optstr++;
882  }
883 
884  /* Look for the end of this option, handling escaped semicolons. */
885  char *optend = optstr;
886  for (;;) {
887  optend = strchr(optend, ';');
888  if (optend == NULL) {
889  SCLogError("no terminating \";\" found");
890  goto error;
891  }
892  else if (optend > optstr && *(optend -1 ) == '\\') {
893  optend++;
894  } else {
895  break;
896  }
897  }
898  *(optend++) = '\0';
899 
900  /* Find the start of the option value. */
901  char *optvalptr = strchr(optstr, ':');
902  if (optvalptr) {
903  *(optvalptr++) = '\0';
904 
905  /* Trim trailing space from name. */
906  for (size_t i = strlen(optvalptr); i > 0; i--) {
907  if (isblank(optvalptr[i - 1])) {
908  optvalptr[i - 1] = '\0';
909  } else {
910  break;
911  }
912  }
913 
914  optvalue = optvalptr;
915  }
916 
917  /* Trim trailing space from name. */
918  for (size_t i = strlen(optstr); i > 0; i--) {
919  if (isblank(optstr[i - 1])) {
920  optstr[i - 1] = '\0';
921  } else {
922  break;
923  }
924  }
925  optname = optstr;
926 
927  /* Check for options that are only to be processed during the
928  * first "requires" pass. */
929  bool requires_only = strcasecmp(optname, "requires") == 0 || strcasecmp(optname, "sid") == 0;
930  if ((requires && !requires_only) || (!requires && requires_only)) {
931  goto finish;
932  }
933 
934  /* Call option parsing */
935  st = SigTableGet(optname);
936  if (st == NULL || st->Setup == NULL) {
937  SCLogError("unknown rule keyword '%s'.", optname);
938  goto error;
939  }
940 
941  if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
942  if (optvalue == NULL || strlen(optvalue) == 0) {
943  SCLogError(
944  "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
945  goto error;
946  }
947  } else if (st->flags & SIGMATCH_NOOPT) {
948  if (optvalue && strlen(optvalue)) {
949  SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
950  goto error;
951  }
952  }
953  s->init_data->negated = false;
954 
955  const enum DetectKeywordId idx = SigTableGetIndex(st);
957 
958  if (st->flags & SIGMATCH_INFO_DEPRECATED) {
959 #define URL "https://suricata.io/our-story/deprecation-policy/"
960  if (st->alternative == 0)
961  SCLogWarning("keyword '%s' is deprecated "
962  "and will be removed soon. See %s",
963  st->name, URL);
964  else
965  SCLogWarning("keyword '%s' is deprecated "
966  "and will be removed soon. Use '%s' instead. "
967  "See %s",
968  st->name, sigmatch_table[st->alternative].name, URL);
969 #undef URL
970  }
971 
972  int setup_ret = 0;
973 
974  /* Validate double quoting, trimming trailing white space along the way. */
975  if (optvalue != NULL && strlen(optvalue) > 0) {
976  size_t ovlen = strlen(optvalue);
977  char *ptr = optvalue;
978 
979  /* skip leading whitespace */
980  while (ovlen > 0) {
981  if (!isblank(*ptr))
982  break;
983  ptr++;
984  ovlen--;
985  }
986  if (ovlen == 0) {
987  SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
988  optstr);
989  goto error;
990  }
991 
992  if (s->init_data->firewall_rule && (st->flags & SIGMATCH_SUPPORT_FIREWALL) == 0) {
993  SCLogWarning("keyword \'%s\' has not been tested for firewall rules", optname);
994  }
995 
996  /* see if value is negated */
997  if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
998  s->init_data->negated = true;
999  ptr++;
1000  ovlen--;
1001  }
1002  /* skip more whitespace */
1003  while (ovlen > 0) {
1004  if (!isblank(*ptr))
1005  break;
1006  ptr++;
1007  ovlen--;
1008  }
1009  if (ovlen == 0) {
1010  SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
1011  optstr);
1012  goto error;
1013  }
1014  /* if quoting is mandatory, enforce it */
1015  if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') {
1016  SCLogError("invalid formatting to %s keyword: "
1017  "value must be double quoted \'%s\'",
1018  optname, optstr);
1019  goto error;
1020  }
1021 
1023  && ovlen && *ptr == '"')
1024  {
1025  for (; ovlen > 0; ovlen--) {
1026  if (isblank(ptr[ovlen - 1])) {
1027  ptr[ovlen - 1] = '\0';
1028  } else {
1029  break;
1030  }
1031  }
1032  if (ovlen && ptr[ovlen - 1] != '"') {
1033  SCLogError("bad option value formatting (possible missing semicolon) "
1034  "for keyword %s: \'%s\'",
1035  optname, optvalue);
1036  goto error;
1037  }
1038  if (ovlen > 1) {
1039  /* strip leading " */
1040  ptr++;
1041  ovlen--;
1042  ptr[ovlen - 1] = '\0';
1043  ovlen--;
1044  }
1045  if (ovlen == 0) {
1046  SCLogError("bad input "
1047  "for keyword %s: \'%s\'",
1048  optname, optvalue);
1049  goto error;
1050  }
1051  } else {
1052  if (*ptr == '"') {
1053  SCLogError(
1054  "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1055  goto error;
1056  }
1057  }
1058  /* setup may or may not add a new SigMatch to the list */
1059  if (st->flags & SIGMATCH_SUPPORT_DIR) {
1060  if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1061  SCLogError("%s failed to setup direction", st->name);
1062  goto error;
1063  }
1064  }
1065  setup_ret = st->Setup(de_ctx, s, ptr);
1068  } else {
1069  /* setup may or may not add a new SigMatch to the list */
1070  setup_ret = st->Setup(de_ctx, s, NULL);
1071  }
1072  if (setup_ret < 0) {
1073  SCLogDebug("\"%s\" failed to setup", st->name);
1074 
1075  /* handle 'silent' error case */
1076  if (setup_ret == -2) {
1077  if (!de_ctx->sm_types_silent_error[idx]) {
1078  de_ctx->sm_types_silent_error[idx] = true;
1079  return -1;
1080  }
1081  return -2;
1082  }
1083  return setup_ret;
1084  }
1085  s->init_data->negated = false;
1086 
1087 finish:
1088  if (strlen(optend) > 0) {
1089  strlcpy(output, optend, output_size);
1090  return 1;
1091  }
1092 
1093  return 0;
1094 
1095 error:
1096  return -1;
1097 }
1098 
1099 /** \brief Parse address string and update signature
1100  *
1101  * \retval 0 ok, -1 error
1102  */
1103 static int SigParseAddress(DetectEngineCtx *de_ctx,
1104  Signature *s, const char *addrstr, char flag)
1105 {
1106  SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
1107 
1108  /* pass on to the address(list) parser */
1109  if (flag == 0) {
1110  if (strcasecmp(addrstr, "any") == 0)
1111  s->flags |= SIG_FLAG_SRC_ANY;
1112 
1113  s->init_data->src = DetectParseAddress(de_ctx, addrstr,
1115  if (s->init_data->src == NULL)
1116  goto error;
1117  } else {
1118  if (strcasecmp(addrstr, "any") == 0)
1119  s->flags |= SIG_FLAG_DST_ANY;
1120 
1121  s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
1123  if (s->init_data->dst == NULL)
1124  goto error;
1125  }
1126 
1127  return 0;
1128 
1129 error:
1130  return -1;
1131 }
1132 
1133 static bool IsBuiltIn(const char *n)
1134 {
1135  if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
1136  return true;
1137  }
1138  if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
1139  return true;
1140  }
1141  return false;
1142 }
1143 
1144 /** \brief register app hooks as generic lists
1145  *
1146  * Register each hook in each app protocol as:
1147  * <alproto>:<hook name>:generic
1148  * These lists can be used by lua scripts to hook into.
1149  *
1150  * \todo move elsewhere? maybe a detect-engine-hook.c?
1151  */
1153 {
1154  for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1155  const char *alproto_name = AppProtoToString(a);
1156  if (strcmp(alproto_name, "http") == 0)
1157  alproto_name = "http1";
1158  SCLogDebug("alproto %u/%s", a, alproto_name);
1159 
1160  const int max_progress_ts =
1162  const int max_progress_tc =
1164 
1165  char ts_tx_started[64];
1166  snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:request_started:generic", alproto_name);
1168  ts_tx_started, a, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
1169  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_started,
1170  (uint32_t)strlen(ts_tx_started));
1171 
1172  char tc_tx_started[64];
1173  snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:response_started:generic", alproto_name);
1175  tc_tx_started, a, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
1176  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_started,
1177  (uint32_t)strlen(tc_tx_started));
1178 
1179  char ts_tx_complete[64];
1180  snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:request_complete:generic",
1181  alproto_name);
1182  DetectAppLayerInspectEngineRegister(ts_tx_complete, a, SIG_FLAG_TOSERVER, max_progress_ts,
1184  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_complete,
1185  (uint32_t)strlen(ts_tx_complete));
1186 
1187  char tc_tx_complete[64];
1188  snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:response_complete:generic",
1189  alproto_name);
1190  DetectAppLayerInspectEngineRegister(tc_tx_complete, a, SIG_FLAG_TOCLIENT, max_progress_tc,
1192  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_complete,
1193  (uint32_t)strlen(tc_tx_complete));
1194 
1195  for (int p = 0; p <= max_progress_ts; p++) {
1196  const char *name = AppLayerParserGetStateNameById(
1197  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOSERVER);
1198  if (name != NULL && !IsBuiltIn(name)) {
1199  char list_name[64];
1200  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1201  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1202  (uint32_t)strlen(list_name));
1203 
1205  list_name, a, SIG_FLAG_TOSERVER, p, DetectEngineInspectGenericList, NULL);
1206  }
1207  }
1208  for (int p = 0; p <= max_progress_tc; p++) {
1209  const char *name = AppLayerParserGetStateNameById(
1210  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOCLIENT);
1211  if (name != NULL && !IsBuiltIn(name)) {
1212  char list_name[64];
1213  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1214  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1215  (uint32_t)strlen(list_name));
1216 
1218  list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
1219  }
1220  }
1221  }
1222 }
1223 
1224 #ifdef DEBUG
1225 static const char *SignatureHookTypeToString(enum SignatureHookType t)
1226 {
1227  switch (t) {
1229  return "not_set";
1231  return "app";
1233  return "pkt";
1234  }
1235  return "unknown";
1236 }
1237 #endif
1238 
1239 static enum SignatureHookPkt HookPktFromString(const char *str)
1240 {
1241  if (strcmp(str, "flow_start") == 0) {
1243  } else if (strcmp(str, "all") == 0) {
1244  return SIGNATURE_HOOK_PKT_ALL;
1245  }
1247 }
1248 
1249 #ifdef DEBUG
1250 static const char *HookPktToString(const enum SignatureHookPkt ph)
1251 {
1252  switch (ph) {
1254  return "not set";
1256  return "flow_start";
1258  return "all";
1259  }
1260  return "error";
1261 }
1262 #endif
1263 
1264 static SignatureHook SetPktHook(const char *hook_str)
1265 {
1266  SignatureHook h = {
1268  .t.pkt.ph = HookPktFromString(hook_str),
1269  };
1270  return h;
1271 }
1272 
1273 /**
1274  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1275  */
1276 static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1277 {
1278  enum SignatureHookPkt hook = HookPktFromString(h);
1279  if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
1280  s->init_data->hook = SetPktHook(h);
1281  if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
1282  return -1; // TODO unreachable?
1283  }
1284  } else {
1285  SCLogError("unknown pkt hook %s", h);
1286  return -1;
1287  }
1288 
1289  SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
1290  SignatureHookTypeToString(s->init_data->hook.type),
1291  HookPktToString(s->init_data->hook.t.pkt.ph));
1292  return 0;
1293 }
1294 
1295 static SignatureHook SetAppHook(const AppProto alproto, int progress)
1296 {
1297  SignatureHook h = {
1299  .t.app.alproto = alproto,
1300  .t.app.app_progress = progress,
1301  };
1302  return h;
1303 }
1304 
1305 /**
1306  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1307  */
1308 static int SigParseProtoHookApp(Signature *s, const char *proto_hook, const char *p, const char *h)
1309 {
1310  if (strcmp(h, "request_started") == 0) {
1311  s->flags |= SIG_FLAG_TOSERVER;
1312  s->init_data->hook =
1313  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1314  } else if (strcmp(h, "response_started") == 0) {
1315  s->flags |= SIG_FLAG_TOCLIENT;
1316  s->init_data->hook =
1317  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1318  } else if (strcmp(h, "request_complete") == 0) {
1319  s->flags |= SIG_FLAG_TOSERVER;
1320  s->init_data->hook = SetAppHook(s->alproto,
1322  } else if (strcmp(h, "response_complete") == 0) {
1323  s->flags |= SIG_FLAG_TOCLIENT;
1324  s->init_data->hook = SetAppHook(s->alproto,
1326  } else {
1327  const int progress_ts = AppLayerParserGetStateIdByName(
1328  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
1329  if (progress_ts >= 0) {
1330  s->flags |= SIG_FLAG_TOSERVER;
1331  s->init_data->hook = SetAppHook(s->alproto, progress_ts);
1332  } else {
1333  const int progress_tc = AppLayerParserGetStateIdByName(
1334  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
1335  if (progress_tc < 0) {
1336  return -1;
1337  }
1338  s->flags |= SIG_FLAG_TOCLIENT;
1339  s->init_data->hook = SetAppHook(s->alproto, progress_tc);
1340  }
1341  }
1342 
1343  char generic_hook_name[64];
1344  snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:generic", proto_hook);
1345  int list = DetectBufferTypeGetByName(generic_hook_name);
1346  if (list < 0) {
1347  SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
1348  return -1;
1349  }
1350  s->init_data->hook.sm_list = list;
1351 
1352  SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
1353  SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
1354  s->init_data->hook.t.app.app_progress);
1355 
1356  s->app_progress_hook = (uint8_t)s->init_data->hook.t.app.app_progress;
1357  return 0;
1358 }
1359 
1360 /**
1361  * \brief Parses the protocol supplied by the Signature.
1362  *
1363  * http://www.iana.org/assignments/protocol-numbers
1364  *
1365  * \param s Pointer to the Signature instance to which the parsed
1366  * protocol has to be added.
1367  * \param protostr Pointer to the character string containing the protocol name.
1368  *
1369  * \retval 0 On successfully parsing the protocol sent as the argument.
1370  * \retval -1 On failure
1371  */
1372 static int SigParseProto(Signature *s, const char *protostr)
1373 {
1374  SCEnter();
1375  if (strlen(protostr) > 32)
1376  return -1;
1377 
1378  char proto[33];
1379  strlcpy(proto, protostr, 33);
1380  const char *p = proto;
1381  const char *h = NULL;
1382 
1383  bool has_hook = strchr(proto, ':') != NULL;
1384  if (has_hook) {
1385  char *xsaveptr = NULL;
1386  p = strtok_r(proto, ":", &xsaveptr);
1387  h = strtok_r(NULL, ":", &xsaveptr);
1388  SCLogDebug("p: '%s' h: '%s'", p, h);
1389  }
1390  if (p == NULL) {
1391  SCLogError("invalid protocol specification '%s'", proto);
1392  return -1;
1393  }
1394 
1395  int r = DetectProtoParse(&s->proto, p);
1396  if (r < 0) {
1398  /* indicate that the signature is app-layer */
1399  if (s->alproto != ALPROTO_UNKNOWN) {
1400  s->flags |= SIG_FLAG_APPLAYER;
1401 
1403 
1404  if (h) {
1405  if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
1406  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1407  SCReturnInt(-1);
1408  }
1409  }
1410  }
1411  else {
1412  SCLogError("protocol \"%s\" cannot be used "
1413  "in a signature. Either detection for this protocol "
1414  "is not yet supported OR detection has been disabled for "
1415  "protocol through the yaml option "
1416  "app-layer.protocols.%s.detection-enabled",
1417  p, p);
1418  SCReturnInt(-1);
1419  }
1420  } else if (h != NULL) {
1421  SCLogDebug("non-app-layer rule with %s:%s", p, h);
1422 
1423  if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
1424  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1425  SCReturnInt(-1);
1426  }
1427  }
1428 
1429  /* if any of these flags are set they are set in a mutually exclusive
1430  * manner */
1431  if (s->proto.flags & DETECT_PROTO_ONLY_PKT) {
1433  } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1435  }
1436 
1437  SCReturnInt(0);
1438 }
1439 
1440 /**
1441  * \brief Parses the port(source or destination) field, from a Signature.
1442  *
1443  * \param s Pointer to the signature which has to be updated with the
1444  * port information.
1445  * \param portstr Pointer to the character string containing the port info.
1446  * \param Flag which indicates if the portstr received is src or dst
1447  * port. For src port: flag = 0, dst port: flag = 1.
1448  *
1449  * \retval 0 On success.
1450  * \retval -1 On failure.
1451  */
1452 static int SigParsePort(const DetectEngineCtx *de_ctx,
1453  Signature *s, const char *portstr, char flag)
1454 {
1455  int r = 0;
1456 
1457  /* XXX VJ exclude handling this for none UDP/TCP proto's */
1458 
1459  SCLogDebug("Port group \"%s\" to be parsed", portstr);
1460 
1461  if (flag == 0) {
1462  if (strcasecmp(portstr, "any") == 0)
1463  s->flags |= SIG_FLAG_SP_ANY;
1464 
1465  r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1466  } else if (flag == 1) {
1467  if (strcasecmp(portstr, "any") == 0)
1468  s->flags |= SIG_FLAG_DP_ANY;
1469 
1470  r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1471  }
1472 
1473  if (r < 0)
1474  return -1;
1475 
1476  return 0;
1477 }
1478 
1479 /** \retval 1 valid
1480  * \retval 0 invalid
1481  */
1482 static int SigParseActionRejectValidate(const char *action)
1483 {
1484 #ifdef HAVE_LIBNET11
1485 #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1486  if (sc_set_caps) {
1487  SCLogError("Libnet 1.1 is "
1488  "incompatible with POSIX based capabilities with privs dropping. "
1489  "For rejects to work, run as root/super user.");
1490  return 0;
1491  }
1492 #endif
1493 #else /* no libnet 1.1 */
1494  SCLogError("Libnet 1.1.x is "
1495  "required for action \"%s\" but is not compiled into Suricata",
1496  action);
1497  return 0;
1498 #endif
1499  return 1;
1500 }
1501 
1502 /** \retval 0 on error
1503  * \retval flags on success
1504  */
1505 static uint8_t ActionStringToFlags(const char *action)
1506 {
1507  if (strcasecmp(action, "alert") == 0) {
1508  return ACTION_ALERT;
1509  } else if (strcasecmp(action, "drop") == 0) {
1510  return ACTION_DROP | ACTION_ALERT;
1511  } else if (strcasecmp(action, "pass") == 0) {
1512  return ACTION_PASS;
1513  } else if (strcasecmp(action, "reject") == 0 ||
1514  strcasecmp(action, "rejectsrc") == 0)
1515  {
1516  if (!(SigParseActionRejectValidate(action)))
1517  return 0;
1519  } else if (strcasecmp(action, "rejectdst") == 0) {
1520  if (!(SigParseActionRejectValidate(action)))
1521  return 0;
1523  } else if (strcasecmp(action, "rejectboth") == 0) {
1524  if (!(SigParseActionRejectValidate(action)))
1525  return 0;
1527  } else if (strcasecmp(action, "config") == 0) {
1528  return ACTION_CONFIG;
1529  } else if (strcasecmp(action, "accept") == 0) {
1530  return ACTION_ACCEPT;
1531  } else {
1532  SCLogError("An invalid action \"%s\" was given", action);
1533  return 0;
1534  }
1535 }
1536 
1537 /**
1538  * \brief Parses the action that has been used by the Signature and allots it
1539  * to its Signature instance.
1540  *
1541  * \param s Pointer to the Signature instance to which the action belongs.
1542  * \param action Pointer to the action string used by the Signature.
1543  *
1544  * \retval 0 On successfully parsing the action string and adding it to the
1545  * Signature.
1546  * \retval -1 On failure.
1547  */
1548 static int SigParseAction(Signature *s, const char *action_in)
1549 {
1550  char action[32];
1551  strlcpy(action, action_in, sizeof(action));
1552  const char *a = action;
1553  const char *o = NULL;
1554 
1555  bool has_scope = strchr(action, ':') != NULL;
1556  if (has_scope) {
1557  char *xsaveptr = NULL;
1558  a = strtok_r(action, ":", &xsaveptr);
1559  o = strtok_r(NULL, ":", &xsaveptr);
1560  SCLogDebug("a: '%s' o: '%s'", a, o);
1561  }
1562  if (a == NULL) {
1563  SCLogError("invalid protocol specification '%s'", action_in);
1564  return -1;
1565  }
1566 
1567  uint8_t flags = ActionStringToFlags(a);
1568  if (flags == 0)
1569  return -1;
1570 
1571  /* parse scope, if any */
1572  if (o) {
1573  uint8_t scope_flags = 0;
1574  if (flags & (ACTION_DROP | ACTION_PASS)) {
1575  if (strcmp(o, "packet") == 0) {
1576  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1577  } else if (strcmp(o, "flow") == 0) {
1578  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1579  } else {
1580  SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1581  "allowed",
1582  o, action_in);
1583  return -1;
1584  }
1585  s->action_scope = scope_flags;
1586  } else if (flags & (ACTION_ACCEPT)) {
1587  if (strcmp(o, "packet") == 0) {
1588  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1589  } else if (strcmp(o, "hook") == 0) {
1590  scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1591  } else if (strcmp(o, "tx") == 0) {
1592  scope_flags = (uint8_t)ACTION_SCOPE_TX;
1593  } else if (strcmp(o, "flow") == 0) {
1594  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1595  } else {
1596  SCLogError(
1597  "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1598  "'hook' allowed",
1599  o, action_in);
1600  return -1;
1601  }
1602  s->action_scope = scope_flags;
1603  } else {
1604  SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1605  "'drop', 'pass' and 'reject'",
1606  o, action_in);
1607  return -1;
1608  }
1609  }
1610 
1611  /* require explicit action scope for fw rules */
1612  if (s->init_data->firewall_rule && s->action_scope == 0) {
1613  SCLogError("firewall rules require setting an explicit action scope");
1614  return -1;
1615  }
1616 
1617  if (!s->init_data->firewall_rule && (flags & ACTION_ACCEPT)) {
1618  SCLogError("'accept' action only supported for firewall rules");
1619  return -1;
1620  }
1621 
1622  if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
1623  SCLogError("'pass' action not supported for firewall rules");
1624  return -1;
1625  }
1626 
1627  s->action = flags;
1628  return 0;
1629 }
1630 
1631 /**
1632  * \brief Parse the next token in rule.
1633  *
1634  * For rule parsing a token is considered to be a string of characters
1635  * separated by white space.
1636  *
1637  * \param input double pointer to input buffer, will be advanced as input is
1638  * parsed.
1639  * \param output buffer to copy token into.
1640  * \param output_size length of output buffer.
1641  */
1642 static inline int SigParseToken(char **input, char *output,
1643  const size_t output_size)
1644 {
1645  size_t len = *input == NULL ? 0 : strlen(*input);
1646 
1647  if (!len) {
1648  return 0;
1649  }
1650 
1651  while (len && isblank(**input)) {
1652  (*input)++;
1653  len--;
1654  }
1655 
1656  char *endptr = strpbrk(*input, " \t\n\r");
1657  if (endptr != NULL) {
1658  *(endptr++) = '\0';
1659  }
1660  strlcpy(output, *input, output_size);
1661  *input = endptr;
1662 
1663  return 1;
1664 }
1665 
1666 /**
1667  * \brief Parse the next rule "list" token.
1668  *
1669  * Parses rule tokens that may be lists such as addresses and ports
1670  * handling the case when they may not be lists.
1671  *
1672  * \param input double pointer to input buffer, will be advanced as input is
1673  * parsed.
1674  * \param output buffer to copy token into.
1675  * \param output_size length of output buffer.
1676  */
1677 static inline int SigParseList(char **input, char *output,
1678  const size_t output_size)
1679 {
1680  int in_list = 0;
1681  size_t len = *input != NULL ? strlen(*input) : 0;
1682 
1683  if (len == 0) {
1684  return 0;
1685  }
1686 
1687  while (len && isblank(**input)) {
1688  (*input)++;
1689  len--;
1690  }
1691 
1692  size_t i = 0;
1693  for (i = 0; i < len; i++) {
1694  char c = (*input)[i];
1695  if (c == '[') {
1696  in_list++;
1697  } else if (c == ']') {
1698  in_list--;
1699  } else if (c == ' ') {
1700  if (!in_list) {
1701  break;
1702  }
1703  }
1704  }
1705  if (i == len) {
1706  *input = NULL;
1707  return 0;
1708  }
1709  (*input)[i] = '\0';
1710  strlcpy(output, *input, output_size);
1711  *input = *input + i + 1;
1712 
1713  return 1;
1714 }
1715 
1716 /**
1717  * \internal
1718  * \brief split a signature string into a few blocks for further parsing
1719  *
1720  * \param scan_only just scan, don't validate
1721  */
1722 static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1723  SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1724 {
1725  char *index, dup[DETECT_MAX_RULE_SIZE];
1726 
1727  strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1728  index = dup;
1729 
1730  /* Action. */
1731  SigParseToken(&index, parser->action, sizeof(parser->action));
1732 
1733  /* Protocol. */
1734  SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1735 
1736  /* Source. */
1737  SigParseList(&index, parser->src, sizeof(parser->src));
1738 
1739  /* Source port(s). */
1740  SigParseList(&index, parser->sp, sizeof(parser->sp));
1741 
1742  /* Direction. */
1743  SigParseToken(&index, parser->direction, sizeof(parser->direction));
1744 
1745  /* Destination. */
1746  SigParseList(&index, parser->dst, sizeof(parser->dst));
1747 
1748  /* Destination port(s). */
1749  SigParseList(&index, parser->dp, sizeof(parser->dp));
1750 
1751  /* Options. */
1752  if (index == NULL) {
1753  SCLogError("no rule options.");
1754  goto error;
1755  }
1756  while (isspace(*index) || *index == '(') {
1757  index++;
1758  }
1759  for (size_t i = strlen(index); i > 0; i--) {
1760  if (isspace(index[i - 1]) || index[i - 1] == ')') {
1761  index[i - 1] = '\0';
1762  } else {
1763  break;
1764  }
1765  }
1766  strlcpy(parser->opts, index, sizeof(parser->opts));
1767 
1768  if (scan_only) {
1769  return 0;
1770  }
1771 
1772  /* Parse Action */
1773  if (SigParseAction(s, parser->action) < 0)
1774  goto error;
1775 
1776  if (SigParseProto(s, parser->protocol) < 0)
1777  goto error;
1778 
1779  if (strcmp(parser->direction, "<>") == 0) {
1781  } else if (strcmp(parser->direction, "=>") == 0) {
1782  if (s->flags & SIG_FLAG_FIREWALL) {
1783  SCLogError("transactional bidirectional rules not supported for firewall rules");
1784  goto error;
1785  }
1786 
1787  s->flags |= SIG_FLAG_TXBOTHDIR;
1788  } else if (strcmp(parser->direction, "->") != 0) {
1789  SCLogError("\"%s\" is not a valid direction modifier, "
1790  "\"->\" and \"<>\" are supported.",
1791  parser->direction);
1792  goto error;
1793  }
1794 
1795  /* Parse Address & Ports */
1796  if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1797  goto error;
1798 
1799  if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1800  goto error;
1801 
1802  /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1803  * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1804  * changes that we made sees to it that at this point of time we don't
1805  * set the ip proto for the sig. We do it a bit later. */
1806  if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1807  goto error;
1808  if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1809  goto error;
1810 
1811  return 0;
1812 
1813 error:
1814  return -1;
1815 }
1816 
1817 static inline bool CheckAscii(const char *str)
1818 {
1819  for (size_t i = 0; i < strlen(str); i++) {
1820  if (str[i] < 0x20) {
1821  // LF CR TAB
1822  if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1823  continue;
1824  }
1825  return false;
1826  } else if (str[i] == 0x7f) {
1827  return false;
1828  }
1829  }
1830  return true;
1831 }
1832 
1833 /**
1834  * \brief parse a signature
1835  *
1836  * \param de_ctx detection engine ctx to add it to
1837  * \param s memory structure to store the signature in
1838  * \param sigstr the raw signature as a null terminated string
1839  * \param addrs_direction direction (for bi-directional sigs)
1840  * \param require only scan rule for requires
1841  *
1842  * \param -1 parse error
1843  * \param 0 ok
1844  */
1845 static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1846  uint8_t addrs_direction, SignatureParser *parser, bool requires)
1847 {
1848  SCEnter();
1849 
1850  if (!SCCheckUtf8(sigstr)) {
1851  SCLogError("rule is not valid UTF-8");
1852  SCReturnInt(-1);
1853  }
1854 
1855  if (!CheckAscii(sigstr)) {
1856  SCLogError("rule contains invalid (control) characters");
1857  SCReturnInt(-1);
1858  }
1859 
1860  int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
1861  if (ret < 0) {
1862  SCLogDebug("SigParseBasics failed");
1863  SCReturnInt(-1);
1864  }
1865 
1866  /* we can have no options, so make sure we have them */
1867  if (strlen(parser->opts) > 0) {
1868  size_t buffer_size = strlen(parser->opts) + 1;
1869  char input[buffer_size];
1870  char output[buffer_size];
1871  memset(input, 0x00, buffer_size);
1872  memcpy(input, parser->opts, strlen(parser->opts) + 1);
1873 
1874  /* loop the option parsing. Each run processes one option
1875  * and returns the rest of the option string through the
1876  * output variable. */
1877  do {
1878  memset(output, 0x00, buffer_size);
1879  ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
1880  if (ret == 1) {
1881  memcpy(input, output, buffer_size);
1882  }
1883 
1884  } while (ret == 1);
1885 
1886  if (ret < 0) {
1887  /* Suricata didn't meet the rule requirements, skip. */
1888  goto end;
1889  }
1890  }
1891 
1892 end:
1894 
1895  SCReturnInt(ret);
1896 }
1897 
1898 /** \brief check if buffers array still has space left, expand if not
1899  */
1901 {
1902  if (s->init_data->buffers_size >= 64)
1903  return -1;
1904 
1905  if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
1906  void *ptr = SCRealloc(s->init_data->buffers,
1907  (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
1908  if (ptr == NULL)
1909  return -1;
1910  s->init_data->buffers = ptr;
1911  for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
1913  memset(b, 0, sizeof(*b));
1914  }
1915  s->init_data->buffers_size += 8;
1916  }
1917  return 0;
1918 }
1919 
1921 {
1922  Signature *sig = SCCalloc(1, sizeof(Signature));
1923  if (unlikely(sig == NULL))
1924  return NULL;
1925 
1926  sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
1927  if (sig->init_data == NULL) {
1928  SCFree(sig);
1929  return NULL;
1930  }
1931  sig->init_data->mpm_sm_list = -1;
1932 
1933  sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
1934  if (sig->init_data->buffers == NULL) {
1935  SCFree(sig->init_data);
1936  SCFree(sig);
1937  return NULL;
1938  }
1939  sig->init_data->buffers_size = 8;
1940 
1941  /* assign it to -1, so that we can later check if the value has been
1942  * overwritten after the Signature has been parsed, and if it hasn't been
1943  * overwritten, we can then assign the default value of 3 */
1944  sig->prio = -1;
1945 
1946  /* rule interdepency is false, at start */
1947  sig->init_data->is_rule_state_dependant = false;
1948  /* first index is 0 */
1950 
1952  return sig;
1953 }
1954 
1955 /**
1956  * \internal
1957  * \brief Free Metadata list
1958  *
1959  * \param s Pointer to the signature
1960  */
1961 static void SigMetadataFree(Signature *s)
1962 {
1963  SCEnter();
1964 
1965  DetectMetadata *mdata = NULL;
1966  DetectMetadata *next_mdata = NULL;
1967 
1968  if (s == NULL || s->metadata == NULL) {
1969  SCReturn;
1970  }
1971 
1972  SCLogDebug("s %p, s->metadata %p", s, s->metadata);
1973 
1974  for (mdata = s->metadata->list; mdata != NULL;) {
1975  next_mdata = mdata->next;
1976  DetectMetadataFree(mdata);
1977  mdata = next_mdata;
1978  }
1979  SCFree(s->metadata->json_str);
1980  SCFree(s->metadata);
1981  s->metadata = NULL;
1982 
1983  SCReturn;
1984 }
1985 
1986 /**
1987  * \internal
1988  * \brief Free Reference list
1989  *
1990  * \param s Pointer to the signature
1991  */
1992 static void SigRefFree (Signature *s)
1993 {
1994  SCEnter();
1995 
1996  DetectReference *ref = NULL;
1997  DetectReference *next_ref = NULL;
1998 
1999  if (s == NULL) {
2000  SCReturn;
2001  }
2002 
2003  SCLogDebug("s %p, s->references %p", s, s->references);
2004 
2005  for (ref = s->references; ref != NULL;) {
2006  next_ref = ref->next;
2007  DetectReferenceFree(ref);
2008  ref = next_ref;
2009  }
2010 
2011  s->references = NULL;
2012 
2013  SCReturn;
2014 }
2015 
2016 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2017 {
2018  if (s != NULL) {
2019  int type;
2020  for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2021  if (s->sm_arrays[type] != NULL) {
2022  if (ctxs) {
2023  SigMatchData *smd = s->sm_arrays[type];
2024  while(1) {
2025  if (sigmatch_table[smd->type].Free != NULL) {
2026  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2027  }
2028  if (smd->is_last)
2029  break;
2030  smd++;
2031  }
2032  }
2033 
2034  SCFree(s->sm_arrays[type]);
2035  }
2036  }
2037  }
2038 }
2039 
2041 {
2042  if (s == NULL)
2043  return;
2044 
2045  int i;
2046 
2047  if (s->init_data && s->init_data->transforms.cnt) {
2048  for(i = 0; i < s->init_data->transforms.cnt; i++) {
2049  if (s->init_data->transforms.transforms[i].options) {
2050  int transform = s->init_data->transforms.transforms[i].transform;
2051  sigmatch_table[transform].Free(
2053  s->init_data->transforms.transforms[i].options = NULL;
2054  }
2055  }
2056  }
2057  if (s->init_data) {
2058  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2059  SigMatch *sm = s->init_data->smlists[i];
2060  while (sm != NULL) {
2061  SigMatch *nsm = sm->next;
2062  SigMatchFree(de_ctx, sm);
2063  sm = nsm;
2064  }
2065  }
2066 
2067  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2068  SigMatch *sm = s->init_data->buffers[x].head;
2069  while (sm != NULL) {
2070  SigMatch *nsm = sm->next;
2071  SigMatchFree(de_ctx, sm);
2072  sm = nsm;
2073  }
2074  }
2075  if (s->init_data->cidr_dst != NULL)
2077 
2078  if (s->init_data->cidr_src != NULL)
2080 
2081  SCFree(s->init_data->buffers);
2082  s->init_data->buffers = NULL;
2083  }
2084  SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2085  if (s->init_data) {
2086  SCFree(s->init_data);
2087  s->init_data = NULL;
2088  }
2089 
2090  if (s->sp != NULL) {
2091  DetectPortCleanupList(NULL, s->sp);
2092  }
2093  if (s->dp != NULL) {
2094  DetectPortCleanupList(NULL, s->dp);
2095  }
2096 
2097  if (s->msg != NULL)
2098  SCFree(s->msg);
2099 
2100  if (s->addr_src_match4 != NULL) {
2101  SCFree(s->addr_src_match4);
2102  }
2103  if (s->addr_dst_match4 != NULL) {
2104  SCFree(s->addr_dst_match4);
2105  }
2106  if (s->addr_src_match6 != NULL) {
2107  SCFree(s->addr_src_match6);
2108  }
2109  if (s->addr_dst_match6 != NULL) {
2110  SCFree(s->addr_dst_match6);
2111  }
2112  if (s->sig_str != NULL) {
2113  SCFree(s->sig_str);
2114  }
2115 
2116  SigRefFree(s);
2117  SigMetadataFree(s);
2118 
2120 
2121  SCFree(s);
2122 }
2123 
2124 /**
2125  * \brief this function is used to set multiple possible app-layer protos
2126  * \brief into the current signature (for example ja4 for both tls and quic)
2127  *
2128  * \param s pointer to the Current Signature
2129  * \param alprotos an array terminated by ALPROTO_UNKNOWN
2130  *
2131  * \retval 0 on Success
2132  * \retval -1 on Failure
2133  */
2135 {
2136  if (s->alproto != ALPROTO_UNKNOWN) {
2137  // One alproto was set, check if it matches the new ones proposed
2138  while (*alprotos != ALPROTO_UNKNOWN) {
2139  if (s->alproto == *alprotos) {
2140  // alproto already set to only one
2141  return 0;
2142  }
2143  alprotos++;
2144  }
2145  // alproto already set and not matching the new set of alprotos
2146  return -1;
2147  }
2148  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2149  // check intersection of already used alprotos and new ones
2150  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2151  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2152  break;
2153  }
2154  // first disable the ones that do not match
2155  bool found = false;
2156  const AppProto *args = alprotos;
2157  while (*args != ALPROTO_UNKNOWN) {
2158  if (s->init_data->alprotos[i] == *args) {
2159  found = true;
2160  break;
2161  }
2162  args++;
2163  }
2164  if (!found) {
2166  }
2167  }
2168  // Then put at the beginning every defined protocol
2169  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2170  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2171  for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2172  if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2173  s->init_data->alprotos[i] = s->init_data->alprotos[j];
2175  break;
2176  }
2177  }
2178  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2179  if (i == 0) {
2180  // there was no intersection
2181  return -1;
2182  } else if (i == 1) {
2183  // intersection is singleton, set it as usual
2184  AppProto alproto = s->init_data->alprotos[0];
2186  return SCDetectSignatureSetAppProto(s, alproto);
2187  }
2188  break;
2189  }
2190  }
2191  }
2192  } else {
2193  if (alprotos[0] == ALPROTO_UNKNOWN) {
2194  // do not allow empty set
2195  return -1;
2196  }
2197  if (alprotos[1] == ALPROTO_UNKNOWN) {
2198  // allow singleton, but call traditional setter
2199  return SCDetectSignatureSetAppProto(s, alprotos[0]);
2200  }
2201  // first time we enforce alprotos
2202  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2203  if (alprotos[i] == ALPROTO_UNKNOWN) {
2204  break;
2205  }
2206  s->init_data->alprotos[i] = alprotos[i];
2207  }
2208  }
2209  return 0;
2210 }
2211 
2213 {
2214  if (!AppProtoIsValid(alproto)) {
2215  SCLogError("invalid alproto %u", alproto);
2216  return -1;
2217  }
2218 
2219  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2220  // Multiple alprotos were set, check if we restrict to one
2221  bool found = false;
2222  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2223  if (s->init_data->alprotos[i] == alproto) {
2224  found = true;
2225  break;
2226  }
2227  }
2228  if (!found) {
2229  // fail if we set to a alproto which was not in the set
2230  return -1;
2231  }
2232  // we will use s->alproto if there is a single alproto and
2233  // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2235  }
2236 
2237  if (s->alproto != ALPROTO_UNKNOWN) {
2238  alproto = AppProtoCommon(s->alproto, alproto);
2239  if (alproto == ALPROTO_FAILED) {
2240  SCLogError("can't set rule app proto to %s: already set to %s",
2241  AppProtoToString(alproto), AppProtoToString(s->alproto));
2242  return -1;
2243  }
2244  }
2245 
2246  if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2247  SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2248  return -1;
2249  }
2250  s->alproto = alproto;
2251  s->flags |= SIG_FLAG_APPLAYER;
2252  return 0;
2253 }
2254 
2255 static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2256  const DetectAddress *head, uint16_t *match4_cnt)
2257 {
2258  uint16_t cnt = 0;
2259 
2260  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2261  cnt++;
2262  }
2263  if (cnt == 0) {
2264  return NULL;
2265  }
2266  DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2267  if (addr_match4 == NULL) {
2268  exit(EXIT_FAILURE);
2269  }
2270 
2271  uint16_t idx = 0;
2272  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2273  addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2274  addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2275  idx++;
2276  }
2277  *match4_cnt = cnt;
2278  return addr_match4;
2279 }
2280 
2281 static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2282  const DetectAddress *head, uint16_t *match6_cnt)
2283 {
2284  uint16_t cnt = 0;
2285  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2286  cnt++;
2287  }
2288  if (cnt == 0) {
2289  return NULL;
2290  }
2291 
2292  DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2293  if (addr_match6 == NULL) {
2294  exit(EXIT_FAILURE);
2295  }
2296 
2297  uint16_t idx = 0;
2298  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2299  addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2300  addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2301  addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2302  addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2303  addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2304  addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2305  addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2306  addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2307  idx++;
2308  }
2309  *match6_cnt = cnt;
2310  return addr_match6;
2311 }
2312 
2313 /**
2314  * \internal
2315  * \brief build address match array for cache efficient matching
2316  *
2317  * \param s the signature
2318  */
2319 static void SigBuildAddressMatchArray(Signature *s)
2320 {
2321  /* source addresses */
2322  s->addr_src_match4 =
2323  SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2324  /* destination addresses */
2325  s->addr_dst_match4 =
2326  SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2327 
2328  /* source addresses IPv6 */
2329  s->addr_src_match6 =
2330  SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2331  /* destination addresses IPv6 */
2332  s->addr_dst_match6 =
2333  SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2334 }
2335 
2336 static int SigMatchListLen(SigMatch *sm)
2337 {
2338  int len = 0;
2339  for (; sm != NULL; sm = sm->next)
2340  len++;
2341 
2342  return len;
2343 }
2344 
2345 /** \brief convert SigMatch list to SigMatchData array
2346  * \note ownership of sm->ctx is transferred to smd->ctx
2347  */
2349 {
2350  int len = SigMatchListLen(head);
2351  if (len == 0)
2352  return NULL;
2353 
2354  SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
2355  if (smd == NULL) {
2356  FatalError("initializing the detection engine failed");
2357  }
2358  SigMatchData *out = smd;
2359 
2360  /* Copy sm type and Context into array */
2361  SigMatch *sm = head;
2362  for (; sm != NULL; sm = sm->next, smd++) {
2363  smd->type = sm->type;
2364  smd->ctx = sm->ctx;
2365  sm->ctx = NULL; // SigMatch no longer owns the ctx
2366  smd->is_last = (sm->next == NULL);
2367  }
2368  return out;
2369 }
2370 
2371 extern int g_skip_prefilter;
2372 
2373 static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2374 {
2375  SCEnter();
2376  SCLogDebug("s %u: set up prefilter/mpm", s->id);
2377  DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
2378 
2379  if (s->init_data->prefilter_sm != NULL) {
2380  if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
2382  if (s->init_data->mpm_sm != NULL) {
2383  s->flags |= SIG_FLAG_PREFILTER;
2384  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2385  SCReturn;
2386  }
2387  /* fall through, this can happen if the mpm doesn't support the pattern */
2388  } else {
2389  s->flags |= SIG_FLAG_PREFILTER;
2390  SCReturn;
2391  }
2392  } else {
2393  SCLogDebug("%u: RetrieveFPForSig", s->id);
2395  if (s->init_data->mpm_sm != NULL) {
2396  s->flags |= SIG_FLAG_PREFILTER;
2397  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2398  SCReturn;
2399  }
2400  }
2401 
2402  SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2403  "s->init_data->has_possible_prefilter %s",
2405 
2407  SCReturn;
2408 
2411  int prefilter_list = DETECT_TBLSIZE;
2412  /* get the keyword supporting prefilter with the lowest type */
2413  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2414  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2415  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2416  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
2417  prefilter_list = MIN(prefilter_list, sm->type);
2418  }
2419  }
2420  }
2421  }
2422 
2423  /* apply that keyword as prefilter */
2424  if (prefilter_list != DETECT_TBLSIZE) {
2425  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2426  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2427  if (sm->type == prefilter_list) {
2428  s->init_data->prefilter_sm = sm;
2429  s->flags |= SIG_FLAG_PREFILTER;
2430  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2431  sigmatch_table[sm->type].name);
2432  break;
2433  }
2434  }
2435  }
2436  }
2437  }
2438  SCReturn;
2439 }
2440 
2441 static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2442 {
2444  SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2445  "explicit hook",
2446  s->id);
2447  return false;
2448  }
2449  return true;
2450 }
2451 
2452 static void DetectFirewallRuleSetTable(Signature *s)
2453 {
2454  enum FirewallTable table;
2455  if (s->flags & SIG_FLAG_FIREWALL) {
2456  if (s->type == SIG_TYPE_PKT) {
2458  } else if (s->type == SIG_TYPE_APP_TX) {
2459  table = FIREWALL_TABLE_APP_FILTER;
2460  } else {
2461  BUG_ON(1);
2462  }
2463  } else {
2464  if (s->type != SIG_TYPE_APP_TX) {
2465  table = FIREWALL_TABLE_PACKET_TD;
2466  } else {
2467  table = FIREWALL_TABLE_APP_TD;
2468  }
2469  }
2470 
2471  s->firewall_table = (uint8_t)table;
2472 }
2473 
2474 /**
2475  * \internal
2476  * \brief validate a just parsed signature for internal inconsistencies
2477  *
2478  * \param s just parsed signature
2479  *
2480  * \retval 0 invalid
2481  * \retval 1 valid
2482  */
2483 static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
2484 {
2485  SCEnter();
2486 
2487  if (s->init_data->firewall_rule) {
2488  if (!DetectFirewallRuleValidate(de_ctx, s))
2489  SCReturnInt(0);
2490  }
2491 
2492  uint32_t sig_flags = 0;
2493  int nlists = 0;
2494  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2495  nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2496  }
2497  nlists += (nlists > 0);
2498  SCLogDebug("nlists %d", nlists);
2499 
2500  if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2501  SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2503  SCReturnInt(0);
2504  }
2505 
2506  bool has_frame = false;
2507  bool has_app = false;
2508  bool has_pkt = false;
2509  bool has_pmatch = false;
2510 
2511  /* run buffer type validation callbacks if any */
2514  SCReturnInt(0);
2515 
2516  has_pmatch = true;
2517  }
2518 
2519  struct BufferVsDir {
2520  int ts;
2521  int tc;
2522  } bufdir[nlists + 1];
2523  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2524 
2525  int ts_excl = 0;
2526  int tc_excl = 0;
2527 
2528  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2531  if (bt == NULL) {
2532  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2533  continue;
2534  }
2535  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2536  for (SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2537  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2538  }
2539 
2540  if (b->head == NULL) {
2541  SCLogError("no matches in sticky buffer %s", bt->name);
2542  SCReturnInt(0);
2543  }
2544 
2545  has_frame |= bt->frame;
2546  has_app |= (!bt->frame && !bt->packet);
2547  has_pkt |= bt->packet;
2548 
2549  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2550  SCLogError("Signature combines packet "
2551  "specific matches (like dsize, flags, ttl) with stream / "
2552  "state matching by matching on app layer proto (like using "
2553  "http_* keywords).");
2554  SCReturnInt(0);
2555  }
2556 
2558  for (; app != NULL; app = app->next) {
2559  if (app->sm_list == b->id &&
2560  (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2561  SCLogDebug("engine %s dir %d alproto %d",
2563  app->alproto);
2564  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2565 
2566  if (b->only_tc) {
2567  if (app->dir == 1)
2568  tc_excl++;
2569  } else if (b->only_ts) {
2570  if (app->dir == 0)
2571  ts_excl++;
2572  } else {
2573  bufdir[b->id].ts += (app->dir == 0);
2574  bufdir[b->id].tc += (app->dir == 1);
2575  }
2576 
2577  /* only allow rules to use the hook for engines at that
2578  * exact progress for now. */
2580  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2581  app->progress != s->init_data->hook.t.app.app_progress) {
2582  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2583  s->init_data->hook.t.app.app_progress);
2584  SCReturnInt(0);
2585  }
2586  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2587  app->progress != s->init_data->hook.t.app.app_progress) {
2588  SCLogError("engine progress value doesn't match hook");
2589  SCReturnInt(0);
2590  }
2591  }
2592  }
2593  }
2594 
2596  SCReturnInt(0);
2597  }
2598 
2600  SCReturnInt(0);
2601  }
2603  SCReturnInt(0);
2604  }
2605  }
2606 
2607  int dir_amb = 0;
2608  for (int x = 0; x < nlists; x++) {
2609  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2610  continue;
2611  ts_excl += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2612  tc_excl += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2613  dir_amb += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2614 
2615  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2616  bufdir[x].tc);
2617  }
2618  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2619  if (!ts_excl || !tc_excl) {
2620  SCLogError("rule %u should use both directions, but does not", s->id);
2621  SCReturnInt(0);
2622  }
2623  if (dir_amb) {
2624  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2625  "directions",
2626  s->id);
2627  SCReturnInt(0);
2628  }
2629  } else if (ts_excl && tc_excl) {
2630  SCLogError(
2631  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2632  "should be used",
2633  s->id);
2634  SCReturnInt(0);
2635  } else if (ts_excl) {
2636  SCLogDebug("%u: implied rule direction is toserver", s->id);
2638  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2639  SCReturnInt(0);
2640  }
2641  } else if (tc_excl) {
2642  SCLogDebug("%u: implied rule direction is toclient", s->id);
2644  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2645  SCReturnInt(0);
2646  }
2647  } else if (dir_amb) {
2648  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2649  }
2650 
2651  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) &&
2652  (s->flags & SIG_FLAG_REQUIRE_STREAM)) {
2653  SCLogError("can't mix packet keywords with "
2654  "tcp-stream or flow:only_stream. Invalidating signature.");
2655  SCReturnInt(0);
2656  }
2657 
2659  SCLogError("You seem to have mixed keywords "
2660  "that require inspection in both directions. Atm we only "
2661  "support keywords in one direction within a rule.");
2662  SCReturnInt(0);
2663  }
2664 
2665  if (has_pmatch && has_frame) {
2666  SCLogError("can't mix pure content and frame inspection");
2667  SCReturnInt(0);
2668  }
2669  if (has_app && has_frame) {
2670  SCLogError("can't mix app-layer buffer and frame inspection");
2671  SCReturnInt(0);
2672  }
2673  if (has_pkt && has_frame) {
2674  SCLogError("can't mix pkt buffer and frame inspection");
2675  SCReturnInt(0);
2676  }
2677 
2678  /* TCP: corner cases:
2679  * - pkt vs stream vs depth/offset
2680  * - pkt vs stream vs stream_size
2681  */
2682  if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
2686  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2687  sm = sm->next) {
2688  if (sm->type == DETECT_CONTENT &&
2689  (((DetectContentData *)(sm->ctx))->flags &
2692  break;
2693  }
2694  }
2695  /* if stream_size is in use, also inspect packets */
2696  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2697  sm = sm->next) {
2698  if (sm->type == DETECT_STREAM_SIZE) {
2700  break;
2701  }
2702  }
2703  }
2704  }
2705  }
2706 
2707  if ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2709  if (s->alproto != ALPROTO_UNKNOWN &&
2710  !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto))
2711  {
2712  SCLogError("protocol %s doesn't "
2713  "support file matching",
2715  SCReturnInt(0);
2716  } else if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2717  bool found = false;
2718  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2719  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2720  break;
2721  }
2722  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i])) {
2723  found = true;
2724  break;
2725  }
2726  }
2727  if (!found) {
2728  SCLogError("No protocol support file matching");
2729  SCReturnInt(0);
2730  }
2731  }
2733  SCLogError("protocol HTTP2 doesn't support file name matching");
2734  SCReturnInt(0);
2735  }
2736 
2737  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2739  }
2740  }
2741 
2742  SCReturnInt(1);
2743 }
2744 
2745 /**
2746  * \internal
2747  * \brief Helper function for SigInit().
2748  */
2749 static Signature *SigInitHelper(
2750  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2751 {
2752  SignatureParser parser;
2753  memset(&parser, 0x00, sizeof(parser));
2754 
2755  Signature *sig = SigAlloc();
2756  if (sig == NULL)
2757  goto error;
2758  if (firewall_rule) {
2759  sig->init_data->firewall_rule = true;
2760  sig->flags |= SIG_FLAG_FIREWALL;
2761  }
2762 
2763  sig->sig_str = SCStrdup(sigstr);
2764  if (unlikely(sig->sig_str == NULL)) {
2765  goto error;
2766  }
2767 
2768  /* default gid to 1 */
2769  sig->gid = 1;
2770 
2771  /* We do a first parse of the rule in a requires, or scan-only
2772  * mode. Syntactic errors will be picked up here, but the only
2773  * part of the rule that is validated completely is the "requires"
2774  * keyword. */
2775  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
2776  if (ret == -4) {
2777  /* Rule requirements not met. */
2778  de_ctx->sigerror_silent = true;
2779  de_ctx->sigerror_ok = true;
2780  de_ctx->sigerror_requires = true;
2781  goto error;
2782  } else if (ret < 0) {
2783  goto error;
2784  }
2785 
2786  /* Check for a SID before continuuing. */
2787  if (sig->id == 0) {
2788  SCLogError("Signature missing required value \"sid\".");
2789  goto error;
2790  }
2791 
2792  /* Now completely parse the rule. */
2793  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2794  BUG_ON(ret == -4);
2795  if (ret == -3) {
2796  de_ctx->sigerror_silent = true;
2797  de_ctx->sigerror_ok = true;
2798  goto error;
2799  } else if (ret == -2) {
2800  de_ctx->sigerror_silent = true;
2801  goto error;
2802  } else if (ret < 0) {
2803  goto error;
2804  }
2805 
2806  /* signature priority hasn't been overwritten. Using default priority */
2807  if (sig->prio == -1)
2808  sig->prio = DETECT_DEFAULT_PRIO;
2809 
2810  sig->iid = de_ctx->signum;
2811  de_ctx->signum++;
2812 
2813  if (sig->alproto != ALPROTO_UNKNOWN) {
2814  int override_needed = 0;
2815  if (sig->proto.flags & DETECT_PROTO_ANY) {
2816  sig->proto.flags &= ~DETECT_PROTO_ANY;
2817  memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
2818  override_needed = 1;
2819  } else {
2820  override_needed = 1;
2821  size_t s = 0;
2822  for (s = 0; s < sizeof(sig->proto.proto); s++) {
2823  if (sig->proto.proto[s] != 0x00) {
2824  override_needed = 0;
2825  break;
2826  }
2827  }
2828  }
2829 
2830  /* at this point if we had alert ip and the ip proto was not
2831  * overridden, we use the ip proto that has been configured
2832  * against the app proto in use. */
2833  if (override_needed)
2835  }
2836 
2837  /* set the packet and app layer flags, but only if the
2838  * app layer flag wasn't already set in which case we
2839  * only consider the app layer */
2840  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
2841  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
2843  for ( ; sm != NULL; sm = sm->next) {
2844  if (sigmatch_table[sm->type].Match != NULL)
2846  }
2847  } else {
2849  }
2850  }
2851 
2852  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
2853  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
2854  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
2856  }
2857  }
2858  }
2859 
2860  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
2861  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
2862  sig->flags |= SIG_FLAG_TOSERVER;
2863  sig->flags |= SIG_FLAG_TOCLIENT;
2864  }
2865  }
2866 
2867  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
2868  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
2869  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
2870 
2871  SigBuildAddressMatchArray(sig);
2872 
2873  /* run buffer type callbacks if any */
2874  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
2875  if (sig->init_data->smlists[x])
2877  }
2878  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
2880  }
2881 
2882  SigSetupPrefilter(de_ctx, sig);
2883 
2884  /* validate signature, SigValidate will report the error reason */
2885  if (SigValidate(de_ctx, sig) == 0) {
2886  goto error;
2887  }
2888 
2889  /* check what the type of this sig is */
2890  SignatureSetType(de_ctx, sig);
2891 
2892  if (de_ctx->flags & DE_HAS_FIREWALL) {
2893  DetectFirewallRuleSetTable(sig);
2894  }
2895 
2896  if (sig->type == SIG_TYPE_IPONLY) {
2897  /* For IPOnly */
2898  if (IPOnlySigParseAddress(de_ctx, sig, parser.src, SIG_DIREC_SRC ^ dir) < 0)
2899  goto error;
2900 
2901  if (IPOnlySigParseAddress(de_ctx, sig, parser.dst, SIG_DIREC_DST ^ dir) < 0)
2902  goto error;
2903  }
2904  return sig;
2905 
2906 error:
2907  if (sig != NULL) {
2908  SigFree(de_ctx, sig);
2909  }
2910  return NULL;
2911 }
2912 
2913 /**
2914  * \brief Checks if a signature has the same source and destination
2915  * \param s parsed signature
2916  *
2917  * \retval true if source and destination are the same, false otherwise
2918  */
2919 static bool SigHasSameSourceAndDestination(const Signature *s)
2920 {
2921  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
2922  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
2923  return false;
2924  }
2925  }
2926 
2927  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
2930 
2932  return false;
2933  }
2934 
2935  src = s->init_data->src->ipv6_head;
2936  dst = s->init_data->dst->ipv6_head;
2937 
2939  return false;
2940  }
2941  }
2942 
2943  return true;
2944 }
2945 
2946 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
2947 {
2948  SCEnter();
2949 
2950  uint32_t oldsignum = de_ctx->signum;
2951  de_ctx->sigerror_ok = false;
2952  de_ctx->sigerror_silent = false;
2953  de_ctx->sigerror_requires = false;
2954 
2955  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
2956  if (sig == NULL) {
2957  goto error;
2958  }
2959 
2961  if (SigHasSameSourceAndDestination(sig)) {
2962  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
2963  "treating the rule as unidirectional", sig->id);
2964 
2966  } else {
2967  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
2968  if (sig->next == NULL) {
2969  goto error;
2970  }
2971  }
2972  }
2973 
2974  SCReturnPtr(sig, "Signature");
2975 
2976 error:
2977  if (sig != NULL) {
2978  SigFree(de_ctx, sig);
2979  }
2980  /* if something failed, restore the old signum count
2981  * since we didn't install it */
2982  de_ctx->signum = oldsignum;
2983 
2984  SCReturnPtr(NULL, "Signature");
2985 }
2986 
2987 /**
2988  * \brief Parses a signature and adds it to the Detection Engine Context.
2989  *
2990  * \param de_ctx Pointer to the Detection Engine Context.
2991  * \param sigstr Pointer to a character string containing the signature to be
2992  * parsed.
2993  *
2994  * \retval Pointer to the Signature instance on success; NULL on failure.
2995  */
2996 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
2997 {
2998  return SigInitDo(de_ctx, sigstr, false);
2999 }
3000 
3001 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3002 {
3003  return SigInitDo(de_ctx, sigstr, true);
3004 }
3005 
3006 /**
3007  * \brief The hash free function to be the used by the hash table -
3008  * DetectEngineCtx->dup_sig_hash_table.
3009  *
3010  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3011  */
3012 static void DetectParseDupSigFreeFunc(void *data)
3013 {
3014  if (data != NULL)
3015  SCFree(data);
3016 }
3017 
3018 /**
3019  * \brief The hash function to be the used by the hash table -
3020  * DetectEngineCtx->dup_sig_hash_table.
3021  *
3022  * \param ht Pointer to the hash table.
3023  * \param data Pointer to the data, in our case SigDuplWrapper.
3024  * \param datalen Not used in our case.
3025  *
3026  * \retval sw->s->id The generated hash value.
3027  */
3028 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3029 {
3030  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3031 
3032  return (sw->s->id % ht->array_size);
3033 }
3034 
3035 /**
3036  * \brief The Compare function to be used by the hash table -
3037  * DetectEngineCtx->dup_sig_hash_table.
3038  *
3039  * \param data1 Pointer to the first SigDuplWrapper.
3040  * \param len1 Not used.
3041  * \param data2 Pointer to the second SigDuplWrapper.
3042  * \param len2 Not used.
3043  *
3044  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3045  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3046  */
3047 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3048  uint16_t len2)
3049 {
3050  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3051  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3052 
3053  if (sw1 == NULL || sw2 == NULL ||
3054  sw1->s == NULL || sw2->s == NULL)
3055  return 0;
3056 
3057  /* sid and gid match required */
3058  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3059 
3060  return 0;
3061 }
3062 
3063 /**
3064  * \brief Initializes the hash table that is used to cull duplicate sigs.
3065  *
3066  * \param de_ctx Pointer to the detection engine context.
3067  *
3068  * \retval 0 On success.
3069  * \retval -1 On failure.
3070  */
3072 {
3074  DetectParseDupSigHashFunc,
3075  DetectParseDupSigCompareFunc,
3076  DetectParseDupSigFreeFunc);
3077  if (de_ctx->dup_sig_hash_table == NULL)
3078  return -1;
3079 
3080  return 0;
3081 }
3082 
3083 /**
3084  * \brief Frees the hash table that is used to cull duplicate sigs.
3085  *
3086  * \param de_ctx Pointer to the detection engine context that holds this table.
3087  */
3089 {
3090  if (de_ctx->dup_sig_hash_table != NULL)
3092 
3093  de_ctx->dup_sig_hash_table = NULL;
3094 }
3095 
3096 /**
3097  * \brief Check if a signature is a duplicate.
3098  *
3099  * There are 3 types of return values for this function.
3100  *
3101  * - 0, which indicates that the Signature is not a duplicate
3102  * and has to be added to the detection engine list.
3103  * - 1, Signature is duplicate, and the existing signature in
3104  * the list shouldn't be replaced with this duplicate.
3105  * - 2, Signature is duplicate, and the existing signature in
3106  * the list should be replaced with this duplicate.
3107  *
3108  * \param de_ctx Pointer to the detection engine context.
3109  * \param sig Pointer to the Signature that has to be checked.
3110  *
3111  * \retval 2 If Signature is duplicate and the existing signature in
3112  * the list should be chucked out and replaced with this.
3113  * \retval 1 If Signature is duplicate, and should be chucked out.
3114  * \retval 0 If Signature is not a duplicate.
3115  */
3116 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3117  Signature *sig)
3118 {
3119  /* we won't do any NULL checks on the args */
3120 
3121  /* return value */
3122  int ret = 0;
3123 
3124  SigDuplWrapper *sw_dup = NULL;
3125  SigDuplWrapper *sw = NULL;
3126 
3127  /* used for making a duplicate_sig_hash_table entry */
3128  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3129  if (unlikely(sw == NULL)) {
3130  exit(EXIT_FAILURE);
3131  }
3132  sw->s = sig;
3133 
3134  /* check if we have a duplicate entry for this signature */
3135  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3136  /* we don't have a duplicate entry for this sig */
3137  if (sw_dup == NULL) {
3138  /* add it to the hash table */
3139  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3140 
3141  /* add the s_prev entry for the previously loaded sw in the hash_table */
3142  if (de_ctx->sig_list != NULL) {
3143  SigDuplWrapper *sw_old = NULL;
3144  SigDuplWrapper sw_tmp;
3145  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3146 
3147  /* the topmost sig would be the last loaded sig */
3148  sw_tmp.s = de_ctx->sig_list;
3150  (void *)&sw_tmp, 0);
3151  /* sw_old == NULL case is impossible */
3152  sw_old->s_prev = sig;
3153  }
3154 
3155  ret = 0;
3156  goto end;
3157  }
3158 
3159  /* if we have reached here we have a duplicate entry for this signature.
3160  * Check the signature revision. Store the signature with the latest rev
3161  * and discard the other one */
3162  if (sw->s->rev <= sw_dup->s->rev) {
3163  ret = 1;
3164  SCFree(sw);
3165  sw = NULL;
3166  goto end;
3167  }
3168 
3169  /* the new sig is of a newer revision than the one that is already in the
3170  * list. Remove the old sig from the list */
3171  if (sw_dup->s_prev == NULL) {
3172  SigDuplWrapper sw_temp;
3173  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3174  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3175  sw_temp.s = sw_dup->s->next->next;
3176  de_ctx->sig_list = sw_dup->s->next->next;
3177  SigFree(de_ctx, sw_dup->s->next);
3178  } else {
3179  sw_temp.s = sw_dup->s->next;
3180  de_ctx->sig_list = sw_dup->s->next;
3181  }
3182  SigDuplWrapper *sw_next = NULL;
3183  if (sw_temp.s != NULL) {
3185  (void *)&sw_temp, 0);
3186  sw_next->s_prev = sw_dup->s_prev;
3187  }
3188  SigFree(de_ctx, sw_dup->s);
3189  } else {
3190  SigDuplWrapper sw_temp;
3191  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3192  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3193  sw_temp.s = sw_dup->s->next->next;
3194  /* If previous signature is bidirectional,
3195  * it has 2 items in the linked list.
3196  * So we need to change next->next instead of next
3197  */
3199  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3200  } else {
3201  sw_dup->s_prev->next = sw_dup->s->next->next;
3202  }
3203  SigFree(de_ctx, sw_dup->s->next);
3204  } else {
3205  sw_temp.s = sw_dup->s->next;
3207  sw_dup->s_prev->next->next = sw_dup->s->next;
3208  } else {
3209  sw_dup->s_prev->next = sw_dup->s->next;
3210  }
3211  }
3212  SigDuplWrapper *sw_next = NULL;
3213  if (sw_temp.s != NULL) {
3215  (void *)&sw_temp, 0);
3216  sw_next->s_prev = sw_dup->s_prev;
3217  }
3218  SigFree(de_ctx, sw_dup->s);
3219  }
3220 
3221  /* make changes to the entry to reflect the presence of the new sig */
3222  sw_dup->s = sig;
3223  sw_dup->s_prev = NULL;
3224 
3225  if (de_ctx->sig_list != NULL) {
3226  SigDuplWrapper sw_tmp;
3227  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3228  sw_tmp.s = de_ctx->sig_list;
3230  (void *)&sw_tmp, 0);
3231  if (sw_old->s != sw_dup->s) {
3232  // Link on top of the list if there was another element
3233  sw_old->s_prev = sig;
3234  }
3235  }
3236 
3237  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3238  ret = 2;
3239 
3240  SCFree(sw);
3241 
3242 end:
3243  return ret;
3244 }
3245 
3246 /**
3247  * \brief Parse and append a Signature into the Detection Engine Context
3248  * signature list.
3249  *
3250  * If the signature is bidirectional it should append two signatures
3251  * (with the addresses switched) into the list. Also handle duplicate
3252  * signatures. In case of duplicate sigs, use the ones that have the
3253  * latest revision. We use the sid and the msg to identify duplicate
3254  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3255  *
3256  * \param de_ctx Pointer to the Detection Engine Context.
3257  * \param sigstr Pointer to a character string containing the signature to be
3258  * parsed.
3259  * \param sig_file Pointer to a character string containing the filename from
3260  * which signature is read
3261  * \param lineno Line number from where signature is read
3262  *
3263  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3264  * on success; NULL on failure.
3265  */
3267 {
3268  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3269  if (sig == NULL) {
3270  return NULL;
3271  }
3272 
3273  /* checking for the status of duplicate signature */
3274  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3275  /* a duplicate signature that should be chucked out. Check the previously
3276  * called function details to understand the different return values */
3277  if (dup_sig == 1) {
3278  SCLogError("Duplicate signature \"%s\"", sigstr);
3279  goto error;
3280  } else if (dup_sig == 2) {
3281  SCLogWarning("Signature with newer revision,"
3282  " so the older sig replaced by this new signature \"%s\"",
3283  sigstr);
3284  }
3285 
3287  if (sig->next != NULL) {
3288  sig->next->next = de_ctx->sig_list;
3289  } else {
3290  goto error;
3291  }
3292  } else {
3293  /* if this sig is the first one, sig_list should be null */
3294  sig->next = de_ctx->sig_list;
3295  }
3296 
3297  de_ctx->sig_list = sig;
3298 
3299  /**
3300  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3301  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3302  * to the cloned signatures with the switched addresses
3303  */
3304  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3305 
3306 error:
3307  /* free the 2nd sig bidir may have set up */
3308  if (sig != NULL && sig->next != NULL) {
3309  SigFree(de_ctx, sig->next);
3310  sig->next = NULL;
3311  }
3312  if (sig != NULL) {
3313  SigFree(de_ctx, sig);
3314  }
3315  return NULL;
3316 }
3317 
3318 /**
3319  * \brief Parse and append a Signature into the Detection Engine Context
3320  * signature list.
3321  *
3322  * If the signature is bidirectional it should append two signatures
3323  * (with the addresses switched) into the list. Also handle duplicate
3324  * signatures. In case of duplicate sigs, use the ones that have the
3325  * latest revision. We use the sid and the msg to identify duplicate
3326  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3327  *
3328  * \param de_ctx Pointer to the Detection Engine Context.
3329  * \param sigstr Pointer to a character string containing the signature to be
3330  * parsed.
3331  * \param sig_file Pointer to a character string containing the filename from
3332  * which signature is read
3333  * \param lineno Line number from where signature is read
3334  *
3335  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3336  * on success; NULL on failure.
3337  */
3339 {
3340  Signature *sig = SigInit(de_ctx, sigstr);
3341  if (sig == NULL) {
3342  return NULL;
3343  }
3344 
3345  /* checking for the status of duplicate signature */
3346  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3347  /* a duplicate signature that should be chucked out. Check the previously
3348  * called function details to understand the different return values */
3349  if (dup_sig == 1) {
3350  SCLogError("Duplicate signature \"%s\"", sigstr);
3351  goto error;
3352  } else if (dup_sig == 2) {
3353  SCLogWarning("Signature with newer revision,"
3354  " so the older sig replaced by this new signature \"%s\"",
3355  sigstr);
3356  }
3357 
3359  if (sig->next != NULL) {
3360  sig->next->next = de_ctx->sig_list;
3361  } else {
3362  goto error;
3363  }
3364  } else {
3365  /* if this sig is the first one, sig_list should be null */
3366  sig->next = de_ctx->sig_list;
3367  }
3368 
3369  de_ctx->sig_list = sig;
3370 
3371  /**
3372  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3373  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3374  * to the cloned signatures with the switched addresses
3375  */
3376  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3377 
3378 error:
3379  /* free the 2nd sig bidir may have set up */
3380  if (sig != NULL && sig->next != NULL) {
3381  SigFree(de_ctx, sig->next);
3382  sig->next = NULL;
3383  }
3384  if (sig != NULL) {
3385  SigFree(de_ctx, sig);
3386  }
3387  return NULL;
3388 }
3389 
3390 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3391 
3392 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3393  int start_offset, int options)
3394 {
3395  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3396  if (*match)
3397  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3398  *match, parse_regex->context);
3399  return -1;
3400 }
3401 
3403 {
3404  if (r->regex) {
3405  pcre2_code_free(r->regex);
3406  }
3407  if (r->context) {
3408  pcre2_match_context_free(r->context);
3409  }
3410 }
3411 
3413 {
3414  DetectParseRegex *r = g_detect_parse_regex_list;
3415  while (r) {
3416  DetectParseRegex *next = r->next;
3417 
3419 
3420  SCFree(r);
3421  r = next;
3422  }
3423  g_detect_parse_regex_list = NULL;
3424 }
3425 
3426 /** \brief add regex and/or study to at exit free list
3427  */
3429 {
3430  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3431  if (r == NULL) {
3432  FatalError("failed to alloc memory for pcre free list");
3433  }
3434  r->regex = detect_parse->regex;
3435  r->next = g_detect_parse_regex_list;
3436  g_detect_parse_regex_list = r;
3437 }
3438 
3439 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3440 {
3441  int en;
3442  PCRE2_SIZE eo;
3443 
3444  detect_parse->regex =
3445  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3446  if (detect_parse->regex == NULL) {
3447  PCRE2_UCHAR errbuffer[256];
3448  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3449  SCLogError("pcre compile of \"%s\" failed at "
3450  "offset %d: %s",
3451  parse_str, en, errbuffer);
3452  return false;
3453  }
3454  detect_parse->context = pcre2_match_context_create(NULL);
3455  if (detect_parse->context == NULL) {
3456  SCLogError("pcre2 could not create match context");
3457  pcre2_code_free(detect_parse->regex);
3458  detect_parse->regex = NULL;
3459  return false;
3460  }
3461  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3462  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3463  DetectParseRegexAddToFreeList(detect_parse);
3464 
3465  return true;
3466 }
3467 
3468 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3469 {
3470  int en;
3471  PCRE2_SIZE eo;
3472  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3473  if (detect_parse == NULL) {
3474  return NULL;
3475  }
3476 
3477  detect_parse->regex =
3478  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3479  if (detect_parse->regex == NULL) {
3480  PCRE2_UCHAR errbuffer[256];
3481  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3482  SCLogError("pcre2 compile of \"%s\" failed at "
3483  "offset %d: %s",
3484  parse_str, (int)eo, errbuffer);
3485  SCFree(detect_parse);
3486  return NULL;
3487  }
3488 
3489  detect_parse->next = g_detect_parse_regex_list;
3490  g_detect_parse_regex_list = detect_parse;
3491  return detect_parse;
3492 }
3493 
3495  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3496 {
3497  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3498  if (r == PCRE2_ERROR_UNSET) {
3499  buffer[0] = 0;
3500  *bufflen = 0;
3501  return 0;
3502  }
3503  return r;
3504 }
3505 
3507  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3508 {
3509  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3510  if (r == PCRE2_ERROR_UNSET) {
3511  *bufferptr = NULL;
3512  *bufflen = 0;
3513  return 0;
3514  }
3515  return r;
3516 }
3517 
3518 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3519 {
3520  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3521  FatalError("pcre compile and study failed");
3522  }
3523 }
3524 
3525 /*
3526  * TESTS
3527  */
3528 
3529 #ifdef UNITTESTS
3530 #include "detect-engine-alert.h"
3531 #include "packet.h"
3532 
3533 static int SigParseTest01 (void)
3534 {
3535  int result = 1;
3536  Signature *sig = NULL;
3537 
3539  if (de_ctx == NULL)
3540  goto end;
3541 
3542  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3543  if (sig == NULL)
3544  result = 0;
3545 
3546 end:
3547  if (sig != NULL) SigFree(de_ctx, sig);
3548  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3549  return result;
3550 }
3551 
3552 static int SigParseTest02 (void)
3553 {
3554  int result = 0;
3555  Signature *sig = NULL;
3556  DetectPort *port = NULL;
3557 
3559 
3560  if (de_ctx == NULL)
3561  goto end;
3562 
3565 
3566  sig = SigInit(de_ctx, "alert tcp any !21:902 -> any any (msg:\"ET MALWARE Suspicious 220 Banner on Local Port\"; content:\"220\"; offset:0; depth:4; pcre:\"/220[- ]/\"; sid:2003055; rev:4;)");
3567  if (sig == NULL) {
3568  goto end;
3569  }
3570 
3571  int r = DetectPortParse(de_ctx, &port, "0:20");
3572  if (r < 0)
3573  goto end;
3574 
3575  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3576  result = 1;
3577  } else {
3578  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3579  }
3580 
3581 end:
3582  if (port != NULL)
3584  if (sig != NULL)
3585  SigFree(de_ctx, sig);
3586  if (de_ctx != NULL)
3588  return result;
3589 }
3590 
3591 /**
3592  * \test SigParseTest03 test for invalid direction operator in rule
3593  */
3594 static int SigParseTest03 (void)
3595 {
3596  int result = 1;
3597  Signature *sig = NULL;
3598 
3600  if (de_ctx == NULL)
3601  goto end;
3602 
3603  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3604  if (sig != NULL) {
3605  result = 0;
3606  printf("expected NULL got sig ptr %p: ",sig);
3607  }
3608 
3609 end:
3610  if (sig != NULL) SigFree(de_ctx, sig);
3611  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3612  return result;
3613 }
3614 
3615 static int SigParseTest04 (void)
3616 {
3617  int result = 1;
3618  Signature *sig = NULL;
3619 
3621  if (de_ctx == NULL)
3622  goto end;
3623 
3624  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3625  if (sig == NULL)
3626  result = 0;
3627 
3628 end:
3629  if (sig != NULL) SigFree(de_ctx, sig);
3630  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3631  return result;
3632 }
3633 
3634 /** \test Port validation */
3635 static int SigParseTest05 (void)
3636 {
3637  int result = 0;
3638  Signature *sig = NULL;
3639 
3641  if (de_ctx == NULL)
3642  goto end;
3643 
3644  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3645  if (sig == NULL) {
3646  result = 1;
3647  } else {
3648  printf("signature didn't fail to parse as we expected: ");
3649  }
3650 
3651 end:
3652  if (sig != NULL) SigFree(de_ctx, sig);
3653  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3654  return result;
3655 }
3656 
3657 /** \test Parsing bug debugging at 2010-03-18 */
3658 static int SigParseTest06 (void)
3659 {
3660  int result = 0;
3661  Signature *sig = NULL;
3662 
3664  if (de_ctx == NULL)
3665  goto end;
3666 
3667  sig = SigInit(de_ctx, "alert tcp any any -> any any (flow:to_server; content:\"GET\"; nocase; http_method; uricontent:\"/uri/\"; nocase; content:\"Host|3A| abc\"; nocase; sid:1; rev:1;)");
3668  if (sig != NULL) {
3669  result = 1;
3670  } else {
3671  printf("signature failed to parse: ");
3672  }
3673 
3674 end:
3675  if (sig != NULL)
3676  SigFree(de_ctx, sig);
3677  if (de_ctx != NULL)
3679  return result;
3680 }
3681 
3682 /**
3683  * \test Parsing duplicate sigs.
3684  */
3685 static int SigParseTest07(void)
3686 {
3687  int result = 0;
3688 
3690  if (de_ctx == NULL)
3691  goto end;
3692 
3693  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3694  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3695 
3696  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3697 
3698 end:
3699  if (de_ctx != NULL)
3701  return result;
3702 }
3703 
3704 /**
3705  * \test Parsing duplicate sigs.
3706  */
3707 static int SigParseTest08(void)
3708 {
3709  int result = 0;
3710 
3712  if (de_ctx == NULL)
3713  goto end;
3714 
3715  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3716  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3717 
3718  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3719  de_ctx->sig_list->rev == 2);
3720 
3721 end:
3722  if (de_ctx != NULL)
3724  return result;
3725 }
3726 
3727 /**
3728  * \test Parsing duplicate sigs.
3729  */
3730 static int SigParseTest09(void)
3731 {
3732  int result = 1;
3733 
3735  if (de_ctx == NULL)
3736  goto end;
3737 
3738  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3739  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3740  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3741  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3742  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3743  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3744  de_ctx->sig_list->rev == 2);
3745  if (result == 0)
3746  goto end;
3747  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3748  de_ctx->sig_list->next->rev == 6);
3749  if (result == 0)
3750  goto end;
3751 
3752  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3753  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3754  de_ctx->sig_list->rev == 2);
3755  if (result == 0)
3756  goto end;
3757  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3758  de_ctx->sig_list->next->rev == 6);
3759  if (result == 0)
3760  goto end;
3761 
3762  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3763  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3764  de_ctx->sig_list->rev == 4);
3765  if (result == 0)
3766  goto end;
3767  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3768  de_ctx->sig_list->next->rev == 6);
3769  if (result == 0)
3770  goto end;
3771 
3772 end:
3773  if (de_ctx != NULL)
3775  return result;
3776 }
3777 
3778 /**
3779  * \test Parsing duplicate sigs.
3780  */
3781 static int SigParseTest10(void)
3782 {
3783  int result = 1;
3784 
3786  if (de_ctx == NULL)
3787  goto end;
3788 
3789  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3790  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3791  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3792  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3793  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3794  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3795  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3796 
3797  result &= ((de_ctx->sig_list->id == 2) &&
3798  (de_ctx->sig_list->next->id == 3) &&
3799  (de_ctx->sig_list->next->next->id == 5) &&
3800  (de_ctx->sig_list->next->next->next->id == 4) &&
3801  (de_ctx->sig_list->next->next->next->next->id == 1));
3802 
3803 end:
3804  if (de_ctx != NULL)
3806  return result;
3807 }
3808 
3809 /**
3810  * \test Parsing sig with trailing space(s) as reported by
3811  * Morgan Cox on oisf-users.
3812  */
3813 static int SigParseTest11(void)
3814 {
3815  int result = 0;
3816 
3818  if (de_ctx == NULL)
3819  goto end;
3820 
3821  Signature *s = NULL;
3822 
3824  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3825  if (s == NULL) {
3826  printf("sig 1 didn't parse: ");
3827  goto end;
3828  }
3829 
3830  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3831  "the http link\"; sid:2;) ");
3832  if (s == NULL) {
3833  printf("sig 2 didn't parse: ");
3834  goto end;
3835  }
3836 
3837  result = 1;
3838 end:
3839  if (de_ctx != NULL)
3841  return result;
3842 }
3843 
3844 /**
3845  * \test file_data with rawbytes
3846  */
3847 static int SigParseTest12(void)
3848 {
3849  int result = 0;
3850 
3852  if (de_ctx == NULL)
3853  goto end;
3854 
3855  Signature *s = NULL;
3856 
3857  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3858  if (s != NULL) {
3859  printf("sig 1 should have given an error: ");
3860  goto end;
3861  }
3862 
3863  result = 1;
3864 end:
3865  if (de_ctx != NULL)
3867  return result;
3868 }
3869 
3870 /**
3871  * \test packet/stream sig
3872  */
3873 static int SigParseTest13(void)
3874 {
3875  int result = 0;
3876 
3878  if (de_ctx == NULL)
3879  goto end;
3880 
3881  Signature *s = NULL;
3882 
3883  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
3884  if (s == NULL) {
3885  printf("sig 1 invalidated: failure");
3886  goto end;
3887  }
3888 
3889  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
3890  printf("sig doesn't have stream flag set\n");
3891  goto end;
3892  }
3893 
3894  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
3895  printf("sig has packet flag set\n");
3896  goto end;
3897  }
3898 
3899  result = 1;
3900 
3901 end:
3902  if (de_ctx != NULL)
3904  return result;
3905 }
3906 
3907 /**
3908  * \test packet/stream sig
3909  */
3910 static int SigParseTest14(void)
3911 {
3912  int result = 0;
3913 
3915  if (de_ctx == NULL)
3916  goto end;
3917 
3918  Signature *s = NULL;
3919 
3920  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
3921  if (s == NULL) {
3922  printf("sig 1 invalidated: failure");
3923  goto end;
3924  }
3925 
3926  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
3927  printf("sig doesn't have packet flag set\n");
3928  goto end;
3929  }
3930 
3931  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
3932  printf("sig has stream flag set\n");
3933  goto end;
3934  }
3935 
3936  result = 1;
3937 
3938 end:
3939  if (de_ctx != NULL)
3941  return result;
3942 }
3943 
3944 /**
3945  * \test packet/stream sig
3946  */
3947 static int SigParseTest15(void)
3948 {
3949  int result = 0;
3950 
3952  if (de_ctx == NULL)
3953  goto end;
3954 
3955  Signature *s = NULL;
3956 
3957  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
3958  if (s == NULL) {
3959  printf("sig 1 invalidated: failure");
3960  goto end;
3961  }
3962 
3963  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
3964  printf("sig doesn't have packet flag set\n");
3965  goto end;
3966  }
3967 
3968  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
3969  printf("sig doesn't have stream flag set\n");
3970  goto end;
3971  }
3972 
3973  result = 1;
3974 
3975 end:
3976  if (de_ctx != NULL)
3978  return result;
3979 }
3980 
3981 /**
3982  * \test packet/stream sig
3983  */
3984 static int SigParseTest16(void)
3985 {
3986  int result = 0;
3987 
3989  if (de_ctx == NULL)
3990  goto end;
3991 
3992  Signature *s = NULL;
3993 
3994  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
3995  if (s == NULL) {
3996  printf("sig 1 invalidated: failure");
3997  goto end;
3998  }
3999 
4000  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4001  printf("sig doesn't have packet flag set\n");
4002  goto end;
4003  }
4004 
4005  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4006  printf("sig doesn't have stream flag set\n");
4007  goto end;
4008  }
4009 
4010  result = 1;
4011 
4012 end:
4013  if (de_ctx != NULL)
4015  return result;
4016 }
4017 
4018 /**
4019  * \test packet/stream sig
4020  */
4021 static int SigParseTest17(void)
4022 {
4023  int result = 0;
4024 
4026  if (de_ctx == NULL)
4027  goto end;
4028 
4029  Signature *s = NULL;
4030 
4031  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4032  if (s == NULL) {
4033  printf("sig 1 invalidated: failure");
4034  goto end;
4035  }
4036 
4037  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4038  printf("sig doesn't have packet flag set\n");
4039  goto end;
4040  }
4041 
4042  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4043  printf("sig doesn't have stream flag set\n");
4044  goto end;
4045  }
4046 
4047  result = 1;
4048 
4049 end:
4050  if (de_ctx != NULL)
4052  return result;
4053 }
4054 
4055 /** \test sid value too large. Bug #779 */
4056 static int SigParseTest18 (void)
4057 {
4058  int result = 0;
4059 
4061  if (de_ctx == NULL)
4062  goto end;
4063 
4064  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4065  goto end;
4066 
4067  result = 1;
4068 end:
4069  if (de_ctx != NULL)
4071  return result;
4072 }
4073 
4074 /** \test gid value too large. Related to bug #779 */
4075 static int SigParseTest19 (void)
4076 {
4077  int result = 0;
4078 
4080  if (de_ctx == NULL)
4081  goto end;
4082 
4083  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4084  goto end;
4085 
4086  result = 1;
4087 end:
4088  if (de_ctx != NULL)
4090  return result;
4091 }
4092 
4093 /** \test rev value too large. Related to bug #779 */
4094 static int SigParseTest20 (void)
4095 {
4096  int result = 0;
4097 
4099  if (de_ctx == NULL)
4100  goto end;
4101 
4102  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4103  goto end;
4104 
4105  result = 1;
4106 end:
4107  if (de_ctx != NULL)
4109  return result;
4110 }
4111 
4112 /** \test address parsing */
4113 static int SigParseTest21 (void)
4114 {
4115  int result = 0;
4116 
4118  if (de_ctx == NULL)
4119  goto end;
4120 
4121  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4122  goto end;
4123 
4124  result = 1;
4125 end:
4126  if (de_ctx != NULL)
4128  return result;
4129 }
4130 
4131 /** \test address parsing */
4132 static int SigParseTest22 (void)
4133 {
4134  int result = 0;
4135 
4137  if (de_ctx == NULL)
4138  goto end;
4139 
4140  if (DetectEngineAppendSig(de_ctx, "alert tcp [10.10.10.0/24, !10.10.10.247] any -> [10.10.10.0/24, !10.10.10.247] any (sid:1;)") == NULL)
4141  goto end;
4142 
4143  result = 1;
4144 end:
4145  if (de_ctx != NULL)
4147  return result;
4148 }
4149 
4150 /**
4151  * \test rule ending in carriage return
4152  */
4153 static int SigParseTest23(void)
4154 {
4157 
4158  Signature *s = NULL;
4159 
4160  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4161  FAIL_IF_NULL(s);
4162 
4164  PASS;
4165 }
4166 
4167 /** \test Direction operator validation (invalid) */
4168 static int SigParseBidirecTest06 (void)
4169 {
4170  int result = 1;
4171  Signature *sig = NULL;
4172 
4174  if (de_ctx == NULL)
4175  goto end;
4176 
4177  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4178  if (sig == NULL)
4179  result = 1;
4180 
4181 end:
4182  if (sig != NULL) SigFree(de_ctx, sig);
4183  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4184  return result;
4185 }
4186 
4187 /** \test Direction operator validation (invalid) */
4188 static int SigParseBidirecTest07 (void)
4189 {
4190  int result = 1;
4191  Signature *sig = NULL;
4192 
4194  if (de_ctx == NULL)
4195  goto end;
4196 
4197  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4198  if (sig == NULL)
4199  result = 1;
4200 
4201 end:
4202  if (sig != NULL) SigFree(de_ctx, sig);
4203  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4204  return result;
4205 }
4206 
4207 /** \test Direction operator validation (invalid) */
4208 static int SigParseBidirecTest08 (void)
4209 {
4210  int result = 1;
4211  Signature *sig = NULL;
4212 
4214  if (de_ctx == NULL)
4215  goto end;
4216 
4217  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4218  if (sig == NULL)
4219  result = 1;
4220 
4221 end:
4222  if (sig != NULL) SigFree(de_ctx, sig);
4223  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4224  return result;
4225 }
4226 
4227 /** \test Direction operator validation (invalid) */
4228 static int SigParseBidirecTest09 (void)
4229 {
4230  int result = 1;
4231  Signature *sig = NULL;
4232 
4234  if (de_ctx == NULL)
4235  goto end;
4236 
4237  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4238  if (sig == NULL)
4239  result = 1;
4240 
4241 end:
4242  if (sig != NULL) SigFree(de_ctx, sig);
4243  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4244  return result;
4245 }
4246 
4247 /** \test Direction operator validation (invalid) */
4248 static int SigParseBidirecTest10 (void)
4249 {
4250  int result = 1;
4251  Signature *sig = NULL;
4252 
4254  if (de_ctx == NULL)
4255  goto end;
4256 
4257  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4258  if (sig == NULL)
4259  result = 1;
4260 
4261 end:
4262  if (sig != NULL) SigFree(de_ctx, sig);
4263  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4264  return result;
4265 }
4266 
4267 /** \test Direction operator validation (invalid) */
4268 static int SigParseBidirecTest11 (void)
4269 {
4270  int result = 1;
4271  Signature *sig = NULL;
4272 
4274  if (de_ctx == NULL)
4275  goto end;
4276 
4277  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4278  if (sig == NULL)
4279  result = 1;
4280 
4281 end:
4282  if (sig != NULL) SigFree(de_ctx, sig);
4283  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4284  return result;
4285 }
4286 
4287 /** \test Direction operator validation (invalid) */
4288 static int SigParseBidirecTest12 (void)
4289 {
4290  int result = 1;
4291  Signature *sig = NULL;
4292 
4294  if (de_ctx == NULL)
4295  goto end;
4296 
4297  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4298  if (sig == NULL)
4299  result = 1;
4300 
4301 end:
4302  if (sig != NULL) SigFree(de_ctx, sig);
4303  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4304  return result;
4305 }
4306 
4307 /** \test Direction operator validation (valid) */
4308 static int SigParseBidirecTest13 (void)
4309 {
4310  int result = 1;
4311  Signature *sig = NULL;
4312 
4314  if (de_ctx == NULL)
4315  goto end;
4316 
4317  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4318  if (sig != NULL)
4319  result = 1;
4320 
4321 end:
4322  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4323  return result;
4324 }
4325 
4326 /** \test Direction operator validation (valid) */
4327 static int SigParseBidirecTest14 (void)
4328 {
4329  int result = 1;
4330  Signature *sig = NULL;
4331 
4333  if (de_ctx == NULL)
4334  goto end;
4335 
4336  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4337  if (sig != NULL)
4338  result = 1;
4339 
4340 end:
4341  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4342  return result;
4343 }
4344 
4345 /** \test Ensure that we don't set bidirectional in a
4346  * normal (one direction) Signature
4347  */
4348 static int SigTestBidirec01 (void)
4349 {
4350  Signature *sig = NULL;
4351  int result = 0;
4352 
4354  if (de_ctx == NULL)
4355  goto end;
4356 
4357  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4358  if (sig == NULL)
4359  goto end;
4360  if (sig->next != NULL)
4361  goto end;
4363  goto end;
4364  if (de_ctx->signum != 1)
4365  goto end;
4366 
4367  result = 1;
4368 
4369 end:
4370  if (de_ctx != NULL) {
4374  }
4375  return result;
4376 }
4377 
4378 /** \test Ensure that we set a bidirectional Signature correctly */
4379 static int SigTestBidirec02 (void)
4380 {
4381  int result = 0;
4382  Signature *sig = NULL;
4383  Signature *copy = NULL;
4384 
4386  if (de_ctx == NULL)
4387  goto end;
4388 
4389  de_ctx->flags |= DE_QUIET;
4390 
4391  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4392  if (sig == NULL)
4393  goto end;
4394  if (de_ctx->sig_list != sig)
4395  goto end;
4397  goto end;
4398  if (sig->next == NULL)
4399  goto end;
4400  if (de_ctx->signum != 2)
4401  goto end;
4402  copy = sig->next;
4403  if (copy->next != NULL)
4404  goto end;
4405  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4406  goto end;
4407 
4408  result = 1;
4409 
4410 end:
4411  if (de_ctx != NULL) {
4415  }
4416 
4417  return result;
4418 }
4419 
4420 /** \test Ensure that we set a bidirectional Signature correctly
4421 * and we install it with the rest of the signatures, checking
4422 * also that it match with the correct addr directions
4423 */
4424 static int SigTestBidirec03 (void)
4425 {
4426  int result = 0;
4427  Signature *sig = NULL;
4428  Packet *p = NULL;
4429 
4431  if (de_ctx == NULL)
4432  goto end;
4433 
4434  de_ctx->flags |= DE_QUIET;
4435 
4436  const char *sigs[3];
4437  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4438  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4439  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4440  UTHAppendSigs(de_ctx, sigs, 3);
4441 
4442  /* Checking that bidirectional rules are set correctly */
4443  sig = de_ctx->sig_list;
4444  if (sig == NULL)
4445  goto end;
4446  if (sig->next == NULL)
4447  goto end;
4448  if (sig->next->next == NULL)
4449  goto end;
4450  if (sig->next->next->next == NULL)
4451  goto end;
4452  if (sig->next->next->next->next != NULL)
4453  goto end;
4454  if (de_ctx->signum != 4)
4455  goto end;
4456 
4457  uint8_t rawpkt1_ether[] = {
4458  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4459  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4460  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4461  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4462  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4463  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4464  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4465  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4466  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4467  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4468  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4469  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4470  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4471  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4472  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4473  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4474  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4475  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4476  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4477  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4478  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4479  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4480  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4481  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4482  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4483  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4484  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4485  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4486  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4487  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4488  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4489  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4490  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4491  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4492  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4493  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4494  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4495  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4496  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4497  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4498  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4499  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4500  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4501  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4502  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4503  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4504  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4505  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4506  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4507  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4508  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4509  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4510  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4511  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4512  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4513 
4515  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4516  if (p == NULL) {
4517  SCLogDebug("Error building packet");
4518  goto end;
4519  }
4520  UTHMatchPackets(de_ctx, &p, 1);
4521 
4522  uint32_t sids[3] = {1, 2, 3};
4523  uint32_t results[3] = {1, 1, 1};
4524  result = UTHCheckPacketMatchResults(p, sids, results, 1);
4525 
4526 end:
4527  if (p != NULL) {
4528  PacketRecycle(p);
4529  SCFree(p);
4530  }
4531  FlowShutdown();
4532  return result;
4533 }
4534 
4535 /** \test Ensure that we set a bidirectional Signature correctly
4536 * and we install it with the rest of the signatures, checking
4537 * also that it match with the correct addr directions
4538 */
4539 static int SigTestBidirec04 (void)
4540 {
4541  int result = 0;
4542  Signature *sig = NULL;
4543  Packet *p = NULL;
4544 
4546  if (de_ctx == NULL)
4547  goto end;
4548 
4549  de_ctx->flags |= DE_QUIET;
4550 
4551  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4552  if (sig == NULL)
4553  goto end;
4554  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4555  if (sig == NULL)
4556  goto end;
4557  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4558  goto end;
4559  if (sig->next == NULL)
4560  goto end;
4561  if (sig->next->next == NULL)
4562  goto end;
4563  if (sig->next->next->next != NULL)
4564  goto end;
4565  if (de_ctx->signum != 3)
4566  goto end;
4567 
4568  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4569  if (sig == NULL)
4570  goto end;
4571  if (sig->next == NULL)
4572  goto end;
4573  if (sig->next->next == NULL)
4574  goto end;
4575  if (sig->next->next->next == NULL)
4576  goto end;
4577  if (sig->next->next->next->next != NULL)
4578  goto end;
4579  if (de_ctx->signum != 4)
4580  goto end;
4581 
4582  uint8_t rawpkt1_ether[] = {
4583  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4584  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4585  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4586  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4587  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4588  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4589  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4590  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4591  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4592  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4593  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4594  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4595  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4596  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4597  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4598  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4599  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4600  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4601  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4602  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4603  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4604  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4605  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4606  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4607  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4608  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4609  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4610  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4611  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4612  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4613  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4614  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4615  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4616  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4617  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4618  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4619  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4620  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4621  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4622  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4623  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4624  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4625  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4626  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4627  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4628  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4629  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4630  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4631  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4632  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4633  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4634  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4635  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4636  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4637  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4638 
4639  p = PacketGetFromAlloc();
4640  if (unlikely(p == NULL))
4641  return 0;
4643  ThreadVars th_v;
4644  DetectEngineThreadCtx *det_ctx;
4645 
4646  memset(&th_v, 0, sizeof(th_v));
4647 
4649  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4650  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4651 
4652  /* At this point we have a list of 4 signatures. The last one
4653  is a copy of the second one. If we receive a packet
4654  with source 192.168.1.1 80, all the sids should match */
4655 
4657  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4658 
4659  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4660  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4661  PacketAlertCheck(p, 2) == 1) {
4662  result = 1;
4663  }
4664 
4665  if (p != NULL) {
4666  PacketRecycle(p);
4667  }
4668  FlowShutdown();
4669  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4670 
4671 end:
4672  if (de_ctx != NULL) {
4676  }
4677 
4678  if (p != NULL)
4679  SCFree(p);
4680  return result;
4681 }
4682 
4683 /**
4684  * \test check that we don't allow invalid negation options
4685  */
4686 static int SigParseTestNegation01 (void)
4687 {
4690  de_ctx->flags |= DE_QUIET;
4691  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4692  FAIL_IF_NOT_NULL(s);
4694  PASS;
4695 }
4696 
4697 /**
4698  * \test check that we don't allow invalid negation options
4699  */
4700 static int SigParseTestNegation02 (void)
4701 {
4702  int result = 0;
4704  Signature *s=NULL;
4705 
4707  if (de_ctx == NULL)
4708  goto end;
4709  de_ctx->flags |= DE_QUIET;
4710 
4711  s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)");
4712  if (s != NULL) {
4713  SigFree(de_ctx, s);
4714  goto end;
4715  }
4716 
4717  result = 1;
4718 end:
4719  if (de_ctx != NULL)
4721  return result;
4722 }
4723 /**
4724  * \test check that we don't allow invalid negation options
4725  */
4726 static int SigParseTestNegation03 (void)
4727 {
4728  int result = 0;
4730  Signature *s=NULL;
4731 
4733  if (de_ctx == NULL)
4734  goto end;
4735  de_ctx->flags |= DE_QUIET;
4736 
4737  s = SigInit(de_ctx,"alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
4738  if (s != NULL) {
4739  SigFree(de_ctx, s);
4740  goto end;
4741  }
4742 
4743  result = 1;
4744 end:
4745  if (de_ctx != NULL)
4747  return result;
4748 }
4749 /**
4750  * \test check that we don't allow invalid negation options
4751  */
4752 static int SigParseTestNegation04 (void)
4753 {
4754  int result = 0;
4756  Signature *s=NULL;
4757 
4759  if (de_ctx == NULL)
4760  goto end;
4761  de_ctx->flags |= DE_QUIET;
4762 
4763  s = SigInit(de_ctx,"alert tcp any any -> any [80,!80] (msg:\"SigTest41-03 dst port [80:!80] \"; classtype:misc-activity; sid:410003; rev:1;)");
4764  if (s != NULL) {
4765  SigFree(de_ctx, s);
4766  goto end;
4767  }
4768 
4769  result = 1;
4770 end:
4771  if (de_ctx != NULL)
4773  return result;
4774 }
4775 /**
4776  * \test check that we don't allow invalid negation options
4777  */
4778 static int SigParseTestNegation05 (void)
4779 {
4780  int result = 0;
4782  Signature *s=NULL;
4783 
4785  if (de_ctx == NULL)
4786  goto end;
4787  de_ctx->flags |= DE_QUIET;
4788 
4789  s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.2,!192.168.0.2] any (msg:\"SigTest41-04 dst ip [192.168.0.2,!192.168.0.2] \"; classtype:misc-activity; sid:410004; rev:1;)");
4790  if (s != NULL) {
4791  SigFree(de_ctx, s);
4792  goto end;
4793  }
4794 
4795  result = 1;
4796 end:
4797  if (de_ctx != NULL)
4799  return result;
4800 }
4801 /**
4802  * \test check that we don't allow invalid negation options
4803  */
4804 static int SigParseTestNegation06 (void)
4805 {
4806  int result = 0;
4808  Signature *s=NULL;
4809 
4811  if (de_ctx == NULL)
4812  goto end;
4813  de_ctx->flags |= DE_QUIET;
4814 
4815  s = SigInit(de_ctx,"alert tcp any any -> any [100:1000,!1:20000] (msg:\"SigTest41-05 dst port [100:1000,!1:20000] \"; classtype:misc-activity; sid:410005; rev:1;)");
4816  if (s != NULL) {
4817  SigFree(de_ctx, s);
4818  goto end;
4819  }
4820 
4821  result = 1;
4822 end:
4823  if (de_ctx != NULL)
4825  return result;
4826 }
4827 
4828 /**
4829  * \test check that we don't allow invalid negation options
4830  */
4831 static int SigParseTestNegation07 (void)
4832 {
4835  de_ctx->flags |= DE_QUIET;
4837  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4838  FAIL_IF_NOT_NULL(s);
4840  PASS;
4841 }
4842 
4843 /**
4844  * \test check valid negation bug 1079
4845  */
4846 static int SigParseTestNegation08 (void)
4847 {
4848  int result = 0;
4850  Signature *s=NULL;
4851 
4853  if (de_ctx == NULL)
4854  goto end;
4855  de_ctx->flags |= DE_QUIET;
4856 
4857  s = SigInit(de_ctx,"alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4858  if (s == NULL) {
4859  goto end;
4860  }
4861 
4862  result = 1;
4863 end:
4864  if (de_ctx != NULL)
4866  return result;
4867 }
4868 
4869 /**
4870  * \test mpm
4871  */
4872 static int SigParseTestMpm01 (void)
4873 {
4874  int result = 0;
4875  Signature *sig = NULL;
4876 
4878  if (de_ctx == NULL)
4879  goto end;
4880 
4881  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
4882  if (sig == NULL) {
4883  printf("sig failed to init: ");
4884  goto end;
4885  }
4886 
4887  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4888  printf("sig doesn't have content list: ");
4889  goto end;
4890  }
4891 
4892  result = 1;
4893 end:
4894  if (sig != NULL)
4895  SigFree(de_ctx, sig);
4897  return result;
4898 }
4899 
4900 /**
4901  * \test mpm
4902  */
4903 static int SigParseTestMpm02 (void)
4904 {
4905  int result = 0;
4906  Signature *sig = NULL;
4907 
4909  if (de_ctx == NULL)
4910  goto end;
4911 
4912  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
4913  if (sig == NULL) {
4914  printf("sig failed to init: ");
4915  goto end;
4916  }
4917 
4918  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4919  printf("sig doesn't have content list: ");
4920  goto end;
4921  }
4922 
4923  result = 1;
4924 end:
4925  if (sig != NULL)
4926  SigFree(de_ctx, sig);
4928  return result;
4929 }
4930 
4931 /**
4932  * \test test tls (app layer) rule
4933  */
4934 static int SigParseTestAppLayerTLS01(void)
4935 {
4936  int result = 0;
4938  Signature *s=NULL;
4939 
4941  if (de_ctx == NULL)
4942  goto end;
4943  de_ctx->flags |= DE_QUIET;
4944 
4945  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
4946  if (s == NULL) {
4947  printf("parsing sig failed: ");
4948  goto end;
4949  }
4950 
4951  if (s->alproto == 0) {
4952  printf("alproto not set: ");
4953  goto end;
4954  }
4955 
4956  result = 1;
4957 end:
4958  if (s != NULL)
4959  SigFree(de_ctx, s);
4960  if (de_ctx != NULL)
4962 
4963  return result;
4964 }
4965 
4966 /**
4967  * \test test tls (app layer) rule
4968  */
4969 static int SigParseTestAppLayerTLS02(void)
4970 {
4971  int result = 0;
4973  Signature *s=NULL;
4974 
4976  if (de_ctx == NULL)
4977  goto end;
4978  de_ctx->flags |= DE_QUIET;
4979 
4980  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
4981  if (s == NULL) {
4982  printf("parsing sig failed: ");
4983  goto end;
4984  }
4985 
4986  if (s->alproto == 0) {
4987  printf("alproto not set: ");
4988  goto end;
4989  }
4990 
4991  result = 1;
4992 end:
4993  if (s != NULL)
4994  SigFree(de_ctx, s);
4995  if (de_ctx != NULL)
4997  return result;
4998 }
4999 
5000 /**
5001  * \test test tls (app layer) rule
5002  */
5003 static int SigParseTestAppLayerTLS03(void)
5004 {
5005  int result = 0;
5007  Signature *s=NULL;
5008 
5010  if (de_ctx == NULL)
5011  goto end;
5012  de_ctx->flags |= DE_QUIET;
5013 
5014  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)");
5015  if (s != NULL) {
5016  SigFree(de_ctx, s);
5017  goto end;
5018  }
5019 
5020  result = 1;
5021 end:
5022  if (de_ctx != NULL)
5024  return result;
5025 }
5026 
5027 static int SigParseTestUnbalancedQuotes01(void)
5028 {
5030  Signature *s;
5031 
5034  de_ctx->flags |= DE_QUIET;
5035 
5036  s = SigInit(de_ctx,
5037  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5038  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5039  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5040  FAIL_IF_NOT_NULL(s);
5041 
5042  PASS;
5043 }
5044 
5045 static int SigParseTestContentGtDsize01(void)
5046 {
5049  de_ctx->flags |= DE_QUIET;
5050 
5051  Signature *s = SigInit(de_ctx,
5052  "alert http any any -> any any ("
5053  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5054  "sid:1; rev:1;)");
5055  FAIL_IF_NOT_NULL(s);
5056 
5057  PASS;
5058 }
5059 
5060 static int SigParseTestContentGtDsize02(void)
5061 {
5064  de_ctx->flags |= DE_QUIET;
5065 
5066  Signature *s = SigInit(de_ctx,
5067  "alert http any any -> any any ("
5068  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5069  "sid:1; rev:1;)");
5070  FAIL_IF_NOT_NULL(s);
5071 
5072  PASS;
5073 }
5074 
5075 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5076 {
5077  int cnt = 0;
5078  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5079  if (sid == s->id)
5080  cnt++;
5081  }
5082  return cnt;
5083 }
5084 
5085 static int SigParseBidirWithSameSrcAndDest01(void)
5086 {
5089  de_ctx->flags |= DE_QUIET;
5090 
5091  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5092  FAIL_IF_NULL(s);
5093  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5095 
5096  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5097  FAIL_IF_NULL(s);
5098  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5100 
5102  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5103  FAIL_IF_NULL(s);
5104  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5106 
5108  PASS;
5109 }
5110 
5111 static int SigParseBidirWithSameSrcAndDest02(void)
5112 {
5115  de_ctx->flags |= DE_QUIET;
5116 
5117  // Source is a subset of destination
5119  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5120  FAIL_IF_NULL(s);
5121  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5123 
5124  // Source is a subset of destination
5126  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5127  FAIL_IF_NULL(s);
5128  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5130 
5131  // Source intersects with destination
5133  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5134  FAIL_IF_NULL(s);
5135  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5137 
5138  // mix in negation, these are the same
5140  de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)");
5141  FAIL_IF_NULL(s);
5142  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5144 
5145  // mix in negation, these are not the same
5147  de_ctx, "alert tcp [1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:5;)");
5148  FAIL_IF_NULL(s);
5149  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5151 
5153  PASS;
5154 }
5155 
5156 static int SigParseTestActionReject(void)
5157 {
5160 
5162  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5163 #ifdef HAVE_LIBNET11
5164  FAIL_IF_NULL(sig);
5166 #else
5167  FAIL_IF_NOT_NULL(sig);
5168 #endif
5169 
5171  PASS;
5172 }
5173 
5174 static int SigParseTestActionDrop(void)
5175 {
5178 
5180  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5181  FAIL_IF_NULL(sig);
5182  FAIL_IF_NOT(sig->action & ACTION_DROP);
5183 
5185  PASS;
5186 }
5187 
5188 static int SigSetMultiAppProto(void)
5189 {
5190  Signature *s = SigAlloc();
5191  FAIL_IF_NULL(s);
5192 
5193  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5194  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5195 
5196  // check intersection gives multiple entries
5197  alprotos[0] = 3;
5198  alprotos[1] = 2;
5199  alprotos[2] = ALPROTO_UNKNOWN;
5200  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5201  FAIL_IF(s->init_data->alprotos[0] != 3);
5202  FAIL_IF(s->init_data->alprotos[1] != 2);
5204 
5205  // check single after multiple
5208  FAIL_IF(s->alproto != 3);
5209  alprotos[0] = 4;
5210  alprotos[1] = 3;
5211  alprotos[2] = ALPROTO_UNKNOWN;
5212  // check multiple containing singleton
5213  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5214  FAIL_IF(s->alproto != 3);
5215 
5216  // reset
5217  s->alproto = ALPROTO_UNKNOWN;
5218  alprotos[0] = 1;
5219  alprotos[1] = 2;
5220  alprotos[2] = 3;
5221  alprotos[3] = ALPROTO_UNKNOWN;
5222  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5223  // fail if set single not in multiple
5225 
5227  s->alproto = ALPROTO_UNKNOWN;
5228  alprotos[0] = 1;
5229  alprotos[1] = 2;
5230  alprotos[2] = 3;
5231  alprotos[3] = ALPROTO_UNKNOWN;
5232  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5233  alprotos[0] = 4;
5234  alprotos[1] = 5;
5235  alprotos[2] = ALPROTO_UNKNOWN;
5236  // fail if multiple do not have intersection
5237  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5238 
5240  s->alproto = ALPROTO_UNKNOWN;
5241  alprotos[0] = 1;
5242  alprotos[1] = 2;
5243  alprotos[2] = 3;
5244  alprotos[3] = ALPROTO_UNKNOWN;
5245  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5246  alprotos[0] = 3;
5247  alprotos[1] = 4;
5248  alprotos[2] = 5;
5249  alprotos[3] = ALPROTO_UNKNOWN;
5250  // check multiple intersect to singleton
5251  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5252  FAIL_IF(s->alproto != 3);
5253  alprotos[0] = 5;
5254  alprotos[1] = 4;
5255  alprotos[2] = ALPROTO_UNKNOWN;
5256  // fail if multiple do not belong to singleton
5257  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5258 
5259  SigFree(NULL, s);
5260  PASS;
5261 }
5262 
5263 static int DetectSetupDirection01(void)
5264 {
5265  Signature *s = SigAlloc();
5266  FAIL_IF_NULL(s);
5267  // Basic case : ok
5268  char *str = (char *)"to_client";
5269  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5270  SigFree(NULL, s);
5271  PASS;
5272 }
5273 
5274 static int DetectSetupDirection02(void)
5275 {
5276  Signature *s = SigAlloc();
5277  FAIL_IF_NULL(s);
5278  char *str = (char *)"to_server";
5279  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5280  // ok so far
5281  str = (char *)"to_client";
5282  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5283  // fails because we cannot have both to_client and to_server for same signature
5284  SigFree(NULL, s);
5285  PASS;
5286 }
5287 
5288 static int DetectSetupDirection03(void)
5289 {
5290  Signature *s = SigAlloc();
5291  FAIL_IF_NULL(s);
5292  char *str = (char *)"to_client , something";
5293  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5294  FAIL_IF(strcmp(str, "something") != 0);
5295  str = (char *)"to_client,something";
5296  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5297  FAIL_IF(strcmp(str, "something") != 0);
5298  SigFree(NULL, s);
5299  PASS;
5300 }
5301 
5302 static int DetectSetupDirection04(void)
5303 {
5304  Signature *s = SigAlloc();
5305  FAIL_IF_NULL(s);
5306  // invalid case
5307  char *str = (char *)"to_client_toto";
5308  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5309  // test we do not change the string pointer if only_dir is false
5310  str = (char *)"to_client_toto";
5311  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5312  FAIL_IF(strcmp(str, "to_client_toto") != 0);
5313  str = (char *)"to_client,something";
5314  // fails because we call with only_dir=true
5315  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5316  SigFree(NULL, s);
5317  PASS;
5318 }
5319 
5320 #endif /* UNITTESTS */
5321 
5322 #ifdef UNITTESTS
5323 void DetectParseRegisterTests (void);
5324 #include "tests/detect-parse.c"
5325 #endif
5326 
5328 {
5329 #ifdef UNITTESTS
5331 
5332  UtRegisterTest("SigParseTest01", SigParseTest01);
5333  UtRegisterTest("SigParseTest02", SigParseTest02);
5334  UtRegisterTest("SigParseTest03", SigParseTest03);
5335  UtRegisterTest("SigParseTest04", SigParseTest04);
5336  UtRegisterTest("SigParseTest05", SigParseTest05);
5337  UtRegisterTest("SigParseTest06", SigParseTest06);
5338  UtRegisterTest("SigParseTest07", SigParseTest07);
5339  UtRegisterTest("SigParseTest08", SigParseTest08);
5340  UtRegisterTest("SigParseTest09", SigParseTest09);
5341  UtRegisterTest("SigParseTest10", SigParseTest10);
5342  UtRegisterTest("SigParseTest11", SigParseTest11);
5343  UtRegisterTest("SigParseTest12", SigParseTest12);
5344  UtRegisterTest("SigParseTest13", SigParseTest13);
5345  UtRegisterTest("SigParseTest14", SigParseTest14);
5346  UtRegisterTest("SigParseTest15", SigParseTest15);
5347  UtRegisterTest("SigParseTest16", SigParseTest16);
5348  UtRegisterTest("SigParseTest17", SigParseTest17);
5349  UtRegisterTest("SigParseTest18", SigParseTest18);
5350  UtRegisterTest("SigParseTest19", SigParseTest19);
5351  UtRegisterTest("SigParseTest20", SigParseTest20);
5352  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5353  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5354  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5355 
5356  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5357  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5358  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5359  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5360  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5361  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5362  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5363  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5364  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5365  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5366  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5367  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5368  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5369  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5370  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5371  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5372  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5373  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5374  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5375  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5376  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5377  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5378  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5379  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5380  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5381  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5382  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5383 
5384  UtRegisterTest("SigParseTestContentGtDsize01",
5385  SigParseTestContentGtDsize01);
5386  UtRegisterTest("SigParseTestContentGtDsize02",
5387  SigParseTestContentGtDsize02);
5388 
5389  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5390  SigParseBidirWithSameSrcAndDest01);
5391  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5392  SigParseBidirWithSameSrcAndDest02);
5393  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5394  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5395 
5396  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5397 
5398  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5399  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5400  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5401  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5402 
5403 #endif /* UNITTESTS */
5404 }
DetectAddressListsAreEqual
bool DetectAddressListsAreEqual(DetectAddress *list1, DetectAddress *list2)
Checks if two address group lists are equal.
Definition: detect-engine-address.c:349
DetectIPProtoRemoveAllSMs
void DetectIPProtoRemoveAllSMs(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-ipproto.c:430
SignatureParser_
Definition: detect-parse.c:101
SignatureInitData_::max_content_list_id
uint32_t max_content_list_id
Definition: detect.h:642
host.h
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:648
DetectPortCmp
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
Definition: detect-engine-port.c:497
DetectEngineAppInspectionEngine_
Definition: detect.h:417
SC_MATCH_LIMIT_DEFAULT
#define SC_MATCH_LIMIT_DEFAULT
Definition: detect-pcre.h:43
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
SignatureInitDataBuffer_::head
SigMatch * head
Definition: detect.h:535
SigMatch_::prev
struct SigMatch_ * prev
Definition: detect.h:362
detect-content.h
SignatureInitDataBuffer_::sm_init
bool sm_init
Definition: detect.h:527
len
uint8_t len
Definition: app-layer-dnp3.h:2
ts
uint64_t ts
Definition: source-erf-file.c:55
DetectMetadataHead::json_str
char * json_str
Definition: detect-metadata.h:40
DetectMetadataFree
void DetectMetadataFree(DetectMetadata *mdata)
Free a Metadata object.
Definition: detect-metadata.c:60
AppLayerHtpNeedFileInspection
void AppLayerHtpNeedFileInspection(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request file...
Definition: app-layer-htp.c:574
detect-engine.h
SigMatchRemoveSMFromList
void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
Definition: detect-parse.c:487
detect-app-layer-protocol.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
DE_HAS_FIREWALL
#define DE_HAS_FIREWALL
Definition: detect.h:331
DetectParseRegisterTests
void DetectParseRegisterTests(void)
this function registers unit tests for DetectParse
Definition: detect-parse.c:146
SignatureInitData_::smlists
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition: detect.h:631
SignatureHook_
Definition: detect.h:560
DetectParseDupSigHashInit
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3071
SignatureInitData_::list_set
bool list_set
Definition: detect.h:618
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:700
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:734
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
SIG_TYPE_APP_TX
@ SIG_TYPE_APP_TX
Definition: detect.h:77
SigMatchFree
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
free a SigMatch
Definition: detect-parse.c:288
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1409
SigDuplWrapper_
Registration table for file handlers.
Definition: detect-parse.c:93
AppLayerParserGetStateNameById
const char * AppLayerParserGetStateNameById(uint8_t ipproto, AppProto alproto, const int id, const uint8_t direction)
Definition: app-layer-parser.c:1616
SignatureHook_::sm_list
int sm_list
Definition: detect.h:562
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:442
SignatureParser_::sp
char sp[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:107
DetectPortListsAreEqual
bool DetectPortListsAreEqual(DetectPort *list1, DetectPort *list2)
Checks if two port group lists are equal.
Definition: detect-engine-port.c:638
SIGMATCH_STRICT_PARSING
#define SIGMATCH_STRICT_PARSING
Definition: detect.h:1640
DetectParseRegex
Definition: detect-parse.h:93
SIG_DIREC_NORMAL
@ SIG_DIREC_NORMAL
Definition: detect-parse.h:40
SignatureParser_::action
char action[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:102
SigTableElmt_::name
const char * name
Definition: detect.h:1419
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:633
DetectEngineBufferRunSetupCallback
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
Definition: detect-engine.c:1460
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:112
SIG_FLAG_INIT_FLOW
#define SIG_FLAG_INIT_FLOW
Definition: detect.h:292
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
ACTION_PASS
#define ACTION_PASS
Definition: action-globals.h:34
ACTION_REJECT
#define ACTION_REJECT
Definition: action-globals.h:31
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SigDuplWrapper
struct SigDuplWrapper_ SigDuplWrapper
Registration table for file handlers.
Signature_::app_progress_hook
uint8_t app_progress_hook
Definition: detect.h:694
AppLayerGetProtoByName
AppProto AppLayerGetProtoByName(const char *alproto_name)
Given a protocol string, returns the corresponding internal protocol id.
Definition: app-layer.c:1001
DetectSignatureSetMultiAppProto
int DetectSignatureSetMultiAppProto(Signature *s, const AppProto *alprotos)
this function is used to set multiple possible app-layer protos
Definition: detect-parse.c:2134
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:69
DetectAddress_
address structure for use in the detection engine.
Definition: detect.h:168
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:614
SignatureInitData_::src_contains_negation
bool src_contains_negation
Definition: detect.h:590
DetectEngineCtx_::sigerror_silent
bool sigerror_silent
Definition: detect.h:1013
DetectParseRegex::context
pcre2_match_context * context
Definition: detect-parse.h:95
Signature_::alproto
AppProto alproto
Definition: detect.h:662
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:645
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:270
SIG_FLAG_INIT_FILEDATA
#define SIG_FLAG_INIT_FILEDATA
Definition: detect.h:300
detect-isdataat.h
DetectBsizeValidateContentCallback
bool DetectBsizeValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-bsize.c:49
SIGMATCH_QUOTES_OPTIONAL
#define SIGMATCH_QUOTES_OPTIONAL
Definition: detect.h:1624
IPOnlySigParseAddress
int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag)
Parses an address group sent as a character string and updates the IPOnlyCIDRItem lists src and dst o...
Definition: detect-engine-iponly.c:867
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:368
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:86
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:141
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:369
detect-bsize.h
URL
#define URL
action-globals.h
PacketRecycle
void PacketRecycle(Packet *p)
Definition: packet.c:145
DetectReferenceFree
void DetectReferenceFree(DetectReference *ref)
Free a Reference object.
Definition: detect-reference.c:76
DetectSetupPCRE2
DetectParseRegex * DetectSetupPCRE2(const char *parse_str, int opts)
Definition: detect-parse.c:3468
SignatureParser_::src
char src[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:105
DETECT_SM_LIST_THRESHOLD
@ DETECT_SM_LIST_THRESHOLD
Definition: detect.h:133
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:40
SigTableElmt_::flags
uint16_t flags
Definition: detect.h:1413
ctx
struct Thresholds ctx
AppLayerParserSupportsFiles
bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto)
Definition: app-layer-parser.c:1172
SignatureHook_::pkt
struct SignatureHook_::@85::@87 pkt
SigDuplWrapper_::s_prev
Signature * s_prev
Definition: detect-parse.c:97
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:919
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:28
DETECT_CONTENT_RAWBYTES
#define DETECT_CONTENT_RAWBYTES
Definition: detect-content.h:38
AppLayerParserGetStateProgressCompletionStatus
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:1115
CASE_CODE_STRING
#define CASE_CODE_STRING(E, S)
TransformData_::options
void * options
Definition: detect.h:389
DETECT_STREAM_SIZE
@ DETECT_STREAM_SIZE
Definition: detect-engine-register.h:119
SIGNATURE_HOOK_PKT_NOT_SET
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition: detect.h:540
SIG_FLAG_INIT_FORCE_TOCLIENT
#define SIG_FLAG_INIT_FORCE_TOCLIENT
Definition: detect.h:301
AppLayerParserGetStateIdByName
int AppLayerParserGetStateIdByName(uint8_t ipproto, AppProto alproto, const char *name, const uint8_t direction)
Definition: app-layer-parser.c:1601
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2624
AppLayerProtoDetectSupportedIpprotos
void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
Definition: app-layer-detect-proto.c:2048
detect-lua.h
SIG_DIREC_SWITCHED
@ SIG_DIREC_SWITCHED
Definition: detect-parse.h:41
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1286
UTHCheckPacketMatchResults
int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs)
UTHCheckPacketMatches: function to check if a packet match some sids.
Definition: util-unittest-helper.c:611
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:242
ACTION_SCOPE_FLOW
@ ACTION_SCOPE_FLOW
Definition: action-globals.h:45
SIG_FLAG_REQUIRE_STREAM
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:255
SIG_FLAG_TXBOTHDIR
#define SIG_FLAG_TXBOTHDIR
Definition: detect.h:250
MIN
#define MIN(x, y)
Definition: suricata-common.h:408
DetectParseRegex::regex
pcre2_code * regex
Definition: detect-parse.h:94
DetectKeywordId
DetectKeywordId
Definition: detect-engine-register.h:27
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
DetectGetLastSMByListPtr
SigMatch * DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list,...)
Returns the sm with the largest index (added last) from the list passed to us as a pointer.
Definition: detect-parse.c:626
DetectRegisterAppLayerHookLists
void DetectRegisterAppLayerHookLists(void)
register app hooks as generic lists
Definition: detect-parse.c:1152
DetectEngineCtx_::sigerror_requires
bool sigerror_requires
Definition: detect.h:1017
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2349
FILE_SIG_NEED_FILENAME
#define FILE_SIG_NEED_FILENAME
Definition: detect.h:321
SignatureInitDataBuffer_::multi_capable
bool multi_capable
Definition: detect.h:530
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:720
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:1051
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:597
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3088
SIG_DIREC_DST
@ SIG_DIREC_DST
Definition: detect-parse.h:48
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3392
DetectBufferType_
Definition: detect.h:450
proto
uint8_t proto
Definition: decode-template.h:0
DetectContentData_
Definition: detect-content.h:93
DetectEngineCtx_::sigerror_ok
bool sigerror_ok
Definition: detect.h:1014
DetectPcreData_::flags
uint16_t flags
Definition: detect-pcre.h:51
SignatureParser_::dp
char dp[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:108
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:55
SCDetectSignatureSetAppProto
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2212
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect.h:1642
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:245
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:272
MAX
#define MAX(x, y)
Definition: suricata-common.h:412
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:241
SigTableElmt_
element in sigmatch type table.
Definition: detect.h:1382
SigMatchData_
Data needed for Match()
Definition: detect.h:366
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1404
DetectFlowSetupImplicit
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
Definition: detect-flow.c:337
detect-pcre.h
SigMatchData_::type
uint16_t type
Definition: detect.h:367
DetectMatchAddressIPv4_::ip
uint32_t ip
Definition: detect.h:190
DetectContentPMATCHValidateCallback
bool DetectContentPMATCHValidateCallback(const Signature *s)
Definition: detect-content.c:456
DetectParseRegexAddToFreeList
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
add regex and/or study to at exit free list
Definition: detect-parse.c:3428
util-unittest.h
DetectParseRegex::next
struct DetectParseRegex * next
Definition: detect-parse.h:96
FIREWALL_TABLE_APP_FILTER
@ FIREWALL_TABLE_APP_FILTER
Definition: detect.h:554
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
DetectPortPrint
void DetectPortPrint(DetectPort *dp)
Helper function that print the DetectPort info.
Definition: detect-engine-port.c:590
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:249
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1256
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
HashListTableAdd
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:114
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
DETECT_PREFILTER_AUTO
@ DETECT_PREFILTER_AUTO
Definition: detect.h:886
SIG_FLAG_FIREWALL
#define SIG_FLAG_FIREWALL
Definition: detect.h:246
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
detect-reference.h
Signature_::gid
uint32_t gid
Definition: detect.h:703
DetectMatchAddressIPv6_::ip2
uint32_t ip2[4]
Definition: detect.h:196
SIGNATURE_HOOK_TYPE_APP
@ SIGNATURE_HOOK_TYPE_APP
Definition: detect.h:548
Signature_::next
struct Signature_ * next
Definition: detect.h:739
ACTION_REJECT_DST
#define ACTION_REJECT_DST
Definition: action-globals.h:32
DetectParseFreeRegexes
void DetectParseFreeRegexes(void)
Definition: detect-parse.c:3412
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:425
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1628
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:546
UTHMatchPackets
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
Definition: util-unittest-helper.c:718
app-layer-detect-proto.h
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:127
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:271
app-layer-htp.h
DetectPortParse
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
Definition: detect-engine-port.c:1182
detect-app-layer-event.h
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:72
HashListTableInit
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
Signature_::addr_src_match4
DetectMatchAddressIPv4 * addr_src_match4
Definition: detect.h:697
SigParseRegisterTests
void SigParseRegisterTests(void)
Definition: detect-parse.c:5327
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
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_DISTANCE
Definition: detect-content.h:30
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
SIG_FLAG_INIT_BIDIREC
#define SIG_FLAG_INIT_BIDIREC
Definition: detect.h:293
DetectProtoParse
int DetectProtoParse(DetectProto *dp, const char *str)
Parses a protocol sent as a string.
Definition: detect-engine-proto.c:56
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:29
SignatureInitData_::buffers_size
uint32_t buffers_size
Definition: detect.h:638
SigFree
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-parse.c:2040
DetectEngineThreadCtx_
Definition: detect.h:1211
DetectGetLastSMFromMpmLists
SigMatch * DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
get the last SigMatch from lists that support MPM.
Definition: detect-parse.c:527
FIREWALL_TABLE_PACKET_TD
@ FIREWALL_TABLE_PACKET_TD
Definition: detect.h:553
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:66
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:612
SIGMATCH_SUPPORT_DIR
#define SIGMATCH_SUPPORT_DIR
Definition: detect.h:1644
g_skip_prefilter
int g_skip_prefilter
Definition: detect-engine-mpm.c:1075
SignatureInitData_::src
const DetectAddressHead * src
Definition: detect.h:628
DETECT_SM_LIST_BASE64_DATA
@ DETECT_SM_LIST_BASE64_DATA
Definition: detect.h:124
detect-engine-file.h
SignatureInitData_::mpm_sm_list
int mpm_sm_list
Definition: detect.h:610
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:528
SignatureInitData_::cidr_dst
IPOnlyCIDRItem * cidr_dst
Definition: detect.h:607
PORT_EQ
@ PORT_EQ
Definition: detect.h:208
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3518
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
SignatureInitData_::list
int list
Definition: detect.h:617
SCEnter
#define SCEnter(...)
Definition: util-debug.h:272
detect-engine-mpm.h
Signature_::references
DetectReference * references
Definition: detect.h:730
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
CASE_CODE
#define CASE_CODE(E)
Definition: detect-parse.c:129
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineCtx_::sm_types_prefilter
bool * sm_types_prefilter
Definition: detect.h:1098
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:2348
SignatureHookPkt
SignatureHookPkt
Definition: detect.h:539
pkt-var.h
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3350
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:361
detect-engine-port.h
SigDuplWrapper_::s
Signature * s
Definition: detect-parse.c:95
FIREWALL_TABLE_PACKET_FILTER
@ FIREWALL_TABLE_PACKET_FILTER
Definition: detect.h:552
SigMatchStrictEnabled
bool SigMatchStrictEnabled(const enum DetectKeywordId id)
Definition: detect-parse.c:336
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:117
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:250
SC_Pcre2SubstringGet
int SC_Pcre2SubstringGet(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
Definition: detect-parse.c:3506
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:2996
DetectPort_
Port structure for detection engine.
Definition: detect.h:220
SigTableElmt_::alternative
uint16_t alternative
Definition: detect.h:1417
SignatureInitData_::cidr_src
IPOnlyCIDRItem * cidr_src
Definition: detect.h:607
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:360
DetectReference_
Signature reference list.
Definition: detect-reference.h:30
SignatureInitData_::hook
SignatureHook hook
Definition: detect.h:579
SIGNATURE_HOOK_TYPE_NOT_SET
@ SIGNATURE_HOOK_TYPE_NOT_SET
Definition: detect.h:546
SC_MATCH_LIMIT_RECURSION_DEFAULT
#define SC_MATCH_LIMIT_RECURSION_DEFAULT
Definition: detect-pcre.h:44
DetectProto_::proto
uint8_t proto[256/8]
Definition: detect-engine-proto.h:36
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2201
Signature_::action
uint8_t action
Definition: detect.h:672
util-profiling.h
util-rule-vars.h
SignatureHookType
SignatureHookType
Definition: detect.h:545
DetectMetadataHead::list
DetectMetadata * list
Definition: detect-metadata.h:41
SCReturn
#define SCReturn
Definition: util-debug.h:274
Signature_::flags
uint32_t flags
Definition: detect.h:658
sc_set_caps
bool sc_set_caps
Definition: suricata.c:188
SignatureHook_::app
struct SignatureHook_::@85::@86 app
DetectEngineContentModifierBufferSetup
int DetectEngineContentModifierBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg, int sm_type, int sm_list, AppProto alproto)
Definition: detect-parse.c:146
ACTION_ALERT
#define ACTION_ALERT
Definition: action-globals.h:29
Packet_
Definition: decode.h:492
detect-engine-build.h
type
uint16_t type
Definition: decode-vlan.c:106
conf-yaml-loader.h
ACTION_SCOPE_TX
@ ACTION_SCOPE_TX
Definition: action-globals.h:47
detect-engine-alert.h
conf.h
DetectBufferType_::packet
bool packet
Definition: detect.h:456
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DETECT_MAX_RULE_SIZE
#define DETECT_MAX_RULE_SIZE
Definition: detect.h:46
SignatureParser_::direction
char direction[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:104
detect-ipproto.h
DetectEngineBufferTypeGetById
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1276
SignatureInitDataBufferCheckExpand
int SignatureInitDataBufferCheckExpand(Signature *s)
check if buffers array still has space left, expand if not
Definition: detect-parse.c:1900
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect.h:1632
DetectBufferType_::name
char name[64]
Definition: detect.h:451
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:736
name
const char * name
Definition: tm-threads.c:2123
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:288
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SignatureInitData_::negated
bool negated
Definition: detect.h:586
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1384
SignatureInitData_
Definition: detect.h:578
HashListTable_
Definition: util-hashlist.h:37
DetectGetLastSM
SigMatch * DetectGetLastSM(const Signature *s)
Returns the sm with the largest index (added latest) from this sig.
Definition: detect-parse.c:709
SignatureInitData_::dst_contains_negation
bool dst_contains_negation
Definition: detect.h:591
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:393
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
Signature_::addr_dst_match6_cnt
uint16_t addr_dst_match6_cnt
Definition: detect.h:684
DetectReference_::next
struct DetectReference_ * next
Definition: detect-reference.h:43
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:274
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:225
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:71
SIG_ALPROTO_MAX
#define SIG_ALPROTO_MAX
Definition: detect.h:576
Signature_::sp
DetectPort * sp
Definition: detect.h:708
DetectMetadata_
Signature metadata list.
Definition: detect-metadata.h:30
DetectAbsentValidateContentCallback
bool DetectAbsentValidateContentCallback(Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-isdataat.c:118
IPOnlyCIDRListFree
void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead)
This function free a IPOnlyCIDRItem list.
Definition: detect-engine-iponly.c:482
Flow_::next
struct Flow_ * next
Definition: flow.h:396
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2130
DetectEngineBufferTypeSupportsMpmGetById
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1432
DetectEngineCtx_::dup_sig_hash_table
HashListTable * dup_sig_hash_table
Definition: detect.h:955
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:418
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:352
DETECT_SM_LIST_NOTSET
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:144
ACTION_REJECT_BOTH
#define ACTION_REJECT_BOTH
Definition: action-globals.h:33
SigTableApplyStrictCommandLineOption
void SigTableApplyStrictCommandLineOption(const char *str)
Definition: detect-parse.c:344
SignatureInitDataBuffer_::tail
SigMatch * tail
Definition: detect.h:536
DetectAddressHead_::ipv6_head
DetectAddress * ipv6_head
Definition: detect.h:185
DetectBufferType_::frame
bool frame
Definition: detect.h:457
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:37
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3338
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
SigMatchSilentErrorEnabled
bool SigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, const enum DetectKeywordId id)
Definition: detect-parse.c:330
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
SignatureParser_::opts
char opts[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:109
flags
uint8_t flags
Definition: decode-gre.h:0
Signature_::proto
DetectProto proto
Definition: detect.h:676
SigTableElmt_::alias
const char * alias
Definition: detect.h:1420
suricata-common.h
SigMatch_::idx
uint16_t idx
Definition: detect.h:359
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:243
SigMatch_::type
uint16_t type
Definition: detect.h:358
SignatureParser_::protocol
char protocol[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:103
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
Signature_::file_flags
uint8_t file_flags
Definition: detect.h:673
SIG_FLAG_INIT_FORCE_TOSERVER
#define SIG_FLAG_INIT_FORCE_TOSERVER
Definition: detect.h:302
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:690
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:679
packet.h
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SignatureInitData_::curbuf
SignatureInitDataBuffer * curbuf
Definition: detect.h:639
SignatureHook_::type
enum SignatureHookType type
Definition: detect.h:561
DETECT_PROTO_ONLY_STREAM
#define DETECT_PROTO_ONLY_STREAM
Definition: detect-engine-proto.h:30
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3576
SIG_FLAG_INIT_PACKET
#define SIG_FLAG_INIT_PACKET
Definition: detect.h:291
SignatureParser_::dst
char dst[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:106
DetectListToString
const char * DetectListToString(int list)
Definition: detect-parse.c:130
DetectMatchAddressIPv4_::ip2
uint32_t ip2
Definition: detect.h:191
Signature_::rev
uint32_t rev
Definition: detect.h:704
SignatureInitData_::sm_cnt
uint16_t sm_cnt
Definition: detect.h:582
util-classification-config.h
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
FatalError
#define FatalError(...)
Definition: util-debug.h:503
SIGNATURE_HOOK_TYPE_PKT
@ SIGNATURE_HOOK_TYPE_PKT
Definition: detect.h:547
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:928
DetectEngineInspectGenericList
uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Definition: detect-engine.c:1933
DetectEngineAppInspectionEngineSignatureFree
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
free app inspect engines for a signature
Definition: detect-engine.c:907
ACTION_CONFIG
#define ACTION_CONFIG
Definition: action-globals.h:35
DETECT_SM_LIST_TMATCH
@ DETECT_SM_LIST_TMATCH
Definition: detect.h:129
TransformData_::transform
int transform
Definition: detect.h:388
SignatureParser
struct SignatureParser_ SignatureParser
Signature_::prio
int prio
Definition: detect.h:705
DetectEngineCtx_::sm_types_silent_error
bool * sm_types_silent_error
Definition: detect.h:1099
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:427
DetectMatchAddressIPv6_::ip
uint32_t ip[4]
Definition: detect.h:195
SIGMATCH_OPTIONAL_OPT
#define SIGMATCH_OPTIONAL_OPT
Definition: detect.h:1621
SignatureInitDataBuffer_::only_ts
bool only_ts
Definition: detect.h:533
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:232
detect-flow.h
Signature_::addr_src_match6_cnt
uint16_t addr_src_match6_cnt
Definition: detect.h:685
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SIG_DIREC_SRC
@ SIG_DIREC_SRC
Definition: detect-parse.h:47
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:636
DetectEngineCtx_::app_inspect_engines
DetectEngineAppInspectionEngine * app_inspect_engines
Definition: detect.h:1074
SignatureInitData_::dst
const DetectAddressHead * dst
Definition: detect.h:628
SignatureInitData_::firewall_rule
bool firewall_rule
Definition: detect.h:653
SIGNATURE_HOOK_PKT_ALL
@ SIGNATURE_HOOK_PKT_ALL
Definition: detect.h:542
Signature_::dp
DetectPort * dp
Definition: detect.h:708
str
#define str(s)
Definition: suricata-common.h:308
detect-http-method.h
Signature_::metadata
DetectMetadataHead * metadata
Definition: detect.h:732
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:262
DETECT_TBLSIZE
int DETECT_TBLSIZE
Definition: detect-engine-register.c:290
Signature_::iid
SigIntId iid
Definition: detect.h:669
head
Flow * head
Definition: flow-hash.h:1
SigMatchListSMBelongsTo
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:763
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SCNtohl
#define SCNtohl(x)
Definition: suricata-common.h:430
SIGMATCH_INFO_DEPRECATED
#define SIGMATCH_INFO_DEPRECATED
Definition: detect.h:1638
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:954
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1406
Signature_::addr_dst_match6
DetectMatchAddressIPv6 * addr_dst_match6
Definition: detect.h:699
Signature_::id
uint32_t id
Definition: detect.h:702
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
DetectMetadata_::next
struct DetectMetadata_ * next
Definition: detect-metadata.h:36
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
detect-engine-iponly.h
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
SignatureInitDataBuffer_::id
uint32_t id
Definition: detect.h:526
Signature_
Signature container.
Definition: detect.h:657
SigMatch_
a single match condition for a signature
Definition: detect.h:357
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:135
ALPROTO_HTTP
@ ALPROTO_HTTP
Definition: app-layer-protos.h:76
DETECT_PROTO_ONLY_PKT
#define DETECT_PROTO_ONLY_PKT
Definition: detect-engine-proto.h:29
UTHBuildPacketFromEth
Packet * UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes.
Definition: util-unittest-helper.c:382
DetectMatchAddressIPv6_
Definition: detect.h:194
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
ALPROTO_FAILED
@ ALPROTO_FAILED
Definition: app-layer-protos.h:33
DetectMatchAddressIPv4_
Definition: detect.h:189
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2585
DETECT_PCRE_RELATIVE_NEXT
#define DETECT_PCRE_RELATIVE_NEXT
Definition: detect-pcre.h:34
SignatureInitData_::has_possible_prefilter
bool has_possible_prefilter
Definition: detect.h:594
SignatureSetType
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-build.c:1654
app-layer-protos.h
SC_Pcre2SubstringCopy
int SC_Pcre2SubstringCopy(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
Definition: detect-parse.c:3494
ACTION_ACCEPT
#define ACTION_ACCEPT
Definition: action-globals.h:36
FirewallTable
FirewallTable
Definition: detect.h:551
SIGNATURE_HOOK_PKT_FLOW_START
@ SIGNATURE_HOOK_PKT_FLOW_START
Definition: detect.h:541
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:394
SCClassConfGenerateValidDummyClassConfigFD01
FILE * SCClassConfGenerateValidDummyClassConfigFD01(void)
Creates a dummy classification file, with all valid Classtypes, for testing purposes.
Definition: util-classification-config.c:587
DetectPcreData_
Definition: detect-pcre.h:47
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:419
DetectParseAddress
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
Definition: detect-engine-address.c:1434
Signature_::firewall_table
uint8_t firewall_table
Definition: detect.h:691
SignatureInitDataBuffer_::only_tc
bool only_tc
Definition: detect.h:532
detect-uricontent.h
DETECT_DEFAULT_PRIO
#define DETECT_DEFAULT_PRIO
Definition: detect.h:52
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect.h:1611
DetectEngineBufferRunValidateCallback
bool DetectEngineBufferRunValidateCallback(const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
Definition: detect-engine.c:1479
DetectEngineCtx_::sigerror
const char * sigerror
Definition: detect.h:1012
DetectAppLayerInspectEngineRegister
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData)
Registers an app inspection engine.
Definition: detect-engine.c:249
DetectParseFreeRegex
void DetectParseFreeRegex(DetectParseRegex *r)
Definition: detect-parse.c:3402
DetectGetLastSMFromLists
SigMatch * DetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us.
Definition: detect-parse.c:564
id
uint32_t id
Definition: detect-flowbits.c:933
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:921
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:1920
SignatureInitData_::transforms
DetectEngineTransforms transforms
Definition: detect.h:620
UTHAppendSigs
int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
UTHAppendSigs: Add sigs to the detection_engine checking for errors.
Definition: util-unittest-helper.c:644
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
FIREWALL_TABLE_APP_TD
@ FIREWALL_TABLE_APP_TD
Definition: detect.h:555
Signature_::addr_dst_match4
DetectMatchAddressIPv4 * addr_dst_match4
Definition: detect.h:696
DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_REPLACE
Definition: detect-content.h:51
Signature_::msg
char * msg
Definition: detect.h:725
flow.h
SignatureInitDataBuffer_
Definition: detect.h:525
Signature_::addr_src_match4_cnt
uint16_t addr_src_match4_cnt
Definition: detect.h:683
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:682
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:276
Signature_::type
enum SignatureType type
Definition: detect.h:660
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:940
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:637
DetectSetupParseRegexesOpts
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
Definition: detect-parse.c:3439
DetectPortCleanupList
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
Definition: detect-engine-port.c:124
DETECT_SM_LIST_SUPPRESS
@ DETECT_SM_LIST_SUPPRESS
Definition: detect.h:132
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
SCClassConfLoadClassificationConfigFile
bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
Definition: util-classification-config.c:524
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:278
DetectAddressHead_::ipv4_head
DetectAddress * ipv4_head
Definition: detect.h:184
SignatureHook_::t
union SignatureHook_::@85 t
detect-engine-address.h
DetectFirewallRuleAppendNew
Signature * DetectFirewallRuleAppendNew(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3266
SIG_FLAG_FILESTORE
#define SIG_FLAG_FILESTORE
Definition: detect.h:269
DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_WITHIN
Definition: detect-content.h:31
detect-parse.c
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:244
AppLayerProtoDetectGetProtoName
const char * AppLayerProtoDetectGetProtoName(AppProto alproto)
Definition: app-layer-detect-proto.c:2093
RetrieveFPForSig
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-mpm.c:1097
app-layer.h
SignatureInitData_::alprotos
AppProto alprotos[SIG_ALPROTO_MAX]
Definition: detect.h:601
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:254