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