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 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 SigParseAction(Signature *s, const char *action_in)
1558 {
1559  char action[32];
1560  strlcpy(action, action_in, sizeof(action));
1561  const char *a = action;
1562  const char *o = NULL;
1563 
1564  bool has_scope = strchr(action, ':') != NULL;
1565  if (has_scope) {
1566  char *xsaveptr = NULL;
1567  a = strtok_r(action, ":", &xsaveptr);
1568  o = strtok_r(NULL, ":", &xsaveptr);
1569  SCLogDebug("a: '%s' o: '%s'", a, o);
1570  }
1571  if (a == NULL) {
1572  SCLogError("invalid protocol specification '%s'", action_in);
1573  return -1;
1574  }
1575 
1576  uint8_t flags = ActionStringToFlags(a);
1577  if (flags == 0)
1578  return -1;
1579 
1580  /* parse scope, if any */
1581  if (o) {
1582  uint8_t scope_flags = 0;
1583  if (flags & (ACTION_DROP | ACTION_PASS)) {
1584  if (strcmp(o, "packet") == 0) {
1585  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1586  } else if (strcmp(o, "flow") == 0) {
1587  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1588  } else {
1589  SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1590  "allowed",
1591  o, action_in);
1592  return -1;
1593  }
1594  s->action_scope = scope_flags;
1595  } else if (flags & (ACTION_ACCEPT)) {
1596  if (strcmp(o, "packet") == 0) {
1597  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1598  } else if (strcmp(o, "hook") == 0) {
1599  scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1600  } else if (strcmp(o, "tx") == 0) {
1601  scope_flags = (uint8_t)ACTION_SCOPE_TX;
1602  } else if (strcmp(o, "flow") == 0) {
1603  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1604  } else {
1605  SCLogError(
1606  "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1607  "'hook' allowed",
1608  o, action_in);
1609  return -1;
1610  }
1611  s->action_scope = scope_flags;
1612  } else if (flags & (ACTION_CONFIG)) {
1613  if (strcmp(o, "packet") == 0) {
1614  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1615  } else {
1616  SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
1617  action_in);
1618  return -1;
1619  }
1620  s->action_scope = scope_flags;
1621  } else {
1622  SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1623  "'drop', 'pass' and 'reject'",
1624  o, action_in);
1625  return -1;
1626  }
1627  }
1628 
1629  /* require explicit action scope for fw rules */
1630  if (s->init_data->firewall_rule && s->action_scope == 0) {
1631  SCLogError("firewall rules require setting an explicit action scope");
1632  return -1;
1633  }
1634 
1635  if (!s->init_data->firewall_rule && (flags & ACTION_ACCEPT)) {
1636  SCLogError("'accept' action only supported for firewall rules");
1637  return -1;
1638  }
1639 
1640  if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
1641  SCLogError("'pass' action not supported for firewall rules");
1642  return -1;
1643  }
1644 
1645  s->action = flags;
1646  return 0;
1647 }
1648 
1649 /**
1650  * \brief Parse the next token in rule.
1651  *
1652  * For rule parsing a token is considered to be a string of characters
1653  * separated by white space.
1654  *
1655  * \param input double pointer to input buffer, will be advanced as input is
1656  * parsed.
1657  * \param output buffer to copy token into.
1658  * \param output_size length of output buffer.
1659  */
1660 static inline int SigParseToken(char **input, char *output,
1661  const size_t output_size)
1662 {
1663  size_t len = *input == NULL ? 0 : strlen(*input);
1664 
1665  if (!len) {
1666  return 0;
1667  }
1668 
1669  while (len && isblank(**input)) {
1670  (*input)++;
1671  len--;
1672  }
1673 
1674  char *endptr = strpbrk(*input, " \t\n\r");
1675  if (endptr != NULL) {
1676  *(endptr++) = '\0';
1677  }
1678  strlcpy(output, *input, output_size);
1679  *input = endptr;
1680 
1681  return 1;
1682 }
1683 
1684 /**
1685  * \brief Parse the next rule "list" token.
1686  *
1687  * Parses rule tokens that may be lists such as addresses and ports
1688  * handling the case when they may not be lists.
1689  *
1690  * \param input double pointer to input buffer, will be advanced as input is
1691  * parsed.
1692  * \param output buffer to copy token into.
1693  * \param output_size length of output buffer.
1694  */
1695 static inline int SigParseList(char **input, char *output,
1696  const size_t output_size)
1697 {
1698  int in_list = 0;
1699  size_t len = *input != NULL ? strlen(*input) : 0;
1700 
1701  if (len == 0) {
1702  return 0;
1703  }
1704 
1705  while (len && isblank(**input)) {
1706  (*input)++;
1707  len--;
1708  }
1709 
1710  size_t i = 0;
1711  for (i = 0; i < len; i++) {
1712  char c = (*input)[i];
1713  if (c == '[') {
1714  in_list++;
1715  } else if (c == ']') {
1716  in_list--;
1717  } else if (c == ' ') {
1718  if (!in_list) {
1719  break;
1720  }
1721  }
1722  }
1723  if (i == len) {
1724  *input = NULL;
1725  return 0;
1726  }
1727  (*input)[i] = '\0';
1728  strlcpy(output, *input, output_size);
1729  *input = *input + i + 1;
1730 
1731  return 1;
1732 }
1733 
1734 /**
1735  * \internal
1736  * \brief split a signature string into a few blocks for further parsing
1737  *
1738  * \param scan_only just scan, don't validate
1739  */
1740 static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1741  SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1742 {
1743  char *index, dup[DETECT_MAX_RULE_SIZE];
1744 
1745  strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1746  index = dup;
1747 
1748  /* Action. */
1749  SigParseToken(&index, parser->action, sizeof(parser->action));
1750 
1751  /* Protocol. */
1752  SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1753 
1754  /* Source. */
1755  SigParseList(&index, parser->src, sizeof(parser->src));
1756 
1757  /* Source port(s). */
1758  SigParseList(&index, parser->sp, sizeof(parser->sp));
1759 
1760  /* Direction. */
1761  SigParseToken(&index, parser->direction, sizeof(parser->direction));
1762 
1763  /* Destination. */
1764  SigParseList(&index, parser->dst, sizeof(parser->dst));
1765 
1766  /* Destination port(s). */
1767  SigParseList(&index, parser->dp, sizeof(parser->dp));
1768 
1769  /* Options. */
1770  if (index == NULL) {
1771  SCLogError("no rule options.");
1772  goto error;
1773  }
1774  while (isspace(*index) || *index == '(') {
1775  index++;
1776  }
1777  for (size_t i = strlen(index); i > 0; i--) {
1778  if (isspace(index[i - 1]) || index[i - 1] == ')') {
1779  index[i - 1] = '\0';
1780  } else {
1781  break;
1782  }
1783  }
1784  strlcpy(parser->opts, index, sizeof(parser->opts));
1785 
1786  if (scan_only) {
1787  return 0;
1788  }
1789 
1790  /* Parse Action */
1791  if (SigParseAction(s, parser->action) < 0)
1792  goto error;
1793 
1794  if (SigParseProto(s, parser->protocol) < 0)
1795  goto error;
1796 
1797  if (strcmp(parser->direction, "<>") == 0) {
1799  } else if (strcmp(parser->direction, "=>") == 0) {
1800  if (s->flags & SIG_FLAG_FIREWALL) {
1801  SCLogError("transactional bidirectional rules not supported for firewall rules");
1802  goto error;
1803  }
1804 
1805  s->flags |= SIG_FLAG_TXBOTHDIR;
1806  } else if (strcmp(parser->direction, "->") != 0) {
1807  SCLogError("\"%s\" is not a valid direction modifier, "
1808  "\"->\" and \"<>\" are supported.",
1809  parser->direction);
1810  goto error;
1811  }
1812 
1813  /* Parse Address & Ports */
1814  if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1815  goto error;
1816 
1817  if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1818  goto error;
1819 
1820  /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1821  * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1822  * changes that we made sees to it that at this point of time we don't
1823  * set the ip proto for the sig. We do it a bit later. */
1824  if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1825  goto error;
1826  if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1827  goto error;
1828 
1829  return 0;
1830 
1831 error:
1832  return -1;
1833 }
1834 
1835 static inline bool CheckAscii(const char *str)
1836 {
1837  for (size_t i = 0; i < strlen(str); i++) {
1838  if (str[i] < 0x20) {
1839  // LF CR TAB
1840  if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1841  continue;
1842  }
1843  return false;
1844  } else if (str[i] == 0x7f) {
1845  return false;
1846  }
1847  }
1848  return true;
1849 }
1850 
1851 /**
1852  * \brief parse a signature
1853  *
1854  * \param de_ctx detection engine ctx to add it to
1855  * \param s memory structure to store the signature in
1856  * \param sigstr the raw signature as a null terminated string
1857  * \param addrs_direction direction (for bi-directional sigs)
1858  * \param require only scan rule for requires
1859  *
1860  * \param -1 parse error
1861  * \param 0 ok
1862  */
1863 static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1864  uint8_t addrs_direction, SignatureParser *parser, bool requires)
1865 {
1866  SCEnter();
1867 
1868  if (!SCCheckUtf8(sigstr)) {
1869  SCLogError("rule is not valid UTF-8");
1870  SCReturnInt(-1);
1871  }
1872 
1873  if (!CheckAscii(sigstr)) {
1874  SCLogError("rule contains invalid (control) characters");
1875  SCReturnInt(-1);
1876  }
1877 
1878  int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
1879  if (ret < 0) {
1880  SCLogDebug("SigParseBasics failed");
1881  SCReturnInt(-1);
1882  }
1883 
1884  /* we can have no options, so make sure we have them */
1885  if (strlen(parser->opts) > 0) {
1886  size_t buffer_size = strlen(parser->opts) + 1;
1888  char input[buffer_size];
1889  char output[buffer_size];
1890  memset(input, 0x00, buffer_size);
1891  memcpy(input, parser->opts, strlen(parser->opts) + 1);
1892 
1893  /* loop the option parsing. Each run processes one option
1894  * and returns the rest of the option string through the
1895  * output variable. */
1896  do {
1897  memset(output, 0x00, buffer_size);
1898  ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
1899  if (ret == 1) {
1900  memcpy(input, output, buffer_size);
1901  }
1902 
1903  } while (ret == 1);
1904 
1905  if (ret < 0) {
1906  /* Suricata didn't meet the rule requirements, skip. */
1907  goto end;
1908  }
1909  }
1910 
1911 end:
1913 
1914  SCReturnInt(ret);
1915 }
1916 
1917 /** \brief check if buffers array still has space left, expand if not
1918  */
1920 {
1921  if (s->init_data->buffers_size >= 64)
1922  return -1;
1923 
1924  if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
1925  void *ptr = SCRealloc(s->init_data->buffers,
1926  (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
1927  if (ptr == NULL)
1928  return -1;
1929  s->init_data->buffers = ptr;
1930  for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
1932  memset(b, 0, sizeof(*b));
1933  }
1934  s->init_data->buffers_size += 8;
1935  }
1936  return 0;
1937 }
1938 
1940 {
1941  Signature *sig = SCCalloc(1, sizeof(Signature));
1942  if (unlikely(sig == NULL))
1943  return NULL;
1944 
1945  sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
1946  if (sig->init_data == NULL) {
1947  SCFree(sig);
1948  return NULL;
1949  }
1950  sig->init_data->mpm_sm_list = -1;
1951 
1952  sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
1953  if (sig->init_data->buffers == NULL) {
1954  SCFree(sig->init_data);
1955  SCFree(sig);
1956  return NULL;
1957  }
1958  sig->init_data->buffers_size = 8;
1959 
1960  /* assign it to -1, so that we can later check if the value has been
1961  * overwritten after the Signature has been parsed, and if it hasn't been
1962  * overwritten, we can then assign the default value of 3 */
1963  sig->prio = -1;
1964 
1965  /* rule interdepency is false, at start */
1966  sig->init_data->is_rule_state_dependant = false;
1967  /* first index is 0 */
1969 
1971  return sig;
1972 }
1973 
1974 /**
1975  * \internal
1976  * \brief Free Metadata list
1977  *
1978  * \param s Pointer to the signature
1979  */
1980 static void SigMetadataFree(Signature *s)
1981 {
1982  SCEnter();
1983 
1984  DetectMetadata *mdata = NULL;
1985  DetectMetadata *next_mdata = NULL;
1986 
1987  if (s == NULL || s->metadata == NULL) {
1988  SCReturn;
1989  }
1990 
1991  SCLogDebug("s %p, s->metadata %p", s, s->metadata);
1992 
1993  for (mdata = s->metadata->list; mdata != NULL;) {
1994  next_mdata = mdata->next;
1995  DetectMetadataFree(mdata);
1996  mdata = next_mdata;
1997  }
1998  SCFree(s->metadata->json_str);
1999  SCFree(s->metadata);
2000  s->metadata = NULL;
2001 
2002  SCReturn;
2003 }
2004 
2005 /**
2006  * \internal
2007  * \brief Free Reference list
2008  *
2009  * \param s Pointer to the signature
2010  */
2011 static void SigRefFree (Signature *s)
2012 {
2013  SCEnter();
2014 
2015  DetectReference *ref = NULL;
2016  DetectReference *next_ref = NULL;
2017 
2018  if (s == NULL) {
2019  SCReturn;
2020  }
2021 
2022  SCLogDebug("s %p, s->references %p", s, s->references);
2023 
2024  for (ref = s->references; ref != NULL;) {
2025  next_ref = ref->next;
2026  DetectReferenceFree(ref);
2027  ref = next_ref;
2028  }
2029 
2030  s->references = NULL;
2031 
2032  SCReturn;
2033 }
2034 
2035 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2036 {
2037  if (s != NULL) {
2038  int type;
2039  for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2040  if (s->sm_arrays[type] != NULL) {
2041  if (ctxs) {
2042  SigMatchData *smd = s->sm_arrays[type];
2043  while(1) {
2044  if (sigmatch_table[smd->type].Free != NULL) {
2045  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2046  }
2047  if (smd->is_last)
2048  break;
2049  smd++;
2050  }
2051  }
2052 
2053  SCFree(s->sm_arrays[type]);
2054  }
2055  }
2056  }
2057 }
2058 
2060 {
2061  if (s == NULL)
2062  return;
2063 
2064  int i;
2065 
2066  if (s->init_data && s->init_data->transforms.cnt) {
2067  for(i = 0; i < s->init_data->transforms.cnt; i++) {
2068  if (s->init_data->transforms.transforms[i].options) {
2069  int transform = s->init_data->transforms.transforms[i].transform;
2070  sigmatch_table[transform].Free(
2072  s->init_data->transforms.transforms[i].options = NULL;
2073  }
2074  }
2075  }
2076  if (s->init_data) {
2077  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2078  SigMatch *sm = s->init_data->smlists[i];
2079  while (sm != NULL) {
2080  SigMatch *nsm = sm->next;
2081  SigMatchFree(de_ctx, sm);
2082  sm = nsm;
2083  }
2084  }
2085 
2086  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2087  SigMatch *sm = s->init_data->buffers[x].head;
2088  while (sm != NULL) {
2089  SigMatch *nsm = sm->next;
2090  SigMatchFree(de_ctx, sm);
2091  sm = nsm;
2092  }
2093  }
2094  if (s->init_data->cidr_dst != NULL)
2096 
2097  if (s->init_data->cidr_src != NULL)
2099 
2100  SCFree(s->init_data->buffers);
2101  s->init_data->buffers = NULL;
2102  }
2103  SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2104  if (s->init_data) {
2105  SCFree(s->init_data);
2106  s->init_data = NULL;
2107  }
2108 
2109  if (s->sp != NULL) {
2110  DetectPortCleanupList(NULL, s->sp);
2111  }
2112  if (s->dp != NULL) {
2113  DetectPortCleanupList(NULL, s->dp);
2114  }
2115  if (s->proto) {
2116  SCFree(s->proto);
2117  }
2118 
2119  if (s->msg != NULL)
2120  SCFree(s->msg);
2121 
2122  if (s->addr_src_match4 != NULL) {
2123  SCFree(s->addr_src_match4);
2124  }
2125  if (s->addr_dst_match4 != NULL) {
2126  SCFree(s->addr_dst_match4);
2127  }
2128  if (s->addr_src_match6 != NULL) {
2129  SCFree(s->addr_src_match6);
2130  }
2131  if (s->addr_dst_match6 != NULL) {
2132  SCFree(s->addr_dst_match6);
2133  }
2134  if (s->sig_str != NULL) {
2135  SCFree(s->sig_str);
2136  }
2137 
2138  SigRefFree(s);
2139  SigMetadataFree(s);
2140 
2142 
2143  SCFree(s);
2144 }
2145 
2146 /**
2147  * \brief this function is used to set multiple possible app-layer protos
2148  * \brief into the current signature (for example ja4 for both tls and quic)
2149  *
2150  * \param s pointer to the Current Signature
2151  * \param alprotos an array terminated by ALPROTO_UNKNOWN
2152  *
2153  * \retval 0 on Success
2154  * \retval -1 on Failure
2155  */
2157 {
2158  if (s->alproto != ALPROTO_UNKNOWN) {
2159  // One alproto was set, check if it matches the new ones proposed
2160  while (*alprotos != ALPROTO_UNKNOWN) {
2161  if (s->alproto == *alprotos) {
2162  // alproto already set to only one
2163  return 0;
2164  }
2165  alprotos++;
2166  }
2167  // alproto already set and not matching the new set of alprotos
2168  return -1;
2169  }
2170  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2171  // check intersection of already used alprotos and new ones
2172  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2173  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2174  break;
2175  }
2176  // first disable the ones that do not match
2177  bool found = false;
2178  const AppProto *args = alprotos;
2179  while (*args != ALPROTO_UNKNOWN) {
2180  if (s->init_data->alprotos[i] == *args) {
2181  found = true;
2182  break;
2183  }
2184  args++;
2185  }
2186  if (!found) {
2188  }
2189  }
2190  // Then put at the beginning every defined protocol
2191  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2192  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2193  for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2194  if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2195  s->init_data->alprotos[i] = s->init_data->alprotos[j];
2197  break;
2198  }
2199  }
2200  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2201  if (i == 0) {
2202  // there was no intersection
2203  return -1;
2204  } else if (i == 1) {
2205  // intersection is singleton, set it as usual
2206  AppProto alproto = s->init_data->alprotos[0];
2208  return SCDetectSignatureSetAppProto(s, alproto);
2209  }
2210  break;
2211  }
2212  }
2213  }
2214  } else {
2215  if (alprotos[0] == ALPROTO_UNKNOWN) {
2216  // do not allow empty set
2217  return -1;
2218  }
2219  if (alprotos[1] == ALPROTO_UNKNOWN) {
2220  // allow singleton, but call traditional setter
2221  return SCDetectSignatureSetAppProto(s, alprotos[0]);
2222  }
2223  // first time we enforce alprotos
2224  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2225  if (alprotos[i] == ALPROTO_UNKNOWN) {
2226  break;
2227  }
2228  s->init_data->alprotos[i] = alprotos[i];
2229  }
2230  }
2231  return 0;
2232 }
2233 
2235 {
2236  if (!AppProtoIsValid(alproto)) {
2237  SCLogError("invalid alproto %u", alproto);
2238  return -1;
2239  }
2240 
2241  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2242  // Multiple alprotos were set, check if we restrict to one
2243  bool found = false;
2244  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2245  if (s->init_data->alprotos[i] == alproto) {
2246  found = true;
2247  break;
2248  }
2249  }
2250  if (!found) {
2251  // fail if we set to a alproto which was not in the set
2252  return -1;
2253  }
2254  // we will use s->alproto if there is a single alproto and
2255  // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2257  }
2258 
2259  if (s->alproto != ALPROTO_UNKNOWN) {
2260  alproto = AppProtoCommon(s->alproto, alproto);
2261  if (alproto == ALPROTO_FAILED) {
2262  SCLogError("can't set rule app proto to %s: already set to %s",
2263  AppProtoToString(alproto), AppProtoToString(s->alproto));
2264  return -1;
2265  }
2266  }
2267 
2268  if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2269  SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2270  return -1;
2271  }
2272  s->alproto = alproto;
2273  s->flags |= SIG_FLAG_APPLAYER;
2274  return 0;
2275 }
2276 
2277 static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2278  const DetectAddress *head, uint16_t *match4_cnt)
2279 {
2280  uint16_t cnt = 0;
2281 
2282  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2283  cnt++;
2284  }
2285  if (cnt == 0) {
2286  return NULL;
2287  }
2288  DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2289  if (addr_match4 == NULL) {
2290  return NULL;
2291  }
2292 
2293  uint16_t idx = 0;
2294  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2295  addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2296  addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2297  idx++;
2298  }
2299  *match4_cnt = cnt;
2300  return addr_match4;
2301 }
2302 
2303 static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2304  const DetectAddress *head, uint16_t *match6_cnt)
2305 {
2306  uint16_t cnt = 0;
2307  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2308  cnt++;
2309  }
2310  if (cnt == 0) {
2311  return NULL;
2312  }
2313 
2314  DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2315  if (addr_match6 == NULL) {
2316  return NULL;
2317  }
2318 
2319  uint16_t idx = 0;
2320  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2321  addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2322  addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2323  addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2324  addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2325  addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2326  addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2327  addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2328  addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2329  idx++;
2330  }
2331  *match6_cnt = cnt;
2332  return addr_match6;
2333 }
2334 
2335 /**
2336  * \internal
2337  * \brief build address match array for cache efficient matching
2338  *
2339  * \param s the signature
2340  */
2341 static void SigBuildAddressMatchArray(Signature *s)
2342 {
2343  /* source addresses */
2344  s->addr_src_match4 =
2345  SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2346  /* destination addresses */
2347  s->addr_dst_match4 =
2348  SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2349 
2350  /* source addresses IPv6 */
2351  s->addr_src_match6 =
2352  SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2353  /* destination addresses IPv6 */
2354  s->addr_dst_match6 =
2355  SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2356 }
2357 
2358 static int SigMatchListLen(SigMatch *sm)
2359 {
2360  int len = 0;
2361  for (; sm != NULL; sm = sm->next)
2362  len++;
2363 
2364  return len;
2365 }
2366 
2367 /** \brief convert SigMatch list to SigMatchData array
2368  * \note ownership of sm->ctx is transferred to smd->ctx
2369  */
2371 {
2372  int len = SigMatchListLen(head);
2373  if (len == 0)
2374  return NULL;
2375 
2376  SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
2377  if (smd == NULL) {
2378  FatalError("initializing the detection engine failed");
2379  }
2380  SigMatchData *out = smd;
2381 
2382  /* Copy sm type and Context into array */
2383  SigMatch *sm = head;
2384  for (; sm != NULL; sm = sm->next, smd++) {
2385  smd->type = sm->type;
2386  smd->ctx = sm->ctx;
2387  sm->ctx = NULL; // SigMatch no longer owns the ctx
2388  smd->is_last = (sm->next == NULL);
2389  }
2390  return out;
2391 }
2392 
2393 extern int g_skip_prefilter;
2394 
2395 static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2396 {
2397  SCEnter();
2398  SCLogDebug("s %u: set up prefilter/mpm", s->id);
2399  DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
2400 
2401  if (s->init_data->prefilter_sm != NULL) {
2402  if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
2404  if (s->init_data->mpm_sm != NULL) {
2405  s->flags |= SIG_FLAG_PREFILTER;
2406  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2407  SCReturn;
2408  }
2409  /* fall through, this can happen if the mpm doesn't support the pattern */
2410  } else {
2411  s->flags |= SIG_FLAG_PREFILTER;
2412  SCReturn;
2413  }
2414  } else {
2415  SCLogDebug("%u: RetrieveFPForSig", s->id);
2417  if (s->init_data->mpm_sm != NULL) {
2418  s->flags |= SIG_FLAG_PREFILTER;
2419  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2420  SCReturn;
2421  }
2422  }
2423 
2424  SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2425  "s->init_data->has_possible_prefilter %s",
2427 
2429  SCReturn;
2430 
2433  int prefilter_list = DETECT_TBLSIZE;
2434  /* get the keyword supporting prefilter with the lowest type */
2435  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2436  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2437  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2438  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
2439  prefilter_list = MIN(prefilter_list, sm->type);
2440  }
2441  }
2442  }
2443  }
2444 
2445  /* apply that keyword as prefilter */
2446  if (prefilter_list != DETECT_TBLSIZE) {
2447  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2448  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2449  if (sm->type == prefilter_list) {
2450  s->init_data->prefilter_sm = sm;
2451  s->flags |= SIG_FLAG_PREFILTER;
2452  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2453  sigmatch_table[sm->type].name);
2454  break;
2455  }
2456  }
2457  }
2458  }
2459  }
2460  SCReturn;
2461 }
2462 
2463 /** \internal
2464  * \brief check if signature's table requirement is supported by each of the keywords it uses.
2465  */
2466 static bool DetectRuleValidateTable(const Signature *s)
2467 {
2468  if (s->detect_table == 0)
2469  return true;
2470 
2471  const uint8_t table_as_flag = BIT_U8(s->detect_table);
2472 
2473  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
2474  const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
2475  if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
2476  SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
2478  return false;
2479  }
2480  }
2481  return true;
2482 }
2483 
2484 static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2485 {
2487  SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2488  "explicit hook",
2489  s->id);
2490  return false;
2491  }
2492  return true;
2493 }
2494 
2495 static void DetectRuleSetTable(Signature *s)
2496 {
2497  enum DetectTable table;
2498  if (s->flags & SIG_FLAG_FIREWALL) {
2499  if (s->type == SIG_TYPE_PKT) {
2503  else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
2506  else
2508  } else if (s->type == SIG_TYPE_APP_TX) {
2509  table = DETECT_TABLE_APP_FILTER;
2510  } else {
2511  BUG_ON(1);
2512  }
2513  } else {
2514  // TODO pre_flow/pre_stream
2515  if (s->type != SIG_TYPE_APP_TX) {
2516  table = DETECT_TABLE_PACKET_TD;
2517  } else {
2518  table = DETECT_TABLE_APP_TD;
2519  }
2520  }
2521 
2522  s->detect_table = (uint8_t)table;
2523 }
2524 
2525 static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2526 {
2527  if (s->init_data->firewall_rule) {
2528  if (!DetectFirewallRuleValidate(de_ctx, s))
2529  SCReturnInt(0);
2530  }
2531  SCReturnInt(1);
2532 }
2533 
2534 static int SigValidateCheckBuffers(
2535  DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2536 {
2537  bool has_frame = false;
2538  bool has_app = false;
2539  bool has_pkt = false;
2540  bool has_pmatch = false;
2541 
2542  int nlists = 0;
2543  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2544  nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2545  }
2546  nlists += (nlists > 0);
2547  SCLogDebug("nlists %d", nlists);
2548 
2549  if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2550  SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2552  SCReturnInt(0);
2553  }
2554 
2555  /* run buffer type validation callbacks if any */
2558  SCReturnInt(0);
2559 
2560  has_pmatch = true;
2561  }
2562 
2563  DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
2564  struct BufferVsDir {
2565  int ts;
2566  int tc;
2567  } bufdir[nlists + 1];
2568  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2569 
2570  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2573  if (bt == NULL) {
2574  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2575  continue;
2576  }
2577  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2578  for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2579  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2580  }
2581 
2582  if (b->head == NULL) {
2583  SCLogError("no matches in sticky buffer %s", bt->name);
2584  SCReturnInt(0);
2585  }
2586 
2587  has_frame |= bt->frame;
2588  has_app |= (!bt->frame && !bt->packet);
2589  has_pkt |= bt->packet;
2590 
2591  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2592  SCLogError("Signature combines packet "
2593  "specific matches (like dsize, flags, ttl) with stream / "
2594  "state matching by matching on app layer proto (like using "
2595  "http_* keywords).");
2596  SCReturnInt(0);
2597  }
2598 
2600  for (; app != NULL; app = app->next) {
2601  if (app->sm_list == b->id &&
2602  (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2603  SCLogDebug("engine %s dir %d alproto %d",
2605  app->alproto);
2606  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2607 
2608  if (b->only_tc) {
2609  if (app->dir == 1)
2610  (*tc_excl)++;
2611  } else if (b->only_ts) {
2612  if (app->dir == 0)
2613  (*ts_excl)++;
2614  } else {
2615  bufdir[b->id].ts += (app->dir == 0);
2616  bufdir[b->id].tc += (app->dir == 1);
2617  }
2618 
2619  /* only allow rules to use the hook for engines at that
2620  * exact progress for now. */
2622  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2623  app->progress != s->init_data->hook.t.app.app_progress) {
2624  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2625  s->init_data->hook.t.app.app_progress);
2626  SCReturnInt(0);
2627  }
2628  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2629  app->progress != s->init_data->hook.t.app.app_progress) {
2630  SCLogError("engine progress value doesn't match hook");
2631  SCReturnInt(0);
2632  }
2633  }
2634  }
2635  }
2636 
2638  SCReturnInt(0);
2639  }
2640 
2642  SCReturnInt(0);
2643  }
2645  SCReturnInt(0);
2646  }
2647  }
2648 
2649  if (has_pmatch && has_frame) {
2650  SCLogError("can't mix pure content and frame inspection");
2651  SCReturnInt(0);
2652  }
2653  if (has_app && has_frame) {
2654  SCLogError("can't mix app-layer buffer and frame inspection");
2655  SCReturnInt(0);
2656  }
2657  if (has_pkt && has_frame) {
2658  SCLogError("can't mix pkt buffer and frame inspection");
2659  SCReturnInt(0);
2660  }
2661 
2662  for (int x = 0; x < nlists; x++) {
2663  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2664  continue;
2665  (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2666  (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2667  (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2668 
2669  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2670  bufdir[x].tc);
2671  }
2672 
2673  SCReturnInt(1);
2674 }
2675 
2676 static int SigValidatePacketStream(const Signature *s)
2677 {
2679  SCLogError("can't mix packet keywords with "
2680  "tcp-stream or flow:only_stream. Invalidating signature.");
2681  SCReturnInt(0);
2682  }
2683  SCReturnInt(1);
2684 }
2685 
2686 static int SigConsolidateDirection(
2687  Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2688 {
2689  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2690  if (!ts_excl || !tc_excl) {
2691  SCLogError("rule %u should use both directions, but does not", s->id);
2692  SCReturnInt(0);
2693  }
2694  if (dir_amb) {
2695  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2696  "directions",
2697  s->id);
2698  SCReturnInt(0);
2699  }
2700  } else if (ts_excl && tc_excl) {
2701  SCLogError(
2702  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2703  "should be used",
2704  s->id);
2705  SCReturnInt(0);
2706  } else if (ts_excl) {
2707  SCLogDebug("%u: implied rule direction is toserver", s->id);
2709  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2710  SCReturnInt(0);
2711  }
2712  } else if (tc_excl) {
2713  SCLogDebug("%u: implied rule direction is toclient", s->id);
2715  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2716  SCReturnInt(0);
2717  }
2718  } else if (dir_amb) {
2719  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2720  }
2721  SCReturnInt(1);
2722 }
2723 
2724 static void SigConsolidateTcpBuffer(Signature *s)
2725 {
2726  /* TCP: corner cases:
2727  * - pkt vs stream vs depth/offset
2728  * - pkt vs stream vs stream_size
2729  */
2730  if (DetectProtoContainsProto(&s->init_data->proto, IPPROTO_TCP)) {
2734  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2735  sm = sm->next) {
2736  if (sm->type == DETECT_CONTENT &&
2737  (((DetectContentData *)(sm->ctx))->flags &
2740  break;
2741  }
2742  }
2743  /* if stream_size is in use, also inspect packets */
2744  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2745  sm = sm->next) {
2746  if (sm->type == DETECT_STREAM_SIZE) {
2748  break;
2749  }
2750  }
2751  }
2752  }
2753  }
2754 }
2755 
2756 static bool SigInspectsFiles(const Signature *s)
2757 {
2758  return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2760 }
2761 
2762 /** \internal
2763  * \brief validate file handling
2764  * \retval 1 good signature
2765  * \retval 0 bad signature
2766  */
2767 static int SigValidateFileHandling(const Signature *s)
2768 {
2769  if (!SigInspectsFiles(s)) {
2770  SCReturnInt(1);
2771  }
2772 
2773  if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
2774  !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
2775  SCLogError("protocol %s doesn't "
2776  "support file matching",
2778  SCReturnInt(0);
2779  }
2780  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2781  bool found = false;
2782  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2783  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2784  break;
2785  }
2786  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
2787  AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
2788  found = true;
2789  break;
2790  }
2791  }
2792  if (!found) {
2793  SCLogError("No protocol support file matching");
2794  SCReturnInt(0);
2795  }
2796  }
2798  SCLogError("protocol HTTP2 doesn't support file name matching");
2799  SCReturnInt(0);
2800  }
2801  SCReturnInt(1);
2802 }
2803 
2804 static bool SigValidateEthernet(const Signature *s)
2805 {
2807  if ((s->flags & (SIG_FLAG_SP_ANY | SIG_FLAG_DP_ANY)) !=
2809  SCLogError("can't use ports with ether or arp rule");
2810  return false;
2811  }
2812  }
2813  return true;
2814 }
2815 
2816 /* `pkthdr` is meant to allow matching on "any" packet with a decoder event. */
2817 static bool SigValidateProtoPkthdr(const Signature *s)
2818 {
2820  SCLogError("protocol 'pkthdr' is for decoder-events only");
2821  return false;
2822  }
2823  return true;
2824 }
2825 
2826 /**
2827  * \internal
2828  * \brief validate and consolidate parsed signature
2829  *
2830  * \param de_ctx detect engine
2831  * \param s signature to validate and consolidate
2832  *
2833  * \retval 0 invalid
2834  * \retval 1 valid
2835  */
2836 static int SigValidateConsolidate(
2837  DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2838 {
2839  SCEnter();
2840 
2841  if (SigValidateFirewall(de_ctx, s) == 0)
2842  SCReturnInt(0);
2843 
2844  if (SigValidatePacketStream(s) == 0) {
2845  SCReturnInt(0);
2846  }
2847 
2848  if (!SigValidateEthernet(s)) {
2849  SCReturnInt(0);
2850  }
2851 
2852  int ts_excl = 0;
2853  int tc_excl = 0;
2854  int dir_amb = 0;
2855 
2856  if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
2857  SCReturnInt(0);
2858  }
2859 
2860  if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
2861  SCReturnInt(0);
2862  }
2863 
2864  SigConsolidateTcpBuffer(s);
2865 
2867  DetectRuleSetTable(s);
2868 
2869  if (!SigValidateProtoPkthdr(s)) {
2870  SCReturnInt(0);
2871  }
2872 
2873  if (DetectProtoFinalizeSignature(s) != 0)
2874  SCReturnInt(0);
2875 
2876  int r = SigValidateFileHandling(s);
2877  if (r == 0) {
2878  SCReturnInt(0);
2879  }
2880  if (SigInspectsFiles(s)) {
2881  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2883  }
2884  }
2885  if (DetectRuleValidateTable(s) == false) {
2886  SCReturnInt(0);
2887  }
2888 
2889  if (s->type == SIG_TYPE_IPONLY) {
2890  /* For IPOnly */
2891  if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
2892  SCReturnInt(0);
2893 
2894  if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
2895  SCReturnInt(0);
2896  }
2897  SCReturnInt(1);
2898 }
2899 
2900 /**
2901  * \internal
2902  * \brief Helper function for SigInit().
2903  */
2904 static Signature *SigInitHelper(
2905  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2906 {
2907  SignatureParser parser;
2908  memset(&parser, 0x00, sizeof(parser));
2909 
2910  Signature *sig = SigAlloc();
2911  if (sig == NULL)
2912  goto error;
2913  if (firewall_rule) {
2914  sig->init_data->firewall_rule = true;
2915  sig->flags |= SIG_FLAG_FIREWALL;
2916  }
2917 
2918  sig->sig_str = SCStrdup(sigstr);
2919  if (unlikely(sig->sig_str == NULL)) {
2920  goto error;
2921  }
2922 
2923  /* default gid to 1 */
2924  sig->gid = 1;
2925 
2926  /* We do a first parse of the rule in a requires, or scan-only
2927  * mode. Syntactic errors will be picked up here, but the only
2928  * part of the rule that is validated completely is the "requires"
2929  * keyword. */
2930  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
2931  if (ret == -4) {
2932  /* Rule requirements not met. */
2933  de_ctx->sigerror_silent = true;
2934  de_ctx->sigerror_ok = true;
2935  de_ctx->sigerror_requires = true;
2936  goto error;
2937  } else if (ret < 0) {
2938  goto error;
2939  }
2940 
2941  /* Check for a SID before continuuing. */
2942  if (sig->id == 0) {
2943  SCLogError("Signature missing required value \"sid\".");
2944  goto error;
2945  }
2946 
2947  /* Now completely parse the rule. */
2948  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2949  BUG_ON(ret == -4);
2950  if (ret == -3) {
2951  de_ctx->sigerror_silent = true;
2952  de_ctx->sigerror_ok = true;
2953  goto error;
2954  } else if (ret == -2) {
2955  de_ctx->sigerror_silent = true;
2956  goto error;
2957  } else if (ret < 0) {
2958  goto error;
2959  }
2960 
2961  /* signature priority hasn't been overwritten. Using default priority */
2962  if (sig->prio == -1)
2963  sig->prio = DETECT_DEFAULT_PRIO;
2964 
2965  sig->iid = de_ctx->signum;
2966  de_ctx->signum++;
2967 
2968  if (sig->alproto != ALPROTO_UNKNOWN) {
2969  int override_needed = 0;
2970  if (sig->init_data->proto.flags & DETECT_PROTO_ANY) {
2972  memset(sig->init_data->proto.proto, 0x00, sizeof(sig->init_data->proto.proto));
2973  override_needed = 1;
2974  } else {
2975  override_needed = 1;
2976  size_t s = 0;
2977  for (s = 0; s < sizeof(sig->init_data->proto.proto); s++) {
2978  if (sig->init_data->proto.proto[s] != 0x00) {
2979  override_needed = 0;
2980  break;
2981  }
2982  }
2983  }
2984 
2985  /* at this point if we had alert ip and the ip proto was not
2986  * overridden, we use the ip proto that has been configured
2987  * against the app proto in use. */
2988  if (override_needed)
2990  }
2991 
2992  /* set the packet and app layer flags, but only if the
2993  * app layer flag wasn't already set in which case we
2994  * only consider the app layer */
2995  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
2996  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
2998  for ( ; sm != NULL; sm = sm->next) {
2999  if (sigmatch_table[sm->type].Match != NULL)
3001  }
3002  } else {
3004  }
3005  }
3006 
3007  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
3008  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
3009  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
3011  }
3012  }
3013  }
3014 
3015  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
3016  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
3017  sig->flags |= SIG_FLAG_TOSERVER;
3018  sig->flags |= SIG_FLAG_TOCLIENT;
3019  }
3020  }
3021 
3022  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
3023  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
3024  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
3025 
3026  SigBuildAddressMatchArray(sig);
3027 
3028  /* run buffer type callbacks if any */
3029  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
3030  if (sig->init_data->smlists[x])
3032  }
3033  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
3035  }
3036 
3037  SigSetupPrefilter(de_ctx, sig);
3038 
3039  /* validate signature, SigValidate will report the error reason */
3040  if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3041  goto error;
3042  }
3043 
3044  return sig;
3045 
3046 error:
3047  if (sig != NULL) {
3048  SigFree(de_ctx, sig);
3049  }
3050  return NULL;
3051 }
3052 
3053 /**
3054  * \brief Checks if a signature has the same source and destination
3055  * \param s parsed signature
3056  *
3057  * \retval true if source and destination are the same, false otherwise
3058  */
3059 static bool SigHasSameSourceAndDestination(const Signature *s)
3060 {
3061  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3062  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3063  return false;
3064  }
3065  }
3066 
3067  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3070 
3072  return false;
3073  }
3074 
3075  src = s->init_data->src->ipv6_head;
3076  dst = s->init_data->dst->ipv6_head;
3077 
3079  return false;
3080  }
3081  }
3082 
3083  return true;
3084 }
3085 
3086 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3087 {
3088  SCEnter();
3089 
3090  uint32_t oldsignum = de_ctx->signum;
3091  de_ctx->sigerror_ok = false;
3092  de_ctx->sigerror_silent = false;
3093  de_ctx->sigerror_requires = false;
3094 
3095  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3096  if (sig == NULL) {
3097  goto error;
3098  }
3099 
3101  if (SigHasSameSourceAndDestination(sig)) {
3102  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3103  "treating the rule as unidirectional", sig->id);
3104 
3106  } else {
3107  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3108  if (sig->next == NULL) {
3109  goto error;
3110  }
3111  }
3112  }
3113 
3114  SCReturnPtr(sig, "Signature");
3115 
3116 error:
3117  if (sig != NULL) {
3118  SigFree(de_ctx, sig);
3119  }
3120  /* if something failed, restore the old signum count
3121  * since we didn't install it */
3122  de_ctx->signum = oldsignum;
3123 
3124  SCReturnPtr(NULL, "Signature");
3125 }
3126 
3127 /**
3128  * \brief Parses a signature and adds it to the Detection Engine Context.
3129  *
3130  * \param de_ctx Pointer to the Detection Engine Context.
3131  * \param sigstr Pointer to a character string containing the signature to be
3132  * parsed.
3133  *
3134  * \retval Pointer to the Signature instance on success; NULL on failure.
3135  */
3136 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3137 {
3138  return SigInitDo(de_ctx, sigstr, false);
3139 }
3140 
3141 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3142 {
3143  return SigInitDo(de_ctx, sigstr, true);
3144 }
3145 
3146 /**
3147  * \brief The hash free function to be the used by the hash table -
3148  * DetectEngineCtx->dup_sig_hash_table.
3149  *
3150  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3151  */
3152 static void DetectParseDupSigFreeFunc(void *data)
3153 {
3154  if (data != NULL)
3155  SCFree(data);
3156 }
3157 
3158 /**
3159  * \brief The hash function to be the used by the hash table -
3160  * DetectEngineCtx->dup_sig_hash_table.
3161  *
3162  * \param ht Pointer to the hash table.
3163  * \param data Pointer to the data, in our case SigDuplWrapper.
3164  * \param datalen Not used in our case.
3165  *
3166  * \retval sw->s->id The generated hash value.
3167  */
3168 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3169 {
3170  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3171 
3172  return (sw->s->id % ht->array_size);
3173 }
3174 
3175 /**
3176  * \brief The Compare function to be used by the hash table -
3177  * DetectEngineCtx->dup_sig_hash_table.
3178  *
3179  * \param data1 Pointer to the first SigDuplWrapper.
3180  * \param len1 Not used.
3181  * \param data2 Pointer to the second SigDuplWrapper.
3182  * \param len2 Not used.
3183  *
3184  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3185  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3186  */
3187 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3188  uint16_t len2)
3189 {
3190  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3191  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3192 
3193  if (sw1 == NULL || sw2 == NULL ||
3194  sw1->s == NULL || sw2->s == NULL)
3195  return 0;
3196 
3197  /* sid and gid match required */
3198  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3199 
3200  return 0;
3201 }
3202 
3203 /**
3204  * \brief Initializes the hash table that is used to cull duplicate sigs.
3205  *
3206  * \param de_ctx Pointer to the detection engine context.
3207  *
3208  * \retval 0 On success.
3209  * \retval -1 On failure.
3210  */
3212 {
3214  DetectParseDupSigHashFunc,
3215  DetectParseDupSigCompareFunc,
3216  DetectParseDupSigFreeFunc);
3217  if (de_ctx->dup_sig_hash_table == NULL)
3218  return -1;
3219 
3220  return 0;
3221 }
3222 
3223 /**
3224  * \brief Frees the hash table that is used to cull duplicate sigs.
3225  *
3226  * \param de_ctx Pointer to the detection engine context that holds this table.
3227  */
3229 {
3230  if (de_ctx->dup_sig_hash_table != NULL)
3232 
3233  de_ctx->dup_sig_hash_table = NULL;
3234 }
3235 
3236 /**
3237  * \brief Check if a signature is a duplicate.
3238  *
3239  * There are 3 types of return values for this function.
3240  *
3241  * - 0, which indicates that the Signature is not a duplicate
3242  * and has to be added to the detection engine list.
3243  * - 1, Signature is duplicate, and the existing signature in
3244  * the list shouldn't be replaced with this duplicate.
3245  * - 2, Signature is duplicate, and the existing signature in
3246  * the list should be replaced with this duplicate.
3247  *
3248  * \param de_ctx Pointer to the detection engine context.
3249  * \param sig Pointer to the Signature that has to be checked.
3250  *
3251  * \retval 2 If Signature is duplicate and the existing signature in
3252  * the list should be chucked out and replaced with this.
3253  * \retval 1 If Signature is duplicate, and should be chucked out.
3254  * \retval 0 If Signature is not a duplicate.
3255  */
3256 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3257  Signature *sig)
3258 {
3259  /* we won't do any NULL checks on the args */
3260 
3261  /* return value */
3262  int ret = 0;
3263 
3264  SigDuplWrapper *sw_dup = NULL;
3265  SigDuplWrapper *sw = NULL;
3266 
3267  /* used for making a duplicate_sig_hash_table entry */
3268  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3269  if (unlikely(sw == NULL)) {
3270  exit(EXIT_FAILURE);
3271  }
3272  sw->s = sig;
3273 
3274  /* check if we have a duplicate entry for this signature */
3275  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3276  /* we don't have a duplicate entry for this sig */
3277  if (sw_dup == NULL) {
3278  /* add it to the hash table */
3279  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3280 
3281  /* add the s_prev entry for the previously loaded sw in the hash_table */
3282  if (de_ctx->sig_list != NULL) {
3283  SigDuplWrapper *sw_old = NULL;
3284  SigDuplWrapper sw_tmp;
3285  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3286 
3287  /* the topmost sig would be the last loaded sig */
3288  sw_tmp.s = de_ctx->sig_list;
3290  (void *)&sw_tmp, 0);
3291  /* sw_old == NULL case is impossible */
3292  sw_old->s_prev = sig;
3293  }
3294 
3295  ret = 0;
3296  goto end;
3297  }
3298 
3299  /* if we have reached here we have a duplicate entry for this signature.
3300  * Check the signature revision. Store the signature with the latest rev
3301  * and discard the other one */
3302  if (sw->s->rev <= sw_dup->s->rev) {
3303  ret = 1;
3304  SCFree(sw);
3305  sw = NULL;
3306  goto end;
3307  }
3308 
3309  /* the new sig is of a newer revision than the one that is already in the
3310  * list. Remove the old sig from the list */
3311  if (sw_dup->s_prev == NULL) {
3312  SigDuplWrapper sw_temp;
3313  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3314  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3315  sw_temp.s = sw_dup->s->next->next;
3316  de_ctx->sig_list = sw_dup->s->next->next;
3317  SigFree(de_ctx, sw_dup->s->next);
3318  } else {
3319  sw_temp.s = sw_dup->s->next;
3320  de_ctx->sig_list = sw_dup->s->next;
3321  }
3322  SigDuplWrapper *sw_next = NULL;
3323  if (sw_temp.s != NULL) {
3325  (void *)&sw_temp, 0);
3326  sw_next->s_prev = sw_dup->s_prev;
3327  }
3328  SigFree(de_ctx, sw_dup->s);
3329  } else {
3330  SigDuplWrapper sw_temp;
3331  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3332  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3333  sw_temp.s = sw_dup->s->next->next;
3334  /* If previous signature is bidirectional,
3335  * it has 2 items in the linked list.
3336  * So we need to change next->next instead of next
3337  */
3339  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3340  } else {
3341  sw_dup->s_prev->next = sw_dup->s->next->next;
3342  }
3343  SigFree(de_ctx, sw_dup->s->next);
3344  } else {
3345  sw_temp.s = sw_dup->s->next;
3347  sw_dup->s_prev->next->next = sw_dup->s->next;
3348  } else {
3349  sw_dup->s_prev->next = sw_dup->s->next;
3350  }
3351  }
3352  SigDuplWrapper *sw_next = NULL;
3353  if (sw_temp.s != NULL) {
3355  (void *)&sw_temp, 0);
3356  sw_next->s_prev = sw_dup->s_prev;
3357  }
3358  SigFree(de_ctx, sw_dup->s);
3359  }
3360 
3361  /* make changes to the entry to reflect the presence of the new sig */
3362  sw_dup->s = sig;
3363  sw_dup->s_prev = NULL;
3364 
3365  if (de_ctx->sig_list != NULL) {
3366  SigDuplWrapper sw_tmp;
3367  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3368  sw_tmp.s = de_ctx->sig_list;
3370  (void *)&sw_tmp, 0);
3371  if (sw_old->s != sw_dup->s) {
3372  // Link on top of the list if there was another element
3373  sw_old->s_prev = sig;
3374  }
3375  }
3376 
3377  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3378  ret = 2;
3379 
3380  SCFree(sw);
3381 
3382 end:
3383  return ret;
3384 }
3385 
3386 /**
3387  * \brief Parse and append a Signature into the Detection Engine Context
3388  * signature list.
3389  *
3390  * If the signature is bidirectional it should append two signatures
3391  * (with the addresses switched) into the list. Also handle duplicate
3392  * signatures. In case of duplicate sigs, use the ones that have the
3393  * latest revision. We use the sid and the msg to identify duplicate
3394  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3395  *
3396  * \param de_ctx Pointer to the Detection Engine Context.
3397  * \param sigstr Pointer to a character string containing the signature to be
3398  * parsed.
3399  * \param sig_file Pointer to a character string containing the filename from
3400  * which signature is read
3401  * \param lineno Line number from where signature is read
3402  *
3403  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3404  * on success; NULL on failure.
3405  */
3407 {
3408  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3409  if (sig == NULL) {
3410  return NULL;
3411  }
3412 
3413  /* checking for the status of duplicate signature */
3414  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3415  /* a duplicate signature that should be chucked out. Check the previously
3416  * called function details to understand the different return values */
3417  if (dup_sig == 1) {
3418  SCLogError("Duplicate signature \"%s\"", sigstr);
3419  goto error;
3420  } else if (dup_sig == 2) {
3421  SCLogWarning("Signature with newer revision,"
3422  " so the older sig replaced by this new signature \"%s\"",
3423  sigstr);
3424  }
3425 
3427  if (sig->next != NULL) {
3428  sig->next->next = de_ctx->sig_list;
3429  } else {
3430  goto error;
3431  }
3432  } else {
3433  /* if this sig is the first one, sig_list should be null */
3434  sig->next = de_ctx->sig_list;
3435  }
3436 
3437  de_ctx->sig_list = sig;
3438 
3439  /**
3440  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3441  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3442  * to the cloned signatures with the switched addresses
3443  */
3444  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3445 
3446 error:
3447  /* free the 2nd sig bidir may have set up */
3448  if (sig != NULL && sig->next != NULL) {
3449  SigFree(de_ctx, sig->next);
3450  sig->next = NULL;
3451  }
3452  if (sig != NULL) {
3453  SigFree(de_ctx, sig);
3454  }
3455  return NULL;
3456 }
3457 
3458 /**
3459  * \brief Parse and append a Signature into the Detection Engine Context
3460  * signature list.
3461  *
3462  * If the signature is bidirectional it should append two signatures
3463  * (with the addresses switched) into the list. Also handle duplicate
3464  * signatures. In case of duplicate sigs, use the ones that have the
3465  * latest revision. We use the sid and the msg to identify duplicate
3466  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3467  *
3468  * \param de_ctx Pointer to the Detection Engine Context.
3469  * \param sigstr Pointer to a character string containing the signature to be
3470  * parsed.
3471  * \param sig_file Pointer to a character string containing the filename from
3472  * which signature is read
3473  * \param lineno Line number from where signature is read
3474  *
3475  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3476  * on success; NULL on failure.
3477  */
3479 {
3480  Signature *sig = SigInit(de_ctx, sigstr);
3481  if (sig == NULL) {
3482  return NULL;
3483  }
3484 
3485  /* checking for the status of duplicate signature */
3486  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3487  /* a duplicate signature that should be chucked out. Check the previously
3488  * called function details to understand the different return values */
3489  if (dup_sig == 1) {
3490  SCLogError("Duplicate signature \"%s\"", sigstr);
3491  goto error;
3492  } else if (dup_sig == 2) {
3493  SCLogWarning("Signature with newer revision,"
3494  " so the older sig replaced by this new signature \"%s\"",
3495  sigstr);
3496  }
3497 
3499  if (sig->next != NULL) {
3500  sig->next->next = de_ctx->sig_list;
3501  } else {
3502  goto error;
3503  }
3504  } else {
3505  /* if this sig is the first one, sig_list should be null */
3506  sig->next = de_ctx->sig_list;
3507  }
3508 
3509  de_ctx->sig_list = sig;
3510 
3511  /**
3512  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3513  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3514  * to the cloned signatures with the switched addresses
3515  */
3516  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3517 
3518 error:
3519  /* free the 2nd sig bidir may have set up */
3520  if (sig != NULL && sig->next != NULL) {
3521  SigFree(de_ctx, sig->next);
3522  sig->next = NULL;
3523  }
3524  if (sig != NULL) {
3525  SigFree(de_ctx, sig);
3526  }
3527  return NULL;
3528 }
3529 
3530 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3531 
3532 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3533  int start_offset, int options)
3534 {
3535  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3536  if (*match)
3537  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3538  *match, parse_regex->context);
3539  return -1;
3540 }
3541 
3543 {
3544  if (r->regex) {
3545  pcre2_code_free(r->regex);
3546  }
3547  if (r->context) {
3548  pcre2_match_context_free(r->context);
3549  }
3550 }
3551 
3553 {
3554  DetectParseRegex *r = g_detect_parse_regex_list;
3555  while (r) {
3556  DetectParseRegex *next = r->next;
3557 
3559 
3560  SCFree(r);
3561  r = next;
3562  }
3563  g_detect_parse_regex_list = NULL;
3564 }
3565 
3566 /** \brief add regex and/or study to at exit free list
3567  */
3569 {
3570  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3571  if (r == NULL) {
3572  FatalError("failed to alloc memory for pcre free list");
3573  }
3574  r->regex = detect_parse->regex;
3575  r->next = g_detect_parse_regex_list;
3576  g_detect_parse_regex_list = r;
3577 }
3578 
3579 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3580 {
3581  int en;
3582  PCRE2_SIZE eo;
3583 
3584  detect_parse->regex =
3585  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3586  if (detect_parse->regex == NULL) {
3587  PCRE2_UCHAR errbuffer[256];
3588  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3589  SCLogError("pcre compile of \"%s\" failed at "
3590  "offset %d: %s",
3591  parse_str, en, errbuffer);
3592  return false;
3593  }
3594  detect_parse->context = pcre2_match_context_create(NULL);
3595  if (detect_parse->context == NULL) {
3596  SCLogError("pcre2 could not create match context");
3597  pcre2_code_free(detect_parse->regex);
3598  detect_parse->regex = NULL;
3599  return false;
3600  }
3601  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3602  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3603  DetectParseRegexAddToFreeList(detect_parse);
3604 
3605  return true;
3606 }
3607 
3608 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3609 {
3610  int en;
3611  PCRE2_SIZE eo;
3612  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3613  if (detect_parse == NULL) {
3614  return NULL;
3615  }
3616 
3617  detect_parse->regex =
3618  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3619  if (detect_parse->regex == NULL) {
3620  PCRE2_UCHAR errbuffer[256];
3621  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3622  SCLogError("pcre2 compile of \"%s\" failed at "
3623  "offset %d: %s",
3624  parse_str, (int)eo, errbuffer);
3625  SCFree(detect_parse);
3626  return NULL;
3627  }
3628 
3629  detect_parse->next = g_detect_parse_regex_list;
3630  g_detect_parse_regex_list = detect_parse;
3631  return detect_parse;
3632 }
3633 
3635  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3636 {
3637  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3638  if (r == PCRE2_ERROR_UNSET) {
3639  buffer[0] = 0;
3640  *bufflen = 0;
3641  return 0;
3642  }
3643  return r;
3644 }
3645 
3647  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3648 {
3649  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3650  if (r == PCRE2_ERROR_UNSET) {
3651  *bufferptr = NULL;
3652  *bufflen = 0;
3653  return 0;
3654  }
3655  return r;
3656 }
3657 
3658 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3659 {
3660  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3661  FatalError("pcre compile and study failed");
3662  }
3663 }
3664 
3665 /*
3666  * TESTS
3667  */
3668 
3669 #ifdef UNITTESTS
3670 #include "detect-engine-alert.h"
3671 #include "packet.h"
3672 
3673 static int SigParseTest01 (void)
3674 {
3675  int result = 1;
3676  Signature *sig = NULL;
3677 
3679  if (de_ctx == NULL)
3680  goto end;
3681 
3682  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3683  if (sig == NULL)
3684  result = 0;
3685 
3686 end:
3687  if (sig != NULL) SigFree(de_ctx, sig);
3688  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3689  return result;
3690 }
3691 
3692 static int SigParseTest02 (void)
3693 {
3694  int result = 0;
3695  Signature *sig = NULL;
3696  DetectPort *port = NULL;
3697 
3699 
3700  if (de_ctx == NULL)
3701  goto end;
3702 
3706 
3707  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;)");
3708  if (sig == NULL) {
3709  goto end;
3710  }
3711 
3712  int r = DetectPortParse(de_ctx, &port, "0:20");
3713  if (r < 0)
3714  goto end;
3715 
3716  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3717  result = 1;
3718  } else {
3719  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3720  }
3721 
3722 end:
3723  if (port != NULL)
3725  if (sig != NULL)
3726  SigFree(de_ctx, sig);
3727  if (de_ctx != NULL)
3729  return result;
3730 }
3731 
3732 /**
3733  * \test SigParseTest03 test for invalid direction operator in rule
3734  */
3735 static int SigParseTest03 (void)
3736 {
3737  int result = 1;
3738  Signature *sig = NULL;
3739 
3741  if (de_ctx == NULL)
3742  goto end;
3743 
3744  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3745  if (sig != NULL) {
3746  result = 0;
3747  printf("expected NULL got sig ptr %p: ",sig);
3748  }
3749 
3750 end:
3751  if (sig != NULL) SigFree(de_ctx, sig);
3752  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3753  return result;
3754 }
3755 
3756 static int SigParseTest04 (void)
3757 {
3758  int result = 1;
3759  Signature *sig = NULL;
3760 
3762  if (de_ctx == NULL)
3763  goto end;
3764 
3765  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3766  if (sig == NULL)
3767  result = 0;
3768 
3769 end:
3770  if (sig != NULL) SigFree(de_ctx, sig);
3771  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3772  return result;
3773 }
3774 
3775 /** \test Port validation */
3776 static int SigParseTest05 (void)
3777 {
3778  int result = 0;
3779  Signature *sig = NULL;
3780 
3782  if (de_ctx == NULL)
3783  goto end;
3784 
3785  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3786  if (sig == NULL) {
3787  result = 1;
3788  } else {
3789  printf("signature didn't fail to parse as we expected: ");
3790  }
3791 
3792 end:
3793  if (sig != NULL) SigFree(de_ctx, sig);
3794  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3795  return result;
3796 }
3797 
3798 /** \test Parsing bug debugging at 2010-03-18 */
3799 static int SigParseTest06 (void)
3800 {
3801  int result = 0;
3802  Signature *sig = NULL;
3803 
3805  if (de_ctx == NULL)
3806  goto end;
3807 
3808  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;)");
3809  if (sig != NULL) {
3810  result = 1;
3811  } else {
3812  printf("signature failed to parse: ");
3813  }
3814 
3815 end:
3816  if (sig != NULL)
3817  SigFree(de_ctx, sig);
3818  if (de_ctx != NULL)
3820  return result;
3821 }
3822 
3823 /**
3824  * \test Parsing duplicate sigs.
3825  */
3826 static int SigParseTest07(void)
3827 {
3828  int result = 0;
3829 
3831  if (de_ctx == NULL)
3832  goto end;
3833 
3834  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3835  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3836 
3837  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3838 
3839 end:
3840  if (de_ctx != NULL)
3842  return result;
3843 }
3844 
3845 /**
3846  * \test Parsing duplicate sigs.
3847  */
3848 static int SigParseTest08(void)
3849 {
3850  int result = 0;
3851 
3853  if (de_ctx == NULL)
3854  goto end;
3855 
3856  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3857  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3858 
3859  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3860  de_ctx->sig_list->rev == 2);
3861 
3862 end:
3863  if (de_ctx != NULL)
3865  return result;
3866 }
3867 
3868 /**
3869  * \test Parsing duplicate sigs.
3870  */
3871 static int SigParseTest09(void)
3872 {
3873  int result = 1;
3874 
3876  if (de_ctx == NULL)
3877  goto end;
3878 
3879  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3880  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3881  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3882  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3883  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3884  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3885  de_ctx->sig_list->rev == 2);
3886  if (result == 0)
3887  goto end;
3888  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3889  de_ctx->sig_list->next->rev == 6);
3890  if (result == 0)
3891  goto end;
3892 
3893  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3894  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3895  de_ctx->sig_list->rev == 2);
3896  if (result == 0)
3897  goto end;
3898  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3899  de_ctx->sig_list->next->rev == 6);
3900  if (result == 0)
3901  goto end;
3902 
3903  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3904  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3905  de_ctx->sig_list->rev == 4);
3906  if (result == 0)
3907  goto end;
3908  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3909  de_ctx->sig_list->next->rev == 6);
3910  if (result == 0)
3911  goto end;
3912 
3913 end:
3914  if (de_ctx != NULL)
3916  return result;
3917 }
3918 
3919 /**
3920  * \test Parsing duplicate sigs.
3921  */
3922 static int SigParseTest10(void)
3923 {
3924  int result = 1;
3925 
3927  if (de_ctx == NULL)
3928  goto end;
3929 
3930  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3931  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3932  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3933  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3934  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3935  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3936  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3937 
3938  result &= ((de_ctx->sig_list->id == 2) &&
3939  (de_ctx->sig_list->next->id == 3) &&
3940  (de_ctx->sig_list->next->next->id == 5) &&
3941  (de_ctx->sig_list->next->next->next->id == 4) &&
3942  (de_ctx->sig_list->next->next->next->next->id == 1));
3943 
3944 end:
3945  if (de_ctx != NULL)
3947  return result;
3948 }
3949 
3950 /**
3951  * \test Parsing sig with trailing space(s) as reported by
3952  * Morgan Cox on oisf-users.
3953  */
3954 static int SigParseTest11(void)
3955 {
3956  int result = 0;
3957 
3959  if (de_ctx == NULL)
3960  goto end;
3961 
3962  Signature *s = NULL;
3963 
3965  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3966  if (s == NULL) {
3967  printf("sig 1 didn't parse: ");
3968  goto end;
3969  }
3970 
3971  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3972  "the http link\"; sid:2;) ");
3973  if (s == NULL) {
3974  printf("sig 2 didn't parse: ");
3975  goto end;
3976  }
3977 
3978  result = 1;
3979 end:
3980  if (de_ctx != NULL)
3982  return result;
3983 }
3984 
3985 /**
3986  * \test file_data with rawbytes
3987  */
3988 static int SigParseTest12(void)
3989 {
3990  int result = 0;
3991 
3993  if (de_ctx == NULL)
3994  goto end;
3995 
3996  Signature *s = NULL;
3997 
3998  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3999  if (s != NULL) {
4000  printf("sig 1 should have given an error: ");
4001  goto end;
4002  }
4003 
4004  result = 1;
4005 end:
4006  if (de_ctx != NULL)
4008  return result;
4009 }
4010 
4011 /**
4012  * \test packet/stream sig
4013  */
4014 static int SigParseTest13(void)
4015 {
4016  int result = 0;
4017 
4019  if (de_ctx == NULL)
4020  goto end;
4021 
4022  Signature *s = NULL;
4023 
4024  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
4025  if (s == NULL) {
4026  printf("sig 1 invalidated: failure");
4027  goto end;
4028  }
4029 
4030  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4031  printf("sig doesn't have stream flag set\n");
4032  goto end;
4033  }
4034 
4035  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
4036  printf("sig has packet flag set\n");
4037  goto end;
4038  }
4039 
4040  result = 1;
4041 
4042 end:
4043  if (de_ctx != NULL)
4045  return result;
4046 }
4047 
4048 /**
4049  * \test packet/stream sig
4050  */
4051 static int SigParseTest14(void)
4052 {
4053  int result = 0;
4054 
4056  if (de_ctx == NULL)
4057  goto end;
4058 
4059  Signature *s = NULL;
4060 
4061  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4062  if (s == NULL) {
4063  printf("sig 1 invalidated: failure");
4064  goto end;
4065  }
4066 
4067  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4068  printf("sig doesn't have packet flag set\n");
4069  goto end;
4070  }
4071 
4072  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4073  printf("sig has stream flag set\n");
4074  goto end;
4075  }
4076 
4077  result = 1;
4078 
4079 end:
4080  if (de_ctx != NULL)
4082  return result;
4083 }
4084 
4085 /**
4086  * \test packet/stream sig
4087  */
4088 static int SigParseTest15(void)
4089 {
4090  int result = 0;
4091 
4093  if (de_ctx == NULL)
4094  goto end;
4095 
4096  Signature *s = NULL;
4097 
4098  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4099  if (s == NULL) {
4100  printf("sig 1 invalidated: failure");
4101  goto end;
4102  }
4103 
4104  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4105  printf("sig doesn't have packet flag set\n");
4106  goto end;
4107  }
4108 
4109  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4110  printf("sig doesn't have stream flag set\n");
4111  goto end;
4112  }
4113 
4114  result = 1;
4115 
4116 end:
4117  if (de_ctx != NULL)
4119  return result;
4120 }
4121 
4122 /**
4123  * \test packet/stream sig
4124  */
4125 static int SigParseTest16(void)
4126 {
4127  int result = 0;
4128 
4130  if (de_ctx == NULL)
4131  goto end;
4132 
4133  Signature *s = NULL;
4134 
4135  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4136  if (s == NULL) {
4137  printf("sig 1 invalidated: failure");
4138  goto end;
4139  }
4140 
4141  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4142  printf("sig doesn't have packet flag set\n");
4143  goto end;
4144  }
4145 
4146  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4147  printf("sig doesn't have stream flag set\n");
4148  goto end;
4149  }
4150 
4151  result = 1;
4152 
4153 end:
4154  if (de_ctx != NULL)
4156  return result;
4157 }
4158 
4159 /**
4160  * \test packet/stream sig
4161  */
4162 static int SigParseTest17(void)
4163 {
4164  int result = 0;
4165 
4167  if (de_ctx == NULL)
4168  goto end;
4169 
4170  Signature *s = NULL;
4171 
4172  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4173  if (s == NULL) {
4174  printf("sig 1 invalidated: failure");
4175  goto end;
4176  }
4177 
4178  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4179  printf("sig doesn't have packet flag set\n");
4180  goto end;
4181  }
4182 
4183  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4184  printf("sig doesn't have stream flag set\n");
4185  goto end;
4186  }
4187 
4188  result = 1;
4189 
4190 end:
4191  if (de_ctx != NULL)
4193  return result;
4194 }
4195 
4196 /** \test sid value too large. Bug #779 */
4197 static int SigParseTest18 (void)
4198 {
4199  int result = 0;
4200 
4202  if (de_ctx == NULL)
4203  goto end;
4204 
4205  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4206  goto end;
4207 
4208  result = 1;
4209 end:
4210  if (de_ctx != NULL)
4212  return result;
4213 }
4214 
4215 /** \test gid value too large. Related to bug #779 */
4216 static int SigParseTest19 (void)
4217 {
4218  int result = 0;
4219 
4221  if (de_ctx == NULL)
4222  goto end;
4223 
4224  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4225  goto end;
4226 
4227  result = 1;
4228 end:
4229  if (de_ctx != NULL)
4231  return result;
4232 }
4233 
4234 /** \test rev value too large. Related to bug #779 */
4235 static int SigParseTest20 (void)
4236 {
4237  int result = 0;
4238 
4240  if (de_ctx == NULL)
4241  goto end;
4242 
4243  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4244  goto end;
4245 
4246  result = 1;
4247 end:
4248  if (de_ctx != NULL)
4250  return result;
4251 }
4252 
4253 /** \test address parsing */
4254 static int SigParseTest21 (void)
4255 {
4256  int result = 0;
4257 
4259  if (de_ctx == NULL)
4260  goto end;
4261 
4262  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4263  goto end;
4264 
4265  result = 1;
4266 end:
4267  if (de_ctx != NULL)
4269  return result;
4270 }
4271 
4272 /** \test address parsing */
4273 static int SigParseTest22 (void)
4274 {
4275  int result = 0;
4276 
4278  if (de_ctx == NULL)
4279  goto end;
4280 
4281  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)
4282  goto end;
4283 
4284  result = 1;
4285 end:
4286  if (de_ctx != NULL)
4288  return result;
4289 }
4290 
4291 /**
4292  * \test rule ending in carriage return
4293  */
4294 static int SigParseTest23(void)
4295 {
4298 
4299  Signature *s = NULL;
4300 
4301  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4302  FAIL_IF_NULL(s);
4303 
4305  PASS;
4306 }
4307 
4308 /** \test Direction operator validation (invalid) */
4309 static int SigParseBidirecTest06 (void)
4310 {
4311  int result = 1;
4312  Signature *sig = NULL;
4313 
4315  if (de_ctx == NULL)
4316  goto end;
4317 
4318  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4319  if (sig == NULL)
4320  result = 1;
4321 
4322 end:
4323  if (sig != NULL) SigFree(de_ctx, sig);
4324  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4325  return result;
4326 }
4327 
4328 /** \test Direction operator validation (invalid) */
4329 static int SigParseBidirecTest07 (void)
4330 {
4331  int result = 1;
4332  Signature *sig = NULL;
4333 
4335  if (de_ctx == NULL)
4336  goto end;
4337 
4338  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4339  if (sig == NULL)
4340  result = 1;
4341 
4342 end:
4343  if (sig != NULL) SigFree(de_ctx, sig);
4344  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4345  return result;
4346 }
4347 
4348 /** \test Direction operator validation (invalid) */
4349 static int SigParseBidirecTest08 (void)
4350 {
4351  int result = 1;
4352  Signature *sig = NULL;
4353 
4355  if (de_ctx == NULL)
4356  goto end;
4357 
4358  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4359  if (sig == NULL)
4360  result = 1;
4361 
4362 end:
4363  if (sig != NULL) SigFree(de_ctx, sig);
4364  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4365  return result;
4366 }
4367 
4368 /** \test Direction operator validation (invalid) */
4369 static int SigParseBidirecTest09 (void)
4370 {
4371  int result = 1;
4372  Signature *sig = NULL;
4373 
4375  if (de_ctx == NULL)
4376  goto end;
4377 
4378  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4379  if (sig == NULL)
4380  result = 1;
4381 
4382 end:
4383  if (sig != NULL) SigFree(de_ctx, sig);
4384  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4385  return result;
4386 }
4387 
4388 /** \test Direction operator validation (invalid) */
4389 static int SigParseBidirecTest10 (void)
4390 {
4391  int result = 1;
4392  Signature *sig = NULL;
4393 
4395  if (de_ctx == NULL)
4396  goto end;
4397 
4398  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4399  if (sig == NULL)
4400  result = 1;
4401 
4402 end:
4403  if (sig != NULL) SigFree(de_ctx, sig);
4404  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4405  return result;
4406 }
4407 
4408 /** \test Direction operator validation (invalid) */
4409 static int SigParseBidirecTest11 (void)
4410 {
4411  int result = 1;
4412  Signature *sig = NULL;
4413 
4415  if (de_ctx == NULL)
4416  goto end;
4417 
4418  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4419  if (sig == NULL)
4420  result = 1;
4421 
4422 end:
4423  if (sig != NULL) SigFree(de_ctx, sig);
4424  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4425  return result;
4426 }
4427 
4428 /** \test Direction operator validation (invalid) */
4429 static int SigParseBidirecTest12 (void)
4430 {
4431  int result = 1;
4432  Signature *sig = NULL;
4433 
4435  if (de_ctx == NULL)
4436  goto end;
4437 
4438  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4439  if (sig == NULL)
4440  result = 1;
4441 
4442 end:
4443  if (sig != NULL) SigFree(de_ctx, sig);
4444  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4445  return result;
4446 }
4447 
4448 /** \test Direction operator validation (valid) */
4449 static int SigParseBidirecTest13 (void)
4450 {
4451  int result = 1;
4452  Signature *sig = NULL;
4453 
4455  if (de_ctx == NULL)
4456  goto end;
4457 
4458  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4459  if (sig != NULL)
4460  result = 1;
4461 
4462 end:
4463  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4464  return result;
4465 }
4466 
4467 /** \test Direction operator validation (valid) */
4468 static int SigParseBidirecTest14 (void)
4469 {
4470  int result = 1;
4471  Signature *sig = NULL;
4472 
4474  if (de_ctx == NULL)
4475  goto end;
4476 
4477  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4478  if (sig != NULL)
4479  result = 1;
4480 
4481 end:
4482  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4483  return result;
4484 }
4485 
4486 /** \test Ensure that we don't set bidirectional in a
4487  * normal (one direction) Signature
4488  */
4489 static int SigTestBidirec01 (void)
4490 {
4491  Signature *sig = NULL;
4492  int result = 0;
4493 
4495  if (de_ctx == NULL)
4496  goto end;
4497 
4498  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4499  if (sig == NULL)
4500  goto end;
4501  if (sig->next != NULL)
4502  goto end;
4504  goto end;
4505  if (de_ctx->signum != 1)
4506  goto end;
4507 
4508  result = 1;
4509 
4510 end:
4511  if (de_ctx != NULL) {
4515  }
4516  return result;
4517 }
4518 
4519 /** \test Ensure that we set a bidirectional Signature correctly */
4520 static int SigTestBidirec02 (void)
4521 {
4522  int result = 0;
4523  Signature *sig = NULL;
4524  Signature *copy = NULL;
4525 
4527  if (de_ctx == NULL)
4528  goto end;
4529 
4530  de_ctx->flags |= DE_QUIET;
4531 
4532  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4533  if (sig == NULL)
4534  goto end;
4535  if (de_ctx->sig_list != sig)
4536  goto end;
4538  goto end;
4539  if (sig->next == NULL)
4540  goto end;
4541  if (de_ctx->signum != 2)
4542  goto end;
4543  copy = sig->next;
4544  if (copy->next != NULL)
4545  goto end;
4546  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4547  goto end;
4548 
4549  result = 1;
4550 
4551 end:
4552  if (de_ctx != NULL) {
4556  }
4557 
4558  return result;
4559 }
4560 
4561 /** \test Ensure that we set a bidirectional Signature correctly
4562 * and we install it with the rest of the signatures, checking
4563 * also that it match with the correct addr directions
4564 */
4565 static int SigTestBidirec03 (void)
4566 {
4567  int result = 0;
4568  Signature *sig = NULL;
4569  Packet *p = NULL;
4570 
4572  if (de_ctx == NULL)
4573  goto end;
4574 
4575  de_ctx->flags |= DE_QUIET;
4576 
4577  const char *sigs[3];
4578  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4579  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4580  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4581  UTHAppendSigs(de_ctx, sigs, 3);
4582 
4583  /* Checking that bidirectional rules are set correctly */
4584  sig = de_ctx->sig_list;
4585  if (sig == NULL)
4586  goto end;
4587  if (sig->next == NULL)
4588  goto end;
4589  if (sig->next->next == NULL)
4590  goto end;
4591  if (sig->next->next->next == NULL)
4592  goto end;
4593  if (sig->next->next->next->next != NULL)
4594  goto end;
4595  if (de_ctx->signum != 4)
4596  goto end;
4597 
4598  uint8_t rawpkt1_ether[] = {
4599  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4600  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4601  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4602  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4603  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4604  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4605  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4606  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4607  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4608  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4609  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4610  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4611  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4612  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4613  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4614  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4615  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4616  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4617  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4618  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4619  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4620  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4621  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4622  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4623  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4624  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4625  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4626  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4627  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4628  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4629  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4630  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4631  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4632  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4633  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4634  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4635  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4636  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4637  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4638  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4639  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4640  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4641  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4642  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4643  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4644  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4645  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4646  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4647  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4648  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4649  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4650  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4651  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4652  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4653  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4654 
4656  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4657  if (p == NULL) {
4658  SCLogDebug("Error building packet");
4659  goto end;
4660  }
4661  UTHMatchPackets(de_ctx, &p, 1);
4662 
4663  uint32_t sids[3] = {1, 2, 3};
4664  uint32_t results[3] = {1, 1, 1};
4665  result = UTHCheckPacketMatchResults(p, sids, results, 1);
4666 
4667 end:
4668  if (p != NULL) {
4669  PacketFree(p);
4670  }
4672  FlowShutdown();
4673  return result;
4674 }
4675 
4676 /** \test Ensure that we set a bidirectional Signature correctly
4677 * and we install it with the rest of the signatures, checking
4678 * also that it match with the correct addr directions
4679 */
4680 static int SigTestBidirec04 (void)
4681 {
4682  int result = 0;
4683  Signature *sig = NULL;
4684  Packet *p = NULL;
4685 
4687  if (de_ctx == NULL)
4688  goto end;
4689 
4690  de_ctx->flags |= DE_QUIET;
4691 
4692  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4693  if (sig == NULL)
4694  goto end;
4695  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4696  if (sig == NULL)
4697  goto end;
4698  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4699  goto end;
4700  if (sig->next == NULL)
4701  goto end;
4702  if (sig->next->next == NULL)
4703  goto end;
4704  if (sig->next->next->next != NULL)
4705  goto end;
4706  if (de_ctx->signum != 3)
4707  goto end;
4708 
4709  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4710  if (sig == NULL)
4711  goto end;
4712  if (sig->next == NULL)
4713  goto end;
4714  if (sig->next->next == NULL)
4715  goto end;
4716  if (sig->next->next->next == NULL)
4717  goto end;
4718  if (sig->next->next->next->next != NULL)
4719  goto end;
4720  if (de_ctx->signum != 4)
4721  goto end;
4722 
4723  uint8_t rawpkt1_ether[] = {
4724  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4725  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4726  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4727  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4728  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4729  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4730  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4731  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4732  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4733  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4734  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4735  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4736  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4737  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4738  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4739  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4740  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4741  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4742  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4743  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4744  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4745  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4746  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4747  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4748  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4749  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4750  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4751  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4752  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4753  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4754  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4755  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4756  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4757  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4758  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4759  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4760  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4761  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4762  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4763  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4764  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4765  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4766  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4767  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4768  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4769  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4770  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4771  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4772  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4773  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4774  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4775  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4776  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4777  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4778  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4779 
4780  p = PacketGetFromAlloc();
4781  if (unlikely(p == NULL))
4782  return 0;
4784  ThreadVars th_v;
4785  DetectEngineThreadCtx *det_ctx;
4786 
4787  memset(&th_v, 0, sizeof(th_v));
4788  StatsThreadInit(&th_v.stats);
4789 
4791  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4792  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4793 
4794  /* At this point we have a list of 4 signatures. The last one
4795  is a copy of the second one. If we receive a packet
4796  with source 192.168.1.1 80, all the sids should match */
4797 
4799  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4800 
4801  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4802  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4803  PacketAlertCheck(p, 2) == 1) {
4804  result = 1;
4805  }
4806 
4807  if (p != NULL) {
4808  PacketRecycle(p);
4809  }
4810  FlowShutdown();
4811  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4812 
4813 end:
4814  if (de_ctx != NULL) {
4816  }
4817 
4818  if (p != NULL)
4819  PacketFree(p);
4820  StatsThreadCleanup(&th_v.stats);
4821  return result;
4822 }
4823 
4824 /**
4825  * \test check that we don't allow invalid negation options
4826  */
4827 static int SigParseTestNegation01 (void)
4828 {
4831  de_ctx->flags |= DE_QUIET;
4832  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4833  FAIL_IF_NOT_NULL(s);
4835  PASS;
4836 }
4837 
4838 /**
4839  * \test check that we don't allow invalid negation options
4840  */
4841 static int SigParseTestNegation02 (void)
4842 {
4845  de_ctx->flags |= DE_QUIET;
4847  "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
4848  "classtype:misc-activity; sid:410002; rev:1;)");
4849  FAIL_IF_NOT_NULL(s);
4851  PASS;
4852 }
4853 /**
4854  * \test check that we don't allow invalid negation options
4855  */
4856 static int SigParseTestNegation03 (void)
4857 {
4860  de_ctx->flags |= DE_QUIET;
4862  "alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; "
4863  "classtype:misc-activity; sid:410003; rev:1;)");
4864  FAIL_IF_NOT_NULL(s);
4866  PASS;
4867 }
4868 /**
4869  * \test check that we don't allow invalid negation options
4870  */
4871 static int SigParseTestNegation04 (void)
4872 {
4873  int result = 0;
4875  Signature *s=NULL;
4876 
4878  if (de_ctx == NULL)
4879  goto end;
4880  de_ctx->flags |= DE_QUIET;
4881 
4882  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;)");
4883  if (s != NULL) {
4884  SigFree(de_ctx, s);
4885  goto end;
4886  }
4887 
4888  result = 1;
4889 end:
4890  if (de_ctx != NULL)
4892  return result;
4893 }
4894 /**
4895  * \test check that we don't allow invalid negation options
4896  */
4897 static int SigParseTestNegation05 (void)
4898 {
4899  int result = 0;
4901  Signature *s=NULL;
4902 
4904  if (de_ctx == NULL)
4905  goto end;
4906  de_ctx->flags |= DE_QUIET;
4907 
4908  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;)");
4909  if (s != NULL) {
4910  SigFree(de_ctx, s);
4911  goto end;
4912  }
4913 
4914  result = 1;
4915 end:
4916  if (de_ctx != NULL)
4918  return result;
4919 }
4920 /**
4921  * \test check that we don't allow invalid negation options
4922  */
4923 static int SigParseTestNegation06 (void)
4924 {
4925  int result = 0;
4927  Signature *s=NULL;
4928 
4930  if (de_ctx == NULL)
4931  goto end;
4932  de_ctx->flags |= DE_QUIET;
4933 
4934  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;)");
4935  if (s != NULL) {
4936  SigFree(de_ctx, s);
4937  goto end;
4938  }
4939 
4940  result = 1;
4941 end:
4942  if (de_ctx != NULL)
4944  return result;
4945 }
4946 
4947 /**
4948  * \test check that we don't allow invalid negation options
4949  */
4950 static int SigParseTestNegation07 (void)
4951 {
4954  de_ctx->flags |= DE_QUIET;
4956  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4957  FAIL_IF_NOT_NULL(s);
4959  PASS;
4960 }
4961 
4962 /**
4963  * \test check valid negation bug 1079
4964  */
4965 static int SigParseTestNegation08 (void)
4966 {
4967  int result = 0;
4969  Signature *s=NULL;
4970 
4972  if (de_ctx == NULL)
4973  goto end;
4974  de_ctx->flags |= DE_QUIET;
4975 
4977  "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4978  if (s == NULL) {
4979  goto end;
4980  }
4981 
4982  result = 1;
4983 end:
4984  if (de_ctx != NULL)
4986  return result;
4987 }
4988 
4989 /**
4990  * \test mpm
4991  */
4992 static int SigParseTestMpm01 (void)
4993 {
4994  int result = 0;
4995  Signature *sig = NULL;
4996 
4998  if (de_ctx == NULL)
4999  goto end;
5000 
5001  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
5002  if (sig == NULL) {
5003  printf("sig failed to init: ");
5004  goto end;
5005  }
5006 
5007  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5008  printf("sig doesn't have content list: ");
5009  goto end;
5010  }
5011 
5012  result = 1;
5013 end:
5014  if (sig != NULL)
5015  SigFree(de_ctx, sig);
5017  return result;
5018 }
5019 
5020 /**
5021  * \test mpm
5022  */
5023 static int SigParseTestMpm02 (void)
5024 {
5025  int result = 0;
5026  Signature *sig = NULL;
5027 
5029  if (de_ctx == NULL)
5030  goto end;
5031 
5032  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; content:\"abcdef\"; sid:1;)");
5033  if (sig == NULL) {
5034  printf("sig failed to init: ");
5035  goto end;
5036  }
5037 
5038  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
5039  printf("sig doesn't have content list: ");
5040  goto end;
5041  }
5042 
5043  result = 1;
5044 end:
5045  if (sig != NULL)
5046  SigFree(de_ctx, sig);
5048  return result;
5049 }
5050 
5051 /**
5052  * \test test tls (app layer) rule
5053  */
5054 static int SigParseTestAppLayerTLS01(void)
5055 {
5056  int result = 0;
5058  Signature *s=NULL;
5059 
5061  if (de_ctx == NULL)
5062  goto end;
5063  de_ctx->flags |= DE_QUIET;
5064 
5065  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5066  if (s == NULL) {
5067  printf("parsing sig failed: ");
5068  goto end;
5069  }
5070 
5071  if (s->alproto == 0) {
5072  printf("alproto not set: ");
5073  goto end;
5074  }
5075 
5076  result = 1;
5077 end:
5078  if (s != NULL)
5079  SigFree(de_ctx, s);
5080  if (de_ctx != NULL)
5082 
5083  return result;
5084 }
5085 
5086 /**
5087  * \test test tls (app layer) rule
5088  */
5089 static int SigParseTestAppLayerTLS02(void)
5090 {
5091  int result = 0;
5093  Signature *s=NULL;
5094 
5096  if (de_ctx == NULL)
5097  goto end;
5098  de_ctx->flags |= DE_QUIET;
5099 
5100  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5101  if (s == NULL) {
5102  printf("parsing sig failed: ");
5103  goto end;
5104  }
5105 
5106  if (s->alproto == 0) {
5107  printf("alproto not set: ");
5108  goto end;
5109  }
5110 
5111  result = 1;
5112 end:
5113  if (s != NULL)
5114  SigFree(de_ctx, s);
5115  if (de_ctx != NULL)
5117  return result;
5118 }
5119 
5120 /**
5121  * \test test tls (app layer) rule
5122  */
5123 static int SigParseTestAppLayerTLS03(void)
5124 {
5127  de_ctx->flags |= DE_QUIET;
5128 
5130  "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
5131  "tls.version:2.5; sid:410006; rev:1;)");
5132  FAIL_IF_NOT_NULL(s);
5134  PASS;
5135 }
5136 
5137 static int SigParseTestUnbalancedQuotes01(void)
5138 {
5141  de_ctx->flags |= DE_QUIET;
5143  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5144  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5145  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5146  FAIL_IF_NOT_NULL(s);
5148  PASS;
5149 }
5150 
5151 static int SigParseTestContentGtDsize01(void)
5152 {
5155  de_ctx->flags |= DE_QUIET;
5156  Signature *s =
5157  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5158  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5159  "sid:1; rev:1;)");
5160  FAIL_IF_NOT_NULL(s);
5162  PASS;
5163 }
5164 
5165 static int SigParseTestContentGtDsize02(void)
5166 {
5169  de_ctx->flags |= DE_QUIET;
5170  Signature *s =
5171  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5172  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5173  "sid:1; rev:1;)");
5174  FAIL_IF_NOT_NULL(s);
5176  PASS;
5177 }
5178 
5179 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5180 {
5181  int cnt = 0;
5182  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5183  if (sid == s->id)
5184  cnt++;
5185  }
5186  return cnt;
5187 }
5188 
5189 static int SigParseBidirWithSameSrcAndDest01(void)
5190 {
5193  de_ctx->flags |= DE_QUIET;
5194 
5195  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5196  FAIL_IF_NULL(s);
5197  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5199 
5200  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5201  FAIL_IF_NULL(s);
5202  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5204 
5206  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5207  FAIL_IF_NULL(s);
5208  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5210 
5212  PASS;
5213 }
5214 
5215 static int SigParseBidirWithSameSrcAndDest02(void)
5216 {
5219  de_ctx->flags |= DE_QUIET;
5220 
5221  // Source is a subset of destination
5223  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5224  FAIL_IF_NULL(s);
5225  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5227 
5228  // Source is a subset of destination
5230  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5231  FAIL_IF_NULL(s);
5232  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5234 
5235  // Source intersects with destination
5237  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5238  FAIL_IF_NULL(s);
5239  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5241 
5242  // mix in negation, these are the same
5244  de_ctx, "alert tcp [!1.2.3.4, 1.2.3.0/24] any <> [1.2.3.0/24, !1.2.3.4] any (sid:4;)");
5245  FAIL_IF_NULL(s);
5246  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5248 
5249  // mix in negation, these are not the same
5251  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;)");
5252  FAIL_IF_NULL(s);
5253  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5255 
5257  PASS;
5258 }
5259 
5260 static int SigParseTestActionReject(void)
5261 {
5264 
5266  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5267 #ifdef HAVE_LIBNET11
5268  FAIL_IF_NULL(sig);
5270 #else
5271  FAIL_IF_NOT_NULL(sig);
5272 #endif
5273 
5275  PASS;
5276 }
5277 
5278 static int SigParseTestActionDrop(void)
5279 {
5282 
5284  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5285  FAIL_IF_NULL(sig);
5286  FAIL_IF_NOT(sig->action & ACTION_DROP);
5287 
5289  PASS;
5290 }
5291 
5292 static int SigSetMultiAppProto(void)
5293 {
5294  Signature *s = SigAlloc();
5295  FAIL_IF_NULL(s);
5296 
5297  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5298  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5299 
5300  // check intersection gives multiple entries
5301  alprotos[0] = 3;
5302  alprotos[1] = 2;
5303  alprotos[2] = ALPROTO_UNKNOWN;
5304  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5305  FAIL_IF(s->init_data->alprotos[0] != 3);
5306  FAIL_IF(s->init_data->alprotos[1] != 2);
5308 
5309  // check single after multiple
5312  FAIL_IF(s->alproto != 3);
5313  alprotos[0] = 4;
5314  alprotos[1] = 3;
5315  alprotos[2] = ALPROTO_UNKNOWN;
5316  // check multiple containing singleton
5317  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5318  FAIL_IF(s->alproto != 3);
5319 
5320  // reset
5321  s->alproto = ALPROTO_UNKNOWN;
5322  alprotos[0] = 1;
5323  alprotos[1] = 2;
5324  alprotos[2] = 3;
5325  alprotos[3] = ALPROTO_UNKNOWN;
5326  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5327  // fail if set single not in multiple
5329 
5331  s->alproto = ALPROTO_UNKNOWN;
5332  alprotos[0] = 1;
5333  alprotos[1] = 2;
5334  alprotos[2] = 3;
5335  alprotos[3] = ALPROTO_UNKNOWN;
5336  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5337  alprotos[0] = 4;
5338  alprotos[1] = 5;
5339  alprotos[2] = ALPROTO_UNKNOWN;
5340  // fail if multiple do not have intersection
5341  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5342 
5344  s->alproto = ALPROTO_UNKNOWN;
5345  alprotos[0] = 1;
5346  alprotos[1] = 2;
5347  alprotos[2] = 3;
5348  alprotos[3] = ALPROTO_UNKNOWN;
5349  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5350  alprotos[0] = 3;
5351  alprotos[1] = 4;
5352  alprotos[2] = 5;
5353  alprotos[3] = ALPROTO_UNKNOWN;
5354  // check multiple intersect to singleton
5355  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5356  FAIL_IF(s->alproto != 3);
5357  alprotos[0] = 5;
5358  alprotos[1] = 4;
5359  alprotos[2] = ALPROTO_UNKNOWN;
5360  // fail if multiple do not belong to singleton
5361  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5362 
5363  SigFree(NULL, s);
5364  PASS;
5365 }
5366 
5367 static int DetectSetupDirection01(void)
5368 {
5369  Signature *s = SigAlloc();
5370  FAIL_IF_NULL(s);
5371  // Basic case : ok
5372  char *str = (char *)"to_client";
5373  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5374  SigFree(NULL, s);
5375  PASS;
5376 }
5377 
5378 static int DetectSetupDirection02(void)
5379 {
5380  Signature *s = SigAlloc();
5381  FAIL_IF_NULL(s);
5382  char *str = (char *)"to_server";
5383  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5384  // ok so far
5385  str = (char *)"to_client";
5386  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5387  // fails because we cannot have both to_client and to_server for same signature
5388  SigFree(NULL, s);
5389  PASS;
5390 }
5391 
5392 static int DetectSetupDirection03(void)
5393 {
5394  Signature *s = SigAlloc();
5395  FAIL_IF_NULL(s);
5396  char *str = (char *)"to_client , something";
5397  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5398  FAIL_IF(strcmp(str, "something") != 0);
5399  str = (char *)"to_client,something";
5400  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5401  FAIL_IF(strcmp(str, "something") != 0);
5402  SigFree(NULL, s);
5403  PASS;
5404 }
5405 
5406 static int DetectSetupDirection04(void)
5407 {
5408  Signature *s = SigAlloc();
5409  FAIL_IF_NULL(s);
5410  // invalid case
5411  char *str = (char *)"to_client_toto";
5412  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5413  // test we do not change the string pointer if only_dir is false
5414  str = (char *)"to_client_toto";
5415  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5416  FAIL_IF(strcmp(str, "to_client_toto") != 0);
5417  str = (char *)"to_client,something";
5418  // fails because we call with only_dir=true
5419  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5420  SigFree(NULL, s);
5421  PASS;
5422 }
5423 
5424 #endif /* UNITTESTS */
5425 
5426 #ifdef UNITTESTS
5427 void DetectParseRegisterTests (void);
5428 #include "tests/detect-parse.c"
5429 #endif
5430 
5432 {
5433 #ifdef UNITTESTS
5435 
5436  UtRegisterTest("SigParseTest01", SigParseTest01);
5437  UtRegisterTest("SigParseTest02", SigParseTest02);
5438  UtRegisterTest("SigParseTest03", SigParseTest03);
5439  UtRegisterTest("SigParseTest04", SigParseTest04);
5440  UtRegisterTest("SigParseTest05", SigParseTest05);
5441  UtRegisterTest("SigParseTest06", SigParseTest06);
5442  UtRegisterTest("SigParseTest07", SigParseTest07);
5443  UtRegisterTest("SigParseTest08", SigParseTest08);
5444  UtRegisterTest("SigParseTest09", SigParseTest09);
5445  UtRegisterTest("SigParseTest10", SigParseTest10);
5446  UtRegisterTest("SigParseTest11", SigParseTest11);
5447  UtRegisterTest("SigParseTest12", SigParseTest12);
5448  UtRegisterTest("SigParseTest13", SigParseTest13);
5449  UtRegisterTest("SigParseTest14", SigParseTest14);
5450  UtRegisterTest("SigParseTest15", SigParseTest15);
5451  UtRegisterTest("SigParseTest16", SigParseTest16);
5452  UtRegisterTest("SigParseTest17", SigParseTest17);
5453  UtRegisterTest("SigParseTest18", SigParseTest18);
5454  UtRegisterTest("SigParseTest19", SigParseTest19);
5455  UtRegisterTest("SigParseTest20", SigParseTest20);
5456  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5457  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5458  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5459 
5460  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5461  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5462  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5463  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5464  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5465  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5466  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5467  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5468  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5469  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5470  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5471  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5472  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5473  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5474  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5475  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5476  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5477  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5478  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5479  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5480  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5481  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5482  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5483  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5484  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5485  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5486  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5487 
5488  UtRegisterTest("SigParseTestContentGtDsize01",
5489  SigParseTestContentGtDsize01);
5490  UtRegisterTest("SigParseTestContentGtDsize02",
5491  SigParseTestContentGtDsize02);
5492 
5493  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5494  SigParseBidirWithSameSrcAndDest01);
5495  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5496  SigParseBidirWithSameSrcAndDest02);
5497  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5498  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5499 
5500  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5501 
5502  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5503  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5504  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5505  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5506 
5507 #endif /* UNITTESTS */
5508 }
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
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:311
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:3211
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
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1455
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
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:1468
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:2156
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:1459
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:1034
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:159
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:321
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:3608
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:335
SigDuplWrapper_::s_prev
Signature * s_prev
Definition: detect-parse.c:97
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:937
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
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:2652
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:408
DetectParseRegex::regex
pcre2_code * regex
Definition: detect-parse.h:93
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:1038
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2434
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
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:1072
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:3228
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3532
DetectBufferType_
Definition: detect.h:449
proto
uint8_t proto
Definition: decode-template.h:0
DetectContentData_
Definition: detect-content.h:93
DetectEngineCtx_::sigerror_ok
bool sigerror_ok
Definition: detect.h:1035
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:2234
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:412
SIG_FLAG_SRC_ANY
#define SIG_FLAG_SRC_ANY
Definition: detect.h:240
SigTableElmt_
element in sigmatch type table.
Definition: detect.h:1428
SigMatchData_
Data needed for Match()
Definition: detect.h:365
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1450
DetectFlowSetupImplicit
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
Definition: detect-flow.c:341
detect-pcre.h
SigMatchData_::type
uint16_t type
Definition: detect.h:366
DetectMatchAddressIPv4_::ip
uint32_t ip
Definition: detect.h:190
DetectContentPMATCHValidateCallback
bool DetectContentPMATCHValidateCallback(const Signature *s)
Definition: detect-content.c:453
DetectParseRegexAddToFreeList
void DetectParseRegexAddToFreeList(DetectParseRegex *detect_parse)
add regex and/or study to at exit free list
Definition: detect-parse.c:3568
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:3552
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:341
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:1134
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:5431
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
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:19
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:2059
DetectEngineThreadCtx_
Definition: detect.h:1252
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:3658
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:1463
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:1119
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:2370
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:3386
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:360
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
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:3646
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3136
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:1466
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:317
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
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:1919
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:1430
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
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect-engine-register.h:325
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:394
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:973
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:34
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1331
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:3478
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
BIT_U8
#define BIT_U8(n)
Definition: suricata-common.h:415
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
SignatureParser_::opts
char opts[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:109
flags
uint8_t flags
Definition: decode-gre.h:0
SigTableElmt_::alias
const char * alias
Definition: detect.h:1469
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
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:318
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:3625
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:946
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:1120
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:337
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:1095
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:308
detect-http-method.h
Signature_::metadata
DetectMetadataHead * metadata
Definition: detect.h:747
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
DETECT_TBLSIZE
int DETECT_TBLSIZE
Definition: detect-engine-register.c:268
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:430
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:982
SigTableElmt_::SupportsPrefilter
bool(* SupportsPrefilter)(const Signature *s)
Definition: detect.h:1452
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:2613
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:3634
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:339
SCClassConfGenerateValidDummyClassConfigFD01
FILE * SCClassConfGenerateValidDummyClassConfigFD01(void)
Creates a dummy classification file, with all valid Classtypes, for testing purposes.
Definition: util-classification-config.c:586
DetectPcreData_
Definition: detect-pcre.h:47
FLOW_QUIET
#define FLOW_QUIET
Definition: flow.h:43
DetectEngineAppInspectionEngine_::dir
uint8_t dir
Definition: detect.h:418
Signature_::detect_table
uint8_t detect_table
Definition: detect.h:706
DetectParseAddress
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
Definition: detect-engine-address.c:1431
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:1033
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:3542
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:939
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:1939
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
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
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:958
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:652
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1427
DetectSetupParseRegexesOpts
bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
Definition: detect-parse.c:3579
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect-engine-register.h:329
DetectPortCleanupList
void DetectPortCleanupList(const DetectEngineCtx *de_ctx, DetectPort *head)
Free a DetectPort list and each of its members.
Definition: detect-engine-port.c:124
DETECT_SM_LIST_SUPPRESS
@ DETECT_SM_LIST_SUPPRESS
Definition: detect.h:132
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
SCClassConfLoadClassificationConfigFile
bool SCClassConfLoadClassificationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
Definition: util-classification-config.c:519
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:3406
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:190
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