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  struct BufferVsDir {
2559  int ts;
2560  int tc;
2561  } bufdir[nlists + 1];
2562  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2563 
2564  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2567  if (bt == NULL) {
2568  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2569  continue;
2570  }
2571  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2572  for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2573  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2574  }
2575 
2576  if (b->head == NULL) {
2577  SCLogError("no matches in sticky buffer %s", bt->name);
2578  SCReturnInt(0);
2579  }
2580 
2581  has_frame |= bt->frame;
2582  has_app |= (!bt->frame && !bt->packet);
2583  has_pkt |= bt->packet;
2584 
2585  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2586  SCLogError("Signature combines packet "
2587  "specific matches (like dsize, flags, ttl) with stream / "
2588  "state matching by matching on app layer proto (like using "
2589  "http_* keywords).");
2590  SCReturnInt(0);
2591  }
2592 
2594  for (; app != NULL; app = app->next) {
2595  if (app->sm_list == b->id &&
2596  (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2597  SCLogDebug("engine %s dir %d alproto %d",
2599  app->alproto);
2600  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2601 
2602  if (b->only_tc) {
2603  if (app->dir == 1)
2604  (*tc_excl)++;
2605  } else if (b->only_ts) {
2606  if (app->dir == 0)
2607  (*ts_excl)++;
2608  } else {
2609  bufdir[b->id].ts += (app->dir == 0);
2610  bufdir[b->id].tc += (app->dir == 1);
2611  }
2612 
2613  /* only allow rules to use the hook for engines at that
2614  * exact progress for now. */
2616  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2617  app->progress != s->init_data->hook.t.app.app_progress) {
2618  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2619  s->init_data->hook.t.app.app_progress);
2620  SCReturnInt(0);
2621  }
2622  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2623  app->progress != s->init_data->hook.t.app.app_progress) {
2624  SCLogError("engine progress value doesn't match hook");
2625  SCReturnInt(0);
2626  }
2627  }
2628  }
2629  }
2630 
2632  SCReturnInt(0);
2633  }
2634 
2636  SCReturnInt(0);
2637  }
2639  SCReturnInt(0);
2640  }
2641  }
2642 
2643  if (has_pmatch && has_frame) {
2644  SCLogError("can't mix pure content and frame inspection");
2645  SCReturnInt(0);
2646  }
2647  if (has_app && has_frame) {
2648  SCLogError("can't mix app-layer buffer and frame inspection");
2649  SCReturnInt(0);
2650  }
2651  if (has_pkt && has_frame) {
2652  SCLogError("can't mix pkt buffer and frame inspection");
2653  SCReturnInt(0);
2654  }
2655 
2656  for (int x = 0; x < nlists; x++) {
2657  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2658  continue;
2659  (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2660  (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2661  (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2662 
2663  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2664  bufdir[x].tc);
2665  }
2666 
2667  SCReturnInt(1);
2668 }
2669 
2670 static int SigValidatePacketStream(const Signature *s)
2671 {
2673  SCLogError("can't mix packet keywords with "
2674  "tcp-stream or flow:only_stream. Invalidating signature.");
2675  SCReturnInt(0);
2676  }
2677  SCReturnInt(1);
2678 }
2679 
2680 static int SigConsolidateDirection(
2681  Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2682 {
2683  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2684  if (!ts_excl || !tc_excl) {
2685  SCLogError("rule %u should use both directions, but does not", s->id);
2686  SCReturnInt(0);
2687  }
2688  if (dir_amb) {
2689  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2690  "directions",
2691  s->id);
2692  SCReturnInt(0);
2693  }
2694  } else if (ts_excl && tc_excl) {
2695  SCLogError(
2696  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2697  "should be used",
2698  s->id);
2699  SCReturnInt(0);
2700  } else if (ts_excl) {
2701  SCLogDebug("%u: implied rule direction is toserver", s->id);
2703  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2704  SCReturnInt(0);
2705  }
2706  } else if (tc_excl) {
2707  SCLogDebug("%u: implied rule direction is toclient", s->id);
2709  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2710  SCReturnInt(0);
2711  }
2712  } else if (dir_amb) {
2713  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2714  }
2715  SCReturnInt(1);
2716 }
2717 
2718 static void SigConsolidateTcpBuffer(Signature *s)
2719 {
2720  /* TCP: corner cases:
2721  * - pkt vs stream vs depth/offset
2722  * - pkt vs stream vs stream_size
2723  */
2724  if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
2728  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2729  sm = sm->next) {
2730  if (sm->type == DETECT_CONTENT &&
2731  (((DetectContentData *)(sm->ctx))->flags &
2734  break;
2735  }
2736  }
2737  /* if stream_size is in use, also inspect packets */
2738  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2739  sm = sm->next) {
2740  if (sm->type == DETECT_STREAM_SIZE) {
2742  break;
2743  }
2744  }
2745  }
2746  }
2747  }
2748 }
2749 
2750 static bool SigInspectsFiles(const Signature *s)
2751 {
2752  return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2754 }
2755 
2756 /** \internal
2757  * \brief validate file handling
2758  * \retval 1 good signature
2759  * \retval 0 bad signature
2760  */
2761 static int SigValidateFileHandling(const Signature *s)
2762 {
2763  if (!SigInspectsFiles(s)) {
2764  SCReturnInt(1);
2765  }
2766 
2767  if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
2768  !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
2769  SCLogError("protocol %s doesn't "
2770  "support file matching",
2772  SCReturnInt(0);
2773  }
2774  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2775  bool found = false;
2776  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2777  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2778  break;
2779  }
2780  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
2781  AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
2782  found = true;
2783  break;
2784  }
2785  }
2786  if (!found) {
2787  SCLogError("No protocol support file matching");
2788  SCReturnInt(0);
2789  }
2790  }
2792  SCLogError("protocol HTTP2 doesn't support file name matching");
2793  SCReturnInt(0);
2794  }
2795  SCReturnInt(1);
2796 }
2797 
2798 /**
2799  * \internal
2800  * \brief validate and consolidate parsed signature
2801  *
2802  * \param de_ctx detect engine
2803  * \param s signature to validate and consolidate
2804  *
2805  * \retval 0 invalid
2806  * \retval 1 valid
2807  */
2808 static int SigValidateConsolidate(
2809  DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2810 {
2811  SCEnter();
2812 
2813  if (SigValidateFirewall(de_ctx, s) == 0)
2814  SCReturnInt(0);
2815 
2816  if (SigValidatePacketStream(s) == 0) {
2817  SCReturnInt(0);
2818  }
2819 
2820  int ts_excl = 0;
2821  int tc_excl = 0;
2822  int dir_amb = 0;
2823 
2824  if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
2825  SCReturnInt(0);
2826  }
2827 
2828  if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
2829  SCReturnInt(0);
2830  }
2831 
2832  SigConsolidateTcpBuffer(s);
2833 
2835  DetectRuleSetTable(s);
2836 
2837  int r = SigValidateFileHandling(s);
2838  if (r == 0) {
2839  SCReturnInt(0);
2840  }
2841  if (SigInspectsFiles(s)) {
2842  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2844  }
2845  }
2846  if (DetectRuleValidateTable(s) == false) {
2847  SCReturnInt(0);
2848  }
2849 
2850  if (s->type == SIG_TYPE_IPONLY) {
2851  /* For IPOnly */
2852  if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
2853  SCReturnInt(0);
2854 
2855  if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
2856  SCReturnInt(0);
2857  }
2858  SCReturnInt(1);
2859 }
2860 
2861 /**
2862  * \internal
2863  * \brief Helper function for SigInit().
2864  */
2865 static Signature *SigInitHelper(
2866  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2867 {
2868  SignatureParser parser;
2869  memset(&parser, 0x00, sizeof(parser));
2870 
2871  Signature *sig = SigAlloc();
2872  if (sig == NULL)
2873  goto error;
2874  if (firewall_rule) {
2875  sig->init_data->firewall_rule = true;
2876  sig->flags |= SIG_FLAG_FIREWALL;
2877  }
2878 
2879  sig->sig_str = SCStrdup(sigstr);
2880  if (unlikely(sig->sig_str == NULL)) {
2881  goto error;
2882  }
2883 
2884  /* default gid to 1 */
2885  sig->gid = 1;
2886 
2887  /* We do a first parse of the rule in a requires, or scan-only
2888  * mode. Syntactic errors will be picked up here, but the only
2889  * part of the rule that is validated completely is the "requires"
2890  * keyword. */
2891  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
2892  if (ret == -4) {
2893  /* Rule requirements not met. */
2894  de_ctx->sigerror_silent = true;
2895  de_ctx->sigerror_ok = true;
2896  de_ctx->sigerror_requires = true;
2897  goto error;
2898  } else if (ret < 0) {
2899  goto error;
2900  }
2901 
2902  /* Check for a SID before continuuing. */
2903  if (sig->id == 0) {
2904  SCLogError("Signature missing required value \"sid\".");
2905  goto error;
2906  }
2907 
2908  /* Now completely parse the rule. */
2909  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2910  BUG_ON(ret == -4);
2911  if (ret == -3) {
2912  de_ctx->sigerror_silent = true;
2913  de_ctx->sigerror_ok = true;
2914  goto error;
2915  } else if (ret == -2) {
2916  de_ctx->sigerror_silent = true;
2917  goto error;
2918  } else if (ret < 0) {
2919  goto error;
2920  }
2921 
2922  /* signature priority hasn't been overwritten. Using default priority */
2923  if (sig->prio == -1)
2924  sig->prio = DETECT_DEFAULT_PRIO;
2925 
2926  sig->iid = de_ctx->signum;
2927  de_ctx->signum++;
2928 
2929  if (sig->alproto != ALPROTO_UNKNOWN) {
2930  int override_needed = 0;
2931  if (sig->proto.flags & DETECT_PROTO_ANY) {
2932  sig->proto.flags &= ~DETECT_PROTO_ANY;
2933  memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
2934  override_needed = 1;
2935  } else {
2936  override_needed = 1;
2937  size_t s = 0;
2938  for (s = 0; s < sizeof(sig->proto.proto); s++) {
2939  if (sig->proto.proto[s] != 0x00) {
2940  override_needed = 0;
2941  break;
2942  }
2943  }
2944  }
2945 
2946  /* at this point if we had alert ip and the ip proto was not
2947  * overridden, we use the ip proto that has been configured
2948  * against the app proto in use. */
2949  if (override_needed)
2951  }
2952 
2953  /* set the packet and app layer flags, but only if the
2954  * app layer flag wasn't already set in which case we
2955  * only consider the app layer */
2956  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
2957  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
2959  for ( ; sm != NULL; sm = sm->next) {
2960  if (sigmatch_table[sm->type].Match != NULL)
2962  }
2963  } else {
2965  }
2966  }
2967 
2968  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
2969  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
2970  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
2972  }
2973  }
2974  }
2975 
2976  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
2977  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
2978  sig->flags |= SIG_FLAG_TOSERVER;
2979  sig->flags |= SIG_FLAG_TOCLIENT;
2980  }
2981  }
2982 
2983  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
2984  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
2985  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
2986 
2987  SigBuildAddressMatchArray(sig);
2988 
2989  /* run buffer type callbacks if any */
2990  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
2991  if (sig->init_data->smlists[x])
2993  }
2994  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
2996  }
2997 
2998  SigSetupPrefilter(de_ctx, sig);
2999 
3000  /* validate signature, SigValidate will report the error reason */
3001  if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3002  goto error;
3003  }
3004 
3005  return sig;
3006 
3007 error:
3008  if (sig != NULL) {
3009  SigFree(de_ctx, sig);
3010  }
3011  return NULL;
3012 }
3013 
3014 /**
3015  * \brief Checks if a signature has the same source and destination
3016  * \param s parsed signature
3017  *
3018  * \retval true if source and destination are the same, false otherwise
3019  */
3020 static bool SigHasSameSourceAndDestination(const Signature *s)
3021 {
3022  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3023  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3024  return false;
3025  }
3026  }
3027 
3028  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3031 
3033  return false;
3034  }
3035 
3036  src = s->init_data->src->ipv6_head;
3037  dst = s->init_data->dst->ipv6_head;
3038 
3040  return false;
3041  }
3042  }
3043 
3044  return true;
3045 }
3046 
3047 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3048 {
3049  SCEnter();
3050 
3051  uint32_t oldsignum = de_ctx->signum;
3052  de_ctx->sigerror_ok = false;
3053  de_ctx->sigerror_silent = false;
3054  de_ctx->sigerror_requires = false;
3055 
3056  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3057  if (sig == NULL) {
3058  goto error;
3059  }
3060 
3062  if (SigHasSameSourceAndDestination(sig)) {
3063  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3064  "treating the rule as unidirectional", sig->id);
3065 
3067  } else {
3068  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3069  if (sig->next == NULL) {
3070  goto error;
3071  }
3072  }
3073  }
3074 
3075  SCReturnPtr(sig, "Signature");
3076 
3077 error:
3078  if (sig != NULL) {
3079  SigFree(de_ctx, sig);
3080  }
3081  /* if something failed, restore the old signum count
3082  * since we didn't install it */
3083  de_ctx->signum = oldsignum;
3084 
3085  SCReturnPtr(NULL, "Signature");
3086 }
3087 
3088 /**
3089  * \brief Parses a signature and adds it to the Detection Engine Context.
3090  *
3091  * \param de_ctx Pointer to the Detection Engine Context.
3092  * \param sigstr Pointer to a character string containing the signature to be
3093  * parsed.
3094  *
3095  * \retval Pointer to the Signature instance on success; NULL on failure.
3096  */
3097 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3098 {
3099  return SigInitDo(de_ctx, sigstr, false);
3100 }
3101 
3102 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3103 {
3104  return SigInitDo(de_ctx, sigstr, true);
3105 }
3106 
3107 /**
3108  * \brief The hash free function to be the used by the hash table -
3109  * DetectEngineCtx->dup_sig_hash_table.
3110  *
3111  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3112  */
3113 static void DetectParseDupSigFreeFunc(void *data)
3114 {
3115  if (data != NULL)
3116  SCFree(data);
3117 }
3118 
3119 /**
3120  * \brief The hash function to be the used by the hash table -
3121  * DetectEngineCtx->dup_sig_hash_table.
3122  *
3123  * \param ht Pointer to the hash table.
3124  * \param data Pointer to the data, in our case SigDuplWrapper.
3125  * \param datalen Not used in our case.
3126  *
3127  * \retval sw->s->id The generated hash value.
3128  */
3129 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3130 {
3131  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3132 
3133  return (sw->s->id % ht->array_size);
3134 }
3135 
3136 /**
3137  * \brief The Compare function to be used by the hash table -
3138  * DetectEngineCtx->dup_sig_hash_table.
3139  *
3140  * \param data1 Pointer to the first SigDuplWrapper.
3141  * \param len1 Not used.
3142  * \param data2 Pointer to the second SigDuplWrapper.
3143  * \param len2 Not used.
3144  *
3145  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3146  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3147  */
3148 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3149  uint16_t len2)
3150 {
3151  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3152  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3153 
3154  if (sw1 == NULL || sw2 == NULL ||
3155  sw1->s == NULL || sw2->s == NULL)
3156  return 0;
3157 
3158  /* sid and gid match required */
3159  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3160 
3161  return 0;
3162 }
3163 
3164 /**
3165  * \brief Initializes the hash table that is used to cull duplicate sigs.
3166  *
3167  * \param de_ctx Pointer to the detection engine context.
3168  *
3169  * \retval 0 On success.
3170  * \retval -1 On failure.
3171  */
3173 {
3175  DetectParseDupSigHashFunc,
3176  DetectParseDupSigCompareFunc,
3177  DetectParseDupSigFreeFunc);
3178  if (de_ctx->dup_sig_hash_table == NULL)
3179  return -1;
3180 
3181  return 0;
3182 }
3183 
3184 /**
3185  * \brief Frees the hash table that is used to cull duplicate sigs.
3186  *
3187  * \param de_ctx Pointer to the detection engine context that holds this table.
3188  */
3190 {
3191  if (de_ctx->dup_sig_hash_table != NULL)
3193 
3194  de_ctx->dup_sig_hash_table = NULL;
3195 }
3196 
3197 /**
3198  * \brief Check if a signature is a duplicate.
3199  *
3200  * There are 3 types of return values for this function.
3201  *
3202  * - 0, which indicates that the Signature is not a duplicate
3203  * and has to be added to the detection engine list.
3204  * - 1, Signature is duplicate, and the existing signature in
3205  * the list shouldn't be replaced with this duplicate.
3206  * - 2, Signature is duplicate, and the existing signature in
3207  * the list should be replaced with this duplicate.
3208  *
3209  * \param de_ctx Pointer to the detection engine context.
3210  * \param sig Pointer to the Signature that has to be checked.
3211  *
3212  * \retval 2 If Signature is duplicate and the existing signature in
3213  * the list should be chucked out and replaced with this.
3214  * \retval 1 If Signature is duplicate, and should be chucked out.
3215  * \retval 0 If Signature is not a duplicate.
3216  */
3217 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3218  Signature *sig)
3219 {
3220  /* we won't do any NULL checks on the args */
3221 
3222  /* return value */
3223  int ret = 0;
3224 
3225  SigDuplWrapper *sw_dup = NULL;
3226  SigDuplWrapper *sw = NULL;
3227 
3228  /* used for making a duplicate_sig_hash_table entry */
3229  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3230  if (unlikely(sw == NULL)) {
3231  exit(EXIT_FAILURE);
3232  }
3233  sw->s = sig;
3234 
3235  /* check if we have a duplicate entry for this signature */
3236  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3237  /* we don't have a duplicate entry for this sig */
3238  if (sw_dup == NULL) {
3239  /* add it to the hash table */
3240  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3241 
3242  /* add the s_prev entry for the previously loaded sw in the hash_table */
3243  if (de_ctx->sig_list != NULL) {
3244  SigDuplWrapper *sw_old = NULL;
3245  SigDuplWrapper sw_tmp;
3246  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3247 
3248  /* the topmost sig would be the last loaded sig */
3249  sw_tmp.s = de_ctx->sig_list;
3251  (void *)&sw_tmp, 0);
3252  /* sw_old == NULL case is impossible */
3253  sw_old->s_prev = sig;
3254  }
3255 
3256  ret = 0;
3257  goto end;
3258  }
3259 
3260  /* if we have reached here we have a duplicate entry for this signature.
3261  * Check the signature revision. Store the signature with the latest rev
3262  * and discard the other one */
3263  if (sw->s->rev <= sw_dup->s->rev) {
3264  ret = 1;
3265  SCFree(sw);
3266  sw = NULL;
3267  goto end;
3268  }
3269 
3270  /* the new sig is of a newer revision than the one that is already in the
3271  * list. Remove the old sig from the list */
3272  if (sw_dup->s_prev == NULL) {
3273  SigDuplWrapper sw_temp;
3274  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3275  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3276  sw_temp.s = sw_dup->s->next->next;
3277  de_ctx->sig_list = sw_dup->s->next->next;
3278  SigFree(de_ctx, sw_dup->s->next);
3279  } else {
3280  sw_temp.s = sw_dup->s->next;
3281  de_ctx->sig_list = sw_dup->s->next;
3282  }
3283  SigDuplWrapper *sw_next = NULL;
3284  if (sw_temp.s != NULL) {
3286  (void *)&sw_temp, 0);
3287  sw_next->s_prev = sw_dup->s_prev;
3288  }
3289  SigFree(de_ctx, sw_dup->s);
3290  } else {
3291  SigDuplWrapper sw_temp;
3292  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3293  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3294  sw_temp.s = sw_dup->s->next->next;
3295  /* If previous signature is bidirectional,
3296  * it has 2 items in the linked list.
3297  * So we need to change next->next instead of next
3298  */
3300  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3301  } else {
3302  sw_dup->s_prev->next = sw_dup->s->next->next;
3303  }
3304  SigFree(de_ctx, sw_dup->s->next);
3305  } else {
3306  sw_temp.s = sw_dup->s->next;
3308  sw_dup->s_prev->next->next = sw_dup->s->next;
3309  } else {
3310  sw_dup->s_prev->next = sw_dup->s->next;
3311  }
3312  }
3313  SigDuplWrapper *sw_next = NULL;
3314  if (sw_temp.s != NULL) {
3316  (void *)&sw_temp, 0);
3317  sw_next->s_prev = sw_dup->s_prev;
3318  }
3319  SigFree(de_ctx, sw_dup->s);
3320  }
3321 
3322  /* make changes to the entry to reflect the presence of the new sig */
3323  sw_dup->s = sig;
3324  sw_dup->s_prev = NULL;
3325 
3326  if (de_ctx->sig_list != NULL) {
3327  SigDuplWrapper sw_tmp;
3328  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3329  sw_tmp.s = de_ctx->sig_list;
3331  (void *)&sw_tmp, 0);
3332  if (sw_old->s != sw_dup->s) {
3333  // Link on top of the list if there was another element
3334  sw_old->s_prev = sig;
3335  }
3336  }
3337 
3338  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3339  ret = 2;
3340 
3341  SCFree(sw);
3342 
3343 end:
3344  return ret;
3345 }
3346 
3347 /**
3348  * \brief Parse and append a Signature into the Detection Engine Context
3349  * signature list.
3350  *
3351  * If the signature is bidirectional it should append two signatures
3352  * (with the addresses switched) into the list. Also handle duplicate
3353  * signatures. In case of duplicate sigs, use the ones that have the
3354  * latest revision. We use the sid and the msg to identify duplicate
3355  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3356  *
3357  * \param de_ctx Pointer to the Detection Engine Context.
3358  * \param sigstr Pointer to a character string containing the signature to be
3359  * parsed.
3360  * \param sig_file Pointer to a character string containing the filename from
3361  * which signature is read
3362  * \param lineno Line number from where signature is read
3363  *
3364  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3365  * on success; NULL on failure.
3366  */
3368 {
3369  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3370  if (sig == NULL) {
3371  return NULL;
3372  }
3373 
3374  /* checking for the status of duplicate signature */
3375  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3376  /* a duplicate signature that should be chucked out. Check the previously
3377  * called function details to understand the different return values */
3378  if (dup_sig == 1) {
3379  SCLogError("Duplicate signature \"%s\"", sigstr);
3380  goto error;
3381  } else if (dup_sig == 2) {
3382  SCLogWarning("Signature with newer revision,"
3383  " so the older sig replaced by this new signature \"%s\"",
3384  sigstr);
3385  }
3386 
3388  if (sig->next != NULL) {
3389  sig->next->next = de_ctx->sig_list;
3390  } else {
3391  goto error;
3392  }
3393  } else {
3394  /* if this sig is the first one, sig_list should be null */
3395  sig->next = de_ctx->sig_list;
3396  }
3397 
3398  de_ctx->sig_list = sig;
3399 
3400  /**
3401  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3402  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3403  * to the cloned signatures with the switched addresses
3404  */
3405  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3406 
3407 error:
3408  /* free the 2nd sig bidir may have set up */
3409  if (sig != NULL && sig->next != NULL) {
3410  SigFree(de_ctx, sig->next);
3411  sig->next = NULL;
3412  }
3413  if (sig != NULL) {
3414  SigFree(de_ctx, sig);
3415  }
3416  return NULL;
3417 }
3418 
3419 /**
3420  * \brief Parse and append a Signature into the Detection Engine Context
3421  * signature list.
3422  *
3423  * If the signature is bidirectional it should append two signatures
3424  * (with the addresses switched) into the list. Also handle duplicate
3425  * signatures. In case of duplicate sigs, use the ones that have the
3426  * latest revision. We use the sid and the msg to identify duplicate
3427  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3428  *
3429  * \param de_ctx Pointer to the Detection Engine Context.
3430  * \param sigstr Pointer to a character string containing the signature to be
3431  * parsed.
3432  * \param sig_file Pointer to a character string containing the filename from
3433  * which signature is read
3434  * \param lineno Line number from where signature is read
3435  *
3436  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3437  * on success; NULL on failure.
3438  */
3440 {
3441  Signature *sig = SigInit(de_ctx, sigstr);
3442  if (sig == NULL) {
3443  return NULL;
3444  }
3445 
3446  /* checking for the status of duplicate signature */
3447  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3448  /* a duplicate signature that should be chucked out. Check the previously
3449  * called function details to understand the different return values */
3450  if (dup_sig == 1) {
3451  SCLogError("Duplicate signature \"%s\"", sigstr);
3452  goto error;
3453  } else if (dup_sig == 2) {
3454  SCLogWarning("Signature with newer revision,"
3455  " so the older sig replaced by this new signature \"%s\"",
3456  sigstr);
3457  }
3458 
3460  if (sig->next != NULL) {
3461  sig->next->next = de_ctx->sig_list;
3462  } else {
3463  goto error;
3464  }
3465  } else {
3466  /* if this sig is the first one, sig_list should be null */
3467  sig->next = de_ctx->sig_list;
3468  }
3469 
3470  de_ctx->sig_list = sig;
3471 
3472  /**
3473  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3474  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3475  * to the cloned signatures with the switched addresses
3476  */
3477  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3478 
3479 error:
3480  /* free the 2nd sig bidir may have set up */
3481  if (sig != NULL && sig->next != NULL) {
3482  SigFree(de_ctx, sig->next);
3483  sig->next = NULL;
3484  }
3485  if (sig != NULL) {
3486  SigFree(de_ctx, sig);
3487  }
3488  return NULL;
3489 }
3490 
3491 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3492 
3493 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3494  int start_offset, int options)
3495 {
3496  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3497  if (*match)
3498  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3499  *match, parse_regex->context);
3500  return -1;
3501 }
3502 
3504 {
3505  if (r->regex) {
3506  pcre2_code_free(r->regex);
3507  }
3508  if (r->context) {
3509  pcre2_match_context_free(r->context);
3510  }
3511 }
3512 
3514 {
3515  DetectParseRegex *r = g_detect_parse_regex_list;
3516  while (r) {
3517  DetectParseRegex *next = r->next;
3518 
3520 
3521  SCFree(r);
3522  r = next;
3523  }
3524  g_detect_parse_regex_list = NULL;
3525 }
3526 
3527 /** \brief add regex and/or study to at exit free list
3528  */
3530 {
3531  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3532  if (r == NULL) {
3533  FatalError("failed to alloc memory for pcre free list");
3534  }
3535  r->regex = detect_parse->regex;
3536  r->next = g_detect_parse_regex_list;
3537  g_detect_parse_regex_list = r;
3538 }
3539 
3540 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3541 {
3542  int en;
3543  PCRE2_SIZE eo;
3544 
3545  detect_parse->regex =
3546  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3547  if (detect_parse->regex == NULL) {
3548  PCRE2_UCHAR errbuffer[256];
3549  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3550  SCLogError("pcre compile of \"%s\" failed at "
3551  "offset %d: %s",
3552  parse_str, en, errbuffer);
3553  return false;
3554  }
3555  detect_parse->context = pcre2_match_context_create(NULL);
3556  if (detect_parse->context == NULL) {
3557  SCLogError("pcre2 could not create match context");
3558  pcre2_code_free(detect_parse->regex);
3559  detect_parse->regex = NULL;
3560  return false;
3561  }
3562  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3563  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3564  DetectParseRegexAddToFreeList(detect_parse);
3565 
3566  return true;
3567 }
3568 
3569 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3570 {
3571  int en;
3572  PCRE2_SIZE eo;
3573  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3574  if (detect_parse == NULL) {
3575  return NULL;
3576  }
3577 
3578  detect_parse->regex =
3579  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3580  if (detect_parse->regex == NULL) {
3581  PCRE2_UCHAR errbuffer[256];
3582  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3583  SCLogError("pcre2 compile of \"%s\" failed at "
3584  "offset %d: %s",
3585  parse_str, (int)eo, errbuffer);
3586  SCFree(detect_parse);
3587  return NULL;
3588  }
3589 
3590  detect_parse->next = g_detect_parse_regex_list;
3591  g_detect_parse_regex_list = detect_parse;
3592  return detect_parse;
3593 }
3594 
3596  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3597 {
3598  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3599  if (r == PCRE2_ERROR_UNSET) {
3600  buffer[0] = 0;
3601  *bufflen = 0;
3602  return 0;
3603  }
3604  return r;
3605 }
3606 
3608  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3609 {
3610  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3611  if (r == PCRE2_ERROR_UNSET) {
3612  *bufferptr = NULL;
3613  *bufflen = 0;
3614  return 0;
3615  }
3616  return r;
3617 }
3618 
3619 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3620 {
3621  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3622  FatalError("pcre compile and study failed");
3623  }
3624 }
3625 
3626 /*
3627  * TESTS
3628  */
3629 
3630 #ifdef UNITTESTS
3631 #include "detect-engine-alert.h"
3632 #include "packet.h"
3633 
3634 static int SigParseTest01 (void)
3635 {
3636  int result = 1;
3637  Signature *sig = NULL;
3638 
3640  if (de_ctx == NULL)
3641  goto end;
3642 
3643  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3644  if (sig == NULL)
3645  result = 0;
3646 
3647 end:
3648  if (sig != NULL) SigFree(de_ctx, sig);
3649  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3650  return result;
3651 }
3652 
3653 static int SigParseTest02 (void)
3654 {
3655  int result = 0;
3656  Signature *sig = NULL;
3657  DetectPort *port = NULL;
3658 
3660 
3661  if (de_ctx == NULL)
3662  goto end;
3663 
3667 
3668  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;)");
3669  if (sig == NULL) {
3670  goto end;
3671  }
3672 
3673  int r = DetectPortParse(de_ctx, &port, "0:20");
3674  if (r < 0)
3675  goto end;
3676 
3677  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3678  result = 1;
3679  } else {
3680  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3681  }
3682 
3683 end:
3684  if (port != NULL)
3686  if (sig != NULL)
3687  SigFree(de_ctx, sig);
3688  if (de_ctx != NULL)
3690  return result;
3691 }
3692 
3693 /**
3694  * \test SigParseTest03 test for invalid direction operator in rule
3695  */
3696 static int SigParseTest03 (void)
3697 {
3698  int result = 1;
3699  Signature *sig = NULL;
3700 
3702  if (de_ctx == NULL)
3703  goto end;
3704 
3705  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3706  if (sig != NULL) {
3707  result = 0;
3708  printf("expected NULL got sig ptr %p: ",sig);
3709  }
3710 
3711 end:
3712  if (sig != NULL) SigFree(de_ctx, sig);
3713  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3714  return result;
3715 }
3716 
3717 static int SigParseTest04 (void)
3718 {
3719  int result = 1;
3720  Signature *sig = NULL;
3721 
3723  if (de_ctx == NULL)
3724  goto end;
3725 
3726  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3727  if (sig == NULL)
3728  result = 0;
3729 
3730 end:
3731  if (sig != NULL) SigFree(de_ctx, sig);
3732  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3733  return result;
3734 }
3735 
3736 /** \test Port validation */
3737 static int SigParseTest05 (void)
3738 {
3739  int result = 0;
3740  Signature *sig = NULL;
3741 
3743  if (de_ctx == NULL)
3744  goto end;
3745 
3746  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3747  if (sig == NULL) {
3748  result = 1;
3749  } else {
3750  printf("signature didn't fail to parse as we expected: ");
3751  }
3752 
3753 end:
3754  if (sig != NULL) SigFree(de_ctx, sig);
3755  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3756  return result;
3757 }
3758 
3759 /** \test Parsing bug debugging at 2010-03-18 */
3760 static int SigParseTest06 (void)
3761 {
3762  int result = 0;
3763  Signature *sig = NULL;
3764 
3766  if (de_ctx == NULL)
3767  goto end;
3768 
3769  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;)");
3770  if (sig != NULL) {
3771  result = 1;
3772  } else {
3773  printf("signature failed to parse: ");
3774  }
3775 
3776 end:
3777  if (sig != NULL)
3778  SigFree(de_ctx, sig);
3779  if (de_ctx != NULL)
3781  return result;
3782 }
3783 
3784 /**
3785  * \test Parsing duplicate sigs.
3786  */
3787 static int SigParseTest07(void)
3788 {
3789  int result = 0;
3790 
3792  if (de_ctx == NULL)
3793  goto end;
3794 
3795  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3796  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3797 
3798  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3799 
3800 end:
3801  if (de_ctx != NULL)
3803  return result;
3804 }
3805 
3806 /**
3807  * \test Parsing duplicate sigs.
3808  */
3809 static int SigParseTest08(void)
3810 {
3811  int result = 0;
3812 
3814  if (de_ctx == NULL)
3815  goto end;
3816 
3817  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3818  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3819 
3820  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3821  de_ctx->sig_list->rev == 2);
3822 
3823 end:
3824  if (de_ctx != NULL)
3826  return result;
3827 }
3828 
3829 /**
3830  * \test Parsing duplicate sigs.
3831  */
3832 static int SigParseTest09(void)
3833 {
3834  int result = 1;
3835 
3837  if (de_ctx == NULL)
3838  goto end;
3839 
3840  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3841  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3842  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3843  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3844  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3845  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3846  de_ctx->sig_list->rev == 2);
3847  if (result == 0)
3848  goto end;
3849  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3850  de_ctx->sig_list->next->rev == 6);
3851  if (result == 0)
3852  goto end;
3853 
3854  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3855  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3856  de_ctx->sig_list->rev == 2);
3857  if (result == 0)
3858  goto end;
3859  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3860  de_ctx->sig_list->next->rev == 6);
3861  if (result == 0)
3862  goto end;
3863 
3864  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3865  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3866  de_ctx->sig_list->rev == 4);
3867  if (result == 0)
3868  goto end;
3869  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3870  de_ctx->sig_list->next->rev == 6);
3871  if (result == 0)
3872  goto end;
3873 
3874 end:
3875  if (de_ctx != NULL)
3877  return result;
3878 }
3879 
3880 /**
3881  * \test Parsing duplicate sigs.
3882  */
3883 static int SigParseTest10(void)
3884 {
3885  int result = 1;
3886 
3888  if (de_ctx == NULL)
3889  goto end;
3890 
3891  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3892  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3893  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3894  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3895  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3896  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3897  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3898 
3899  result &= ((de_ctx->sig_list->id == 2) &&
3900  (de_ctx->sig_list->next->id == 3) &&
3901  (de_ctx->sig_list->next->next->id == 5) &&
3902  (de_ctx->sig_list->next->next->next->id == 4) &&
3903  (de_ctx->sig_list->next->next->next->next->id == 1));
3904 
3905 end:
3906  if (de_ctx != NULL)
3908  return result;
3909 }
3910 
3911 /**
3912  * \test Parsing sig with trailing space(s) as reported by
3913  * Morgan Cox on oisf-users.
3914  */
3915 static int SigParseTest11(void)
3916 {
3917  int result = 0;
3918 
3920  if (de_ctx == NULL)
3921  goto end;
3922 
3923  Signature *s = NULL;
3924 
3926  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3927  if (s == NULL) {
3928  printf("sig 1 didn't parse: ");
3929  goto end;
3930  }
3931 
3932  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3933  "the http link\"; sid:2;) ");
3934  if (s == NULL) {
3935  printf("sig 2 didn't parse: ");
3936  goto end;
3937  }
3938 
3939  result = 1;
3940 end:
3941  if (de_ctx != NULL)
3943  return result;
3944 }
3945 
3946 /**
3947  * \test file_data with rawbytes
3948  */
3949 static int SigParseTest12(void)
3950 {
3951  int result = 0;
3952 
3954  if (de_ctx == NULL)
3955  goto end;
3956 
3957  Signature *s = NULL;
3958 
3959  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3960  if (s != NULL) {
3961  printf("sig 1 should have given an error: ");
3962  goto end;
3963  }
3964 
3965  result = 1;
3966 end:
3967  if (de_ctx != NULL)
3969  return result;
3970 }
3971 
3972 /**
3973  * \test packet/stream sig
3974  */
3975 static int SigParseTest13(void)
3976 {
3977  int result = 0;
3978 
3980  if (de_ctx == NULL)
3981  goto end;
3982 
3983  Signature *s = NULL;
3984 
3985  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
3986  if (s == NULL) {
3987  printf("sig 1 invalidated: failure");
3988  goto end;
3989  }
3990 
3991  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
3992  printf("sig doesn't have stream flag set\n");
3993  goto end;
3994  }
3995 
3996  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
3997  printf("sig has packet flag set\n");
3998  goto end;
3999  }
4000 
4001  result = 1;
4002 
4003 end:
4004  if (de_ctx != NULL)
4006  return result;
4007 }
4008 
4009 /**
4010  * \test packet/stream sig
4011  */
4012 static int SigParseTest14(void)
4013 {
4014  int result = 0;
4015 
4017  if (de_ctx == NULL)
4018  goto end;
4019 
4020  Signature *s = NULL;
4021 
4022  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4023  if (s == NULL) {
4024  printf("sig 1 invalidated: failure");
4025  goto end;
4026  }
4027 
4028  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4029  printf("sig doesn't have packet flag set\n");
4030  goto end;
4031  }
4032 
4033  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4034  printf("sig has stream flag set\n");
4035  goto end;
4036  }
4037 
4038  result = 1;
4039 
4040 end:
4041  if (de_ctx != NULL)
4043  return result;
4044 }
4045 
4046 /**
4047  * \test packet/stream sig
4048  */
4049 static int SigParseTest15(void)
4050 {
4051  int result = 0;
4052 
4054  if (de_ctx == NULL)
4055  goto end;
4056 
4057  Signature *s = NULL;
4058 
4059  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4060  if (s == NULL) {
4061  printf("sig 1 invalidated: failure");
4062  goto end;
4063  }
4064 
4065  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4066  printf("sig doesn't have packet flag set\n");
4067  goto end;
4068  }
4069 
4070  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4071  printf("sig doesn't have stream flag set\n");
4072  goto end;
4073  }
4074 
4075  result = 1;
4076 
4077 end:
4078  if (de_ctx != NULL)
4080  return result;
4081 }
4082 
4083 /**
4084  * \test packet/stream sig
4085  */
4086 static int SigParseTest16(void)
4087 {
4088  int result = 0;
4089 
4091  if (de_ctx == NULL)
4092  goto end;
4093 
4094  Signature *s = NULL;
4095 
4096  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4097  if (s == NULL) {
4098  printf("sig 1 invalidated: failure");
4099  goto end;
4100  }
4101 
4102  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4103  printf("sig doesn't have packet flag set\n");
4104  goto end;
4105  }
4106 
4107  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4108  printf("sig doesn't have stream flag set\n");
4109  goto end;
4110  }
4111 
4112  result = 1;
4113 
4114 end:
4115  if (de_ctx != NULL)
4117  return result;
4118 }
4119 
4120 /**
4121  * \test packet/stream sig
4122  */
4123 static int SigParseTest17(void)
4124 {
4125  int result = 0;
4126 
4128  if (de_ctx == NULL)
4129  goto end;
4130 
4131  Signature *s = NULL;
4132 
4133  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4134  if (s == NULL) {
4135  printf("sig 1 invalidated: failure");
4136  goto end;
4137  }
4138 
4139  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4140  printf("sig doesn't have packet flag set\n");
4141  goto end;
4142  }
4143 
4144  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4145  printf("sig doesn't have stream flag set\n");
4146  goto end;
4147  }
4148 
4149  result = 1;
4150 
4151 end:
4152  if (de_ctx != NULL)
4154  return result;
4155 }
4156 
4157 /** \test sid value too large. Bug #779 */
4158 static int SigParseTest18 (void)
4159 {
4160  int result = 0;
4161 
4163  if (de_ctx == NULL)
4164  goto end;
4165 
4166  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4167  goto end;
4168 
4169  result = 1;
4170 end:
4171  if (de_ctx != NULL)
4173  return result;
4174 }
4175 
4176 /** \test gid value too large. Related to bug #779 */
4177 static int SigParseTest19 (void)
4178 {
4179  int result = 0;
4180 
4182  if (de_ctx == NULL)
4183  goto end;
4184 
4185  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4186  goto end;
4187 
4188  result = 1;
4189 end:
4190  if (de_ctx != NULL)
4192  return result;
4193 }
4194 
4195 /** \test rev value too large. Related to bug #779 */
4196 static int SigParseTest20 (void)
4197 {
4198  int result = 0;
4199 
4201  if (de_ctx == NULL)
4202  goto end;
4203 
4204  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4205  goto end;
4206 
4207  result = 1;
4208 end:
4209  if (de_ctx != NULL)
4211  return result;
4212 }
4213 
4214 /** \test address parsing */
4215 static int SigParseTest21 (void)
4216 {
4217  int result = 0;
4218 
4220  if (de_ctx == NULL)
4221  goto end;
4222 
4223  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4224  goto end;
4225 
4226  result = 1;
4227 end:
4228  if (de_ctx != NULL)
4230  return result;
4231 }
4232 
4233 /** \test address parsing */
4234 static int SigParseTest22 (void)
4235 {
4236  int result = 0;
4237 
4239  if (de_ctx == NULL)
4240  goto end;
4241 
4242  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)
4243  goto end;
4244 
4245  result = 1;
4246 end:
4247  if (de_ctx != NULL)
4249  return result;
4250 }
4251 
4252 /**
4253  * \test rule ending in carriage return
4254  */
4255 static int SigParseTest23(void)
4256 {
4259 
4260  Signature *s = NULL;
4261 
4262  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4263  FAIL_IF_NULL(s);
4264 
4266  PASS;
4267 }
4268 
4269 /** \test Direction operator validation (invalid) */
4270 static int SigParseBidirecTest06 (void)
4271 {
4272  int result = 1;
4273  Signature *sig = NULL;
4274 
4276  if (de_ctx == NULL)
4277  goto end;
4278 
4279  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4280  if (sig == NULL)
4281  result = 1;
4282 
4283 end:
4284  if (sig != NULL) SigFree(de_ctx, sig);
4285  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4286  return result;
4287 }
4288 
4289 /** \test Direction operator validation (invalid) */
4290 static int SigParseBidirecTest07 (void)
4291 {
4292  int result = 1;
4293  Signature *sig = NULL;
4294 
4296  if (de_ctx == NULL)
4297  goto end;
4298 
4299  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4300  if (sig == NULL)
4301  result = 1;
4302 
4303 end:
4304  if (sig != NULL) SigFree(de_ctx, sig);
4305  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4306  return result;
4307 }
4308 
4309 /** \test Direction operator validation (invalid) */
4310 static int SigParseBidirecTest08 (void)
4311 {
4312  int result = 1;
4313  Signature *sig = NULL;
4314 
4316  if (de_ctx == NULL)
4317  goto end;
4318 
4319  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4320  if (sig == NULL)
4321  result = 1;
4322 
4323 end:
4324  if (sig != NULL) SigFree(de_ctx, sig);
4325  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4326  return result;
4327 }
4328 
4329 /** \test Direction operator validation (invalid) */
4330 static int SigParseBidirecTest09 (void)
4331 {
4332  int result = 1;
4333  Signature *sig = NULL;
4334 
4336  if (de_ctx == NULL)
4337  goto end;
4338 
4339  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4340  if (sig == NULL)
4341  result = 1;
4342 
4343 end:
4344  if (sig != NULL) SigFree(de_ctx, sig);
4345  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4346  return result;
4347 }
4348 
4349 /** \test Direction operator validation (invalid) */
4350 static int SigParseBidirecTest10 (void)
4351 {
4352  int result = 1;
4353  Signature *sig = NULL;
4354 
4356  if (de_ctx == NULL)
4357  goto end;
4358 
4359  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4360  if (sig == NULL)
4361  result = 1;
4362 
4363 end:
4364  if (sig != NULL) SigFree(de_ctx, sig);
4365  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4366  return result;
4367 }
4368 
4369 /** \test Direction operator validation (invalid) */
4370 static int SigParseBidirecTest11 (void)
4371 {
4372  int result = 1;
4373  Signature *sig = NULL;
4374 
4376  if (de_ctx == NULL)
4377  goto end;
4378 
4379  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4380  if (sig == NULL)
4381  result = 1;
4382 
4383 end:
4384  if (sig != NULL) SigFree(de_ctx, sig);
4385  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4386  return result;
4387 }
4388 
4389 /** \test Direction operator validation (invalid) */
4390 static int SigParseBidirecTest12 (void)
4391 {
4392  int result = 1;
4393  Signature *sig = NULL;
4394 
4396  if (de_ctx == NULL)
4397  goto end;
4398 
4399  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4400  if (sig == NULL)
4401  result = 1;
4402 
4403 end:
4404  if (sig != NULL) SigFree(de_ctx, sig);
4405  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4406  return result;
4407 }
4408 
4409 /** \test Direction operator validation (valid) */
4410 static int SigParseBidirecTest13 (void)
4411 {
4412  int result = 1;
4413  Signature *sig = NULL;
4414 
4416  if (de_ctx == NULL)
4417  goto end;
4418 
4419  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4420  if (sig != NULL)
4421  result = 1;
4422 
4423 end:
4424  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4425  return result;
4426 }
4427 
4428 /** \test Direction operator validation (valid) */
4429 static int SigParseBidirecTest14 (void)
4430 {
4431  int result = 1;
4432  Signature *sig = NULL;
4433 
4435  if (de_ctx == NULL)
4436  goto end;
4437 
4438  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4439  if (sig != NULL)
4440  result = 1;
4441 
4442 end:
4443  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4444  return result;
4445 }
4446 
4447 /** \test Ensure that we don't set bidirectional in a
4448  * normal (one direction) Signature
4449  */
4450 static int SigTestBidirec01 (void)
4451 {
4452  Signature *sig = NULL;
4453  int result = 0;
4454 
4456  if (de_ctx == NULL)
4457  goto end;
4458 
4459  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4460  if (sig == NULL)
4461  goto end;
4462  if (sig->next != NULL)
4463  goto end;
4465  goto end;
4466  if (de_ctx->signum != 1)
4467  goto end;
4468 
4469  result = 1;
4470 
4471 end:
4472  if (de_ctx != NULL) {
4476  }
4477  return result;
4478 }
4479 
4480 /** \test Ensure that we set a bidirectional Signature correctly */
4481 static int SigTestBidirec02 (void)
4482 {
4483  int result = 0;
4484  Signature *sig = NULL;
4485  Signature *copy = NULL;
4486 
4488  if (de_ctx == NULL)
4489  goto end;
4490 
4491  de_ctx->flags |= DE_QUIET;
4492 
4493  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4494  if (sig == NULL)
4495  goto end;
4496  if (de_ctx->sig_list != sig)
4497  goto end;
4499  goto end;
4500  if (sig->next == NULL)
4501  goto end;
4502  if (de_ctx->signum != 2)
4503  goto end;
4504  copy = sig->next;
4505  if (copy->next != NULL)
4506  goto end;
4507  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4508  goto end;
4509 
4510  result = 1;
4511 
4512 end:
4513  if (de_ctx != NULL) {
4517  }
4518 
4519  return result;
4520 }
4521 
4522 /** \test Ensure that we set a bidirectional Signature correctly
4523 * and we install it with the rest of the signatures, checking
4524 * also that it match with the correct addr directions
4525 */
4526 static int SigTestBidirec03 (void)
4527 {
4528  int result = 0;
4529  Signature *sig = NULL;
4530  Packet *p = NULL;
4531 
4533  if (de_ctx == NULL)
4534  goto end;
4535 
4536  de_ctx->flags |= DE_QUIET;
4537 
4538  const char *sigs[3];
4539  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4540  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4541  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4542  UTHAppendSigs(de_ctx, sigs, 3);
4543 
4544  /* Checking that bidirectional rules are set correctly */
4545  sig = de_ctx->sig_list;
4546  if (sig == NULL)
4547  goto end;
4548  if (sig->next == NULL)
4549  goto end;
4550  if (sig->next->next == NULL)
4551  goto end;
4552  if (sig->next->next->next == NULL)
4553  goto end;
4554  if (sig->next->next->next->next != NULL)
4555  goto end;
4556  if (de_ctx->signum != 4)
4557  goto end;
4558 
4559  uint8_t rawpkt1_ether[] = {
4560  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4561  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4562  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4563  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4564  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4565  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4566  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4567  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4568  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4569  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4570  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4571  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4572  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4573  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4574  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4575  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4576  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4577  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4578  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4579  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4580  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4581  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4582  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4583  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4584  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4585  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4586  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4587  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4588  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4589  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4590  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4591  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4592  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4593  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4594  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4595  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4596  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4597  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4598  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4599  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4600  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4601  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4602  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4603  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4604  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4605  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4606  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4607  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4608  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4609  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4610  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4611  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4612  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4613  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4614  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4615 
4617  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4618  if (p == NULL) {
4619  SCLogDebug("Error building packet");
4620  goto end;
4621  }
4622  UTHMatchPackets(de_ctx, &p, 1);
4623 
4624  uint32_t sids[3] = {1, 2, 3};
4625  uint32_t results[3] = {1, 1, 1};
4626  result = UTHCheckPacketMatchResults(p, sids, results, 1);
4627 
4628 end:
4629  if (p != NULL) {
4630  PacketFree(p);
4631  }
4633  FlowShutdown();
4634  return result;
4635 }
4636 
4637 /** \test Ensure that we set a bidirectional Signature correctly
4638 * and we install it with the rest of the signatures, checking
4639 * also that it match with the correct addr directions
4640 */
4641 static int SigTestBidirec04 (void)
4642 {
4643  int result = 0;
4644  Signature *sig = NULL;
4645  Packet *p = NULL;
4646 
4648  if (de_ctx == NULL)
4649  goto end;
4650 
4651  de_ctx->flags |= DE_QUIET;
4652 
4653  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4654  if (sig == NULL)
4655  goto end;
4656  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4657  if (sig == NULL)
4658  goto end;
4659  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4660  goto end;
4661  if (sig->next == NULL)
4662  goto end;
4663  if (sig->next->next == NULL)
4664  goto end;
4665  if (sig->next->next->next != NULL)
4666  goto end;
4667  if (de_ctx->signum != 3)
4668  goto end;
4669 
4670  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4671  if (sig == NULL)
4672  goto end;
4673  if (sig->next == NULL)
4674  goto end;
4675  if (sig->next->next == NULL)
4676  goto end;
4677  if (sig->next->next->next == NULL)
4678  goto end;
4679  if (sig->next->next->next->next != NULL)
4680  goto end;
4681  if (de_ctx->signum != 4)
4682  goto end;
4683 
4684  uint8_t rawpkt1_ether[] = {
4685  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4686  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4687  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4688  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4689  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4690  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4691  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4692  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4693  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4694  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4695  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4696  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4697  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4698  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4699  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4700  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4701  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4702  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4703  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4704  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4705  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4706  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4707  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4708  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4709  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4710  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4711  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4712  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4713  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4714  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4715  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4716  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4717  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4718  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4719  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4720  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4721  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4722  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4723  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4724  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4725  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4726  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4727  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4728  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4729  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4730  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4731  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4732  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4733  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4734  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4735  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4736  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4737  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4738  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4739  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4740 
4741  p = PacketGetFromAlloc();
4742  if (unlikely(p == NULL))
4743  return 0;
4745  ThreadVars th_v;
4746  DetectEngineThreadCtx *det_ctx;
4747 
4748  memset(&th_v, 0, sizeof(th_v));
4749 
4751  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4752  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4753 
4754  /* At this point we have a list of 4 signatures. The last one
4755  is a copy of the second one. If we receive a packet
4756  with source 192.168.1.1 80, all the sids should match */
4757 
4759  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4760 
4761  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4762  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4763  PacketAlertCheck(p, 2) == 1) {
4764  result = 1;
4765  }
4766 
4767  if (p != NULL) {
4768  PacketRecycle(p);
4769  }
4770  FlowShutdown();
4771  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4772 
4773 end:
4774  if (de_ctx != NULL) {
4776  }
4777 
4778  if (p != NULL)
4779  PacketFree(p);
4780  StatsThreadCleanup(&th_v);
4781  return result;
4782 }
4783 
4784 /**
4785  * \test check that we don't allow invalid negation options
4786  */
4787 static int SigParseTestNegation01 (void)
4788 {
4791  de_ctx->flags |= DE_QUIET;
4792  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4793  FAIL_IF_NOT_NULL(s);
4795  PASS;
4796 }
4797 
4798 /**
4799  * \test check that we don't allow invalid negation options
4800  */
4801 static int SigParseTestNegation02 (void)
4802 {
4803  int result = 0;
4805  Signature *s=NULL;
4806 
4808  if (de_ctx == NULL)
4809  goto end;
4810  de_ctx->flags |= DE_QUIET;
4811 
4812  s = SigInit(de_ctx,"alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; classtype:misc-activity; sid:410002; rev:1;)");
4813  if (s != NULL) {
4814  SigFree(de_ctx, s);
4815  goto end;
4816  }
4817 
4818  result = 1;
4819 end:
4820  if (de_ctx != NULL)
4822  return result;
4823 }
4824 /**
4825  * \test check that we don't allow invalid negation options
4826  */
4827 static int SigParseTestNegation03 (void)
4828 {
4829  int result = 0;
4831  Signature *s=NULL;
4832 
4834  if (de_ctx == NULL)
4835  goto end;
4836  de_ctx->flags |= DE_QUIET;
4837 
4838  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;)");
4839  if (s != NULL) {
4840  SigFree(de_ctx, s);
4841  goto end;
4842  }
4843 
4844  result = 1;
4845 end:
4846  if (de_ctx != NULL)
4848  return result;
4849 }
4850 /**
4851  * \test check that we don't allow invalid negation options
4852  */
4853 static int SigParseTestNegation04 (void)
4854 {
4855  int result = 0;
4857  Signature *s=NULL;
4858 
4860  if (de_ctx == NULL)
4861  goto end;
4862  de_ctx->flags |= DE_QUIET;
4863 
4864  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;)");
4865  if (s != NULL) {
4866  SigFree(de_ctx, s);
4867  goto end;
4868  }
4869 
4870  result = 1;
4871 end:
4872  if (de_ctx != NULL)
4874  return result;
4875 }
4876 /**
4877  * \test check that we don't allow invalid negation options
4878  */
4879 static int SigParseTestNegation05 (void)
4880 {
4881  int result = 0;
4883  Signature *s=NULL;
4884 
4886  if (de_ctx == NULL)
4887  goto end;
4888  de_ctx->flags |= DE_QUIET;
4889 
4890  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;)");
4891  if (s != NULL) {
4892  SigFree(de_ctx, s);
4893  goto end;
4894  }
4895 
4896  result = 1;
4897 end:
4898  if (de_ctx != NULL)
4900  return result;
4901 }
4902 /**
4903  * \test check that we don't allow invalid negation options
4904  */
4905 static int SigParseTestNegation06 (void)
4906 {
4907  int result = 0;
4909  Signature *s=NULL;
4910 
4912  if (de_ctx == NULL)
4913  goto end;
4914  de_ctx->flags |= DE_QUIET;
4915 
4916  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;)");
4917  if (s != NULL) {
4918  SigFree(de_ctx, s);
4919  goto end;
4920  }
4921 
4922  result = 1;
4923 end:
4924  if (de_ctx != NULL)
4926  return result;
4927 }
4928 
4929 /**
4930  * \test check that we don't allow invalid negation options
4931  */
4932 static int SigParseTestNegation07 (void)
4933 {
4936  de_ctx->flags |= DE_QUIET;
4938  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4939  FAIL_IF_NOT_NULL(s);
4941  PASS;
4942 }
4943 
4944 /**
4945  * \test check valid negation bug 1079
4946  */
4947 static int SigParseTestNegation08 (void)
4948 {
4949  int result = 0;
4951  Signature *s=NULL;
4952 
4954  if (de_ctx == NULL)
4955  goto end;
4956  de_ctx->flags |= DE_QUIET;
4957 
4959  "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4960  if (s == NULL) {
4961  goto end;
4962  }
4963 
4964  result = 1;
4965 end:
4966  if (de_ctx != NULL)
4968  return result;
4969 }
4970 
4971 /**
4972  * \test mpm
4973  */
4974 static int SigParseTestMpm01 (void)
4975 {
4976  int result = 0;
4977  Signature *sig = NULL;
4978 
4980  if (de_ctx == NULL)
4981  goto end;
4982 
4983  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
4984  if (sig == NULL) {
4985  printf("sig failed to init: ");
4986  goto end;
4987  }
4988 
4989  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4990  printf("sig doesn't have content list: ");
4991  goto end;
4992  }
4993 
4994  result = 1;
4995 end:
4996  if (sig != NULL)
4997  SigFree(de_ctx, sig);
4999  return result;
5000 }
5001 
5002 /**
5003  * \test mpm
5004  */
5005 static int SigParseTestMpm02 (void)
5006 {
5007  int result = 0;
5008  Signature *sig = NULL;
5009 
5011  if (de_ctx == NULL)
5012  goto end;
5013 
5014  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5015  if (sig == NULL) {
5016  printf("sig failed to init: ");
5017  goto end;
5018  }
5019 
5020  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5021  printf("sig doesn't have content list: ");
5022  goto end;
5023  }
5024 
5025  result = 1;
5026 end:
5027  if (sig != NULL)
5028  SigFree(de_ctx, sig);
5030  return result;
5031 }
5032 
5033 /**
5034  * \test test tls (app layer) rule
5035  */
5036 static int SigParseTestAppLayerTLS01(void)
5037 {
5038  int result = 0;
5040  Signature *s=NULL;
5041 
5043  if (de_ctx == NULL)
5044  goto end;
5045  de_ctx->flags |= DE_QUIET;
5046 
5047  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5048  if (s == NULL) {
5049  printf("parsing sig failed: ");
5050  goto end;
5051  }
5052 
5053  if (s->alproto == 0) {
5054  printf("alproto not set: ");
5055  goto end;
5056  }
5057 
5058  result = 1;
5059 end:
5060  if (s != NULL)
5061  SigFree(de_ctx, s);
5062  if (de_ctx != NULL)
5064 
5065  return result;
5066 }
5067 
5068 /**
5069  * \test test tls (app layer) rule
5070  */
5071 static int SigParseTestAppLayerTLS02(void)
5072 {
5073  int result = 0;
5075  Signature *s=NULL;
5076 
5078  if (de_ctx == NULL)
5079  goto end;
5080  de_ctx->flags |= DE_QUIET;
5081 
5082  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5083  if (s == NULL) {
5084  printf("parsing sig failed: ");
5085  goto end;
5086  }
5087 
5088  if (s->alproto == 0) {
5089  printf("alproto not set: ");
5090  goto end;
5091  }
5092 
5093  result = 1;
5094 end:
5095  if (s != NULL)
5096  SigFree(de_ctx, s);
5097  if (de_ctx != NULL)
5099  return result;
5100 }
5101 
5102 /**
5103  * \test test tls (app layer) rule
5104  */
5105 static int SigParseTestAppLayerTLS03(void)
5106 {
5107  int result = 0;
5109  Signature *s=NULL;
5110 
5112  if (de_ctx == NULL)
5113  goto end;
5114  de_ctx->flags |= DE_QUIET;
5115 
5116  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; tls.version:2.5; sid:410006; rev:1;)");
5117  if (s != NULL) {
5118  SigFree(de_ctx, s);
5119  goto end;
5120  }
5121 
5122  result = 1;
5123 end:
5124  if (de_ctx != NULL)
5126  return result;
5127 }
5128 
5129 static int SigParseTestUnbalancedQuotes01(void)
5130 {
5133  de_ctx->flags |= DE_QUIET;
5135  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5136  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5137  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5138  FAIL_IF_NOT_NULL(s);
5140  PASS;
5141 }
5142 
5143 static int SigParseTestContentGtDsize01(void)
5144 {
5147  de_ctx->flags |= DE_QUIET;
5148  Signature *s =
5149  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5150  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5151  "sid:1; rev:1;)");
5152  FAIL_IF_NOT_NULL(s);
5154  PASS;
5155 }
5156 
5157 static int SigParseTestContentGtDsize02(void)
5158 {
5161  de_ctx->flags |= DE_QUIET;
5162  Signature *s =
5163  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5164  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5165  "sid:1; rev:1;)");
5166  FAIL_IF_NOT_NULL(s);
5168  PASS;
5169 }
5170 
5171 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5172 {
5173  int cnt = 0;
5174  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5175  if (sid == s->id)
5176  cnt++;
5177  }
5178  return cnt;
5179 }
5180 
5181 static int SigParseBidirWithSameSrcAndDest01(void)
5182 {
5185  de_ctx->flags |= DE_QUIET;
5186 
5187  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5188  FAIL_IF_NULL(s);
5189  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5191 
5192  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5193  FAIL_IF_NULL(s);
5194  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5196 
5198  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5199  FAIL_IF_NULL(s);
5200  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5202 
5204  PASS;
5205 }
5206 
5207 static int SigParseBidirWithSameSrcAndDest02(void)
5208 {
5211  de_ctx->flags |= DE_QUIET;
5212 
5213  // Source is a subset of destination
5215  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5216  FAIL_IF_NULL(s);
5217  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5219 
5220  // Source is a subset of destination
5222  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5223  FAIL_IF_NULL(s);
5224  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5226 
5227  // Source intersects with destination
5229  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5230  FAIL_IF_NULL(s);
5231  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5233 
5234  // mix in negation, these are the same
5236  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;)");
5237  FAIL_IF_NULL(s);
5238  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5240 
5241  // mix in negation, these are not the same
5243  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;)");
5244  FAIL_IF_NULL(s);
5245  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5247 
5249  PASS;
5250 }
5251 
5252 static int SigParseTestActionReject(void)
5253 {
5256 
5258  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5259 #ifdef HAVE_LIBNET11
5260  FAIL_IF_NULL(sig);
5262 #else
5263  FAIL_IF_NOT_NULL(sig);
5264 #endif
5265 
5267  PASS;
5268 }
5269 
5270 static int SigParseTestActionDrop(void)
5271 {
5274 
5276  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5277  FAIL_IF_NULL(sig);
5278  FAIL_IF_NOT(sig->action & ACTION_DROP);
5279 
5281  PASS;
5282 }
5283 
5284 static int SigSetMultiAppProto(void)
5285 {
5286  Signature *s = SigAlloc();
5287  FAIL_IF_NULL(s);
5288 
5289  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5290  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5291 
5292  // check intersection gives multiple entries
5293  alprotos[0] = 3;
5294  alprotos[1] = 2;
5295  alprotos[2] = ALPROTO_UNKNOWN;
5296  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5297  FAIL_IF(s->init_data->alprotos[0] != 3);
5298  FAIL_IF(s->init_data->alprotos[1] != 2);
5300 
5301  // check single after multiple
5304  FAIL_IF(s->alproto != 3);
5305  alprotos[0] = 4;
5306  alprotos[1] = 3;
5307  alprotos[2] = ALPROTO_UNKNOWN;
5308  // check multiple containing singleton
5309  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5310  FAIL_IF(s->alproto != 3);
5311 
5312  // reset
5313  s->alproto = ALPROTO_UNKNOWN;
5314  alprotos[0] = 1;
5315  alprotos[1] = 2;
5316  alprotos[2] = 3;
5317  alprotos[3] = ALPROTO_UNKNOWN;
5318  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5319  // fail if set single not in multiple
5321 
5323  s->alproto = ALPROTO_UNKNOWN;
5324  alprotos[0] = 1;
5325  alprotos[1] = 2;
5326  alprotos[2] = 3;
5327  alprotos[3] = ALPROTO_UNKNOWN;
5328  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5329  alprotos[0] = 4;
5330  alprotos[1] = 5;
5331  alprotos[2] = ALPROTO_UNKNOWN;
5332  // fail if multiple do not have intersection
5333  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5334 
5336  s->alproto = ALPROTO_UNKNOWN;
5337  alprotos[0] = 1;
5338  alprotos[1] = 2;
5339  alprotos[2] = 3;
5340  alprotos[3] = ALPROTO_UNKNOWN;
5341  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5342  alprotos[0] = 3;
5343  alprotos[1] = 4;
5344  alprotos[2] = 5;
5345  alprotos[3] = ALPROTO_UNKNOWN;
5346  // check multiple intersect to singleton
5347  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5348  FAIL_IF(s->alproto != 3);
5349  alprotos[0] = 5;
5350  alprotos[1] = 4;
5351  alprotos[2] = ALPROTO_UNKNOWN;
5352  // fail if multiple do not belong to singleton
5353  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5354 
5355  SigFree(NULL, s);
5356  PASS;
5357 }
5358 
5359 static int DetectSetupDirection01(void)
5360 {
5361  Signature *s = SigAlloc();
5362  FAIL_IF_NULL(s);
5363  // Basic case : ok
5364  char *str = (char *)"to_client";
5365  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5366  SigFree(NULL, s);
5367  PASS;
5368 }
5369 
5370 static int DetectSetupDirection02(void)
5371 {
5372  Signature *s = SigAlloc();
5373  FAIL_IF_NULL(s);
5374  char *str = (char *)"to_server";
5375  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5376  // ok so far
5377  str = (char *)"to_client";
5378  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5379  // fails because we cannot have both to_client and to_server for same signature
5380  SigFree(NULL, s);
5381  PASS;
5382 }
5383 
5384 static int DetectSetupDirection03(void)
5385 {
5386  Signature *s = SigAlloc();
5387  FAIL_IF_NULL(s);
5388  char *str = (char *)"to_client , something";
5389  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5390  FAIL_IF(strcmp(str, "something") != 0);
5391  str = (char *)"to_client,something";
5392  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5393  FAIL_IF(strcmp(str, "something") != 0);
5394  SigFree(NULL, s);
5395  PASS;
5396 }
5397 
5398 static int DetectSetupDirection04(void)
5399 {
5400  Signature *s = SigAlloc();
5401  FAIL_IF_NULL(s);
5402  // invalid case
5403  char *str = (char *)"to_client_toto";
5404  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5405  // test we do not change the string pointer if only_dir is false
5406  str = (char *)"to_client_toto";
5407  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5408  FAIL_IF(strcmp(str, "to_client_toto") != 0);
5409  str = (char *)"to_client,something";
5410  // fails because we call with only_dir=true
5411  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5412  SigFree(NULL, s);
5413  PASS;
5414 }
5415 
5416 #endif /* UNITTESTS */
5417 
5418 #ifdef UNITTESTS
5419 void DetectParseRegisterTests (void);
5420 #include "tests/detect-parse.c"
5421 #endif
5422 
5424 {
5425 #ifdef UNITTESTS
5427 
5428  UtRegisterTest("SigParseTest01", SigParseTest01);
5429  UtRegisterTest("SigParseTest02", SigParseTest02);
5430  UtRegisterTest("SigParseTest03", SigParseTest03);
5431  UtRegisterTest("SigParseTest04", SigParseTest04);
5432  UtRegisterTest("SigParseTest05", SigParseTest05);
5433  UtRegisterTest("SigParseTest06", SigParseTest06);
5434  UtRegisterTest("SigParseTest07", SigParseTest07);
5435  UtRegisterTest("SigParseTest08", SigParseTest08);
5436  UtRegisterTest("SigParseTest09", SigParseTest09);
5437  UtRegisterTest("SigParseTest10", SigParseTest10);
5438  UtRegisterTest("SigParseTest11", SigParseTest11);
5439  UtRegisterTest("SigParseTest12", SigParseTest12);
5440  UtRegisterTest("SigParseTest13", SigParseTest13);
5441  UtRegisterTest("SigParseTest14", SigParseTest14);
5442  UtRegisterTest("SigParseTest15", SigParseTest15);
5443  UtRegisterTest("SigParseTest16", SigParseTest16);
5444  UtRegisterTest("SigParseTest17", SigParseTest17);
5445  UtRegisterTest("SigParseTest18", SigParseTest18);
5446  UtRegisterTest("SigParseTest19", SigParseTest19);
5447  UtRegisterTest("SigParseTest20", SigParseTest20);
5448  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5449  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5450  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5451 
5452  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5453  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5454  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5455  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5456  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5457  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5458  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5459  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5460  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5461  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5462  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5463  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5464  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5465  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5466  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5467  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5468  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5469  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5470  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5471  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5472  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5473  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5474  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5475  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5476  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5477  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5478  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5479 
5480  UtRegisterTest("SigParseTestContentGtDsize01",
5481  SigParseTestContentGtDsize01);
5482  UtRegisterTest("SigParseTestContentGtDsize02",
5483  SigParseTestContentGtDsize02);
5484 
5485  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5486  SigParseBidirWithSameSrcAndDest01);
5487  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5488  SigParseBidirWithSameSrcAndDest02);
5489  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5490  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5491 
5492  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5493 
5494  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5495  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5496  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5497  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5498 
5499 #endif /* UNITTESTS */
5500 }
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:3172
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:1444
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:1617
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:1678
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:1457
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
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:996
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:1448
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:1026
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
SIG_DIREC_DST
@ SIG_DIREC_DST
Definition: detect-parse.h:48
detect-isdataat.h
SIGMATCH_QUOTES_OPTIONAL
#define SIGMATCH_QUOTES_OPTIONAL
Definition: detect.h:1662
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
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
PacketRecycle
void PacketRecycle(Packet *p)
Definition: packet.c:151
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:3569
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:40
ctx
struct Thresholds ctx
AppLayerParserSupportsFiles
bool AppLayerParserSupportsFiles(uint8_t ipproto, AppProto alproto)
Definition: app-layer-parser.c:1173
SigDuplWrapper_::s_prev
Signature * s_prev
Definition: detect-parse.c:97
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
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:1116
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:1602
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2633
SIG_DIREC_NORMAL
@ SIG_DIREC_NORMAL
Definition: detect-parse.h:40
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
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:1030
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:1064
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:3189
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3493
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:1027
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:1680
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:1417
SigMatchData_
Data needed for Match()
Definition: detect.h:365
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1439
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:460
DetectParseRegexAddToFreeList
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
add regex and/or study to at exit free list
Definition: detect-parse.c:3529
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:897
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:3513
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:424
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1666
FlowInitConfig
void FlowInitConfig(bool quiet)
initialize the configuration
Definition: flow.c:547
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_DIREC_SRC
@ SIG_DIREC_SRC
Definition: detect-parse.h:47
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
SignatureHook_::t
union SignatureHook_::@93 t
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:5423
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
SignatureHook_::pkt
struct SignatureHook_::@93::@95 pkt
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:29
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:1244
DetectGetLastSMFromMpmLists
SigMatch * DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
get the last SigMatch from lists that support MPM.
Definition: detect-parse.c:527
SignatureHook_::app
struct SignatureHook_::@93::@94 app
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:1682
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:3619
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:1452
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:1111
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:3360
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
PacketFree
void PacketFree(Packet *p)
Return a malloced packet.
Definition: decode.c:219
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:3607
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3097
DetectPort_
Port structure for detection engine.
Definition: detect.h:220
SigTableElmt_::alternative
uint16_t alternative
Definition: detect.h:1455
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
SIG_DIREC_SWITCHED
@ SIG_DIREC_SWITCHED
Definition: detect-parse.h:41
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:2256
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:1670
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:1419
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:2185
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:968
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
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:3439
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:1458
PORT_EQ
@ PORT_EQ
Definition: detect.h:208
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:691
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
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:3592
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:941
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:1112
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:1659
SignatureInitDataBuffer_::only_ts
bool only_ts
Definition: detect.h:532
util-validate.h
PacketGetFromAlloc
Packet * PacketGetFromAlloc(void)
Get a malloced packet.
Definition: decode.c:258
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:1087
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:1676
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:1441
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:2594
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:1636
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:3595
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:587
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:1649
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:1025
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:3503
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:938
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:934
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:953
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:3540
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:3367
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_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