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