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, "pre_flow") == 0) {
1245  } else if (strcmp(str, "pre_stream") == 0) {
1247  } else if (strcmp(str, "all") == 0) {
1248  return SIGNATURE_HOOK_PKT_ALL;
1249  }
1251 }
1252 
1253 #ifdef DEBUG
1254 static const char *HookPktToString(const enum SignatureHookPkt ph)
1255 {
1256  switch (ph) {
1258  return "not set";
1260  return "flow_start";
1262  return "pre_flow";
1264  return "pre_stream";
1266  return "all";
1267  }
1268  return "error";
1269 }
1270 #endif
1271 
1272 static SignatureHook SetPktHook(const char *hook_str)
1273 {
1274  SignatureHook h = {
1276  .t.pkt.ph = HookPktFromString(hook_str),
1277  };
1278  return h;
1279 }
1280 
1281 /**
1282  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1283  */
1284 static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1285 {
1286  enum SignatureHookPkt hook = HookPktFromString(h);
1287  if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
1288  s->init_data->hook = SetPktHook(h);
1289  if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
1290  return -1; // TODO unreachable?
1291  }
1292  } else {
1293  SCLogError("unknown pkt hook %s", h);
1294  return -1;
1295  }
1296 
1297  SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
1298  SignatureHookTypeToString(s->init_data->hook.type),
1299  HookPktToString(s->init_data->hook.t.pkt.ph));
1300  return 0;
1301 }
1302 
1303 static SignatureHook SetAppHook(const AppProto alproto, int progress)
1304 {
1305  SignatureHook h = {
1307  .t.app.alproto = alproto,
1308  .t.app.app_progress = progress,
1309  };
1310  return h;
1311 }
1312 
1313 /**
1314  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1315  */
1316 static int SigParseProtoHookApp(Signature *s, const char *proto_hook, const char *p, const char *h)
1317 {
1318  if (strcmp(h, "request_started") == 0) {
1319  s->flags |= SIG_FLAG_TOSERVER;
1320  s->init_data->hook =
1321  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1322  } else if (strcmp(h, "response_started") == 0) {
1323  s->flags |= SIG_FLAG_TOCLIENT;
1324  s->init_data->hook =
1325  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1326  } else if (strcmp(h, "request_complete") == 0) {
1327  s->flags |= SIG_FLAG_TOSERVER;
1328  s->init_data->hook = SetAppHook(s->alproto,
1330  } else if (strcmp(h, "response_complete") == 0) {
1331  s->flags |= SIG_FLAG_TOCLIENT;
1332  s->init_data->hook = SetAppHook(s->alproto,
1334  } else {
1335  const int progress_ts = AppLayerParserGetStateIdByName(
1336  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
1337  if (progress_ts >= 0) {
1338  s->flags |= SIG_FLAG_TOSERVER;
1339  s->init_data->hook = SetAppHook(s->alproto, progress_ts);
1340  } else {
1341  const int progress_tc = AppLayerParserGetStateIdByName(
1342  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
1343  if (progress_tc < 0) {
1344  return -1;
1345  }
1346  s->flags |= SIG_FLAG_TOCLIENT;
1347  s->init_data->hook = SetAppHook(s->alproto, progress_tc);
1348  }
1349  }
1350 
1351  char generic_hook_name[64];
1352  snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:generic", proto_hook);
1353  int list = DetectBufferTypeGetByName(generic_hook_name);
1354  if (list < 0) {
1355  SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
1356  return -1;
1357  }
1358  s->init_data->hook.sm_list = list;
1359 
1360  SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
1361  SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
1362  s->init_data->hook.t.app.app_progress);
1363 
1364  s->app_progress_hook = (uint8_t)s->init_data->hook.t.app.app_progress;
1365  return 0;
1366 }
1367 
1369 {
1370  printf("=========Supported Rule Protocols=========\n");
1373 }
1374 
1375 /**
1376  * \brief Parses the protocol supplied by the Signature.
1377  *
1378  * http://www.iana.org/assignments/protocol-numbers
1379  *
1380  * \param s Pointer to the Signature instance to which the parsed
1381  * protocol has to be added.
1382  * \param protostr Pointer to the character string containing the protocol name.
1383  *
1384  * \retval 0 On successfully parsing the protocol sent as the argument.
1385  * \retval -1 On failure
1386  */
1387 static int SigParseProto(Signature *s, const char *protostr)
1388 {
1389  SCEnter();
1390  if (strlen(protostr) > 32)
1391  return -1;
1392 
1393  char proto[33];
1394  strlcpy(proto, protostr, 33);
1395  const char *p = proto;
1396  const char *h = NULL;
1397 
1398  bool has_hook = strchr(proto, ':') != NULL;
1399  if (has_hook) {
1400  char *xsaveptr = NULL;
1401  p = strtok_r(proto, ":", &xsaveptr);
1402  h = strtok_r(NULL, ":", &xsaveptr);
1403  SCLogDebug("p: '%s' h: '%s'", p, h);
1404  }
1405  if (p == NULL) {
1406  SCLogError("invalid protocol specification '%s'", proto);
1407  return -1;
1408  }
1409 
1410  int r = DetectProtoParse(&s->proto, p);
1411  if (r < 0) {
1413  /* indicate that the signature is app-layer */
1414  if (s->alproto != ALPROTO_UNKNOWN) {
1415  s->flags |= SIG_FLAG_APPLAYER;
1416 
1418 
1419  if (h) {
1420  if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
1421  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1422  SCReturnInt(-1);
1423  }
1424  }
1425  }
1426  else {
1427  SCLogError("protocol \"%s\" cannot be used "
1428  "in a signature. Either detection for this protocol "
1429  "is not yet supported OR detection has been disabled for "
1430  "protocol through the yaml option "
1431  "app-layer.protocols.%s.detection-enabled",
1432  p, p);
1433  SCReturnInt(-1);
1434  }
1435  } else if (h != NULL) {
1436  SCLogDebug("non-app-layer rule with %s:%s", p, h);
1437 
1438  if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
1439  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1440  SCReturnInt(-1);
1441  }
1442  }
1443 
1444  /* if any of these flags are set they are set in a mutually exclusive
1445  * manner */
1446  if (s->proto.flags & DETECT_PROTO_ONLY_PKT) {
1448  } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1450  }
1451 
1452  SCReturnInt(0);
1453 }
1454 
1455 /**
1456  * \brief Parses the port(source or destination) field, from a Signature.
1457  *
1458  * \param s Pointer to the signature which has to be updated with the
1459  * port information.
1460  * \param portstr Pointer to the character string containing the port info.
1461  * \param Flag which indicates if the portstr received is src or dst
1462  * port. For src port: flag = 0, dst port: flag = 1.
1463  *
1464  * \retval 0 On success.
1465  * \retval -1 On failure.
1466  */
1467 static int SigParsePort(const DetectEngineCtx *de_ctx,
1468  Signature *s, const char *portstr, char flag)
1469 {
1470  int r = 0;
1471 
1472  /* XXX VJ exclude handling this for none UDP/TCP proto's */
1473 
1474  SCLogDebug("Port group \"%s\" to be parsed", portstr);
1475 
1476  if (flag == 0) {
1477  if (strcasecmp(portstr, "any") == 0)
1478  s->flags |= SIG_FLAG_SP_ANY;
1479 
1480  r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1481  } else if (flag == 1) {
1482  if (strcasecmp(portstr, "any") == 0)
1483  s->flags |= SIG_FLAG_DP_ANY;
1484 
1485  r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1486  }
1487 
1488  if (r < 0)
1489  return -1;
1490 
1491  return 0;
1492 }
1493 
1494 /** \retval 1 valid
1495  * \retval 0 invalid
1496  */
1497 static int SigParseActionRejectValidate(const char *action)
1498 {
1499 #ifdef HAVE_LIBNET11
1500 #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1501  if (sc_set_caps) {
1502  SCLogError("Libnet 1.1 is "
1503  "incompatible with POSIX based capabilities with privs dropping. "
1504  "For rejects to work, run as root/super user.");
1505  return 0;
1506  }
1507 #endif
1508 #else /* no libnet 1.1 */
1509  SCLogError("Libnet 1.1.x is "
1510  "required for action \"%s\" but is not compiled into Suricata",
1511  action);
1512  return 0;
1513 #endif
1514  return 1;
1515 }
1516 
1517 /** \retval 0 on error
1518  * \retval flags on success
1519  */
1520 static uint8_t ActionStringToFlags(const char *action)
1521 {
1522  if (strcasecmp(action, "alert") == 0) {
1523  return ACTION_ALERT;
1524  } else if (strcasecmp(action, "drop") == 0) {
1525  return ACTION_DROP | ACTION_ALERT;
1526  } else if (strcasecmp(action, "pass") == 0) {
1527  return ACTION_PASS;
1528  } else if (strcasecmp(action, "reject") == 0 ||
1529  strcasecmp(action, "rejectsrc") == 0)
1530  {
1531  if (!(SigParseActionRejectValidate(action)))
1532  return 0;
1534  } else if (strcasecmp(action, "rejectdst") == 0) {
1535  if (!(SigParseActionRejectValidate(action)))
1536  return 0;
1538  } else if (strcasecmp(action, "rejectboth") == 0) {
1539  if (!(SigParseActionRejectValidate(action)))
1540  return 0;
1542  } else if (strcasecmp(action, "config") == 0) {
1543  return ACTION_CONFIG;
1544  } else if (strcasecmp(action, "accept") == 0) {
1545  return ACTION_ACCEPT;
1546  } else {
1547  SCLogError("An invalid action \"%s\" was given", action);
1548  return 0;
1549  }
1550 }
1551 
1552 /**
1553  * \brief Parses the action that has been used by the Signature and allots it
1554  * to its Signature instance.
1555  *
1556  * \param s Pointer to the Signature instance to which the action belongs.
1557  * \param action Pointer to the action string used by the Signature.
1558  *
1559  * \retval 0 On successfully parsing the action string and adding it to the
1560  * Signature.
1561  * \retval -1 On failure.
1562  */
1563 static int SigParseAction(Signature *s, const char *action_in)
1564 {
1565  char action[32];
1566  strlcpy(action, action_in, sizeof(action));
1567  const char *a = action;
1568  const char *o = NULL;
1569 
1570  bool has_scope = strchr(action, ':') != NULL;
1571  if (has_scope) {
1572  char *xsaveptr = NULL;
1573  a = strtok_r(action, ":", &xsaveptr);
1574  o = strtok_r(NULL, ":", &xsaveptr);
1575  SCLogDebug("a: '%s' o: '%s'", a, o);
1576  }
1577  if (a == NULL) {
1578  SCLogError("invalid protocol specification '%s'", action_in);
1579  return -1;
1580  }
1581 
1582  uint8_t flags = ActionStringToFlags(a);
1583  if (flags == 0)
1584  return -1;
1585 
1586  /* parse scope, if any */
1587  if (o) {
1588  uint8_t scope_flags = 0;
1589  if (flags & (ACTION_DROP | ACTION_PASS)) {
1590  if (strcmp(o, "packet") == 0) {
1591  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1592  } else if (strcmp(o, "flow") == 0) {
1593  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1594  } else {
1595  SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1596  "allowed",
1597  o, action_in);
1598  return -1;
1599  }
1600  s->action_scope = scope_flags;
1601  } else if (flags & (ACTION_ACCEPT)) {
1602  if (strcmp(o, "packet") == 0) {
1603  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1604  } else if (strcmp(o, "hook") == 0) {
1605  scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1606  } else if (strcmp(o, "tx") == 0) {
1607  scope_flags = (uint8_t)ACTION_SCOPE_TX;
1608  } else if (strcmp(o, "flow") == 0) {
1609  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1610  } else {
1611  SCLogError(
1612  "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1613  "'hook' allowed",
1614  o, action_in);
1615  return -1;
1616  }
1617  s->action_scope = scope_flags;
1618  } else if (flags & (ACTION_CONFIG)) {
1619  if (strcmp(o, "packet") == 0) {
1620  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1621  } else {
1622  SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
1623  action_in);
1624  return -1;
1625  }
1626  s->action_scope = scope_flags;
1627  } else {
1628  SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1629  "'drop', 'pass' and 'reject'",
1630  o, action_in);
1631  return -1;
1632  }
1633  }
1634 
1635  /* require explicit action scope for fw rules */
1636  if (s->init_data->firewall_rule && s->action_scope == 0) {
1637  SCLogError("firewall rules require setting an explicit action scope");
1638  return -1;
1639  }
1640 
1641  if (!s->init_data->firewall_rule && (flags & ACTION_ACCEPT)) {
1642  SCLogError("'accept' action only supported for firewall rules");
1643  return -1;
1644  }
1645 
1646  if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
1647  SCLogError("'pass' action not supported for firewall rules");
1648  return -1;
1649  }
1650 
1651  s->action = flags;
1652  return 0;
1653 }
1654 
1655 /**
1656  * \brief Parse the next token in rule.
1657  *
1658  * For rule parsing a token is considered to be a string of characters
1659  * separated by white space.
1660  *
1661  * \param input double pointer to input buffer, will be advanced as input is
1662  * parsed.
1663  * \param output buffer to copy token into.
1664  * \param output_size length of output buffer.
1665  */
1666 static inline int SigParseToken(char **input, char *output,
1667  const size_t output_size)
1668 {
1669  size_t len = *input == NULL ? 0 : strlen(*input);
1670 
1671  if (!len) {
1672  return 0;
1673  }
1674 
1675  while (len && isblank(**input)) {
1676  (*input)++;
1677  len--;
1678  }
1679 
1680  char *endptr = strpbrk(*input, " \t\n\r");
1681  if (endptr != NULL) {
1682  *(endptr++) = '\0';
1683  }
1684  strlcpy(output, *input, output_size);
1685  *input = endptr;
1686 
1687  return 1;
1688 }
1689 
1690 /**
1691  * \brief Parse the next rule "list" token.
1692  *
1693  * Parses rule tokens that may be lists such as addresses and ports
1694  * handling the case when they may not be lists.
1695  *
1696  * \param input double pointer to input buffer, will be advanced as input is
1697  * parsed.
1698  * \param output buffer to copy token into.
1699  * \param output_size length of output buffer.
1700  */
1701 static inline int SigParseList(char **input, char *output,
1702  const size_t output_size)
1703 {
1704  int in_list = 0;
1705  size_t len = *input != NULL ? strlen(*input) : 0;
1706 
1707  if (len == 0) {
1708  return 0;
1709  }
1710 
1711  while (len && isblank(**input)) {
1712  (*input)++;
1713  len--;
1714  }
1715 
1716  size_t i = 0;
1717  for (i = 0; i < len; i++) {
1718  char c = (*input)[i];
1719  if (c == '[') {
1720  in_list++;
1721  } else if (c == ']') {
1722  in_list--;
1723  } else if (c == ' ') {
1724  if (!in_list) {
1725  break;
1726  }
1727  }
1728  }
1729  if (i == len) {
1730  *input = NULL;
1731  return 0;
1732  }
1733  (*input)[i] = '\0';
1734  strlcpy(output, *input, output_size);
1735  *input = *input + i + 1;
1736 
1737  return 1;
1738 }
1739 
1740 /**
1741  * \internal
1742  * \brief split a signature string into a few blocks for further parsing
1743  *
1744  * \param scan_only just scan, don't validate
1745  */
1746 static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1747  SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1748 {
1749  char *index, dup[DETECT_MAX_RULE_SIZE];
1750 
1751  strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1752  index = dup;
1753 
1754  /* Action. */
1755  SigParseToken(&index, parser->action, sizeof(parser->action));
1756 
1757  /* Protocol. */
1758  SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1759 
1760  /* Source. */
1761  SigParseList(&index, parser->src, sizeof(parser->src));
1762 
1763  /* Source port(s). */
1764  SigParseList(&index, parser->sp, sizeof(parser->sp));
1765 
1766  /* Direction. */
1767  SigParseToken(&index, parser->direction, sizeof(parser->direction));
1768 
1769  /* Destination. */
1770  SigParseList(&index, parser->dst, sizeof(parser->dst));
1771 
1772  /* Destination port(s). */
1773  SigParseList(&index, parser->dp, sizeof(parser->dp));
1774 
1775  /* Options. */
1776  if (index == NULL) {
1777  SCLogError("no rule options.");
1778  goto error;
1779  }
1780  while (isspace(*index) || *index == '(') {
1781  index++;
1782  }
1783  for (size_t i = strlen(index); i > 0; i--) {
1784  if (isspace(index[i - 1]) || index[i - 1] == ')') {
1785  index[i - 1] = '\0';
1786  } else {
1787  break;
1788  }
1789  }
1790  strlcpy(parser->opts, index, sizeof(parser->opts));
1791 
1792  if (scan_only) {
1793  return 0;
1794  }
1795 
1796  /* Parse Action */
1797  if (SigParseAction(s, parser->action) < 0)
1798  goto error;
1799 
1800  if (SigParseProto(s, parser->protocol) < 0)
1801  goto error;
1802 
1803  if (strcmp(parser->direction, "<>") == 0) {
1805  } else if (strcmp(parser->direction, "=>") == 0) {
1806  if (s->flags & SIG_FLAG_FIREWALL) {
1807  SCLogError("transactional bidirectional rules not supported for firewall rules");
1808  goto error;
1809  }
1810 
1811  s->flags |= SIG_FLAG_TXBOTHDIR;
1812  } else if (strcmp(parser->direction, "->") != 0) {
1813  SCLogError("\"%s\" is not a valid direction modifier, "
1814  "\"->\" and \"<>\" are supported.",
1815  parser->direction);
1816  goto error;
1817  }
1818 
1819  /* Parse Address & Ports */
1820  if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1821  goto error;
1822 
1823  if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1824  goto error;
1825 
1826  /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1827  * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1828  * changes that we made sees to it that at this point of time we don't
1829  * set the ip proto for the sig. We do it a bit later. */
1830  if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1831  goto error;
1832  if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1833  goto error;
1834 
1835  return 0;
1836 
1837 error:
1838  return -1;
1839 }
1840 
1841 static inline bool CheckAscii(const char *str)
1842 {
1843  for (size_t i = 0; i < strlen(str); i++) {
1844  if (str[i] < 0x20) {
1845  // LF CR TAB
1846  if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1847  continue;
1848  }
1849  return false;
1850  } else if (str[i] == 0x7f) {
1851  return false;
1852  }
1853  }
1854  return true;
1855 }
1856 
1857 /**
1858  * \brief parse a signature
1859  *
1860  * \param de_ctx detection engine ctx to add it to
1861  * \param s memory structure to store the signature in
1862  * \param sigstr the raw signature as a null terminated string
1863  * \param addrs_direction direction (for bi-directional sigs)
1864  * \param require only scan rule for requires
1865  *
1866  * \param -1 parse error
1867  * \param 0 ok
1868  */
1869 static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1870  uint8_t addrs_direction, SignatureParser *parser, bool requires)
1871 {
1872  SCEnter();
1873 
1874  if (!SCCheckUtf8(sigstr)) {
1875  SCLogError("rule is not valid UTF-8");
1876  SCReturnInt(-1);
1877  }
1878 
1879  if (!CheckAscii(sigstr)) {
1880  SCLogError("rule contains invalid (control) characters");
1881  SCReturnInt(-1);
1882  }
1883 
1884  int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
1885  if (ret < 0) {
1886  SCLogDebug("SigParseBasics failed");
1887  SCReturnInt(-1);
1888  }
1889 
1890  /* we can have no options, so make sure we have them */
1891  if (strlen(parser->opts) > 0) {
1892  size_t buffer_size = strlen(parser->opts) + 1;
1893  char input[buffer_size];
1894  char output[buffer_size];
1895  memset(input, 0x00, buffer_size);
1896  memcpy(input, parser->opts, strlen(parser->opts) + 1);
1897 
1898  /* loop the option parsing. Each run processes one option
1899  * and returns the rest of the option string through the
1900  * output variable. */
1901  do {
1902  memset(output, 0x00, buffer_size);
1903  ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
1904  if (ret == 1) {
1905  memcpy(input, output, buffer_size);
1906  }
1907 
1908  } while (ret == 1);
1909 
1910  if (ret < 0) {
1911  /* Suricata didn't meet the rule requirements, skip. */
1912  goto end;
1913  }
1914  }
1915 
1916 end:
1918 
1919  SCReturnInt(ret);
1920 }
1921 
1922 /** \brief check if buffers array still has space left, expand if not
1923  */
1925 {
1926  if (s->init_data->buffers_size >= 64)
1927  return -1;
1928 
1929  if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
1930  void *ptr = SCRealloc(s->init_data->buffers,
1931  (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
1932  if (ptr == NULL)
1933  return -1;
1934  s->init_data->buffers = ptr;
1935  for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
1937  memset(b, 0, sizeof(*b));
1938  }
1939  s->init_data->buffers_size += 8;
1940  }
1941  return 0;
1942 }
1943 
1945 {
1946  Signature *sig = SCCalloc(1, sizeof(Signature));
1947  if (unlikely(sig == NULL))
1948  return NULL;
1949 
1950  sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
1951  if (sig->init_data == NULL) {
1952  SCFree(sig);
1953  return NULL;
1954  }
1955  sig->init_data->mpm_sm_list = -1;
1956 
1957  sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
1958  if (sig->init_data->buffers == NULL) {
1959  SCFree(sig->init_data);
1960  SCFree(sig);
1961  return NULL;
1962  }
1963  sig->init_data->buffers_size = 8;
1964 
1965  /* assign it to -1, so that we can later check if the value has been
1966  * overwritten after the Signature has been parsed, and if it hasn't been
1967  * overwritten, we can then assign the default value of 3 */
1968  sig->prio = -1;
1969 
1970  /* rule interdepency is false, at start */
1971  sig->init_data->is_rule_state_dependant = false;
1972  /* first index is 0 */
1974 
1976  return sig;
1977 }
1978 
1979 /**
1980  * \internal
1981  * \brief Free Metadata list
1982  *
1983  * \param s Pointer to the signature
1984  */
1985 static void SigMetadataFree(Signature *s)
1986 {
1987  SCEnter();
1988 
1989  DetectMetadata *mdata = NULL;
1990  DetectMetadata *next_mdata = NULL;
1991 
1992  if (s == NULL || s->metadata == NULL) {
1993  SCReturn;
1994  }
1995 
1996  SCLogDebug("s %p, s->metadata %p", s, s->metadata);
1997 
1998  for (mdata = s->metadata->list; mdata != NULL;) {
1999  next_mdata = mdata->next;
2000  DetectMetadataFree(mdata);
2001  mdata = next_mdata;
2002  }
2003  SCFree(s->metadata->json_str);
2004  SCFree(s->metadata);
2005  s->metadata = NULL;
2006 
2007  SCReturn;
2008 }
2009 
2010 /**
2011  * \internal
2012  * \brief Free Reference list
2013  *
2014  * \param s Pointer to the signature
2015  */
2016 static void SigRefFree (Signature *s)
2017 {
2018  SCEnter();
2019 
2020  DetectReference *ref = NULL;
2021  DetectReference *next_ref = NULL;
2022 
2023  if (s == NULL) {
2024  SCReturn;
2025  }
2026 
2027  SCLogDebug("s %p, s->references %p", s, s->references);
2028 
2029  for (ref = s->references; ref != NULL;) {
2030  next_ref = ref->next;
2031  DetectReferenceFree(ref);
2032  ref = next_ref;
2033  }
2034 
2035  s->references = NULL;
2036 
2037  SCReturn;
2038 }
2039 
2040 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2041 {
2042  if (s != NULL) {
2043  int type;
2044  for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2045  if (s->sm_arrays[type] != NULL) {
2046  if (ctxs) {
2047  SigMatchData *smd = s->sm_arrays[type];
2048  while(1) {
2049  if (sigmatch_table[smd->type].Free != NULL) {
2050  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2051  }
2052  if (smd->is_last)
2053  break;
2054  smd++;
2055  }
2056  }
2057 
2058  SCFree(s->sm_arrays[type]);
2059  }
2060  }
2061  }
2062 }
2063 
2065 {
2066  if (s == NULL)
2067  return;
2068 
2069  int i;
2070 
2071  if (s->init_data && s->init_data->transforms.cnt) {
2072  for(i = 0; i < s->init_data->transforms.cnt; i++) {
2073  if (s->init_data->transforms.transforms[i].options) {
2074  int transform = s->init_data->transforms.transforms[i].transform;
2075  sigmatch_table[transform].Free(
2077  s->init_data->transforms.transforms[i].options = NULL;
2078  }
2079  }
2080  }
2081  if (s->init_data) {
2082  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2083  SigMatch *sm = s->init_data->smlists[i];
2084  while (sm != NULL) {
2085  SigMatch *nsm = sm->next;
2086  SigMatchFree(de_ctx, sm);
2087  sm = nsm;
2088  }
2089  }
2090 
2091  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2092  SigMatch *sm = s->init_data->buffers[x].head;
2093  while (sm != NULL) {
2094  SigMatch *nsm = sm->next;
2095  SigMatchFree(de_ctx, sm);
2096  sm = nsm;
2097  }
2098  }
2099  if (s->init_data->cidr_dst != NULL)
2101 
2102  if (s->init_data->cidr_src != NULL)
2104 
2105  SCFree(s->init_data->buffers);
2106  s->init_data->buffers = NULL;
2107  }
2108  SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2109  if (s->init_data) {
2110  SCFree(s->init_data);
2111  s->init_data = NULL;
2112  }
2113 
2114  if (s->sp != NULL) {
2115  DetectPortCleanupList(NULL, s->sp);
2116  }
2117  if (s->dp != NULL) {
2118  DetectPortCleanupList(NULL, s->dp);
2119  }
2120 
2121  if (s->msg != NULL)
2122  SCFree(s->msg);
2123 
2124  if (s->addr_src_match4 != NULL) {
2125  SCFree(s->addr_src_match4);
2126  }
2127  if (s->addr_dst_match4 != NULL) {
2128  SCFree(s->addr_dst_match4);
2129  }
2130  if (s->addr_src_match6 != NULL) {
2131  SCFree(s->addr_src_match6);
2132  }
2133  if (s->addr_dst_match6 != NULL) {
2134  SCFree(s->addr_dst_match6);
2135  }
2136  if (s->sig_str != NULL) {
2137  SCFree(s->sig_str);
2138  }
2139 
2140  SigRefFree(s);
2141  SigMetadataFree(s);
2142 
2144 
2145  SCFree(s);
2146 }
2147 
2148 /**
2149  * \brief this function is used to set multiple possible app-layer protos
2150  * \brief into the current signature (for example ja4 for both tls and quic)
2151  *
2152  * \param s pointer to the Current Signature
2153  * \param alprotos an array terminated by ALPROTO_UNKNOWN
2154  *
2155  * \retval 0 on Success
2156  * \retval -1 on Failure
2157  */
2159 {
2160  if (s->alproto != ALPROTO_UNKNOWN) {
2161  // One alproto was set, check if it matches the new ones proposed
2162  while (*alprotos != ALPROTO_UNKNOWN) {
2163  if (s->alproto == *alprotos) {
2164  // alproto already set to only one
2165  return 0;
2166  }
2167  alprotos++;
2168  }
2169  // alproto already set and not matching the new set of alprotos
2170  return -1;
2171  }
2172  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2173  // check intersection of already used alprotos and new ones
2174  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2175  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2176  break;
2177  }
2178  // first disable the ones that do not match
2179  bool found = false;
2180  const AppProto *args = alprotos;
2181  while (*args != ALPROTO_UNKNOWN) {
2182  if (s->init_data->alprotos[i] == *args) {
2183  found = true;
2184  break;
2185  }
2186  args++;
2187  }
2188  if (!found) {
2190  }
2191  }
2192  // Then put at the beginning every defined protocol
2193  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2194  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2195  for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2196  if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2197  s->init_data->alprotos[i] = s->init_data->alprotos[j];
2199  break;
2200  }
2201  }
2202  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2203  if (i == 0) {
2204  // there was no intersection
2205  return -1;
2206  } else if (i == 1) {
2207  // intersection is singleton, set it as usual
2208  AppProto alproto = s->init_data->alprotos[0];
2210  return SCDetectSignatureSetAppProto(s, alproto);
2211  }
2212  break;
2213  }
2214  }
2215  }
2216  } else {
2217  if (alprotos[0] == ALPROTO_UNKNOWN) {
2218  // do not allow empty set
2219  return -1;
2220  }
2221  if (alprotos[1] == ALPROTO_UNKNOWN) {
2222  // allow singleton, but call traditional setter
2223  return SCDetectSignatureSetAppProto(s, alprotos[0]);
2224  }
2225  // first time we enforce alprotos
2226  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2227  if (alprotos[i] == ALPROTO_UNKNOWN) {
2228  break;
2229  }
2230  s->init_data->alprotos[i] = alprotos[i];
2231  }
2232  }
2233  return 0;
2234 }
2235 
2237 {
2238  if (!AppProtoIsValid(alproto)) {
2239  SCLogError("invalid alproto %u", alproto);
2240  return -1;
2241  }
2242 
2243  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2244  // Multiple alprotos were set, check if we restrict to one
2245  bool found = false;
2246  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2247  if (s->init_data->alprotos[i] == alproto) {
2248  found = true;
2249  break;
2250  }
2251  }
2252  if (!found) {
2253  // fail if we set to a alproto which was not in the set
2254  return -1;
2255  }
2256  // we will use s->alproto if there is a single alproto and
2257  // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2259  }
2260 
2261  if (s->alproto != ALPROTO_UNKNOWN) {
2262  alproto = AppProtoCommon(s->alproto, alproto);
2263  if (alproto == ALPROTO_FAILED) {
2264  SCLogError("can't set rule app proto to %s: already set to %s",
2265  AppProtoToString(alproto), AppProtoToString(s->alproto));
2266  return -1;
2267  }
2268  }
2269 
2270  if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2271  SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2272  return -1;
2273  }
2274  s->alproto = alproto;
2275  s->flags |= SIG_FLAG_APPLAYER;
2276  return 0;
2277 }
2278 
2279 static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2280  const DetectAddress *head, uint16_t *match4_cnt)
2281 {
2282  uint16_t cnt = 0;
2283 
2284  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2285  cnt++;
2286  }
2287  if (cnt == 0) {
2288  return NULL;
2289  }
2290  DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2291  if (addr_match4 == NULL) {
2292  exit(EXIT_FAILURE);
2293  }
2294 
2295  uint16_t idx = 0;
2296  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2297  addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2298  addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2299  idx++;
2300  }
2301  *match4_cnt = cnt;
2302  return addr_match4;
2303 }
2304 
2305 static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2306  const DetectAddress *head, uint16_t *match6_cnt)
2307 {
2308  uint16_t cnt = 0;
2309  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2310  cnt++;
2311  }
2312  if (cnt == 0) {
2313  return NULL;
2314  }
2315 
2316  DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2317  if (addr_match6 == NULL) {
2318  exit(EXIT_FAILURE);
2319  }
2320 
2321  uint16_t idx = 0;
2322  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2323  addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2324  addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2325  addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2326  addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2327  addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2328  addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2329  addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2330  addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2331  idx++;
2332  }
2333  *match6_cnt = cnt;
2334  return addr_match6;
2335 }
2336 
2337 /**
2338  * \internal
2339  * \brief build address match array for cache efficient matching
2340  *
2341  * \param s the signature
2342  */
2343 static void SigBuildAddressMatchArray(Signature *s)
2344 {
2345  /* source addresses */
2346  s->addr_src_match4 =
2347  SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2348  /* destination addresses */
2349  s->addr_dst_match4 =
2350  SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2351 
2352  /* source addresses IPv6 */
2353  s->addr_src_match6 =
2354  SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2355  /* destination addresses IPv6 */
2356  s->addr_dst_match6 =
2357  SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2358 }
2359 
2360 static int SigMatchListLen(SigMatch *sm)
2361 {
2362  int len = 0;
2363  for (; sm != NULL; sm = sm->next)
2364  len++;
2365 
2366  return len;
2367 }
2368 
2369 /** \brief convert SigMatch list to SigMatchData array
2370  * \note ownership of sm->ctx is transferred to smd->ctx
2371  */
2373 {
2374  int len = SigMatchListLen(head);
2375  if (len == 0)
2376  return NULL;
2377 
2378  SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
2379  if (smd == NULL) {
2380  FatalError("initializing the detection engine failed");
2381  }
2382  SigMatchData *out = smd;
2383 
2384  /* Copy sm type and Context into array */
2385  SigMatch *sm = head;
2386  for (; sm != NULL; sm = sm->next, smd++) {
2387  smd->type = sm->type;
2388  smd->ctx = sm->ctx;
2389  sm->ctx = NULL; // SigMatch no longer owns the ctx
2390  smd->is_last = (sm->next == NULL);
2391  }
2392  return out;
2393 }
2394 
2395 extern int g_skip_prefilter;
2396 
2397 static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2398 {
2399  SCEnter();
2400  SCLogDebug("s %u: set up prefilter/mpm", s->id);
2401  DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
2402 
2403  if (s->init_data->prefilter_sm != NULL) {
2404  if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
2406  if (s->init_data->mpm_sm != NULL) {
2407  s->flags |= SIG_FLAG_PREFILTER;
2408  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2409  SCReturn;
2410  }
2411  /* fall through, this can happen if the mpm doesn't support the pattern */
2412  } else {
2413  s->flags |= SIG_FLAG_PREFILTER;
2414  SCReturn;
2415  }
2416  } else {
2417  SCLogDebug("%u: RetrieveFPForSig", s->id);
2419  if (s->init_data->mpm_sm != NULL) {
2420  s->flags |= SIG_FLAG_PREFILTER;
2421  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2422  SCReturn;
2423  }
2424  }
2425 
2426  SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2427  "s->init_data->has_possible_prefilter %s",
2429 
2431  SCReturn;
2432 
2435  int prefilter_list = DETECT_TBLSIZE;
2436  /* get the keyword supporting prefilter with the lowest type */
2437  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2438  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2439  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2440  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
2441  prefilter_list = MIN(prefilter_list, sm->type);
2442  }
2443  }
2444  }
2445  }
2446 
2447  /* apply that keyword as prefilter */
2448  if (prefilter_list != DETECT_TBLSIZE) {
2449  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2450  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2451  if (sm->type == prefilter_list) {
2452  s->init_data->prefilter_sm = sm;
2453  s->flags |= SIG_FLAG_PREFILTER;
2454  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2455  sigmatch_table[sm->type].name);
2456  break;
2457  }
2458  }
2459  }
2460  }
2461  }
2462  SCReturn;
2463 }
2464 
2465 /** \internal
2466  * \brief check if signature's table requirement is supported by each of the keywords it uses.
2467  */
2468 static bool DetectRuleValidateTable(const Signature *s)
2469 {
2470  if (s->detect_table == 0)
2471  return true;
2472 
2473  const uint8_t table_as_flag = BIT_U8(s->detect_table);
2474 
2475  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
2476  const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
2477  if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
2478  SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
2480  return false;
2481  }
2482  }
2483  return true;
2484 }
2485 
2486 static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2487 {
2489  SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2490  "explicit hook",
2491  s->id);
2492  return false;
2493  }
2494  return true;
2495 }
2496 
2497 static void DetectRuleSetTable(Signature *s)
2498 {
2499  enum DetectTable table;
2500  if (s->flags & SIG_FLAG_FIREWALL) {
2501  if (s->type == SIG_TYPE_PKT) {
2505  else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
2508  else
2510  } else if (s->type == SIG_TYPE_APP_TX) {
2511  table = DETECT_TABLE_APP_FILTER;
2512  } else {
2513  BUG_ON(1);
2514  }
2515  } else {
2516  // TODO pre_flow/pre_stream
2517  if (s->type != SIG_TYPE_APP_TX) {
2518  table = DETECT_TABLE_PACKET_TD;
2519  } else {
2520  table = DETECT_TABLE_APP_TD;
2521  }
2522  }
2523 
2524  s->detect_table = (uint8_t)table;
2525 }
2526 
2527 static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2528 {
2529  if (s->init_data->firewall_rule) {
2530  if (!DetectFirewallRuleValidate(de_ctx, s))
2531  SCReturnInt(0);
2532  }
2533  SCReturnInt(1);
2534 }
2535 
2536 static int SigValidateCheckBuffers(
2537  DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2538 {
2539  bool has_frame = false;
2540  bool has_app = false;
2541  bool has_pkt = false;
2542  bool has_pmatch = false;
2543 
2544  int nlists = 0;
2545  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2546  nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2547  }
2548  nlists += (nlists > 0);
2549  SCLogDebug("nlists %d", nlists);
2550 
2551  if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2552  SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2554  SCReturnInt(0);
2555  }
2556 
2557  /* run buffer type validation callbacks if any */
2560  SCReturnInt(0);
2561 
2562  has_pmatch = true;
2563  }
2564 
2565  DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
2566  struct BufferVsDir {
2567  int ts;
2568  int tc;
2569  } bufdir[nlists + 1];
2570  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2571 
2572  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2575  if (bt == NULL) {
2576  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2577  continue;
2578  }
2579  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2580  for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2581  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2582  }
2583 
2584  if (b->head == NULL) {
2585  SCLogError("no matches in sticky buffer %s", bt->name);
2586  SCReturnInt(0);
2587  }
2588 
2589  has_frame |= bt->frame;
2590  has_app |= (!bt->frame && !bt->packet);
2591  has_pkt |= bt->packet;
2592 
2593  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2594  SCLogError("Signature combines packet "
2595  "specific matches (like dsize, flags, ttl) with stream / "
2596  "state matching by matching on app layer proto (like using "
2597  "http_* keywords).");
2598  SCReturnInt(0);
2599  }
2600 
2602  for (; app != NULL; app = app->next) {
2603  if (app->sm_list == b->id &&
2604  (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2605  SCLogDebug("engine %s dir %d alproto %d",
2607  app->alproto);
2608  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2609 
2610  if (b->only_tc) {
2611  if (app->dir == 1)
2612  (*tc_excl)++;
2613  } else if (b->only_ts) {
2614  if (app->dir == 0)
2615  (*ts_excl)++;
2616  } else {
2617  bufdir[b->id].ts += (app->dir == 0);
2618  bufdir[b->id].tc += (app->dir == 1);
2619  }
2620 
2621  /* only allow rules to use the hook for engines at that
2622  * exact progress for now. */
2624  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2625  app->progress != s->init_data->hook.t.app.app_progress) {
2626  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2627  s->init_data->hook.t.app.app_progress);
2628  SCReturnInt(0);
2629  }
2630  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2631  app->progress != s->init_data->hook.t.app.app_progress) {
2632  SCLogError("engine progress value doesn't match hook");
2633  SCReturnInt(0);
2634  }
2635  }
2636  }
2637  }
2638 
2640  SCReturnInt(0);
2641  }
2642 
2644  SCReturnInt(0);
2645  }
2647  SCReturnInt(0);
2648  }
2649  }
2650 
2651  if (has_pmatch && has_frame) {
2652  SCLogError("can't mix pure content and frame inspection");
2653  SCReturnInt(0);
2654  }
2655  if (has_app && has_frame) {
2656  SCLogError("can't mix app-layer buffer and frame inspection");
2657  SCReturnInt(0);
2658  }
2659  if (has_pkt && has_frame) {
2660  SCLogError("can't mix pkt buffer and frame inspection");
2661  SCReturnInt(0);
2662  }
2663 
2664  for (int x = 0; x < nlists; x++) {
2665  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2666  continue;
2667  (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2668  (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2669  (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2670 
2671  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2672  bufdir[x].tc);
2673  }
2674 
2675  SCReturnInt(1);
2676 }
2677 
2678 static int SigValidatePacketStream(const Signature *s)
2679 {
2681  SCLogError("can't mix packet keywords with "
2682  "tcp-stream or flow:only_stream. Invalidating signature.");
2683  SCReturnInt(0);
2684  }
2685  SCReturnInt(1);
2686 }
2687 
2688 static int SigConsolidateDirection(
2689  Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2690 {
2691  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2692  if (!ts_excl || !tc_excl) {
2693  SCLogError("rule %u should use both directions, but does not", s->id);
2694  SCReturnInt(0);
2695  }
2696  if (dir_amb) {
2697  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2698  "directions",
2699  s->id);
2700  SCReturnInt(0);
2701  }
2702  } else if (ts_excl && tc_excl) {
2703  SCLogError(
2704  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2705  "should be used",
2706  s->id);
2707  SCReturnInt(0);
2708  } else if (ts_excl) {
2709  SCLogDebug("%u: implied rule direction is toserver", s->id);
2711  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2712  SCReturnInt(0);
2713  }
2714  } else if (tc_excl) {
2715  SCLogDebug("%u: implied rule direction is toclient", s->id);
2717  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2718  SCReturnInt(0);
2719  }
2720  } else if (dir_amb) {
2721  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2722  }
2723  SCReturnInt(1);
2724 }
2725 
2726 static void SigConsolidateTcpBuffer(Signature *s)
2727 {
2728  /* TCP: corner cases:
2729  * - pkt vs stream vs depth/offset
2730  * - pkt vs stream vs stream_size
2731  */
2732  if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
2736  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2737  sm = sm->next) {
2738  if (sm->type == DETECT_CONTENT &&
2739  (((DetectContentData *)(sm->ctx))->flags &
2742  break;
2743  }
2744  }
2745  /* if stream_size is in use, also inspect packets */
2746  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2747  sm = sm->next) {
2748  if (sm->type == DETECT_STREAM_SIZE) {
2750  break;
2751  }
2752  }
2753  }
2754  }
2755  }
2756 }
2757 
2758 static bool SigInspectsFiles(const Signature *s)
2759 {
2760  return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2762 }
2763 
2764 /** \internal
2765  * \brief validate file handling
2766  * \retval 1 good signature
2767  * \retval 0 bad signature
2768  */
2769 static int SigValidateFileHandling(const Signature *s)
2770 {
2771  if (!SigInspectsFiles(s)) {
2772  SCReturnInt(1);
2773  }
2774 
2775  if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
2776  !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
2777  SCLogError("protocol %s doesn't "
2778  "support file matching",
2780  SCReturnInt(0);
2781  }
2782  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2783  bool found = false;
2784  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2785  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2786  break;
2787  }
2788  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
2789  AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
2790  found = true;
2791  break;
2792  }
2793  }
2794  if (!found) {
2795  SCLogError("No protocol support file matching");
2796  SCReturnInt(0);
2797  }
2798  }
2800  SCLogError("protocol HTTP2 doesn't support file name matching");
2801  SCReturnInt(0);
2802  }
2803  SCReturnInt(1);
2804 }
2805 
2806 /**
2807  * \internal
2808  * \brief validate and consolidate parsed signature
2809  *
2810  * \param de_ctx detect engine
2811  * \param s signature to validate and consolidate
2812  *
2813  * \retval 0 invalid
2814  * \retval 1 valid
2815  */
2816 static int SigValidateConsolidate(
2817  DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2818 {
2819  SCEnter();
2820 
2821  if (SigValidateFirewall(de_ctx, s) == 0)
2822  SCReturnInt(0);
2823 
2824  if (SigValidatePacketStream(s) == 0) {
2825  SCReturnInt(0);
2826  }
2827 
2828  int ts_excl = 0;
2829  int tc_excl = 0;
2830  int dir_amb = 0;
2831 
2832  if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
2833  SCReturnInt(0);
2834  }
2835 
2836  if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
2837  SCReturnInt(0);
2838  }
2839 
2840  SigConsolidateTcpBuffer(s);
2841 
2843  DetectRuleSetTable(s);
2844 
2845  int r = SigValidateFileHandling(s);
2846  if (r == 0) {
2847  SCReturnInt(0);
2848  }
2849  if (SigInspectsFiles(s)) {
2850  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2852  }
2853  }
2854  if (DetectRuleValidateTable(s) == false) {
2855  SCReturnInt(0);
2856  }
2857 
2858  if (s->type == SIG_TYPE_IPONLY) {
2859  /* For IPOnly */
2860  if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
2861  SCReturnInt(0);
2862 
2863  if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
2864  SCReturnInt(0);
2865  }
2866  SCReturnInt(1);
2867 }
2868 
2869 /**
2870  * \internal
2871  * \brief Helper function for SigInit().
2872  */
2873 static Signature *SigInitHelper(
2874  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2875 {
2876  SignatureParser parser;
2877  memset(&parser, 0x00, sizeof(parser));
2878 
2879  Signature *sig = SigAlloc();
2880  if (sig == NULL)
2881  goto error;
2882  if (firewall_rule) {
2883  sig->init_data->firewall_rule = true;
2884  sig->flags |= SIG_FLAG_FIREWALL;
2885  }
2886 
2887  sig->sig_str = SCStrdup(sigstr);
2888  if (unlikely(sig->sig_str == NULL)) {
2889  goto error;
2890  }
2891 
2892  /* default gid to 1 */
2893  sig->gid = 1;
2894 
2895  /* We do a first parse of the rule in a requires, or scan-only
2896  * mode. Syntactic errors will be picked up here, but the only
2897  * part of the rule that is validated completely is the "requires"
2898  * keyword. */
2899  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
2900  if (ret == -4) {
2901  /* Rule requirements not met. */
2902  de_ctx->sigerror_silent = true;
2903  de_ctx->sigerror_ok = true;
2904  de_ctx->sigerror_requires = true;
2905  goto error;
2906  } else if (ret < 0) {
2907  goto error;
2908  }
2909 
2910  /* Check for a SID before continuuing. */
2911  if (sig->id == 0) {
2912  SCLogError("Signature missing required value \"sid\".");
2913  goto error;
2914  }
2915 
2916  /* Now completely parse the rule. */
2917  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2918  BUG_ON(ret == -4);
2919  if (ret == -3) {
2920  de_ctx->sigerror_silent = true;
2921  de_ctx->sigerror_ok = true;
2922  goto error;
2923  } else if (ret == -2) {
2924  de_ctx->sigerror_silent = true;
2925  goto error;
2926  } else if (ret < 0) {
2927  goto error;
2928  }
2929 
2930  /* signature priority hasn't been overwritten. Using default priority */
2931  if (sig->prio == -1)
2932  sig->prio = DETECT_DEFAULT_PRIO;
2933 
2934  sig->iid = de_ctx->signum;
2935  de_ctx->signum++;
2936 
2937  if (sig->alproto != ALPROTO_UNKNOWN) {
2938  int override_needed = 0;
2939  if (sig->proto.flags & DETECT_PROTO_ANY) {
2940  sig->proto.flags &= ~DETECT_PROTO_ANY;
2941  memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
2942  override_needed = 1;
2943  } else {
2944  override_needed = 1;
2945  size_t s = 0;
2946  for (s = 0; s < sizeof(sig->proto.proto); s++) {
2947  if (sig->proto.proto[s] != 0x00) {
2948  override_needed = 0;
2949  break;
2950  }
2951  }
2952  }
2953 
2954  /* at this point if we had alert ip and the ip proto was not
2955  * overridden, we use the ip proto that has been configured
2956  * against the app proto in use. */
2957  if (override_needed)
2959  }
2960 
2961  /* set the packet and app layer flags, but only if the
2962  * app layer flag wasn't already set in which case we
2963  * only consider the app layer */
2964  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
2965  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
2967  for ( ; sm != NULL; sm = sm->next) {
2968  if (sigmatch_table[sm->type].Match != NULL)
2970  }
2971  } else {
2973  }
2974  }
2975 
2976  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
2977  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
2978  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
2980  }
2981  }
2982  }
2983 
2984  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
2985  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
2986  sig->flags |= SIG_FLAG_TOSERVER;
2987  sig->flags |= SIG_FLAG_TOCLIENT;
2988  }
2989  }
2990 
2991  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
2992  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
2993  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
2994 
2995  SigBuildAddressMatchArray(sig);
2996 
2997  /* run buffer type callbacks if any */
2998  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
2999  if (sig->init_data->smlists[x])
3001  }
3002  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
3004  }
3005 
3006  SigSetupPrefilter(de_ctx, sig);
3007 
3008  /* validate signature, SigValidate will report the error reason */
3009  if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3010  goto error;
3011  }
3012 
3013  return sig;
3014 
3015 error:
3016  if (sig != NULL) {
3017  SigFree(de_ctx, sig);
3018  }
3019  return NULL;
3020 }
3021 
3022 /**
3023  * \brief Checks if a signature has the same source and destination
3024  * \param s parsed signature
3025  *
3026  * \retval true if source and destination are the same, false otherwise
3027  */
3028 static bool SigHasSameSourceAndDestination(const Signature *s)
3029 {
3030  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3031  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3032  return false;
3033  }
3034  }
3035 
3036  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3039 
3041  return false;
3042  }
3043 
3044  src = s->init_data->src->ipv6_head;
3045  dst = s->init_data->dst->ipv6_head;
3046 
3048  return false;
3049  }
3050  }
3051 
3052  return true;
3053 }
3054 
3055 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3056 {
3057  SCEnter();
3058 
3059  uint32_t oldsignum = de_ctx->signum;
3060  de_ctx->sigerror_ok = false;
3061  de_ctx->sigerror_silent = false;
3062  de_ctx->sigerror_requires = false;
3063 
3064  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3065  if (sig == NULL) {
3066  goto error;
3067  }
3068 
3070  if (SigHasSameSourceAndDestination(sig)) {
3071  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3072  "treating the rule as unidirectional", sig->id);
3073 
3075  } else {
3076  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3077  if (sig->next == NULL) {
3078  goto error;
3079  }
3080  }
3081  }
3082 
3083  SCReturnPtr(sig, "Signature");
3084 
3085 error:
3086  if (sig != NULL) {
3087  SigFree(de_ctx, sig);
3088  }
3089  /* if something failed, restore the old signum count
3090  * since we didn't install it */
3091  de_ctx->signum = oldsignum;
3092 
3093  SCReturnPtr(NULL, "Signature");
3094 }
3095 
3096 /**
3097  * \brief Parses a signature and adds it to the Detection Engine Context.
3098  *
3099  * \param de_ctx Pointer to the Detection Engine Context.
3100  * \param sigstr Pointer to a character string containing the signature to be
3101  * parsed.
3102  *
3103  * \retval Pointer to the Signature instance on success; NULL on failure.
3104  */
3105 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3106 {
3107  return SigInitDo(de_ctx, sigstr, false);
3108 }
3109 
3110 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3111 {
3112  return SigInitDo(de_ctx, sigstr, true);
3113 }
3114 
3115 /**
3116  * \brief The hash free function to be the used by the hash table -
3117  * DetectEngineCtx->dup_sig_hash_table.
3118  *
3119  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3120  */
3121 static void DetectParseDupSigFreeFunc(void *data)
3122 {
3123  if (data != NULL)
3124  SCFree(data);
3125 }
3126 
3127 /**
3128  * \brief The hash function to be the used by the hash table -
3129  * DetectEngineCtx->dup_sig_hash_table.
3130  *
3131  * \param ht Pointer to the hash table.
3132  * \param data Pointer to the data, in our case SigDuplWrapper.
3133  * \param datalen Not used in our case.
3134  *
3135  * \retval sw->s->id The generated hash value.
3136  */
3137 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3138 {
3139  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3140 
3141  return (sw->s->id % ht->array_size);
3142 }
3143 
3144 /**
3145  * \brief The Compare function to be used by the hash table -
3146  * DetectEngineCtx->dup_sig_hash_table.
3147  *
3148  * \param data1 Pointer to the first SigDuplWrapper.
3149  * \param len1 Not used.
3150  * \param data2 Pointer to the second SigDuplWrapper.
3151  * \param len2 Not used.
3152  *
3153  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3154  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3155  */
3156 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3157  uint16_t len2)
3158 {
3159  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3160  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3161 
3162  if (sw1 == NULL || sw2 == NULL ||
3163  sw1->s == NULL || sw2->s == NULL)
3164  return 0;
3165 
3166  /* sid and gid match required */
3167  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3168 
3169  return 0;
3170 }
3171 
3172 /**
3173  * \brief Initializes the hash table that is used to cull duplicate sigs.
3174  *
3175  * \param de_ctx Pointer to the detection engine context.
3176  *
3177  * \retval 0 On success.
3178  * \retval -1 On failure.
3179  */
3181 {
3183  DetectParseDupSigHashFunc,
3184  DetectParseDupSigCompareFunc,
3185  DetectParseDupSigFreeFunc);
3186  if (de_ctx->dup_sig_hash_table == NULL)
3187  return -1;
3188 
3189  return 0;
3190 }
3191 
3192 /**
3193  * \brief Frees the hash table that is used to cull duplicate sigs.
3194  *
3195  * \param de_ctx Pointer to the detection engine context that holds this table.
3196  */
3198 {
3199  if (de_ctx->dup_sig_hash_table != NULL)
3201 
3202  de_ctx->dup_sig_hash_table = NULL;
3203 }
3204 
3205 /**
3206  * \brief Check if a signature is a duplicate.
3207  *
3208  * There are 3 types of return values for this function.
3209  *
3210  * - 0, which indicates that the Signature is not a duplicate
3211  * and has to be added to the detection engine list.
3212  * - 1, Signature is duplicate, and the existing signature in
3213  * the list shouldn't be replaced with this duplicate.
3214  * - 2, Signature is duplicate, and the existing signature in
3215  * the list should be replaced with this duplicate.
3216  *
3217  * \param de_ctx Pointer to the detection engine context.
3218  * \param sig Pointer to the Signature that has to be checked.
3219  *
3220  * \retval 2 If Signature is duplicate and the existing signature in
3221  * the list should be chucked out and replaced with this.
3222  * \retval 1 If Signature is duplicate, and should be chucked out.
3223  * \retval 0 If Signature is not a duplicate.
3224  */
3225 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3226  Signature *sig)
3227 {
3228  /* we won't do any NULL checks on the args */
3229 
3230  /* return value */
3231  int ret = 0;
3232 
3233  SigDuplWrapper *sw_dup = NULL;
3234  SigDuplWrapper *sw = NULL;
3235 
3236  /* used for making a duplicate_sig_hash_table entry */
3237  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3238  if (unlikely(sw == NULL)) {
3239  exit(EXIT_FAILURE);
3240  }
3241  sw->s = sig;
3242 
3243  /* check if we have a duplicate entry for this signature */
3244  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3245  /* we don't have a duplicate entry for this sig */
3246  if (sw_dup == NULL) {
3247  /* add it to the hash table */
3248  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3249 
3250  /* add the s_prev entry for the previously loaded sw in the hash_table */
3251  if (de_ctx->sig_list != NULL) {
3252  SigDuplWrapper *sw_old = NULL;
3253  SigDuplWrapper sw_tmp;
3254  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3255 
3256  /* the topmost sig would be the last loaded sig */
3257  sw_tmp.s = de_ctx->sig_list;
3259  (void *)&sw_tmp, 0);
3260  /* sw_old == NULL case is impossible */
3261  sw_old->s_prev = sig;
3262  }
3263 
3264  ret = 0;
3265  goto end;
3266  }
3267 
3268  /* if we have reached here we have a duplicate entry for this signature.
3269  * Check the signature revision. Store the signature with the latest rev
3270  * and discard the other one */
3271  if (sw->s->rev <= sw_dup->s->rev) {
3272  ret = 1;
3273  SCFree(sw);
3274  sw = NULL;
3275  goto end;
3276  }
3277 
3278  /* the new sig is of a newer revision than the one that is already in the
3279  * list. Remove the old sig from the list */
3280  if (sw_dup->s_prev == NULL) {
3281  SigDuplWrapper sw_temp;
3282  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3283  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3284  sw_temp.s = sw_dup->s->next->next;
3285  de_ctx->sig_list = sw_dup->s->next->next;
3286  SigFree(de_ctx, sw_dup->s->next);
3287  } else {
3288  sw_temp.s = sw_dup->s->next;
3289  de_ctx->sig_list = sw_dup->s->next;
3290  }
3291  SigDuplWrapper *sw_next = NULL;
3292  if (sw_temp.s != NULL) {
3294  (void *)&sw_temp, 0);
3295  sw_next->s_prev = sw_dup->s_prev;
3296  }
3297  SigFree(de_ctx, sw_dup->s);
3298  } else {
3299  SigDuplWrapper sw_temp;
3300  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3301  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3302  sw_temp.s = sw_dup->s->next->next;
3303  /* If previous signature is bidirectional,
3304  * it has 2 items in the linked list.
3305  * So we need to change next->next instead of next
3306  */
3308  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3309  } else {
3310  sw_dup->s_prev->next = sw_dup->s->next->next;
3311  }
3312  SigFree(de_ctx, sw_dup->s->next);
3313  } else {
3314  sw_temp.s = sw_dup->s->next;
3316  sw_dup->s_prev->next->next = sw_dup->s->next;
3317  } else {
3318  sw_dup->s_prev->next = sw_dup->s->next;
3319  }
3320  }
3321  SigDuplWrapper *sw_next = NULL;
3322  if (sw_temp.s != NULL) {
3324  (void *)&sw_temp, 0);
3325  sw_next->s_prev = sw_dup->s_prev;
3326  }
3327  SigFree(de_ctx, sw_dup->s);
3328  }
3329 
3330  /* make changes to the entry to reflect the presence of the new sig */
3331  sw_dup->s = sig;
3332  sw_dup->s_prev = NULL;
3333 
3334  if (de_ctx->sig_list != NULL) {
3335  SigDuplWrapper sw_tmp;
3336  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3337  sw_tmp.s = de_ctx->sig_list;
3339  (void *)&sw_tmp, 0);
3340  if (sw_old->s != sw_dup->s) {
3341  // Link on top of the list if there was another element
3342  sw_old->s_prev = sig;
3343  }
3344  }
3345 
3346  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3347  ret = 2;
3348 
3349  SCFree(sw);
3350 
3351 end:
3352  return ret;
3353 }
3354 
3355 /**
3356  * \brief Parse and append a Signature into the Detection Engine Context
3357  * signature list.
3358  *
3359  * If the signature is bidirectional it should append two signatures
3360  * (with the addresses switched) into the list. Also handle duplicate
3361  * signatures. In case of duplicate sigs, use the ones that have the
3362  * latest revision. We use the sid and the msg to identify duplicate
3363  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3364  *
3365  * \param de_ctx Pointer to the Detection Engine Context.
3366  * \param sigstr Pointer to a character string containing the signature to be
3367  * parsed.
3368  * \param sig_file Pointer to a character string containing the filename from
3369  * which signature is read
3370  * \param lineno Line number from where signature is read
3371  *
3372  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3373  * on success; NULL on failure.
3374  */
3376 {
3377  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3378  if (sig == NULL) {
3379  return NULL;
3380  }
3381 
3382  /* checking for the status of duplicate signature */
3383  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3384  /* a duplicate signature that should be chucked out. Check the previously
3385  * called function details to understand the different return values */
3386  if (dup_sig == 1) {
3387  SCLogError("Duplicate signature \"%s\"", sigstr);
3388  goto error;
3389  } else if (dup_sig == 2) {
3390  SCLogWarning("Signature with newer revision,"
3391  " so the older sig replaced by this new signature \"%s\"",
3392  sigstr);
3393  }
3394 
3396  if (sig->next != NULL) {
3397  sig->next->next = de_ctx->sig_list;
3398  } else {
3399  goto error;
3400  }
3401  } else {
3402  /* if this sig is the first one, sig_list should be null */
3403  sig->next = de_ctx->sig_list;
3404  }
3405 
3406  de_ctx->sig_list = sig;
3407 
3408  /**
3409  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3410  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3411  * to the cloned signatures with the switched addresses
3412  */
3413  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3414 
3415 error:
3416  /* free the 2nd sig bidir may have set up */
3417  if (sig != NULL && sig->next != NULL) {
3418  SigFree(de_ctx, sig->next);
3419  sig->next = NULL;
3420  }
3421  if (sig != NULL) {
3422  SigFree(de_ctx, sig);
3423  }
3424  return NULL;
3425 }
3426 
3427 /**
3428  * \brief Parse and append a Signature into the Detection Engine Context
3429  * signature list.
3430  *
3431  * If the signature is bidirectional it should append two signatures
3432  * (with the addresses switched) into the list. Also handle duplicate
3433  * signatures. In case of duplicate sigs, use the ones that have the
3434  * latest revision. We use the sid and the msg to identify duplicate
3435  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3436  *
3437  * \param de_ctx Pointer to the Detection Engine Context.
3438  * \param sigstr Pointer to a character string containing the signature to be
3439  * parsed.
3440  * \param sig_file Pointer to a character string containing the filename from
3441  * which signature is read
3442  * \param lineno Line number from where signature is read
3443  *
3444  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3445  * on success; NULL on failure.
3446  */
3448 {
3449  Signature *sig = SigInit(de_ctx, sigstr);
3450  if (sig == NULL) {
3451  return NULL;
3452  }
3453 
3454  /* checking for the status of duplicate signature */
3455  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3456  /* a duplicate signature that should be chucked out. Check the previously
3457  * called function details to understand the different return values */
3458  if (dup_sig == 1) {
3459  SCLogError("Duplicate signature \"%s\"", sigstr);
3460  goto error;
3461  } else if (dup_sig == 2) {
3462  SCLogWarning("Signature with newer revision,"
3463  " so the older sig replaced by this new signature \"%s\"",
3464  sigstr);
3465  }
3466 
3468  if (sig->next != NULL) {
3469  sig->next->next = de_ctx->sig_list;
3470  } else {
3471  goto error;
3472  }
3473  } else {
3474  /* if this sig is the first one, sig_list should be null */
3475  sig->next = de_ctx->sig_list;
3476  }
3477 
3478  de_ctx->sig_list = sig;
3479 
3480  /**
3481  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3482  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3483  * to the cloned signatures with the switched addresses
3484  */
3485  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3486 
3487 error:
3488  /* free the 2nd sig bidir may have set up */
3489  if (sig != NULL && sig->next != NULL) {
3490  SigFree(de_ctx, sig->next);
3491  sig->next = NULL;
3492  }
3493  if (sig != NULL) {
3494  SigFree(de_ctx, sig);
3495  }
3496  return NULL;
3497 }
3498 
3499 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3500 
3501 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3502  int start_offset, int options)
3503 {
3504  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3505  if (*match)
3506  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3507  *match, parse_regex->context);
3508  return -1;
3509 }
3510 
3512 {
3513  if (r->regex) {
3514  pcre2_code_free(r->regex);
3515  }
3516  if (r->context) {
3517  pcre2_match_context_free(r->context);
3518  }
3519 }
3520 
3522 {
3523  DetectParseRegex *r = g_detect_parse_regex_list;
3524  while (r) {
3525  DetectParseRegex *next = r->next;
3526 
3528 
3529  SCFree(r);
3530  r = next;
3531  }
3532  g_detect_parse_regex_list = NULL;
3533 }
3534 
3535 /** \brief add regex and/or study to at exit free list
3536  */
3538 {
3539  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3540  if (r == NULL) {
3541  FatalError("failed to alloc memory for pcre free list");
3542  }
3543  r->regex = detect_parse->regex;
3544  r->next = g_detect_parse_regex_list;
3545  g_detect_parse_regex_list = r;
3546 }
3547 
3548 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3549 {
3550  int en;
3551  PCRE2_SIZE eo;
3552 
3553  detect_parse->regex =
3554  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3555  if (detect_parse->regex == NULL) {
3556  PCRE2_UCHAR errbuffer[256];
3557  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3558  SCLogError("pcre compile of \"%s\" failed at "
3559  "offset %d: %s",
3560  parse_str, en, errbuffer);
3561  return false;
3562  }
3563  detect_parse->context = pcre2_match_context_create(NULL);
3564  if (detect_parse->context == NULL) {
3565  SCLogError("pcre2 could not create match context");
3566  pcre2_code_free(detect_parse->regex);
3567  detect_parse->regex = NULL;
3568  return false;
3569  }
3570  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3571  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3572  DetectParseRegexAddToFreeList(detect_parse);
3573 
3574  return true;
3575 }
3576 
3577 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3578 {
3579  int en;
3580  PCRE2_SIZE eo;
3581  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3582  if (detect_parse == NULL) {
3583  return NULL;
3584  }
3585 
3586  detect_parse->regex =
3587  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3588  if (detect_parse->regex == NULL) {
3589  PCRE2_UCHAR errbuffer[256];
3590  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3591  SCLogError("pcre2 compile of \"%s\" failed at "
3592  "offset %d: %s",
3593  parse_str, (int)eo, errbuffer);
3594  SCFree(detect_parse);
3595  return NULL;
3596  }
3597 
3598  detect_parse->next = g_detect_parse_regex_list;
3599  g_detect_parse_regex_list = detect_parse;
3600  return detect_parse;
3601 }
3602 
3604  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3605 {
3606  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3607  if (r == PCRE2_ERROR_UNSET) {
3608  buffer[0] = 0;
3609  *bufflen = 0;
3610  return 0;
3611  }
3612  return r;
3613 }
3614 
3616  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3617 {
3618  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3619  if (r == PCRE2_ERROR_UNSET) {
3620  *bufferptr = NULL;
3621  *bufflen = 0;
3622  return 0;
3623  }
3624  return r;
3625 }
3626 
3627 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3628 {
3629  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3630  FatalError("pcre compile and study failed");
3631  }
3632 }
3633 
3634 /*
3635  * TESTS
3636  */
3637 
3638 #ifdef UNITTESTS
3639 #include "detect-engine-alert.h"
3640 #include "packet.h"
3641 
3642 static int SigParseTest01 (void)
3643 {
3644  int result = 1;
3645  Signature *sig = NULL;
3646 
3648  if (de_ctx == NULL)
3649  goto end;
3650 
3651  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3652  if (sig == NULL)
3653  result = 0;
3654 
3655 end:
3656  if (sig != NULL) SigFree(de_ctx, sig);
3657  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3658  return result;
3659 }
3660 
3661 static int SigParseTest02 (void)
3662 {
3663  int result = 0;
3664  Signature *sig = NULL;
3665  DetectPort *port = NULL;
3666 
3668 
3669  if (de_ctx == NULL)
3670  goto end;
3671 
3675 
3676  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;)");
3677  if (sig == NULL) {
3678  goto end;
3679  }
3680 
3681  int r = DetectPortParse(de_ctx, &port, "0:20");
3682  if (r < 0)
3683  goto end;
3684 
3685  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3686  result = 1;
3687  } else {
3688  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3689  }
3690 
3691 end:
3692  if (port != NULL)
3694  if (sig != NULL)
3695  SigFree(de_ctx, sig);
3696  if (de_ctx != NULL)
3698  return result;
3699 }
3700 
3701 /**
3702  * \test SigParseTest03 test for invalid direction operator in rule
3703  */
3704 static int SigParseTest03 (void)
3705 {
3706  int result = 1;
3707  Signature *sig = NULL;
3708 
3710  if (de_ctx == NULL)
3711  goto end;
3712 
3713  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3714  if (sig != NULL) {
3715  result = 0;
3716  printf("expected NULL got sig ptr %p: ",sig);
3717  }
3718 
3719 end:
3720  if (sig != NULL) SigFree(de_ctx, sig);
3721  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3722  return result;
3723 }
3724 
3725 static int SigParseTest04 (void)
3726 {
3727  int result = 1;
3728  Signature *sig = NULL;
3729 
3731  if (de_ctx == NULL)
3732  goto end;
3733 
3734  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3735  if (sig == NULL)
3736  result = 0;
3737 
3738 end:
3739  if (sig != NULL) SigFree(de_ctx, sig);
3740  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3741  return result;
3742 }
3743 
3744 /** \test Port validation */
3745 static int SigParseTest05 (void)
3746 {
3747  int result = 0;
3748  Signature *sig = NULL;
3749 
3751  if (de_ctx == NULL)
3752  goto end;
3753 
3754  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3755  if (sig == NULL) {
3756  result = 1;
3757  } else {
3758  printf("signature didn't fail to parse as we expected: ");
3759  }
3760 
3761 end:
3762  if (sig != NULL) SigFree(de_ctx, sig);
3763  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3764  return result;
3765 }
3766 
3767 /** \test Parsing bug debugging at 2010-03-18 */
3768 static int SigParseTest06 (void)
3769 {
3770  int result = 0;
3771  Signature *sig = NULL;
3772 
3774  if (de_ctx == NULL)
3775  goto end;
3776 
3777  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;)");
3778  if (sig != NULL) {
3779  result = 1;
3780  } else {
3781  printf("signature failed to parse: ");
3782  }
3783 
3784 end:
3785  if (sig != NULL)
3786  SigFree(de_ctx, sig);
3787  if (de_ctx != NULL)
3789  return result;
3790 }
3791 
3792 /**
3793  * \test Parsing duplicate sigs.
3794  */
3795 static int SigParseTest07(void)
3796 {
3797  int result = 0;
3798 
3800  if (de_ctx == NULL)
3801  goto end;
3802 
3803  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3804  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3805 
3806  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3807 
3808 end:
3809  if (de_ctx != NULL)
3811  return result;
3812 }
3813 
3814 /**
3815  * \test Parsing duplicate sigs.
3816  */
3817 static int SigParseTest08(void)
3818 {
3819  int result = 0;
3820 
3822  if (de_ctx == NULL)
3823  goto end;
3824 
3825  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3826  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3827 
3828  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3829  de_ctx->sig_list->rev == 2);
3830 
3831 end:
3832  if (de_ctx != NULL)
3834  return result;
3835 }
3836 
3837 /**
3838  * \test Parsing duplicate sigs.
3839  */
3840 static int SigParseTest09(void)
3841 {
3842  int result = 1;
3843 
3845  if (de_ctx == NULL)
3846  goto end;
3847 
3848  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3849  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3850  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3851  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3852  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3853  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3854  de_ctx->sig_list->rev == 2);
3855  if (result == 0)
3856  goto end;
3857  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3858  de_ctx->sig_list->next->rev == 6);
3859  if (result == 0)
3860  goto end;
3861 
3862  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3863  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3864  de_ctx->sig_list->rev == 2);
3865  if (result == 0)
3866  goto end;
3867  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3868  de_ctx->sig_list->next->rev == 6);
3869  if (result == 0)
3870  goto end;
3871 
3872  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3873  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3874  de_ctx->sig_list->rev == 4);
3875  if (result == 0)
3876  goto end;
3877  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3878  de_ctx->sig_list->next->rev == 6);
3879  if (result == 0)
3880  goto end;
3881 
3882 end:
3883  if (de_ctx != NULL)
3885  return result;
3886 }
3887 
3888 /**
3889  * \test Parsing duplicate sigs.
3890  */
3891 static int SigParseTest10(void)
3892 {
3893  int result = 1;
3894 
3896  if (de_ctx == NULL)
3897  goto end;
3898 
3899  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3900  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3901  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3902  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3903  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3904  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3905  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3906 
3907  result &= ((de_ctx->sig_list->id == 2) &&
3908  (de_ctx->sig_list->next->id == 3) &&
3909  (de_ctx->sig_list->next->next->id == 5) &&
3910  (de_ctx->sig_list->next->next->next->id == 4) &&
3911  (de_ctx->sig_list->next->next->next->next->id == 1));
3912 
3913 end:
3914  if (de_ctx != NULL)
3916  return result;
3917 }
3918 
3919 /**
3920  * \test Parsing sig with trailing space(s) as reported by
3921  * Morgan Cox on oisf-users.
3922  */
3923 static int SigParseTest11(void)
3924 {
3925  int result = 0;
3926 
3928  if (de_ctx == NULL)
3929  goto end;
3930 
3931  Signature *s = NULL;
3932 
3934  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3935  if (s == NULL) {
3936  printf("sig 1 didn't parse: ");
3937  goto end;
3938  }
3939 
3940  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3941  "the http link\"; sid:2;) ");
3942  if (s == NULL) {
3943  printf("sig 2 didn't parse: ");
3944  goto end;
3945  }
3946 
3947  result = 1;
3948 end:
3949  if (de_ctx != NULL)
3951  return result;
3952 }
3953 
3954 /**
3955  * \test file_data with rawbytes
3956  */
3957 static int SigParseTest12(void)
3958 {
3959  int result = 0;
3960 
3962  if (de_ctx == NULL)
3963  goto end;
3964 
3965  Signature *s = NULL;
3966 
3967  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3968  if (s != NULL) {
3969  printf("sig 1 should have given an error: ");
3970  goto end;
3971  }
3972 
3973  result = 1;
3974 end:
3975  if (de_ctx != NULL)
3977  return result;
3978 }
3979 
3980 /**
3981  * \test packet/stream sig
3982  */
3983 static int SigParseTest13(void)
3984 {
3985  int result = 0;
3986 
3988  if (de_ctx == NULL)
3989  goto end;
3990 
3991  Signature *s = NULL;
3992 
3993  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
3994  if (s == NULL) {
3995  printf("sig 1 invalidated: failure");
3996  goto end;
3997  }
3998 
3999  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4000  printf("sig doesn't have stream flag set\n");
4001  goto end;
4002  }
4003 
4004  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
4005  printf("sig has packet flag set\n");
4006  goto end;
4007  }
4008 
4009  result = 1;
4010 
4011 end:
4012  if (de_ctx != NULL)
4014  return result;
4015 }
4016 
4017 /**
4018  * \test packet/stream sig
4019  */
4020 static int SigParseTest14(void)
4021 {
4022  int result = 0;
4023 
4025  if (de_ctx == NULL)
4026  goto end;
4027 
4028  Signature *s = NULL;
4029 
4030  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4031  if (s == NULL) {
4032  printf("sig 1 invalidated: failure");
4033  goto end;
4034  }
4035 
4036  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4037  printf("sig doesn't have packet flag set\n");
4038  goto end;
4039  }
4040 
4041  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4042  printf("sig has stream flag set\n");
4043  goto end;
4044  }
4045 
4046  result = 1;
4047 
4048 end:
4049  if (de_ctx != NULL)
4051  return result;
4052 }
4053 
4054 /**
4055  * \test packet/stream sig
4056  */
4057 static int SigParseTest15(void)
4058 {
4059  int result = 0;
4060 
4062  if (de_ctx == NULL)
4063  goto end;
4064 
4065  Signature *s = NULL;
4066 
4067  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4068  if (s == NULL) {
4069  printf("sig 1 invalidated: failure");
4070  goto end;
4071  }
4072 
4073  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4074  printf("sig doesn't have packet flag set\n");
4075  goto end;
4076  }
4077 
4078  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4079  printf("sig doesn't have stream flag set\n");
4080  goto end;
4081  }
4082 
4083  result = 1;
4084 
4085 end:
4086  if (de_ctx != NULL)
4088  return result;
4089 }
4090 
4091 /**
4092  * \test packet/stream sig
4093  */
4094 static int SigParseTest16(void)
4095 {
4096  int result = 0;
4097 
4099  if (de_ctx == NULL)
4100  goto end;
4101 
4102  Signature *s = NULL;
4103 
4104  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4105  if (s == NULL) {
4106  printf("sig 1 invalidated: failure");
4107  goto end;
4108  }
4109 
4110  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4111  printf("sig doesn't have packet flag set\n");
4112  goto end;
4113  }
4114 
4115  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4116  printf("sig doesn't have stream flag set\n");
4117  goto end;
4118  }
4119 
4120  result = 1;
4121 
4122 end:
4123  if (de_ctx != NULL)
4125  return result;
4126 }
4127 
4128 /**
4129  * \test packet/stream sig
4130  */
4131 static int SigParseTest17(void)
4132 {
4133  int result = 0;
4134 
4136  if (de_ctx == NULL)
4137  goto end;
4138 
4139  Signature *s = NULL;
4140 
4141  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4142  if (s == NULL) {
4143  printf("sig 1 invalidated: failure");
4144  goto end;
4145  }
4146 
4147  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4148  printf("sig doesn't have packet flag set\n");
4149  goto end;
4150  }
4151 
4152  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4153  printf("sig doesn't have stream flag set\n");
4154  goto end;
4155  }
4156 
4157  result = 1;
4158 
4159 end:
4160  if (de_ctx != NULL)
4162  return result;
4163 }
4164 
4165 /** \test sid value too large. Bug #779 */
4166 static int SigParseTest18 (void)
4167 {
4168  int result = 0;
4169 
4171  if (de_ctx == NULL)
4172  goto end;
4173 
4174  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4175  goto end;
4176 
4177  result = 1;
4178 end:
4179  if (de_ctx != NULL)
4181  return result;
4182 }
4183 
4184 /** \test gid value too large. Related to bug #779 */
4185 static int SigParseTest19 (void)
4186 {
4187  int result = 0;
4188 
4190  if (de_ctx == NULL)
4191  goto end;
4192 
4193  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4194  goto end;
4195 
4196  result = 1;
4197 end:
4198  if (de_ctx != NULL)
4200  return result;
4201 }
4202 
4203 /** \test rev value too large. Related to bug #779 */
4204 static int SigParseTest20 (void)
4205 {
4206  int result = 0;
4207 
4209  if (de_ctx == NULL)
4210  goto end;
4211 
4212  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4213  goto end;
4214 
4215  result = 1;
4216 end:
4217  if (de_ctx != NULL)
4219  return result;
4220 }
4221 
4222 /** \test address parsing */
4223 static int SigParseTest21 (void)
4224 {
4225  int result = 0;
4226 
4228  if (de_ctx == NULL)
4229  goto end;
4230 
4231  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4232  goto end;
4233 
4234  result = 1;
4235 end:
4236  if (de_ctx != NULL)
4238  return result;
4239 }
4240 
4241 /** \test address parsing */
4242 static int SigParseTest22 (void)
4243 {
4244  int result = 0;
4245 
4247  if (de_ctx == NULL)
4248  goto end;
4249 
4250  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)
4251  goto end;
4252 
4253  result = 1;
4254 end:
4255  if (de_ctx != NULL)
4257  return result;
4258 }
4259 
4260 /**
4261  * \test rule ending in carriage return
4262  */
4263 static int SigParseTest23(void)
4264 {
4267 
4268  Signature *s = NULL;
4269 
4270  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4271  FAIL_IF_NULL(s);
4272 
4274  PASS;
4275 }
4276 
4277 /** \test Direction operator validation (invalid) */
4278 static int SigParseBidirecTest06 (void)
4279 {
4280  int result = 1;
4281  Signature *sig = NULL;
4282 
4284  if (de_ctx == NULL)
4285  goto end;
4286 
4287  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4288  if (sig == NULL)
4289  result = 1;
4290 
4291 end:
4292  if (sig != NULL) SigFree(de_ctx, sig);
4293  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4294  return result;
4295 }
4296 
4297 /** \test Direction operator validation (invalid) */
4298 static int SigParseBidirecTest07 (void)
4299 {
4300  int result = 1;
4301  Signature *sig = NULL;
4302 
4304  if (de_ctx == NULL)
4305  goto end;
4306 
4307  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4308  if (sig == NULL)
4309  result = 1;
4310 
4311 end:
4312  if (sig != NULL) SigFree(de_ctx, sig);
4313  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4314  return result;
4315 }
4316 
4317 /** \test Direction operator validation (invalid) */
4318 static int SigParseBidirecTest08 (void)
4319 {
4320  int result = 1;
4321  Signature *sig = NULL;
4322 
4324  if (de_ctx == NULL)
4325  goto end;
4326 
4327  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4328  if (sig == NULL)
4329  result = 1;
4330 
4331 end:
4332  if (sig != NULL) SigFree(de_ctx, sig);
4333  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4334  return result;
4335 }
4336 
4337 /** \test Direction operator validation (invalid) */
4338 static int SigParseBidirecTest09 (void)
4339 {
4340  int result = 1;
4341  Signature *sig = NULL;
4342 
4344  if (de_ctx == NULL)
4345  goto end;
4346 
4347  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4348  if (sig == NULL)
4349  result = 1;
4350 
4351 end:
4352  if (sig != NULL) SigFree(de_ctx, sig);
4353  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4354  return result;
4355 }
4356 
4357 /** \test Direction operator validation (invalid) */
4358 static int SigParseBidirecTest10 (void)
4359 {
4360  int result = 1;
4361  Signature *sig = NULL;
4362 
4364  if (de_ctx == NULL)
4365  goto end;
4366 
4367  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4368  if (sig == NULL)
4369  result = 1;
4370 
4371 end:
4372  if (sig != NULL) SigFree(de_ctx, sig);
4373  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4374  return result;
4375 }
4376 
4377 /** \test Direction operator validation (invalid) */
4378 static int SigParseBidirecTest11 (void)
4379 {
4380  int result = 1;
4381  Signature *sig = NULL;
4382 
4384  if (de_ctx == NULL)
4385  goto end;
4386 
4387  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4388  if (sig == NULL)
4389  result = 1;
4390 
4391 end:
4392  if (sig != NULL) SigFree(de_ctx, sig);
4393  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4394  return result;
4395 }
4396 
4397 /** \test Direction operator validation (invalid) */
4398 static int SigParseBidirecTest12 (void)
4399 {
4400  int result = 1;
4401  Signature *sig = NULL;
4402 
4404  if (de_ctx == NULL)
4405  goto end;
4406 
4407  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4408  if (sig == NULL)
4409  result = 1;
4410 
4411 end:
4412  if (sig != NULL) SigFree(de_ctx, sig);
4413  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4414  return result;
4415 }
4416 
4417 /** \test Direction operator validation (valid) */
4418 static int SigParseBidirecTest13 (void)
4419 {
4420  int result = 1;
4421  Signature *sig = NULL;
4422 
4424  if (de_ctx == NULL)
4425  goto end;
4426 
4427  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4428  if (sig != NULL)
4429  result = 1;
4430 
4431 end:
4432  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4433  return result;
4434 }
4435 
4436 /** \test Direction operator validation (valid) */
4437 static int SigParseBidirecTest14 (void)
4438 {
4439  int result = 1;
4440  Signature *sig = NULL;
4441 
4443  if (de_ctx == NULL)
4444  goto end;
4445 
4446  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4447  if (sig != NULL)
4448  result = 1;
4449 
4450 end:
4451  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4452  return result;
4453 }
4454 
4455 /** \test Ensure that we don't set bidirectional in a
4456  * normal (one direction) Signature
4457  */
4458 static int SigTestBidirec01 (void)
4459 {
4460  Signature *sig = NULL;
4461  int result = 0;
4462 
4464  if (de_ctx == NULL)
4465  goto end;
4466 
4467  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4468  if (sig == NULL)
4469  goto end;
4470  if (sig->next != NULL)
4471  goto end;
4473  goto end;
4474  if (de_ctx->signum != 1)
4475  goto end;
4476 
4477  result = 1;
4478 
4479 end:
4480  if (de_ctx != NULL) {
4484  }
4485  return result;
4486 }
4487 
4488 /** \test Ensure that we set a bidirectional Signature correctly */
4489 static int SigTestBidirec02 (void)
4490 {
4491  int result = 0;
4492  Signature *sig = NULL;
4493  Signature *copy = NULL;
4494 
4496  if (de_ctx == NULL)
4497  goto end;
4498 
4499  de_ctx->flags |= DE_QUIET;
4500 
4501  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4502  if (sig == NULL)
4503  goto end;
4504  if (de_ctx->sig_list != sig)
4505  goto end;
4507  goto end;
4508  if (sig->next == NULL)
4509  goto end;
4510  if (de_ctx->signum != 2)
4511  goto end;
4512  copy = sig->next;
4513  if (copy->next != NULL)
4514  goto end;
4515  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4516  goto end;
4517 
4518  result = 1;
4519 
4520 end:
4521  if (de_ctx != NULL) {
4525  }
4526 
4527  return result;
4528 }
4529 
4530 /** \test Ensure that we set a bidirectional Signature correctly
4531 * and we install it with the rest of the signatures, checking
4532 * also that it match with the correct addr directions
4533 */
4534 static int SigTestBidirec03 (void)
4535 {
4536  int result = 0;
4537  Signature *sig = NULL;
4538  Packet *p = NULL;
4539 
4541  if (de_ctx == NULL)
4542  goto end;
4543 
4544  de_ctx->flags |= DE_QUIET;
4545 
4546  const char *sigs[3];
4547  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4548  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4549  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4550  UTHAppendSigs(de_ctx, sigs, 3);
4551 
4552  /* Checking that bidirectional rules are set correctly */
4553  sig = de_ctx->sig_list;
4554  if (sig == NULL)
4555  goto end;
4556  if (sig->next == NULL)
4557  goto end;
4558  if (sig->next->next == NULL)
4559  goto end;
4560  if (sig->next->next->next == NULL)
4561  goto end;
4562  if (sig->next->next->next->next != NULL)
4563  goto end;
4564  if (de_ctx->signum != 4)
4565  goto end;
4566 
4567  uint8_t rawpkt1_ether[] = {
4568  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4569  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4570  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4571  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4572  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4573  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4574  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4575  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4576  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4577  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4578  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4579  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4580  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4581  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4582  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4583  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4584  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4585  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4586  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4587  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4588  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4589  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4590  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4591  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4592  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4593  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4594  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4595  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4596  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4597  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4598  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4599  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4600  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4601  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4602  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4603  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4604  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4605  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4606  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4607  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4608  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4609  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4610  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4611  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4612  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4613  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4614  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4615  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4616  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4617  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4618  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4619  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4620  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4621  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4622  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4623 
4625  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4626  if (p == NULL) {
4627  SCLogDebug("Error building packet");
4628  goto end;
4629  }
4630  UTHMatchPackets(de_ctx, &p, 1);
4631 
4632  uint32_t sids[3] = {1, 2, 3};
4633  uint32_t results[3] = {1, 1, 1};
4634  result = UTHCheckPacketMatchResults(p, sids, results, 1);
4635 
4636 end:
4637  if (p != NULL) {
4638  PacketFree(p);
4639  }
4641  FlowShutdown();
4642  return result;
4643 }
4644 
4645 /** \test Ensure that we set a bidirectional Signature correctly
4646 * and we install it with the rest of the signatures, checking
4647 * also that it match with the correct addr directions
4648 */
4649 static int SigTestBidirec04 (void)
4650 {
4651  int result = 0;
4652  Signature *sig = NULL;
4653  Packet *p = NULL;
4654 
4656  if (de_ctx == NULL)
4657  goto end;
4658 
4659  de_ctx->flags |= DE_QUIET;
4660 
4661  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4662  if (sig == NULL)
4663  goto end;
4664  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4665  if (sig == NULL)
4666  goto end;
4667  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4668  goto end;
4669  if (sig->next == NULL)
4670  goto end;
4671  if (sig->next->next == NULL)
4672  goto end;
4673  if (sig->next->next->next != NULL)
4674  goto end;
4675  if (de_ctx->signum != 3)
4676  goto end;
4677 
4678  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4679  if (sig == NULL)
4680  goto end;
4681  if (sig->next == NULL)
4682  goto end;
4683  if (sig->next->next == NULL)
4684  goto end;
4685  if (sig->next->next->next == NULL)
4686  goto end;
4687  if (sig->next->next->next->next != NULL)
4688  goto end;
4689  if (de_ctx->signum != 4)
4690  goto end;
4691 
4692  uint8_t rawpkt1_ether[] = {
4693  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4694  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4695  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4696  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4697  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4698  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4699  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4700  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4701  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4702  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4703  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4704  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4705  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4706  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4707  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4708  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4709  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4710  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4711  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4712  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4713  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4714  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4715  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4716  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4717  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4718  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4719  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4720  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4721  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4722  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4723  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4724  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4725  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4726  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4727  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4728  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4729  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4730  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4731  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4732  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4733  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4734  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4735  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4736  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4737  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4738  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4739  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4740  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4741  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4742  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4743  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4744  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4745  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4746  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4747  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4748 
4749  p = PacketGetFromAlloc();
4750  if (unlikely(p == NULL))
4751  return 0;
4753  ThreadVars th_v;
4754  DetectEngineThreadCtx *det_ctx;
4755 
4756  memset(&th_v, 0, sizeof(th_v));
4757  StatsThreadInit(&th_v.stats);
4758 
4760  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4761  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4762 
4763  /* At this point we have a list of 4 signatures. The last one
4764  is a copy of the second one. If we receive a packet
4765  with source 192.168.1.1 80, all the sids should match */
4766 
4768  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4769 
4770  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4771  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4772  PacketAlertCheck(p, 2) == 1) {
4773  result = 1;
4774  }
4775 
4776  if (p != NULL) {
4777  PacketRecycle(p);
4778  }
4779  FlowShutdown();
4780  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4781 
4782 end:
4783  if (de_ctx != NULL) {
4785  }
4786 
4787  if (p != NULL)
4788  PacketFree(p);
4789  StatsThreadCleanup(&th_v.stats);
4790  return result;
4791 }
4792 
4793 /**
4794  * \test check that we don't allow invalid negation options
4795  */
4796 static int SigParseTestNegation01 (void)
4797 {
4800  de_ctx->flags |= DE_QUIET;
4801  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4802  FAIL_IF_NOT_NULL(s);
4804  PASS;
4805 }
4806 
4807 /**
4808  * \test check that we don't allow invalid negation options
4809  */
4810 static int SigParseTestNegation02 (void)
4811 {
4812  int result = 0;
4814  Signature *s=NULL;
4815 
4817  if (de_ctx == NULL)
4818  goto end;
4819  de_ctx->flags |= DE_QUIET;
4820 
4821  s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)");
4822  if (s != NULL) {
4823  SigFree(de_ctx, s);
4824  goto end;
4825  }
4826 
4827  result = 1;
4828 end:
4829  if (de_ctx != NULL)
4831  return result;
4832 }
4833 /**
4834  * \test check that we don't allow invalid negation options
4835  */
4836 static int SigParseTestNegation03 (void)
4837 {
4838  int result = 0;
4840  Signature *s=NULL;
4841 
4843  if (de_ctx == NULL)
4844  goto end;
4845  de_ctx->flags |= DE_QUIET;
4846 
4847  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;)");
4848  if (s != NULL) {
4849  SigFree(de_ctx, s);
4850  goto end;
4851  }
4852 
4853  result = 1;
4854 end:
4855  if (de_ctx != NULL)
4857  return result;
4858 }
4859 /**
4860  * \test check that we don't allow invalid negation options
4861  */
4862 static int SigParseTestNegation04 (void)
4863 {
4864  int result = 0;
4866  Signature *s=NULL;
4867 
4869  if (de_ctx == NULL)
4870  goto end;
4871  de_ctx->flags |= DE_QUIET;
4872 
4873  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;)");
4874  if (s != NULL) {
4875  SigFree(de_ctx, s);
4876  goto end;
4877  }
4878 
4879  result = 1;
4880 end:
4881  if (de_ctx != NULL)
4883  return result;
4884 }
4885 /**
4886  * \test check that we don't allow invalid negation options
4887  */
4888 static int SigParseTestNegation05 (void)
4889 {
4890  int result = 0;
4892  Signature *s=NULL;
4893 
4895  if (de_ctx == NULL)
4896  goto end;
4897  de_ctx->flags |= DE_QUIET;
4898 
4899  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;)");
4900  if (s != NULL) {
4901  SigFree(de_ctx, s);
4902  goto end;
4903  }
4904 
4905  result = 1;
4906 end:
4907  if (de_ctx != NULL)
4909  return result;
4910 }
4911 /**
4912  * \test check that we don't allow invalid negation options
4913  */
4914 static int SigParseTestNegation06 (void)
4915 {
4916  int result = 0;
4918  Signature *s=NULL;
4919 
4921  if (de_ctx == NULL)
4922  goto end;
4923  de_ctx->flags |= DE_QUIET;
4924 
4925  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;)");
4926  if (s != NULL) {
4927  SigFree(de_ctx, s);
4928  goto end;
4929  }
4930 
4931  result = 1;
4932 end:
4933  if (de_ctx != NULL)
4935  return result;
4936 }
4937 
4938 /**
4939  * \test check that we don't allow invalid negation options
4940  */
4941 static int SigParseTestNegation07 (void)
4942 {
4945  de_ctx->flags |= DE_QUIET;
4947  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4948  FAIL_IF_NOT_NULL(s);
4950  PASS;
4951 }
4952 
4953 /**
4954  * \test check valid negation bug 1079
4955  */
4956 static int SigParseTestNegation08 (void)
4957 {
4958  int result = 0;
4960  Signature *s=NULL;
4961 
4963  if (de_ctx == NULL)
4964  goto end;
4965  de_ctx->flags |= DE_QUIET;
4966 
4968  "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4969  if (s == NULL) {
4970  goto end;
4971  }
4972 
4973  result = 1;
4974 end:
4975  if (de_ctx != NULL)
4977  return result;
4978 }
4979 
4980 /**
4981  * \test mpm
4982  */
4983 static int SigParseTestMpm01 (void)
4984 {
4985  int result = 0;
4986  Signature *sig = NULL;
4987 
4989  if (de_ctx == NULL)
4990  goto end;
4991 
4992  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
4993  if (sig == NULL) {
4994  printf("sig failed to init: ");
4995  goto end;
4996  }
4997 
4998  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4999  printf("sig doesn't have content list: ");
5000  goto end;
5001  }
5002 
5003  result = 1;
5004 end:
5005  if (sig != NULL)
5006  SigFree(de_ctx, sig);
5008  return result;
5009 }
5010 
5011 /**
5012  * \test mpm
5013  */
5014 static int SigParseTestMpm02 (void)
5015 {
5016  int result = 0;
5017  Signature *sig = NULL;
5018 
5020  if (de_ctx == NULL)
5021  goto end;
5022 
5023  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5024  if (sig == NULL) {
5025  printf("sig failed to init: ");
5026  goto end;
5027  }
5028 
5029  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5030  printf("sig doesn't have content list: ");
5031  goto end;
5032  }
5033 
5034  result = 1;
5035 end:
5036  if (sig != NULL)
5037  SigFree(de_ctx, sig);
5039  return result;
5040 }
5041 
5042 /**
5043  * \test test tls (app layer) rule
5044  */
5045 static int SigParseTestAppLayerTLS01(void)
5046 {
5047  int result = 0;
5049  Signature *s=NULL;
5050 
5052  if (de_ctx == NULL)
5053  goto end;
5054  de_ctx->flags |= DE_QUIET;
5055 
5056  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5057  if (s == NULL) {
5058  printf("parsing sig failed: ");
5059  goto end;
5060  }
5061 
5062  if (s->alproto == 0) {
5063  printf("alproto not set: ");
5064  goto end;
5065  }
5066 
5067  result = 1;
5068 end:
5069  if (s != NULL)
5070  SigFree(de_ctx, s);
5071  if (de_ctx != NULL)
5073 
5074  return result;
5075 }
5076 
5077 /**
5078  * \test test tls (app layer) rule
5079  */
5080 static int SigParseTestAppLayerTLS02(void)
5081 {
5082  int result = 0;
5084  Signature *s=NULL;
5085 
5087  if (de_ctx == NULL)
5088  goto end;
5089  de_ctx->flags |= DE_QUIET;
5090 
5091  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5092  if (s == NULL) {
5093  printf("parsing sig failed: ");
5094  goto end;
5095  }
5096 
5097  if (s->alproto == 0) {
5098  printf("alproto not set: ");
5099  goto end;
5100  }
5101 
5102  result = 1;
5103 end:
5104  if (s != NULL)
5105  SigFree(de_ctx, s);
5106  if (de_ctx != NULL)
5108  return result;
5109 }
5110 
5111 /**
5112  * \test test tls (app layer) rule
5113  */
5114 static int SigParseTestAppLayerTLS03(void)
5115 {
5116  int result = 0;
5118  Signature *s=NULL;
5119 
5121  if (de_ctx == NULL)
5122  goto end;
5123  de_ctx->flags |= DE_QUIET;
5124 
5125  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)");
5126  if (s != NULL) {
5127  SigFree(de_ctx, s);
5128  goto end;
5129  }
5130 
5131  result = 1;
5132 end:
5133  if (de_ctx != NULL)
5135  return result;
5136 }
5137 
5138 static int SigParseTestUnbalancedQuotes01(void)
5139 {
5142  de_ctx->flags |= DE_QUIET;
5144  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5145  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5146  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5147  FAIL_IF_NOT_NULL(s);
5149  PASS;
5150 }
5151 
5152 static int SigParseTestContentGtDsize01(void)
5153 {
5156  de_ctx->flags |= DE_QUIET;
5157  Signature *s =
5158  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5159  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5160  "sid:1; rev:1;)");
5161  FAIL_IF_NOT_NULL(s);
5163  PASS;
5164 }
5165 
5166 static int SigParseTestContentGtDsize02(void)
5167 {
5170  de_ctx->flags |= DE_QUIET;
5171  Signature *s =
5172  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5173  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5174  "sid:1; rev:1;)");
5175  FAIL_IF_NOT_NULL(s);
5177  PASS;
5178 }
5179 
5180 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5181 {
5182  int cnt = 0;
5183  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5184  if (sid == s->id)
5185  cnt++;
5186  }
5187  return cnt;
5188 }
5189 
5190 static int SigParseBidirWithSameSrcAndDest01(void)
5191 {
5194  de_ctx->flags |= DE_QUIET;
5195 
5196  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5197  FAIL_IF_NULL(s);
5198  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5200 
5201  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5202  FAIL_IF_NULL(s);
5203  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5205 
5207  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5208  FAIL_IF_NULL(s);
5209  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5211 
5213  PASS;
5214 }
5215 
5216 static int SigParseBidirWithSameSrcAndDest02(void)
5217 {
5220  de_ctx->flags |= DE_QUIET;
5221 
5222  // Source is a subset of destination
5224  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5225  FAIL_IF_NULL(s);
5226  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5228 
5229  // Source is a subset of destination
5231  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5232  FAIL_IF_NULL(s);
5233  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5235 
5236  // Source intersects with destination
5238  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5239  FAIL_IF_NULL(s);
5240  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5242 
5243  // mix in negation, these are the same
5245  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;)");
5246  FAIL_IF_NULL(s);
5247  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5249 
5250  // mix in negation, these are not the same
5252  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;)");
5253  FAIL_IF_NULL(s);
5254  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5256 
5258  PASS;
5259 }
5260 
5261 static int SigParseTestActionReject(void)
5262 {
5265 
5267  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5268 #ifdef HAVE_LIBNET11
5269  FAIL_IF_NULL(sig);
5271 #else
5272  FAIL_IF_NOT_NULL(sig);
5273 #endif
5274 
5276  PASS;
5277 }
5278 
5279 static int SigParseTestActionDrop(void)
5280 {
5283 
5285  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5286  FAIL_IF_NULL(sig);
5287  FAIL_IF_NOT(sig->action & ACTION_DROP);
5288 
5290  PASS;
5291 }
5292 
5293 static int SigSetMultiAppProto(void)
5294 {
5295  Signature *s = SigAlloc();
5296  FAIL_IF_NULL(s);
5297 
5298  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5299  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5300 
5301  // check intersection gives multiple entries
5302  alprotos[0] = 3;
5303  alprotos[1] = 2;
5304  alprotos[2] = ALPROTO_UNKNOWN;
5305  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5306  FAIL_IF(s->init_data->alprotos[0] != 3);
5307  FAIL_IF(s->init_data->alprotos[1] != 2);
5309 
5310  // check single after multiple
5313  FAIL_IF(s->alproto != 3);
5314  alprotos[0] = 4;
5315  alprotos[1] = 3;
5316  alprotos[2] = ALPROTO_UNKNOWN;
5317  // check multiple containing singleton
5318  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5319  FAIL_IF(s->alproto != 3);
5320 
5321  // reset
5322  s->alproto = ALPROTO_UNKNOWN;
5323  alprotos[0] = 1;
5324  alprotos[1] = 2;
5325  alprotos[2] = 3;
5326  alprotos[3] = ALPROTO_UNKNOWN;
5327  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5328  // fail if set single not in multiple
5330 
5332  s->alproto = ALPROTO_UNKNOWN;
5333  alprotos[0] = 1;
5334  alprotos[1] = 2;
5335  alprotos[2] = 3;
5336  alprotos[3] = ALPROTO_UNKNOWN;
5337  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5338  alprotos[0] = 4;
5339  alprotos[1] = 5;
5340  alprotos[2] = ALPROTO_UNKNOWN;
5341  // fail if multiple do not have intersection
5342  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5343 
5345  s->alproto = ALPROTO_UNKNOWN;
5346  alprotos[0] = 1;
5347  alprotos[1] = 2;
5348  alprotos[2] = 3;
5349  alprotos[3] = ALPROTO_UNKNOWN;
5350  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5351  alprotos[0] = 3;
5352  alprotos[1] = 4;
5353  alprotos[2] = 5;
5354  alprotos[3] = ALPROTO_UNKNOWN;
5355  // check multiple intersect to singleton
5356  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5357  FAIL_IF(s->alproto != 3);
5358  alprotos[0] = 5;
5359  alprotos[1] = 4;
5360  alprotos[2] = ALPROTO_UNKNOWN;
5361  // fail if multiple do not belong to singleton
5362  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5363 
5364  SigFree(NULL, s);
5365  PASS;
5366 }
5367 
5368 static int DetectSetupDirection01(void)
5369 {
5370  Signature *s = SigAlloc();
5371  FAIL_IF_NULL(s);
5372  // Basic case : ok
5373  char *str = (char *)"to_client";
5374  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5375  SigFree(NULL, s);
5376  PASS;
5377 }
5378 
5379 static int DetectSetupDirection02(void)
5380 {
5381  Signature *s = SigAlloc();
5382  FAIL_IF_NULL(s);
5383  char *str = (char *)"to_server";
5384  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5385  // ok so far
5386  str = (char *)"to_client";
5387  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5388  // fails because we cannot have both to_client and to_server for same signature
5389  SigFree(NULL, s);
5390  PASS;
5391 }
5392 
5393 static int DetectSetupDirection03(void)
5394 {
5395  Signature *s = SigAlloc();
5396  FAIL_IF_NULL(s);
5397  char *str = (char *)"to_client , something";
5398  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5399  FAIL_IF(strcmp(str, "something") != 0);
5400  str = (char *)"to_client,something";
5401  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5402  FAIL_IF(strcmp(str, "something") != 0);
5403  SigFree(NULL, s);
5404  PASS;
5405 }
5406 
5407 static int DetectSetupDirection04(void)
5408 {
5409  Signature *s = SigAlloc();
5410  FAIL_IF_NULL(s);
5411  // invalid case
5412  char *str = (char *)"to_client_toto";
5413  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5414  // test we do not change the string pointer if only_dir is false
5415  str = (char *)"to_client_toto";
5416  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5417  FAIL_IF(strcmp(str, "to_client_toto") != 0);
5418  str = (char *)"to_client,something";
5419  // fails because we call with only_dir=true
5420  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5421  SigFree(NULL, s);
5422  PASS;
5423 }
5424 
5425 #endif /* UNITTESTS */
5426 
5427 #ifdef UNITTESTS
5428 void DetectParseRegisterTests (void);
5429 #include "tests/detect-parse.c"
5430 #endif
5431 
5433 {
5434 #ifdef UNITTESTS
5436 
5437  UtRegisterTest("SigParseTest01", SigParseTest01);
5438  UtRegisterTest("SigParseTest02", SigParseTest02);
5439  UtRegisterTest("SigParseTest03", SigParseTest03);
5440  UtRegisterTest("SigParseTest04", SigParseTest04);
5441  UtRegisterTest("SigParseTest05", SigParseTest05);
5442  UtRegisterTest("SigParseTest06", SigParseTest06);
5443  UtRegisterTest("SigParseTest07", SigParseTest07);
5444  UtRegisterTest("SigParseTest08", SigParseTest08);
5445  UtRegisterTest("SigParseTest09", SigParseTest09);
5446  UtRegisterTest("SigParseTest10", SigParseTest10);
5447  UtRegisterTest("SigParseTest11", SigParseTest11);
5448  UtRegisterTest("SigParseTest12", SigParseTest12);
5449  UtRegisterTest("SigParseTest13", SigParseTest13);
5450  UtRegisterTest("SigParseTest14", SigParseTest14);
5451  UtRegisterTest("SigParseTest15", SigParseTest15);
5452  UtRegisterTest("SigParseTest16", SigParseTest16);
5453  UtRegisterTest("SigParseTest17", SigParseTest17);
5454  UtRegisterTest("SigParseTest18", SigParseTest18);
5455  UtRegisterTest("SigParseTest19", SigParseTest19);
5456  UtRegisterTest("SigParseTest20", SigParseTest20);
5457  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5458  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5459  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5460 
5461  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5462  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5463  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5464  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5465  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5466  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5467  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5468  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5469  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5470  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5471  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5472  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5473  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5474  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5475  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5476  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5477  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5478  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5479  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5480  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5481  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5482  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5483  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5484  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5485  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5486  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5487  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5488 
5489  UtRegisterTest("SigParseTestContentGtDsize01",
5490  SigParseTestContentGtDsize01);
5491  UtRegisterTest("SigParseTestContentGtDsize02",
5492  SigParseTestContentGtDsize02);
5493 
5494  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5495  SigParseBidirWithSameSrcAndDest01);
5496  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5497  SigParseBidirWithSameSrcAndDest02);
5498  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5499  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5500 
5501  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5502 
5503  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5504  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5505  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5506  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5507 
5508 #endif /* UNITTESTS */
5509 }
DetectAddressListsAreEqual
bool DetectAddressListsAreEqual(DetectAddress *list1, DetectAddress *list2)
Checks if two address group lists are equal.
Definition: detect-engine-address.c:348
DetectIPProtoRemoveAllSMs
void DetectIPProtoRemoveAllSMs(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-ipproto.c:430
DETECT_TABLE_APP_TD
@ DETECT_TABLE_APP_TD
Definition: detect.h:559
SignatureParser_
Definition: detect-parse.c:101
SignatureInitData_::max_content_list_id
uint32_t max_content_list_id
Definition: detect.h:653
host.h
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:659
DetectPortCmp
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
Definition: detect-engine-port.c:497
DetectEngineAppInspectionEngine_
Definition: detect.h:416
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:534
SigMatch_::prev
struct SigMatch_ * prev
Definition: detect.h:361
detect-content.h
SignatureInitDataBuffer_::sm_init
bool sm_init
Definition: detect.h:526
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:575
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
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:642
DetectEngineProtoList
void DetectEngineProtoList(void)
Definition: detect-engine-proto.c:69
SignatureHook_
Definition: detect.h:571
DetectParseDupSigHashInit
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3180
SignatureInitData_::list_set
bool list_set
Definition: detect.h:629
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:711
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:745
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:1445
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:1603
SignatureHook_::sm_list
int sm_list
Definition: detect.h:573
DETECT_TABLE_APP_FILTER
@ DETECT_TABLE_APP_FILTER
Definition: detect.h:558
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:441
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:1679
DetectParseRegex
Definition: detect-parse.h:93
SignatureParser_::action
char action[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:102
SigTableElmt_::name
const char * name
Definition: detect.h:1458
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:644
DetectEngineBufferRunSetupCallback
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
Definition: detect-engine.c:1473
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:705
AppLayerGetProtoByName
AppProto AppLayerGetProtoByName(const char *alproto_name)
Given a protocol string, returns the corresponding internal protocol id.
Definition: app-layer.c:998
DetectSignatureSetMultiAppProto
int DetectSignatureSetMultiAppProto(Signature *s, const AppProto *alprotos)
this function is used to set multiple possible app-layer protos
Definition: detect-parse.c:2158
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:69
DetectAddress_
address structure for use in the detection engine.
Definition: detect.h:168
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1449
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:625
SignatureInitData_::src_contains_negation
bool src_contains_negation
Definition: detect.h:601
DetectEngineCtx_::sigerror_silent
bool sigerror_silent
Definition: detect.h:1027
DetectParseRegex::context
pcre2_match_context * context
Definition: detect-parse.h:95
Signature_::alproto
AppProto alproto
Definition: detect.h:673
DETECT_TABLE_PACKET_PRE_STREAM
@ DETECT_TABLE_PACKET_PRE_STREAM
Definition: detect.h:555
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:656
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
SIG_FLAG_INIT_FILEDATA
#define SIG_FLAG_INIT_FILEDATA
Definition: detect.h:300
detect-isdataat.h
SIGMATCH_QUOTES_OPTIONAL
#define SIGMATCH_QUOTES_OPTIONAL
Definition: detect.h:1663
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:869
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:367
name
const char * name
Definition: detect-engine-proto.c:48
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:142
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:368
detect-bsize.h
URL
#define URL
action-globals.h
PacketRecycle
void PacketRecycle(Packet *p)
Definition: packet.c:160
DetectReferenceFree
void DetectReferenceFree(DetectReference *ref)
Free a Reference object.
Definition: detect-reference.c:76
DetectTable
DetectTable
Definition: detect.h:552
DetectSetupPCRE2
DetectParseRegex * DetectSetupPCRE2(const char *parse_str, int opts)
Definition: detect-parse.c:3577
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
SIG_DIREC_DST
@ SIG_DIREC_DST
Definition: detect-parse.h:48
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:41
ctx
struct Thresholds ctx
AppLayerParserSupportsFiles
bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto)
Definition: app-layer-parser.c:1159
SigDuplWrapper_::s_prev
Signature * s_prev
Definition: detect-parse.c:97
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
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:1102
CASE_CODE_STRING
#define CASE_CODE_STRING(E, S)
TransformData_::options
void * options
Definition: detect.h:388
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:539
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:1588
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2634
AppLayerProtoDetectSupportedIpprotos
void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
Definition: app-layer-detect-proto.c:2041
detect-lua.h
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1308
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:621
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:1031
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2418
FILE_SIG_NEED_FILENAME
#define FILE_SIG_NEED_FILENAME
Definition: detect.h:321
SignatureInitDataBuffer_::multi_capable
bool multi_capable
Definition: detect.h:529
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:731
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:1065
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:608
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3197
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3501
DetectBufferType_
Definition: detect.h:449
proto
uint8_t proto
Definition: decode-template.h:0
DetectContentData_
Definition: detect-content.h:93
DetectEngineCtx_::sigerror_ok
bool sigerror_ok
Definition: detect.h:1028
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:56
SCDetectSignatureSetAppProto
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2236
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect.h:1681
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:1418
SigMatchData_
Data needed for Match()
Definition: detect.h:365
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1440
DetectFlowSetupImplicit
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
Definition: detect-flow.c:341
detect-pcre.h
SigMatchData_::type
uint16_t type
Definition: detect.h:366
PORT_EQ
@ PORT_EQ
Definition: detect.h:208
DetectMatchAddressIPv4_::ip
uint32_t ip
Definition: detect.h:190
SIG_DIREC_SWITCHED
@ SIG_DIREC_SWITCHED
Definition: detect-parse.h:41
DetectContentPMATCHValidateCallback
bool DetectContentPMATCHValidateCallback(const Signature *s)
Definition: detect-content.c:453
DetectParseRegexAddToFreeList
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
add regex and/or study to at exit free list
Definition: detect-parse.c:3537
util-unittest.h
DetectParseRegex::next
struct DetectParseRegex * next
Definition: detect-parse.h:96
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:1278
SIG_DIREC_NORMAL
@ SIG_DIREC_NORMAL
Definition: detect-parse.h:40
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:898
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:714
DetectMatchAddressIPv6_::ip2
uint32_t ip2[4]
Definition: detect.h:196
SIGNATURE_HOOK_TYPE_APP
@ SIGNATURE_HOOK_TYPE_APP
Definition: detect.h:549
Signature_::next
struct Signature_ * next
Definition: detect.h:750
ACTION_REJECT_DST
#define ACTION_REJECT_DST
Definition: action-globals.h:32
DetectParseFreeRegexes
void DetectParseFreeRegexes(void)
Definition: detect-parse.c:3521
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:424
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1667
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:549
UTHMatchPackets
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
Definition: util-unittest-helper.c:730
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:1185
detect-app-layer-event.h
SignatureHook_::app
struct SignatureHook_::@88::@89 app
SignatureHook_::t
union SignatureHook_::@88 t
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:708
SigParseRegisterTests
void SigParseRegisterTests(void)
Definition: detect-parse.c:5432
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
DetectTableToString
const char * DetectTableToString(enum DetectTable table)
Definition: detect-engine.c:131
DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_DISTANCE
Definition: detect-content.h:30
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:19
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:85
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:30
SignatureInitData_::buffers_size
uint32_t buffers_size
Definition: detect.h:649
SigFree
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-parse.c:2064
DetectEngineThreadCtx_
Definition: detect.h:1245
DetectGetLastSMFromMpmLists
SigMatch * DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
get the last SigMatch from lists that support MPM.
Definition: detect-parse.c:527
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:66
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:623
SIGMATCH_SUPPORT_DIR
#define SIGMATCH_SUPPORT_DIR
Definition: detect.h:1683
g_skip_prefilter
int g_skip_prefilter
Definition: detect-engine-mpm.c:1121
SignatureInitData_::src
const DetectAddressHead * src
Definition: detect.h:639
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:621
AppProtoDetectListNames
void AppProtoDetectListNames(void)
Definition: app-layer-detect-proto.c:1699
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:542
SignatureInitData_::cidr_dst
IPOnlyCIDRItem * cidr_dst
Definition: detect.h:618
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3627
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
SignatureInitData_::list
int list
Definition: detect.h:628
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
detect-engine-mpm.h
Signature_::references
DetectReference * references
Definition: detect.h:741
SigTableElmt_::tables
uint8_t tables
Definition: detect.h:1453
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:1112
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:2372
SignatureHookPkt
SignatureHookPkt
Definition: detect.h:538
pkt-var.h
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3364
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:223
DETECT_TABLE_PACKET_PRE_FLOW
@ DETECT_TABLE_PACKET_PRE_FLOW
Definition: detect.h:554
detect-engine-port.h
SigDuplWrapper_::s
Signature * s
Definition: detect-parse.c:95
DETECT_TABLE_PACKET_FILTER
@ DETECT_TABLE_PACKET_FILTER
Definition: detect.h:556
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:262
SC_Pcre2SubstringGet
int SC_Pcre2SubstringGet(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
Definition: detect-parse.c:3615
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3105
DetectPort_
Port structure for detection engine.
Definition: detect.h:220
SigTableElmt_::alternative
uint16_t alternative
Definition: detect.h:1456
SignatureInitData_::cidr_src
IPOnlyCIDRItem * cidr_src
Definition: detect.h:618
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
DetectReference_
Signature reference list.
Definition: detect-reference.h:30
SignatureInitData_::hook
SignatureHook hook
Definition: detect.h:590
SIGNATURE_HOOK_TYPE_NOT_SET
@ SIGNATURE_HOOK_TYPE_NOT_SET
Definition: detect.h:547
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:2265
Signature_::action
uint8_t action
Definition: detect.h:683
util-profiling.h
util-rule-vars.h
SignatureHookType
SignatureHookType
Definition: detect.h:546
DetectMetadataHead::list
DetectMetadata * list
Definition: detect-metadata.h:41
SCReturn
#define SCReturn
Definition: util-debug.h:286
Signature_::flags
uint32_t flags
Definition: detect.h:669
sc_set_caps
bool sc_set_caps
Definition: suricata.c:193
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:501
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:455
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:1298
SignatureInitDataBufferCheckExpand
int SignatureInitDataBufferCheckExpand(Signature *s)
check if buffers array still has space left, expand if not
Definition: detect-parse.c:1924
DETECT_TABLE_PACKET_TD
@ DETECT_TABLE_PACKET_TD
Definition: detect.h:557
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect.h:1671
DetectBufferType_::name
char name[64]
Definition: detect.h:450
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:747
SCReturnPtr
#define SCReturnPtr(x, type)
Definition: util-debug.h:300
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
SignatureInitData_::negated
bool negated
Definition: detect.h:597
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1420
SignatureInitData_
Definition: detect.h:589
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:602
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:392
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
Signature_::addr_dst_match6_cnt
uint16_t addr_dst_match6_cnt
Definition: detect.h:695
SIGNATURE_HOOK_PKT_PRE_STREAM
@ SIGNATURE_HOOK_PKT_PRE_STREAM
Definition: detect.h:542
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:232
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:71
SIG_ALPROTO_MAX
#define SIG_ALPROTO_MAX
Definition: detect.h:587
Signature_::sp
DetectPort * sp
Definition: detect.h:719
DetectMetadata_
Signature metadata list.
Definition: detect-metadata.h:30
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:388
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2194
DetectEngineBufferTypeSupportsMpmGetById
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1445
DetectEngineCtx_::dup_sig_hash_table
HashListTable * dup_sig_hash_table
Definition: detect.h:969
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:34
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1258
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:417
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:351
DETECT_SM_LIST_NOTSET
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:144
DetectAbsentValidateContentCallback
bool DetectAbsentValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-isdataat.c:118
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:535
DetectAddressHead_::ipv6_head
DetectAddress * ipv6_head
Definition: detect.h:185
DetectBufferType_::frame
bool frame
Definition: detect.h:456
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:3447
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
BIT_U8
#define BIT_U8(n)
Definition: suricata-common.h:415
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:687
SigTableElmt_::alias
const char * alias
Definition: detect.h:1459
suricata-common.h
SigMatch_::idx
uint16_t idx
Definition: detect.h:358
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:243
SigMatch_::type
uint16_t type
Definition: detect.h:357
SignatureParser_::protocol
char protocol[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:103
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
SIG_DIREC_SRC
@ SIG_DIREC_SRC
Definition: detect-parse.h:47
Signature_::file_flags
uint8_t file_flags
Definition: detect.h:684
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:693
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:690
packet.h
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SignatureInitData_::curbuf
SignatureInitDataBuffer * curbuf
Definition: detect.h:650
SignatureHook_::type
enum SignatureHookType type
Definition: detect.h:572
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:3601
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
SIGNATURE_HOOK_PKT_PRE_FLOW
@ SIGNATURE_HOOK_PKT_PRE_FLOW
Definition: detect.h:541
DetectMatchAddressIPv4_::ip2
uint32_t ip2
Definition: detect.h:191
Signature_::rev
uint32_t rev
Definition: detect.h:715
SignatureInitData_::sm_cnt
uint16_t sm_cnt
Definition: detect.h:593
util-classification-config.h
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
DetectBsizeValidateContentCallback
bool DetectBsizeValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-bsize.c:49
FatalError
#define FatalError(...)
Definition: util-debug.h:517
SIGNATURE_HOOK_TYPE_PKT
@ SIGNATURE_HOOK_TYPE_PKT
Definition: detect.h:548
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:942
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:1946
DetectEngineAppInspectionEngineSignatureFree
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
free app inspect engines for a signature
Definition: detect-engine.c:929
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:387
SignatureParser
struct SignatureParser_ SignatureParser
Signature_::prio
int prio
Definition: detect.h:716
DetectEngineCtx_::sm_types_silent_error
bool * sm_types_silent_error
Definition: detect.h:1113
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:426
DetectMatchAddressIPv6_::ip
uint32_t ip[4]
Definition: detect.h:195
SIGMATCH_OPTIONAL_OPT
#define SIGMATCH_OPTIONAL_OPT
Definition: detect.h:1660
SignatureInitDataBuffer_::only_ts
bool only_ts
Definition: detect.h:532
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:262
detect-flow.h
Signature_::addr_src_match6_cnt
uint16_t addr_src_match6_cnt
Definition: detect.h:696
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:647
DetectEngineCtx_::app_inspect_engines
DetectEngineAppInspectionEngine * app_inspect_engines
Definition: detect.h:1088
SignatureInitData_::dst
const DetectAddressHead * dst
Definition: detect.h:639
SignatureInitData_::firewall_rule
bool firewall_rule
Definition: detect.h:664
SIGNATURE_HOOK_PKT_ALL
@ SIGNATURE_HOOK_PKT_ALL
Definition: detect.h:543
Signature_::dp
DetectPort * dp
Definition: detect.h:719
str
#define str(s)
Definition: suricata-common.h:308
detect-http-method.h
Signature_::metadata
DetectMetadataHead * metadata
Definition: detect.h:743
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
DETECT_TBLSIZE
int DETECT_TBLSIZE
Definition: detect-engine-register.c:288
Signature_::iid
SigIntId iid
Definition: detect.h:680
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:1677
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:963
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1442
Signature_::addr_dst_match6
DetectMatchAddressIPv6 * addr_dst_match6
Definition: detect.h:710
Signature_::id
uint32_t id
Definition: detect.h:713
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:525
Signature_
Signature container.
Definition: detect.h:668
SigMatch_
a single match condition for a signature
Definition: detect.h:356
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:2595
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:605
SignatureSetType
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-build.c:1645
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:3603
ACTION_ACCEPT
#define ACTION_ACCEPT
Definition: action-globals.h:36
SIGNATURE_HOOK_PKT_FLOW_START
@ SIGNATURE_HOOK_PKT_FLOW_START
Definition: detect.h:540
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:393
SCClassConfGenerateValidDummyClassConfigFD01
FILE * SCClassConfGenerateValidDummyClassConfigFD01(void)
Creates a dummy classification file, with all valid Classtypes, for testing purposes.
Definition: util-classification-config.c:591
DetectPcreData_
Definition: detect-pcre.h:47
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:418
Signature_::detect_table
uint8_t detect_table
Definition: detect.h:702
DetectParseAddress
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
Definition: detect-engine-address.c:1435
SignatureInitDataBuffer_::only_tc
bool only_tc
Definition: detect.h:531
detect-uricontent.h
DETECT_DEFAULT_PRIO
#define DETECT_DEFAULT_PRIO
Definition: detect.h:52
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect.h:1650
DetectEngineBufferRunValidateCallback
bool DetectEngineBufferRunValidateCallback(const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
Definition: detect-engine.c:1492
DetectEngineCtx_::sigerror
const char * sigerror
Definition: detect.h:1026
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:273
DetectParseFreeRegex
void DetectParseFreeRegex(DetectParseRegex *r)
Definition: detect-parse.c:3511
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:944
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:935
SignatureHook_::pkt
struct SignatureHook_::@88::@90 pkt
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:1944
SignatureInitData_::transforms
DetectEngineTransforms transforms
Definition: detect.h:631
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:654
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
Signature_::addr_dst_match4
DetectMatchAddressIPv4 * addr_dst_match4
Definition: detect.h:707
DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_REPLACE
Definition: detect-content.h:51
Signature_::msg
char * msg
Definition: detect.h:736
flow.h
SignatureInitDataBuffer_
Definition: detect.h:524
Signature_::addr_src_match4_cnt
uint16_t addr_src_match4_cnt
Definition: detect.h:694
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:693
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
Signature_::type
enum SignatureType type
Definition: detect.h:671
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:954
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:648
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1354
DetectSetupParseRegexesOpts
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
Definition: detect-parse.c:3548
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
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:3375
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:2086
RetrieveFPForSig
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-mpm.c:1143
DetectListSupportedProtocols
void DetectListSupportedProtocols(void)
Definition: detect-parse.c:1368
app-layer.h
SignatureInitData_::alprotos
AppProto alprotos[SIG_ALPROTO_MAX]
Definition: detect.h:612
SCClassConfDeInitContext
void SCClassConfDeInitContext(DetectEngineCtx *de_ctx)
Releases resources used by the Classification Config API.
Definition: util-classification-config.c:190
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:254