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