suricata
detect-parse.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2025 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * signature parser
24  */
25 
26 #include "suricata-common.h"
27 
28 #include "detect.h"
29 #include "detect-engine.h"
30 #include "detect-engine-address.h"
31 #include "detect-engine-port.h"
32 #include "detect-engine-mpm.h"
33 #include "detect-engine-state.h"
34 #include "detect-engine-build.h"
35 
36 #include "detect-content.h"
37 #include "detect-bsize.h"
38 #include "detect-isdataat.h"
39 #include "detect-pcre.h"
40 #include "detect-uricontent.h"
41 #include "detect-reference.h"
42 #include "detect-ipproto.h"
43 #include "detect-flow.h"
45 #include "detect-lua.h"
46 #include "detect-app-layer-event.h"
47 #include "detect-http-method.h"
48 
49 #include "pkt-var.h"
50 #include "host.h"
51 #include "util-profiling.h"
52 #include "decode.h"
53 
54 #include "flow.h"
55 
56 #include "util-rule-vars.h"
57 #include "conf.h"
58 #include "conf-yaml-loader.h"
59 
60 #include "app-layer.h"
61 #include "app-layer-protos.h"
62 #include "app-layer-parser.h"
63 #include "app-layer-htp.h"
64 
66 #include "util-unittest.h"
67 #include "util-unittest-helper.h"
68 #include "util-debug.h"
69 #include "string.h"
70 #include "detect-parse.h"
71 #include "detect-engine-iponly.h"
72 #include "detect-engine-file.h"
73 #include "app-layer-detect-proto.h"
74 
75 #include "action-globals.h"
76 #include "util-validate.h"
77 
78 /* Table with all SigMatch registrations */
80 
81 extern bool sc_set_caps;
82 
83 static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
84  SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
85  SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail);
86 
87 /**
88  * \brief Registration table for file handlers
89  */
90 /**
91  * \brief We use this as data to the hash table DetectEngineCtx->dup_sig_hash_table.
92  */
93 typedef struct SigDuplWrapper_ {
94  /* the signature we want to wrap */
96  /* the signature right before the above signature in the det_ctx->sig_list */
99 
100 /** helper structure for sig parsing */
101 typedef struct SignatureParser_ {
111 
112 const char *DetectListToHumanString(int list)
113 {
114 #define CASE_CODE_STRING(E, S) case E: return S; break
115  switch (list) {
123  CASE_CODE_STRING(DETECT_SM_LIST_MAX, "max (internal)");
124  }
125 #undef CASE_CODE_STRING
126  return "unknown";
127 }
128 
129 #define CASE_CODE(E) case E: return #E
130 const char *DetectListToString(int list)
131 {
132  switch (list) {
141  }
142  return "unknown";
143 }
144 
145 /** \param arg NULL or empty string */
147  Signature *s, const char *arg, int sm_type, int sm_list,
148  AppProto alproto)
149 {
150  SigMatch *sm = NULL;
151  int ret = -1;
152 
153  if (arg != NULL && strcmp(arg, "") != 0) {
154  SCLogError("%s shouldn't be supplied "
155  "with an argument",
156  sigmatch_table[sm_type].name);
157  goto end;
158  }
159 
160  if (s->init_data->list != DETECT_SM_LIST_NOTSET) {
161  SCLogError("\"%s\" keyword seen "
162  "with a sticky buffer still set. Reset sticky buffer "
163  "with pkt_data before using the modifier.",
164  sigmatch_table[sm_type].name);
165  goto end;
166  }
167  if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, alproto)) {
168  SCLogError("rule contains conflicting "
169  "alprotos set");
170  goto end;
171  }
172 
175  if (sm == NULL) {
176  SCLogError("\"%s\" keyword "
177  "found inside the rule without a content context. "
178  "Please use a \"content\" keyword before using the "
179  "\"%s\" keyword",
180  sigmatch_table[sm_type].name, sigmatch_table[sm_type].name);
181  goto end;
182  }
184  if (cd->flags & DETECT_CONTENT_RAWBYTES) {
185  SCLogError("%s rule can not "
186  "be used with the rawbytes rule keyword",
187  sigmatch_table[sm_type].name);
188  goto end;
189  }
190  if (cd->flags & DETECT_CONTENT_REPLACE) {
191  SCLogError("%s rule can not "
192  "be used with the replace rule keyword",
193  sigmatch_table[sm_type].name);
194  goto end;
195  }
199  if (pm != NULL) {
200  if (pm->type == DETECT_CONTENT) {
201  DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
203  } else {
204  DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
205  tmp_pd->flags &= ~DETECT_PCRE_RELATIVE_NEXT;
206  }
207  }
208 
209  if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id == sm_list) {
212  if (pm != NULL) {
213  if (pm->type == DETECT_CONTENT) {
214  DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
216  } else {
217  DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
218  tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
219  }
220  }
221  }
222  }
223  s->alproto = alproto;
224  s->flags |= SIG_FLAG_APPLAYER;
225 
226  if (s->init_data->curbuf == NULL || (int)s->init_data->curbuf->id != sm_list) {
227  if (s->init_data->curbuf != NULL && s->init_data->curbuf->head == NULL) {
228  SCLogError("no matches for previous buffer");
229  return -1;
230  }
231  bool reuse_buffer = false;
232  if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != sm_list) {
233  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
234  if (s->init_data->buffers[x].id == (uint32_t)sm_list) {
235  s->init_data->curbuf = &s->init_data->buffers[x];
236  reuse_buffer = true;
237  break;
238  }
239  }
240  }
241 
242  if (!reuse_buffer) {
244  SCLogError("failed to expand rule buffer array");
245  return -1;
246  }
247 
248  /* initialize a new buffer */
250  s->init_data->curbuf->id = sm_list;
251  s->init_data->curbuf->head = NULL;
252  s->init_data->curbuf->tail = NULL;
253  SCLogDebug("idx %u list %d set up curbuf %p s->init_data->buffer_index %u",
254  s->init_data->buffer_index - 1, sm_list, s->init_data->curbuf,
255  s->init_data->buffer_index);
256  }
257  }
258 
259  /* transfer the sm from the pmatch list to sm_list */
260  SigMatchTransferSigMatchAcrossLists(sm, &s->init_data->smlists[DETECT_SM_LIST_PMATCH],
262  &s->init_data->curbuf->tail);
263 
264  if (sm->type == DETECT_CONTENT) {
266  MAX(s->init_data->max_content_list_id, (uint32_t)sm_list);
267  }
268 
269  ret = 0;
270  end:
271  return ret;
272 }
273 
275 {
276  SigMatch *sm = SCCalloc(1, sizeof(SigMatch));
277  if (unlikely(sm == NULL))
278  return NULL;
279 
280  sm->prev = NULL;
281  sm->next = NULL;
282  return sm;
283 }
284 
285 /** \brief free a SigMatch
286  * \param sm SigMatch to free.
287  */
289 {
290  if (sm == NULL)
291  return;
292 
293  /** free the ctx, for that we call the Free func */
294  if (sm->ctx != NULL) {
295  if (sigmatch_table[sm->type].Free != NULL) {
296  sigmatch_table[sm->type].Free(de_ctx, sm->ctx);
297  }
298  }
299  SCFree(sm);
300 }
301 
302 static enum DetectKeywordId SigTableGetIndex(const SigTableElmt *e)
303 {
304  const SigTableElmt *table = &sigmatch_table[0];
305  ptrdiff_t offset = e - table;
307  return (enum DetectKeywordId)offset;
308 }
309 
310 /* Get the detection module by name */
311 static SigTableElmt *SigTableGet(char *name)
312 {
313  SigTableElmt *st = NULL;
314  int i = 0;
315 
316  for (i = 0; i < DETECT_TBLSIZE; i++) {
317  st = &sigmatch_table[i];
318 
319  if (st->name != NULL) {
320  if (strcasecmp(name,st->name) == 0)
321  return st;
322  if (st->alias != NULL && strcasecmp(name,st->alias) == 0)
323  return st;
324  }
325  }
326 
327  return NULL;
328 }
329 
331 {
332  return de_ctx->sm_types_silent_error[id];
333 }
334 
336 {
337  if ((int)id < DETECT_TBLSIZE) {
338  return ((sigmatch_table[id].flags & SIGMATCH_STRICT_PARSING) != 0);
339  }
340  return false;
341 }
342 
344 {
345  if (str == NULL) {
346  /* nothing to be done */
347  return;
348  }
349 
350  /* "all" just sets the flag for each keyword */
351  if (strcmp(str, "all") == 0) {
352  for (int i = 0; i < DETECT_TBLSIZE; i++) {
353  SigTableElmt *st = &sigmatch_table[i];
355  }
356  return;
357  }
358 
359  char *copy = SCStrdup(str);
360  if (copy == NULL)
361  FatalError("could not duplicate opt string");
362 
363  char *xsaveptr = NULL;
364  char *key = strtok_r(copy, ",", &xsaveptr);
365  while (key != NULL) {
366  SigTableElmt *st = SigTableGet(key);
367  if (st != NULL) {
369  } else {
370  SCLogWarning("'strict' command line "
371  "argument '%s' not found",
372  key);
373  }
374  key = strtok_r(NULL, ",", &xsaveptr);
375  }
376 
377  SCFree(copy);
378 }
379 
380 /**
381  * \brief Append a SigMatch to the list type.
382  *
383  * \param s Signature.
384  * \param new The sig match to append.
385  * \param list The list to append to.
386  */
388  DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
389 {
390  SigMatch *new = SigMatchAlloc();
391  if (new == NULL)
392  return NULL;
393 
394  new->type = type;
395  new->ctx = ctx;
396 
397  if (new->type == DETECT_CONTENT) {
399  }
400 
401  SCLogDebug("s:%p new:%p list:%d: %s, s->init_data->list_set %s s->init_data->list %d", s, new,
402  list, sigmatch_table[new->type].name, BOOL2STR(s->init_data->list_set),
403  s->init_data->list);
404 
405  if (list < DETECT_SM_LIST_MAX) {
406  if (s->init_data->smlists[list] == NULL) {
407  s->init_data->smlists[list] = new;
408  s->init_data->smlists_tail[list] = new;
409  new->next = NULL;
410  new->prev = NULL;
411  } else {
412  SigMatch *cur = s->init_data->smlists_tail[list];
413  cur->next = new;
414  new->prev = cur;
415  new->next = NULL;
416  s->init_data->smlists_tail[list] = new;
417  }
418  new->idx = s->init_data->sm_cnt;
419  s->init_data->sm_cnt++;
420 
421  } else {
422  /* app-layer-events (and possibly others?) can get here w/o a "list"
423  * already set up. */
424 
425  /* unset any existing list if it isn't the same as the new */
426  if (s->init_data->list != DETECT_SM_LIST_NOTSET && list != s->init_data->list) {
427  SCLogDebug("reset: list %d != s->init_data->list %d", list, s->init_data->list);
429  }
430 
431  if (s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) {
432  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
433  if (s->init_data->buffers[x].id == (uint32_t)list &&
434  !s->init_data->buffers[x].multi_capable) {
435  SCLogDebug("reusing buffer %u as it isn't multi-capable", x);
436  s->init_data->curbuf = &s->init_data->buffers[x];
437  break;
438  }
439  }
440  }
441 
442  if ((s->init_data->curbuf != NULL && (int)s->init_data->curbuf->id != list) ||
443  s->init_data->curbuf == NULL) {
445  SCLogError("failed to expand rule buffer array");
446  new->ctx = NULL;
447  SigMatchFree(de_ctx, new);
448  return NULL;
449  } else {
450  /* initialize new buffer */
452  s->init_data->curbuf->id = list;
453  /* buffer set up by sigmatch is tracked in case we add a stickybuffer for the
454  * same list. */
455  s->init_data->curbuf->sm_init = true;
457  s->init_data->curbuf->only_tc = true;
458  }
460  s->init_data->curbuf->only_ts = true;
461  }
462  SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
463  }
464  }
465  BUG_ON(s->init_data->curbuf == NULL);
466 
467  new->prev = s->init_data->curbuf->tail;
468  if (s->init_data->curbuf->tail)
469  s->init_data->curbuf->tail->next = new;
470  if (s->init_data->curbuf->head == NULL)
471  s->init_data->curbuf->head = new;
472  s->init_data->curbuf->tail = new;
473  new->idx = s->init_data->sm_cnt;
474  s->init_data->sm_cnt++;
475  SCLogDebug("appended %s to list %d, rule pos %u (s->init_data->list %d)",
476  sigmatch_table[new->type].name, list, new->idx, s->init_data->list);
477 
478  for (SigMatch *sm = s->init_data->curbuf->head; sm != NULL; sm = sm->next) {
479  SCLogDebug("buf:%p: id:%u: '%s' pos %u", s->init_data->curbuf, s->init_data->curbuf->id,
480  sigmatch_table[sm->type].name, sm->idx);
481  }
482  }
483  return new;
484 }
485 
486 void SigMatchRemoveSMFromList(Signature *s, SigMatch *sm, int sm_list)
487 {
488  if (sm == s->init_data->smlists[sm_list]) {
489  s->init_data->smlists[sm_list] = sm->next;
490  }
491  if (sm == s->init_data->smlists_tail[sm_list]) {
492  s->init_data->smlists_tail[sm_list] = sm->prev;
493  }
494  if (sm->prev != NULL)
495  sm->prev->next = sm->next;
496  if (sm->next != NULL)
497  sm->next->prev = sm->prev;
498 }
499 
500 /**
501  * \brief Returns a pointer to the last SigMatch instance of a particular type
502  * in a Signature of the payload list.
503  *
504  * \param s Pointer to the tail of the sigmatch list
505  * \param type SigMatch type which has to be searched for in the Signature.
506  *
507  * \retval match Pointer to the last SigMatch instance of type 'type'.
508  */
509 static SigMatch *SigMatchGetLastSMByType(SigMatch *sm, int type)
510 {
511  while (sm != NULL) {
512  if (sm->type == type) {
513  return sm;
514  }
515  sm = sm->prev;
516  }
517 
518  return NULL;
519 }
520 
521 /** \brief get the last SigMatch from lists that support
522  * MPM.
523  * \note only supports the lists that are registered through
524  * DetectBufferTypeSupportsMpm().
525  */
527 {
528  SigMatch *sm_last = NULL;
529  SigMatch *sm_new;
530  uint32_t sm_type;
531 
532  for (uint32_t i = 0; i < s->init_data->buffer_index; i++) {
533  const int id = s->init_data->buffers[i].id;
536  if (sm_new == NULL)
537  continue;
538  if (sm_last == NULL || sm_new->idx > sm_last->idx)
539  sm_last = sm_new;
540  }
541  }
542  /* otherwise brute force it */
543  for (sm_type = 0; sm_type < DETECT_SM_LIST_MAX; sm_type++) {
545  continue;
546  SigMatch *sm_list = s->init_data->smlists_tail[sm_type];
547  sm_new = SigMatchGetLastSMByType(sm_list, DETECT_CONTENT);
548  if (sm_new == NULL)
549  continue;
550  if (sm_last == NULL || sm_new->idx > sm_last->idx)
551  sm_last = sm_new;
552  }
553 
554  return sm_last;
555 }
556 
557 /**
558  * \brief Returns the sm with the largest index (added latest) from the lists
559  * passed to us.
560  *
561  * \retval Pointer to Last sm.
562  */
564 {
565  SigMatch *sm_last = NULL;
566  SigMatch *sm_new;
567 
568  SCLogDebug("s->init_data->buffer_index %u", s->init_data->buffer_index);
569  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
570  if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
571  s->init_data->list != (int)s->init_data->buffers[x].id) {
572  SCLogDebug("skip x %u s->init_data->list %d (int)s->init_data->buffers[x].id %d", x,
573  s->init_data->list, (int)s->init_data->buffers[x].id);
574 
575  continue;
576  }
577  int sm_type;
578  va_list ap;
579  va_start(ap, s);
580 
581  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
582  sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
583  if (sm_new == NULL)
584  continue;
585  if (sm_last == NULL || sm_new->idx > sm_last->idx)
586  sm_last = sm_new;
587  }
588  va_end(ap);
589  }
590 
591  for (int buf_type = 0; buf_type < DETECT_SM_LIST_MAX; buf_type++) {
592  if (s->init_data->smlists[buf_type] == NULL)
593  continue;
594  if (s->init_data->list != DETECT_SM_LIST_NOTSET &&
595  buf_type != s->init_data->list)
596  continue;
597 
598  int sm_type;
599  va_list ap;
600  va_start(ap, s);
601 
602  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
603  {
604  sm_new = SigMatchGetLastSMByType(s->init_data->smlists_tail[buf_type], sm_type);
605  if (sm_new == NULL)
606  continue;
607  if (sm_last == NULL || sm_new->idx > sm_last->idx)
608  sm_last = sm_new;
609  }
610  va_end(ap);
611  }
612 
613  return sm_last;
614 }
615 
616 /**
617  * \brief Returns the sm with the largest index (added last) from the list
618  * passed to us as a pointer.
619  *
620  * \param sm_list pointer to the SigMatch we should look before
621  * \param va_args list of keyword types terminated by -1
622  *
623  * \retval sm_last to last sm.
624  */
626 {
627  SigMatch *sm_last = NULL;
628  SigMatch *sm_new;
629  int sm_type;
630 
631  va_list ap;
632  va_start(ap, sm_list);
633 
634  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int))
635  {
636  sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
637  if (sm_new == NULL)
638  continue;
639  if (sm_last == NULL || sm_new->idx > sm_last->idx)
640  sm_last = sm_new;
641  }
642 
643  va_end(ap);
644 
645  return sm_last;
646 }
647 
648 /**
649  * \brief Returns the sm with the largest index (added last) from the list
650  * passed to us as an id.
651  *
652  * \param list_id id of the list to be searched
653  * \param va_args list of keyword types terminated by -1
654  *
655  * \retval sm_last to last sm.
656  */
657 SigMatch *DetectGetLastSMByListId(const Signature *s, int list_id, ...)
658 {
659  SigMatch *sm_last = NULL;
660  SigMatch *sm_new;
661  int sm_type;
662 
663  if ((uint32_t)list_id >= DETECT_SM_LIST_MAX) {
664  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
665  sm_new = s->init_data->buffers[x].tail;
666  if (sm_new == NULL)
667  continue;
668 
669  va_list ap;
670  va_start(ap, list_id);
671 
672  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
673  sm_new = SigMatchGetLastSMByType(s->init_data->buffers[x].tail, sm_type);
674  if (sm_new == NULL)
675  continue;
676  if (sm_last == NULL || sm_new->idx > sm_last->idx)
677  sm_last = sm_new;
678  }
679 
680  va_end(ap);
681  }
682  } else {
683  SigMatch *sm_list = s->init_data->smlists_tail[list_id];
684  if (sm_list == NULL)
685  return NULL;
686 
687  va_list ap;
688  va_start(ap, list_id);
689 
690  for (sm_type = va_arg(ap, int); sm_type != -1; sm_type = va_arg(ap, int)) {
691  sm_new = SigMatchGetLastSMByType(sm_list, sm_type);
692  if (sm_new == NULL)
693  continue;
694  if (sm_last == NULL || sm_new->idx > sm_last->idx)
695  sm_last = sm_new;
696  }
697 
698  va_end(ap);
699  }
700  return sm_last;
701 }
702 
703 /**
704  * \brief Returns the sm with the largest index (added latest) from this sig
705  *
706  * \retval sm_last Pointer to last sm
707  */
709 {
710  SigMatch *sm_last = NULL;
711  SigMatch *sm_new;
712 
713  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
714  sm_new = s->init_data->buffers[x].tail;
715  if (sm_new == NULL)
716  continue;
717  if (sm_last == NULL || sm_new->idx > sm_last->idx)
718  sm_last = sm_new;
719  }
720 
721  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
722  sm_new = s->init_data->smlists_tail[i];
723  if (sm_new == NULL)
724  continue;
725  if (sm_last == NULL || sm_new->idx > sm_last->idx)
726  sm_last = sm_new;
727  }
728 
729  return sm_last;
730 }
731 
732 static void SigMatchTransferSigMatchAcrossLists(SigMatch *sm,
733  SigMatch **src_sm_list, SigMatch **src_sm_list_tail,
734  SigMatch **dst_sm_list, SigMatch **dst_sm_list_tail)
735 {
736  /* we won't do any checks for args */
737 
738  if (sm->prev != NULL)
739  sm->prev->next = sm->next;
740  if (sm->next != NULL)
741  sm->next->prev = sm->prev;
742 
743  if (sm == *src_sm_list)
744  *src_sm_list = sm->next;
745  if (sm == *src_sm_list_tail)
746  *src_sm_list_tail = sm->prev;
747 
748  if (*dst_sm_list == NULL) {
749  *dst_sm_list = sm;
750  *dst_sm_list_tail = sm;
751  sm->next = NULL;
752  sm->prev = NULL;
753  } else {
754  SigMatch *cur = *dst_sm_list_tail;
755  cur->next = sm;
756  sm->prev = cur;
757  sm->next = NULL;
758  *dst_sm_list_tail = sm;
759  }
760 }
761 
762 int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
763 {
764  if (key_sm == NULL)
765  return -1;
766 
767  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
768  const SigMatch *sm = s->init_data->buffers[x].head;
769  while (sm != NULL) {
770  if (sm == key_sm)
771  return s->init_data->buffers[x].id;
772  sm = sm->next;
773  }
774  }
775 
776  for (int list = 0; list < DETECT_SM_LIST_MAX; list++) {
777  const SigMatch *sm = s->init_data->smlists[list];
778  while (sm != NULL) {
779  if (sm == key_sm)
780  return list;
781  sm = sm->next;
782  }
783  }
784 
785  SCLogError("Unable to find the sm in any of the "
786  "sm lists");
787  return -1;
788 }
789 
790 /**
791  * \brief Parse and setup a direction
792  *
793  * \param s signature
794  * \param str argument to the keyword
795  * \param only_dir argument wether the keyword only accepts a direction
796  *
797  * \retval 0 on success, -1 on failure
798  */
799 static int DetectSetupDirection(Signature *s, char **str, bool only_dir)
800 {
801  char *orig = *str;
802  if (strncmp(*str, "to_client", strlen("to_client")) == 0) {
803  *str += strlen("to_client");
804  // skip space
805  while (**str && isblank(**str)) {
806  (*str)++;
807  }
808  // check comma or nothing
809  if (**str) {
810  if (only_dir) {
811  SCLogError("unknown option: only accepts to_server or to_client");
812  return -1;
813  }
814  if (**str != ',') {
815  // leave to_client_something for next parser if not only_dir
816  *str = orig;
817  return 0;
818  } else {
819  (*str)++;
820  }
821  while (**str && isblank(**str)) {
822  (*str)++;
823  }
824  }
826  if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
827  if (s->flags & SIG_FLAG_TOSERVER) {
828  SCLogError("contradictory directions");
829  return -1;
830  }
831  s->flags |= SIG_FLAG_TOCLIENT;
832  }
833  } else if (strncmp(*str, "to_server", strlen("to_server")) == 0) {
834  *str += strlen("to_server");
835  // skip space
836  while (**str && isblank(**str)) {
837  (*str)++;
838  }
839  // check comma or nothing
840  if (**str) {
841  if (only_dir) {
842  SCLogError("unknown option: only accepts to_server or to_client");
843  return -1;
844  }
845  if (**str != ',') {
846  // leave to_client_something for next parser if not only_dir
847  *str = orig;
848  return 0;
849  } else {
850  (*str)++;
851  }
852  while (**str && isblank(**str)) {
853  (*str)++;
854  }
855  }
857  if ((s->flags & SIG_FLAG_TXBOTHDIR) == 0) {
858  if (s->flags & SIG_FLAG_TOCLIENT) {
859  SCLogError("contradictory directions");
860  return -1;
861  }
862  s->flags |= SIG_FLAG_TOSERVER;
863  }
864  } else if (only_dir) {
865  SCLogError("unknown option: only accepts to_server or to_client");
866  return -1;
867  }
868  return 0;
869 }
870 
871 static int SigParseOptions(DetectEngineCtx *de_ctx, Signature *s, char *optstr, char *output,
872  size_t output_size, bool requires)
873 {
874  SigTableElmt *st = NULL;
875  char *optname = NULL;
876  char *optvalue = NULL;
877 
878  /* Trim leading space. */
879  while (isblank(*optstr)) {
880  optstr++;
881  }
882 
883  /* Look for the end of this option, handling escaped semicolons. */
884  char *optend = optstr;
885  for (;;) {
886  optend = strchr(optend, ';');
887  if (optend == NULL) {
888  SCLogError("no terminating \";\" found");
889  goto error;
890  }
891  else if (optend > optstr && *(optend -1 ) == '\\') {
892  optend++;
893  } else {
894  break;
895  }
896  }
897  *(optend++) = '\0';
898 
899  /* Find the start of the option value. */
900  char *optvalptr = strchr(optstr, ':');
901  if (optvalptr) {
902  *(optvalptr++) = '\0';
903 
904  /* Trim trailing space from name. */
905  for (size_t i = strlen(optvalptr); i > 0; i--) {
906  if (isblank(optvalptr[i - 1])) {
907  optvalptr[i - 1] = '\0';
908  } else {
909  break;
910  }
911  }
912 
913  optvalue = optvalptr;
914  }
915 
916  /* Trim trailing space from name. */
917  for (size_t i = strlen(optstr); i > 0; i--) {
918  if (isblank(optstr[i - 1])) {
919  optstr[i - 1] = '\0';
920  } else {
921  break;
922  }
923  }
924  optname = optstr;
925 
926  /* Check for options that are only to be processed during the
927  * first "requires" pass. */
928  bool requires_only = strcasecmp(optname, "requires") == 0 || strcasecmp(optname, "sid") == 0;
929  if ((requires && !requires_only) || (!requires && requires_only)) {
930  goto finish;
931  }
932 
933  /* Call option parsing */
934  st = SigTableGet(optname);
935  if (st == NULL || st->Setup == NULL) {
936  SCLogError("unknown rule keyword '%s'.", optname);
937  goto error;
938  }
939 
940  if (!(st->flags & (SIGMATCH_NOOPT|SIGMATCH_OPTIONAL_OPT))) {
941  if (optvalue == NULL || strlen(optvalue) == 0) {
942  SCLogError(
943  "invalid formatting or malformed option to %s keyword: '%s'", optname, optstr);
944  goto error;
945  }
946  } else if (st->flags & SIGMATCH_NOOPT) {
947  if (optvalue && strlen(optvalue)) {
948  SCLogError("unexpected option to %s keyword: '%s'", optname, optstr);
949  goto error;
950  }
951  }
952  s->init_data->negated = false;
953 
954  const enum DetectKeywordId idx = SigTableGetIndex(st);
956 
957  if (st->flags & SIGMATCH_INFO_DEPRECATED) {
958 #define URL "https://suricata.io/our-story/deprecation-policy/"
959  if (st->alternative == 0)
960  SCLogWarning("keyword '%s' is deprecated "
961  "and will be removed soon. See %s",
962  st->name, URL);
963  else
964  SCLogWarning("keyword '%s' is deprecated "
965  "and will be removed soon. Use '%s' instead. "
966  "See %s",
967  st->name, sigmatch_table[st->alternative].name, URL);
968 #undef URL
969  }
970 
971  if (s->init_data->firewall_rule && (st->flags & SIGMATCH_BAN_FIREWALL_RULE) != 0) {
972  SCLogError("keyword \'%s\' is not allowed with firewall rules", optname);
973  goto error;
974  }
975 
976  if (EngineModeIsFirewall() && (st->flags & SIGMATCH_BAN_FIREWALL_MODE) != 0) {
977  SCLogError("keyword \'%s\' is not allowed in firewall mode", optname);
978  goto error;
979  }
980 
981  int setup_ret = 0;
982 
983  /* Validate double quoting, trimming trailing white space along the way. */
984  if (optvalue != NULL && strlen(optvalue) > 0) {
985  size_t ovlen = strlen(optvalue);
986  char *ptr = optvalue;
987 
988  /* skip leading whitespace */
989  while (ovlen > 0) {
990  if (!isblank(*ptr))
991  break;
992  ptr++;
993  ovlen--;
994  }
995  if (ovlen == 0) {
996  SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
997  optstr);
998  goto error;
999  }
1000 
1001  if (s->init_data->firewall_rule && (st->flags & SIGMATCH_SUPPORT_FIREWALL) == 0) {
1002  SCLogWarning("keyword \'%s\' has not been tested for firewall rules", optname);
1003  }
1004 
1005  /* see if value is negated */
1006  if ((st->flags & SIGMATCH_HANDLE_NEGATION) && *ptr == '!') {
1007  s->init_data->negated = true;
1008  ptr++;
1009  ovlen--;
1010  }
1011  /* skip more whitespace */
1012  while (ovlen > 0) {
1013  if (!isblank(*ptr))
1014  break;
1015  ptr++;
1016  ovlen--;
1017  }
1018  if (ovlen == 0) {
1019  SCLogError("invalid formatting or malformed option to %s keyword: \'%s\'", optname,
1020  optstr);
1021  goto error;
1022  }
1023  /* if quoting is mandatory, enforce it */
1024  if (st->flags & SIGMATCH_QUOTES_MANDATORY && ovlen && *ptr != '"') {
1025  SCLogError("invalid formatting to %s keyword: "
1026  "value must be double quoted \'%s\'",
1027  optname, optstr);
1028  goto error;
1029  }
1030 
1032  && ovlen && *ptr == '"')
1033  {
1034  for (; ovlen > 0; ovlen--) {
1035  if (isblank(ptr[ovlen - 1])) {
1036  ptr[ovlen - 1] = '\0';
1037  } else {
1038  break;
1039  }
1040  }
1041  if (ovlen && ptr[ovlen - 1] != '"') {
1042  SCLogError("bad option value formatting (possible missing semicolon) "
1043  "for keyword %s: \'%s\'",
1044  optname, optvalue);
1045  goto error;
1046  }
1047  if (ovlen > 1) {
1048  /* strip leading " */
1049  ptr++;
1050  ovlen--;
1051  ptr[ovlen - 1] = '\0';
1052  ovlen--;
1053  }
1054  if (ovlen == 0) {
1055  SCLogError("bad input "
1056  "for keyword %s: \'%s\'",
1057  optname, optvalue);
1058  goto error;
1059  }
1060  } else {
1061  if (*ptr == '"') {
1062  SCLogError(
1063  "quotes on %s keyword that doesn't support them: \'%s\'", optname, optstr);
1064  goto error;
1065  }
1066  }
1067  /* setup may or may not add a new SigMatch to the list */
1068  if (st->flags & SIGMATCH_SUPPORT_DIR) {
1069  if (DetectSetupDirection(s, &ptr, st->flags & SIGMATCH_OPTIONAL_OPT) < 0) {
1070  SCLogError("%s failed to setup direction", st->name);
1071  goto error;
1072  }
1073  }
1074  setup_ret = st->Setup(de_ctx, s, ptr);
1077  } else {
1078  /* setup may or may not add a new SigMatch to the list */
1079  setup_ret = st->Setup(de_ctx, s, NULL);
1080  }
1081  if (setup_ret < 0) {
1082  SCLogDebug("\"%s\" failed to setup", st->name);
1083 
1084  /* handle 'silent' error case */
1085  if (setup_ret == -2) {
1086  if (!de_ctx->sm_types_silent_error[idx]) {
1087  de_ctx->sm_types_silent_error[idx] = true;
1088  return -1;
1089  }
1090  return -2;
1091  }
1092  return setup_ret;
1093  }
1094  s->init_data->negated = false;
1095 
1096 finish:
1097  if (strlen(optend) > 0) {
1098  strlcpy(output, optend, output_size);
1099  return 1;
1100  }
1101 
1102  return 0;
1103 
1104 error:
1105  return -1;
1106 }
1107 
1108 /** \brief Parse address string and update signature
1109  *
1110  * \retval 0 ok, -1 error
1111  */
1112 static int SigParseAddress(DetectEngineCtx *de_ctx,
1113  Signature *s, const char *addrstr, char flag)
1114 {
1115  SCLogDebug("Address Group \"%s\" to be parsed now", addrstr);
1116 
1117  /* pass on to the address(list) parser */
1118  if (flag == 0) {
1119  if (strcasecmp(addrstr, "any") == 0)
1120  s->flags |= SIG_FLAG_SRC_ANY;
1121 
1122  s->init_data->src = DetectParseAddress(de_ctx, addrstr,
1124  if (s->init_data->src == NULL)
1125  goto error;
1126  } else {
1127  if (strcasecmp(addrstr, "any") == 0)
1128  s->flags |= SIG_FLAG_DST_ANY;
1129 
1130  s->init_data->dst = DetectParseAddress(de_ctx, addrstr,
1132  if (s->init_data->dst == NULL)
1133  goto error;
1134  }
1135 
1136  return 0;
1137 
1138 error:
1139  return -1;
1140 }
1141 
1142 static bool IsBuiltIn(const char *n)
1143 {
1144  return strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0 ||
1145  strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0;
1146 }
1147 
1148 /** \brief register app hooks as generic lists
1149  *
1150  * Register each hook in each app protocol as:
1151  * <alproto>:<hook name>:generic
1152  * These lists can be used by lua scripts to hook into.
1153  *
1154  * \todo move elsewhere? maybe a detect-engine-hook.c?
1155  */
1157 {
1158  for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1159  const char *alproto_name = AppProtoToString(a);
1160  if (strcmp(alproto_name, "http") == 0)
1161  alproto_name = "http1";
1162  SCLogDebug("alproto %u/%s", a, alproto_name);
1163 
1165  uint8_t max_sub_state = AppLayerParserGetMaxSubState(a);
1166  SCLogDebug("%s: max sub state for %u is %u", AppProtoToString(a), a, max_sub_state);
1167  for (uint8_t s = 1; s <= max_sub_state; s++) {
1168  const uint8_t max_state = AppLayerParserGetSubStateCompletion(
1169  a, s); // TODO allow different completion per direction?
1170  const char *sub_state_name = AppLayerParserGetSubStateName(a, s);
1171  if (sub_state_name == NULL)
1172  continue;
1173 
1174  char ts_tx_started[64];
1175  snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:%s:request_started:generic",
1176  alproto_name, sub_state_name);
1179 
1180  char tc_tx_started[64];
1181  snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:%s:response_started:generic",
1182  alproto_name, sub_state_name);
1185 
1186  char ts_tx_complete[64];
1187  snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:%s:request_complete:generic",
1188  alproto_name, sub_state_name);
1190  max_state, DetectEngineInspectGenericList, NULL);
1191 
1192  char tc_tx_complete[64];
1193  snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:%s:response_complete:generic",
1194  alproto_name, sub_state_name);
1196  max_state, DetectEngineInspectGenericList, NULL);
1197 
1198  /* to_server */
1199  for (uint8_t state = 0; state <= max_state; state++) {
1200  const char *state_name =
1201  AppLayerParserGetSubStateProgressName(a, s, state, STREAM_TOSERVER);
1202  BUG_ON(state_name == NULL);
1203 
1204  if (state_name != NULL && !IsBuiltIn(state_name)) {
1205  char list_name[64];
1206  snprintf(list_name, sizeof(list_name), "%s:%s:%s:generic", alproto_name,
1207  sub_state_name, state_name);
1209  s, state, DetectEngineInspectGenericList, NULL);
1210  }
1211  }
1212  /* to_client */
1213  for (uint8_t state = 0; state <= max_state; state++) {
1214  const char *state_name =
1215  AppLayerParserGetSubStateProgressName(a, s, state, STREAM_TOCLIENT);
1216  BUG_ON(state_name == NULL);
1217  if (state_name != NULL && !IsBuiltIn(state_name)) {
1218  char list_name[64];
1219  snprintf(list_name, sizeof(list_name), "%s:%s:%s:generic", alproto_name,
1220  sub_state_name, state_name);
1222  s, state, DetectEngineInspectGenericList, NULL);
1223  }
1224  }
1225  }
1226  } else {
1227  const uint8_t max_progress_ts =
1229  const uint8_t max_progress_tc =
1231 
1232  char ts_tx_started[64];
1233  snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:request_started:generic",
1234  alproto_name);
1236  ts_tx_started, a, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
1237  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_started,
1238  (uint32_t)strlen(ts_tx_started));
1239 
1240  char tc_tx_started[64];
1241  snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:response_started:generic",
1242  alproto_name);
1244  tc_tx_started, a, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
1245  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_started,
1246  (uint32_t)strlen(tc_tx_started));
1247 
1248  char ts_tx_complete[64];
1249  snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:request_complete:generic",
1250  alproto_name);
1252  max_progress_ts, DetectEngineInspectGenericList, NULL);
1253  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_complete,
1254  (uint32_t)strlen(ts_tx_complete));
1255 
1256  char tc_tx_complete[64];
1257  snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:response_complete:generic",
1258  alproto_name);
1260  max_progress_tc, DetectEngineInspectGenericList, NULL);
1261  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_complete,
1262  (uint32_t)strlen(tc_tx_complete));
1263 
1264  for (uint8_t p = 0; p <= max_progress_ts; p++) {
1265  const char *name = AppLayerParserGetStateNameById(
1266  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOSERVER);
1267  if (name != NULL && !IsBuiltIn(name)) {
1268  char list_name[64];
1269  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1270  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1271  (uint32_t)strlen(list_name));
1272 
1275  }
1276  }
1277  for (uint8_t p = 0; p <= max_progress_tc; p++) {
1278  const char *name = AppLayerParserGetStateNameById(
1279  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOCLIENT);
1280  if (name != NULL && !IsBuiltIn(name)) {
1281  char list_name[64];
1282  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1283  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1284  (uint32_t)strlen(list_name));
1285 
1288  }
1289  }
1290  }
1291  }
1292 }
1293 
1294 #ifdef DEBUG
1295 static const char *SignatureHookTypeToString(enum SignatureHookType t)
1296 {
1297  switch (t) {
1299  return "not_set";
1301  return "app";
1303  return "pkt";
1304  }
1305  return "unknown";
1306 }
1307 #endif
1308 
1309 static enum SignatureHookPkt HookPktFromString(const char *str)
1310 {
1311  if (strcmp(str, "flow_start") == 0) {
1313  } else if (strcmp(str, "pre_flow") == 0) {
1315  } else if (strcmp(str, "pre_stream") == 0) {
1317  } else if (strcmp(str, "all") == 0) {
1318  return SIGNATURE_HOOK_PKT_ALL;
1319  }
1321 }
1322 
1323 #ifdef DEBUG
1324 static const char *HookPktToString(const enum SignatureHookPkt ph)
1325 {
1326  switch (ph) {
1328  return "not set";
1330  return "flow_start";
1332  return "pre_flow";
1334  return "pre_stream";
1336  return "all";
1337  }
1338  return "error";
1339 }
1340 #endif
1341 
1342 static SignatureHook SetPktHook(const char *hook_str)
1343 {
1344  SignatureHook h = {
1346  .t.pkt.ph = HookPktFromString(hook_str),
1347  };
1348  return h;
1349 }
1350 
1351 /**
1352  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1353  */
1354 static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1355 {
1356  enum SignatureHookPkt hook = HookPktFromString(h);
1357  if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
1358  s->init_data->hook = SetPktHook(h);
1359  if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
1360  return -1; // TODO unreachable?
1361  }
1362  } else {
1363  SCLogError("unknown pkt hook %s", h);
1364  return -1;
1365  }
1366 
1367  SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
1368  SignatureHookTypeToString(s->init_data->hook.type),
1369  HookPktToString(s->init_data->hook.t.pkt.ph));
1370  return 0;
1371 }
1372 
1373 static SignatureHook SetAppHook(const AppProto alproto, uint8_t sub_state, uint8_t progress)
1374 {
1375  SignatureHook h = {
1377  .t.app.alproto = alproto,
1378  .t.app.sub_state = sub_state,
1379  .t.app.app_progress = progress,
1380  };
1381  return h;
1382 }
1383 
1384 /**
1385  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1386  */
1387 static int SigParseProtoHookApp(
1388  Signature *s, const char *proto_hook, const char *p, const char *in_h)
1389 {
1390  char hook[64];
1391  char generic_hook_name[256];
1392  strlcpy(hook, in_h, sizeof(hook));
1393  const char *h = hook;
1394  const char *t = NULL;
1395  uint8_t sub_state = 0;
1396 
1397  bool has_type = strchr(hook, ':') != NULL;
1398  if (has_type) {
1399  char *rem = NULL;
1400  t = strtok_r(hook, ":", &rem);
1401  h = rem;
1402  SCLogDebug("h: '%s' t: '%s'", h, t);
1403  }
1404  if (h == NULL || strlen(h) == 0) {
1405  SCLogError("invalid hook specification '%s'", hook);
1406  return -1;
1407  }
1408 
1409  if (t != NULL) {
1410  if (strlen(t) == 0) {
1411  SCLogError("invalid tx type specification '%s'", hook);
1412  return -1;
1413  }
1414  if (strcmp(p, "http2") == 0 || strcmp(p, "doh2") == 0) {
1415  if (strcmp(t, "stream") == 0) {
1416  sub_state = HTTP2TxTypeStream;
1417  } else if (strcmp(t, "global") == 0) {
1418  sub_state = HTTP2TxTypeGlobal;
1419  } else {
1420  SCLogError("unknown %s tx type specification '%s': valid values are 'stream' "
1421  "and 'global'",
1422  p, hook);
1423  return -1;
1424  }
1425  } else {
1426  SCLogError("sub states currently only supported for http2 and doh2");
1427  return -1;
1428  }
1429  /* FW hook LTE mode */
1430  if (*h == '<') {
1431  h++;
1432  SCLogDebug("hook and prior hooks: '%s'", h);
1434  }
1435  const uint8_t max_state = AppLayerParserGetSubStateCompletion(
1436  s->alproto, sub_state); // TODO allow different completion per direction?
1437  if (strcmp(h, "request_started") == 0) {
1438  s->flags |= SIG_FLAG_TOSERVER;
1439  s->init_data->hook = SetAppHook(s->alproto, sub_state,
1440  0); // state 0 should be the starting state in each protocol.
1441  } else if (strcmp(h, "response_started") == 0) {
1442  s->flags |= SIG_FLAG_TOCLIENT;
1443  s->init_data->hook = SetAppHook(s->alproto, sub_state,
1444  0); // state 0 should be the starting state in each protocol.
1445  } else if (strcmp(h, "request_complete") == 0) {
1446  s->flags |= SIG_FLAG_TOSERVER;
1447  s->init_data->hook = SetAppHook(s->alproto, sub_state, max_state);
1448  } else if (strcmp(h, "response_complete") == 0) {
1449  s->flags |= SIG_FLAG_TOCLIENT;
1450  s->init_data->hook = SetAppHook(s->alproto, sub_state, max_state);
1451  } else {
1452  const int8_t progress_ts =
1453  AppLayerParserGetSubStateProgressId(s->alproto, sub_state, h, STREAM_TOSERVER);
1454  if (progress_ts >= 0) {
1455  s->flags |= SIG_FLAG_TOSERVER;
1456  s->init_data->hook = SetAppHook(s->alproto, sub_state, progress_ts);
1457  } else {
1458  const int8_t progress_tc = AppLayerParserGetSubStateProgressId(
1459  s->alproto, sub_state, h, STREAM_TOCLIENT);
1460  if (progress_tc < 0) {
1461  return -1;
1462  }
1463  s->flags |= SIG_FLAG_TOCLIENT;
1464  s->init_data->hook = SetAppHook(s->alproto, sub_state, progress_tc);
1465  }
1466  }
1467  snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:%s:%s:generic", p, t, h);
1468  } else {
1470  SCLogError(
1471  "protocol %s requires a substate specification: %s:<sub_state>:%s", p, p, hook);
1472  return -1;
1473  }
1474 
1475  /* FW hook LTE mode */
1476  if (*h == '<') {
1477  h++;
1478  SCLogDebug("hook and prior hooks: '%s'", h);
1480  }
1481  SCLogDebug("h:'%s'", h);
1482  if (strcmp(h, "request_started") == 0) {
1483  s->flags |= SIG_FLAG_TOSERVER;
1484  s->init_data->hook = SetAppHook(s->alproto, sub_state,
1485  0); // state 0 should be the starting state in each protocol.
1486  } else if (strcmp(h, "response_started") == 0) {
1487  s->flags |= SIG_FLAG_TOCLIENT;
1488  s->init_data->hook = SetAppHook(s->alproto, sub_state,
1489  0); // state 0 should be the starting state in each protocol.
1490  } else if (strcmp(h, "request_complete") == 0) {
1491  s->flags |= SIG_FLAG_TOSERVER;
1492  s->init_data->hook = SetAppHook(s->alproto, sub_state,
1494  } else if (strcmp(h, "response_complete") == 0) {
1495  s->flags |= SIG_FLAG_TOCLIENT;
1496  s->init_data->hook = SetAppHook(s->alproto, sub_state,
1498  } else {
1499  const int progress_ts = AppLayerParserGetStateIdByName(
1500  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
1501  if (progress_ts >= 0) {
1502  if (progress_ts >= APP_LAYER_MAX_PROGRESS) {
1503  return -1;
1504  }
1505  s->flags |= SIG_FLAG_TOSERVER;
1506  s->init_data->hook = SetAppHook(s->alproto, sub_state, (uint8_t)progress_ts);
1507  } else {
1508  const int progress_tc = AppLayerParserGetStateIdByName(
1509  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
1510  if (progress_tc < 0 || progress_tc >= APP_LAYER_MAX_PROGRESS) {
1511  return -1;
1512  }
1513  s->flags |= SIG_FLAG_TOCLIENT;
1514  s->init_data->hook = SetAppHook(s->alproto, sub_state, (uint8_t)progress_tc);
1515  }
1516  }
1517  snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:%s:generic", p, h);
1518  }
1519  SCLogDebug("generic_hook_name %s", generic_hook_name);
1520 
1521  int list = DetectBufferTypeGetByName(generic_hook_name);
1522  if (list < 0) {
1523  SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
1524  return -1;
1525  }
1526  s->init_data->hook.sm_list = list;
1527 
1528  SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
1529  SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
1530  s->init_data->hook.t.app.app_progress);
1531 
1532  s->app_progress_hook = s->init_data->hook.t.app.app_progress;
1533  return 0;
1534 }
1535 
1537 {
1538  printf("=========Supported Rule Protocols=========\n");
1541 }
1542 
1543 /**
1544  * \brief Parses the protocol supplied by the Signature.
1545  *
1546  * http://www.iana.org/assignments/protocol-numbers
1547  *
1548  * \param s Pointer to the Signature instance to which the parsed
1549  * protocol has to be added.
1550  * \param protostr Pointer to the character string containing the protocol name.
1551  *
1552  * \retval 0 On successfully parsing the protocol sent as the argument.
1553  * \retval -1 On failure
1554  */
1555 static int SigParseProto(Signature *s, const char *protostr)
1556 {
1557  SCEnter();
1558  if (strlen(protostr) >= 64)
1559  return -1;
1560 
1561  char proto[64];
1562  strlcpy(proto, protostr, sizeof(proto));
1563  const char *p = proto;
1564  const char *h = NULL;
1565 
1566  bool has_hook = strchr(proto, ':') != NULL;
1567  if (has_hook) {
1568  char *rem = NULL;
1569  p = strtok_r(proto, ":", &rem);
1570  h = rem;
1571  SCLogDebug("p: '%s' h: '%s'", p, h);
1572  }
1573  if (p == NULL || strlen(p) == 0) {
1574  SCLogError("invalid protocol specification '%s'", proto);
1575  return -1;
1576  }
1577 
1578  int r = DetectProtoParse(&s->init_data->proto, (char *)p);
1579  if (r < 0) {
1581  /* indicate that the signature is app-layer */
1582  if (s->alproto != ALPROTO_UNKNOWN) {
1583  s->flags |= SIG_FLAG_APPLAYER;
1584 
1586 
1587  if (h) {
1588  if (strlen(h) == 0) {
1589  SCLogError("invalid protocol specification '%s'", proto);
1590  return -1;
1591  }
1592  if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
1593  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1594  SCReturnInt(-1);
1595  }
1596  }
1597  }
1598  else {
1599  SCLogError("protocol \"%s\" cannot be used "
1600  "in a signature. Either detection for this protocol "
1601  "is not yet supported OR detection has been disabled for "
1602  "protocol through the yaml option "
1603  "app-layer.protocols.%s.detection-enabled",
1604  p, p);
1605  SCReturnInt(-1);
1606  }
1607  } else if (h != NULL) {
1608  SCLogDebug("non-app-layer rule with %s:%s", p, h);
1609 
1610  if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
1611  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1612  SCReturnInt(-1);
1613  }
1614  }
1615 
1616  /* if any of these flags are set they are set in a mutually exclusive
1617  * manner */
1620  } else if (s->init_data->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1622  }
1623 
1624  SCReturnInt(0);
1625 }
1626 
1627 /**
1628  * \brief Parses the port(source or destination) field, from a Signature.
1629  *
1630  * \param s Pointer to the signature which has to be updated with the
1631  * port information.
1632  * \param portstr Pointer to the character string containing the port info.
1633  * \param Flag which indicates if the portstr received is src or dst
1634  * port. For src port: flag = 0, dst port: flag = 1.
1635  *
1636  * \retval 0 On success.
1637  * \retval -1 On failure.
1638  */
1639 static int SigParsePort(const DetectEngineCtx *de_ctx,
1640  Signature *s, const char *portstr, char flag)
1641 {
1642  int r = 0;
1643 
1644  /* XXX VJ exclude handling this for none UDP/TCP proto's */
1645 
1646  SCLogDebug("Port group \"%s\" to be parsed", portstr);
1647 
1648  if (flag == 0) {
1649  if (strcasecmp(portstr, "any") == 0)
1650  s->flags |= SIG_FLAG_SP_ANY;
1651 
1652  r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1653  } else if (flag == 1) {
1654  if (strcasecmp(portstr, "any") == 0)
1655  s->flags |= SIG_FLAG_DP_ANY;
1656 
1657  r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1658  }
1659 
1660  if (r < 0)
1661  return -1;
1662 
1663  return 0;
1664 }
1665 
1666 /** \retval 1 valid
1667  * \retval 0 invalid
1668  */
1669 static int SigParseActionRejectValidate(const char *action)
1670 {
1671 #ifdef HAVE_LIBNET11
1672 #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1673  if (sc_set_caps) {
1674  SCLogError("Libnet 1.1 is "
1675  "incompatible with POSIX based capabilities with privs dropping. "
1676  "For rejects to work, run as root/super user.");
1677  return 0;
1678  }
1679 #endif
1680 #else /* no libnet 1.1 */
1681  SCLogError("Libnet 1.1.x is "
1682  "required for action \"%s\" but is not compiled into Suricata",
1683  action);
1684  return 0;
1685 #endif
1686  return 1;
1687 }
1688 
1689 /** \retval 0 on error
1690  * \retval flags on success
1691  */
1692 static uint8_t ActionStringToFlags(const char *action)
1693 {
1694  if (strcasecmp(action, "alert") == 0) {
1695  return ACTION_ALERT;
1696  } else if (strcasecmp(action, "drop") == 0) {
1697  return ACTION_DROP | ACTION_ALERT;
1698  } else if (strcasecmp(action, "pass") == 0) {
1699  return ACTION_PASS;
1700  } else if (strcasecmp(action, "reject") == 0 ||
1701  strcasecmp(action, "rejectsrc") == 0)
1702  {
1703  if (!(SigParseActionRejectValidate(action)))
1704  return 0;
1706  } else if (strcasecmp(action, "rejectdst") == 0) {
1707  if (!(SigParseActionRejectValidate(action)))
1708  return 0;
1710  } else if (strcasecmp(action, "rejectboth") == 0) {
1711  if (!(SigParseActionRejectValidate(action)))
1712  return 0;
1714  } else if (strcasecmp(action, "config") == 0) {
1715  return ACTION_CONFIG;
1716  } else if (strcasecmp(action, "accept") == 0) {
1717  return ACTION_ACCEPT;
1718  } else {
1719  SCLogError("An invalid action \"%s\" was given", action);
1720  return 0;
1721  }
1722 }
1723 
1724 /**
1725  * \brief Parses the action that has been used by the Signature and allots it
1726  * to its Signature instance.
1727  *
1728  * \param s Pointer to the Signature instance to which the action belongs.
1729  * \param action_in Pointer to the action string used by the Signature.
1730  *
1731  * \retval 0 On successfully parsing the action string and adding it to the
1732  * Signature.
1733  * \retval -1 On failure.
1734  */
1735 static int SigParseActionDo(const char *action_in, const int idx, const bool fw_rule,
1736  uint8_t *action_out, uint8_t *scope_out)
1737 {
1738  char action[32];
1739  strlcpy(action, action_in, sizeof(action));
1740  const char *a = action;
1741  const char *o = NULL;
1742 
1743  bool has_scope = strchr(action, ':') != NULL;
1744  if (has_scope) {
1745  char *xsaveptr = NULL;
1746  a = strtok_r(action, ":", &xsaveptr);
1747  o = strtok_r(NULL, ":", &xsaveptr);
1748  SCLogDebug("a: '%s' o: '%s'", a, o);
1749  }
1750  if (a == NULL) {
1751  SCLogError("invalid protocol specification '%s'", action_in);
1752  return -1;
1753  }
1754 
1755  uint8_t flags = ActionStringToFlags(a);
1756  if (flags == 0)
1757  return -1;
1758 
1759  if (fw_rule) {
1760  /* in firewall mode, drop is just drop. Whereas in IDS/IPS mode, drop is drop+alert.
1761  * Same for reject which includes ACTION_DROP. */
1762  if (flags & ACTION_DROP) {
1763  flags &= ~ACTION_ALERT;
1764  }
1765 
1766  if (idx == 0 &&
1768  SCLogError("only accept, config, drop and reject actions allowed as primary action "
1769  "firewall "
1770  "rules");
1771  return -1;
1772  }
1773  if (idx > 0 &&
1775  SCLogError("accept, config, drop and reject actions not allowed as secondary action "
1776  "firewall "
1777  "rules");
1778  return -1;
1779  }
1780  }
1781 
1782  /* parse scope, if any */
1783  if (o) {
1784  uint8_t scope_flags = 0;
1785  if (flags & (ACTION_DROP | ACTION_PASS)) {
1786  if (strcmp(o, "packet") == 0) {
1787  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1788  } else if (strcmp(o, "flow") == 0) {
1789  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1790  } else {
1791  SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1792  "allowed",
1793  o, action_in);
1794  return -1;
1795  }
1796  } else if (flags & (ACTION_ACCEPT)) {
1797  if (strcmp(o, "packet") == 0) {
1798  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1799  } else if (strcmp(o, "hook") == 0) {
1800  scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1801  } else if (strcmp(o, "tx") == 0) {
1802  scope_flags = (uint8_t)ACTION_SCOPE_TX;
1803  } else if (strcmp(o, "flow") == 0) {
1804  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1805  } else {
1806  SCLogError(
1807  "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1808  "'hook' allowed",
1809  o, action_in);
1810  return -1;
1811  }
1812  } else if (flags & (ACTION_CONFIG)) {
1813  if (strcmp(o, "packet") == 0) {
1814  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1815  } else {
1816  SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
1817  action_in);
1818  return -1;
1819  }
1820  } else {
1821  SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1822  "'drop', 'pass' and 'reject'",
1823  o, action_in);
1824  return -1;
1825  }
1826  if (*scope_out != 0 && *scope_out != scope_flags) {
1827  SCLogError("multi-action rules cannot use different action scopes");
1828  return -1;
1829  }
1830  *scope_out = scope_flags;
1831  }
1832 
1833  /* require explicit action scope for fw rules */
1834  if (fw_rule && *scope_out == 0) {
1835  SCLogError("firewall rules require setting an explicit action scope");
1836  return -1;
1837  }
1838 
1839  if (!fw_rule && (flags & ACTION_ACCEPT)) {
1840  SCLogError("'accept' action only supported for firewall rules");
1841  return -1;
1842  }
1843  *action_out |= flags;
1844  return 0;
1845 }
1846 
1847 static int SigParseAction(Signature *s, const char *action_in)
1848 {
1849  /* multi-action rules are only supported for firewall rules at this time. */
1850  if (!s->init_data->firewall_rule)
1851  return SigParseActionDo(action_in, 0, false, &s->action, &s->action_scope);
1852 
1853  int r = 0;
1854  char *copy = SCStrdup(action_in);
1855  if (copy == NULL)
1856  FatalError("could not duplicate opt string");
1857 
1858  int i = 0;
1859  char *xsaveptr = NULL;
1860  char *a = strtok_r(copy, ",", &xsaveptr);
1861  while (a != NULL) {
1862  if (SigParseActionDo(a, i, true, &s->action, &s->action_scope) < 0) {
1863  r = -1;
1864  break;
1865  }
1866  a = strtok_r(NULL, ",", &xsaveptr);
1867  i++;
1868  }
1869 
1870  SCFree(copy);
1871 
1872  SCLogDebug("s->action %02x", s->action);
1873  return r;
1874 }
1875 
1876 /**
1877  * \brief Parse the next token in rule.
1878  *
1879  * For rule parsing a token is considered to be a string of characters
1880  * separated by white space.
1881  *
1882  * \param input double pointer to input buffer, will be advanced as input is
1883  * parsed.
1884  * \param output buffer to copy token into.
1885  * \param output_size length of output buffer.
1886  */
1887 static inline int SigParseToken(char **input, char *output,
1888  const size_t output_size)
1889 {
1890  size_t len = *input == NULL ? 0 : strlen(*input);
1891 
1892  if (!len) {
1893  return 0;
1894  }
1895 
1896  while (len && isblank(**input)) {
1897  (*input)++;
1898  len--;
1899  }
1900 
1901  char *endptr = strpbrk(*input, " \t\n\r");
1902  if (endptr != NULL) {
1903  *(endptr++) = '\0';
1904  }
1905  strlcpy(output, *input, output_size);
1906  *input = endptr;
1907 
1908  return 1;
1909 }
1910 
1911 /**
1912  * \brief Parse the next rule "list" token.
1913  *
1914  * Parses rule tokens that may be lists such as addresses and ports
1915  * handling the case when they may not be lists.
1916  *
1917  * \param input double pointer to input buffer, will be advanced as input is
1918  * parsed.
1919  * \param output buffer to copy token into.
1920  * \param output_size length of output buffer.
1921  */
1922 static inline int SigParseList(char **input, char *output,
1923  const size_t output_size)
1924 {
1925  int in_list = 0;
1926  size_t len = *input != NULL ? strlen(*input) : 0;
1927 
1928  if (len == 0) {
1929  return 0;
1930  }
1931 
1932  while (len && isblank(**input)) {
1933  (*input)++;
1934  len--;
1935  }
1936 
1937  size_t i = 0;
1938  for (i = 0; i < len; i++) {
1939  char c = (*input)[i];
1940  if (c == '[') {
1941  in_list++;
1942  } else if (c == ']') {
1943  in_list--;
1944  } else if (c == ' ') {
1945  if (!in_list) {
1946  break;
1947  }
1948  }
1949  }
1950  if (i == len) {
1951  *input = NULL;
1952  return 0;
1953  }
1954  (*input)[i] = '\0';
1955  strlcpy(output, *input, output_size);
1956  *input = *input + i + 1;
1957 
1958  return 1;
1959 }
1960 
1961 /**
1962  * \internal
1963  * \brief split a signature string into a few blocks for further parsing
1964  *
1965  * \param scan_only just scan, don't validate
1966  */
1967 static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1968  SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1969 {
1970  char *index, dup[DETECT_MAX_RULE_SIZE];
1971 
1972  strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1973  index = dup;
1974 
1975  /* Action. */
1976  SigParseToken(&index, parser->action, sizeof(parser->action));
1977 
1978  /* Protocol. */
1979  SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1980 
1981  /* Source. */
1982  SigParseList(&index, parser->src, sizeof(parser->src));
1983 
1984  /* Source port(s). */
1985  SigParseList(&index, parser->sp, sizeof(parser->sp));
1986 
1987  /* Direction. */
1988  SigParseToken(&index, parser->direction, sizeof(parser->direction));
1989 
1990  /* Destination. */
1991  SigParseList(&index, parser->dst, sizeof(parser->dst));
1992 
1993  /* Destination port(s). */
1994  SigParseList(&index, parser->dp, sizeof(parser->dp));
1995 
1996  /* Options. */
1997  if (index == NULL) {
1998  SCLogError("no rule options.");
1999  goto error;
2000  }
2001  while (isspace(*index) || *index == '(') {
2002  index++;
2003  }
2004  for (size_t i = strlen(index); i > 0; i--) {
2005  if (isspace(index[i - 1]) || index[i - 1] == ')') {
2006  index[i - 1] = '\0';
2007  } else {
2008  break;
2009  }
2010  }
2011  strlcpy(parser->opts, index, sizeof(parser->opts));
2012 
2013  if (scan_only) {
2014  return 0;
2015  }
2016 
2017  /* Parse Action */
2018  if (SigParseAction(s, parser->action) < 0)
2019  goto error;
2020 
2021  if (SigParseProto(s, parser->protocol) < 0)
2022  goto error;
2023 
2024  if (strcmp(parser->direction, "<>") == 0) {
2026  } else if (strcmp(parser->direction, "=>") == 0) {
2027  if (s->flags & SIG_FLAG_FIREWALL) {
2028  SCLogError("transactional bidirectional rules not supported for firewall rules");
2029  goto error;
2030  }
2031 
2032  s->flags |= SIG_FLAG_TXBOTHDIR;
2033  } else if (strcmp(parser->direction, "->") != 0) {
2034  SCLogError("\"%s\" is not a valid direction modifier, "
2035  "\"->\" and \"<>\" are supported.",
2036  parser->direction);
2037  goto error;
2038  }
2039 
2040  /* Parse Address & Ports */
2041  if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
2042  goto error;
2043 
2044  if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
2045  goto error;
2046 
2047  /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
2048  * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
2049  * changes that we made sees to it that at this point of time we don't
2050  * set the ip proto for the sig. We do it a bit later. */
2051  if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
2052  goto error;
2053  if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
2054  goto error;
2055 
2056  return 0;
2057 
2058 error:
2059  return -1;
2060 }
2061 
2062 static inline bool CheckAscii(const char *str)
2063 {
2064  for (size_t i = 0; i < strlen(str); i++) {
2065  if (str[i] < 0x20) {
2066  // LF CR TAB
2067  if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
2068  continue;
2069  }
2070  return false;
2071  } else if (str[i] == 0x7f) {
2072  return false;
2073  }
2074  }
2075  return true;
2076 }
2077 
2078 /**
2079  * \brief parse a signature
2080  *
2081  * \param de_ctx detection engine ctx to add it to
2082  * \param s memory structure to store the signature in
2083  * \param sigstr the raw signature as a null terminated string
2084  * \param addrs_direction direction (for bi-directional sigs)
2085  * \param require only scan rule for requires
2086  *
2087  * \param -1 parse error
2088  * \param 0 ok
2089  */
2090 static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
2091  uint8_t addrs_direction, SignatureParser *parser, bool requires)
2092 {
2093  SCEnter();
2094 
2095  if (!SCCheckUtf8(sigstr)) {
2096  SCLogError("rule is not valid UTF-8");
2097  SCReturnInt(-1);
2098  }
2099 
2100  if (!CheckAscii(sigstr)) {
2101  SCLogError("rule contains invalid (control) characters");
2102  SCReturnInt(-1);
2103  }
2104 
2105  int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
2106  if (ret < 0) {
2107  SCLogDebug("SigParseBasics failed");
2108  SCReturnInt(-1);
2109  }
2110 
2111  /* we can have no options, so make sure we have them */
2112  if (strlen(parser->opts) > 0) {
2113  size_t buffer_size = strlen(parser->opts) + 1;
2115  char input[buffer_size];
2116  char output[buffer_size];
2117  memset(input, 0x00, buffer_size);
2118  memcpy(input, parser->opts, strlen(parser->opts) + 1);
2119 
2120  /* loop the option parsing. Each run processes one option
2121  * and returns the rest of the option string through the
2122  * output variable. */
2123  do {
2124  memset(output, 0x00, buffer_size);
2125  ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
2126  if (ret == 1) {
2127  memcpy(input, output, buffer_size);
2128  }
2129 
2130  } while (ret == 1);
2131 
2132  if (ret < 0) {
2133  /* Suricata didn't meet the rule requirements, skip. */
2134  goto end;
2135  }
2136  }
2137 
2138 end:
2140 
2141  SCReturnInt(ret);
2142 }
2143 
2144 /** \brief check if buffers array still has space left, expand if not
2145  */
2147 {
2148  if (s->init_data->buffers_size >= 64)
2149  return -1;
2150 
2151  if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
2152  void *ptr = SCRealloc(s->init_data->buffers,
2153  (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
2154  if (ptr == NULL)
2155  return -1;
2156  s->init_data->buffers = ptr;
2157  for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
2159  memset(b, 0, sizeof(*b));
2160  }
2161  s->init_data->buffers_size += 8;
2162  }
2163  return 0;
2164 }
2165 
2167 {
2168  Signature *sig = SCCalloc(1, sizeof(Signature));
2169  if (unlikely(sig == NULL))
2170  return NULL;
2171 
2172  sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
2173  if (sig->init_data == NULL) {
2174  SCFree(sig);
2175  return NULL;
2176  }
2177  sig->init_data->mpm_sm_list = -1;
2178 
2179  sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
2180  if (sig->init_data->buffers == NULL) {
2181  SCFree(sig->init_data);
2182  SCFree(sig);
2183  return NULL;
2184  }
2185  sig->init_data->buffers_size = 8;
2186 
2187  /* assign it to -1, so that we can later check if the value has been
2188  * overwritten after the Signature has been parsed, and if it hasn't been
2189  * overwritten, we can then assign the default value of 3 */
2190  sig->prio = -1;
2191 
2192  /* rule interdepency is false, at start */
2193  sig->init_data->is_rule_state_dependant = false;
2194  /* first index is 0 */
2196 
2198  return sig;
2199 }
2200 
2201 /**
2202  * \internal
2203  * \brief Free Metadata list
2204  *
2205  * \param s Pointer to the signature
2206  */
2207 static void SigMetadataFree(Signature *s)
2208 {
2209  SCEnter();
2210 
2211  DetectMetadata *mdata = NULL;
2212  DetectMetadata *next_mdata = NULL;
2213 
2214  if (s == NULL || s->metadata == NULL) {
2215  SCReturn;
2216  }
2217 
2218  SCLogDebug("s %p, s->metadata %p", s, s->metadata);
2219 
2220  for (mdata = s->metadata->list; mdata != NULL;) {
2221  next_mdata = mdata->next;
2222  DetectMetadataFree(mdata);
2223  mdata = next_mdata;
2224  }
2225  SCFree(s->metadata->json_str);
2226  SCFree(s->metadata);
2227  s->metadata = NULL;
2228 
2229  SCReturn;
2230 }
2231 
2232 /**
2233  * \internal
2234  * \brief Free Reference list
2235  *
2236  * \param s Pointer to the signature
2237  */
2238 static void SigRefFree (Signature *s)
2239 {
2240  SCEnter();
2241 
2242  DetectReference *ref = NULL;
2243  DetectReference *next_ref = NULL;
2244 
2245  if (s == NULL) {
2246  SCReturn;
2247  }
2248 
2249  SCLogDebug("s %p, s->references %p", s, s->references);
2250 
2251  for (ref = s->references; ref != NULL;) {
2252  next_ref = ref->next;
2253  DetectReferenceFree(ref);
2254  ref = next_ref;
2255  }
2256 
2257  s->references = NULL;
2258 
2259  SCReturn;
2260 }
2261 
2262 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2263 {
2264  if (s != NULL) {
2265  int type;
2266  for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2267  if (s->sm_arrays[type] != NULL) {
2268  if (ctxs) {
2269  SigMatchData *smd = s->sm_arrays[type];
2270  while(1) {
2271  if (sigmatch_table[smd->type].Free != NULL) {
2272  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2273  }
2274  if (smd->is_last)
2275  break;
2276  smd++;
2277  }
2278  }
2279 
2280  SCFree(s->sm_arrays[type]);
2281  }
2282  }
2283  }
2284 }
2285 
2287 {
2288  if (s == NULL)
2289  return;
2290 
2291  int i;
2292 
2293  if (s->init_data && s->init_data->transforms.cnt) {
2294  for(i = 0; i < s->init_data->transforms.cnt; i++) {
2295  if (s->init_data->transforms.transforms[i].options) {
2296  int transform = s->init_data->transforms.transforms[i].transform;
2297  sigmatch_table[transform].Free(
2299  s->init_data->transforms.transforms[i].options = NULL;
2300  }
2301  }
2302  }
2303  if (s->init_data) {
2304  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2305  SigMatch *sm = s->init_data->smlists[i];
2306  while (sm != NULL) {
2307  SigMatch *nsm = sm->next;
2308  SigMatchFree(de_ctx, sm);
2309  sm = nsm;
2310  }
2311  }
2312 
2313  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2314  SigMatch *sm = s->init_data->buffers[x].head;
2315  while (sm != NULL) {
2316  SigMatch *nsm = sm->next;
2317  SigMatchFree(de_ctx, sm);
2318  sm = nsm;
2319  }
2320  }
2321  if (s->init_data->cidr_dst != NULL)
2323 
2324  if (s->init_data->cidr_src != NULL)
2326 
2327  SCFree(s->init_data->buffers);
2328  s->init_data->buffers = NULL;
2329  }
2330  SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2331  if (s->init_data) {
2332  SCFree(s->init_data);
2333  s->init_data = NULL;
2334  }
2335 
2336  if (s->sp != NULL) {
2337  DetectPortCleanupList(NULL, s->sp);
2338  }
2339  if (s->dp != NULL) {
2340  DetectPortCleanupList(NULL, s->dp);
2341  }
2342  if (s->proto) {
2343  SCFree(s->proto);
2344  }
2345 
2346  if (s->msg != NULL)
2347  SCFree(s->msg);
2348 
2349  if (s->addr_src_match4 != NULL) {
2350  SCFree(s->addr_src_match4);
2351  }
2352  if (s->addr_dst_match4 != NULL) {
2353  SCFree(s->addr_dst_match4);
2354  }
2355  if (s->addr_src_match6 != NULL) {
2356  SCFree(s->addr_src_match6);
2357  }
2358  if (s->addr_dst_match6 != NULL) {
2359  SCFree(s->addr_dst_match6);
2360  }
2361  if (s->sig_str != NULL) {
2362  SCFree(s->sig_str);
2363  }
2364 
2365  SigRefFree(s);
2366  SigMetadataFree(s);
2367 
2369 
2370  SCFree(s);
2371 }
2372 
2373 /**
2374  * \brief this function is used to set multiple possible app-layer protos
2375  * \brief into the current signature (for example ja4 for both tls and quic)
2376  *
2377  * \param s pointer to the Current Signature
2378  * \param alprotos an array terminated by ALPROTO_UNKNOWN
2379  *
2380  * \retval 0 on Success
2381  * \retval -1 on Failure
2382  */
2384 {
2385  if (s->alproto != ALPROTO_UNKNOWN) {
2386  // One alproto was set, check if it matches the new ones proposed
2387  while (*alprotos != ALPROTO_UNKNOWN) {
2388  if (s->alproto == *alprotos) {
2389  // alproto already set to only one
2390  return 0;
2391  }
2392  alprotos++;
2393  }
2394  // alproto already set and not matching the new set of alprotos
2395  return -1;
2396  }
2397  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2398  // check intersection of already used alprotos and new ones
2399  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2400  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2401  break;
2402  }
2403  // first disable the ones that do not match
2404  bool found = false;
2405  const AppProto *args = alprotos;
2406  while (*args != ALPROTO_UNKNOWN) {
2407  if (s->init_data->alprotos[i] == *args) {
2408  found = true;
2409  break;
2410  }
2411  args++;
2412  }
2413  if (!found) {
2415  }
2416  }
2417  // Then put at the beginning every defined protocol
2418  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2419  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2420  for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2421  if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2422  s->init_data->alprotos[i] = s->init_data->alprotos[j];
2424  break;
2425  }
2426  }
2427  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2428  if (i == 0) {
2429  // there was no intersection
2430  return -1;
2431  } else if (i == 1) {
2432  // intersection is singleton, set it as usual
2433  AppProto alproto = s->init_data->alprotos[0];
2435  return SCDetectSignatureSetAppProto(s, alproto);
2436  }
2437  break;
2438  }
2439  }
2440  }
2441  } else {
2442  if (alprotos[0] == ALPROTO_UNKNOWN) {
2443  // do not allow empty set
2444  return -1;
2445  }
2446  if (alprotos[1] == ALPROTO_UNKNOWN) {
2447  // allow singleton, but call traditional setter
2448  return SCDetectSignatureSetAppProto(s, alprotos[0]);
2449  }
2450  // first time we enforce alprotos
2451  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2452  if (alprotos[i] == ALPROTO_UNKNOWN) {
2453  break;
2454  }
2455  s->init_data->alprotos[i] = alprotos[i];
2456  }
2457  }
2458  return 0;
2459 }
2460 
2462 {
2463  if (!AppProtoIsValid(alproto)) {
2464  SCLogError("invalid alproto %u", alproto);
2465  return -1;
2466  }
2467 
2468  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2469  // Multiple alprotos were set, check if we restrict to one
2470  bool found = false;
2471  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2472  if (s->init_data->alprotos[i] == alproto) {
2473  found = true;
2474  break;
2475  }
2476  }
2477  if (!found) {
2478  // fail if we set to a alproto which was not in the set
2479  return -1;
2480  }
2481  // we will use s->alproto if there is a single alproto and
2482  // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2484  }
2485 
2486  if (s->alproto != ALPROTO_UNKNOWN) {
2487  alproto = AppProtoCommon(s->alproto, alproto);
2488  if (alproto == ALPROTO_FAILED) {
2489  SCLogError("can't set rule app proto to %s: already set to %s",
2490  AppProtoToString(alproto), AppProtoToString(s->alproto));
2491  return -1;
2492  }
2493  }
2494 
2495  if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2496  SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2497  return -1;
2498  }
2499  s->alproto = alproto;
2500  s->flags |= SIG_FLAG_APPLAYER;
2501  return 0;
2502 }
2503 
2504 static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2505  const DetectAddress *head, uint16_t *match4_cnt)
2506 {
2507  uint16_t cnt = 0;
2508 
2509  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2510  cnt++;
2511  }
2512  if (cnt == 0) {
2513  return NULL;
2514  }
2515  DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2516  if (addr_match4 == NULL) {
2517  return NULL;
2518  }
2519 
2520  uint16_t idx = 0;
2521  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2522  addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2523  addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2524  idx++;
2525  }
2526  *match4_cnt = cnt;
2527  return addr_match4;
2528 }
2529 
2530 static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2531  const DetectAddress *head, uint16_t *match6_cnt)
2532 {
2533  uint16_t cnt = 0;
2534  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2535  cnt++;
2536  }
2537  if (cnt == 0) {
2538  return NULL;
2539  }
2540 
2541  DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2542  if (addr_match6 == NULL) {
2543  return NULL;
2544  }
2545 
2546  uint16_t idx = 0;
2547  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2548  addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2549  addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2550  addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2551  addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2552  addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2553  addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2554  addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2555  addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2556  idx++;
2557  }
2558  *match6_cnt = cnt;
2559  return addr_match6;
2560 }
2561 
2562 /**
2563  * \internal
2564  * \brief build address match array for cache efficient matching
2565  *
2566  * \param s the signature
2567  */
2568 static void SigBuildAddressMatchArray(Signature *s)
2569 {
2570  /* source addresses */
2571  s->addr_src_match4 =
2572  SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2573  /* destination addresses */
2574  s->addr_dst_match4 =
2575  SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2576 
2577  /* source addresses IPv6 */
2578  s->addr_src_match6 =
2579  SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2580  /* destination addresses IPv6 */
2581  s->addr_dst_match6 =
2582  SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2583 }
2584 
2585 static int SigMatchListLen(SigMatch *sm)
2586 {
2587  int len = 0;
2588  for (; sm != NULL; sm = sm->next)
2589  len++;
2590 
2591  return len;
2592 }
2593 
2594 /** \brief convert SigMatch list to SigMatchData array
2595  * \note ownership of sm->ctx is transferred to smd->ctx
2596  */
2598 {
2599  int len = SigMatchListLen(head);
2600  if (len == 0)
2601  return NULL;
2602 
2603  SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
2604  if (smd == NULL) {
2605  FatalError("initializing the detection engine failed");
2606  }
2607  SigMatchData *out = smd;
2608 
2609  /* Copy sm type and Context into array */
2610  SigMatch *sm = head;
2611  for (; sm != NULL; sm = sm->next, smd++) {
2612  smd->type = sm->type;
2613  smd->ctx = sm->ctx;
2614  sm->ctx = NULL; // SigMatch no longer owns the ctx
2615  smd->is_last = (sm->next == NULL);
2616  }
2617  return out;
2618 }
2619 
2620 extern int g_skip_prefilter;
2621 
2622 static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2623 {
2624  SCEnter();
2625  SCLogDebug("s %u: set up prefilter/mpm", s->id);
2626  DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
2627 
2628  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
2629  SCLogDebug("no prefilter for SIG_FLAG_FW_HOOK_LTE sig");
2630  SCReturn;
2631  }
2632 
2633  if (s->init_data->prefilter_sm != NULL) {
2634  if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
2636  if (s->init_data->mpm_sm != NULL) {
2637  s->flags |= SIG_FLAG_PREFILTER;
2638  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2639  SCReturn;
2640  }
2641  /* fall through, this can happen if the mpm doesn't support the pattern */
2642  } else {
2643  s->flags |= SIG_FLAG_PREFILTER;
2644  SCReturn;
2645  }
2646  } else {
2647  SCLogDebug("%u: RetrieveFPForSig", s->id);
2649  if (s->init_data->mpm_sm != NULL) {
2650  s->flags |= SIG_FLAG_PREFILTER;
2651  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2652  SCReturn;
2653  }
2654  }
2655 
2656  SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2657  "s->init_data->has_possible_prefilter %s",
2659 
2661  SCReturn;
2662 
2665  int prefilter_list = DETECT_TBLSIZE;
2666  /* get the keyword supporting prefilter with the lowest type */
2667  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2668  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2669  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2670  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
2671  prefilter_list = MIN(prefilter_list, sm->type);
2672  }
2673  }
2674  }
2675  }
2676 
2677  /* apply that keyword as prefilter */
2678  if (prefilter_list != DETECT_TBLSIZE) {
2679  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2680  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2681  if (sm->type == prefilter_list) {
2682  s->init_data->prefilter_sm = sm;
2683  s->flags |= SIG_FLAG_PREFILTER;
2684  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2685  sigmatch_table[sm->type].name);
2686  break;
2687  }
2688  }
2689  }
2690  }
2691  }
2692  SCReturn;
2693 }
2694 
2695 /** \internal
2696  * \brief check if signature's table requirement is supported by each of the keywords it uses.
2697  */
2698 static bool DetectRuleValidateTable(const Signature *s)
2699 {
2700  if (s->detect_table == 0)
2701  return true;
2702 
2703  const uint8_t table_as_flag = BIT_U8(s->detect_table);
2704 
2705  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
2706  const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
2707  if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
2708  SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
2710  return false;
2711  }
2712  }
2713  return true;
2714 }
2715 
2716 static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2717 {
2719  SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2720  "explicit hook",
2721  s->id);
2722  return false;
2723  }
2725  switch (s->action_scope) {
2726  case ACTION_SCOPE_PACKET:
2727  if (!(DetectProtoContainsProto(&s->init_data->proto, IPPROTO_UDP))) {
2728  if (s->action & (ACTION_ACCEPT | ACTION_DROP)) {
2729  SCLogError("rule %u uses action scope \"packet\" for an non-UDP app hook",
2730  s->id);
2731  return false;
2732  }
2733  }
2734  break;
2735  case ACTION_SCOPE_FLOW:
2736  case ACTION_SCOPE_AUTO:
2737  case ACTION_SCOPE_TX:
2738  case ACTION_SCOPE_HOOK:
2739  // supported for app hooks
2740  break;
2741  }
2742  }
2743  if (s->flags & SIG_FLAG_FW_HOOK_LTE) {
2744  if (!(((s->action & ACTION_ACCEPT) != 0) &&
2746  s->action_scope == ACTION_SCOPE_HOOK))) {
2747  SCLogError("rule %u: auto-accept notation (<hook) can only be used with accept:flow, "
2748  "accept:tx and accept:hook",
2749  s->id);
2750  return false;
2751  }
2752  }
2753 
2754  return true;
2755 }
2756 
2757 static void DetectRuleSetTable(Signature *s)
2758 {
2759  enum DetectTable table;
2760  if (s->flags & SIG_FLAG_FIREWALL) {
2761  if (s->type == SIG_TYPE_PKT) {
2765  else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
2768  else
2770  } else if (s->type == SIG_TYPE_APP_TX) {
2771  table = DETECT_TABLE_APP_FILTER;
2772  } else {
2773  BUG_ON(1);
2774  }
2775  } else {
2776  // TODO pre_flow/pre_stream
2777  if (s->type != SIG_TYPE_APP_TX) {
2778  table = DETECT_TABLE_PACKET_TD;
2779  } else {
2780  table = DETECT_TABLE_APP_TD;
2781  }
2782  }
2783 
2784  s->detect_table = (uint8_t)table;
2785 }
2786 
2787 static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2788 {
2789  if (s->init_data->firewall_rule) {
2790  if (!DetectFirewallRuleValidate(de_ctx, s))
2791  SCReturnInt(0);
2792  }
2793  SCReturnInt(1);
2794 }
2795 
2796 static int SigValidateCheckBuffers(
2797  DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2798 {
2799  bool has_frame = false;
2800  bool has_app = false;
2801  bool has_pkt = false;
2802  bool has_pmatch = false;
2803 
2804  int nlists = 0;
2805  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2806  nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2807  }
2808  nlists += (nlists > 0);
2809  SCLogDebug("nlists %d", nlists);
2810 
2811  if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2812  SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2814  SCReturnInt(0);
2815  }
2816 
2817  /* run buffer type validation callbacks if any */
2820  SCReturnInt(0);
2821 
2822  has_pmatch = true;
2823  }
2824 
2825  DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
2826  struct BufferVsDir {
2827  int ts;
2828  int tc;
2829  } bufdir[nlists + 1];
2830  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2831 
2832  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2835  if (bt == NULL) {
2836  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2837  continue;
2838  }
2839  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2840  for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2841  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2842  }
2843 
2844  if (b->head == NULL) {
2845  SCLogError("no matches in sticky buffer %s", bt->name);
2846  SCReturnInt(0);
2847  }
2848 
2849  has_frame |= bt->frame;
2850  has_app |= (!bt->frame && !bt->packet);
2851  has_pkt |= bt->packet;
2852 
2853  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2854  SCLogError("Signature combines packet "
2855  "specific matches (like dsize, flags, ttl) with stream / "
2856  "state matching by matching on app layer proto (like using "
2857  "http_* keywords).");
2858  SCReturnInt(0);
2859  }
2860 
2861  uint32_t app_buffers_evaluated = 0;
2862  bool buffer_consumed = false;
2863  uint32_t buffer_skip_alproto = 0;
2864  uint32_t buffer_skip_substate = 0;
2866  for (; app != NULL; app = app->next) {
2867  if (app->sm_list != b->id)
2868  continue;
2869  app_buffers_evaluated++;
2870 
2872  /* only allow rules to use the hook for engines at that
2873  * exact progress for now. We make an exception for generic
2874  * engines like app-layer-event. */
2875  if (!(AppProtoEqualsStrict(s->alproto, app->alproto) ||
2876  app->alproto == ALPROTO_UNKNOWN)) {
2877  SCLogDebug("%u:%s: for buffer %s skip engine %s alproto %s", s->id,
2878  AppProtoToString(s->alproto), bt->name,
2880  AppProtoToString(app->alproto));
2881  buffer_skip_alproto++;
2882  continue;
2883  }
2884  if (app->alproto != ALPROTO_UNKNOWN &&
2885  app->sub_state != s->init_data->hook.t.app.sub_state) {
2886  buffer_skip_substate++;
2887  continue;
2888  }
2889  } else {
2890  if (!(AppProtoEquals(s->alproto, app->alproto) || s->alproto == ALPROTO_UNKNOWN ||
2891  app->alproto == ALPROTO_UNKNOWN)) {
2892  SCLogDebug("%u:%s: for buffer %s skip engine %s alproto %s", s->id,
2893  AppProtoToString(s->alproto), bt->name,
2895  AppProtoToString(app->alproto));
2896  buffer_skip_alproto++;
2897  continue;
2898  }
2899  }
2900 
2901  SCLogDebug("engine %s dir %d alproto %d",
2903  app->alproto);
2904  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2905 
2906  if (b->only_tc) {
2907  if (app->dir == 1)
2908  (*tc_excl)++;
2909  } else if (b->only_ts) {
2910  if (app->dir == 0)
2911  (*ts_excl)++;
2912  } else {
2913  bufdir[b->id].ts += (app->dir == 0);
2914  bufdir[b->id].tc += (app->dir == 1);
2915  }
2916 
2918  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2919  app->progress != s->init_data->hook.t.app.app_progress) {
2920  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2921  s->init_data->hook.t.app.app_progress);
2922  SCReturnInt(0);
2923  }
2924  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2925  app->progress != s->init_data->hook.t.app.app_progress) {
2926  SCLogError("engine progress value doesn't match hook");
2927  SCReturnInt(0);
2928  }
2929  }
2930 
2931  buffer_consumed = true;
2932  }
2933  if (app_buffers_evaluated && !buffer_consumed) {
2934  SCLogError("incompatible rule conditions, skipped buffer %s, reasons: app proto %u sub "
2935  "state %u",
2936  bt->name, buffer_skip_alproto, buffer_skip_substate);
2937  SCReturnInt(0);
2938  }
2940  SCReturnInt(0);
2941  }
2942 
2944  SCReturnInt(0);
2945  }
2947  SCReturnInt(0);
2948  }
2949  }
2950 
2951  if (has_pmatch && has_frame) {
2952  SCLogError("can't mix pure content and frame inspection");
2953  SCReturnInt(0);
2954  }
2955  if (has_app && has_frame) {
2956  SCLogError("can't mix app-layer buffer and frame inspection");
2957  SCReturnInt(0);
2958  }
2959  if (has_pkt && has_frame) {
2960  SCLogError("can't mix pkt buffer and frame inspection");
2961  SCReturnInt(0);
2962  }
2963 
2964  for (int x = 0; x < nlists; x++) {
2965  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2966  continue;
2967  (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2968  (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2969  (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2970 
2971  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2972  bufdir[x].tc);
2973  }
2974 
2975  SCReturnInt(1);
2976 }
2977 
2978 static int SigValidatePacketStream(const Signature *s)
2979 {
2981  SCLogError("can't mix packet keywords with "
2982  "tcp-stream or flow:only_stream. Invalidating signature.");
2983  SCReturnInt(0);
2984  }
2985  SCReturnInt(1);
2986 }
2987 
2988 static int SigConsolidateDirection(
2989  Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2990 {
2991  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2992  if (!ts_excl || !tc_excl) {
2993  SCLogError("rule %u should use both directions, but does not", s->id);
2994  SCReturnInt(0);
2995  }
2996  if (dir_amb) {
2997  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2998  "directions",
2999  s->id);
3000  SCReturnInt(0);
3001  }
3002  } else if (ts_excl && tc_excl) {
3003  SCLogError(
3004  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
3005  "should be used",
3006  s->id);
3007  SCReturnInt(0);
3008  } else if (ts_excl) {
3009  SCLogDebug("%u: implied rule direction is toserver", s->id);
3011  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
3012  SCReturnInt(0);
3013  }
3014  } else if (tc_excl) {
3015  SCLogDebug("%u: implied rule direction is toclient", s->id);
3017  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
3018  SCReturnInt(0);
3019  }
3020  } else if (dir_amb) {
3021  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
3022  }
3023  SCReturnInt(1);
3024 }
3025 
3026 static void SigConsolidateTcpBuffer(Signature *s)
3027 {
3028  /* TCP: corner cases:
3029  * - pkt vs stream vs depth/offset
3030  * - pkt vs stream vs stream_size
3031  */
3032  if (DetectProtoContainsProto(&s->init_data->proto, IPPROTO_TCP)) {
3036  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
3037  sm = sm->next) {
3038  if (sm->type == DETECT_CONTENT &&
3039  (((DetectContentData *)(sm->ctx))->flags &
3042  break;
3043  }
3044  }
3045  /* if stream_size is in use, also inspect packets */
3046  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
3047  sm = sm->next) {
3048  if (sm->type == DETECT_STREAM_SIZE) {
3050  break;
3051  }
3052  }
3053  }
3054  }
3055  }
3056 }
3057 
3058 static bool SigInspectsFiles(const Signature *s)
3059 {
3060  return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
3062 }
3063 
3064 /** \internal
3065  * \brief validate file handling
3066  * \retval 1 good signature
3067  * \retval 0 bad signature
3068  */
3069 static int SigValidateFileHandling(const Signature *s)
3070 {
3071  if (!SigInspectsFiles(s)) {
3072  SCReturnInt(1);
3073  }
3074 
3075  if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
3076  !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
3077  SCLogError("protocol %s doesn't "
3078  "support file matching",
3080  SCReturnInt(0);
3081  }
3082  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
3083  bool found = false;
3084  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
3085  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
3086  break;
3087  }
3088  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
3089  AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
3090  found = true;
3091  break;
3092  }
3093  }
3094  if (!found) {
3095  SCLogError("No protocol support file matching");
3096  SCReturnInt(0);
3097  }
3098  }
3100  SCLogError("protocol HTTP2 doesn't support file name matching");
3101  SCReturnInt(0);
3102  }
3103  SCReturnInt(1);
3104 }
3105 
3106 static bool SigValidateEthernet(const Signature *s)
3107 {
3109  if ((s->flags & (SIG_FLAG_SP_ANY | SIG_FLAG_DP_ANY)) !=
3111  SCLogError("can't use ports with ether or arp rule");
3112  return false;
3113  }
3114  }
3115  return true;
3116 }
3117 
3118 /* `pkthdr` is meant to allow matching on "any" packet with a decoder event. */
3119 static bool SigValidateProtoPkthdr(const Signature *s)
3120 {
3122  SCLogError("protocol 'pkthdr' is for decoder-events only");
3123  return false;
3124  }
3125  return true;
3126 }
3127 
3128 static bool SigValidateFlowbitUse(DetectEngineCtx *de_ctx, const Signature *s)
3129 {
3131 
3133  SCLogError(
3134  "rule %u: too many flowbits (max %u per signature)", s->id, de_ctx->max_flowbits);
3135  return false;
3136  }
3137 
3138  return true;
3139 }
3140 
3141 /**
3142  * \internal
3143  * \brief validate and consolidate parsed signature
3144  *
3145  * \param de_ctx detect engine
3146  * \param s signature to validate and consolidate
3147  *
3148  * \retval 0 invalid
3149  * \retval 1 valid
3150  */
3151 static int SigValidateConsolidate(
3152  DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
3153 {
3154  SCEnter();
3155 
3156  if (SigValidateFirewall(de_ctx, s) == 0)
3157  SCReturnInt(0);
3158 
3159  if (SigValidatePacketStream(s) == 0) {
3160  SCReturnInt(0);
3161  }
3162 
3163  if (!SigValidateEthernet(s)) {
3164  SCReturnInt(0);
3165  }
3166 
3167  int ts_excl = 0;
3168  int tc_excl = 0;
3169  int dir_amb = 0;
3170 
3171  if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
3172  SCReturnInt(0);
3173  }
3174 
3175  if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
3176  SCReturnInt(0);
3177  }
3178 
3179  SigConsolidateTcpBuffer(s);
3180 
3182  DetectRuleSetTable(s);
3183 
3184  if (!SigValidateProtoPkthdr(s)) {
3185  SCReturnInt(0);
3186  }
3187 
3188  if (!SigValidateFlowbitUse(de_ctx, s)) {
3189  SCReturnInt(0);
3190  }
3191 
3192  if (DetectProtoFinalizeSignature(s) != 0)
3193  SCReturnInt(0);
3194 
3195  int r = SigValidateFileHandling(s);
3196  if (r == 0) {
3197  SCReturnInt(0);
3198  }
3199  if (SigInspectsFiles(s)) {
3200  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
3202  }
3203  }
3204  if (DetectRuleValidateTable(s) == false) {
3205  SCReturnInt(0);
3206  }
3207 
3208  if (s->type == SIG_TYPE_IPONLY) {
3209  /* For IPOnly */
3210  if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
3211  SCReturnInt(0);
3212 
3213  if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
3214  SCReturnInt(0);
3215  }
3216  SCReturnInt(1);
3217 }
3218 
3219 /**
3220  * \internal
3221  * \brief Helper function for SigInit().
3222  */
3223 static Signature *SigInitHelper(
3224  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
3225 {
3226  SignatureParser parser;
3227  memset(&parser, 0x00, sizeof(parser));
3228 
3229  Signature *sig = SigAlloc();
3230  if (sig == NULL)
3231  goto error;
3232  if (firewall_rule) {
3233  sig->init_data->firewall_rule = true;
3234  sig->flags |= SIG_FLAG_FIREWALL;
3235  }
3236 
3237  sig->sig_str = SCStrdup(sigstr);
3238  if (unlikely(sig->sig_str == NULL)) {
3239  goto error;
3240  }
3241 
3242  /* default gid to 1 */
3243  sig->gid = 1;
3244 
3245  /* We do a first parse of the rule in a requires, or scan-only
3246  * mode. Syntactic errors will be picked up here, but the only
3247  * part of the rule that is validated completely is the "requires"
3248  * keyword. */
3249  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
3250  if (ret == -4) {
3251  /* Rule requirements not met. */
3252  de_ctx->sigerror_silent = true;
3253  de_ctx->sigerror_ok = true;
3254  de_ctx->sigerror_requires = true;
3255  goto error;
3256  } else if (ret < 0) {
3257  goto error;
3258  }
3259 
3260  /* Check for a SID before continuuing. */
3261  if (sig->id == 0) {
3262  SCLogError("Signature missing required value \"sid\".");
3263  goto error;
3264  }
3265 
3266  /* Now completely parse the rule. */
3267  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
3268  BUG_ON(ret == -4);
3269  if (ret == -3) {
3270  de_ctx->sigerror_silent = true;
3271  de_ctx->sigerror_ok = true;
3272  goto error;
3273  } else if (ret == -2) {
3274  de_ctx->sigerror_silent = true;
3275  goto error;
3276  } else if (ret < 0) {
3277  goto error;
3278  }
3279 
3280  /* signature priority hasn't been overwritten. Using default priority */
3281  if (sig->prio == -1)
3282  sig->prio = DETECT_DEFAULT_PRIO;
3283 
3284  sig->iid = de_ctx->signum;
3285  de_ctx->signum++;
3286 
3287  if (sig->alproto != ALPROTO_UNKNOWN) {
3288  int override_needed = 0;
3289  if (sig->init_data->proto.flags & DETECT_PROTO_ANY) {
3291  memset(sig->init_data->proto.proto, 0x00, sizeof(sig->init_data->proto.proto));
3292  override_needed = 1;
3293  } else {
3294  override_needed = 1;
3295  size_t s = 0;
3296  for (s = 0; s < sizeof(sig->init_data->proto.proto); s++) {
3297  if (sig->init_data->proto.proto[s] != 0x00) {
3298  override_needed = 0;
3299  break;
3300  }
3301  }
3302  }
3303 
3304  /* at this point if we had alert ip and the ip proto was not
3305  * overridden, we use the ip proto that has been configured
3306  * against the app proto in use. */
3307  if (override_needed)
3309  }
3310 
3311  /* set the packet and app layer flags, but only if the
3312  * app layer flag wasn't already set in which case we
3313  * only consider the app layer */
3314  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
3315  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
3317  for ( ; sm != NULL; sm = sm->next) {
3318  if (sigmatch_table[sm->type].Match != NULL)
3320  }
3321  } else {
3323  }
3324  }
3325 
3326  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
3327  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
3328  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
3330  }
3331  }
3332  }
3333 
3334  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
3335  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
3336  sig->flags |= SIG_FLAG_TOSERVER;
3337  sig->flags |= SIG_FLAG_TOCLIENT;
3338  }
3339  }
3340 
3341  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
3342  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
3343  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
3344 
3345  SigBuildAddressMatchArray(sig);
3346 
3347  /* run buffer type callbacks if any */
3348  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
3349  if (sig->init_data->smlists[x])
3351  }
3352  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
3354  }
3355 
3356  SigSetupPrefilter(de_ctx, sig);
3357 
3358  /* validate signature, SigValidate will report the error reason */
3359  if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3360  goto error;
3361  }
3362 
3363  return sig;
3364 
3365 error:
3366  if (sig != NULL) {
3367  SigFree(de_ctx, sig);
3368  }
3369  return NULL;
3370 }
3371 
3372 /**
3373  * \brief Checks if a signature has the same source and destination
3374  * \param s parsed signature
3375  *
3376  * \retval true if source and destination are the same, false otherwise
3377  */
3378 static bool SigHasSameSourceAndDestination(const Signature *s)
3379 {
3380  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3381  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3382  return false;
3383  }
3384  }
3385 
3386  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3389 
3391  return false;
3392  }
3393 
3394  src = s->init_data->src->ipv6_head;
3395  dst = s->init_data->dst->ipv6_head;
3396 
3398  return false;
3399  }
3400  }
3401 
3402  return true;
3403 }
3404 
3405 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3406 {
3407  SCEnter();
3408 
3409  uint32_t oldsignum = de_ctx->signum;
3410  de_ctx->sigerror_ok = false;
3411  de_ctx->sigerror_silent = false;
3412  de_ctx->sigerror_requires = false;
3413 
3414  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3415  if (sig == NULL) {
3416  goto error;
3417  }
3418 
3420  if (SigHasSameSourceAndDestination(sig)) {
3421  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3422  "treating the rule as unidirectional", sig->id);
3423 
3425  } else {
3426  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3427  if (sig->next == NULL) {
3428  goto error;
3429  }
3430  }
3431  }
3432 
3433  SCReturnPtr(sig, "Signature");
3434 
3435 error:
3436  if (sig != NULL) {
3437  SigFree(de_ctx, sig);
3438  }
3439  /* if something failed, restore the old signum count
3440  * since we didn't install it */
3441  de_ctx->signum = oldsignum;
3442 
3443  SCReturnPtr(NULL, "Signature");
3444 }
3445 
3446 /**
3447  * \brief Parses a signature and adds it to the Detection Engine Context.
3448  *
3449  * \param de_ctx Pointer to the Detection Engine Context.
3450  * \param sigstr Pointer to a character string containing the signature to be
3451  * parsed.
3452  *
3453  * \retval Pointer to the Signature instance on success; NULL on failure.
3454  */
3455 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3456 {
3457  return SigInitDo(de_ctx, sigstr, false);
3458 }
3459 
3460 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3461 {
3462  return SigInitDo(de_ctx, sigstr, true);
3463 }
3464 
3465 /**
3466  * \brief The hash free function to be the used by the hash table -
3467  * DetectEngineCtx->dup_sig_hash_table.
3468  *
3469  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3470  */
3471 static void DetectParseDupSigFreeFunc(void *data)
3472 {
3473  if (data != NULL)
3474  SCFree(data);
3475 }
3476 
3477 /**
3478  * \brief The hash function to be the used by the hash table -
3479  * DetectEngineCtx->dup_sig_hash_table.
3480  *
3481  * \param ht Pointer to the hash table.
3482  * \param data Pointer to the data, in our case SigDuplWrapper.
3483  * \param datalen Not used in our case.
3484  *
3485  * \retval sw->s->id The generated hash value.
3486  */
3487 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3488 {
3489  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3490 
3491  return (sw->s->id % ht->array_size);
3492 }
3493 
3494 /**
3495  * \brief The Compare function to be used by the hash table -
3496  * DetectEngineCtx->dup_sig_hash_table.
3497  *
3498  * \param data1 Pointer to the first SigDuplWrapper.
3499  * \param len1 Not used.
3500  * \param data2 Pointer to the second SigDuplWrapper.
3501  * \param len2 Not used.
3502  *
3503  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3504  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3505  */
3506 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3507  uint16_t len2)
3508 {
3509  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3510  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3511 
3512  if (sw1 == NULL || sw2 == NULL ||
3513  sw1->s == NULL || sw2->s == NULL)
3514  return 0;
3515 
3516  /* sid and gid match required */
3517  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3518 
3519  return 0;
3520 }
3521 
3522 /**
3523  * \brief Initializes the hash table that is used to cull duplicate sigs.
3524  *
3525  * \param de_ctx Pointer to the detection engine context.
3526  *
3527  * \retval 0 On success.
3528  * \retval -1 On failure.
3529  */
3531 {
3533  DetectParseDupSigHashFunc,
3534  DetectParseDupSigCompareFunc,
3535  DetectParseDupSigFreeFunc);
3536  if (de_ctx->dup_sig_hash_table == NULL)
3537  return -1;
3538 
3539  return 0;
3540 }
3541 
3542 /**
3543  * \brief Frees the hash table that is used to cull duplicate sigs.
3544  *
3545  * \param de_ctx Pointer to the detection engine context that holds this table.
3546  */
3548 {
3549  if (de_ctx->dup_sig_hash_table != NULL)
3551 
3552  de_ctx->dup_sig_hash_table = NULL;
3553 }
3554 
3555 /**
3556  * \brief Check if a signature is a duplicate.
3557  *
3558  * There are 3 types of return values for this function.
3559  *
3560  * - 0, which indicates that the Signature is not a duplicate
3561  * and has to be added to the detection engine list.
3562  * - 1, Signature is duplicate, and the existing signature in
3563  * the list shouldn't be replaced with this duplicate.
3564  * - 2, Signature is duplicate, and the existing signature in
3565  * the list should be replaced with this duplicate.
3566  *
3567  * \param de_ctx Pointer to the detection engine context.
3568  * \param sig Pointer to the Signature that has to be checked.
3569  *
3570  * \retval 2 If Signature is duplicate and the existing signature in
3571  * the list should be chucked out and replaced with this.
3572  * \retval 1 If Signature is duplicate, and should be chucked out.
3573  * \retval 0 If Signature is not a duplicate.
3574  */
3575 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3576  Signature *sig)
3577 {
3578  /* we won't do any NULL checks on the args */
3579 
3580  /* return value */
3581  int ret = 0;
3582 
3583  SigDuplWrapper *sw_dup = NULL;
3584  SigDuplWrapper *sw = NULL;
3585 
3586  /* used for making a duplicate_sig_hash_table entry */
3587  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3588  if (unlikely(sw == NULL)) {
3589  exit(EXIT_FAILURE);
3590  }
3591  sw->s = sig;
3592 
3593  /* check if we have a duplicate entry for this signature */
3594  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3595  /* we don't have a duplicate entry for this sig */
3596  if (sw_dup == NULL) {
3597  /* add it to the hash table */
3598  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3599 
3600  /* add the s_prev entry for the previously loaded sw in the hash_table */
3601  if (de_ctx->sig_list != NULL) {
3602  SigDuplWrapper *sw_old = NULL;
3603  SigDuplWrapper sw_tmp;
3604  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3605 
3606  /* the topmost sig would be the last loaded sig */
3607  sw_tmp.s = de_ctx->sig_list;
3609  (void *)&sw_tmp, 0);
3610  /* sw_old == NULL case is impossible: every sig in sig_list
3611  * must have a corresponding dup_sig_hash_table entry */
3612  DEBUG_VALIDATE_BUG_ON(sw_old == NULL);
3613  sw_old->s_prev = sig;
3614  }
3615 
3616  ret = 0;
3617  goto end;
3618  }
3619 
3620  /* if we have reached here we have a duplicate entry for this signature.
3621  * Check the signature revision. Store the signature with the latest rev
3622  * and discard the other one */
3623  if (sw->s->rev <= sw_dup->s->rev) {
3624  ret = 1;
3625  SCFree(sw);
3626  sw = NULL;
3627  goto end;
3628  }
3629 
3630  /* the new sig is of a newer revision than the one that is already in the
3631  * list. Remove the old sig from the list */
3632  if (sw_dup->s_prev == NULL) {
3633  SigDuplWrapper sw_temp;
3634  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3635  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3636  sw_temp.s = sw_dup->s->next->next;
3637  de_ctx->sig_list = sw_dup->s->next->next;
3638  SigFree(de_ctx, sw_dup->s->next);
3639  } else {
3640  sw_temp.s = sw_dup->s->next;
3641  de_ctx->sig_list = sw_dup->s->next;
3642  }
3643  SigDuplWrapper *sw_next = NULL;
3644  if (sw_temp.s != NULL) {
3646  (void *)&sw_temp, 0);
3647  DEBUG_VALIDATE_BUG_ON(sw_next == NULL);
3648  sw_next->s_prev = sw_dup->s_prev;
3649  }
3650  SigFree(de_ctx, sw_dup->s);
3651  } else {
3652  SigDuplWrapper sw_temp;
3653  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3654  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3655  sw_temp.s = sw_dup->s->next->next;
3656  /* If previous signature is bidirectional,
3657  * it has 2 items in the linked list.
3658  * So we need to change next->next instead of next
3659  */
3661  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3662  } else {
3663  sw_dup->s_prev->next = sw_dup->s->next->next;
3664  }
3665  SigFree(de_ctx, sw_dup->s->next);
3666  } else {
3667  sw_temp.s = sw_dup->s->next;
3669  sw_dup->s_prev->next->next = sw_dup->s->next;
3670  } else {
3671  sw_dup->s_prev->next = sw_dup->s->next;
3672  }
3673  }
3674  SigDuplWrapper *sw_next = NULL;
3675  if (sw_temp.s != NULL) {
3677  (void *)&sw_temp, 0);
3678  DEBUG_VALIDATE_BUG_ON(sw_next == NULL);
3679  sw_next->s_prev = sw_dup->s_prev;
3680  }
3681  SigFree(de_ctx, sw_dup->s);
3682  }
3683 
3684  /* make changes to the entry to reflect the presence of the new sig */
3685  sw_dup->s = sig;
3686  sw_dup->s_prev = NULL;
3687 
3688  if (de_ctx->sig_list != NULL) {
3689  SigDuplWrapper sw_tmp;
3690  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3691  sw_tmp.s = de_ctx->sig_list;
3693  (void *)&sw_tmp, 0);
3694  DEBUG_VALIDATE_BUG_ON(sw_old == NULL);
3695  if (sw_old->s != sw_dup->s) {
3696  // Link on top of the list if there was another element
3697  sw_old->s_prev = sig;
3698  }
3699  }
3700 
3701  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3702  ret = 2;
3703 
3704  SCFree(sw);
3705 
3706 end:
3707  return ret;
3708 }
3709 
3710 /**
3711  * \brief Parse and append a Signature into the Detection Engine Context
3712  * signature list.
3713  *
3714  * If the signature is bidirectional it should append two signatures
3715  * (with the addresses switched) into the list. Also handle duplicate
3716  * signatures. In case of duplicate sigs, use the ones that have the
3717  * latest revision. We use the sid and the msg to identify duplicate
3718  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3719  *
3720  * \param de_ctx Pointer to the Detection Engine Context.
3721  * \param sigstr Pointer to a character string containing the signature to be
3722  * parsed.
3723  * \param sig_file Pointer to a character string containing the filename from
3724  * which signature is read
3725  * \param lineno Line number from where signature is read
3726  *
3727  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3728  * on success; NULL on failure.
3729  */
3731 {
3732  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3733  if (sig == NULL) {
3734  return NULL;
3735  }
3736 
3737  /* checking for the status of duplicate signature */
3738  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3739  /* a duplicate signature that should be chucked out. Check the previously
3740  * called function details to understand the different return values */
3741  if (dup_sig == 1) {
3742  SCLogError("Duplicate signature \"%s\"", sigstr);
3743  goto error;
3744  } else if (dup_sig == 2) {
3745  SCLogWarning("Signature with newer revision,"
3746  " so the older sig replaced by this new signature \"%s\"",
3747  sigstr);
3748  }
3749 
3751  if (sig->next != NULL) {
3752  sig->next->next = de_ctx->sig_list;
3753  } else {
3754  goto error;
3755  }
3756  } else {
3757  /* if this sig is the first one, sig_list should be null */
3758  sig->next = de_ctx->sig_list;
3759  }
3760 
3761  de_ctx->sig_list = sig;
3762 
3763  /**
3764  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3765  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3766  * to the cloned signatures with the switched addresses
3767  */
3768  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3769 
3770 error:
3771  /* free the 2nd sig bidir may have set up */
3772  if (sig != NULL && sig->next != NULL) {
3773  SigFree(de_ctx, sig->next);
3774  sig->next = NULL;
3775  }
3776  if (sig != NULL) {
3777  SigFree(de_ctx, sig);
3778  }
3779  return NULL;
3780 }
3781 
3782 /**
3783  * \brief Parse and append a Signature into the Detection Engine Context
3784  * signature list.
3785  *
3786  * If the signature is bidirectional it should append two signatures
3787  * (with the addresses switched) into the list. Also handle duplicate
3788  * signatures. In case of duplicate sigs, use the ones that have the
3789  * latest revision. We use the sid and the msg to identify duplicate
3790  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3791  *
3792  * \param de_ctx Pointer to the Detection Engine Context.
3793  * \param sigstr Pointer to a character string containing the signature to be
3794  * parsed.
3795  * \param sig_file Pointer to a character string containing the filename from
3796  * which signature is read
3797  * \param lineno Line number from where signature is read
3798  *
3799  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3800  * on success; NULL on failure.
3801  */
3803 {
3804  Signature *sig = SigInit(de_ctx, sigstr);
3805  if (sig == NULL) {
3806  return NULL;
3807  }
3808 
3809  /* checking for the status of duplicate signature */
3810  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3811  /* a duplicate signature that should be chucked out. Check the previously
3812  * called function details to understand the different return values */
3813  if (dup_sig == 1) {
3814  SCLogError("Duplicate signature \"%s\"", sigstr);
3815  goto error;
3816  } else if (dup_sig == 2) {
3817  SCLogWarning("Signature with newer revision,"
3818  " so the older sig replaced by this new signature \"%s\"",
3819  sigstr);
3820  }
3821 
3823  if (sig->next != NULL) {
3824  sig->next->next = de_ctx->sig_list;
3825  } else {
3826  goto error;
3827  }
3828  } else {
3829  /* if this sig is the first one, sig_list should be null */
3830  sig->next = de_ctx->sig_list;
3831  }
3832 
3833  de_ctx->sig_list = sig;
3834 
3835  /**
3836  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3837  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3838  * to the cloned signatures with the switched addresses
3839  */
3840  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3841 
3842 error:
3843  /* free the 2nd sig bidir may have set up */
3844  if (sig != NULL && sig->next != NULL) {
3845  SigFree(de_ctx, sig->next);
3846  sig->next = NULL;
3847  }
3848  if (sig != NULL) {
3849  SigFree(de_ctx, sig);
3850  }
3851  return NULL;
3852 }
3853 
3854 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3855 
3856 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3857  int start_offset, int options)
3858 {
3859  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3860  if (*match)
3861  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3862  *match, parse_regex->context);
3863  return -1;
3864 }
3865 
3867 {
3868  if (r->regex) {
3869  pcre2_code_free(r->regex);
3870  }
3871  if (r->context) {
3872  pcre2_match_context_free(r->context);
3873  }
3874 }
3875 
3877 {
3878  DetectParseRegex *r = g_detect_parse_regex_list;
3879  while (r) {
3880  DetectParseRegex *next = r->next;
3881 
3883 
3884  SCFree(r);
3885  r = next;
3886  }
3887  g_detect_parse_regex_list = NULL;
3888 }
3889 
3890 /** \brief add regex and/or study to at exit free list
3891  */
3893 {
3894  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3895  if (r == NULL) {
3896  FatalError("failed to alloc memory for pcre free list");
3897  }
3898  r->regex = detect_parse->regex;
3899  r->next = g_detect_parse_regex_list;
3900  g_detect_parse_regex_list = r;
3901 }
3902 
3903 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3904 {
3905  int en;
3906  PCRE2_SIZE eo;
3907 
3908  detect_parse->regex =
3909  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3910  if (detect_parse->regex == NULL) {
3911  PCRE2_UCHAR errbuffer[256];
3912  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3913  SCLogError("pcre compile of \"%s\" failed at "
3914  "offset %d: %s",
3915  parse_str, en, errbuffer);
3916  return false;
3917  }
3918  detect_parse->context = pcre2_match_context_create(NULL);
3919  if (detect_parse->context == NULL) {
3920  SCLogError("pcre2 could not create match context");
3921  pcre2_code_free(detect_parse->regex);
3922  detect_parse->regex = NULL;
3923  return false;
3924  }
3925  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3926  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3927  DetectParseRegexAddToFreeList(detect_parse);
3928 
3929  return true;
3930 }
3931 
3932 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3933 {
3934  int en;
3935  PCRE2_SIZE eo;
3936  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3937  if (detect_parse == NULL) {
3938  return NULL;
3939  }
3940 
3941  detect_parse->regex =
3942  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3943  if (detect_parse->regex == NULL) {
3944  PCRE2_UCHAR errbuffer[256];
3945  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3946  SCLogError("pcre2 compile of \"%s\" failed at "
3947  "offset %d: %s",
3948  parse_str, (int)eo, errbuffer);
3949  SCFree(detect_parse);
3950  return NULL;
3951  }
3952 
3953  detect_parse->next = g_detect_parse_regex_list;
3954  g_detect_parse_regex_list = detect_parse;
3955  return detect_parse;
3956 }
3957 
3959  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3960 {
3961  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3962  if (r == PCRE2_ERROR_UNSET) {
3963  buffer[0] = 0;
3964  *bufflen = 0;
3965  return 0;
3966  }
3967  return r;
3968 }
3969 
3971  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3972 {
3973  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3974  if (r == PCRE2_ERROR_UNSET) {
3975  *bufferptr = NULL;
3976  *bufflen = 0;
3977  return 0;
3978  }
3979  return r;
3980 }
3981 
3982 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3983 {
3984  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3985  FatalError("pcre compile and study failed");
3986  }
3987 }
3988 
3989 static uint32_t AppPolicyHashFunc(HashTable *ht, void *data, uint16_t datalen)
3990 {
3991  const struct DetectFirewallAppPolicy *p = data;
3992  /* use a prime-mix hash */
3993  uint32_t hash = p->alproto * 65537 + p->sub_state * 257 + p->progress * 5 +
3994  (p->direction == STREAM_TOSERVER);
3995  hash ^= (hash >> 10) ^ (hash >> 20);
3996  return hash % ht->array_size;
3997 }
3998 
3999 static char AppPolicyCompareFunc(void *data1, uint16_t datalen1, void *data2, uint16_t datalen2)
4000 {
4001  const struct DetectFirewallAppPolicy *p1 = data1;
4002  const struct DetectFirewallAppPolicy *p2 = data2;
4003 
4004  if (p1 == NULL || p2 == NULL)
4005  return 0;
4006 
4007  return p1->direction == p2->direction && p1->alproto == p2->alproto &&
4008  p1->sub_state == p2->sub_state && p1->progress == p2->progress;
4009 }
4010 
4011 static void AppPolicyHashFree(void *data)
4012 {
4013  struct DetectFirewallAppPolicy *p = data;
4014  Signature *s = p->alert_signature;
4015  if (s != NULL) {
4016  SCFree(s->msg);
4017  SCFree(s);
4018  }
4019  SCFree(p);
4020 }
4021 
4023 {
4024  switch (s) {
4025  case ACTION_SCOPE_PACKET:
4026  return "packet";
4027  case ACTION_SCOPE_FLOW:
4028  return "flow";
4029  case ACTION_SCOPE_HOOK:
4030  return "hook";
4031  case ACTION_SCOPE_TX:
4032  return "tx";
4033  case ACTION_SCOPE_AUTO:
4034  return "auto";
4035  }
4037  return "unknown";
4038 }
4039 
4040 void DetectFirewallPolicyToString(const struct DetectFirewallPolicy *p, char *out, size_t out_size)
4041 {
4042  const char *as = ActionScopeToString(p->action_scope);
4043  DEBUG_VALIDATE_BUG_ON(as == NULL);
4044  if (as == NULL)
4045  return;
4046  if (p->action & ACTION_REJECT_ANY) {
4047  if (p->action & ACTION_REJECT_DST) {
4048  snprintf(out, out_size, "rejectdst:%s", as);
4049  } else if (p->action & ACTION_REJECT_BOTH) {
4050  snprintf(out, out_size, "rejectboth:%s", as);
4051  } else {
4052  snprintf(out, out_size, "rejectsrc:%s", as);
4053  }
4054  } else if (p->action & ACTION_DROP) {
4055  snprintf(out, out_size, "drop:%s", as);
4056  } else if (p->action & ACTION_ACCEPT) {
4057  snprintf(out, out_size, "accept:%s", as);
4058  } else {
4060  }
4061  if (p->action & ACTION_PASS) {
4062  if (p->action_scope == ACTION_SCOPE_FLOW) {
4063  strlcat(out, ",pass:flow", out_size);
4064  } else {
4066  }
4067  }
4068  if (p->action & ACTION_ALERT) {
4069  strlcat(out, ",alert", out_size);
4070  }
4071 }
4072 
4073 static int AddPktPolicySignature(struct DetectFirewallPolicies *fw_policies,
4074  struct DetectFirewallPolicy *pol, enum DetectFirewallPacketPolicies pkt_pol)
4075 {
4076  Signature *s = SCCalloc(1, sizeof(*s)); // SigAlloc does way more than we need
4077  if (s == NULL)
4078  return -1;
4079  char msg[256];
4080  switch (pkt_pol) {
4083  break;
4086  break;
4089  break;
4090  }
4091  snprintf(msg, sizeof(msg), "SURICATA FW default packet policy");
4092  s->msg = SCStrdup(msg);
4093  if (s->msg == NULL) {
4094  SCFree(s);
4095  return -1;
4096  }
4097  s->action = pol->action;
4098  s->action_scope = pol->action_scope;
4099  s->flags = SIG_FLAG_FIREWALL;
4100  s->type = SIG_TYPE_PKT;
4101  s->id = 2201000;
4102  s->rev = 1;
4103  s->gid = 1;
4104  s->prio = 3;
4105 
4106  fw_policies->pkt_policy_signatures[pkt_pol] = s;
4107  SCLogDebug("added to array");
4108  return 0;
4109 }
4110 
4111 static int AddAppPolicySignature(struct DetectFirewallAppPolicy *pol)
4112 {
4113  Signature *s = SCCalloc(1, sizeof(*s)); // SigAlloc does way more than we need
4114  if (s == NULL)
4115  return -1;
4116  char msg[256];
4117  snprintf(msg, sizeof(msg), "SURICATA FW default app policy");
4118  s->msg = SCStrdup(msg);
4119  if (s->msg == NULL) {
4120  SCFree(s);
4121  return -1;
4122  }
4123  s->app_progress_hook = pol->progress;
4124  s->action = pol->policy.action;
4125  s->action_scope = pol->policy.action_scope;
4126  s->alproto = pol->alproto;
4127  s->flags = (pol->direction == STREAM_TOSERVER) ? SIG_FLAG_TOSERVER : SIG_FLAG_TOCLIENT;
4128  s->flags |= SIG_FLAG_FIREWALL;
4129  s->type = SIG_TYPE_APP_TX;
4131  s->id = 2201001;
4132  s->rev = 1;
4133  s->gid = 1;
4134  s->prio = 3;
4135 
4136  pol->alert_signature = s;
4137  SCLogDebug("added to hash");
4138  return 0;
4139 }
4140 
4141 static int DoParsePolicy(const char *policy_name, struct DetectFirewallPolicy *pol)
4142 {
4143  SCConfNode *policy_actions = SCConfGetNode(policy_name);
4144  if (policy_actions == NULL) {
4145  SCLogDebug("fw: no policy at %s", policy_name);
4146  return 0;
4147  }
4148 
4149  uint8_t action = 0;
4150  uint8_t action_scope = 0;
4151  int idx = 0;
4152  SCConfNode *paction = NULL;
4153  TAILQ_FOREACH (paction, &policy_actions->head, next) {
4154  SCLogDebug("fw: %s => %s", policy_name, paction->val);
4155  if (SigParseActionDo(paction->val, idx, true, &action, &action_scope) < 0)
4156  return -1;
4157  idx++;
4158  }
4159  pol->action = action;
4160  pol->action_scope = action_scope;
4161  return 1;
4162 }
4163 
4164 static int DoParseAppSubStatePolicy(const char *prefix, const AppProto app_proto,
4165  const uint8_t sub_state, const char *sub_state_name, const uint8_t state,
4166  const char *hookname, const uint8_t complete_state, const int direction,
4167  struct DetectFirewallPolicies *fw_policies)
4168 {
4169  char policy_name[256];
4170  BUG_ON(sub_state_name == NULL);
4171  BUG_ON(hookname == NULL);
4172 
4173  char *nname = SCStrdup(hookname);
4174  if (nname == NULL)
4175  return -1;
4176  for (int i = 0; nname[i] != '\0'; i++) {
4177  if (nname[i] == '_')
4178  nname[i] = '-';
4179  }
4180 
4181  const char *app_name = AppProtoToString(app_proto);
4182  int r = snprintf(policy_name, sizeof(policy_name), "%s.%s.%s.%s", prefix, app_name,
4183  sub_state_name, nname);
4184  SCLogDebug("policy_name %s", policy_name);
4185  SCFree(nname);
4186  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4187  FatalError("internal error: failed to assemble firewall policy config string");
4188  }
4189 
4190  struct DetectFirewallAppPolicy *app_pol = SCCalloc(1, sizeof(*app_pol));
4191  if (app_pol == NULL)
4192  return -1;
4193 
4194  app_pol->alproto = app_proto;
4195  app_pol->sub_state = sub_state;
4196  app_pol->progress = state;
4197  app_pol->direction = (uint8_t)direction;
4198  /* init to drop:flow by default, will be overwritten by DoParsePolicy if there
4199  * is a config for this hook. */
4200  app_pol->policy.action = ACTION_DROP;
4202 
4203  r = DoParsePolicy(policy_name, &app_pol->policy);
4204  if (r < 0) {
4205  SCFree(app_pol);
4206  return -1;
4207  }
4208 
4209  if (HashTableAdd(fw_policies->app_policies, app_pol, 0) != 0) {
4210  FatalError("internal error: insert policy into hash table");
4211  }
4212  /* for policies with an alert action, create a policy sig */
4213  if (r == 1 && app_pol->policy.action & ACTION_ALERT) {
4214  SCLogDebug("adding policy signature");
4215  return AddAppPolicySignature(app_pol);
4216  }
4217  SCLogDebug("r %d", r);
4218  return r;
4219 }
4220 
4221 static int DoParseAppPolicy(const char *prefix, const AppProto app_proto, const char *hookname,
4222  const uint8_t state, const uint8_t complete_state, const int direction,
4223  struct DetectFirewallPolicies *fw_policies)
4224 {
4225  char policy_name[256];
4226  const char *in_name = hookname;
4227  if (hookname == NULL) {
4228  if (state == 0) {
4229  if (direction == STREAM_TOSERVER)
4230  hookname = "request-started";
4231  else
4232  hookname = "response-started";
4233  } else if (state == complete_state) {
4234  if (direction == STREAM_TOSERVER)
4235  hookname = "request-complete";
4236  else
4237  hookname = "response-complete";
4238  }
4239  if (hookname == NULL)
4240  return 0;
4241  }
4242  char *nname = SCStrdup(hookname);
4243  if (nname == NULL)
4244  return -1;
4245  for (int i = 0; nname[i] != '\0'; i++) {
4246  if (nname[i] == '_')
4247  nname[i] = '-';
4248  }
4249 
4250  const char *app_name = AppProtoToString(app_proto);
4251  int r = snprintf(policy_name, sizeof(policy_name), "%s.%s.%s", prefix, app_name, nname);
4252  SCFree(nname);
4253  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4254  FatalError("internal error: failed to assemble firewall policy config string");
4255  }
4256 
4257  struct DetectFirewallAppPolicy *app_pol = SCCalloc(1, sizeof(*app_pol));
4258  if (app_pol == NULL)
4259  return -1;
4260 
4261  app_pol->alproto = app_proto;
4262  app_pol->sub_state = 0;
4263  app_pol->progress = state;
4264  app_pol->direction = (uint8_t)direction;
4265  /* init to drop:flow by default, will be overwritten by DoParsePolicy if there
4266  * is a config for this hook. */
4267  app_pol->policy.action = ACTION_DROP;
4269 
4270  r = DoParsePolicy(policy_name, &app_pol->policy);
4271  if (r == 0 && in_name != NULL) {
4272  if (state == 0) {
4273  if (direction == STREAM_TOSERVER)
4274  hookname = "request-started";
4275  else
4276  hookname = "response-started";
4277  } else if (state == complete_state) {
4278  if (direction == STREAM_TOSERVER)
4279  hookname = "request-complete";
4280  else
4281  hookname = "response-complete";
4282  }
4283  if (hookname == NULL)
4284  return 0;
4285  r = snprintf(policy_name, sizeof(policy_name), "%s.%s.%s", prefix, app_name, hookname);
4286  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4287  FatalError("internal error: failed to assemble firewall policy config string");
4288  }
4289 
4290  r = DoParsePolicy(policy_name, &app_pol->policy);
4291  }
4292  if (r < 0) {
4293  SCFree(app_pol);
4294  return -1;
4295  }
4296 
4297  if (HashTableAdd(fw_policies->app_policies, app_pol, 0) != 0) {
4298  FatalError("internal error: insert policy into hash table");
4299  }
4300 
4301  /* for policies with an alert action, create a policy sig */
4302  if (r == 1 && app_pol->policy.action & ACTION_ALERT) {
4303  SCLogDebug("adding policy signature");
4304  return AddAppPolicySignature(app_pol);
4305  }
4306 
4307  return r;
4308 }
4309 
4310 /** \brief allocate and initialize to default values the policies table */
4312 {
4313  struct DetectFirewallPolicies *fw_policies = SCCalloc(1, sizeof(*fw_policies));
4314  if (fw_policies == NULL)
4315  return -1;
4316  fw_policies->app_policies =
4317  HashTableInit(512, AppPolicyHashFunc, AppPolicyCompareFunc, AppPolicyHashFree);
4318  if (fw_policies->app_policies == NULL) {
4319  SCFree(fw_policies);
4320  return -1;
4321  }
4322 
4325 
4328 
4331 
4332  de_ctx->fw_policies = fw_policies;
4333  return 0;
4334 }
4335 
4337 {
4338  int r;
4339  char policy_name[256];
4340  char prefix[96] = "firewall.policies";
4341  if (strlen(de_ctx->config_prefix) > 0) {
4342  snprintf(prefix, sizeof(prefix), "%s.firewall.policies", de_ctx->config_prefix);
4343  }
4344 
4345  struct DetectFirewallPolicies *fw_policies = de_ctx->fw_policies;
4346  if (fw_policies == NULL)
4347  return -1;
4348 
4349  r = snprintf(policy_name, sizeof(policy_name), "%s.packet-filter", prefix);
4350  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4351  FatalError("internal error: failed to assemble firewall policy config string");
4352  }
4353  r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PACKET_FILTER]);
4354  if (r < 0)
4355  return -1;
4357  if (AddPktPolicySignature(fw_policies,
4360  return -1;
4361 
4362  r = snprintf(policy_name, sizeof(policy_name), "%s.packet-pre-flow", prefix);
4363  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4364  FatalError("internal error: failed to assemble firewall policy config string");
4365  }
4366  r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW]);
4367  if (r < 0)
4368  return -1;
4370  if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_FLOW],
4372  return -1;
4373 
4374  r = snprintf(policy_name, sizeof(policy_name), "%s.packet-pre-stream", prefix);
4375  if (r < 0 || (size_t)r >= sizeof(policy_name)) {
4376  FatalError("internal error: failed to assemble firewall policy config string");
4377  }
4378  r = DoParsePolicy(policy_name, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM]);
4379  if (r < 0)
4380  return -1;
4382  if (AddPktPolicySignature(fw_policies, &fw_policies->pkt[DETECT_FIREWALL_POLICY_PRE_STREAM],
4384  return -1;
4385 
4386  for (AppProto a = 0; a < g_alproto_max; a++) {
4387  if (!AppProtoIsValid(a))
4388  continue;
4389 
4391  uint8_t max_sub_state = AppLayerParserGetMaxSubState(a);
4392  SCLogDebug("%s: max sub state for %u is %u", AppProtoToString(a), a, max_sub_state);
4393  for (uint8_t s = 1; s <= max_sub_state; s++) {
4394  SCLogDebug("%s: checking sub state %u", AppProtoToString(a), s);
4395 
4396  const char *sub_state_name = AppLayerParserGetSubStateName(a, s);
4397  if (sub_state_name == NULL)
4398  continue;
4399 
4400  // iterate the states belonging to the sub state
4401  const uint8_t max_state = AppLayerParserGetSubStateCompletion(
4402  a, s); // TODO allow different completion per direction?
4403  /* to_server */
4404  for (uint8_t state = 0; state <= max_state; state++) {
4405  SCLogDebug("protocol %s: sub state:%s state:%u", AppProtoToString(a),
4406  sub_state_name, state);
4407  const char *state_name =
4408  AppLayerParserGetSubStateProgressName(a, s, state, STREAM_TOSERVER);
4409  BUG_ON(state_name == NULL);
4410  SCLogDebug("protocol %s: sub state:%s state:%s", AppProtoToString(a),
4411  sub_state_name, state_name);
4412  if (DoParseAppSubStatePolicy(prefix, a, s, sub_state_name, state, state_name,
4413  max_state, STREAM_TOSERVER, fw_policies) < 0)
4414  return -1;
4415  }
4416  /* to_client */
4417  for (uint8_t state = 0; state <= max_state; state++) {
4418  SCLogDebug("protocol %s: to_client: sub state:%s state:%u", AppProtoToString(a),
4419  sub_state_name, state);
4420  const char *state_name =
4421  AppLayerParserGetSubStateProgressName(a, s, state, STREAM_TOCLIENT);
4422  BUG_ON(state_name == NULL);
4423  SCLogDebug("protocol %s: to_client: sub state:%s state:%s", AppProtoToString(a),
4424  sub_state_name, state_name);
4425  if (DoParseAppSubStatePolicy(prefix, a, s, sub_state_name, state, state_name,
4426  max_state, STREAM_TOCLIENT, fw_policies) < 0)
4427  return -1;
4428  }
4429  }
4430  } else {
4431  const uint8_t complete_state_ts =
4433  a, STREAM_TOSERVER);
4434  for (uint8_t state = 0; state <= complete_state_ts; state++) {
4435  const char *name =
4436  AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOSERVER);
4437  if (DoParseAppPolicy(prefix, a, name, state, complete_state_ts, STREAM_TOSERVER,
4438  fw_policies) < 0)
4439  return -1;
4440  }
4441  const uint8_t complete_state_tc =
4443  a, STREAM_TOCLIENT);
4444  for (uint8_t state = 0; state <= complete_state_tc; state++) {
4445  const char *name =
4446  AppLayerParserGetStateNameById(IPPROTO_TCP, a, state, STREAM_TOCLIENT);
4447  if (DoParseAppPolicy(prefix, a, name, state, complete_state_tc, STREAM_TOCLIENT,
4448  fw_policies) < 0)
4449  return -1;
4450  }
4451  }
4452  }
4453  return 0;
4454 }
4455 
4456 /*
4457  * TESTS
4458  */
4459 
4460 #ifdef UNITTESTS
4461 #include "detect-engine-alert.h"
4462 #include "packet.h"
4463 
4464 static int SigParseTest01 (void)
4465 {
4466  int result = 1;
4467  Signature *sig = NULL;
4468 
4470  if (de_ctx == NULL)
4471  goto end;
4472 
4473  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
4474  if (sig == NULL)
4475  result = 0;
4476 
4477 end:
4478  if (sig != NULL) SigFree(de_ctx, sig);
4479  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4480  return result;
4481 }
4482 
4483 static int SigParseTest02 (void)
4484 {
4485  int result = 0;
4486  Signature *sig = NULL;
4487  DetectPort *port = NULL;
4488 
4490 
4491  if (de_ctx == NULL)
4492  goto end;
4493 
4497 
4498  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;)");
4499  if (sig == NULL) {
4500  goto end;
4501  }
4502 
4503  int r = DetectPortParse(de_ctx, &port, "0:20");
4504  if (r < 0)
4505  goto end;
4506 
4507  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
4508  result = 1;
4509  } else {
4510  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
4511  }
4512 
4513 end:
4514  if (port != NULL)
4516  if (sig != NULL)
4517  SigFree(de_ctx, sig);
4518  if (de_ctx != NULL)
4520  return result;
4521 }
4522 
4523 /**
4524  * \test SigParseTest03 test for invalid direction operator in rule
4525  */
4526 static int SigParseTest03 (void)
4527 {
4528  int result = 1;
4529  Signature *sig = NULL;
4530 
4532  if (de_ctx == NULL)
4533  goto end;
4534 
4535  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
4536  if (sig != NULL) {
4537  result = 0;
4538  printf("expected NULL got sig ptr %p: ",sig);
4539  }
4540 
4541 end:
4542  if (sig != NULL) SigFree(de_ctx, sig);
4543  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4544  return result;
4545 }
4546 
4547 static int SigParseTest04 (void)
4548 {
4549  int result = 1;
4550  Signature *sig = NULL;
4551 
4553  if (de_ctx == NULL)
4554  goto end;
4555 
4556  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
4557  if (sig == NULL)
4558  result = 0;
4559 
4560 end:
4561  if (sig != NULL) SigFree(de_ctx, sig);
4562  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4563  return result;
4564 }
4565 
4566 /** \test Port validation */
4567 static int SigParseTest05 (void)
4568 {
4569  int result = 0;
4570  Signature *sig = NULL;
4571 
4573  if (de_ctx == NULL)
4574  goto end;
4575 
4576  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
4577  if (sig == NULL) {
4578  result = 1;
4579  } else {
4580  printf("signature didn't fail to parse as we expected: ");
4581  }
4582 
4583 end:
4584  if (sig != NULL) SigFree(de_ctx, sig);
4585  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4586  return result;
4587 }
4588 
4589 /** \test Parsing bug debugging at 2010-03-18 */
4590 static int SigParseTest06 (void)
4591 {
4592  int result = 0;
4593  Signature *sig = NULL;
4594 
4596  if (de_ctx == NULL)
4597  goto end;
4598 
4599  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;)");
4600  if (sig != NULL) {
4601  result = 1;
4602  } else {
4603  printf("signature failed to parse: ");
4604  }
4605 
4606 end:
4607  if (sig != NULL)
4608  SigFree(de_ctx, sig);
4609  if (de_ctx != NULL)
4611  return result;
4612 }
4613 
4614 /**
4615  * \test Parsing duplicate sigs.
4616  */
4617 static int SigParseTest07(void)
4618 {
4619  int result = 0;
4620 
4622  if (de_ctx == NULL)
4623  goto end;
4624 
4625  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4626  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4627 
4628  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
4629 
4630 end:
4631  if (de_ctx != NULL)
4633  return result;
4634 }
4635 
4636 /**
4637  * \test Parsing duplicate sigs.
4638  */
4639 static int SigParseTest08(void)
4640 {
4641  int result = 0;
4642 
4644  if (de_ctx == NULL)
4645  goto end;
4646 
4647  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4648  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
4649 
4650  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
4651  de_ctx->sig_list->rev == 2);
4652 
4653 end:
4654  if (de_ctx != NULL)
4656  return result;
4657 }
4658 
4659 /**
4660  * \test Parsing duplicate sigs.
4661  */
4662 static int SigParseTest09(void)
4663 {
4664  int result = 1;
4665 
4667  if (de_ctx == NULL)
4668  goto end;
4669 
4670  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4671  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
4672  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
4673  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
4674  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
4675  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
4676  de_ctx->sig_list->rev == 2);
4677  if (result == 0)
4678  goto end;
4679  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
4680  de_ctx->sig_list->next->rev == 6);
4681  if (result == 0)
4682  goto end;
4683 
4684  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
4685  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
4686  de_ctx->sig_list->rev == 2);
4687  if (result == 0)
4688  goto end;
4689  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
4690  de_ctx->sig_list->next->rev == 6);
4691  if (result == 0)
4692  goto end;
4693 
4694  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
4695  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
4696  de_ctx->sig_list->rev == 4);
4697  if (result == 0)
4698  goto end;
4699  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
4700  de_ctx->sig_list->next->rev == 6);
4701  if (result == 0)
4702  goto end;
4703 
4704 end:
4705  if (de_ctx != NULL)
4707  return result;
4708 }
4709 
4710 /**
4711  * \test Parsing duplicate sigs.
4712  */
4713 static int SigParseTest10(void)
4714 {
4715  int result = 1;
4716 
4718  if (de_ctx == NULL)
4719  goto end;
4720 
4721  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
4722  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
4723  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
4724  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
4725  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
4726  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
4727  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
4728 
4729  result &= ((de_ctx->sig_list->id == 2) &&
4730  (de_ctx->sig_list->next->id == 3) &&
4731  (de_ctx->sig_list->next->next->id == 5) &&
4732  (de_ctx->sig_list->next->next->next->id == 4) &&
4733  (de_ctx->sig_list->next->next->next->next->id == 1));
4734 
4735 end:
4736  if (de_ctx != NULL)
4738  return result;
4739 }
4740 
4741 /**
4742  * \test Parsing sig with trailing space(s) as reported by
4743  * Morgan Cox on oisf-users.
4744  */
4745 static int SigParseTest11(void)
4746 {
4747  int result = 0;
4748 
4750  if (de_ctx == NULL)
4751  goto end;
4752 
4753  Signature *s = NULL;
4754 
4756  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
4757  if (s == NULL) {
4758  printf("sig 1 didn't parse: ");
4759  goto end;
4760  }
4761 
4762  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
4763  "the http link\"; sid:2;) ");
4764  if (s == NULL) {
4765  printf("sig 2 didn't parse: ");
4766  goto end;
4767  }
4768 
4769  result = 1;
4770 end:
4771  if (de_ctx != NULL)
4773  return result;
4774 }
4775 
4776 /**
4777  * \test file_data with rawbytes
4778  */
4779 static int SigParseTest12(void)
4780 {
4781  int result = 0;
4782 
4784  if (de_ctx == NULL)
4785  goto end;
4786 
4787  Signature *s = NULL;
4788 
4789  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
4790  if (s != NULL) {
4791  printf("sig 1 should have given an error: ");
4792  goto end;
4793  }
4794 
4795  result = 1;
4796 end:
4797  if (de_ctx != NULL)
4799  return result;
4800 }
4801 
4802 /**
4803  * \test packet/stream sig
4804  */
4805 static int SigParseTest13(void)
4806 {
4807  int result = 0;
4808 
4810  if (de_ctx == NULL)
4811  goto end;
4812 
4813  Signature *s = NULL;
4814 
4815  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
4816  if (s == NULL) {
4817  printf("sig 1 invalidated: failure");
4818  goto end;
4819  }
4820 
4821  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4822  printf("sig doesn't have stream flag set\n");
4823  goto end;
4824  }
4825 
4826  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
4827  printf("sig has packet flag set\n");
4828  goto end;
4829  }
4830 
4831  result = 1;
4832 
4833 end:
4834  if (de_ctx != NULL)
4836  return result;
4837 }
4838 
4839 /**
4840  * \test packet/stream sig
4841  */
4842 static int SigParseTest14(void)
4843 {
4844  int result = 0;
4845 
4847  if (de_ctx == NULL)
4848  goto end;
4849 
4850  Signature *s = NULL;
4851 
4852  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4853  if (s == NULL) {
4854  printf("sig 1 invalidated: failure");
4855  goto end;
4856  }
4857 
4858  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4859  printf("sig doesn't have packet flag set\n");
4860  goto end;
4861  }
4862 
4863  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4864  printf("sig has stream flag set\n");
4865  goto end;
4866  }
4867 
4868  result = 1;
4869 
4870 end:
4871  if (de_ctx != NULL)
4873  return result;
4874 }
4875 
4876 /**
4877  * \test packet/stream sig
4878  */
4879 static int SigParseTest15(void)
4880 {
4881  int result = 0;
4882 
4884  if (de_ctx == NULL)
4885  goto end;
4886 
4887  Signature *s = NULL;
4888 
4889  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4890  if (s == NULL) {
4891  printf("sig 1 invalidated: failure");
4892  goto end;
4893  }
4894 
4895  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4896  printf("sig doesn't have packet flag set\n");
4897  goto end;
4898  }
4899 
4900  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4901  printf("sig doesn't have stream flag set\n");
4902  goto end;
4903  }
4904 
4905  result = 1;
4906 
4907 end:
4908  if (de_ctx != NULL)
4910  return result;
4911 }
4912 
4913 /**
4914  * \test packet/stream sig
4915  */
4916 static int SigParseTest16(void)
4917 {
4918  int result = 0;
4919 
4921  if (de_ctx == NULL)
4922  goto end;
4923 
4924  Signature *s = NULL;
4925 
4926  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4927  if (s == NULL) {
4928  printf("sig 1 invalidated: failure");
4929  goto end;
4930  }
4931 
4932  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4933  printf("sig doesn't have packet flag set\n");
4934  goto end;
4935  }
4936 
4937  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4938  printf("sig doesn't have stream flag set\n");
4939  goto end;
4940  }
4941 
4942  result = 1;
4943 
4944 end:
4945  if (de_ctx != NULL)
4947  return result;
4948 }
4949 
4950 /**
4951  * \test packet/stream sig
4952  */
4953 static int SigParseTest17(void)
4954 {
4955  int result = 0;
4956 
4958  if (de_ctx == NULL)
4959  goto end;
4960 
4961  Signature *s = NULL;
4962 
4963  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4964  if (s == NULL) {
4965  printf("sig 1 invalidated: failure");
4966  goto end;
4967  }
4968 
4969  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4970  printf("sig doesn't have packet flag set\n");
4971  goto end;
4972  }
4973 
4974  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4975  printf("sig doesn't have stream flag set\n");
4976  goto end;
4977  }
4978 
4979  result = 1;
4980 
4981 end:
4982  if (de_ctx != NULL)
4984  return result;
4985 }
4986 
4987 /** \test sid value too large. Bug #779 */
4988 static int SigParseTest18 (void)
4989 {
4990  int result = 0;
4991 
4993  if (de_ctx == NULL)
4994  goto end;
4995 
4996  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4997  goto end;
4998 
4999  result = 1;
5000 end:
5001  if (de_ctx != NULL)
5003  return result;
5004 }
5005 
5006 /** \test gid value too large. Related to bug #779 */
5007 static int SigParseTest19 (void)
5008 {
5009  int result = 0;
5010 
5012  if (de_ctx == NULL)
5013  goto end;
5014 
5015  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
5016  goto end;
5017 
5018  result = 1;
5019 end:
5020  if (de_ctx != NULL)
5022  return result;
5023 }
5024 
5025 /** \test rev value too large. Related to bug #779 */
5026 static int SigParseTest20 (void)
5027 {
5028  int result = 0;
5029 
5031  if (de_ctx == NULL)
5032  goto end;
5033 
5034  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
5035  goto end;
5036 
5037  result = 1;
5038 end:
5039  if (de_ctx != NULL)
5041  return result;
5042 }
5043 
5044 /** \test address parsing */
5045 static int SigParseTest21 (void)
5046 {
5047  int result = 0;
5048 
5050  if (de_ctx == NULL)
5051  goto end;
5052 
5053  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
5054  goto end;
5055 
5056  result = 1;
5057 end:
5058  if (de_ctx != NULL)
5060  return result;
5061 }
5062 
5063 /** \test address parsing */
5064 static int SigParseTest22 (void)
5065 {
5066  int result = 0;
5067 
5069  if (de_ctx == NULL)
5070  goto end;
5071 
5072  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)
5073  goto end;
5074 
5075  result = 1;
5076 end:
5077  if (de_ctx != NULL)
5079  return result;
5080 }
5081 
5082 /**
5083  * \test rule ending in carriage return
5084  */
5085 static int SigParseTest23(void)
5086 {
5089 
5090  Signature *s = NULL;
5091 
5092  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
5093  FAIL_IF_NULL(s);
5094 
5096  PASS;
5097 }
5098 
5099 /** \test Direction operator validation (invalid) */
5100 static int SigParseBidirecTest06 (void)
5101 {
5102  int result = 1;
5103  Signature *sig = NULL;
5104 
5106  if (de_ctx == NULL)
5107  goto end;
5108 
5109  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5110  if (sig == NULL)
5111  result = 1;
5112 
5113 end:
5114  if (sig != NULL) SigFree(de_ctx, sig);
5115  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5116  return result;
5117 }
5118 
5119 /** \test Direction operator validation (invalid) */
5120 static int SigParseBidirecTest07 (void)
5121 {
5122  int result = 1;
5123  Signature *sig = NULL;
5124 
5126  if (de_ctx == NULL)
5127  goto end;
5128 
5129  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5130  if (sig == NULL)
5131  result = 1;
5132 
5133 end:
5134  if (sig != NULL) SigFree(de_ctx, sig);
5135  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5136  return result;
5137 }
5138 
5139 /** \test Direction operator validation (invalid) */
5140 static int SigParseBidirecTest08 (void)
5141 {
5142  int result = 1;
5143  Signature *sig = NULL;
5144 
5146  if (de_ctx == NULL)
5147  goto end;
5148 
5149  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5150  if (sig == NULL)
5151  result = 1;
5152 
5153 end:
5154  if (sig != NULL) SigFree(de_ctx, sig);
5155  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5156  return result;
5157 }
5158 
5159 /** \test Direction operator validation (invalid) */
5160 static int SigParseBidirecTest09 (void)
5161 {
5162  int result = 1;
5163  Signature *sig = NULL;
5164 
5166  if (de_ctx == NULL)
5167  goto end;
5168 
5169  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5170  if (sig == NULL)
5171  result = 1;
5172 
5173 end:
5174  if (sig != NULL) SigFree(de_ctx, sig);
5175  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5176  return result;
5177 }
5178 
5179 /** \test Direction operator validation (invalid) */
5180 static int SigParseBidirecTest10 (void)
5181 {
5182  int result = 1;
5183  Signature *sig = NULL;
5184 
5186  if (de_ctx == NULL)
5187  goto end;
5188 
5189  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5190  if (sig == NULL)
5191  result = 1;
5192 
5193 end:
5194  if (sig != NULL) SigFree(de_ctx, sig);
5195  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5196  return result;
5197 }
5198 
5199 /** \test Direction operator validation (invalid) */
5200 static int SigParseBidirecTest11 (void)
5201 {
5202  int result = 1;
5203  Signature *sig = NULL;
5204 
5206  if (de_ctx == NULL)
5207  goto end;
5208 
5209  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5210  if (sig == NULL)
5211  result = 1;
5212 
5213 end:
5214  if (sig != NULL) SigFree(de_ctx, sig);
5215  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5216  return result;
5217 }
5218 
5219 /** \test Direction operator validation (invalid) */
5220 static int SigParseBidirecTest12 (void)
5221 {
5222  int result = 1;
5223  Signature *sig = NULL;
5224 
5226  if (de_ctx == NULL)
5227  goto end;
5228 
5229  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5230  if (sig == NULL)
5231  result = 1;
5232 
5233 end:
5234  if (sig != NULL) SigFree(de_ctx, sig);
5235  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5236  return result;
5237 }
5238 
5239 /** \test Direction operator validation (valid) */
5240 static int SigParseBidirecTest13 (void)
5241 {
5242  int result = 1;
5243  Signature *sig = NULL;
5244 
5246  if (de_ctx == NULL)
5247  goto end;
5248 
5249  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5250  if (sig != NULL)
5251  result = 1;
5252 
5253 end:
5254  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5255  return result;
5256 }
5257 
5258 /** \test Direction operator validation (valid) */
5259 static int SigParseBidirecTest14 (void)
5260 {
5261  int result = 1;
5262  Signature *sig = NULL;
5263 
5265  if (de_ctx == NULL)
5266  goto end;
5267 
5268  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
5269  if (sig != NULL)
5270  result = 1;
5271 
5272 end:
5273  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
5274  return result;
5275 }
5276 
5277 /** \test Ensure that we don't set bidirectional in a
5278  * normal (one direction) Signature
5279  */
5280 static int SigTestBidirec01 (void)
5281 {
5282  Signature *sig = NULL;
5283  int result = 0;
5284 
5286  if (de_ctx == NULL)
5287  goto end;
5288 
5289  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
5290  if (sig == NULL)
5291  goto end;
5292  if (sig->next != NULL)
5293  goto end;
5295  goto end;
5296  if (de_ctx->signum != 1)
5297  goto end;
5298 
5299  result = 1;
5300 
5301 end:
5302  if (de_ctx != NULL) {
5306  }
5307  return result;
5308 }
5309 
5310 /** \test Ensure that we set a bidirectional Signature correctly */
5311 static int SigTestBidirec02 (void)
5312 {
5313  int result = 0;
5314  Signature *sig = NULL;
5315  Signature *copy = NULL;
5316 
5318  if (de_ctx == NULL)
5319  goto end;
5320 
5321  de_ctx->flags |= DE_QUIET;
5322 
5323  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
5324  if (sig == NULL)
5325  goto end;
5326  if (de_ctx->sig_list != sig)
5327  goto end;
5329  goto end;
5330  if (sig->next == NULL)
5331  goto end;
5332  if (de_ctx->signum != 2)
5333  goto end;
5334  copy = sig->next;
5335  if (copy->next != NULL)
5336  goto end;
5337  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
5338  goto end;
5339 
5340  result = 1;
5341 
5342 end:
5343  if (de_ctx != NULL) {
5347  }
5348 
5349  return result;
5350 }
5351 
5352 /** \test Ensure that we set a bidirectional Signature correctly
5353 * and we install it with the rest of the signatures, checking
5354 * also that it match with the correct addr directions
5355 */
5356 static int SigTestBidirec03 (void)
5357 {
5358  int result = 0;
5359  Signature *sig = NULL;
5360  Packet *p = NULL;
5361 
5363  if (de_ctx == NULL)
5364  goto end;
5365 
5366  de_ctx->flags |= DE_QUIET;
5367 
5368  const char *sigs[3];
5369  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
5370  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
5371  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
5372  UTHAppendSigs(de_ctx, sigs, 3);
5373 
5374  /* Checking that bidirectional rules are set correctly */
5375  sig = de_ctx->sig_list;
5376  if (sig == NULL)
5377  goto end;
5378  if (sig->next == NULL)
5379  goto end;
5380  if (sig->next->next == NULL)
5381  goto end;
5382  if (sig->next->next->next == NULL)
5383  goto end;
5384  if (sig->next->next->next->next != NULL)
5385  goto end;
5386  if (de_ctx->signum != 4)
5387  goto end;
5388 
5389  uint8_t rawpkt1_ether[] = {
5390  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
5391  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
5392  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
5393  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
5394  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
5395  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
5396  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
5397  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
5398  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
5399  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
5400  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
5401  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
5402  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
5403  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
5404  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
5405  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
5406  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
5407  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
5408  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
5409  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
5410  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
5411  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
5412  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
5413  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
5414  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
5415  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
5416  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
5417  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
5418  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
5419  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
5420  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
5421  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
5422  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
5423  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
5424  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5425  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5426  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
5427  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
5428  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
5429  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
5430  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
5431  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
5432  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
5433  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5434  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
5435  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
5436  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
5437  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
5438  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5439  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
5440  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
5441  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
5442  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
5443  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
5444  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
5445 
5447  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
5448  if (p == NULL) {
5449  SCLogDebug("Error building packet");
5450  goto end;
5451  }
5452  UTHMatchPackets(de_ctx, &p, 1);
5453 
5454  uint32_t sids[3] = {1, 2, 3};
5455  uint32_t results[3] = {1, 1, 1};
5456  result = UTHCheckPacketMatchResults(p, sids, results, 1);
5457 
5458 end:
5459  if (p != NULL) {
5460  PacketFree(p);
5461  }
5463  FlowShutdown();
5464  return result;
5465 }
5466 
5467 /** \test Ensure that we set a bidirectional Signature correctly
5468 * and we install it with the rest of the signatures, checking
5469 * also that it match with the correct addr directions
5470 */
5471 static int SigTestBidirec04 (void)
5472 {
5473  int result = 0;
5474  Signature *sig = NULL;
5475  Packet *p = NULL;
5476 
5478  if (de_ctx == NULL)
5479  goto end;
5480 
5481  de_ctx->flags |= DE_QUIET;
5482 
5483  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
5484  if (sig == NULL)
5485  goto end;
5486  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
5487  if (sig == NULL)
5488  goto end;
5489  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
5490  goto end;
5491  if (sig->next == NULL)
5492  goto end;
5493  if (sig->next->next == NULL)
5494  goto end;
5495  if (sig->next->next->next != NULL)
5496  goto end;
5497  if (de_ctx->signum != 3)
5498  goto end;
5499 
5500  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
5501  if (sig == NULL)
5502  goto end;
5503  if (sig->next == NULL)
5504  goto end;
5505  if (sig->next->next == NULL)
5506  goto end;
5507  if (sig->next->next->next == NULL)
5508  goto end;
5509  if (sig->next->next->next->next != NULL)
5510  goto end;
5511  if (de_ctx->signum != 4)
5512  goto end;
5513 
5514  uint8_t rawpkt1_ether[] = {
5515  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
5516  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
5517  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
5518  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
5519  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
5520  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
5521  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
5522  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
5523  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
5524  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
5525  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
5526  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
5527  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
5528  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
5529  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
5530  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
5531  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
5532  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
5533  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
5534  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
5535  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
5536  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
5537  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
5538  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
5539  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
5540  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
5541  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
5542  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
5543  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
5544  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
5545  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
5546  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
5547  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
5548  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
5549  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5550  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5551  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
5552  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
5553  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
5554  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
5555  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
5556  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
5557  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
5558  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
5559  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
5560  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
5561  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
5562  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
5563  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
5564  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
5565  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
5566  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
5567  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
5568  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
5569  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
5570 
5571  p = PacketGetFromAlloc();
5572  if (unlikely(p == NULL))
5573  return 0;
5575  ThreadVars th_v;
5576  DetectEngineThreadCtx *det_ctx;
5577 
5578  memset(&th_v, 0, sizeof(th_v));
5580 
5582  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
5583  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
5584 
5585  /* At this point we have a list of 4 signatures. The last one
5586  is a copy of the second one. If we receive a packet
5587  with source 192.168.1.1 80, all the sids should match */
5588 
5590  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
5591 
5592  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
5593  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
5594  PacketAlertCheck(p, 2) == 1) {
5595  result = 1;
5596  }
5597 
5598  if (p != NULL) {
5599  PacketRecycle(p);
5600  }
5601  FlowShutdown();
5602  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
5603 
5604 end:
5605  if (de_ctx != NULL) {
5607  }
5608 
5609  if (p != NULL)
5610  PacketFree(p);
5612  return result;
5613 }
5614 
5615 /**
5616  * \test check that we don't allow invalid negation options
5617  */
5618 static int SigParseTestNegation01 (void)
5619 {
5622  de_ctx->flags |= DE_QUIET;
5623  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
5624  FAIL_IF_NOT_NULL(s);
5626  PASS;
5627 }
5628 
5629 /**
5630  * \test check that we don't allow invalid negation options
5631  */
5632 static int SigParseTestNegation02 (void)
5633 {
5636  de_ctx->flags |= DE_QUIET;
5638  "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
5639  "classtype:misc-activity; sid:410002; rev:1;)");
5640  FAIL_IF_NOT_NULL(s);
5642  PASS;
5643 }
5644 /**
5645  * \test check that we don't allow invalid negation options
5646  */
5647 static int SigParseTestNegation03 (void)
5648 {
5651  de_ctx->flags |= DE_QUIET;
5653  "alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; "
5654  "classtype:misc-activity; sid:410003; rev:1;)");
5655  FAIL_IF_NOT_NULL(s);
5657  PASS;
5658 }
5659 /**
5660  * \test check that we don't allow invalid negation options
5661  */
5662 static int SigParseTestNegation04 (void)
5663 {
5664  int result = 0;
5666  Signature *s=NULL;
5667 
5669  if (de_ctx == NULL)
5670  goto end;
5671  de_ctx->flags |= DE_QUIET;
5672 
5673  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;)");
5674  if (s != NULL) {
5675  SigFree(de_ctx, s);
5676  goto end;
5677  }
5678 
5679  result = 1;
5680 end:
5681  if (de_ctx != NULL)
5683  return result;
5684 }
5685 /**
5686  * \test check that we don't allow invalid negation options
5687  */
5688 static int SigParseTestNegation05 (void)
5689 {
5690  int result = 0;
5692  Signature *s=NULL;
5693 
5695  if (de_ctx == NULL)
5696  goto end;
5697  de_ctx->flags |= DE_QUIET;
5698 
5699  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;)");
5700  if (s != NULL) {
5701  SigFree(de_ctx, s);
5702  goto end;
5703  }
5704 
5705  result = 1;
5706 end:
5707  if (de_ctx != NULL)
5709  return result;
5710 }
5711 /**
5712  * \test check that we don't allow invalid negation options
5713  */
5714 static int SigParseTestNegation06 (void)
5715 {
5716  int result = 0;
5718  Signature *s=NULL;
5719 
5721  if (de_ctx == NULL)
5722  goto end;
5723  de_ctx->flags |= DE_QUIET;
5724 
5725  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;)");
5726  if (s != NULL) {
5727  SigFree(de_ctx, s);
5728  goto end;
5729  }
5730 
5731  result = 1;
5732 end:
5733  if (de_ctx != NULL)
5735  return result;
5736 }
5737 
5738 /**
5739  * \test check that we don't allow invalid negation options
5740  */
5741 static int SigParseTestNegation07 (void)
5742 {
5745  de_ctx->flags |= DE_QUIET;
5747  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
5748  FAIL_IF_NOT_NULL(s);
5750  PASS;
5751 }
5752 
5753 /**
5754  * \test check valid negation bug 1079
5755  */
5756 static int SigParseTestNegation08 (void)
5757 {
5758  int result = 0;
5760  Signature *s=NULL;
5761 
5763  if (de_ctx == NULL)
5764  goto end;
5765  de_ctx->flags |= DE_QUIET;
5766 
5768  "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
5769  if (s == NULL) {
5770  goto end;
5771  }
5772 
5773  result = 1;
5774 end:
5775  if (de_ctx != NULL)
5777  return result;
5778 }
5779 
5780 /**
5781  * \test mpm
5782  */
5783 static int SigParseTestMpm01 (void)
5784 {
5785  int result = 0;
5786  Signature *sig = NULL;
5787 
5789  if (de_ctx == NULL)
5790  goto end;
5791 
5792  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
5793  if (sig == NULL) {
5794  printf("sig failed to init: ");
5795  goto end;
5796  }
5797 
5798  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5799  printf("sig doesn't have content list: ");
5800  goto end;
5801  }
5802 
5803  result = 1;
5804 end:
5805  if (sig != NULL)
5806  SigFree(de_ctx, sig);
5808  return result;
5809 }
5810 
5811 /**
5812  * \test mpm
5813  */
5814 static int SigParseTestMpm02 (void)
5815 {
5816  int result = 0;
5817  Signature *sig = NULL;
5818 
5820  if (de_ctx == NULL)
5821  goto end;
5822 
5823  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5824  if (sig == NULL) {
5825  printf("sig failed to init: ");
5826  goto end;
5827  }
5828 
5829  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5830  printf("sig doesn't have content list: ");
5831  goto end;
5832  }
5833 
5834  result = 1;
5835 end:
5836  if (sig != NULL)
5837  SigFree(de_ctx, sig);
5839  return result;
5840 }
5841 
5842 /**
5843  * \test test tls (app layer) rule
5844  */
5845 static int SigParseTestAppLayerTLS01(void)
5846 {
5847  int result = 0;
5849  Signature *s=NULL;
5850 
5852  if (de_ctx == NULL)
5853  goto end;
5854  de_ctx->flags |= DE_QUIET;
5855 
5856  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5857  if (s == NULL) {
5858  printf("parsing sig failed: ");
5859  goto end;
5860  }
5861 
5862  if (s->alproto == 0) {
5863  printf("alproto not set: ");
5864  goto end;
5865  }
5866 
5867  result = 1;
5868 end:
5869  if (s != NULL)
5870  SigFree(de_ctx, s);
5871  if (de_ctx != NULL)
5873 
5874  return result;
5875 }
5876 
5877 /**
5878  * \test test tls (app layer) rule
5879  */
5880 static int SigParseTestAppLayerTLS02(void)
5881 {
5882  int result = 0;
5884  Signature *s=NULL;
5885 
5887  if (de_ctx == NULL)
5888  goto end;
5889  de_ctx->flags |= DE_QUIET;
5890 
5891  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5892  if (s == NULL) {
5893  printf("parsing sig failed: ");
5894  goto end;
5895  }
5896 
5897  if (s->alproto == 0) {
5898  printf("alproto not set: ");
5899  goto end;
5900  }
5901 
5902  result = 1;
5903 end:
5904  if (s != NULL)
5905  SigFree(de_ctx, s);
5906  if (de_ctx != NULL)
5908  return result;
5909 }
5910 
5911 /**
5912  * \test test tls (app layer) rule
5913  */
5914 static int SigParseTestAppLayerTLS03(void)
5915 {
5918  de_ctx->flags |= DE_QUIET;
5919 
5921  "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
5922  "tls.version:2.5; sid:410006; rev:1;)");
5923  FAIL_IF_NOT_NULL(s);
5925  PASS;
5926 }
5927 
5928 static int SigParseTestUnbalancedQuotes01(void)
5929 {
5932  de_ctx->flags |= DE_QUIET;
5934  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5935  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5936  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5937  FAIL_IF_NOT_NULL(s);
5939  PASS;
5940 }
5941 
5942 static int SigParseTestContentGtDsize01(void)
5943 {
5946  de_ctx->flags |= DE_QUIET;
5947  Signature *s =
5948  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5949  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5950  "sid:1; rev:1;)");
5951  FAIL_IF_NOT_NULL(s);
5953  PASS;
5954 }
5955 
5956 static int SigParseTestContentGtDsize02(void)
5957 {
5960  de_ctx->flags |= DE_QUIET;
5961  Signature *s =
5962  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5963  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5964  "sid:1; rev:1;)");
5965  FAIL_IF_NOT_NULL(s);
5967  PASS;
5968 }
5969 
5970 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5971 {
5972  int cnt = 0;
5973  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5974  if (sid == s->id)
5975  cnt++;
5976  }
5977  return cnt;
5978 }
5979 
5980 static int SigParseBidirWithSameSrcAndDest01(void)
5981 {
5984  de_ctx->flags |= DE_QUIET;
5985 
5986  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5987  FAIL_IF_NULL(s);
5988  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5990 
5991  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5992  FAIL_IF_NULL(s);
5993  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5995 
5997  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5998  FAIL_IF_NULL(s);
5999  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
6001 
6003  PASS;
6004 }
6005 
6006 static int SigParseBidirWithSameSrcAndDest02(void)
6007 {
6010  de_ctx->flags |= DE_QUIET;
6011 
6012  // Source is a subset of destination
6014  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
6015  FAIL_IF_NULL(s);
6016  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
6018 
6019  // Source is a subset of destination
6021  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
6022  FAIL_IF_NULL(s);
6023  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
6025 
6026  // Source intersects with destination
6028  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
6029  FAIL_IF_NULL(s);
6030  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
6032 
6033  // mix in negation, these are the same
6035  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;)");
6036  FAIL_IF_NULL(s);
6037  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
6039 
6040  // mix in negation, these are not the same
6042  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;)");
6043  FAIL_IF_NULL(s);
6044  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
6046 
6048  PASS;
6049 }
6050 
6051 static int SigParseTestActionReject(void)
6052 {
6055 
6057  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
6058 #ifdef HAVE_LIBNET11
6059  FAIL_IF_NULL(sig);
6061 #else
6062  FAIL_IF_NOT_NULL(sig);
6063 #endif
6064 
6066  PASS;
6067 }
6068 
6069 static int SigParseTestActionDrop(void)
6070 {
6073 
6075  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
6076  FAIL_IF_NULL(sig);
6077  FAIL_IF_NOT(sig->action & ACTION_DROP);
6078 
6080  PASS;
6081 }
6082 
6083 static int SigSetMultiAppProto(void)
6084 {
6085  Signature *s = SigAlloc();
6086  FAIL_IF_NULL(s);
6087 
6088  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
6089  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6090 
6091  // check intersection gives multiple entries
6092  alprotos[0] = 3;
6093  alprotos[1] = 2;
6094  alprotos[2] = ALPROTO_UNKNOWN;
6095  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6096  FAIL_IF(s->init_data->alprotos[0] != 3);
6097  FAIL_IF(s->init_data->alprotos[1] != 2);
6099 
6100  // check single after multiple
6103  FAIL_IF(s->alproto != 3);
6104  alprotos[0] = 4;
6105  alprotos[1] = 3;
6106  alprotos[2] = ALPROTO_UNKNOWN;
6107  // check multiple containing singleton
6108  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6109  FAIL_IF(s->alproto != 3);
6110 
6111  // reset
6112  s->alproto = ALPROTO_UNKNOWN;
6113  alprotos[0] = 1;
6114  alprotos[1] = 2;
6115  alprotos[2] = 3;
6116  alprotos[3] = ALPROTO_UNKNOWN;
6117  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6118  // fail if set single not in multiple
6120 
6122  s->alproto = ALPROTO_UNKNOWN;
6123  alprotos[0] = 1;
6124  alprotos[1] = 2;
6125  alprotos[2] = 3;
6126  alprotos[3] = ALPROTO_UNKNOWN;
6127  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6128  alprotos[0] = 4;
6129  alprotos[1] = 5;
6130  alprotos[2] = ALPROTO_UNKNOWN;
6131  // fail if multiple do not have intersection
6132  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
6133 
6135  s->alproto = ALPROTO_UNKNOWN;
6136  alprotos[0] = 1;
6137  alprotos[1] = 2;
6138  alprotos[2] = 3;
6139  alprotos[3] = ALPROTO_UNKNOWN;
6140  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6141  alprotos[0] = 3;
6142  alprotos[1] = 4;
6143  alprotos[2] = 5;
6144  alprotos[3] = ALPROTO_UNKNOWN;
6145  // check multiple intersect to singleton
6146  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
6147  FAIL_IF(s->alproto != 3);
6148  alprotos[0] = 5;
6149  alprotos[1] = 4;
6150  alprotos[2] = ALPROTO_UNKNOWN;
6151  // fail if multiple do not belong to singleton
6152  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
6153 
6154  SigFree(NULL, s);
6155  PASS;
6156 }
6157 
6158 static int DetectSetupDirection01(void)
6159 {
6160  Signature *s = SigAlloc();
6161  FAIL_IF_NULL(s);
6162  // Basic case : ok
6163  char *str = (char *)"to_client";
6164  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
6165  SigFree(NULL, s);
6166  PASS;
6167 }
6168 
6169 static int DetectSetupDirection02(void)
6170 {
6171  Signature *s = SigAlloc();
6172  FAIL_IF_NULL(s);
6173  char *str = (char *)"to_server";
6174  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
6175  // ok so far
6176  str = (char *)"to_client";
6177  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
6178  // fails because we cannot have both to_client and to_server for same signature
6179  SigFree(NULL, s);
6180  PASS;
6181 }
6182 
6183 static int DetectSetupDirection03(void)
6184 {
6185  Signature *s = SigAlloc();
6186  FAIL_IF_NULL(s);
6187  char *str = (char *)"to_client , something";
6188  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
6189  FAIL_IF(strcmp(str, "something") != 0);
6190  str = (char *)"to_client,something";
6191  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
6192  FAIL_IF(strcmp(str, "something") != 0);
6193  SigFree(NULL, s);
6194  PASS;
6195 }
6196 
6197 static int DetectSetupDirection04(void)
6198 {
6199  Signature *s = SigAlloc();
6200  FAIL_IF_NULL(s);
6201  // invalid case
6202  char *str = (char *)"to_client_toto";
6203  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
6204  // test we do not change the string pointer if only_dir is false
6205  str = (char *)"to_client_toto";
6206  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
6207  FAIL_IF(strcmp(str, "to_client_toto") != 0);
6208  str = (char *)"to_client,something";
6209  // fails because we call with only_dir=true
6210  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
6211  SigFree(NULL, s);
6212  PASS;
6213 }
6214 
6215 #endif /* UNITTESTS */
6216 
6217 #ifdef UNITTESTS
6218 void DetectParseRegisterTests (void);
6219 #include "tests/detect-parse.c"
6220 #endif
6221 
6223 {
6224 #ifdef UNITTESTS
6226 
6227  UtRegisterTest("SigParseTest01", SigParseTest01);
6228  UtRegisterTest("SigParseTest02", SigParseTest02);
6229  UtRegisterTest("SigParseTest03", SigParseTest03);
6230  UtRegisterTest("SigParseTest04", SigParseTest04);
6231  UtRegisterTest("SigParseTest05", SigParseTest05);
6232  UtRegisterTest("SigParseTest06", SigParseTest06);
6233  UtRegisterTest("SigParseTest07", SigParseTest07);
6234  UtRegisterTest("SigParseTest08", SigParseTest08);
6235  UtRegisterTest("SigParseTest09", SigParseTest09);
6236  UtRegisterTest("SigParseTest10", SigParseTest10);
6237  UtRegisterTest("SigParseTest11", SigParseTest11);
6238  UtRegisterTest("SigParseTest12", SigParseTest12);
6239  UtRegisterTest("SigParseTest13", SigParseTest13);
6240  UtRegisterTest("SigParseTest14", SigParseTest14);
6241  UtRegisterTest("SigParseTest15", SigParseTest15);
6242  UtRegisterTest("SigParseTest16", SigParseTest16);
6243  UtRegisterTest("SigParseTest17", SigParseTest17);
6244  UtRegisterTest("SigParseTest18", SigParseTest18);
6245  UtRegisterTest("SigParseTest19", SigParseTest19);
6246  UtRegisterTest("SigParseTest20", SigParseTest20);
6247  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
6248  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
6249  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
6250 
6251  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
6252  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
6253  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
6254  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
6255  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
6256  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
6257  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
6258  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
6259  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
6260  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
6261  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
6262  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
6263  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
6264  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
6265  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
6266  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
6267  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
6268  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
6269  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
6270  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
6271  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
6272  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
6273  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
6274  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
6275  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
6276  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
6277  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
6278 
6279  UtRegisterTest("SigParseTestContentGtDsize01",
6280  SigParseTestContentGtDsize01);
6281  UtRegisterTest("SigParseTestContentGtDsize02",
6282  SigParseTestContentGtDsize02);
6283 
6284  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
6285  SigParseBidirWithSameSrcAndDest01);
6286  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
6287  SigParseBidirWithSameSrcAndDest02);
6288  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
6289  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
6290 
6291  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
6292 
6293  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
6294  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
6295  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
6296  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
6297 
6298 #endif /* UNITTESTS */
6299 }
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:564
SignatureParser_
Definition: detect-parse.c:101
SignatureInitData_::max_content_list_id
uint32_t max_content_list_id
Definition: detect.h:667
host.h
DetectFirewallPolicies
Definition: detect.h:948
SignatureInitData_::total_flowbits
uint16_t total_flowbits
Definition: detect.h:640
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:673
DetectPortCmp
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
Definition: detect-engine-port.c:483
DetectEngineAppInspectionEngine_
Definition: detect.h:416
SC_MATCH_LIMIT_DEFAULT
#define SC_MATCH_LIMIT_DEFAULT
Definition: detect-pcre.h:44
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
SignatureInitDataBuffer_::head
SigMatch * head
Definition: detect.h:536
SigMatch_::prev
struct SigMatch_ * prev
Definition: detect.h:361
detect-content.h
SignatureInitDataBuffer_::sm_init
bool sm_init
Definition: detect.h:528
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:306
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:656
DetectEngineProtoList
void DetectEngineProtoList(void)
Definition: detect-engine-proto.c:74
SignatureHook_
Definition: detect.h:576
DetectParseDupSigHashInit
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3530
SignatureInitData_::list_set
bool list_set
Definition: detect.h:636
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:725
SIG_FLAG_FW_HOOK_LTE
#define SIG_FLAG_FW_HOOK_LTE
Definition: detect.h:251
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:759
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:1505
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:578
DETECT_TABLE_APP_FILTER
@ DETECT_TABLE_APP_FILTER
Definition: detect.h:563
DetectFirewallAppPolicy
Definition: detect.h:937
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:442
SignatureParser_::sp
char sp[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:107
DetectPortListsAreEqual
bool DetectPortListsAreEqual(DetectPort *list1, DetectPort *list2)
Checks if two port group lists are equal.
Definition: detect-engine-port.c: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:1518
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:658
DetectEngineBufferRunSetupCallback
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
Definition: detect-engine.c:1650
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:112
SIG_FLAG_INIT_FLOW
#define SIG_FLAG_INIT_FLOW
Definition: detect.h:291
SIGMATCH_BAN_FIREWALL_RULE
#define SIGMATCH_BAN_FIREWALL_RULE
Definition: detect-engine-register.h:354
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
PORT_EQ
@ PORT_EQ
Definition: detect.h:208
ACTION_PASS
#define ACTION_PASS
Definition: action-globals.h:34
ACTION_REJECT
#define ACTION_REJECT
Definition: action-globals.h:31
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SigDuplWrapper
struct SigDuplWrapper_ SigDuplWrapper
Registration table for file handlers.
Signature_::app_progress_hook
uint8_t app_progress_hook
Definition: detect.h:719
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:2383
DETECT_CONTENT
@ DETECT_CONTENT
Definition: detect-engine-register.h:76
DetectAddress_
address structure for use in the detection engine.
Definition: detect.h:168
SigTableElmt_::flags
uint32_t flags
Definition: detect.h:1509
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:632
SignatureInitData_::src_contains_negation
bool src_contains_negation
Definition: detect.h:608
DetectEngineCtx_::sigerror_silent
bool sigerror_silent
Definition: detect.h:1082
DetectParseRegex::context
pcre2_match_context * context
Definition: detect-parse.h:96
Signature_::alproto
AppProto alproto
Definition: detect.h:687
DETECT_TABLE_PACKET_PRE_STREAM
@ DETECT_TABLE_PACKET_PRE_STREAM
Definition: detect.h:560
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:670
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
SIG_FLAG_INIT_FILEDATA
#define SIG_FLAG_INIT_FILEDATA
Definition: detect.h:300
detect-isdataat.h
IPOnlySigParseAddress
int IPOnlySigParseAddress(const DetectEngineCtx *de_ctx, Signature *s, const char *addrstr, char flag)
Parses an address group sent as a character string and updates the IPOnlyCIDRItem lists src and dst o...
Definition: detect-engine-iponly.c:869
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
SigMatchData_::is_last
bool is_last
Definition: detect.h:367
ActionScopeToString
const char * ActionScopeToString(enum ActionScope s)
Definition: detect-parse.c:4022
SignatureHook_::app
struct SignatureHook_::@87::@88 app
name
const char * name
Definition: detect-engine-proto.c:48
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:87
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:144
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:368
detect-bsize.h
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:316
DetectTable
DetectTable
Definition: detect.h:557
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:3932
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:924
AppProtoToString
const char * AppProtoToString(AppProto alproto)
Maps the ALPROTO_*, to its string equivalent.
Definition: app-layer-protos.c:41
DetectFirewallAppPolicy::sub_state
uint8_t sub_state
Definition: detect.h:939
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:330
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:981
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:388
DetectFirewallAppPolicy::policy
struct DetectFirewallPolicy policy
Definition: detect.h:942
DETECT_STREAM_SIZE
@ DETECT_STREAM_SIZE
Definition: detect-engine-register.h:127
SIGNATURE_HOOK_PKT_NOT_SET
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition: detect.h:541
DetectFirewallPolicies::pkt_policy_signatures
Signature * pkt_policy_signatures[DETECT_FIREWALL_POLICY_SIZE]
Definition: detect.h:951
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
SIG_FLAG_INIT_FORCE_TOCLIENT
#define SIG_FLAG_INIT_FORCE_TOCLIENT
Definition: detect.h:301
AppLayerParserGetStateIdByName
int AppLayerParserGetStateIdByName(uint8_t ipproto, AppProto alproto, const char *name, const uint8_t direction)
Definition: app-layer-parser.c:1858
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2872
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:1485
SIG_DIREC_SRC
@ SIG_DIREC_SRC
Definition: detect-parse.h:49
UTHCheckPacketMatchResults
int UTHCheckPacketMatchResults(Packet *p, uint32_t sids[], uint32_t results[], int numsigs)
UTHCheckPacketMatches: function to check if a packet match some sids.
Definition: util-unittest-helper.c:620
SIG_FLAG_DST_ANY
#define SIG_FLAG_DST_ANY
Definition: detect.h:241
ACTION_SCOPE_FLOW
@ ACTION_SCOPE_FLOW
Definition: action-globals.h:45
SIG_FLAG_REQUIRE_STREAM
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:254
HashTable_
Definition: util-hash.h:35
SIG_FLAG_TXBOTHDIR
#define SIG_FLAG_TXBOTHDIR
Definition: detect.h:249
MIN
#define MIN(x, y)
Definition: suricata-common.h:416
DetectParseRegex::regex
pcre2_code * regex
Definition: detect-parse.h:95
ACTION_REJECT_ANY
#define ACTION_REJECT_ANY
Definition: action-globals.h:38
DetectKeywordId
DetectKeywordId
Definition: detect-engine-register.h:27
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
DetectGetLastSMByListPtr
SigMatch * DetectGetLastSMByListPtr(const Signature *s, SigMatch *sm_list,...)
Returns the sm with the largest index (added last) from the list passed to us as a pointer.
Definition: detect-parse.c:625
DetectRegisterAppLayerHookLists
void DetectRegisterAppLayerHookLists(void)
register app hooks as generic lists
Definition: detect-parse.c:1156
DetectEngineCtx_::sigerror_requires
bool sigerror_requires
Definition: detect.h:1086
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:3058
FILE_SIG_NEED_FILENAME
#define FILE_SIG_NEED_FILENAME
Definition: detect.h:321
SignatureInitDataBuffer_::multi_capable
bool multi_capable
Definition: detect.h:531
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:745
DetectFirewallInitDefaultPolicies
int DetectFirewallInitDefaultPolicies(DetectEngineCtx *de_ctx)
allocate and initialize to default values the policies table
Definition: detect-parse.c:4311
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:1120
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:615
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3547
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3856
DetectBufferType_
Definition: detect.h:450
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:1083
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:2461
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:245
EngineModeIsFirewall
bool EngineModeIsFirewall(void)
Definition: suricata.c:239
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:271
MAX
#define MAX(x, y)
Definition: suricata-common.h:420
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:240
SigTableElmt_
element in sigmatch type table.
Definition: detect.h:1478
SigMatchData_
Data needed for Match()
Definition: detect.h:365
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1500
DetectFlowSetupImplicit
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
Definition: detect-flow.c:341
DetectFirewallAppPolicy::alert_signature
Signature * alert_signature
Definition: detect.h:945
detect-pcre.h
SigMatchData_::type
uint16_t type
Definition: detect.h:366
DetectMatchAddressIPv4_::ip
uint32_t ip
Definition: detect.h:190
DetectFirewallPolicy::action
uint8_t action
Definition: detect.h:933
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:3892
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:356
SIG_FLAG_APPLAYER
#define SIG_FLAG_APPLAYER
Definition: detect.h:248
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:1455
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:913
SIG_FLAG_FIREWALL
#define SIG_FLAG_FIREWALL
Definition: detect.h:245
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
detect-reference.h
Signature_::gid
uint32_t gid
Definition: detect.h:728
DetectMatchAddressIPv6_::ip2
uint32_t ip2[4]
Definition: detect.h:196
SIGNATURE_HOOK_TYPE_APP
@ SIGNATURE_HOOK_TYPE_APP
Definition: detect.h:551
Signature_::next
struct Signature_ * next
Definition: detect.h:764
ACTION_REJECT_DST
#define ACTION_REJECT_DST
Definition: action-globals.h:32
DetectParseFreeRegexes
void DetectParseFreeRegexes(void)
Definition: detect-parse.c:3876
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:424
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:577
UTHMatchPackets
int UTHMatchPackets(DetectEngineCtx *de_ctx, Packet **p, int num_packets)
Definition: util-unittest-helper.c:729
SIGMATCH_SUPPORT_DIR
#define SIGMATCH_SUPPORT_DIR
Definition: detect-engine-register.h:336
app-layer-detect-proto.h
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:127
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:270
app-layer-htp.h
DetectPortParse
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
Definition: detect-engine-port.c:1135
detect-app-layer-event.h
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:72
HashListTableInit
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
Signature_::addr_src_match4
DetectMatchAddressIPv4 * addr_src_match4
Definition: detect.h:722
SigParseRegisterTests
void SigParseRegisterTests(void)
Definition: detect-parse.c:6222
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:1012
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:292
DetectProtoParse
int DetectProtoParse(DetectProto *dp, const char *str)
Parses a protocol sent as a string.
Definition: detect-engine-proto.c:90
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:30
SignatureInitData_::buffers_size
uint32_t buffers_size
Definition: detect.h:663
SigFree
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-parse.c:2286
DetectEngineThreadCtx_
Definition: detect.h:1300
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:630
g_skip_prefilter
int g_skip_prefilter
Definition: detect-engine-mpm.c:1159
SignatureInitData_::src
const DetectAddressHead * src
Definition: detect.h:653
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:628
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:625
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3982
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
SignatureInitData_::list
int list
Definition: detect.h:635
DetectEngineCtx_::max_flowbits
uint8_t max_flowbits
Definition: detect.h:985
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
detect-engine-mpm.h
Signature_::references
DetectReference * references
Definition: detect.h:755
SigTableElmt_::tables
uint8_t tables
Definition: detect.h:1513
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:1167
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:2597
SignatureHookPkt
SignatureHookPkt
Definition: detect.h:540
pkt-var.h
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3620
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
DetectFirewallPolicies::pkt
struct DetectFirewallPolicy pkt[DETECT_FIREWALL_POLICY_SIZE]
Definition: detect.h:950
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:559
detect-engine-port.h
SignatureInitData_::proto
DetectProto proto
Definition: detect.h:645
SigDuplWrapper_::s
Signature * s
Definition: detect-parse.c:95
DETECT_TABLE_PACKET_FILTER
@ DETECT_TABLE_PACKET_FILTER
Definition: detect.h:561
DetectFirewallAppPolicy::progress
uint8_t progress
Definition: detect.h:940
DetectFirewallPolicyToString
void DetectFirewallPolicyToString(const struct DetectFirewallPolicy *p, char *out, size_t out_size)
Definition: detect-parse.c:4040
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:3970
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3455
DetectPort_
Port structure for detection engine.
Definition: detect.h:219
SignatureHook_::pkt
struct SignatureHook_::@87::@89 pkt
SigTableElmt_::alternative
uint16_t alternative
Definition: detect.h:1516
SignatureInitData_::cidr_src
IPOnlyCIDRItem * cidr_src
Definition: detect.h:625
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:359
DetectReference_
Signature reference list.
Definition: detect-reference.h:30
SignatureInitData_::hook
SignatureHook hook
Definition: detect.h:597
SIGNATURE_HOOK_TYPE_NOT_SET
@ SIGNATURE_HOOK_TYPE_NOT_SET
Definition: detect.h:549
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:2366
Signature_::action
uint8_t action
Definition: detect.h:697
util-profiling.h
util-rule-vars.h
SignatureHookType
SignatureHookType
Definition: detect.h:548
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:683
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:456
DetectContentData_::flags
uint32_t flags
Definition: detect-content.h:104
DETECT_MAX_RULE_SIZE
#define DETECT_MAX_RULE_SIZE
Definition: detect.h:46
SignatureParser_::direction
char direction[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:104
detect-ipproto.h
DetectEngineBufferTypeGetById
const DetectBufferType * DetectEngineBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1475
SignatureInitDataBufferCheckExpand
int SignatureInitDataBufferCheckExpand(Signature *s)
check if buffers array still has space left, expand if not
Definition: detect-parse.c:2146
DETECT_TABLE_PACKET_TD
@ DETECT_TABLE_PACKET_TD
Definition: detect.h:562
DetectBufferType_::name
char name[64]
Definition: detect.h:451
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:761
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:604
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1480
SignatureInitData_
Definition: detect.h:596
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:609
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:392
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
Signature_::addr_dst_match6_cnt
uint16_t addr_dst_match6_cnt
Definition: detect.h:709
SIG_TYPE_DEONLY
@ SIG_TYPE_DEONLY
Definition: detect.h:71
SIGNATURE_HOOK_PKT_PRE_STREAM
@ SIGNATURE_HOOK_PKT_PRE_STREAM
Definition: detect.h:544
DetectReference_::next
struct DetectReference_ * next
Definition: detect-reference.h:43
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:274
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:78
SIG_ALPROTO_MAX
#define SIG_ALPROTO_MAX
Definition: detect.h:594
Signature_::sp
DetectPort * sp
Definition: detect.h:733
DetectMetadata_
Signature metadata list.
Definition: detect-metadata.h:30
DETECT_FIREWALL_POLICY_PRE_STREAM
@ DETECT_FIREWALL_POLICY_PRE_STREAM
Definition: detect.h:927
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect-engine-register.h:320
SCSigMatchSilentErrorEnabled
bool SCSigMatchSilentErrorEnabled(const DetectEngineCtx *de_ctx, uint16_t id)
Definition: detect-parse.c:330
IPOnlyCIDRListFree
void IPOnlyCIDRListFree(IPOnlyCIDRItem *tmphead)
This function free a IPOnlyCIDRItem list.
Definition: detect-engine-iponly.c:482
Flow_::next
struct Flow_ * next
Definition: flow.h:401
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2295
DetectEngineBufferTypeSupportsMpmGetById
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1622
DetectEngineCtx_::dup_sig_hash_table
HashListTable * dup_sig_hash_table
Definition: detect.h:1021
DetectEngineCtx_::config_prefix
char config_prefix[64]
Definition: detect.h:1107
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:34
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1333
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:417
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
SigMatchCtx_
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition: detect.h:351
DETECT_SM_LIST_NOTSET
#define DETECT_SM_LIST_NOTSET
Definition: detect.h:144
DetectAbsentValidateContentCallback
bool DetectAbsentValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-isdataat.c:118
ACTION_REJECT_BOTH
#define ACTION_REJECT_BOTH
Definition: action-globals.h:33
SigTableApplyStrictCommandLineOption
void SigTableApplyStrictCommandLineOption(const char *str)
Definition: detect-parse.c:343
SignatureInitDataBuffer_::tail
SigMatch * tail
Definition: detect.h:537
DetectAddressHead_::ipv6_head
DetectAddress * ipv6_head
Definition: detect.h:185
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:457
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:3802
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:1519
DetectFirewallLoadDefaultPolicies
int DetectFirewallLoadDefaultPolicies(DetectEngineCtx *de_ctx)
Definition: detect-parse.c:4336
suricata-common.h
SigMatch_::idx
uint16_t idx
Definition: detect.h:358
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:242
ActionScope
ActionScope
Definition: action-globals.h:42
SigMatch_::type
uint16_t type
Definition: detect.h:357
DETECT_FIREWALL_POLICY_PACKET_FILTER
@ DETECT_FIREWALL_POLICY_PACKET_FILTER
Definition: detect.h:925
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:698
SIG_FLAG_INIT_FORCE_TOSERVER
#define SIG_FLAG_INIT_FORCE_TOSERVER
Definition: detect.h:302
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:721
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
SIGMATCH_OPTIONAL_OPT
#define SIGMATCH_OPTIONAL_OPT
Definition: detect-engine-register.h:313
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:704
packet.h
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SignatureInitData_::curbuf
SignatureInitDataBuffer * curbuf
Definition: detect.h:664
SignatureHook_::type
enum SignatureHookType type
Definition: detect.h:577
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:3865
SIG_FLAG_INIT_PACKET
#define SIG_FLAG_INIT_PACKET
Definition: detect.h:290
SignatureParser_::dst
char dst[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:106
DetectListToString
const char * DetectListToString(int list)
Definition: detect-parse.c:130
SIGNATURE_HOOK_PKT_PRE_FLOW
@ SIGNATURE_HOOK_PKT_PRE_FLOW
Definition: detect.h:543
DetectMatchAddressIPv4_::ip2
uint32_t ip2
Definition: detect.h:191
Signature_::rev
uint32_t rev
Definition: detect.h:729
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:600
Signature_::proto
DetectProto * proto
Definition: detect.h:701
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:550
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:991
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:2123
DetectEngineAppInspectionEngineSignatureFree
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
free app inspect engines for a signature
Definition: detect-engine.c:1106
ACTION_CONFIG
#define ACTION_CONFIG
Definition: action-globals.h:35
DETECT_SM_LIST_TMATCH
@ DETECT_SM_LIST_TMATCH
Definition: detect.h:129
TransformData_::transform
int transform
Definition: detect.h:387
SignatureParser
struct SignatureParser_ SignatureParser
Signature_::prio
int prio
Definition: detect.h:730
DetectEngineCtx_::sm_types_silent_error
bool * sm_types_silent_error
Definition: detect.h:1168
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:195
SIGMATCH_STRICT_PARSING
#define SIGMATCH_STRICT_PARSING
Definition: detect-engine-register.h:332
SignatureInitDataBuffer_::only_ts
bool only_ts
Definition: detect.h:534
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:710
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:661
DetectEngineCtx_::app_inspect_engines
DetectEngineAppInspectionEngine * app_inspect_engines
Definition: detect.h:1143
SignatureInitData_::dst
const DetectAddressHead * dst
Definition: detect.h:653
SignatureInitData_::firewall_rule
bool firewall_rule
Definition: detect.h:678
SIGNATURE_HOOK_PKT_ALL
@ SIGNATURE_HOOK_PKT_ALL
Definition: detect.h:545
Signature_::dp
DetectPort * dp
Definition: detect.h:733
str
#define str(s)
Definition: suricata-common.h:316
detect-http-method.h
Signature_::metadata
DetectMetadataHead * metadata
Definition: detect.h:757
DetectFirewallPolicy
Definition: detect.h:932
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:264
Signature_::iid
SigIntId iid
Definition: detect.h:694
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:427
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:1502
Signature_::addr_dst_match6
DetectMatchAddressIPv6 * addr_dst_match6
Definition: detect.h:724
Signature_::id
uint32_t id
Definition: detect.h:727
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
DetectMetadata_::next
struct DetectMetadata_ * next
Definition: detect-metadata.h:36
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
detect-engine-iponly.h
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
SignatureInitDataBuffer_::id
uint32_t id
Definition: detect.h:527
Signature_
Signature container.
Definition: detect.h:682
SigMatch_
a single match condition for a signature
Definition: detect.h:356
DETECT_SM_LIST_MAX
@ DETECT_SM_LIST_MAX
Definition: detect.h:135
ALPROTO_HTTP
@ ALPROTO_HTTP
Definition: app-layer-protos.h:77
DETECT_PROTO_ONLY_PKT
#define DETECT_PROTO_ONLY_PKT
Definition: detect-engine-proto.h:29
HashTableInit
HashTable * HashTableInit(uint32_t size, uint32_t(*Hash)(struct HashTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hash.c:35
UTHBuildPacketFromEth
Packet * UTHBuildPacketFromEth(uint8_t *raw_eth, uint16_t pktsize)
UTHBuildPacketFromEth is a wrapper that build a packet for the rawbytes.
Definition: util-unittest-helper.c:381
DetectMatchAddressIPv6_
Definition: detect.h:194
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
ALPROTO_FAILED
@ ALPROTO_FAILED
Definition: app-layer-protos.h:33
DetectMatchAddressIPv4_
Definition: detect.h:189
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2833
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:612
SignatureSetType
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-build.c:1699
app-layer-protos.h
SC_Pcre2SubstringCopy
int SC_Pcre2SubstringCopy(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
Definition: detect-parse.c:3958
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:542
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:393
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect-engine-register.h:334
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:926
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:418
Signature_::detect_table
uint8_t detect_table
Definition: detect.h:716
DetectParseAddress
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
Definition: detect-engine-address.c:1432
SignatureInitDataBuffer_::only_tc
bool only_tc
Definition: detect.h:533
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:1669
DetectEngineCtx_::sigerror
const char * sigerror
Definition: detect.h:1081
DetectParseFreeRegex
void DetectParseFreeRegex(DetectParseRegex *r)
Definition: detect-parse.c:3866
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:983
AppLayerParserSupportsSubStates
bool AppLayerParserSupportsSubStates(const AppProto alproto)
Definition: app-layer-parser.c:1382
DetectFirewallAppPolicy::alproto
AppProto alproto
Definition: detect.h:938
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:2166
SignatureInitData_::transforms
DetectEngineTransforms transforms
Definition: detect.h:642
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:954
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
Signature_::addr_dst_match4
DetectMatchAddressIPv4 * addr_dst_match4
Definition: detect.h:721
DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_REPLACE
Definition: detect-content.h:51
Signature_::msg
char * msg
Definition: detect.h:750
flow.h
SignatureInitDataBuffer_
Definition: detect.h:526
Signature_::addr_src_match4_cnt
uint16_t addr_src_match4_cnt
Definition: detect.h:708
DetectFirewallPolicy::action_scope
uint8_t action_scope
Definition: detect.h:934
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:707
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:685
SCConfNode_
Definition: conf.h:37
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:1003
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:662
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:3903
SCConfNode_::val
char * val
Definition: conf.h:39
DetectFirewallAppPolicy::direction
uint8_t direction
Definition: detect.h:941
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect-engine-register.h:324
DetectPortCleanupList
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
Definition: detect-engine-port.c:124
DETECT_SM_LIST_SUPPRESS
@ DETECT_SM_LIST_SUPPRESS
Definition: detect.h:132
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:109
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
SCClassConfLoadClassificationConfigFile
bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
Definition: util-classification-config.c:520
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:277
DetectAddressHead_::ipv4_head
DetectAddress * ipv4_head
Definition: detect.h:184
detect-engine-address.h
DetectFirewallRuleAppendNew
Signature * DetectFirewallRuleAppendNew(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3730
SIG_FLAG_FILESTORE
#define SIG_FLAG_FILESTORE
Definition: detect.h:268
DETECT_CONTENT_WITHIN
#define DETECT_CONTENT_WITHIN
Definition: detect-content.h:31
detect-parse.c
SIG_DIREC_NORMAL
@ SIG_DIREC_NORMAL
Definition: detect-parse.h:42
SIG_FLAG_DP_ANY
#define SIG_FLAG_DP_ANY
Definition: detect.h:243
AppLayerProtoDetectGetProtoName
const char * AppLayerProtoDetectGetProtoName(AppProto alproto)
Definition: app-layer-detect-proto.c:2124
RetrieveFPForSig
void RetrieveFPForSig(const DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-mpm.c:1181
DetectListSupportedProtocols
void DetectListSupportedProtocols(void)
Definition: detect-parse.c:1536
app-layer.h
SignatureInitData_::alprotos
AppProto alprotos[SIG_ALPROTO_MAX]
Definition: detect.h:619
DetectEngineAppInspectionEngine_::progress
uint8_t progress
Definition: detect.h:426
SCClassConfDeInitContext
void SCClassConfDeInitContext(DetectEngineCtx *de_ctx)
Releases resources used by the Classification Config API.
Definition: util-classification-config.c:191
DetectProtoContainsProto
int DetectProtoContainsProto(const DetectProto *dp, int proto)
see if a DetectProto contains a certain proto
Definition: detect-engine-proto.c:115
DetectProtoFinalizeSignature
int DetectProtoFinalizeSignature(Signature *s)
Definition: detect-engine-proto.c:157
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:253