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