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