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