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 {
332  return de_ctx->sm_types_silent_error[id];
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  if (s->init_data->firewall_rule && (st->flags & SIGMATCH_BAN_FIREWALL_RULE) != 0) {
972  SCLogError("keyword \'%s\' is not allowed with firewall rules", optname);
973  goto error;
974  }
975 
976  if (EngineModeIsFirewall() && (st->flags & SIGMATCH_BAN_FIREWALL_MODE) != 0) {
977  SCLogError("keyword \'%s\' is not allowed in firewall mode", optname);
978  goto error;
979  }
980 
981  int setup_ret = 0;
982 
983  /* Validate double quoting, trimming trailing white space along the way. */
984  if (optvalue != NULL && strlen(optvalue) > 0) {
985  size_t ovlen = strlen(optvalue);
986  char *ptr = optvalue;
987 
988  /* skip leading whitespace */
989  while (ovlen > 0) {
990  if (!isblank(*ptr))
991  break;
992  ptr++;
993  ovlen--;
994  }
995  if (ovlen == 0) {
996  SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
997  optstr);
998  goto error;
999  }
1000 
1001  if (s->init_data->firewall_rule && (st->flags & SIGMATCH_SUPPORT_FIREWALL) == 0) {
1002  SCLogWarning("keyword \'%s\' has not been tested for firewall rules", optname);
1003  }
1004 
1005  /* see if value is negated */
1006  if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
1007  s->init_data->negated = true;
1008  ptr++;
1009  ovlen--;
1010  }
1011  /* skip more whitespace */
1012  while (ovlen > 0) {
1013  if (!isblank(*ptr))
1014  break;
1015  ptr++;
1016  ovlen--;
1017  }
1018  if (ovlen == 0) {
1019  SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
1020  optstr);
1021  goto error;
1022  }
1023  /* if quoting is mandatory, enforce it */
1024  if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') {
1025  SCLogError("invalid formatting to %s keyword: "
1026  "value must be double quoted \'%s\'",
1027  optname, optstr);
1028  goto error;
1029  }
1030 
1032  && ovlen && *ptr == '"')
1033  {
1034  for (; ovlen > 0; ovlen--) {
1035  if (isblank(ptr[ovlen - 1])) {
1036  ptr[ovlen - 1] = '\0';
1037  } else {
1038  break;
1039  }
1040  }
1041  if (ovlen && ptr[ovlen - 1] != '"') {
1042  SCLogError("bad option value formatting (possible missing semicolon) "
1043  "for keyword %s: \'%s\'",
1044  optname, optvalue);
1045  goto error;
1046  }
1047  if (ovlen > 1) {
1048  /* strip leading " */
1049  ptr++;
1050  ovlen--;
1051  ptr[ovlen - 1] = '\0';
1052  ovlen--;
1053  }
1054  if (ovlen == 0) {
1055  SCLogError("bad input "
1056  "for keyword %s: \'%s\'",
1057  optname, optvalue);
1058  goto error;
1059  }
1060  } else {
1061  if (*ptr == '"') {
1062  SCLogError(
1063  "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1064  goto error;
1065  }
1066  }
1067  /* setup may or may not add a new SigMatch to the list */
1068  if (st->flags & SIGMATCH_SUPPORT_DIR) {
1069  if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1070  SCLogError("%s failed to setup direction", st->name);
1071  goto error;
1072  }
1073  }
1074  setup_ret = st->Setup(de_ctx, s, ptr);
1077  } else {
1078  /* setup may or may not add a new SigMatch to the list */
1079  setup_ret = st->Setup(de_ctx, s, NULL);
1080  }
1081  if (setup_ret < 0) {
1082  SCLogDebug("\"%s\" failed to setup", st->name);
1083 
1084  /* handle 'silent' error case */
1085  if (setup_ret == -2) {
1086  if (!de_ctx->sm_types_silent_error[idx]) {
1087  de_ctx->sm_types_silent_error[idx] = true;
1088  return -1;
1089  }
1090  return -2;
1091  }
1092  return setup_ret;
1093  }
1094  s->init_data->negated = false;
1095 
1096 finish:
1097  if (strlen(optend) > 0) {
1098  strlcpy(output, optend, output_size);
1099  return 1;
1100  }
1101 
1102  return 0;
1103 
1104 error:
1105  return -1;
1106 }
1107 
1108 /** \brief Parse address string and update signature
1109  *
1110  * \retval 0 ok, -1 error
1111  */
1112 static int SigParseAddress(DetectEngineCtx *de_ctx,
1113  Signature *s, const char *addrstr, char flag)
1114 {
1115  SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
1116 
1117  /* pass on to the address(list) parser */
1118  if (flag == 0) {
1119  if (strcasecmp(addrstr, "any") == 0)
1120  s->flags |= SIG_FLAG_SRC_ANY;
1121 
1122  s->init_data->src = DetectParseAddress(de_ctx, addrstr,
1124  if (s->init_data->src == NULL)
1125  goto error;
1126  } else {
1127  if (strcasecmp(addrstr, "any") == 0)
1128  s->flags |= SIG_FLAG_DST_ANY;
1129 
1130  s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
1132  if (s->init_data->dst == NULL)
1133  goto error;
1134  }
1135 
1136  return 0;
1137 
1138 error:
1139  return -1;
1140 }
1141 
1142 static bool IsBuiltIn(const char *n)
1143 {
1144  return strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0 ||
1145  strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0;
1146 }
1147 
1148 /** \brief register app hooks as generic lists
1149  *
1150  * Register each hook in each app protocol as:
1151  * <alproto>:<hook name>:generic
1152  * These lists can be used by lua scripts to hook into.
1153  *
1154  * \todo move elsewhere? maybe a detect-engine-hook.c?
1155  */
1157 {
1158  for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1159  const char *alproto_name = AppProtoToString(a);
1160  if (strcmp(alproto_name, "http") == 0)
1161  alproto_name = "http1";
1162  SCLogDebug("alproto %u/%s", a, alproto_name);
1163 
1164  const int max_progress_ts =
1166  const int max_progress_tc =
1168 
1169  char ts_tx_started[64];
1170  snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:request_started:generic", alproto_name);
1172  ts_tx_started, a, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
1173  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_started,
1174  (uint32_t)strlen(ts_tx_started));
1175 
1176  char tc_tx_started[64];
1177  snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:response_started:generic", alproto_name);
1179  tc_tx_started, a, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
1180  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_started,
1181  (uint32_t)strlen(tc_tx_started));
1182 
1183  char ts_tx_complete[64];
1184  snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:request_complete:generic",
1185  alproto_name);
1186  DetectAppLayerInspectEngineRegister(ts_tx_complete, a, SIG_FLAG_TOSERVER, max_progress_ts,
1188  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_complete,
1189  (uint32_t)strlen(ts_tx_complete));
1190 
1191  char tc_tx_complete[64];
1192  snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:response_complete:generic",
1193  alproto_name);
1194  DetectAppLayerInspectEngineRegister(tc_tx_complete, a, SIG_FLAG_TOCLIENT, max_progress_tc,
1196  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_complete,
1197  (uint32_t)strlen(tc_tx_complete));
1198 
1199  for (int p = 0; p <= max_progress_ts; p++) {
1200  const char *name = AppLayerParserGetStateNameById(
1201  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOSERVER);
1202  if (name != NULL && !IsBuiltIn(name)) {
1203  char list_name[64];
1204  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1205  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1206  (uint32_t)strlen(list_name));
1207 
1209  list_name, a, SIG_FLAG_TOSERVER, p, DetectEngineInspectGenericList, NULL);
1210  }
1211  }
1212  for (int p = 0; p <= max_progress_tc; p++) {
1213  const char *name = AppLayerParserGetStateNameById(
1214  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOCLIENT);
1215  if (name != NULL && !IsBuiltIn(name)) {
1216  char list_name[64];
1217  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1218  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1219  (uint32_t)strlen(list_name));
1220 
1222  list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
1223  }
1224  }
1225  }
1226 }
1227 
1228 #ifdef DEBUG
1229 static const char *SignatureHookTypeToString(enum SignatureHookType t)
1230 {
1231  switch (t) {
1233  return "not_set";
1235  return "app";
1237  return "pkt";
1238  }
1239  return "unknown";
1240 }
1241 #endif
1242 
1243 static enum SignatureHookPkt HookPktFromString(const char *str)
1244 {
1245  if (strcmp(str, "flow_start") == 0) {
1247  } else if (strcmp(str, "pre_flow") == 0) {
1249  } else if (strcmp(str, "pre_stream") == 0) {
1251  } else if (strcmp(str, "all") == 0) {
1252  return SIGNATURE_HOOK_PKT_ALL;
1253  }
1255 }
1256 
1257 #ifdef DEBUG
1258 static const char *HookPktToString(const enum SignatureHookPkt ph)
1259 {
1260  switch (ph) {
1262  return "not set";
1264  return "flow_start";
1266  return "pre_flow";
1268  return "pre_stream";
1270  return "all";
1271  }
1272  return "error";
1273 }
1274 #endif
1275 
1276 static SignatureHook SetPktHook(const char *hook_str)
1277 {
1278  SignatureHook h = {
1280  .t.pkt.ph = HookPktFromString(hook_str),
1281  };
1282  return h;
1283 }
1284 
1285 /**
1286  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1287  */
1288 static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1289 {
1290  enum SignatureHookPkt hook = HookPktFromString(h);
1291  if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
1292  s->init_data->hook = SetPktHook(h);
1293  if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
1294  return -1; // TODO unreachable?
1295  }
1296  } else {
1297  SCLogError("unknown pkt hook %s", h);
1298  return -1;
1299  }
1300 
1301  SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
1302  SignatureHookTypeToString(s->init_data->hook.type),
1303  HookPktToString(s->init_data->hook.t.pkt.ph));
1304  return 0;
1305 }
1306 
1307 static SignatureHook SetAppHook(const AppProto alproto, int progress)
1308 {
1309  SignatureHook h = {
1311  .t.app.alproto = alproto,
1312  .t.app.app_progress = progress,
1313  };
1314  return h;
1315 }
1316 
1317 /**
1318  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1319  */
1320 static int SigParseProtoHookApp(Signature *s, const char *proto_hook, const char *p, const char *h)
1321 {
1322  SCLogDebug("h:'%s'", h);
1323  if (strcmp(h, "request_started") == 0) {
1324  s->flags |= SIG_FLAG_TOSERVER;
1325  s->init_data->hook =
1326  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1327  } else if (strcmp(h, "response_started") == 0) {
1328  s->flags |= SIG_FLAG_TOCLIENT;
1329  s->init_data->hook =
1330  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1331  } else if (strcmp(h, "request_complete") == 0) {
1332  s->flags |= SIG_FLAG_TOSERVER;
1333  s->init_data->hook = SetAppHook(s->alproto,
1335  } else if (strcmp(h, "response_complete") == 0) {
1336  s->flags |= SIG_FLAG_TOCLIENT;
1337  s->init_data->hook = SetAppHook(s->alproto,
1339  } else {
1340  const int progress_ts = AppLayerParserGetStateIdByName(
1341  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
1342  if (progress_ts >= 0) {
1343  s->flags |= SIG_FLAG_TOSERVER;
1344  s->init_data->hook = SetAppHook(s->alproto, progress_ts);
1345  } else {
1346  const int progress_tc = AppLayerParserGetStateIdByName(
1347  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
1348  if (progress_tc < 0) {
1349  return -1;
1350  }
1351  s->flags |= SIG_FLAG_TOCLIENT;
1352  s->init_data->hook = SetAppHook(s->alproto, progress_tc);
1353  }
1354  }
1355 
1356  char generic_hook_name[64];
1357  snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:%s:generic", p, h);
1358  int list = DetectBufferTypeGetByName(generic_hook_name);
1359  if (list < 0) {
1360  SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
1361  return -1;
1362  }
1363  s->init_data->hook.sm_list = list;
1364 
1365  SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
1366  SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
1367  s->init_data->hook.t.app.app_progress);
1368 
1369  s->app_progress_hook = (uint8_t)s->init_data->hook.t.app.app_progress;
1370  return 0;
1371 }
1372 
1374 {
1375  printf("=========Supported Rule Protocols=========\n");
1378 }
1379 
1380 /**
1381  * \brief Parses the protocol supplied by the Signature.
1382  *
1383  * http://www.iana.org/assignments/protocol-numbers
1384  *
1385  * \param s Pointer to the Signature instance to which the parsed
1386  * protocol has to be added.
1387  * \param protostr Pointer to the character string containing the protocol name.
1388  *
1389  * \retval 0 On successfully parsing the protocol sent as the argument.
1390  * \retval -1 On failure
1391  */
1392 static int SigParseProto(Signature *s, const char *protostr)
1393 {
1394  SCEnter();
1395  if (strlen(protostr) > 32)
1396  return -1;
1397 
1398  char proto[33];
1399  strlcpy(proto, protostr, 33);
1400  const char *p = proto;
1401  const char *h = NULL;
1402 
1403  bool has_hook = strchr(proto, ':') != NULL;
1404  if (has_hook) {
1405  char *xsaveptr = NULL;
1406  p = strtok_r(proto, ":", &xsaveptr);
1407  h = strtok_r(NULL, ":", &xsaveptr);
1408  SCLogDebug("p: '%s' h: '%s'", p, h);
1409  }
1410  if (p == NULL) {
1411  SCLogError("invalid protocol specification '%s'", proto);
1412  return -1;
1413  }
1414 
1415  int r = DetectProtoParse(&s->init_data->proto, (char *)p);
1416  if (r < 0) {
1418  /* indicate that the signature is app-layer */
1419  if (s->alproto != ALPROTO_UNKNOWN) {
1420  s->flags |= SIG_FLAG_APPLAYER;
1421 
1423 
1424  if (h) {
1425  /* FW hook LTE mode */
1426  SCLogDebug("hook '%s'", h);
1427  if (*h == '<') {
1428  h++;
1429  SCLogDebug("hook and prior hooks: '%s'", h);
1431  }
1432  if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
1433  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1434  SCReturnInt(-1);
1435  }
1436  }
1437  }
1438  else {
1439  SCLogError("protocol \"%s\" cannot be used "
1440  "in a signature. Either detection for this protocol "
1441  "is not yet supported OR detection has been disabled for "
1442  "protocol through the yaml option "
1443  "app-layer.protocols.%s.detection-enabled",
1444  p, p);
1445  SCReturnInt(-1);
1446  }
1447  } else if (h != NULL) {
1448  SCLogDebug("non-app-layer rule with %s:%s", p, h);
1449 
1450  if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
1451  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1452  SCReturnInt(-1);
1453  }
1454  }
1455 
1456  /* if any of these flags are set they are set in a mutually exclusive
1457  * manner */
1460  } else if (s->init_data->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1462  }
1463 
1464  SCReturnInt(0);
1465 }
1466 
1467 /**
1468  * \brief Parses the port(source or destination) field, from a Signature.
1469  *
1470  * \param s Pointer to the signature which has to be updated with the
1471  * port information.
1472  * \param portstr Pointer to the character string containing the port info.
1473  * \param Flag which indicates if the portstr received is src or dst
1474  * port. For src port: flag = 0, dst port: flag = 1.
1475  *
1476  * \retval 0 On success.
1477  * \retval -1 On failure.
1478  */
1479 static int SigParsePort(const DetectEngineCtx *de_ctx,
1480  Signature *s, const char *portstr, char flag)
1481 {
1482  int r = 0;
1483 
1484  /* XXX VJ exclude handling this for none UDP/TCP proto's */
1485 
1486  SCLogDebug("Port group \"%s\" to be parsed", portstr);
1487 
1488  if (flag == 0) {
1489  if (strcasecmp(portstr, "any") == 0)
1490  s->flags |= SIG_FLAG_SP_ANY;
1491 
1492  r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1493  } else if (flag == 1) {
1494  if (strcasecmp(portstr, "any") == 0)
1495  s->flags |= SIG_FLAG_DP_ANY;
1496 
1497  r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1498  }
1499 
1500  if (r < 0)
1501  return -1;
1502 
1503  return 0;
1504 }
1505 
1506 /** \retval 1 valid
1507  * \retval 0 invalid
1508  */
1509 static int SigParseActionRejectValidate(const char *action)
1510 {
1511 #ifdef HAVE_LIBNET11
1512 #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1513  if (sc_set_caps) {
1514  SCLogError("Libnet 1.1 is "
1515  "incompatible with POSIX based capabilities with privs dropping. "
1516  "For rejects to work, run as root/super user.");
1517  return 0;
1518  }
1519 #endif
1520 #else /* no libnet 1.1 */
1521  SCLogError("Libnet 1.1.x is "
1522  "required for action \"%s\" but is not compiled into Suricata",
1523  action);
1524  return 0;
1525 #endif
1526  return 1;
1527 }
1528 
1529 /** \retval 0 on error
1530  * \retval flags on success
1531  */
1532 static uint8_t ActionStringToFlags(const char *action)
1533 {
1534  if (strcasecmp(action, "alert") == 0) {
1535  return ACTION_ALERT;
1536  } else if (strcasecmp(action, "drop") == 0) {
1537  return ACTION_DROP | ACTION_ALERT;
1538  } else if (strcasecmp(action, "pass") == 0) {
1539  return ACTION_PASS;
1540  } else if (strcasecmp(action, "reject") == 0 ||
1541  strcasecmp(action, "rejectsrc") == 0)
1542  {
1543  if (!(SigParseActionRejectValidate(action)))
1544  return 0;
1546  } else if (strcasecmp(action, "rejectdst") == 0) {
1547  if (!(SigParseActionRejectValidate(action)))
1548  return 0;
1550  } else if (strcasecmp(action, "rejectboth") == 0) {
1551  if (!(SigParseActionRejectValidate(action)))
1552  return 0;
1554  } else if (strcasecmp(action, "config") == 0) {
1555  return ACTION_CONFIG;
1556  } else if (strcasecmp(action, "accept") == 0) {
1557  return ACTION_ACCEPT;
1558  } else {
1559  SCLogError("An invalid action \"%s\" was given", action);
1560  return 0;
1561  }
1562 }
1563 
1564 /**
1565  * \brief Parses the action that has been used by the Signature and allots it
1566  * to its Signature instance.
1567  *
1568  * \param s Pointer to the Signature instance to which the action belongs.
1569  * \param action_in Pointer to the action string used by the Signature.
1570  *
1571  * \retval 0 On successfully parsing the action string and adding it to the
1572  * Signature.
1573  * \retval -1 On failure.
1574  */
1575 static int SigParseActionDo(const char *action_in, const int idx, const bool fw_rule,
1576  uint8_t *action_out, uint8_t *scope_out)
1577 {
1578  char action[32];
1579  strlcpy(action, action_in, sizeof(action));
1580  const char *a = action;
1581  const char *o = NULL;
1582 
1583  bool has_scope = strchr(action, ':') != NULL;
1584  if (has_scope) {
1585  char *xsaveptr = NULL;
1586  a = strtok_r(action, ":", &xsaveptr);
1587  o = strtok_r(NULL, ":", &xsaveptr);
1588  SCLogDebug("a: '%s' o: '%s'", a, o);
1589  }
1590  if (a == NULL) {
1591  SCLogError("invalid protocol specification '%s'", action_in);
1592  return -1;
1593  }
1594 
1595  uint8_t flags = ActionStringToFlags(a);
1596  if (flags == 0)
1597  return -1;
1598 
1599  if (fw_rule) {
1600  /* in firewall mode, drop is just drop. Whereas in IDS/IPS mode, drop is drop+alert.
1601  * Same for reject which includes ACTION_DROP. */
1602  if (flags & ACTION_DROP) {
1603  flags &= ~ACTION_ALERT;
1604  }
1605 
1606  if (idx == 0 &&
1608  SCLogError("only accept, config, drop and reject actions allowed as primary action "
1609  "firewall "
1610  "rules");
1611  return -1;
1612  }
1613  if (idx > 0 &&
1615  SCLogError("accept, config, drop and reject actions not allowed as secondary action "
1616  "firewall "
1617  "rules");
1618  return -1;
1619  }
1620  }
1621 
1622  /* parse scope, if any */
1623  if (o) {
1624  uint8_t scope_flags = 0;
1625  if (flags & (ACTION_DROP | ACTION_PASS)) {
1626  if (strcmp(o, "packet") == 0) {
1627  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1628  } else if (strcmp(o, "flow") == 0) {
1629  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1630  } else {
1631  SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1632  "allowed",
1633  o, action_in);
1634  return -1;
1635  }
1636  } else if (flags & (ACTION_ACCEPT)) {
1637  if (strcmp(o, "packet") == 0) {
1638  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1639  } else if (strcmp(o, "hook") == 0) {
1640  scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1641  } else if (strcmp(o, "tx") == 0) {
1642  scope_flags = (uint8_t)ACTION_SCOPE_TX;
1643  } else if (strcmp(o, "flow") == 0) {
1644  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1645  } else {
1646  SCLogError(
1647  "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1648  "'hook' allowed",
1649  o, action_in);
1650  return -1;
1651  }
1652  } else if (flags & (ACTION_CONFIG)) {
1653  if (strcmp(o, "packet") == 0) {
1654  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1655  } else {
1656  SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
1657  action_in);
1658  return -1;
1659  }
1660  } else {
1661  SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1662  "'drop', 'pass' and 'reject'",
1663  o, action_in);
1664  return -1;
1665  }
1666  if (*scope_out != 0 && *scope_out != scope_flags) {
1667  SCLogError("multi-action rules cannot use different action scopes");
1668  return -1;
1669  }
1670  *scope_out = scope_flags;
1671  }
1672 
1673  /* require explicit action scope for fw rules */
1674  if (fw_rule && *scope_out == 0) {
1675  SCLogError("firewall rules require setting an explicit action scope");
1676  return -1;
1677  }
1678 
1679  if (!fw_rule && (flags & ACTION_ACCEPT)) {
1680  SCLogError("'accept' action only supported for firewall rules");
1681  return -1;
1682  }
1683  *action_out |= flags;
1684  return 0;
1685 }
1686 
1687 static int SigParseAction(Signature *s, const char *action_in)
1688 {
1689  /* multi-action rules are only supported for firewall rules at this time. */
1690  if (!s->init_data->firewall_rule)
1691  return SigParseActionDo(action_in, 0, false, &s->action, &s->action_scope);
1692 
1693  int r = 0;
1694  char *copy = SCStrdup(action_in);
1695  if (copy == NULL)
1696  FatalError("could not duplicate opt string");
1697 
1698  int i = 0;
1699  char *xsaveptr = NULL;
1700  char *a = strtok_r(copy, ",", &xsaveptr);
1701  while (a != NULL) {
1702  if (SigParseActionDo(a, i, true, &s->action, &s->action_scope) < 0) {
1703  r = -1;
1704  break;
1705  }
1706  a = strtok_r(NULL, ",", &xsaveptr);
1707  i++;
1708  }
1709 
1710  SCFree(copy);
1711 
1712  SCLogDebug("s->action %02x", s->action);
1713  return r;
1714 }
1715 
1716 /**
1717  * \brief Parse the next token in rule.
1718  *
1719  * For rule parsing a token is considered to be a string of characters
1720  * separated by white space.
1721  *
1722  * \param input double pointer to input buffer, will be advanced as input is
1723  * parsed.
1724  * \param output buffer to copy token into.
1725  * \param output_size length of output buffer.
1726  */
1727 static inline int SigParseToken(char **input, char *output,
1728  const size_t output_size)
1729 {
1730  size_t len = *input == NULL ? 0 : strlen(*input);
1731 
1732  if (!len) {
1733  return 0;
1734  }
1735 
1736  while (len && isblank(**input)) {
1737  (*input)++;
1738  len--;
1739  }
1740 
1741  char *endptr = strpbrk(*input, " \t\n\r");
1742  if (endptr != NULL) {
1743  *(endptr++) = '\0';
1744  }
1745  strlcpy(output, *input, output_size);
1746  *input = endptr;
1747 
1748  return 1;
1749 }
1750 
1751 /**
1752  * \brief Parse the next rule "list" token.
1753  *
1754  * Parses rule tokens that may be lists such as addresses and ports
1755  * handling the case when they may not be lists.
1756  *
1757  * \param input double pointer to input buffer, will be advanced as input is
1758  * parsed.
1759  * \param output buffer to copy token into.
1760  * \param output_size length of output buffer.
1761  */
1762 static inline int SigParseList(char **input, char *output,
1763  const size_t output_size)
1764 {
1765  int in_list = 0;
1766  size_t len = *input != NULL ? strlen(*input) : 0;
1767 
1768  if (len == 0) {
1769  return 0;
1770  }
1771 
1772  while (len && isblank(**input)) {
1773  (*input)++;
1774  len--;
1775  }
1776 
1777  size_t i = 0;
1778  for (i = 0; i < len; i++) {
1779  char c = (*input)[i];
1780  if (c == '[') {
1781  in_list++;
1782  } else if (c == ']') {
1783  in_list--;
1784  } else if (c == ' ') {
1785  if (!in_list) {
1786  break;
1787  }
1788  }
1789  }
1790  if (i == len) {
1791  *input = NULL;
1792  return 0;
1793  }
1794  (*input)[i] = '\0';
1795  strlcpy(output, *input, output_size);
1796  *input = *input + i + 1;
1797 
1798  return 1;
1799 }
1800 
1801 /**
1802  * \internal
1803  * \brief split a signature string into a few blocks for further parsing
1804  *
1805  * \param scan_only just scan, don't validate
1806  */
1807 static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1808  SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1809 {
1810  char *index, dup[DETECT_MAX_RULE_SIZE];
1811 
1812  strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1813  index = dup;
1814 
1815  /* Action. */
1816  SigParseToken(&index, parser->action, sizeof(parser->action));
1817 
1818  /* Protocol. */
1819  SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1820 
1821  /* Source. */
1822  SigParseList(&index, parser->src, sizeof(parser->src));
1823 
1824  /* Source port(s). */
1825  SigParseList(&index, parser->sp, sizeof(parser->sp));
1826 
1827  /* Direction. */
1828  SigParseToken(&index, parser->direction, sizeof(parser->direction));
1829 
1830  /* Destination. */
1831  SigParseList(&index, parser->dst, sizeof(parser->dst));
1832 
1833  /* Destination port(s). */
1834  SigParseList(&index, parser->dp, sizeof(parser->dp));
1835 
1836  /* Options. */
1837  if (index == NULL) {
1838  SCLogError("no rule options.");
1839  goto error;
1840  }
1841  while (isspace(*index) || *index == '(') {
1842  index++;
1843  }
1844  for (size_t i = strlen(index); i > 0; i--) {
1845  if (isspace(index[i - 1]) || index[i - 1] == ')') {
1846  index[i - 1] = '\0';
1847  } else {
1848  break;
1849  }
1850  }
1851  strlcpy(parser->opts, index, sizeof(parser->opts));
1852 
1853  if (scan_only) {
1854  return 0;
1855  }
1856 
1857  /* Parse Action */
1858  if (SigParseAction(s, parser->action) < 0)
1859  goto error;
1860 
1861  if (SigParseProto(s, parser->protocol) < 0)
1862  goto error;
1863 
1864  if (strcmp(parser->direction, "<>") == 0) {
1866  } else if (strcmp(parser->direction, "=>") == 0) {
1867  if (s->flags & SIG_FLAG_FIREWALL) {
1868  SCLogError("transactional bidirectional rules not supported for firewall rules");
1869  goto error;
1870  }
1871 
1872  s->flags |= SIG_FLAG_TXBOTHDIR;
1873  } else if (strcmp(parser->direction, "->") != 0) {
1874  SCLogError("\"%s\" is not a valid direction modifier, "
1875  "\"->\" and \"<>\" are supported.",
1876  parser->direction);
1877  goto error;
1878  }
1879 
1880  /* Parse Address & Ports */
1881  if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1882  goto error;
1883 
1884  if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1885  goto error;
1886 
1887  /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1888  * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1889  * changes that we made sees to it that at this point of time we don't
1890  * set the ip proto for the sig. We do it a bit later. */
1891  if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1892  goto error;
1893  if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1894  goto error;
1895 
1896  return 0;
1897 
1898 error:
1899  return -1;
1900 }
1901 
1902 static inline bool CheckAscii(const char *str)
1903 {
1904  for (size_t i = 0; i < strlen(str); i++) {
1905  if (str[i] < 0x20) {
1906  // LF CR TAB
1907  if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1908  continue;
1909  }
1910  return false;
1911  } else if (str[i] == 0x7f) {
1912  return false;
1913  }
1914  }
1915  return true;
1916 }
1917 
1918 /**
1919  * \brief parse a signature
1920  *
1921  * \param de_ctx detection engine ctx to add it to
1922  * \param s memory structure to store the signature in
1923  * \param sigstr the raw signature as a null terminated string
1924  * \param addrs_direction direction (for bi-directional sigs)
1925  * \param require only scan rule for requires
1926  *
1927  * \param -1 parse error
1928  * \param 0 ok
1929  */
1930 static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1931  uint8_t addrs_direction, SignatureParser *parser, bool requires)
1932 {
1933  SCEnter();
1934 
1935  if (!SCCheckUtf8(sigstr)) {
1936  SCLogError("rule is not valid UTF-8");
1937  SCReturnInt(-1);
1938  }
1939 
1940  if (!CheckAscii(sigstr)) {
1941  SCLogError("rule contains invalid (control) characters");
1942  SCReturnInt(-1);
1943  }
1944 
1945  int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
1946  if (ret < 0) {
1947  SCLogDebug("SigParseBasics failed");
1948  SCReturnInt(-1);
1949  }
1950 
1951  /* we can have no options, so make sure we have them */
1952  if (strlen(parser->opts) > 0) {
1953  size_t buffer_size = strlen(parser->opts) + 1;
1955  char input[buffer_size];
1956  char output[buffer_size];
1957  memset(input, 0x00, buffer_size);
1958  memcpy(input, parser->opts, strlen(parser->opts) + 1);
1959 
1960  /* loop the option parsing. Each run processes one option
1961  * and returns the rest of the option string through the
1962  * output variable. */
1963  do {
1964  memset(output, 0x00, buffer_size);
1965  ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
1966  if (ret == 1) {
1967  memcpy(input, output, buffer_size);
1968  }
1969 
1970  } while (ret == 1);
1971 
1972  if (ret < 0) {
1973  /* Suricata didn't meet the rule requirements, skip. */
1974  goto end;
1975  }
1976  }
1977 
1978 end:
1980 
1981  SCReturnInt(ret);
1982 }
1983 
1984 /** \brief check if buffers array still has space left, expand if not
1985  */
1987 {
1988  if (s->init_data->buffers_size >= 64)
1989  return -1;
1990 
1991  if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
1992  void *ptr = SCRealloc(s->init_data->buffers,
1993  (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
1994  if (ptr == NULL)
1995  return -1;
1996  s->init_data->buffers = ptr;
1997  for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
1999  memset(b, 0, sizeof(*b));
2000  }
2001  s->init_data->buffers_size += 8;
2002  }
2003  return 0;
2004 }
2005 
2007 {
2008  Signature *sig = SCCalloc(1, sizeof(Signature));
2009  if (unlikely(sig == NULL))
2010  return NULL;
2011 
2012  sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
2013  if (sig->init_data == NULL) {
2014  SCFree(sig);
2015  return NULL;
2016  }
2017  sig->init_data->mpm_sm_list = -1;
2018 
2019  sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
2020  if (sig->init_data->buffers == NULL) {
2021  SCFree(sig->init_data);
2022  SCFree(sig);
2023  return NULL;
2024  }
2025  sig->init_data->buffers_size = 8;
2026 
2027  /* assign it to -1, so that we can later check if the value has been
2028  * overwritten after the Signature has been parsed, and if it hasn't been
2029  * overwritten, we can then assign the default value of 3 */
2030  sig->prio = -1;
2031 
2032  /* rule interdepency is false, at start */
2033  sig->init_data->is_rule_state_dependant = false;
2034  /* first index is 0 */
2036 
2038  return sig;
2039 }
2040 
2041 /**
2042  * \internal
2043  * \brief Free Metadata list
2044  *
2045  * \param s Pointer to the signature
2046  */
2047 static void SigMetadataFree(Signature *s)
2048 {
2049  SCEnter();
2050 
2051  DetectMetadata *mdata = NULL;
2052  DetectMetadata *next_mdata = NULL;
2053 
2054  if (s == NULL || s->metadata == NULL) {
2055  SCReturn;
2056  }
2057 
2058  SCLogDebug("s %p, s->metadata %p", s, s->metadata);
2059 
2060  for (mdata = s->metadata->list; mdata != NULL;) {
2061  next_mdata = mdata->next;
2062  DetectMetadataFree(mdata);
2063  mdata = next_mdata;
2064  }
2065  SCFree(s->metadata->json_str);
2066  SCFree(s->metadata);
2067  s->metadata = NULL;
2068 
2069  SCReturn;
2070 }
2071 
2072 /**
2073  * \internal
2074  * \brief Free Reference list
2075  *
2076  * \param s Pointer to the signature
2077  */
2078 static void SigRefFree (Signature *s)
2079 {
2080  SCEnter();
2081 
2082  DetectReference *ref = NULL;
2083  DetectReference *next_ref = NULL;
2084 
2085  if (s == NULL) {
2086  SCReturn;
2087  }
2088 
2089  SCLogDebug("s %p, s->references %p", s, s->references);
2090 
2091  for (ref = s->references; ref != NULL;) {
2092  next_ref = ref->next;
2093  DetectReferenceFree(ref);
2094  ref = next_ref;
2095  }
2096 
2097  s->references = NULL;
2098 
2099  SCReturn;
2100 }
2101 
2102 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2103 {
2104  if (s != NULL) {
2105  int type;
2106  for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2107  if (s->sm_arrays[type] != NULL) {
2108  if (ctxs) {
2109  SigMatchData *smd = s->sm_arrays[type];
2110  while(1) {
2111  if (sigmatch_table[smd->type].Free != NULL) {
2112  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2113  }
2114  if (smd->is_last)
2115  break;
2116  smd++;
2117  }
2118  }
2119 
2120  SCFree(s->sm_arrays[type]);
2121  }
2122  }
2123  }
2124 }
2125 
2127 {
2128  if (s == NULL)
2129  return;
2130 
2131  int i;
2132 
2133  if (s->init_data && s->init_data->transforms.cnt) {
2134  for(i = 0; i < s->init_data->transforms.cnt; i++) {
2135  if (s->init_data->transforms.transforms[i].options) {
2136  int transform = s->init_data->transforms.transforms[i].transform;
2137  sigmatch_table[transform].Free(
2139  s->init_data->transforms.transforms[i].options = NULL;
2140  }
2141  }
2142  }
2143  if (s->init_data) {
2144  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2145  SigMatch *sm = s->init_data->smlists[i];
2146  while (sm != NULL) {
2147  SigMatch *nsm = sm->next;
2148  SigMatchFree(de_ctx, sm);
2149  sm = nsm;
2150  }
2151  }
2152 
2153  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2154  SigMatch *sm = s->init_data->buffers[x].head;
2155  while (sm != NULL) {
2156  SigMatch *nsm = sm->next;
2157  SigMatchFree(de_ctx, sm);
2158  sm = nsm;
2159  }
2160  }
2161  if (s->init_data->cidr_dst != NULL)
2163 
2164  if (s->init_data->cidr_src != NULL)
2166 
2167  SCFree(s->init_data->buffers);
2168  s->init_data->buffers = NULL;
2169  }
2170  SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2171  if (s->init_data) {
2172  SCFree(s->init_data);
2173  s->init_data = NULL;
2174  }
2175 
2176  if (s->sp != NULL) {
2177  DetectPortCleanupList(NULL, s->sp);
2178  }
2179  if (s->dp != NULL) {
2180  DetectPortCleanupList(NULL, s->dp);
2181  }
2182  if (s->proto) {
2183  SCFree(s->proto);
2184  }
2185 
2186  if (s->msg != NULL)
2187  SCFree(s->msg);
2188 
2189  if (s->addr_src_match4 != NULL) {
2190  SCFree(s->addr_src_match4);
2191  }
2192  if (s->addr_dst_match4 != NULL) {
2193  SCFree(s->addr_dst_match4);
2194  }
2195  if (s->addr_src_match6 != NULL) {
2196  SCFree(s->addr_src_match6);
2197  }
2198  if (s->addr_dst_match6 != NULL) {
2199  SCFree(s->addr_dst_match6);
2200  }
2201  if (s->sig_str != NULL) {
2202  SCFree(s->sig_str);
2203  }
2204 
2205  SigRefFree(s);
2206  SigMetadataFree(s);
2207 
2209 
2210  SCFree(s);
2211 }
2212 
2213 /**
2214  * \brief this function is used to set multiple possible app-layer protos
2215  * \brief into the current signature (for example ja4 for both tls and quic)
2216  *
2217  * \param s pointer to the Current Signature
2218  * \param alprotos an array terminated by ALPROTO_UNKNOWN
2219  *
2220  * \retval 0 on Success
2221  * \retval -1 on Failure
2222  */
2224 {
2225  if (s->alproto != ALPROTO_UNKNOWN) {
2226  // One alproto was set, check if it matches the new ones proposed
2227  while (*alprotos != ALPROTO_UNKNOWN) {
2228  if (s->alproto == *alprotos) {
2229  // alproto already set to only one
2230  return 0;
2231  }
2232  alprotos++;
2233  }
2234  // alproto already set and not matching the new set of alprotos
2235  return -1;
2236  }
2237  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2238  // check intersection of already used alprotos and new ones
2239  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2240  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2241  break;
2242  }
2243  // first disable the ones that do not match
2244  bool found = false;
2245  const AppProto *args = alprotos;
2246  while (*args != ALPROTO_UNKNOWN) {
2247  if (s->init_data->alprotos[i] == *args) {
2248  found = true;
2249  break;
2250  }
2251  args++;
2252  }
2253  if (!found) {
2255  }
2256  }
2257  // Then put at the beginning every defined protocol
2258  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2259  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2260  for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2261  if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2262  s->init_data->alprotos[i] = s->init_data->alprotos[j];
2264  break;
2265  }
2266  }
2267  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2268  if (i == 0) {
2269  // there was no intersection
2270  return -1;
2271  } else if (i == 1) {
2272  // intersection is singleton, set it as usual
2273  AppProto alproto = s->init_data->alprotos[0];
2275  return SCDetectSignatureSetAppProto(s, alproto);
2276  }
2277  break;
2278  }
2279  }
2280  }
2281  } else {
2282  if (alprotos[0] == ALPROTO_UNKNOWN) {
2283  // do not allow empty set
2284  return -1;
2285  }
2286  if (alprotos[1] == ALPROTO_UNKNOWN) {
2287  // allow singleton, but call traditional setter
2288  return SCDetectSignatureSetAppProto(s, alprotos[0]);
2289  }
2290  // first time we enforce alprotos
2291  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2292  if (alprotos[i] == ALPROTO_UNKNOWN) {
2293  break;
2294  }
2295  s->init_data->alprotos[i] = alprotos[i];
2296  }
2297  }
2298  return 0;
2299 }
2300 
2302 {
2303  if (!AppProtoIsValid(alproto)) {
2304  SCLogError("invalid alproto %u", alproto);
2305  return -1;
2306  }
2307 
2308  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2309  // Multiple alprotos were set, check if we restrict to one
2310  bool found = false;
2311  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2312  if (s->init_data->alprotos[i] == alproto) {
2313  found = true;
2314  break;
2315  }
2316  }
2317  if (!found) {
2318  // fail if we set to a alproto which was not in the set
2319  return -1;
2320  }
2321  // we will use s->alproto if there is a single alproto and
2322  // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2324  }
2325 
2326  if (s->alproto != ALPROTO_UNKNOWN) {
2327  alproto = AppProtoCommon(s->alproto, alproto);
2328  if (alproto == ALPROTO_FAILED) {
2329  SCLogError("can't set rule app proto to %s: already set to %s",
2330  AppProtoToString(alproto), AppProtoToString(s->alproto));
2331  return -1;
2332  }
2333  }
2334 
2335  if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2336  SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2337  return -1;
2338  }
2339  s->alproto = alproto;
2340  s->flags |= SIG_FLAG_APPLAYER;
2341  return 0;
2342 }
2343 
2344 static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2345  const DetectAddress *head, uint16_t *match4_cnt)
2346 {
2347  uint16_t cnt = 0;
2348 
2349  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2350  cnt++;
2351  }
2352  if (cnt == 0) {
2353  return NULL;
2354  }
2355  DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2356  if (addr_match4 == NULL) {
2357  return NULL;
2358  }
2359 
2360  uint16_t idx = 0;
2361  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2362  addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2363  addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2364  idx++;
2365  }
2366  *match4_cnt = cnt;
2367  return addr_match4;
2368 }
2369 
2370 static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2371  const DetectAddress *head, uint16_t *match6_cnt)
2372 {
2373  uint16_t cnt = 0;
2374  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2375  cnt++;
2376  }
2377  if (cnt == 0) {
2378  return NULL;
2379  }
2380 
2381  DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2382  if (addr_match6 == NULL) {
2383  return NULL;
2384  }
2385 
2386  uint16_t idx = 0;
2387  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2388  addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2389  addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2390  addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2391  addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2392  addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2393  addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2394  addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2395  addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2396  idx++;
2397  }
2398  *match6_cnt = cnt;
2399  return addr_match6;
2400 }
2401 
2402 /**
2403  * \internal
2404  * \brief build address match array for cache efficient matching
2405  *
2406  * \param s the signature
2407  */
2408 static void SigBuildAddressMatchArray(Signature *s)
2409 {
2410  /* source addresses */
2411  s->addr_src_match4 =
2412  SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2413  /* destination addresses */
2414  s->addr_dst_match4 =
2415  SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2416 
2417  /* source addresses IPv6 */
2418  s->addr_src_match6 =
2419  SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2420  /* destination addresses IPv6 */
2421  s->addr_dst_match6 =
2422  SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2423 }
2424 
2425 static int SigMatchListLen(SigMatch *sm)
2426 {
2427  int len = 0;
2428  for (; sm != NULL; sm = sm->next)
2429  len++;
2430 
2431  return len;
2432 }
2433 
2434 /** \brief convert SigMatch list to SigMatchData array
2435  * \note ownership of sm->ctx is transferred to smd->ctx
2436  */
2438 {
2439  int len = SigMatchListLen(head);
2440  if (len == 0)
2441  return NULL;
2442 
2443  SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
2444  if (smd == NULL) {
2445  FatalError("initializing the detection engine failed");
2446  }
2447  SigMatchData *out = smd;
2448 
2449  /* Copy sm type and Context into array */
2450  SigMatch *sm = head;
2451  for (; sm != NULL; sm = sm->next, smd++) {
2452  smd->type = sm->type;
2453  smd->ctx = sm->ctx;
2454  sm->ctx = NULL; // SigMatch no longer owns the ctx
2455  smd->is_last = (sm->next == NULL);
2456  }
2457  return out;
2458 }
2459 
2460 extern int g_skip_prefilter;
2461 
2462 static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2463 {
2464  SCEnter();
2465  SCLogDebug("s %u: set up prefilter/mpm", s->id);
2466  DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
2467 
2468  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
2469  SCLogDebug("no prefilter for SIG_FLAG_FW_HOOK_LTE sig");
2470  SCReturn;
2471  }
2472 
2473  if (s->init_data->prefilter_sm != NULL) {
2474  if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
2476  if (s->init_data->mpm_sm != NULL) {
2477  s->flags |= SIG_FLAG_PREFILTER;
2478  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2479  SCReturn;
2480  }
2481  /* fall through, this can happen if the mpm doesn't support the pattern */
2482  } else {
2483  s->flags |= SIG_FLAG_PREFILTER;
2484  SCReturn;
2485  }
2486  } else {
2487  SCLogDebug("%u: RetrieveFPForSig", s->id);
2489  if (s->init_data->mpm_sm != NULL) {
2490  s->flags |= SIG_FLAG_PREFILTER;
2491  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2492  SCReturn;
2493  }
2494  }
2495 
2496  SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2497  "s->init_data->has_possible_prefilter %s",
2499 
2501  SCReturn;
2502 
2505  int prefilter_list = DETECT_TBLSIZE;
2506  /* get the keyword supporting prefilter with the lowest type */
2507  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2508  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2509  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2510  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
2511  prefilter_list = MIN(prefilter_list, sm->type);
2512  }
2513  }
2514  }
2515  }
2516 
2517  /* apply that keyword as prefilter */
2518  if (prefilter_list != DETECT_TBLSIZE) {
2519  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2520  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2521  if (sm->type == prefilter_list) {
2522  s->init_data->prefilter_sm = sm;
2523  s->flags |= SIG_FLAG_PREFILTER;
2524  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2525  sigmatch_table[sm->type].name);
2526  break;
2527  }
2528  }
2529  }
2530  }
2531  }
2532  SCReturn;
2533 }
2534 
2535 /** \internal
2536  * \brief check if signature's table requirement is supported by each of the keywords it uses.
2537  */
2538 static bool DetectRuleValidateTable(const Signature *s)
2539 {
2540  if (s->detect_table == 0)
2541  return true;
2542 
2543  const uint8_t table_as_flag = BIT_U8(s->detect_table);
2544 
2545  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
2546  const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
2547  if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
2548  SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
2550  return false;
2551  }
2552  }
2553  return true;
2554 }
2555 
2556 static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2557 {
2559  SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2560  "explicit hook",
2561  s->id);
2562  return false;
2563  }
2565  switch (s->action_scope) {
2566  case ACTION_SCOPE_PACKET:
2567  if (!(DetectProtoContainsProto(&s->init_data->proto, IPPROTO_UDP))) {
2568  if (s->action & (ACTION_ACCEPT | ACTION_DROP)) {
2569  SCLogError("rule %u uses action scope \"packet\" for an non-UDP app hook",
2570  s->id);
2571  return false;
2572  }
2573  }
2574  break;
2575  case ACTION_SCOPE_FLOW:
2576  case ACTION_SCOPE_AUTO:
2577  case ACTION_SCOPE_TX:
2578  case ACTION_SCOPE_HOOK:
2579  // supported for app hooks
2580  break;
2581  }
2582  }
2583  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
2584  if (!(((s->action & ACTION_ACCEPT) != 0) &&
2586  s->action_scope == ACTION_SCOPE_HOOK))) {
2587  SCLogError("rule %u: auto-accept notation (<hook) can only be used with accept:flow, "
2588  "accept:tx and accept:hook",
2589  s->id);
2590  return false;
2591  }
2592  }
2593 
2594  return true;
2595 }
2596 
2597 static void DetectRuleSetTable(Signature *s)
2598 {
2599  enum DetectTable table;
2600  if (s->flags & SIG_FLAG_FIREWALL) {
2601  if (s->type == SIG_TYPE_PKT) {
2605  else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
2608  else
2610  } else if (s->type == SIG_TYPE_APP_TX) {
2611  table = DETECT_TABLE_APP_FILTER;
2612  } else {
2613  BUG_ON(1);
2614  }
2615  } else {
2616  // TODO pre_flow/pre_stream
2617  if (s->type != SIG_TYPE_APP_TX) {
2618  table = DETECT_TABLE_PACKET_TD;
2619  } else {
2620  table = DETECT_TABLE_APP_TD;
2621  }
2622  }
2623 
2624  s->detect_table = (uint8_t)table;
2625 }
2626 
2627 static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2628 {
2629  if (s->init_data->firewall_rule) {
2630  if (!DetectFirewallRuleValidate(de_ctx, s))
2631  SCReturnInt(0);
2632  }
2633  SCReturnInt(1);
2634 }
2635 
2636 static int SigValidateCheckBuffers(
2637  DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2638 {
2639  bool has_frame = false;
2640  bool has_app = false;
2641  bool has_pkt = false;
2642  bool has_pmatch = false;
2643 
2644  int nlists = 0;
2645  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2646  nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2647  }
2648  nlists += (nlists > 0);
2649  SCLogDebug("nlists %d", nlists);
2650 
2651  if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2652  SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2654  SCReturnInt(0);
2655  }
2656 
2657  /* run buffer type validation callbacks if any */
2660  SCReturnInt(0);
2661 
2662  has_pmatch = true;
2663  }
2664 
2665  DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
2666  struct BufferVsDir {
2667  int ts;
2668  int tc;
2669  } bufdir[nlists + 1];
2670  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2671 
2672  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2675  if (bt == NULL) {
2676  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2677  continue;
2678  }
2679  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2680  for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2681  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2682  }
2683 
2684  if (b->head == NULL) {
2685  SCLogError("no matches in sticky buffer %s", bt->name);
2686  SCReturnInt(0);
2687  }
2688 
2689  has_frame |= bt->frame;
2690  has_app |= (!bt->frame && !bt->packet);
2691  has_pkt |= bt->packet;
2692 
2693  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2694  SCLogError("Signature combines packet "
2695  "specific matches (like dsize, flags, ttl) with stream / "
2696  "state matching by matching on app layer proto (like using "
2697  "http_* keywords).");
2698  SCReturnInt(0);
2699  }
2700 
2702  for (; app != NULL; app = app->next) {
2703  if (app->sm_list != b->id)
2704  continue;
2705 
2707  /* only allow rules to use the hook for engines at that
2708  * exact progress for now. */
2709  if (app->alproto != s->alproto) {
2710  continue;
2711  }
2712  } else {
2713  if (!(AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2714  continue;
2715  }
2716  }
2717 
2718  SCLogDebug("engine %s dir %d alproto %d",
2720  app->alproto);
2721  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2722 
2723  if (b->only_tc) {
2724  if (app->dir == 1)
2725  (*tc_excl)++;
2726  } else if (b->only_ts) {
2727  if (app->dir == 0)
2728  (*ts_excl)++;
2729  } else {
2730  bufdir[b->id].ts += (app->dir == 0);
2731  bufdir[b->id].tc += (app->dir == 1);
2732  }
2733 
2735  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2736  app->progress != s->init_data->hook.t.app.app_progress) {
2737  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2738  s->init_data->hook.t.app.app_progress);
2739  SCReturnInt(0);
2740  }
2741  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2742  app->progress != s->init_data->hook.t.app.app_progress) {
2743  SCLogError("engine progress value doesn't match hook");
2744  SCReturnInt(0);
2745  }
2746  }
2747  }
2748 
2750  SCReturnInt(0);
2751  }
2752 
2754  SCReturnInt(0);
2755  }
2757  SCReturnInt(0);
2758  }
2759  }
2760 
2761  if (has_pmatch && has_frame) {
2762  SCLogError("can't mix pure content and frame inspection");
2763  SCReturnInt(0);
2764  }
2765  if (has_app && has_frame) {
2766  SCLogError("can't mix app-layer buffer and frame inspection");
2767  SCReturnInt(0);
2768  }
2769  if (has_pkt && has_frame) {
2770  SCLogError("can't mix pkt buffer and frame inspection");
2771  SCReturnInt(0);
2772  }
2773 
2774  for (int x = 0; x < nlists; x++) {
2775  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2776  continue;
2777  (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2778  (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2779  (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2780 
2781  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2782  bufdir[x].tc);
2783  }
2784 
2785  SCReturnInt(1);
2786 }
2787 
2788 static int SigValidatePacketStream(const Signature *s)
2789 {
2791  SCLogError("can't mix packet keywords with "
2792  "tcp-stream or flow:only_stream. Invalidating signature.");
2793  SCReturnInt(0);
2794  }
2795  SCReturnInt(1);
2796 }
2797 
2798 static int SigConsolidateDirection(
2799  Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2800 {
2801  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2802  if (!ts_excl || !tc_excl) {
2803  SCLogError("rule %u should use both directions, but does not", s->id);
2804  SCReturnInt(0);
2805  }
2806  if (dir_amb) {
2807  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2808  "directions",
2809  s->id);
2810  SCReturnInt(0);
2811  }
2812  } else if (ts_excl && tc_excl) {
2813  SCLogError(
2814  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2815  "should be used",
2816  s->id);
2817  SCReturnInt(0);
2818  } else if (ts_excl) {
2819  SCLogDebug("%u: implied rule direction is toserver", s->id);
2821  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2822  SCReturnInt(0);
2823  }
2824  } else if (tc_excl) {
2825  SCLogDebug("%u: implied rule direction is toclient", s->id);
2827  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2828  SCReturnInt(0);
2829  }
2830  } else if (dir_amb) {
2831  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2832  }
2833  SCReturnInt(1);
2834 }
2835 
2836 static void SigConsolidateTcpBuffer(Signature *s)
2837 {
2838  /* TCP: corner cases:
2839  * - pkt vs stream vs depth/offset
2840  * - pkt vs stream vs stream_size
2841  */
2842  if (DetectProtoContainsProto(&s->init_data->proto, IPPROTO_TCP)) {
2846  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2847  sm = sm->next) {
2848  if (sm->type == DETECT_CONTENT &&
2849  (((DetectContentData *)(sm->ctx))->flags &
2852  break;
2853  }
2854  }
2855  /* if stream_size is in use, also inspect packets */
2856  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2857  sm = sm->next) {
2858  if (sm->type == DETECT_STREAM_SIZE) {
2860  break;
2861  }
2862  }
2863  }
2864  }
2865  }
2866 }
2867 
2868 static bool SigInspectsFiles(const Signature *s)
2869 {
2870  return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2872 }
2873 
2874 /** \internal
2875  * \brief validate file handling
2876  * \retval 1 good signature
2877  * \retval 0 bad signature
2878  */
2879 static int SigValidateFileHandling(const Signature *s)
2880 {
2881  if (!SigInspectsFiles(s)) {
2882  SCReturnInt(1);
2883  }
2884 
2885  if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
2886  !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
2887  SCLogError("protocol %s doesn't "
2888  "support file matching",
2890  SCReturnInt(0);
2891  }
2892  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2893  bool found = false;
2894  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2895  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2896  break;
2897  }
2898  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
2899  AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
2900  found = true;
2901  break;
2902  }
2903  }
2904  if (!found) {
2905  SCLogError("No protocol support file matching");
2906  SCReturnInt(0);
2907  }
2908  }
2910  SCLogError("protocol HTTP2 doesn't support file name matching");
2911  SCReturnInt(0);
2912  }
2913  SCReturnInt(1);
2914 }
2915 
2916 static bool SigValidateEthernet(const Signature *s)
2917 {
2919  if ((s->flags & (SIG_FLAG_SP_ANY | SIG_FLAG_DP_ANY)) !=
2921  SCLogError("can't use ports with ether or arp rule");
2922  return false;
2923  }
2924  }
2925  return true;
2926 }
2927 
2928 /* `pkthdr` is meant to allow matching on "any" packet with a decoder event. */
2929 static bool SigValidateProtoPkthdr(const Signature *s)
2930 {
2932  SCLogError("protocol 'pkthdr' is for decoder-events only");
2933  return false;
2934  }
2935  return true;
2936 }
2937 
2938 /**
2939  * \internal
2940  * \brief validate and consolidate parsed signature
2941  *
2942  * \param de_ctx detect engine
2943  * \param s signature to validate and consolidate
2944  *
2945  * \retval 0 invalid
2946  * \retval 1 valid
2947  */
2948 static int SigValidateConsolidate(
2949  DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2950 {
2951  SCEnter();
2952 
2953  if (SigValidateFirewall(de_ctx, s) == 0)
2954  SCReturnInt(0);
2955 
2956  if (SigValidatePacketStream(s) == 0) {
2957  SCReturnInt(0);
2958  }
2959 
2960  if (!SigValidateEthernet(s)) {
2961  SCReturnInt(0);
2962  }
2963 
2964  int ts_excl = 0;
2965  int tc_excl = 0;
2966  int dir_amb = 0;
2967 
2968  if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
2969  SCReturnInt(0);
2970  }
2971 
2972  if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
2973  SCReturnInt(0);
2974  }
2975 
2976  SigConsolidateTcpBuffer(s);
2977 
2979  DetectRuleSetTable(s);
2980 
2981  if (!SigValidateProtoPkthdr(s)) {
2982  SCReturnInt(0);
2983  }
2984 
2985  if (DetectProtoFinalizeSignature(s) != 0)
2986  SCReturnInt(0);
2987 
2988  int r = SigValidateFileHandling(s);
2989  if (r == 0) {
2990  SCReturnInt(0);
2991  }
2992  if (SigInspectsFiles(s)) {
2993  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2995  }
2996  }
2997  if (DetectRuleValidateTable(s) == false) {
2998  SCReturnInt(0);
2999  }
3000 
3001  if (s->type == SIG_TYPE_IPONLY) {
3002  /* For IPOnly */
3003  if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
3004  SCReturnInt(0);
3005 
3006  if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
3007  SCReturnInt(0);
3008  }
3009  SCReturnInt(1);
3010 }
3011 
3012 /**
3013  * \internal
3014  * \brief Helper function for SigInit().
3015  */
3016 static Signature *SigInitHelper(
3017  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
3018 {
3019  SignatureParser parser;
3020  memset(&parser, 0x00, sizeof(parser));
3021 
3022  Signature *sig = SigAlloc();
3023  if (sig == NULL)
3024  goto error;
3025  if (firewall_rule) {
3026  sig->init_data->firewall_rule = true;
3027  sig->flags |= SIG_FLAG_FIREWALL;
3028  }
3029 
3030  sig->sig_str = SCStrdup(sigstr);
3031  if (unlikely(sig->sig_str == NULL)) {
3032  goto error;
3033  }
3034 
3035  /* default gid to 1 */
3036  sig->gid = 1;
3037 
3038  /* We do a first parse of the rule in a requires, or scan-only
3039  * mode. Syntactic errors will be picked up here, but the only
3040  * part of the rule that is validated completely is the "requires"
3041  * keyword. */
3042  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
3043  if (ret == -4) {
3044  /* Rule requirements not met. */
3045  de_ctx->sigerror_silent = true;
3046  de_ctx->sigerror_ok = true;
3047  de_ctx->sigerror_requires = true;
3048  goto error;
3049  } else if (ret < 0) {
3050  goto error;
3051  }
3052 
3053  /* Check for a SID before continuuing. */
3054  if (sig->id == 0) {
3055  SCLogError("Signature missing required value \"sid\".");
3056  goto error;
3057  }
3058 
3059  /* Now completely parse the rule. */
3060  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
3061  BUG_ON(ret == -4);
3062  if (ret == -3) {
3063  de_ctx->sigerror_silent = true;
3064  de_ctx->sigerror_ok = true;
3065  goto error;
3066  } else if (ret == -2) {
3067  de_ctx->sigerror_silent = true;
3068  goto error;
3069  } else if (ret < 0) {
3070  goto error;
3071  }
3072 
3073  /* signature priority hasn't been overwritten. Using default priority */
3074  if (sig->prio == -1)
3075  sig->prio = DETECT_DEFAULT_PRIO;
3076 
3077  sig->iid = de_ctx->signum;
3078  de_ctx->signum++;
3079 
3080  if (sig->alproto != ALPROTO_UNKNOWN) {
3081  int override_needed = 0;
3082  if (sig->init_data->proto.flags & DETECT_PROTO_ANY) {
3084  memset(sig->init_data->proto.proto, 0x00, sizeof(sig->init_data->proto.proto));
3085  override_needed = 1;
3086  } else {
3087  override_needed = 1;
3088  size_t s = 0;
3089  for (s = 0; s < sizeof(sig->init_data->proto.proto); s++) {
3090  if (sig->init_data->proto.proto[s] != 0x00) {
3091  override_needed = 0;
3092  break;
3093  }
3094  }
3095  }
3096 
3097  /* at this point if we had alert ip and the ip proto was not
3098  * overridden, we use the ip proto that has been configured
3099  * against the app proto in use. */
3100  if (override_needed)
3102  }
3103 
3104  /* set the packet and app layer flags, but only if the
3105  * app layer flag wasn't already set in which case we
3106  * only consider the app layer */
3107  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
3108  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
3110  for ( ; sm != NULL; sm = sm->next) {
3111  if (sigmatch_table[sm->type].Match != NULL)
3113  }
3114  } else {
3116  }
3117  }
3118 
3119  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
3120  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
3121  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
3123  }
3124  }
3125  }
3126 
3127  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
3128  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
3129  sig->flags |= SIG_FLAG_TOSERVER;
3130  sig->flags |= SIG_FLAG_TOCLIENT;
3131  }
3132  }
3133 
3134  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
3135  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
3136  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
3137 
3138  SigBuildAddressMatchArray(sig);
3139 
3140  /* run buffer type callbacks if any */
3141  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
3142  if (sig->init_data->smlists[x])
3144  }
3145  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
3147  }
3148 
3149  SigSetupPrefilter(de_ctx, sig);
3150 
3151  /* validate signature, SigValidate will report the error reason */
3152  if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3153  goto error;
3154  }
3155 
3156  return sig;
3157 
3158 error:
3159  if (sig != NULL) {
3160  SigFree(de_ctx, sig);
3161  }
3162  return NULL;
3163 }
3164 
3165 /**
3166  * \brief Checks if a signature has the same source and destination
3167  * \param s parsed signature
3168  *
3169  * \retval true if source and destination are the same, false otherwise
3170  */
3171 static bool SigHasSameSourceAndDestination(const Signature *s)
3172 {
3173  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3174  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3175  return false;
3176  }
3177  }
3178 
3179  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3182 
3184  return false;
3185  }
3186 
3187  src = s->init_data->src->ipv6_head;
3188  dst = s->init_data->dst->ipv6_head;
3189 
3191  return false;
3192  }
3193  }
3194 
3195  return true;
3196 }
3197 
3198 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3199 {
3200  SCEnter();
3201 
3202  uint32_t oldsignum = de_ctx->signum;
3203  de_ctx->sigerror_ok = false;
3204  de_ctx->sigerror_silent = false;
3205  de_ctx->sigerror_requires = false;
3206 
3207  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3208  if (sig == NULL) {
3209  goto error;
3210  }
3211 
3213  if (SigHasSameSourceAndDestination(sig)) {
3214  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3215  "treating the rule as unidirectional", sig->id);
3216 
3218  } else {
3219  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3220  if (sig->next == NULL) {
3221  goto error;
3222  }
3223  }
3224  }
3225 
3226  SCReturnPtr(sig, "Signature");
3227 
3228 error:
3229  if (sig != NULL) {
3230  SigFree(de_ctx, sig);
3231  }
3232  /* if something failed, restore the old signum count
3233  * since we didn't install it */
3234  de_ctx->signum = oldsignum;
3235 
3236  SCReturnPtr(NULL, "Signature");
3237 }
3238 
3239 /**
3240  * \brief Parses a signature and adds it to the Detection Engine Context.
3241  *
3242  * \param de_ctx Pointer to the Detection Engine Context.
3243  * \param sigstr Pointer to a character string containing the signature to be
3244  * parsed.
3245  *
3246  * \retval Pointer to the Signature instance on success; NULL on failure.
3247  */
3248 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3249 {
3250  return SigInitDo(de_ctx, sigstr, false);
3251 }
3252 
3253 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3254 {
3255  return SigInitDo(de_ctx, sigstr, true);
3256 }
3257 
3258 /**
3259  * \brief The hash free function to be the used by the hash table -
3260  * DetectEngineCtx->dup_sig_hash_table.
3261  *
3262  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3263  */
3264 static void DetectParseDupSigFreeFunc(void *data)
3265 {
3266  if (data != NULL)
3267  SCFree(data);
3268 }
3269 
3270 /**
3271  * \brief The hash function to be the used by the hash table -
3272  * DetectEngineCtx->dup_sig_hash_table.
3273  *
3274  * \param ht Pointer to the hash table.
3275  * \param data Pointer to the data, in our case SigDuplWrapper.
3276  * \param datalen Not used in our case.
3277  *
3278  * \retval sw->s->id The generated hash value.
3279  */
3280 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3281 {
3282  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3283 
3284  return (sw->s->id % ht->array_size);
3285 }
3286 
3287 /**
3288  * \brief The Compare function to be used by the hash table -
3289  * DetectEngineCtx->dup_sig_hash_table.
3290  *
3291  * \param data1 Pointer to the first SigDuplWrapper.
3292  * \param len1 Not used.
3293  * \param data2 Pointer to the second SigDuplWrapper.
3294  * \param len2 Not used.
3295  *
3296  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3297  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3298  */
3299 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3300  uint16_t len2)
3301 {
3302  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3303  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3304 
3305  if (sw1 == NULL || sw2 == NULL ||
3306  sw1->s == NULL || sw2->s == NULL)
3307  return 0;
3308 
3309  /* sid and gid match required */
3310  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3311 
3312  return 0;
3313 }
3314 
3315 /**
3316  * \brief Initializes the hash table that is used to cull duplicate sigs.
3317  *
3318  * \param de_ctx Pointer to the detection engine context.
3319  *
3320  * \retval 0 On success.
3321  * \retval -1 On failure.
3322  */
3324 {
3326  DetectParseDupSigHashFunc,
3327  DetectParseDupSigCompareFunc,
3328  DetectParseDupSigFreeFunc);
3329  if (de_ctx->dup_sig_hash_table == NULL)
3330  return -1;
3331 
3332  return 0;
3333 }
3334 
3335 /**
3336  * \brief Frees the hash table that is used to cull duplicate sigs.
3337  *
3338  * \param de_ctx Pointer to the detection engine context that holds this table.
3339  */
3341 {
3342  if (de_ctx->dup_sig_hash_table != NULL)
3344 
3345  de_ctx->dup_sig_hash_table = NULL;
3346 }
3347 
3348 /**
3349  * \brief Check if a signature is a duplicate.
3350  *
3351  * There are 3 types of return values for this function.
3352  *
3353  * - 0, which indicates that the Signature is not a duplicate
3354  * and has to be added to the detection engine list.
3355  * - 1, Signature is duplicate, and the existing signature in
3356  * the list shouldn't be replaced with this duplicate.
3357  * - 2, Signature is duplicate, and the existing signature in
3358  * the list should be replaced with this duplicate.
3359  *
3360  * \param de_ctx Pointer to the detection engine context.
3361  * \param sig Pointer to the Signature that has to be checked.
3362  *
3363  * \retval 2 If Signature is duplicate and the existing signature in
3364  * the list should be chucked out and replaced with this.
3365  * \retval 1 If Signature is duplicate, and should be chucked out.
3366  * \retval 0 If Signature is not a duplicate.
3367  */
3368 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3369  Signature *sig)
3370 {
3371  /* we won't do any NULL checks on the args */
3372 
3373  /* return value */
3374  int ret = 0;
3375 
3376  SigDuplWrapper *sw_dup = NULL;
3377  SigDuplWrapper *sw = NULL;
3378 
3379  /* used for making a duplicate_sig_hash_table entry */
3380  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3381  if (unlikely(sw == NULL)) {
3382  exit(EXIT_FAILURE);
3383  }
3384  sw->s = sig;
3385 
3386  /* check if we have a duplicate entry for this signature */
3387  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3388  /* we don't have a duplicate entry for this sig */
3389  if (sw_dup == NULL) {
3390  /* add it to the hash table */
3391  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3392 
3393  /* add the s_prev entry for the previously loaded sw in the hash_table */
3394  if (de_ctx->sig_list != NULL) {
3395  SigDuplWrapper *sw_old = NULL;
3396  SigDuplWrapper sw_tmp;
3397  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3398 
3399  /* the topmost sig would be the last loaded sig */
3400  sw_tmp.s = de_ctx->sig_list;
3402  (void *)&sw_tmp, 0);
3403  /* sw_old == NULL case is impossible: every sig in sig_list
3404  * must have a corresponding dup_sig_hash_table entry */
3405  DEBUG_VALIDATE_BUG_ON(sw_old == NULL);
3406  sw_old->s_prev = sig;
3407  }
3408 
3409  ret = 0;
3410  goto end;
3411  }
3412 
3413  /* if we have reached here we have a duplicate entry for this signature.
3414  * Check the signature revision. Store the signature with the latest rev
3415  * and discard the other one */
3416  if (sw->s->rev <= sw_dup->s->rev) {
3417  ret = 1;
3418  SCFree(sw);
3419  sw = NULL;
3420  goto end;
3421  }
3422 
3423  /* the new sig is of a newer revision than the one that is already in the
3424  * list. Remove the old sig from the list */
3425  if (sw_dup->s_prev == NULL) {
3426  SigDuplWrapper sw_temp;
3427  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3428  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3429  sw_temp.s = sw_dup->s->next->next;
3430  de_ctx->sig_list = sw_dup->s->next->next;
3431  SigFree(de_ctx, sw_dup->s->next);
3432  } else {
3433  sw_temp.s = sw_dup->s->next;
3434  de_ctx->sig_list = sw_dup->s->next;
3435  }
3436  SigDuplWrapper *sw_next = NULL;
3437  if (sw_temp.s != NULL) {
3439  (void *)&sw_temp, 0);
3440  DEBUG_VALIDATE_BUG_ON(sw_next == NULL);
3441  sw_next->s_prev = sw_dup->s_prev;
3442  }
3443  SigFree(de_ctx, sw_dup->s);
3444  } else {
3445  SigDuplWrapper sw_temp;
3446  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3447  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3448  sw_temp.s = sw_dup->s->next->next;
3449  /* If previous signature is bidirectional,
3450  * it has 2 items in the linked list.
3451  * So we need to change next->next instead of next
3452  */
3454  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3455  } else {
3456  sw_dup->s_prev->next = sw_dup->s->next->next;
3457  }
3458  SigFree(de_ctx, sw_dup->s->next);
3459  } else {
3460  sw_temp.s = sw_dup->s->next;
3462  sw_dup->s_prev->next->next = sw_dup->s->next;
3463  } else {
3464  sw_dup->s_prev->next = sw_dup->s->next;
3465  }
3466  }
3467  SigDuplWrapper *sw_next = NULL;
3468  if (sw_temp.s != NULL) {
3470  (void *)&sw_temp, 0);
3471  DEBUG_VALIDATE_BUG_ON(sw_next == NULL);
3472  sw_next->s_prev = sw_dup->s_prev;
3473  }
3474  SigFree(de_ctx, sw_dup->s);
3475  }
3476 
3477  /* make changes to the entry to reflect the presence of the new sig */
3478  sw_dup->s = sig;
3479  sw_dup->s_prev = NULL;
3480 
3481  if (de_ctx->sig_list != NULL) {
3482  SigDuplWrapper sw_tmp;
3483  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3484  sw_tmp.s = de_ctx->sig_list;
3486  (void *)&sw_tmp, 0);
3487  DEBUG_VALIDATE_BUG_ON(sw_old == NULL);
3488  if (sw_old->s != sw_dup->s) {
3489  // Link on top of the list if there was another element
3490  sw_old->s_prev = sig;
3491  }
3492  }
3493 
3494  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3495  ret = 2;
3496 
3497  SCFree(sw);
3498 
3499 end:
3500  return ret;
3501 }
3502 
3503 /**
3504  * \brief Parse and append a Signature into the Detection Engine Context
3505  * signature list.
3506  *
3507  * If the signature is bidirectional it should append two signatures
3508  * (with the addresses switched) into the list. Also handle duplicate
3509  * signatures. In case of duplicate sigs, use the ones that have the
3510  * latest revision. We use the sid and the msg to identify duplicate
3511  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3512  *
3513  * \param de_ctx Pointer to the Detection Engine Context.
3514  * \param sigstr Pointer to a character string containing the signature to be
3515  * parsed.
3516  * \param sig_file Pointer to a character string containing the filename from
3517  * which signature is read
3518  * \param lineno Line number from where signature is read
3519  *
3520  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3521  * on success; NULL on failure.
3522  */
3524 {
3525  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3526  if (sig == NULL) {
3527  return NULL;
3528  }
3529 
3530  /* checking for the status of duplicate signature */
3531  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3532  /* a duplicate signature that should be chucked out. Check the previously
3533  * called function details to understand the different return values */
3534  if (dup_sig == 1) {
3535  SCLogError("Duplicate signature \"%s\"", sigstr);
3536  goto error;
3537  } else if (dup_sig == 2) {
3538  SCLogWarning("Signature with newer revision,"
3539  " so the older sig replaced by this new signature \"%s\"",
3540  sigstr);
3541  }
3542 
3544  if (sig->next != NULL) {
3545  sig->next->next = de_ctx->sig_list;
3546  } else {
3547  goto error;
3548  }
3549  } else {
3550  /* if this sig is the first one, sig_list should be null */
3551  sig->next = de_ctx->sig_list;
3552  }
3553 
3554  de_ctx->sig_list = sig;
3555 
3556  /**
3557  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3558  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3559  * to the cloned signatures with the switched addresses
3560  */
3561  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3562 
3563 error:
3564  /* free the 2nd sig bidir may have set up */
3565  if (sig != NULL && sig->next != NULL) {
3566  SigFree(de_ctx, sig->next);
3567  sig->next = NULL;
3568  }
3569  if (sig != NULL) {
3570  SigFree(de_ctx, sig);
3571  }
3572  return NULL;
3573 }
3574 
3575 /**
3576  * \brief Parse and append a Signature into the Detection Engine Context
3577  * signature list.
3578  *
3579  * If the signature is bidirectional it should append two signatures
3580  * (with the addresses switched) into the list. Also handle duplicate
3581  * signatures. In case of duplicate sigs, use the ones that have the
3582  * latest revision. We use the sid and the msg to identify duplicate
3583  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3584  *
3585  * \param de_ctx Pointer to the Detection Engine Context.
3586  * \param sigstr Pointer to a character string containing the signature to be
3587  * parsed.
3588  * \param sig_file Pointer to a character string containing the filename from
3589  * which signature is read
3590  * \param lineno Line number from where signature is read
3591  *
3592  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3593  * on success; NULL on failure.
3594  */
3596 {
3597  Signature *sig = SigInit(de_ctx, sigstr);
3598  if (sig == NULL) {
3599  return NULL;
3600  }
3601 
3602  /* checking for the status of duplicate signature */
3603  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3604  /* a duplicate signature that should be chucked out. Check the previously
3605  * called function details to understand the different return values */
3606  if (dup_sig == 1) {
3607  SCLogError("Duplicate signature \"%s\"", sigstr);
3608  goto error;
3609  } else if (dup_sig == 2) {
3610  SCLogWarning("Signature with newer revision,"
3611  " so the older sig replaced by this new signature \"%s\"",
3612  sigstr);
3613  }
3614 
3616  if (sig->next != NULL) {
3617  sig->next->next = de_ctx->sig_list;
3618  } else {
3619  goto error;
3620  }
3621  } else {
3622  /* if this sig is the first one, sig_list should be null */
3623  sig->next = de_ctx->sig_list;
3624  }
3625 
3626  de_ctx->sig_list = sig;
3627 
3628  /**
3629  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3630  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3631  * to the cloned signatures with the switched addresses
3632  */
3633  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3634 
3635 error:
3636  /* free the 2nd sig bidir may have set up */
3637  if (sig != NULL && sig->next != NULL) {
3638  SigFree(de_ctx, sig->next);
3639  sig->next = NULL;
3640  }
3641  if (sig != NULL) {
3642  SigFree(de_ctx, sig);
3643  }
3644  return NULL;
3645 }
3646 
3647 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3648 
3649 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3650  int start_offset, int options)
3651 {
3652  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3653  if (*match)
3654  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3655  *match, parse_regex->context);
3656  return -1;
3657 }
3658 
3660 {
3661  if (r->regex) {
3662  pcre2_code_free(r->regex);
3663  }
3664  if (r->context) {
3665  pcre2_match_context_free(r->context);
3666  }
3667 }
3668 
3670 {
3671  DetectParseRegex *r = g_detect_parse_regex_list;
3672  while (r) {
3673  DetectParseRegex *next = r->next;
3674 
3676 
3677  SCFree(r);
3678  r = next;
3679  }
3680  g_detect_parse_regex_list = NULL;
3681 }
3682 
3683 /** \brief add regex and/or study to at exit free list
3684  */
3686 {
3687  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3688  if (r == NULL) {
3689  FatalError("failed to alloc memory for pcre free list");
3690  }
3691  r->regex = detect_parse->regex;
3692  r->next = g_detect_parse_regex_list;
3693  g_detect_parse_regex_list = r;
3694 }
3695 
3696 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3697 {
3698  int en;
3699  PCRE2_SIZE eo;
3700 
3701  detect_parse->regex =
3702  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3703  if (detect_parse->regex == NULL) {
3704  PCRE2_UCHAR errbuffer[256];
3705  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3706  SCLogError("pcre compile of \"%s\" failed at "
3707  "offset %d: %s",
3708  parse_str, en, errbuffer);
3709  return false;
3710  }
3711  detect_parse->context = pcre2_match_context_create(NULL);
3712  if (detect_parse->context == NULL) {
3713  SCLogError("pcre2 could not create match context");
3714  pcre2_code_free(detect_parse->regex);
3715  detect_parse->regex = NULL;
3716  return false;
3717  }
3718  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3719  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3720  DetectParseRegexAddToFreeList(detect_parse);
3721 
3722  return true;
3723 }
3724 
3725 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3726 {
3727  int en;
3728  PCRE2_SIZE eo;
3729  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3730  if (detect_parse == NULL) {
3731  return NULL;
3732  }
3733 
3734  detect_parse->regex =
3735  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3736  if (detect_parse->regex == NULL) {
3737  PCRE2_UCHAR errbuffer[256];
3738  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3739  SCLogError("pcre2 compile of \"%s\" failed at "
3740  "offset %d: %s",
3741  parse_str, (int)eo, errbuffer);
3742  SCFree(detect_parse);
3743  return NULL;
3744  }
3745 
3746  detect_parse->next = g_detect_parse_regex_list;
3747  g_detect_parse_regex_list = detect_parse;
3748  return detect_parse;
3749 }
3750 
3752  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3753 {
3754  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3755  if (r == PCRE2_ERROR_UNSET) {
3756  buffer[0] = 0;
3757  *bufflen = 0;
3758  return 0;
3759  }
3760  return r;
3761 }
3762 
3764  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3765 {
3766  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3767  if (r == PCRE2_ERROR_UNSET) {
3768  *bufferptr = NULL;
3769  *bufflen = 0;
3770  return 0;
3771  }
3772  return r;
3773 }
3774 
3775 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3776 {
3777  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3778  FatalError("pcre compile and study failed");
3779  }
3780 }
3781 
3782 static uint32_t PolicySignatureHashFunc(HashTable *ht, void *data, uint16_t datalen)
3783 {
3784  const Signature *s = data;
3785  const int dir = 1 + (s->flags & SIG_FLAG_TOSERVER) != 0; // 2 for ts, 1 for tc
3786  uint32_t hash = s->alproto * s->app_progress_hook * dir;
3787  hash = hash % ht->array_size;
3788  return hash;
3789 }
3790 
3791 static char PolicySignatureCompareFunc(
3792  void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
3793 {
3794  const Signature *s1 = data1;
3795  const Signature *s2 = data2;
3796 
3797  if (s1 == NULL || s2 == NULL)
3798  return 0;
3799 
3800  return s1->flags == s2->flags && s1->alproto == s2->alproto &&
3802 }
3803 
3804 static void PolicySignatureHashFree(void *data)
3805 {
3806  Signature *s = data;
3807  SCFree(s->msg);
3808  SCFree(s);
3809 }
3810 
3812 {
3813  switch (s) {
3814  case ACTION_SCOPE_PACKET:
3815  return "packet";
3816  case ACTION_SCOPE_FLOW:
3817  return "flow";
3818  case ACTION_SCOPE_HOOK:
3819  return "hook";
3820  case ACTION_SCOPE_TX:
3821  return "tx";
3822  case ACTION_SCOPE_AUTO:
3823  return "auto";
3824  }
3826  return "unknown";
3827 }
3828 
3829 void DetectFirewallPolicyToString(const struct DetectFirewallPolicy *p, char *out, size_t out_size)
3830 {
3831  const char *as = ActionScopeToString(p->action_scope);
3832  DEBUG_VALIDATE_BUG_ON(as == NULL);
3833  if (as == NULL)
3834  return;
3835  if (p->action & ACTION_REJECT_ANY) {
3836  if (p->action & ACTION_REJECT_DST) {
3837  snprintf(out, out_size, "rejectdst:%s", as);
3838  } else if (p->action & ACTION_REJECT_BOTH) {
3839  snprintf(out, out_size, "rejectboth:%s", as);
3840  } else {
3841  snprintf(out, out_size, "rejectsrc:%s", as);
3842  }
3843  } else if (p->action & ACTION_DROP) {
3844  snprintf(out, out_size, "drop:%s", as);
3845  } else if (p->action & ACTION_ACCEPT) {
3846  snprintf(out, out_size, "accept:%s", as);
3847  } else {
3849  }
3850  if (p->action & ACTION_PASS) {
3851  if (p->action_scope == ACTION_SCOPE_FLOW) {
3852  strlcat(out, ",pass:flow", out_size);
3853  } else {
3855  }
3856  }
3857  if (p->action & ACTION_ALERT) {
3858  strlcat(out, ",alert", out_size);
3859  }
3860 }
3861 
3862 static int AddPktPolicySignature(struct DetectFirewallPolicies *fw_policies,
3863  struct DetectFirewallPolicy *pol, enum DetectFirewallPacketPolicies pkt_pol)
3864 {
3865  Signature *s = SCCalloc(1, sizeof(*s)); // SigAlloc does way more than we need
3866  if (s == NULL)
3867  return -1;
3868  char msg[256];
3869  switch (pkt_pol) {
3872  break;
3875  break;
3878  break;
3879  }
3880  snprintf(msg, sizeof(msg), "SURICATA FW default packet policy");
3881  s->msg = SCStrdup(msg);
3882  if (s->msg == NULL) {
3883  SCFree(s);
3884  return -1;
3885  }
3886  s->action = pol->action;
3887  s->action_scope = pol->action_scope;
3888  s->flags = SIG_FLAG_FIREWALL;
3889  s->type = SIG_TYPE_PKT;
3890  s->id = 2201000;
3891  s->rev = 1;
3892  s->gid = 1;
3893  s->prio = 3;
3894 
3895  fw_policies->pkt_policy_signatures[pkt_pol] = s;
3896  SCLogDebug("added to array");
3897  return 0;
3898 }
3899 
3900 static int AddAppPolicySignature(HashTable *ht, const int direction, const AppProto alproto,
3901  const char *app_name, const uint8_t hook, const char *hookname,
3902  struct DetectFirewallPolicy *pol)
3903 {
3904  Signature *s = SCCalloc(1, sizeof(*s)); // SigAlloc does way more than we need
3905  if (s == NULL)
3906  return -1;
3907  char msg[256];
3908  snprintf(msg, sizeof(msg), "SURICATA FW default app policy");
3909  s->msg = SCStrdup(msg);
3910  if (s->msg == NULL) {
3911  SCFree(s);
3912  return -1;
3913  }
3914  s->app_progress_hook = hook;
3915  s->action = pol->action;
3916  s->action_scope = pol->action_scope;
3917  s->alproto = alproto;
3918  s->flags = (direction == STREAM_TOSERVER) ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT;
3919  s->flags |= SIG_FLAG_FIREWALL;
3920  s->type = SIG_TYPE_APP_TX;
3922  s->id = 2201001;
3923  s->rev = 1;
3924  s->gid = 1;
3925  s->prio = 3;
3926 
3927  if (HashTableAdd(ht, s, 0) != 0) {
3928  SCFree(s->msg);
3929  SCFree(s);
3930  return -1;
3931  }
3932  SCLogDebug("added to hash");
3933  return 0;
3934 }
3935 
3936 static int DoParsePolicy(const char *policy_name, struct DetectFirewallPolicy *pol)
3937 {
3938  SCConfNode *policy_actions = SCConfGetNode(policy_name);
3939  if (policy_actions == NULL) {
3940  SCLogDebug("fw: no policy at %s", policy_name);
3941  return 0;
3942  }
3943 
3944  uint8_t action = 0;
3945  uint8_t action_scope = 0;
3946  int idx = 0;
3947  SCConfNode *paction = NULL;
3948  TAILQ_FOREACH (paction, &policy_actions->head, next) {
3949  SCLogDebug("fw: %s => %s", policy_name, paction->val);
3950  if (SigParseActionDo(paction->val, idx, true, &action, &action_scope) < 0)
3951  return -1;
3952  idx++;
3953  }
3954  pol->action = action;
3955  pol->action_scope = action_scope;
3956  return 1;
3957 }
3958 
3959 static int DoParseAppPolicy(const char *prefix, const AppProto app_proto, const char *hookname,
3960  const uint8_t state, const uint8_t complete_state, const int direction,
3961  struct DetectFirewallPolicies *fw_policies, struct DetectFirewallAppPolicy *app_fw_policies)
3962 {
3963  char policy_name[256];
3964  const char *in_name = hookname;
3965  if (hookname == NULL) {
3966  if (state == 0) {
3967  if (direction == STREAM_TOSERVER)
3968  hookname = "request-started";
3969  else
3970  hookname = "response-started";
3971  } else if (state == complete_state) {
3972  if (direction == STREAM_TOSERVER)
3973  hookname = "request-complete";
3974  else
3975  hookname = "response-complete";
3976  }
3977  if (hookname == NULL)
3978  return 0;
3979  }
3980  char *nname = SCStrdup(hookname);
3981  if (nname == NULL)
3982  return -1;
3983  for (int i = 0; nname[i] != '\0'; i++) {
3984  if (nname[i] == '_')
3985  nname[i] = '-';
3986  }
3987 
3988  const char *app_name = AppProtoToString(app_proto);
3989  int r = snprintf(policy_name, sizeof(policy_name), "%s.%s.%s", prefix, app_name, nname);
3990  SCFree(nname);
3991  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
3992  FatalError("internal error: failed to assemble firewall policy config string");
3993  }
3994 
3995  struct DetectFirewallPolicy *pol;
3996  if (direction == STREAM_TOSERVER)
3997  pol = &app_fw_policies[app_proto].ts[state];
3998  else
3999  pol = &app_fw_policies[app_proto].tc[state];
4000  r = DoParsePolicy(policy_name, pol);
4001  if (r == 0 && in_name != NULL) {
4002  if (state == 0) {
4003  if (direction == STREAM_TOSERVER)
4004  hookname = "request-started";
4005  else
4006  hookname = "response-started";
4007  } else if (state == complete_state) {
4008  if (direction == STREAM_TOSERVER)
4009  hookname = "request-complete";
4010  else
4011  hookname = "response-complete";
4012  }
4013  if (hookname == NULL)
4014  return 0;
4015  r = snprintf(policy_name, sizeof(policy_name), "%s.%s.%s", prefix, app_name, hookname);
4016  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4017  FatalError("internal error: failed to assemble firewall policy config string");
4018  }
4019 
4020  r = DoParsePolicy(policy_name, pol);
4021  }
4022 
4023  /* for policies with an alert action, create a policy sig */
4024  if (r == 1 && pol->action & ACTION_ALERT) {
4025  SCLogDebug("adding policy signature");
4026  return AddAppPolicySignature(fw_policies->policy_signatures, direction, app_proto, app_name,
4027  state, hookname, pol);
4028  }
4029  return r;
4030 }
4031 
4032 /** \brief allocate and initialize to default values the policies table */
4034 {
4035  struct DetectFirewallPolicies *fw_policies = SCCalloc(
4036  1, sizeof(*fw_policies) + g_alproto_max * sizeof(struct DetectFirewallAppPolicy));
4037  if (fw_policies == NULL)
4038  return -1;
4039  struct DetectFirewallAppPolicy *app_fw_policies = fw_policies->app;
4040  if (app_fw_policies == NULL)
4041  goto error;
4042  fw_policies->policy_signatures = HashTableInit(
4043  512, PolicySignatureHashFunc, PolicySignatureCompareFunc, PolicySignatureHashFree);
4044  if (fw_policies->policy_signatures == NULL)
4045  goto error;
4046 
4049 
4052 
4055 
4056  for (AppProto a = 0; a < g_alproto_max; a++) {
4057  for (int i = 0; i < 48; i++) {
4058  app_fw_policies[a].ts[i].action = ACTION_DROP;
4059  app_fw_policies[a].ts[i].action_scope = ACTION_SCOPE_FLOW;
4060  app_fw_policies[a].tc[i].action = ACTION_DROP;
4061  app_fw_policies[a].tc[i].action_scope = ACTION_SCOPE_FLOW;
4062  }
4063  }
4064  de_ctx->fw_policies = fw_policies;
4065  return 0;
4066 
4067 error:
4068  SCFree(fw_policies);
4069  return -1;
4070 }
4071 
4073 {
4074  int r;
4075  char policy_name[256];
4076  char prefix[96] = "firewall.policies";
4077  if (strlen(de_ctx->config_prefix) > 0) {
4078  snprintf(prefix, sizeof(prefix), "%s.firewall.policies", de_ctx->config_prefix);
4079  }
4080 
4081  struct DetectFirewallPolicies *fw_policies = de_ctx->fw_policies;
4082  if (fw_policies == NULL)
4083  return -1;
4084  struct DetectFirewallAppPolicy *app_fw_policies = fw_policies->app;
4085  if (app_fw_policies == NULL)
4086  return -1;
4087 
4088  r = snprintf(policy_name, sizeof(policy_name), "%s.packet-filter", prefix);
4089  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4090  FatalError("internal error: failed to assemble firewall policy config string");
4091  }
4092  r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER]);
4093  if (r < 0)
4094  return -1;
4096  if (AddPktPolicySignature(fw_policies,
4099  return -1;
4100 
4101  r = snprintf(policy_name, sizeof(policy_name), "%s.packet-pre-flow", prefix);
4102  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4103  FatalError("internal error: failed to assemble firewall policy config string");
4104  }
4105  r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW]);
4106  if (r < 0)
4107  return -1;
4109  if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW],
4111  return -1;
4112 
4113  r = snprintf(policy_name, sizeof(policy_name), "%s.packet-pre-stream", prefix);
4114  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4115  FatalError("internal error: failed to assemble firewall policy config string");
4116  }
4117  r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM]);
4118  if (r < 0)
4119  return -1;
4121  if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM],
4123  return -1;
4124 
4125  for (AppProto a = 0; a < g_alproto_max; a++) {
4126  if (!AppProtoIsValid(a))
4127  continue;
4128 
4129  const uint8_t complete_state_ts =
4130  (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOSERVER);
4131  for (uint8_t state = 0; state <= complete_state_ts; state++) {
4132  const char *name =
4133  AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOSERVER);
4134  if (DoParseAppPolicy(prefix, a, name, state, complete_state_ts, STREAM_TOSERVER,
4135  fw_policies, app_fw_policies) < 0)
4136  return -1;
4137  }
4138 
4139  const uint8_t complete_state_tc =
4140  (const uint8_t)AppLayerParserGetStateProgressCompletionStatus(a, STREAM_TOCLIENT);
4141  for (uint8_t state = 0; state <= complete_state_tc; state++) {
4142  const char *name =
4143  AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOCLIENT);
4144  if (DoParseAppPolicy(prefix, a, name, state, complete_state_tc, STREAM_TOCLIENT,
4145  fw_policies, app_fw_policies) < 0)
4146  return -1;
4147  }
4148  }
4149 
4150  return 0;
4151 }
4152 
4154  const AppProto alproto, const int direction, const uint8_t hook)
4155 {
4156  if (fw_policies != NULL && fw_policies->policy_signatures != NULL) {
4157  Signature lookup;
4158  lookup.alproto = alproto;
4159  lookup.flags = SIG_FLAG_FIREWALL |
4160  (direction == STREAM_TOSERVER ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT);
4161  lookup.app_progress_hook = hook;
4162 
4163  Signature *s = HashTableLookup(fw_policies->policy_signatures, &lookup, 0);
4164  return s;
4165  }
4166  return NULL;
4167 }
4168 
4169 /*
4170  * TESTS
4171  */
4172 
4173 #ifdef UNITTESTS
4174 #include "detect-engine-alert.h"
4175 #include "packet.h"
4176 
4177 static int SigParseTest01 (void)
4178 {
4179  int result = 1;
4180  Signature *sig = NULL;
4181 
4183  if (de_ctx == NULL)
4184  goto end;
4185 
4186  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
4187  if (sig == NULL)
4188  result = 0;
4189 
4190 end:
4191  if (sig != NULL) SigFree(de_ctx, sig);
4192  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4193  return result;
4194 }
4195 
4196 static int SigParseTest02 (void)
4197 {
4198  int result = 0;
4199  Signature *sig = NULL;
4200  DetectPort *port = NULL;
4201 
4203 
4204  if (de_ctx == NULL)
4205  goto end;
4206 
4210 
4211  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;)");
4212  if (sig == NULL) {
4213  goto end;
4214  }
4215 
4216  int r = DetectPortParse(de_ctx, &port, "0:20");
4217  if (r < 0)
4218  goto end;
4219 
4220  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
4221  result = 1;
4222  } else {
4223  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
4224  }
4225 
4226 end:
4227  if (port != NULL)
4229  if (sig != NULL)
4230  SigFree(de_ctx, sig);
4231  if (de_ctx != NULL)
4233  return result;
4234 }
4235 
4236 /**
4237  * \test SigParseTest03 test for invalid direction operator in rule
4238  */
4239 static int SigParseTest03 (void)
4240 {
4241  int result = 1;
4242  Signature *sig = NULL;
4243 
4245  if (de_ctx == NULL)
4246  goto end;
4247 
4248  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
4249  if (sig != NULL) {
4250  result = 0;
4251  printf("expected NULL got sig ptr %p: ",sig);
4252  }
4253 
4254 end:
4255  if (sig != NULL) SigFree(de_ctx, sig);
4256  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4257  return result;
4258 }
4259 
4260 static int SigParseTest04 (void)
4261 {
4262  int result = 1;
4263  Signature *sig = NULL;
4264 
4266  if (de_ctx == NULL)
4267  goto end;
4268 
4269  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
4270  if (sig == NULL)
4271  result = 0;
4272 
4273 end:
4274  if (sig != NULL) SigFree(de_ctx, sig);
4275  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4276  return result;
4277 }
4278 
4279 /** \test Port validation */
4280 static int SigParseTest05 (void)
4281 {
4282  int result = 0;
4283  Signature *sig = NULL;
4284 
4286  if (de_ctx == NULL)
4287  goto end;
4288 
4289  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
4290  if (sig == NULL) {
4291  result = 1;
4292  } else {
4293  printf("signature didn't fail to parse as we expected: ");
4294  }
4295 
4296 end:
4297  if (sig != NULL) SigFree(de_ctx, sig);
4298  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4299  return result;
4300 }
4301 
4302 /** \test Parsing bug debugging at 2010-03-18 */
4303 static int SigParseTest06 (void)
4304 {
4305  int result = 0;
4306  Signature *sig = NULL;
4307 
4309  if (de_ctx == NULL)
4310  goto end;
4311 
4312  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;)");
4313  if (sig != NULL) {
4314  result = 1;
4315  } else {
4316  printf("signature failed to parse: ");
4317  }
4318 
4319 end:
4320  if (sig != NULL)
4321  SigFree(de_ctx, sig);
4322  if (de_ctx != NULL)
4324  return result;
4325 }
4326 
4327 /**
4328  * \test Parsing duplicate sigs.
4329  */
4330 static int SigParseTest07(void)
4331 {
4332  int result = 0;
4333 
4335  if (de_ctx == NULL)
4336  goto end;
4337 
4338  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4339  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4340 
4341  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
4342 
4343 end:
4344  if (de_ctx != NULL)
4346  return result;
4347 }
4348 
4349 /**
4350  * \test Parsing duplicate sigs.
4351  */
4352 static int SigParseTest08(void)
4353 {
4354  int result = 0;
4355 
4357  if (de_ctx == NULL)
4358  goto end;
4359 
4360  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4361  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
4362 
4363  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
4364  de_ctx->sig_list->rev == 2);
4365 
4366 end:
4367  if (de_ctx != NULL)
4369  return result;
4370 }
4371 
4372 /**
4373  * \test Parsing duplicate sigs.
4374  */
4375 static int SigParseTest09(void)
4376 {
4377  int result = 1;
4378 
4380  if (de_ctx == NULL)
4381  goto end;
4382 
4383  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4384  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
4385  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
4386  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
4387  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
4388  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
4389  de_ctx->sig_list->rev == 2);
4390  if (result == 0)
4391  goto end;
4392  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
4393  de_ctx->sig_list->next->rev == 6);
4394  if (result == 0)
4395  goto end;
4396 
4397  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
4398  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
4399  de_ctx->sig_list->rev == 2);
4400  if (result == 0)
4401  goto end;
4402  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
4403  de_ctx->sig_list->next->rev == 6);
4404  if (result == 0)
4405  goto end;
4406 
4407  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
4408  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
4409  de_ctx->sig_list->rev == 4);
4410  if (result == 0)
4411  goto end;
4412  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
4413  de_ctx->sig_list->next->rev == 6);
4414  if (result == 0)
4415  goto end;
4416 
4417 end:
4418  if (de_ctx != NULL)
4420  return result;
4421 }
4422 
4423 /**
4424  * \test Parsing duplicate sigs.
4425  */
4426 static int SigParseTest10(void)
4427 {
4428  int result = 1;
4429 
4431  if (de_ctx == NULL)
4432  goto end;
4433 
4434  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4435  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
4436  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
4437  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
4438  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
4439  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
4440  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
4441 
4442  result &= ((de_ctx->sig_list->id == 2) &&
4443  (de_ctx->sig_list->next->id == 3) &&
4444  (de_ctx->sig_list->next->next->id == 5) &&
4445  (de_ctx->sig_list->next->next->next->id == 4) &&
4446  (de_ctx->sig_list->next->next->next->next->id == 1));
4447 
4448 end:
4449  if (de_ctx != NULL)
4451  return result;
4452 }
4453 
4454 /**
4455  * \test Parsing sig with trailing space(s) as reported by
4456  * Morgan Cox on oisf-users.
4457  */
4458 static int SigParseTest11(void)
4459 {
4460  int result = 0;
4461 
4463  if (de_ctx == NULL)
4464  goto end;
4465 
4466  Signature *s = NULL;
4467 
4469  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
4470  if (s == NULL) {
4471  printf("sig 1 didn't parse: ");
4472  goto end;
4473  }
4474 
4475  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
4476  "the http link\"; sid:2;) ");
4477  if (s == NULL) {
4478  printf("sig 2 didn't parse: ");
4479  goto end;
4480  }
4481 
4482  result = 1;
4483 end:
4484  if (de_ctx != NULL)
4486  return result;
4487 }
4488 
4489 /**
4490  * \test file_data with rawbytes
4491  */
4492 static int SigParseTest12(void)
4493 {
4494  int result = 0;
4495 
4497  if (de_ctx == NULL)
4498  goto end;
4499 
4500  Signature *s = NULL;
4501 
4502  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
4503  if (s != NULL) {
4504  printf("sig 1 should have given an error: ");
4505  goto end;
4506  }
4507 
4508  result = 1;
4509 end:
4510  if (de_ctx != NULL)
4512  return result;
4513 }
4514 
4515 /**
4516  * \test packet/stream sig
4517  */
4518 static int SigParseTest13(void)
4519 {
4520  int result = 0;
4521 
4523  if (de_ctx == NULL)
4524  goto end;
4525 
4526  Signature *s = NULL;
4527 
4528  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
4529  if (s == NULL) {
4530  printf("sig 1 invalidated: failure");
4531  goto end;
4532  }
4533 
4534  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4535  printf("sig doesn't have stream flag set\n");
4536  goto end;
4537  }
4538 
4539  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
4540  printf("sig has packet flag set\n");
4541  goto end;
4542  }
4543 
4544  result = 1;
4545 
4546 end:
4547  if (de_ctx != NULL)
4549  return result;
4550 }
4551 
4552 /**
4553  * \test packet/stream sig
4554  */
4555 static int SigParseTest14(void)
4556 {
4557  int result = 0;
4558 
4560  if (de_ctx == NULL)
4561  goto end;
4562 
4563  Signature *s = NULL;
4564 
4565  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4566  if (s == NULL) {
4567  printf("sig 1 invalidated: failure");
4568  goto end;
4569  }
4570 
4571  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4572  printf("sig doesn't have packet flag set\n");
4573  goto end;
4574  }
4575 
4576  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4577  printf("sig has stream flag set\n");
4578  goto end;
4579  }
4580 
4581  result = 1;
4582 
4583 end:
4584  if (de_ctx != NULL)
4586  return result;
4587 }
4588 
4589 /**
4590  * \test packet/stream sig
4591  */
4592 static int SigParseTest15(void)
4593 {
4594  int result = 0;
4595 
4597  if (de_ctx == NULL)
4598  goto end;
4599 
4600  Signature *s = NULL;
4601 
4602  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4603  if (s == NULL) {
4604  printf("sig 1 invalidated: failure");
4605  goto end;
4606  }
4607 
4608  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4609  printf("sig doesn't have packet flag set\n");
4610  goto end;
4611  }
4612 
4613  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4614  printf("sig doesn't have stream flag set\n");
4615  goto end;
4616  }
4617 
4618  result = 1;
4619 
4620 end:
4621  if (de_ctx != NULL)
4623  return result;
4624 }
4625 
4626 /**
4627  * \test packet/stream sig
4628  */
4629 static int SigParseTest16(void)
4630 {
4631  int result = 0;
4632 
4634  if (de_ctx == NULL)
4635  goto end;
4636 
4637  Signature *s = NULL;
4638 
4639  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4640  if (s == NULL) {
4641  printf("sig 1 invalidated: failure");
4642  goto end;
4643  }
4644 
4645  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4646  printf("sig doesn't have packet flag set\n");
4647  goto end;
4648  }
4649 
4650  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4651  printf("sig doesn't have stream flag set\n");
4652  goto end;
4653  }
4654 
4655  result = 1;
4656 
4657 end:
4658  if (de_ctx != NULL)
4660  return result;
4661 }
4662 
4663 /**
4664  * \test packet/stream sig
4665  */
4666 static int SigParseTest17(void)
4667 {
4668  int result = 0;
4669 
4671  if (de_ctx == NULL)
4672  goto end;
4673 
4674  Signature *s = NULL;
4675 
4676  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4677  if (s == NULL) {
4678  printf("sig 1 invalidated: failure");
4679  goto end;
4680  }
4681 
4682  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4683  printf("sig doesn't have packet flag set\n");
4684  goto end;
4685  }
4686 
4687  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4688  printf("sig doesn't have stream flag set\n");
4689  goto end;
4690  }
4691 
4692  result = 1;
4693 
4694 end:
4695  if (de_ctx != NULL)
4697  return result;
4698 }
4699 
4700 /** \test sid value too large. Bug #779 */
4701 static int SigParseTest18 (void)
4702 {
4703  int result = 0;
4704 
4706  if (de_ctx == NULL)
4707  goto end;
4708 
4709  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4710  goto end;
4711 
4712  result = 1;
4713 end:
4714  if (de_ctx != NULL)
4716  return result;
4717 }
4718 
4719 /** \test gid value too large. Related to bug #779 */
4720 static int SigParseTest19 (void)
4721 {
4722  int result = 0;
4723 
4725  if (de_ctx == NULL)
4726  goto end;
4727 
4728  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4729  goto end;
4730 
4731  result = 1;
4732 end:
4733  if (de_ctx != NULL)
4735  return result;
4736 }
4737 
4738 /** \test rev value too large. Related to bug #779 */
4739 static int SigParseTest20 (void)
4740 {
4741  int result = 0;
4742 
4744  if (de_ctx == NULL)
4745  goto end;
4746 
4747  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4748  goto end;
4749 
4750  result = 1;
4751 end:
4752  if (de_ctx != NULL)
4754  return result;
4755 }
4756 
4757 /** \test address parsing */
4758 static int SigParseTest21 (void)
4759 {
4760  int result = 0;
4761 
4763  if (de_ctx == NULL)
4764  goto end;
4765 
4766  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4767  goto end;
4768 
4769  result = 1;
4770 end:
4771  if (de_ctx != NULL)
4773  return result;
4774 }
4775 
4776 /** \test address parsing */
4777 static int SigParseTest22 (void)
4778 {
4779  int result = 0;
4780 
4782  if (de_ctx == NULL)
4783  goto end;
4784 
4785  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)
4786  goto end;
4787 
4788  result = 1;
4789 end:
4790  if (de_ctx != NULL)
4792  return result;
4793 }
4794 
4795 /**
4796  * \test rule ending in carriage return
4797  */
4798 static int SigParseTest23(void)
4799 {
4802 
4803  Signature *s = NULL;
4804 
4805  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4806  FAIL_IF_NULL(s);
4807 
4809  PASS;
4810 }
4811 
4812 /** \test Direction operator validation (invalid) */
4813 static int SigParseBidirecTest06 (void)
4814 {
4815  int result = 1;
4816  Signature *sig = NULL;
4817 
4819  if (de_ctx == NULL)
4820  goto end;
4821 
4822  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4823  if (sig == NULL)
4824  result = 1;
4825 
4826 end:
4827  if (sig != NULL) SigFree(de_ctx, sig);
4828  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4829  return result;
4830 }
4831 
4832 /** \test Direction operator validation (invalid) */
4833 static int SigParseBidirecTest07 (void)
4834 {
4835  int result = 1;
4836  Signature *sig = NULL;
4837 
4839  if (de_ctx == NULL)
4840  goto end;
4841 
4842  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4843  if (sig == NULL)
4844  result = 1;
4845 
4846 end:
4847  if (sig != NULL) SigFree(de_ctx, sig);
4848  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4849  return result;
4850 }
4851 
4852 /** \test Direction operator validation (invalid) */
4853 static int SigParseBidirecTest08 (void)
4854 {
4855  int result = 1;
4856  Signature *sig = NULL;
4857 
4859  if (de_ctx == NULL)
4860  goto end;
4861 
4862  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4863  if (sig == NULL)
4864  result = 1;
4865 
4866 end:
4867  if (sig != NULL) SigFree(de_ctx, sig);
4868  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4869  return result;
4870 }
4871 
4872 /** \test Direction operator validation (invalid) */
4873 static int SigParseBidirecTest09 (void)
4874 {
4875  int result = 1;
4876  Signature *sig = NULL;
4877 
4879  if (de_ctx == NULL)
4880  goto end;
4881 
4882  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4883  if (sig == NULL)
4884  result = 1;
4885 
4886 end:
4887  if (sig != NULL) SigFree(de_ctx, sig);
4888  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4889  return result;
4890 }
4891 
4892 /** \test Direction operator validation (invalid) */
4893 static int SigParseBidirecTest10 (void)
4894 {
4895  int result = 1;
4896  Signature *sig = NULL;
4897 
4899  if (de_ctx == NULL)
4900  goto end;
4901 
4902  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4903  if (sig == NULL)
4904  result = 1;
4905 
4906 end:
4907  if (sig != NULL) SigFree(de_ctx, sig);
4908  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4909  return result;
4910 }
4911 
4912 /** \test Direction operator validation (invalid) */
4913 static int SigParseBidirecTest11 (void)
4914 {
4915  int result = 1;
4916  Signature *sig = NULL;
4917 
4919  if (de_ctx == NULL)
4920  goto end;
4921 
4922  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4923  if (sig == NULL)
4924  result = 1;
4925 
4926 end:
4927  if (sig != NULL) SigFree(de_ctx, sig);
4928  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4929  return result;
4930 }
4931 
4932 /** \test Direction operator validation (invalid) */
4933 static int SigParseBidirecTest12 (void)
4934 {
4935  int result = 1;
4936  Signature *sig = NULL;
4937 
4939  if (de_ctx == NULL)
4940  goto end;
4941 
4942  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4943  if (sig == NULL)
4944  result = 1;
4945 
4946 end:
4947  if (sig != NULL) SigFree(de_ctx, sig);
4948  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4949  return result;
4950 }
4951 
4952 /** \test Direction operator validation (valid) */
4953 static int SigParseBidirecTest13 (void)
4954 {
4955  int result = 1;
4956  Signature *sig = NULL;
4957 
4959  if (de_ctx == NULL)
4960  goto end;
4961 
4962  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4963  if (sig != NULL)
4964  result = 1;
4965 
4966 end:
4967  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4968  return result;
4969 }
4970 
4971 /** \test Direction operator validation (valid) */
4972 static int SigParseBidirecTest14 (void)
4973 {
4974  int result = 1;
4975  Signature *sig = NULL;
4976 
4978  if (de_ctx == NULL)
4979  goto end;
4980 
4981  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4982  if (sig != NULL)
4983  result = 1;
4984 
4985 end:
4986  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4987  return result;
4988 }
4989 
4990 /** \test Ensure that we don't set bidirectional in a
4991  * normal (one direction) Signature
4992  */
4993 static int SigTestBidirec01 (void)
4994 {
4995  Signature *sig = NULL;
4996  int result = 0;
4997 
4999  if (de_ctx == NULL)
5000  goto end;
5001 
5002  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
5003  if (sig == NULL)
5004  goto end;
5005  if (sig->next != NULL)
5006  goto end;
5008  goto end;
5009  if (de_ctx->signum != 1)
5010  goto end;
5011 
5012  result = 1;
5013 
5014 end:
5015  if (de_ctx != NULL) {
5019  }
5020  return result;
5021 }
5022 
5023 /** \test Ensure that we set a bidirectional Signature correctly */
5024 static int SigTestBidirec02 (void)
5025 {
5026  int result = 0;
5027  Signature *sig = NULL;
5028  Signature *copy = NULL;
5029 
5031  if (de_ctx == NULL)
5032  goto end;
5033 
5034  de_ctx->flags |= DE_QUIET;
5035 
5036  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
5037  if (sig == NULL)
5038  goto end;
5039  if (de_ctx->sig_list != sig)
5040  goto end;
5042  goto end;
5043  if (sig->next == NULL)
5044  goto end;
5045  if (de_ctx->signum != 2)
5046  goto end;
5047  copy = sig->next;
5048  if (copy->next != NULL)
5049  goto end;
5050  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
5051  goto end;
5052 
5053  result = 1;
5054 
5055 end:
5056  if (de_ctx != NULL) {
5060  }
5061 
5062  return result;
5063 }
5064 
5065 /** \test Ensure that we set a bidirectional Signature correctly
5066 * and we install it with the rest of the signatures, checking
5067 * also that it match with the correct addr directions
5068 */
5069 static int SigTestBidirec03 (void)
5070 {
5071  int result = 0;
5072  Signature *sig = NULL;
5073  Packet *p = NULL;
5074 
5076  if (de_ctx == NULL)
5077  goto end;
5078 
5079  de_ctx->flags |= DE_QUIET;
5080 
5081  const char *sigs[3];
5082  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
5083  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
5084  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
5085  UTHAppendSigs(de_ctx, sigs, 3);
5086 
5087  /* Checking that bidirectional rules are set correctly */
5088  sig = de_ctx->sig_list;
5089  if (sig == NULL)
5090  goto end;
5091  if (sig->next == NULL)
5092  goto end;
5093  if (sig->next->next == NULL)
5094  goto end;
5095  if (sig->next->next->next == NULL)
5096  goto end;
5097  if (sig->next->next->next->next != NULL)
5098  goto end;
5099  if (de_ctx->signum != 4)
5100  goto end;
5101 
5102  uint8_t rawpkt1_ether[] = {
5103  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
5104  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
5105  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
5106  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
5107  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
5108  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
5109  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
5110  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
5111  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
5112  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
5113  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
5114  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
5115  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
5116  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
5117  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
5118  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
5119  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
5120  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
5121  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
5122  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
5123  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
5124  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
5125  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
5126  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
5127  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
5128  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
5129  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
5130  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
5131  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
5132  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
5133  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
5134  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
5135  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
5136  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
5137  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5138  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5139  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
5140  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
5141  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
5142  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
5143  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
5144  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
5145  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
5146  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5147  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
5148  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
5149  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
5150  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
5151  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5152  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
5153  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
5154  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
5155  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
5156  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
5157  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
5158 
5160  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
5161  if (p == NULL) {
5162  SCLogDebug("Error building packet");
5163  goto end;
5164  }
5165  UTHMatchPackets(de_ctx, &p, 1);
5166 
5167  uint32_t sids[3] = {1, 2, 3};
5168  uint32_t results[3] = {1, 1, 1};
5169  result = UTHCheckPacketMatchResults(p, sids, results, 1);
5170 
5171 end:
5172  if (p != NULL) {
5173  PacketFree(p);
5174  }
5176  FlowShutdown();
5177  return result;
5178 }
5179 
5180 /** \test Ensure that we set a bidirectional Signature correctly
5181 * and we install it with the rest of the signatures, checking
5182 * also that it match with the correct addr directions
5183 */
5184 static int SigTestBidirec04 (void)
5185 {
5186  int result = 0;
5187  Signature *sig = NULL;
5188  Packet *p = NULL;
5189 
5191  if (de_ctx == NULL)
5192  goto end;
5193 
5194  de_ctx->flags |= DE_QUIET;
5195 
5196  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
5197  if (sig == NULL)
5198  goto end;
5199  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
5200  if (sig == NULL)
5201  goto end;
5202  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
5203  goto end;
5204  if (sig->next == NULL)
5205  goto end;
5206  if (sig->next->next == NULL)
5207  goto end;
5208  if (sig->next->next->next != NULL)
5209  goto end;
5210  if (de_ctx->signum != 3)
5211  goto end;
5212 
5213  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
5214  if (sig == NULL)
5215  goto end;
5216  if (sig->next == NULL)
5217  goto end;
5218  if (sig->next->next == NULL)
5219  goto end;
5220  if (sig->next->next->next == NULL)
5221  goto end;
5222  if (sig->next->next->next->next != NULL)
5223  goto end;
5224  if (de_ctx->signum != 4)
5225  goto end;
5226 
5227  uint8_t rawpkt1_ether[] = {
5228  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
5229  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
5230  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
5231  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
5232  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
5233  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
5234  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
5235  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
5236  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
5237  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
5238  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
5239  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
5240  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
5241  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
5242  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
5243  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
5244  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
5245  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
5246  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
5247  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
5248  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
5249  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
5250  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
5251  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
5252  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
5253  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
5254  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
5255  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
5256  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
5257  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
5258  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
5259  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
5260  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
5261  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
5262  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5263  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5264  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
5265  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
5266  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
5267  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
5268  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
5269  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
5270  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
5271  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5272  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
5273  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
5274  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
5275  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
5276  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5277  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
5278  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
5279  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
5280  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
5281  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
5282  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
5283 
5284  p = PacketGetFromAlloc();
5285  if (unlikely(p == NULL))
5286  return 0;
5288  ThreadVars th_v;
5289  DetectEngineThreadCtx *det_ctx;
5290 
5291  memset(&th_v, 0, sizeof(th_v));
5293 
5295  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
5296  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
5297 
5298  /* At this point we have a list of 4 signatures. The last one
5299  is a copy of the second one. If we receive a packet
5300  with source 192.168.1.1 80, all the sids should match */
5301 
5303  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
5304 
5305  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
5306  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
5307  PacketAlertCheck(p, 2) == 1) {
5308  result = 1;
5309  }
5310 
5311  if (p != NULL) {
5312  PacketRecycle(p);
5313  }
5314  FlowShutdown();
5315  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
5316 
5317 end:
5318  if (de_ctx != NULL) {
5320  }
5321 
5322  if (p != NULL)
5323  PacketFree(p);
5325  return result;
5326 }
5327 
5328 /**
5329  * \test check that we don't allow invalid negation options
5330  */
5331 static int SigParseTestNegation01 (void)
5332 {
5335  de_ctx->flags |= DE_QUIET;
5336  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
5337  FAIL_IF_NOT_NULL(s);
5339  PASS;
5340 }
5341 
5342 /**
5343  * \test check that we don't allow invalid negation options
5344  */
5345 static int SigParseTestNegation02 (void)
5346 {
5349  de_ctx->flags |= DE_QUIET;
5351  "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
5352  "classtype:misc-activity; sid:410002; rev:1;)");
5353  FAIL_IF_NOT_NULL(s);
5355  PASS;
5356 }
5357 /**
5358  * \test check that we don't allow invalid negation options
5359  */
5360 static int SigParseTestNegation03 (void)
5361 {
5364  de_ctx->flags |= DE_QUIET;
5366  "alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; "
5367  "classtype:misc-activity; sid:410003; rev:1;)");
5368  FAIL_IF_NOT_NULL(s);
5370  PASS;
5371 }
5372 /**
5373  * \test check that we don't allow invalid negation options
5374  */
5375 static int SigParseTestNegation04 (void)
5376 {
5377  int result = 0;
5379  Signature *s=NULL;
5380 
5382  if (de_ctx == NULL)
5383  goto end;
5384  de_ctx->flags |= DE_QUIET;
5385 
5386  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;)");
5387  if (s != NULL) {
5388  SigFree(de_ctx, s);
5389  goto end;
5390  }
5391 
5392  result = 1;
5393 end:
5394  if (de_ctx != NULL)
5396  return result;
5397 }
5398 /**
5399  * \test check that we don't allow invalid negation options
5400  */
5401 static int SigParseTestNegation05 (void)
5402 {
5403  int result = 0;
5405  Signature *s=NULL;
5406 
5408  if (de_ctx == NULL)
5409  goto end;
5410  de_ctx->flags |= DE_QUIET;
5411 
5412  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;)");
5413  if (s != NULL) {
5414  SigFree(de_ctx, s);
5415  goto end;
5416  }
5417 
5418  result = 1;
5419 end:
5420  if (de_ctx != NULL)
5422  return result;
5423 }
5424 /**
5425  * \test check that we don't allow invalid negation options
5426  */
5427 static int SigParseTestNegation06 (void)
5428 {
5429  int result = 0;
5431  Signature *s=NULL;
5432 
5434  if (de_ctx == NULL)
5435  goto end;
5436  de_ctx->flags |= DE_QUIET;
5437 
5438  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;)");
5439  if (s != NULL) {
5440  SigFree(de_ctx, s);
5441  goto end;
5442  }
5443 
5444  result = 1;
5445 end:
5446  if (de_ctx != NULL)
5448  return result;
5449 }
5450 
5451 /**
5452  * \test check that we don't allow invalid negation options
5453  */
5454 static int SigParseTestNegation07 (void)
5455 {
5458  de_ctx->flags |= DE_QUIET;
5460  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
5461  FAIL_IF_NOT_NULL(s);
5463  PASS;
5464 }
5465 
5466 /**
5467  * \test check valid negation bug 1079
5468  */
5469 static int SigParseTestNegation08 (void)
5470 {
5471  int result = 0;
5473  Signature *s=NULL;
5474 
5476  if (de_ctx == NULL)
5477  goto end;
5478  de_ctx->flags |= DE_QUIET;
5479 
5481  "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
5482  if (s == NULL) {
5483  goto end;
5484  }
5485 
5486  result = 1;
5487 end:
5488  if (de_ctx != NULL)
5490  return result;
5491 }
5492 
5493 /**
5494  * \test mpm
5495  */
5496 static int SigParseTestMpm01 (void)
5497 {
5498  int result = 0;
5499  Signature *sig = NULL;
5500 
5502  if (de_ctx == NULL)
5503  goto end;
5504 
5505  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
5506  if (sig == NULL) {
5507  printf("sig failed to init: ");
5508  goto end;
5509  }
5510 
5511  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5512  printf("sig doesn't have content list: ");
5513  goto end;
5514  }
5515 
5516  result = 1;
5517 end:
5518  if (sig != NULL)
5519  SigFree(de_ctx, sig);
5521  return result;
5522 }
5523 
5524 /**
5525  * \test mpm
5526  */
5527 static int SigParseTestMpm02 (void)
5528 {
5529  int result = 0;
5530  Signature *sig = NULL;
5531 
5533  if (de_ctx == NULL)
5534  goto end;
5535 
5536  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5537  if (sig == NULL) {
5538  printf("sig failed to init: ");
5539  goto end;
5540  }
5541 
5542  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5543  printf("sig doesn't have content list: ");
5544  goto end;
5545  }
5546 
5547  result = 1;
5548 end:
5549  if (sig != NULL)
5550  SigFree(de_ctx, sig);
5552  return result;
5553 }
5554 
5555 /**
5556  * \test test tls (app layer) rule
5557  */
5558 static int SigParseTestAppLayerTLS01(void)
5559 {
5560  int result = 0;
5562  Signature *s=NULL;
5563 
5565  if (de_ctx == NULL)
5566  goto end;
5567  de_ctx->flags |= DE_QUIET;
5568 
5569  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5570  if (s == NULL) {
5571  printf("parsing sig failed: ");
5572  goto end;
5573  }
5574 
5575  if (s->alproto == 0) {
5576  printf("alproto not set: ");
5577  goto end;
5578  }
5579 
5580  result = 1;
5581 end:
5582  if (s != NULL)
5583  SigFree(de_ctx, s);
5584  if (de_ctx != NULL)
5586 
5587  return result;
5588 }
5589 
5590 /**
5591  * \test test tls (app layer) rule
5592  */
5593 static int SigParseTestAppLayerTLS02(void)
5594 {
5595  int result = 0;
5597  Signature *s=NULL;
5598 
5600  if (de_ctx == NULL)
5601  goto end;
5602  de_ctx->flags |= DE_QUIET;
5603 
5604  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5605  if (s == NULL) {
5606  printf("parsing sig failed: ");
5607  goto end;
5608  }
5609 
5610  if (s->alproto == 0) {
5611  printf("alproto not set: ");
5612  goto end;
5613  }
5614 
5615  result = 1;
5616 end:
5617  if (s != NULL)
5618  SigFree(de_ctx, s);
5619  if (de_ctx != NULL)
5621  return result;
5622 }
5623 
5624 /**
5625  * \test test tls (app layer) rule
5626  */
5627 static int SigParseTestAppLayerTLS03(void)
5628 {
5631  de_ctx->flags |= DE_QUIET;
5632 
5634  "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
5635  "tls.version:2.5; sid:410006; rev:1;)");
5636  FAIL_IF_NOT_NULL(s);
5638  PASS;
5639 }
5640 
5641 static int SigParseTestUnbalancedQuotes01(void)
5642 {
5645  de_ctx->flags |= DE_QUIET;
5647  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5648  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5649  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5650  FAIL_IF_NOT_NULL(s);
5652  PASS;
5653 }
5654 
5655 static int SigParseTestContentGtDsize01(void)
5656 {
5659  de_ctx->flags |= DE_QUIET;
5660  Signature *s =
5661  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5662  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5663  "sid:1; rev:1;)");
5664  FAIL_IF_NOT_NULL(s);
5666  PASS;
5667 }
5668 
5669 static int SigParseTestContentGtDsize02(void)
5670 {
5673  de_ctx->flags |= DE_QUIET;
5674  Signature *s =
5675  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5676  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5677  "sid:1; rev:1;)");
5678  FAIL_IF_NOT_NULL(s);
5680  PASS;
5681 }
5682 
5683 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5684 {
5685  int cnt = 0;
5686  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5687  if (sid == s->id)
5688  cnt++;
5689  }
5690  return cnt;
5691 }
5692 
5693 static int SigParseBidirWithSameSrcAndDest01(void)
5694 {
5697  de_ctx->flags |= DE_QUIET;
5698 
5699  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5700  FAIL_IF_NULL(s);
5701  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5703 
5704  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5705  FAIL_IF_NULL(s);
5706  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5708 
5710  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5711  FAIL_IF_NULL(s);
5712  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5714 
5716  PASS;
5717 }
5718 
5719 static int SigParseBidirWithSameSrcAndDest02(void)
5720 {
5723  de_ctx->flags |= DE_QUIET;
5724 
5725  // Source is a subset of destination
5727  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5728  FAIL_IF_NULL(s);
5729  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5731 
5732  // Source is a subset of destination
5734  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5735  FAIL_IF_NULL(s);
5736  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5738 
5739  // Source intersects with destination
5741  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5742  FAIL_IF_NULL(s);
5743  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5745 
5746  // mix in negation, these are the same
5748  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;)");
5749  FAIL_IF_NULL(s);
5750  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5752 
5753  // mix in negation, these are not the same
5755  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;)");
5756  FAIL_IF_NULL(s);
5757  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5759 
5761  PASS;
5762 }
5763 
5764 static int SigParseTestActionReject(void)
5765 {
5768 
5770  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5771 #ifdef HAVE_LIBNET11
5772  FAIL_IF_NULL(sig);
5774 #else
5775  FAIL_IF_NOT_NULL(sig);
5776 #endif
5777 
5779  PASS;
5780 }
5781 
5782 static int SigParseTestActionDrop(void)
5783 {
5786 
5788  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5789  FAIL_IF_NULL(sig);
5790  FAIL_IF_NOT(sig->action & ACTION_DROP);
5791 
5793  PASS;
5794 }
5795 
5796 static int SigSetMultiAppProto(void)
5797 {
5798  Signature *s = SigAlloc();
5799  FAIL_IF_NULL(s);
5800 
5801  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5802  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5803 
5804  // check intersection gives multiple entries
5805  alprotos[0] = 3;
5806  alprotos[1] = 2;
5807  alprotos[2] = ALPROTO_UNKNOWN;
5808  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5809  FAIL_IF(s->init_data->alprotos[0] != 3);
5810  FAIL_IF(s->init_data->alprotos[1] != 2);
5812 
5813  // check single after multiple
5816  FAIL_IF(s->alproto != 3);
5817  alprotos[0] = 4;
5818  alprotos[1] = 3;
5819  alprotos[2] = ALPROTO_UNKNOWN;
5820  // check multiple containing singleton
5821  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5822  FAIL_IF(s->alproto != 3);
5823 
5824  // reset
5825  s->alproto = ALPROTO_UNKNOWN;
5826  alprotos[0] = 1;
5827  alprotos[1] = 2;
5828  alprotos[2] = 3;
5829  alprotos[3] = ALPROTO_UNKNOWN;
5830  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5831  // fail if set single not in multiple
5833 
5835  s->alproto = ALPROTO_UNKNOWN;
5836  alprotos[0] = 1;
5837  alprotos[1] = 2;
5838  alprotos[2] = 3;
5839  alprotos[3] = ALPROTO_UNKNOWN;
5840  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5841  alprotos[0] = 4;
5842  alprotos[1] = 5;
5843  alprotos[2] = ALPROTO_UNKNOWN;
5844  // fail if multiple do not have intersection
5845  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5846 
5848  s->alproto = ALPROTO_UNKNOWN;
5849  alprotos[0] = 1;
5850  alprotos[1] = 2;
5851  alprotos[2] = 3;
5852  alprotos[3] = ALPROTO_UNKNOWN;
5853  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5854  alprotos[0] = 3;
5855  alprotos[1] = 4;
5856  alprotos[2] = 5;
5857  alprotos[3] = ALPROTO_UNKNOWN;
5858  // check multiple intersect to singleton
5859  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5860  FAIL_IF(s->alproto != 3);
5861  alprotos[0] = 5;
5862  alprotos[1] = 4;
5863  alprotos[2] = ALPROTO_UNKNOWN;
5864  // fail if multiple do not belong to singleton
5865  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5866 
5867  SigFree(NULL, s);
5868  PASS;
5869 }
5870 
5871 static int DetectSetupDirection01(void)
5872 {
5873  Signature *s = SigAlloc();
5874  FAIL_IF_NULL(s);
5875  // Basic case : ok
5876  char *str = (char *)"to_client";
5877  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5878  SigFree(NULL, s);
5879  PASS;
5880 }
5881 
5882 static int DetectSetupDirection02(void)
5883 {
5884  Signature *s = SigAlloc();
5885  FAIL_IF_NULL(s);
5886  char *str = (char *)"to_server";
5887  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5888  // ok so far
5889  str = (char *)"to_client";
5890  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5891  // fails because we cannot have both to_client and to_server for same signature
5892  SigFree(NULL, s);
5893  PASS;
5894 }
5895 
5896 static int DetectSetupDirection03(void)
5897 {
5898  Signature *s = SigAlloc();
5899  FAIL_IF_NULL(s);
5900  char *str = (char *)"to_client , something";
5901  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5902  FAIL_IF(strcmp(str, "something") != 0);
5903  str = (char *)"to_client,something";
5904  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5905  FAIL_IF(strcmp(str, "something") != 0);
5906  SigFree(NULL, s);
5907  PASS;
5908 }
5909 
5910 static int DetectSetupDirection04(void)
5911 {
5912  Signature *s = SigAlloc();
5913  FAIL_IF_NULL(s);
5914  // invalid case
5915  char *str = (char *)"to_client_toto";
5916  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5917  // test we do not change the string pointer if only_dir is false
5918  str = (char *)"to_client_toto";
5919  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5920  FAIL_IF(strcmp(str, "to_client_toto") != 0);
5921  str = (char *)"to_client,something";
5922  // fails because we call with only_dir=true
5923  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5924  SigFree(NULL, s);
5925  PASS;
5926 }
5927 
5928 #endif /* UNITTESTS */
5929 
5930 #ifdef UNITTESTS
5931 void DetectParseRegisterTests (void);
5932 #include "tests/detect-parse.c"
5933 #endif
5934 
5936 {
5937 #ifdef UNITTESTS
5939 
5940  UtRegisterTest("SigParseTest01", SigParseTest01);
5941  UtRegisterTest("SigParseTest02", SigParseTest02);
5942  UtRegisterTest("SigParseTest03", SigParseTest03);
5943  UtRegisterTest("SigParseTest04", SigParseTest04);
5944  UtRegisterTest("SigParseTest05", SigParseTest05);
5945  UtRegisterTest("SigParseTest06", SigParseTest06);
5946  UtRegisterTest("SigParseTest07", SigParseTest07);
5947  UtRegisterTest("SigParseTest08", SigParseTest08);
5948  UtRegisterTest("SigParseTest09", SigParseTest09);
5949  UtRegisterTest("SigParseTest10", SigParseTest10);
5950  UtRegisterTest("SigParseTest11", SigParseTest11);
5951  UtRegisterTest("SigParseTest12", SigParseTest12);
5952  UtRegisterTest("SigParseTest13", SigParseTest13);
5953  UtRegisterTest("SigParseTest14", SigParseTest14);
5954  UtRegisterTest("SigParseTest15", SigParseTest15);
5955  UtRegisterTest("SigParseTest16", SigParseTest16);
5956  UtRegisterTest("SigParseTest17", SigParseTest17);
5957  UtRegisterTest("SigParseTest18", SigParseTest18);
5958  UtRegisterTest("SigParseTest19", SigParseTest19);
5959  UtRegisterTest("SigParseTest20", SigParseTest20);
5960  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5961  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5962  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5963 
5964  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5965  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5966  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5967  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5968  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5969  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5970  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5971  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5972  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5973  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5974  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5975  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5976  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5977  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5978  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5979  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5980  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5981  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5982  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5983  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5984  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5985  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5986  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5987  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5988  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5989  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5990  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5991 
5992  UtRegisterTest("SigParseTestContentGtDsize01",
5993  SigParseTestContentGtDsize01);
5994  UtRegisterTest("SigParseTestContentGtDsize02",
5995  SigParseTestContentGtDsize02);
5996 
5997  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5998  SigParseBidirWithSameSrcAndDest01);
5999  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
6000  SigParseBidirWithSameSrcAndDest02);
6001  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
6002  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
6003 
6004  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
6005 
6006  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
6007  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
6008  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
6009  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
6010 
6011 #endif /* UNITTESTS */
6012 }
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:432
DETECT_TABLE_APP_TD
@ DETECT_TABLE_APP_TD
Definition: detect.h:563
SignatureParser_
Definition: detect-parse.c:101
SignatureInitData_::max_content_list_id
uint32_t max_content_list_id
Definition: detect.h:660
host.h
DetectFirewallPolicies
Definition: detect.h:937
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:666
DetectPortCmp
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
Definition: detect-engine-port.c:483
DetectEngineAppInspectionEngine_
Definition: detect.h:416
SC_MATCH_LIMIT_DEFAULT
#define SC_MATCH_LIMIT_DEFAULT
Definition: detect-pcre.h:43
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
SignatureInitDataBuffer_::head
SigMatch * head
Definition: detect.h:535
SigMatch_::prev
struct SigMatch_ * prev
Definition: detect.h:361
detect-content.h
SignatureInitDataBuffer_::sm_init
bool sm_init
Definition: detect.h:527
len
uint8_t len
Definition: app-layer-dnp3.h:2
ts
uint64_t ts
Definition: source-erf-file.c:55
DetectMetadataHead::json_str
char * json_str
Definition: detect-metadata.h:40
DetectMetadataFree
void DetectMetadataFree(DetectMetadata *mdata)
Free a Metadata object.
Definition: detect-metadata.c:60
AppLayerHtpNeedFileInspection
void AppLayerHtpNeedFileInspection(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request file...
Definition: app-layer-htp.c: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
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect-engine-register.h:311
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:649
DetectEngineProtoList
void DetectEngineProtoList(void)
Definition: detect-engine-proto.c:74
SignatureHook_
Definition: detect.h:575
DetectParseDupSigHashInit
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3323
SignatureInitData_::list_set
bool list_set
Definition: detect.h:633
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:718
SIG_FLAG_FW_HOOK_LTE
#define SIG_FLAG_FW_HOOK_LTE
Definition: detect.h:251
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:752
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
DetectFirewallAppPolicy::tc
struct DetectFirewallPolicy tc[48]
Definition: detect.h:934
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1496
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:1642
SignatureHook_::sm_list
int sm_list
Definition: detect.h:577
DETECT_TABLE_APP_FILTER
@ DETECT_TABLE_APP_FILTER
Definition: detect.h:562
DetectFirewallAppPolicy
Definition: detect.h:930
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:441
SignatureParser_::sp
char sp[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:107
DetectPortListsAreEqual
bool DetectPortListsAreEqual(DetectPort *list1, DetectPort *list2)
Checks if two port group lists are equal.
Definition: detect-engine-port.c:610
DetectParseRegex
Definition: detect-parse.h:94
SignatureParser_::action
char action[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:102
SigTableElmt_::name
const char * name
Definition: detect.h:1509
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:651
DetectEngineBufferRunSetupCallback
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
Definition: detect-engine.c:1579
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:112
SIG_FLAG_INIT_FLOW
#define SIG_FLAG_INIT_FLOW
Definition: detect.h:291
SIGMATCH_BAN_FIREWALL_RULE
#define SIGMATCH_BAN_FIREWALL_RULE
Definition: detect-engine-register.h:359
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:712
DetectFirewallPolicies::policy_signatures
HashTable * policy_signatures
Definition: detect.h:943
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:2223
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:76
DetectAddress_
address structure for use in the detection engine.
Definition: detect.h:168
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1500
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:629
SignatureInitData_::src_contains_negation
bool src_contains_negation
Definition: detect.h:605
DetectEngineCtx_::sigerror_silent
bool sigerror_silent
Definition: detect.h:1073
DetectParseRegex::context
pcre2_match_context * context
Definition: detect-parse.h:96
Signature_::alproto
AppProto alproto
Definition: detect.h:680
DETECT_TABLE_PACKET_PRE_STREAM
@ DETECT_TABLE_PACKET_PRE_STREAM
Definition: detect.h:559
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:663
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
SIG_FLAG_INIT_FILEDATA
#define SIG_FLAG_INIT_FILEDATA
Definition: detect.h:300
detect-isdataat.h
IPOnlySigParseAddress
int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag)
Parses an address group sent as a character string and updates the IPOnlyCIDRItem lists src and dst o...
Definition: detect-engine-iponly.c:869
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:367
ActionScopeToString
const char * ActionScopeToString(enum ActionScope s)
Definition: detect-parse.c:3811
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:87
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:144
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:368
detect-bsize.h
URL
#define URL
action-globals.h
SignatureHook_::t
union SignatureHook_::@87 t
type
uint8_t type
Definition: decode-sctp.h:0
PacketRecycle
void PacketRecycle(Packet *p)
Definition: packet.c:166
DetectReferenceFree
void DetectReferenceFree(DetectReference *ref)
Free a Reference object.
Definition: detect-reference.c:76
Packet_::action
uint8_t action
Definition: decode.h:623
SIGMATCH_QUOTES_OPTIONAL
#define SIGMATCH_QUOTES_OPTIONAL
Definition: detect-engine-register.h:321
DetectTable
DetectTable
Definition: detect.h:556
SCDetectGetLastSMFromLists
SigMatch * SCDetectGetLastSMFromLists(const Signature *s,...)
Returns the sm with the largest index (added latest) from the lists passed to us.
Definition: detect-parse.c:563
DetectSetupPCRE2
DetectParseRegex * DetectSetupPCRE2(const char *parse_str, int opts)
Definition: detect-parse.c:3725
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
DetectFirewallPacketPolicies
DetectFirewallPacketPolicies
Definition: detect.h:916
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:1198
SIGMATCH_INFO_DEPRECATED
#define SIGMATCH_INFO_DEPRECATED
Definition: detect-engine-register.h:335
SigDuplWrapper_::s_prev
Signature * s_prev
Definition: detect-parse.c:97
th_v
ThreadVars * th_v
Definition: fuzz_iprep.c:20
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:973
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:1141
DETECT_PROTO_ETHERNET
#define DETECT_PROTO_ETHERNET
Definition: detect-engine-proto.h:33
CASE_CODE_STRING
#define CASE_CODE_STRING(E, S)
TransformData_::options
void * options
Definition: detect.h:388
DETECT_STREAM_SIZE
@ DETECT_STREAM_SIZE
Definition: detect-engine-register.h:127
SIGNATURE_HOOK_PKT_NOT_SET
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition: detect.h:540
DetectFirewallPolicies::pkt_policy_signatures
Signature * pkt_policy_signatures[DETECT_FIREWALL_POLICY_SIZE]
Definition: detect.h:940
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
SIG_FLAG_INIT_FORCE_TOCLIENT
#define SIG_FLAG_INIT_FORCE_TOCLIENT
Definition: detect.h:301
AppLayerParserGetStateIdByName
int AppLayerParserGetStateIdByName(uint8_t ipproto, AppProto alproto, const char *name, const uint8_t direction)
Definition: app-layer-parser.c:1627
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2760
AppLayerProtoDetectSupportedIpprotos
void AppLayerProtoDetectSupportedIpprotos(AppProto alproto, uint8_t *ipprotos)
Definition: app-layer-detect-proto.c:2079
detect-lua.h
DetectEngineBufferTypeGetNameById
const char * DetectEngineBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1414
SIG_DIREC_SRC
@ SIG_DIREC_SRC
Definition: detect-parse.h:49
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:620
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
HashTable_
Definition: util-hash.h:35
SIG_FLAG_TXBOTHDIR
#define SIG_FLAG_TXBOTHDIR
Definition: detect.h:249
MIN
#define MIN(x, y)
Definition: suricata-common.h:416
DetectParseRegex::regex
pcre2_code * regex
Definition: detect-parse.h:95
ACTION_REJECT_ANY
#define ACTION_REJECT_ANY
Definition: action-globals.h:38
DetectKeywordId
DetectKeywordId
Definition: detect-engine-register.h:27
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
DetectGetLastSMByListPtr
SigMatch * DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list,...)
Returns the sm with the largest index (added last) from the list passed to us as a pointer.
Definition: detect-parse.c:625
DetectRegisterAppLayerHookLists
void DetectRegisterAppLayerHookLists(void)
register app hooks as generic lists
Definition: detect-parse.c:1156
DetectEngineCtx_::sigerror_requires
bool sigerror_requires
Definition: detect.h:1077
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2971
FILE_SIG_NEED_FILENAME
#define FILE_SIG_NEED_FILENAME
Definition: detect.h:321
SignatureInitDataBuffer_::multi_capable
bool multi_capable
Definition: detect.h:530
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:738
DetectFirewallInitDefaultPolicies
int DetectFirewallInitDefaultPolicies(DetectEngineCtx *de_ctx)
allocate and initialize to default values the policies table
Definition: detect-parse.c:4033
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:1111
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:612
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3340
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3649
DetectBufferType_
Definition: detect.h:449
proto
uint8_t proto
Definition: decode-template.h:0
DetectContentData_
Definition: detect-content.h:93
DetectFirewallPolicies::app
struct DetectFirewallAppPolicy app[]
Definition: detect.h:946
p
Packet * p
Definition: fuzz_iprep.c:21
DetectEngineCtx_::sigerror_ok
bool sigerror_ok
Definition: detect.h:1074
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:2301
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:245
EngineModeIsFirewall
bool EngineModeIsFirewall(void)
Definition: suricata.c:239
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:271
MAX
#define MAX(x, y)
Definition: suricata-common.h:420
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:240
SigTableElmt_
element in sigmatch type table.
Definition: detect.h:1469
SigMatchData_
Data needed for Match()
Definition: detect.h:365
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1491
DetectFlowSetupImplicit
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
Definition: detect-flow.c:341
detect-pcre.h
SigMatchData_::type
uint16_t type
Definition: detect.h:366
DetectMatchAddressIPv4_::ip
uint32_t ip
Definition: detect.h:190
DetectFirewallPolicy::action
uint8_t action
Definition: detect.h:925
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:3685
util-unittest.h
DetectParseRegex::next
struct DetectParseRegex * next
Definition: detect-parse.h:97
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
SIGMATCH_BAN_FIREWALL_MODE
#define SIGMATCH_BAN_FIREWALL_MODE
Definition: detect-engine-register.h:361
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:248
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1384
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
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
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:905
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:721
DetectMatchAddressIPv6_::ip2
uint32_t ip2[4]
Definition: detect.h:196
SIGNATURE_HOOK_TYPE_APP
@ SIGNATURE_HOOK_TYPE_APP
Definition: detect.h:550
Signature_::next
struct Signature_ * next
Definition: detect.h:757
ACTION_REJECT_DST
#define ACTION_REJECT_DST
Definition: action-globals.h:32
DetectParseFreeRegexes
void DetectParseFreeRegexes(void)
Definition: detect-parse.c:3669
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:424
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:577
UTHMatchPackets
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
Definition: util-unittest-helper.c:729
SIGMATCH_SUPPORT_DIR
#define SIGMATCH_SUPPORT_DIR
Definition: detect-engine-register.h:341
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:1135
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:715
SigParseRegisterTests
void SigParseRegisterTests(void)
Definition: detect-parse.c:5935
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
DetectEngineCtx_::fw_policies
struct DetectFirewallPolicies * fw_policies
Definition: detect.h:1003
DETECT_PROTO_ARP
#define DETECT_PROTO_ARP
Definition: detect-engine-proto.h:34
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:22
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:90
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:30
SignatureInitData_::buffers_size
uint32_t buffers_size
Definition: detect.h:656
SigFree
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-parse.c:2126
DetectEngineThreadCtx_
Definition: detect.h:1291
DetectGetLastSMFromMpmLists
SigMatch * DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
get the last SigMatch from lists that support MPM.
Definition: detect-parse.c:526
strlcat
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:66
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:627
g_skip_prefilter
int g_skip_prefilter
Definition: detect-engine-mpm.c:1134
SignatureInitData_::src
const DetectAddressHead * src
Definition: detect.h:646
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:625
AppProtoDetectListNames
void AppProtoDetectListNames(void)
Definition: app-layer-detect-proto.c:1724
BOOL2STR
#define BOOL2STR(b)
Definition: util-debug.h:542
SignatureInitData_::cidr_dst
IPOnlyCIDRItem * cidr_dst
Definition: detect.h:622
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3775
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
SignatureInitData_::list
int list
Definition: detect.h:632
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
detect-engine-mpm.h
HashTableLookup
void * HashTableLookup(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:194
Signature_::references
DetectReference * references
Definition: detect.h:748
SigTableElmt_::tables
uint8_t tables
Definition: detect.h:1504
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:1158
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:2437
SignatureHookPkt
SignatureHookPkt
Definition: detect.h:539
pkt-var.h
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3506
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
DetectFirewallPolicies::pkt
struct DetectFirewallPolicy pkt[DETECT_FIREWALL_POLICY_SIZE]
Definition: detect.h:939
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:222
DETECT_TABLE_PACKET_PRE_FLOW
@ DETECT_TABLE_PACKET_PRE_FLOW
Definition: detect.h:558
detect-engine-port.h
SignatureInitData_::proto
DetectProto proto
Definition: detect.h:638
SigDuplWrapper_::s
Signature * s
Definition: detect-parse.c:95
DETECT_TABLE_PACKET_FILTER
@ DETECT_TABLE_PACKET_FILTER
Definition: detect.h:560
DetectFirewallPolicyToString
void DetectFirewallPolicyToString(const struct DetectFirewallPolicy *p, char *out, size_t out_size)
Definition: detect-parse.c:3829
DetectFirewallAppPolicy::ts
struct DetectFirewallPolicy ts[48]
Definition: detect.h:932
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
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:132
SC_Pcre2SubstringGet
int SC_Pcre2SubstringGet(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
Definition: detect-parse.c:3763
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3248
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:1507
SignatureInitData_::cidr_src
IPOnlyCIDRItem * cidr_src
Definition: detect.h:622
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
DetectReference_
Signature reference list.
Definition: detect-reference.h:30
SignatureInitData_::hook
SignatureHook hook
Definition: detect.h:594
SIGNATURE_HOOK_TYPE_NOT_SET
@ SIGNATURE_HOOK_TYPE_NOT_SET
Definition: detect.h:548
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:39
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:325
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2366
Signature_::action
uint8_t action
Definition: detect.h:690
util-profiling.h
util-rule-vars.h
SignatureHookType
SignatureHookType
Definition: detect.h:547
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:676
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:515
detect-engine-build.h
conf-yaml-loader.h
ACTION_SCOPE_TX
@ ACTION_SCOPE_TX
Definition: action-globals.h:47
ACTION_SCOPE_AUTO
@ ACTION_SCOPE_AUTO
Definition: action-globals.h:43
detect-engine-alert.h
conf.h
DetectBufferType_::packet
bool packet
Definition: detect.h:455
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DETECT_MAX_RULE_SIZE
#define DETECT_MAX_RULE_SIZE
Definition: detect.h:46
SignatureParser_::direction
char direction[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:104
detect-ipproto.h
DetectEngineBufferTypeGetById
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1404
SignatureInitDataBufferCheckExpand
int SignatureInitDataBufferCheckExpand(Signature *s)
check if buffers array still has space left, expand if not
Definition: detect-parse.c:1986
DETECT_TABLE_PACKET_TD
@ DETECT_TABLE_PACKET_TD
Definition: detect.h:561
DetectBufferType_::name
char name[64]
Definition: detect.h:450
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:754
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:601
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1471
SignatureInitData_
Definition: detect.h:593
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:606
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:392
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
Signature_::addr_dst_match6_cnt
uint16_t addr_dst_match6_cnt
Definition: detect.h:702
SIG_TYPE_DEONLY
@ SIG_TYPE_DEONLY
Definition: detect.h:71
SIGNATURE_HOOK_PKT_PRE_STREAM
@ SIGNATURE_HOOK_PKT_PRE_STREAM
Definition: detect.h:543
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:78
SIG_ALPROTO_MAX
#define SIG_ALPROTO_MAX
Definition: detect.h:591
Signature_::sp
DetectPort * sp
Definition: detect.h:726
DetectMetadata_
Signature metadata list.
Definition: detect-metadata.h:30
DETECT_FIREWALL_POLICY_PRE_STREAM
@ DETECT_FIREWALL_POLICY_PRE_STREAM
Definition: detect.h:919
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect-engine-register.h:325
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:401
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2295
DetectEngineBufferTypeSupportsMpmGetById
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1551
DetectEngineCtx_::dup_sig_hash_table
HashListTable * dup_sig_hash_table
Definition: detect.h:1012
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:1098
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:34
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1333
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:417
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
DETECT_SM_LIST_NOTSET
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:144
DetectAbsentValidateContentCallback
bool DetectAbsentValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-isdataat.c:118
ACTION_REJECT_BOTH
#define ACTION_REJECT_BOTH
Definition: action-globals.h:33
SigTableApplyStrictCommandLineOption
void SigTableApplyStrictCommandLineOption(const char *str)
Definition: detect-parse.c:343
SignatureInitDataBuffer_::tail
SigMatch * tail
Definition: detect.h:536
DetectAddressHead_::ipv6_head
DetectAddress * ipv6_head
Definition: detect.h:185
SIG_DIREC_DST
@ SIG_DIREC_DST
Definition: detect-parse.h:50
DetectBufferType_::frame
bool frame
Definition: detect.h:456
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:40
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:3595
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
BIT_U8
#define BIT_U8(n)
Definition: suricata-common.h:423
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
SigTableElmt_::alias
const char * alias
Definition: detect.h:1510
DetectFirewallLoadDefaultPolicies
int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx)
Definition: detect-parse.c:4072
suricata-common.h
SigMatch_::idx
uint16_t idx
Definition: detect.h:358
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:242
ActionScope
ActionScope
Definition: action-globals.h:42
SigMatch_::type
uint16_t type
Definition: detect.h:357
DETECT_FIREWALL_POLICY_PACKET_FILTER
@ DETECT_FIREWALL_POLICY_PACKET_FILTER
Definition: detect.h:917
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:691
SIG_FLAG_INIT_FORCE_TOSERVER
#define SIG_FLAG_INIT_FORCE_TOSERVER
Definition: detect.h:302
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:721
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
SIGMATCH_OPTIONAL_OPT
#define SIGMATCH_OPTIONAL_OPT
Definition: detect-engine-register.h:318
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:697
packet.h
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SignatureInitData_::curbuf
SignatureInitDataBuffer * curbuf
Definition: detect.h:657
SignatureHook_::type
enum SignatureHookType type
Definition: detect.h:576
SIG_DIREC_SWITCHED
@ SIG_DIREC_SWITCHED
Definition: detect-parse.h:43
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:3751
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:542
DetectMatchAddressIPv4_::ip2
uint32_t ip2
Definition: detect.h:191
Signature_::rev
uint32_t rev
Definition: detect.h:722
SignatureInitData_::sm_cnt
uint16_t sm_cnt
Definition: detect.h:597
Signature_::proto
DetectProto * proto
Definition: detect.h:694
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:549
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:982
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:2052
DetectEngineAppInspectionEngineSignatureFree
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
free app inspect engines for a signature
Definition: detect-engine.c:1035
ACTION_CONFIG
#define ACTION_CONFIG
Definition: action-globals.h:35
DETECT_SM_LIST_TMATCH
@ DETECT_SM_LIST_TMATCH
Definition: detect.h:129
TransformData_::transform
int transform
Definition: detect.h:387
SignatureParser
struct SignatureParser_ SignatureParser
Signature_::prio
int prio
Definition: detect.h:723
DetectEngineCtx_::sm_types_silent_error
bool * sm_types_silent_error
Definition: detect.h:1159
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:426
DetectMatchAddressIPv6_::ip
uint32_t ip[4]
Definition: detect.h:195
SIGMATCH_STRICT_PARSING
#define SIGMATCH_STRICT_PARSING
Definition: detect-engine-register.h:337
SignatureInitDataBuffer_::only_ts
bool only_ts
Definition: detect.h:533
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:261
detect-flow.h
Signature_::addr_src_match6_cnt
uint16_t addr_src_match6_cnt
Definition: detect.h:703
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:654
DetectEngineCtx_::app_inspect_engines
DetectEngineAppInspectionEngine * app_inspect_engines
Definition: detect.h:1134
SignatureInitData_::dst
const DetectAddressHead * dst
Definition: detect.h:646
SignatureInitData_::firewall_rule
bool firewall_rule
Definition: detect.h:671
SIGNATURE_HOOK_PKT_ALL
@ SIGNATURE_HOOK_PKT_ALL
Definition: detect.h:544
Signature_::dp
DetectPort * dp
Definition: detect.h:726
str
#define str(s)
Definition: suricata-common.h:316
detect-http-method.h
Signature_::metadata
DetectMetadataHead * metadata
Definition: detect.h:750
DetectFirewallPolicy
Definition: detect.h:924
SCConfGetNode
SCConfNode * SCConfGetNode(const char *name)
Get a SCConfNode by name.
Definition: conf.c:184
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
DETECT_TBLSIZE
int DETECT_TBLSIZE
Definition: detect-engine-register.c:268
Signature_::iid
SigIntId iid
Definition: detect.h:687
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:438
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:994
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1493
Signature_::addr_dst_match6
DetectMatchAddressIPv6 * addr_dst_match6
Definition: detect.h:717
Signature_::id
uint32_t id
Definition: detect.h:720
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
DetectMetadata_::next
struct DetectMetadata_ * next
Definition: detect-metadata.h:36
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
detect-engine-iponly.h
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
SignatureInitDataBuffer_::id
uint32_t id
Definition: detect.h:526
Signature_
Signature container.
Definition: detect.h:675
SigMatch_
a single match condition for a signature
Definition: detect.h:356
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:135
ALPROTO_HTTP
@ ALPROTO_HTTP
Definition: app-layer-protos.h:77
DETECT_PROTO_ONLY_PKT
#define DETECT_PROTO_ONLY_PKT
Definition: detect-engine-proto.h:29
HashTableInit
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hash.c:35
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:381
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:2721
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:609
SignatureSetType
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-build.c:1699
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:3751
ACTION_ACCEPT
#define ACTION_ACCEPT
Definition: action-globals.h:36
DETECT_PROTO_L2_ANY
#define DETECT_PROTO_L2_ANY
Definition: detect-engine-proto.h:35
SIGNATURE_HOOK_PKT_FLOW_START
@ SIGNATURE_HOOK_PKT_FLOW_START
Definition: detect.h:541
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:393
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect-engine-register.h:339
SCClassConfGenerateValidDummyClassConfigFD01
FILE * SCClassConfGenerateValidDummyClassConfigFD01(void)
Creates a dummy classification file, with all valid Classtypes, for testing purposes.
Definition: util-classification-config.c:587
DetectPcreData_
Definition: detect-pcre.h:47
DETECT_FIREWALL_POLICY_PRE_FLOW
@ DETECT_FIREWALL_POLICY_PRE_FLOW
Definition: detect.h:918
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:418
Signature_::detect_table
uint8_t detect_table
Definition: detect.h:709
DetectParseAddress
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
Definition: detect-engine-address.c:1432
SignatureInitDataBuffer_::only_tc
bool only_tc
Definition: detect.h:532
detect-uricontent.h
DETECT_DEFAULT_PRIO
#define DETECT_DEFAULT_PRIO
Definition: detect.h:52
DetectEngineBufferRunValidateCallback
bool DetectEngineBufferRunValidateCallback(const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
Definition: detect-engine.c:1598
DetectEngineCtx_::sigerror
const char * sigerror
Definition: detect.h:1072
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:3659
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:975
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:2006
SignatureInitData_::transforms
DetectEngineTransforms transforms
Definition: detect.h:635
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:653
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
Signature_::addr_dst_match4
DetectMatchAddressIPv4 * addr_dst_match4
Definition: detect.h:714
DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_REPLACE
Definition: detect-content.h:51
Signature_::msg
char * msg
Definition: detect.h:743
flow.h
SignatureInitDataBuffer_
Definition: detect.h:525
Signature_::addr_src_match4_cnt
uint16_t addr_src_match4_cnt
Definition: detect.h:701
DetectFirewallPolicy::action_scope
uint8_t action_scope
Definition: detect.h:926
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:700
DetectFirewallGetPolicySignature
Signature * DetectFirewallGetPolicySignature(struct DetectFirewallPolicies *fw_policies, const AppProto alproto, const int direction, const uint8_t hook)
Definition: detect-parse.c:4153
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:678
SCConfNode_
Definition: conf.h:37
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:994
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:655
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:3696
SCConfNode_::val
char * val
Definition: conf.h:39
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect-engine-register.h:329
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:109
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:520
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:3523
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:42
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:2124
RetrieveFPForSig
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-mpm.c:1156
DetectListSupportedProtocols
void DetectListSupportedProtocols(void)
Definition: detect-parse.c:1373
app-layer.h
SignatureInitData_::alprotos
AppProto alprotos[SIG_ALPROTO_MAX]
Definition: detect.h:616
SCClassConfDeInitContext
void SCClassConfDeInitContext(DetectEngineCtx *de_ctx)
Releases resources used by the Classification Config API.
Definition: util-classification-config.c:191
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:115
DetectProtoFinalizeSignature
int DetectProtoFinalizeSignature(Signature *s)
Definition: detect-engine-proto.c:157
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:253