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