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