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