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  if (strcmp(n, "request_started") == 0 || strcmp(n, "response_started") == 0) {
1135  return true;
1136  }
1137  if (strcmp(n, "request_complete") == 0 || strcmp(n, "response_complete") == 0) {
1138  return true;
1139  }
1140  return false;
1141 }
1142 
1143 /** \brief register app hooks as generic lists
1144  *
1145  * Register each hook in each app protocol as:
1146  * <alproto>:<hook name>:generic
1147  * These lists can be used by lua scripts to hook into.
1148  *
1149  * \todo move elsewhere? maybe a detect-engine-hook.c?
1150  */
1152 {
1153  for (AppProto a = ALPROTO_FAILED + 1; a < g_alproto_max; a++) {
1154  const char *alproto_name = AppProtoToString(a);
1155  if (strcmp(alproto_name, "http") == 0)
1156  alproto_name = "http1";
1157  SCLogDebug("alproto %u/%s", a, alproto_name);
1158 
1159  const int max_progress_ts =
1161  const int max_progress_tc =
1163 
1164  char ts_tx_started[64];
1165  snprintf(ts_tx_started, sizeof(ts_tx_started), "%s:request_started:generic", alproto_name);
1167  ts_tx_started, a, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
1168  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_started,
1169  (uint32_t)strlen(ts_tx_started));
1170 
1171  char tc_tx_started[64];
1172  snprintf(tc_tx_started, sizeof(tc_tx_started), "%s:response_started:generic", alproto_name);
1174  tc_tx_started, a, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
1175  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_started,
1176  (uint32_t)strlen(tc_tx_started));
1177 
1178  char ts_tx_complete[64];
1179  snprintf(ts_tx_complete, sizeof(ts_tx_complete), "%s:request_complete:generic",
1180  alproto_name);
1181  DetectAppLayerInspectEngineRegister(ts_tx_complete, a, SIG_FLAG_TOSERVER, max_progress_ts,
1183  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "request_name", ts_tx_complete,
1184  (uint32_t)strlen(ts_tx_complete));
1185 
1186  char tc_tx_complete[64];
1187  snprintf(tc_tx_complete, sizeof(tc_tx_complete), "%s:response_complete:generic",
1188  alproto_name);
1189  DetectAppLayerInspectEngineRegister(tc_tx_complete, a, SIG_FLAG_TOCLIENT, max_progress_tc,
1191  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, "response_name", tc_tx_complete,
1192  (uint32_t)strlen(tc_tx_complete));
1193 
1194  for (int p = 0; p <= max_progress_ts; p++) {
1195  const char *name = AppLayerParserGetStateNameById(
1196  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOSERVER);
1197  if (name != NULL && !IsBuiltIn(name)) {
1198  char list_name[64];
1199  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1200  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1201  (uint32_t)strlen(list_name));
1202 
1204  list_name, a, SIG_FLAG_TOSERVER, p, DetectEngineInspectGenericList, NULL);
1205  }
1206  }
1207  for (int p = 0; p <= max_progress_tc; p++) {
1208  const char *name = AppLayerParserGetStateNameById(
1209  IPPROTO_TCP /* TODO no ipproto */, a, p, STREAM_TOCLIENT);
1210  if (name != NULL && !IsBuiltIn(name)) {
1211  char list_name[64];
1212  snprintf(list_name, sizeof(list_name), "%s:%s:generic", alproto_name, name);
1213  SCLogDebug("- hook %s:%s list %s (%u)", alproto_name, name, list_name,
1214  (uint32_t)strlen(list_name));
1215 
1217  list_name, a, SIG_FLAG_TOCLIENT, p, DetectEngineInspectGenericList, NULL);
1218  }
1219  }
1220  }
1221 }
1222 
1223 #ifdef DEBUG
1224 static const char *SignatureHookTypeToString(enum SignatureHookType t)
1225 {
1226  switch (t) {
1228  return "not_set";
1230  return "app";
1232  return "pkt";
1233  }
1234  return "unknown";
1235 }
1236 #endif
1237 
1238 static enum SignatureHookPkt HookPktFromString(const char *str)
1239 {
1240  if (strcmp(str, "flow_start") == 0) {
1242  } else if (strcmp(str, "pre_flow") == 0) {
1244  } else if (strcmp(str, "pre_stream") == 0) {
1246  } else if (strcmp(str, "all") == 0) {
1247  return SIGNATURE_HOOK_PKT_ALL;
1248  }
1250 }
1251 
1252 #ifdef DEBUG
1253 static const char *HookPktToString(const enum SignatureHookPkt ph)
1254 {
1255  switch (ph) {
1257  return "not set";
1259  return "flow_start";
1261  return "pre_flow";
1263  return "pre_stream";
1265  return "all";
1266  }
1267  return "error";
1268 }
1269 #endif
1270 
1271 static SignatureHook SetPktHook(const char *hook_str)
1272 {
1273  SignatureHook h = {
1275  .t.pkt.ph = HookPktFromString(hook_str),
1276  };
1277  return h;
1278 }
1279 
1280 /**
1281  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1282  */
1283 static int SigParseProtoHookPkt(Signature *s, const char *proto_hook, const char *p, const char *h)
1284 {
1285  enum SignatureHookPkt hook = HookPktFromString(h);
1286  if (hook != SIGNATURE_HOOK_PKT_NOT_SET) {
1287  s->init_data->hook = SetPktHook(h);
1288  if (s->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_NOT_SET) {
1289  return -1; // TODO unreachable?
1290  }
1291  } else {
1292  SCLogError("unknown pkt hook %s", h);
1293  return -1;
1294  }
1295 
1296  SCLogDebug("protocol:%s hook:%s: type:%s parsed hook:%s", p, h,
1297  SignatureHookTypeToString(s->init_data->hook.type),
1298  HookPktToString(s->init_data->hook.t.pkt.ph));
1299  return 0;
1300 }
1301 
1302 static SignatureHook SetAppHook(const AppProto alproto, int progress)
1303 {
1304  SignatureHook h = {
1306  .t.app.alproto = alproto,
1307  .t.app.app_progress = progress,
1308  };
1309  return h;
1310 }
1311 
1312 /**
1313  * \param proto_hook string of protocol and hook, e.g. dns:request_complete
1314  */
1315 static int SigParseProtoHookApp(Signature *s, const char *proto_hook, const char *p, const char *h)
1316 {
1317  if (strcmp(h, "request_started") == 0) {
1318  s->flags |= SIG_FLAG_TOSERVER;
1319  s->init_data->hook =
1320  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1321  } else if (strcmp(h, "response_started") == 0) {
1322  s->flags |= SIG_FLAG_TOCLIENT;
1323  s->init_data->hook =
1324  SetAppHook(s->alproto, 0); // state 0 should be the starting state in each protocol.
1325  } else if (strcmp(h, "request_complete") == 0) {
1326  s->flags |= SIG_FLAG_TOSERVER;
1327  s->init_data->hook = SetAppHook(s->alproto,
1329  } else if (strcmp(h, "response_complete") == 0) {
1330  s->flags |= SIG_FLAG_TOCLIENT;
1331  s->init_data->hook = SetAppHook(s->alproto,
1333  } else {
1334  const int progress_ts = AppLayerParserGetStateIdByName(
1335  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOSERVER);
1336  if (progress_ts >= 0) {
1337  s->flags |= SIG_FLAG_TOSERVER;
1338  s->init_data->hook = SetAppHook(s->alproto, progress_ts);
1339  } else {
1340  const int progress_tc = AppLayerParserGetStateIdByName(
1341  IPPROTO_TCP /* TODO */, s->alproto, h, STREAM_TOCLIENT);
1342  if (progress_tc < 0) {
1343  return -1;
1344  }
1345  s->flags |= SIG_FLAG_TOCLIENT;
1346  s->init_data->hook = SetAppHook(s->alproto, progress_tc);
1347  }
1348  }
1349 
1350  char generic_hook_name[64];
1351  snprintf(generic_hook_name, sizeof(generic_hook_name), "%s:generic", proto_hook);
1352  int list = DetectBufferTypeGetByName(generic_hook_name);
1353  if (list < 0) {
1354  SCLogError("no list registered as %s for hook %s", generic_hook_name, proto_hook);
1355  return -1;
1356  }
1357  s->init_data->hook.sm_list = list;
1358 
1359  SCLogDebug("protocol:%s hook:%s: type:%s alproto:%u hook:%d", p, h,
1360  SignatureHookTypeToString(s->init_data->hook.type), s->init_data->hook.t.app.alproto,
1361  s->init_data->hook.t.app.app_progress);
1362 
1363  s->app_progress_hook = (uint8_t)s->init_data->hook.t.app.app_progress;
1364  return 0;
1365 }
1366 
1368 {
1369  printf("=========Supported Rule Protocols=========\n");
1372 }
1373 
1374 /**
1375  * \brief Parses the protocol supplied by the Signature.
1376  *
1377  * http://www.iana.org/assignments/protocol-numbers
1378  *
1379  * \param s Pointer to the Signature instance to which the parsed
1380  * protocol has to be added.
1381  * \param protostr Pointer to the character string containing the protocol name.
1382  *
1383  * \retval 0 On successfully parsing the protocol sent as the argument.
1384  * \retval -1 On failure
1385  */
1386 static int SigParseProto(Signature *s, const char *protostr)
1387 {
1388  SCEnter();
1389  if (strlen(protostr) > 32)
1390  return -1;
1391 
1392  char proto[33];
1393  strlcpy(proto, protostr, 33);
1394  const char *p = proto;
1395  const char *h = NULL;
1396 
1397  bool has_hook = strchr(proto, ':') != NULL;
1398  if (has_hook) {
1399  char *xsaveptr = NULL;
1400  p = strtok_r(proto, ":", &xsaveptr);
1401  h = strtok_r(NULL, ":", &xsaveptr);
1402  SCLogDebug("p: '%s' h: '%s'", p, h);
1403  }
1404  if (p == NULL) {
1405  SCLogError("invalid protocol specification '%s'", proto);
1406  return -1;
1407  }
1408 
1409  int r = DetectProtoParse(&s->proto, p);
1410  if (r < 0) {
1412  /* indicate that the signature is app-layer */
1413  if (s->alproto != ALPROTO_UNKNOWN) {
1414  s->flags |= SIG_FLAG_APPLAYER;
1415 
1417 
1418  if (h) {
1419  if (SigParseProtoHookApp(s, protostr, p, h) < 0) {
1420  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1421  SCReturnInt(-1);
1422  }
1423  }
1424  }
1425  else {
1426  SCLogError("protocol \"%s\" cannot be used "
1427  "in a signature. Either detection for this protocol "
1428  "is not yet supported OR detection has been disabled for "
1429  "protocol through the yaml option "
1430  "app-layer.protocols.%s.detection-enabled",
1431  p, p);
1432  SCReturnInt(-1);
1433  }
1434  } else if (h != NULL) {
1435  SCLogDebug("non-app-layer rule with %s:%s", p, h);
1436 
1437  if (SigParseProtoHookPkt(s, protostr, p, h) < 0) {
1438  SCLogError("protocol \"%s\" does not support hook \"%s\"", p, h);
1439  SCReturnInt(-1);
1440  }
1441  }
1442 
1443  /* if any of these flags are set they are set in a mutually exclusive
1444  * manner */
1445  if (s->proto.flags & DETECT_PROTO_ONLY_PKT) {
1447  } else if (s->proto.flags & DETECT_PROTO_ONLY_STREAM) {
1449  }
1450 
1451  SCReturnInt(0);
1452 }
1453 
1454 /**
1455  * \brief Parses the port(source or destination) field, from a Signature.
1456  *
1457  * \param s Pointer to the signature which has to be updated with the
1458  * port information.
1459  * \param portstr Pointer to the character string containing the port info.
1460  * \param Flag which indicates if the portstr received is src or dst
1461  * port. For src port: flag = 0, dst port: flag = 1.
1462  *
1463  * \retval 0 On success.
1464  * \retval -1 On failure.
1465  */
1466 static int SigParsePort(const DetectEngineCtx *de_ctx,
1467  Signature *s, const char *portstr, char flag)
1468 {
1469  int r = 0;
1470 
1471  /* XXX VJ exclude handling this for none UDP/TCP proto's */
1472 
1473  SCLogDebug("Port group \"%s\" to be parsed", portstr);
1474 
1475  if (flag == 0) {
1476  if (strcasecmp(portstr, "any") == 0)
1477  s->flags |= SIG_FLAG_SP_ANY;
1478 
1479  r = DetectPortParse(de_ctx, &s->sp, (char *)portstr);
1480  } else if (flag == 1) {
1481  if (strcasecmp(portstr, "any") == 0)
1482  s->flags |= SIG_FLAG_DP_ANY;
1483 
1484  r = DetectPortParse(de_ctx, &s->dp, (char *)portstr);
1485  }
1486 
1487  if (r < 0)
1488  return -1;
1489 
1490  return 0;
1491 }
1492 
1493 /** \retval 1 valid
1494  * \retval 0 invalid
1495  */
1496 static int SigParseActionRejectValidate(const char *action)
1497 {
1498 #ifdef HAVE_LIBNET11
1499 #if defined HAVE_LIBCAP_NG && !defined HAVE_LIBNET_CAPABILITIES
1500  if (sc_set_caps) {
1501  SCLogError("Libnet 1.1 is "
1502  "incompatible with POSIX based capabilities with privs dropping. "
1503  "For rejects to work, run as root/super user.");
1504  return 0;
1505  }
1506 #endif
1507 #else /* no libnet 1.1 */
1508  SCLogError("Libnet 1.1.x is "
1509  "required for action \"%s\" but is not compiled into Suricata",
1510  action);
1511  return 0;
1512 #endif
1513  return 1;
1514 }
1515 
1516 /** \retval 0 on error
1517  * \retval flags on success
1518  */
1519 static uint8_t ActionStringToFlags(const char *action)
1520 {
1521  if (strcasecmp(action, "alert") == 0) {
1522  return ACTION_ALERT;
1523  } else if (strcasecmp(action, "drop") == 0) {
1524  return ACTION_DROP | ACTION_ALERT;
1525  } else if (strcasecmp(action, "pass") == 0) {
1526  return ACTION_PASS;
1527  } else if (strcasecmp(action, "reject") == 0 ||
1528  strcasecmp(action, "rejectsrc") == 0)
1529  {
1530  if (!(SigParseActionRejectValidate(action)))
1531  return 0;
1533  } else if (strcasecmp(action, "rejectdst") == 0) {
1534  if (!(SigParseActionRejectValidate(action)))
1535  return 0;
1537  } else if (strcasecmp(action, "rejectboth") == 0) {
1538  if (!(SigParseActionRejectValidate(action)))
1539  return 0;
1541  } else if (strcasecmp(action, "config") == 0) {
1542  return ACTION_CONFIG;
1543  } else if (strcasecmp(action, "accept") == 0) {
1544  return ACTION_ACCEPT;
1545  } else {
1546  SCLogError("An invalid action \"%s\" was given", action);
1547  return 0;
1548  }
1549 }
1550 
1551 /**
1552  * \brief Parses the action that has been used by the Signature and allots it
1553  * to its Signature instance.
1554  *
1555  * \param s Pointer to the Signature instance to which the action belongs.
1556  * \param action Pointer to the action string used by the Signature.
1557  *
1558  * \retval 0 On successfully parsing the action string and adding it to the
1559  * Signature.
1560  * \retval -1 On failure.
1561  */
1562 static int SigParseAction(Signature *s, const char *action_in)
1563 {
1564  char action[32];
1565  strlcpy(action, action_in, sizeof(action));
1566  const char *a = action;
1567  const char *o = NULL;
1568 
1569  bool has_scope = strchr(action, ':') != NULL;
1570  if (has_scope) {
1571  char *xsaveptr = NULL;
1572  a = strtok_r(action, ":", &xsaveptr);
1573  o = strtok_r(NULL, ":", &xsaveptr);
1574  SCLogDebug("a: '%s' o: '%s'", a, o);
1575  }
1576  if (a == NULL) {
1577  SCLogError("invalid protocol specification '%s'", action_in);
1578  return -1;
1579  }
1580 
1581  uint8_t flags = ActionStringToFlags(a);
1582  if (flags == 0)
1583  return -1;
1584 
1585  /* parse scope, if any */
1586  if (o) {
1587  uint8_t scope_flags = 0;
1588  if (flags & (ACTION_DROP | ACTION_PASS)) {
1589  if (strcmp(o, "packet") == 0) {
1590  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1591  } else if (strcmp(o, "flow") == 0) {
1592  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1593  } else {
1594  SCLogError("invalid action scope '%s' in action '%s': only 'packet' and 'flow' "
1595  "allowed",
1596  o, action_in);
1597  return -1;
1598  }
1599  s->action_scope = scope_flags;
1600  } else if (flags & (ACTION_ACCEPT)) {
1601  if (strcmp(o, "packet") == 0) {
1602  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1603  } else if (strcmp(o, "hook") == 0) {
1604  scope_flags = (uint8_t)ACTION_SCOPE_HOOK;
1605  } else if (strcmp(o, "tx") == 0) {
1606  scope_flags = (uint8_t)ACTION_SCOPE_TX;
1607  } else if (strcmp(o, "flow") == 0) {
1608  scope_flags = (uint8_t)ACTION_SCOPE_FLOW;
1609  } else {
1610  SCLogError(
1611  "invalid action scope '%s' in action '%s': only 'packet', 'flow', 'tx' and "
1612  "'hook' allowed",
1613  o, action_in);
1614  return -1;
1615  }
1616  s->action_scope = scope_flags;
1617  } else if (flags & (ACTION_CONFIG)) {
1618  if (strcmp(o, "packet") == 0) {
1619  scope_flags = (uint8_t)ACTION_SCOPE_PACKET;
1620  } else {
1621  SCLogError("invalid action scope '%s' in action '%s': only 'packet' allowed", o,
1622  action_in);
1623  return -1;
1624  }
1625  s->action_scope = scope_flags;
1626  } else {
1627  SCLogError("invalid action scope '%s' in action '%s': scope only supported for actions "
1628  "'drop', 'pass' and 'reject'",
1629  o, action_in);
1630  return -1;
1631  }
1632  }
1633 
1634  /* require explicit action scope for fw rules */
1635  if (s->init_data->firewall_rule && s->action_scope == 0) {
1636  SCLogError("firewall rules require setting an explicit action scope");
1637  return -1;
1638  }
1639 
1640  if (!s->init_data->firewall_rule && (flags & ACTION_ACCEPT)) {
1641  SCLogError("'accept' action only supported for firewall rules");
1642  return -1;
1643  }
1644 
1645  if (s->init_data->firewall_rule && (flags & ACTION_PASS)) {
1646  SCLogError("'pass' action not supported for firewall rules");
1647  return -1;
1648  }
1649 
1650  s->action = flags;
1651  return 0;
1652 }
1653 
1654 /**
1655  * \brief Parse the next token in rule.
1656  *
1657  * For rule parsing a token is considered to be a string of characters
1658  * separated by white space.
1659  *
1660  * \param input double pointer to input buffer, will be advanced as input is
1661  * parsed.
1662  * \param output buffer to copy token into.
1663  * \param output_size length of output buffer.
1664  */
1665 static inline int SigParseToken(char **input, char *output,
1666  const size_t output_size)
1667 {
1668  size_t len = *input == NULL ? 0 : strlen(*input);
1669 
1670  if (!len) {
1671  return 0;
1672  }
1673 
1674  while (len && isblank(**input)) {
1675  (*input)++;
1676  len--;
1677  }
1678 
1679  char *endptr = strpbrk(*input, " \t\n\r");
1680  if (endptr != NULL) {
1681  *(endptr++) = '\0';
1682  }
1683  strlcpy(output, *input, output_size);
1684  *input = endptr;
1685 
1686  return 1;
1687 }
1688 
1689 /**
1690  * \brief Parse the next rule "list" token.
1691  *
1692  * Parses rule tokens that may be lists such as addresses and ports
1693  * handling the case when they may not be lists.
1694  *
1695  * \param input double pointer to input buffer, will be advanced as input is
1696  * parsed.
1697  * \param output buffer to copy token into.
1698  * \param output_size length of output buffer.
1699  */
1700 static inline int SigParseList(char **input, char *output,
1701  const size_t output_size)
1702 {
1703  int in_list = 0;
1704  size_t len = *input != NULL ? strlen(*input) : 0;
1705 
1706  if (len == 0) {
1707  return 0;
1708  }
1709 
1710  while (len && isblank(**input)) {
1711  (*input)++;
1712  len--;
1713  }
1714 
1715  size_t i = 0;
1716  for (i = 0; i < len; i++) {
1717  char c = (*input)[i];
1718  if (c == '[') {
1719  in_list++;
1720  } else if (c == ']') {
1721  in_list--;
1722  } else if (c == ' ') {
1723  if (!in_list) {
1724  break;
1725  }
1726  }
1727  }
1728  if (i == len) {
1729  *input = NULL;
1730  return 0;
1731  }
1732  (*input)[i] = '\0';
1733  strlcpy(output, *input, output_size);
1734  *input = *input + i + 1;
1735 
1736  return 1;
1737 }
1738 
1739 /**
1740  * \internal
1741  * \brief split a signature string into a few blocks for further parsing
1742  *
1743  * \param scan_only just scan, don't validate
1744  */
1745 static int SigParseBasics(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1746  SignatureParser *parser, uint8_t addrs_direction, bool scan_only)
1747 {
1748  char *index, dup[DETECT_MAX_RULE_SIZE];
1749 
1750  strlcpy(dup, sigstr, DETECT_MAX_RULE_SIZE);
1751  index = dup;
1752 
1753  /* Action. */
1754  SigParseToken(&index, parser->action, sizeof(parser->action));
1755 
1756  /* Protocol. */
1757  SigParseList(&index, parser->protocol, sizeof(parser->protocol));
1758 
1759  /* Source. */
1760  SigParseList(&index, parser->src, sizeof(parser->src));
1761 
1762  /* Source port(s). */
1763  SigParseList(&index, parser->sp, sizeof(parser->sp));
1764 
1765  /* Direction. */
1766  SigParseToken(&index, parser->direction, sizeof(parser->direction));
1767 
1768  /* Destination. */
1769  SigParseList(&index, parser->dst, sizeof(parser->dst));
1770 
1771  /* Destination port(s). */
1772  SigParseList(&index, parser->dp, sizeof(parser->dp));
1773 
1774  /* Options. */
1775  if (index == NULL) {
1776  SCLogError("no rule options.");
1777  goto error;
1778  }
1779  while (isspace(*index) || *index == '(') {
1780  index++;
1781  }
1782  for (size_t i = strlen(index); i > 0; i--) {
1783  if (isspace(index[i - 1]) || index[i - 1] == ')') {
1784  index[i - 1] = '\0';
1785  } else {
1786  break;
1787  }
1788  }
1789  strlcpy(parser->opts, index, sizeof(parser->opts));
1790 
1791  if (scan_only) {
1792  return 0;
1793  }
1794 
1795  /* Parse Action */
1796  if (SigParseAction(s, parser->action) < 0)
1797  goto error;
1798 
1799  if (SigParseProto(s, parser->protocol) < 0)
1800  goto error;
1801 
1802  if (strcmp(parser->direction, "<>") == 0) {
1804  } else if (strcmp(parser->direction, "=>") == 0) {
1805  if (s->flags & SIG_FLAG_FIREWALL) {
1806  SCLogError("transactional bidirectional rules not supported for firewall rules");
1807  goto error;
1808  }
1809 
1810  s->flags |= SIG_FLAG_TXBOTHDIR;
1811  } else if (strcmp(parser->direction, "->") != 0) {
1812  SCLogError("\"%s\" is not a valid direction modifier, "
1813  "\"->\" and \"<>\" are supported.",
1814  parser->direction);
1815  goto error;
1816  }
1817 
1818  /* Parse Address & Ports */
1819  if (SigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ addrs_direction) < 0)
1820  goto error;
1821 
1822  if (SigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ addrs_direction) < 0)
1823  goto error;
1824 
1825  /* By AWS - Traditionally we should be doing this only for tcp/udp/sctp,
1826  * but we do it for regardless of ip proto, since the dns/dnstcp/dnsudp
1827  * changes that we made sees to it that at this point of time we don't
1828  * set the ip proto for the sig. We do it a bit later. */
1829  if (SigParsePort(de_ctx, s, parser->sp, SIG_DIREC_SRC ^ addrs_direction) < 0)
1830  goto error;
1831  if (SigParsePort(de_ctx, s, parser->dp, SIG_DIREC_DST ^ addrs_direction) < 0)
1832  goto error;
1833 
1834  return 0;
1835 
1836 error:
1837  return -1;
1838 }
1839 
1840 static inline bool CheckAscii(const char *str)
1841 {
1842  for (size_t i = 0; i < strlen(str); i++) {
1843  if (str[i] < 0x20) {
1844  // LF CR TAB
1845  if (str[i] == 0x0a || str[i] == 0x0d || str[i] == 0x09) {
1846  continue;
1847  }
1848  return false;
1849  } else if (str[i] == 0x7f) {
1850  return false;
1851  }
1852  }
1853  return true;
1854 }
1855 
1856 /**
1857  * \brief parse a signature
1858  *
1859  * \param de_ctx detection engine ctx to add it to
1860  * \param s memory structure to store the signature in
1861  * \param sigstr the raw signature as a null terminated string
1862  * \param addrs_direction direction (for bi-directional sigs)
1863  * \param require only scan rule for requires
1864  *
1865  * \param -1 parse error
1866  * \param 0 ok
1867  */
1868 static int SigParse(DetectEngineCtx *de_ctx, Signature *s, const char *sigstr,
1869  uint8_t addrs_direction, SignatureParser *parser, bool requires)
1870 {
1871  SCEnter();
1872 
1873  if (!SCCheckUtf8(sigstr)) {
1874  SCLogError("rule is not valid UTF-8");
1875  SCReturnInt(-1);
1876  }
1877 
1878  if (!CheckAscii(sigstr)) {
1879  SCLogError("rule contains invalid (control) characters");
1880  SCReturnInt(-1);
1881  }
1882 
1883  int ret = SigParseBasics(de_ctx, s, sigstr, parser, addrs_direction, requires);
1884  if (ret < 0) {
1885  SCLogDebug("SigParseBasics failed");
1886  SCReturnInt(-1);
1887  }
1888 
1889  /* we can have no options, so make sure we have them */
1890  if (strlen(parser->opts) > 0) {
1891  size_t buffer_size = strlen(parser->opts) + 1;
1893  char input[buffer_size];
1894  char output[buffer_size];
1895  memset(input, 0x00, buffer_size);
1896  memcpy(input, parser->opts, strlen(parser->opts) + 1);
1897 
1898  /* loop the option parsing. Each run processes one option
1899  * and returns the rest of the option string through the
1900  * output variable. */
1901  do {
1902  memset(output, 0x00, buffer_size);
1903  ret = SigParseOptions(de_ctx, s, input, output, buffer_size, requires);
1904  if (ret == 1) {
1905  memcpy(input, output, buffer_size);
1906  }
1907 
1908  } while (ret == 1);
1909 
1910  if (ret < 0) {
1911  /* Suricata didn't meet the rule requirements, skip. */
1912  goto end;
1913  }
1914  }
1915 
1916 end:
1918 
1919  SCReturnInt(ret);
1920 }
1921 
1922 /** \brief check if buffers array still has space left, expand if not
1923  */
1925 {
1926  if (s->init_data->buffers_size >= 64)
1927  return -1;
1928 
1929  if (s->init_data->buffer_index + 1 == s->init_data->buffers_size) {
1930  void *ptr = SCRealloc(s->init_data->buffers,
1931  (s->init_data->buffers_size + 8) * sizeof(SignatureInitDataBuffer));
1932  if (ptr == NULL)
1933  return -1;
1934  s->init_data->buffers = ptr;
1935  for (uint32_t x = s->init_data->buffers_size; x < s->init_data->buffers_size + 8; x++) {
1937  memset(b, 0, sizeof(*b));
1938  }
1939  s->init_data->buffers_size += 8;
1940  }
1941  return 0;
1942 }
1943 
1945 {
1946  Signature *sig = SCCalloc(1, sizeof(Signature));
1947  if (unlikely(sig == NULL))
1948  return NULL;
1949 
1950  sig->init_data = SCCalloc(1, sizeof(SignatureInitData));
1951  if (sig->init_data == NULL) {
1952  SCFree(sig);
1953  return NULL;
1954  }
1955  sig->init_data->mpm_sm_list = -1;
1956 
1957  sig->init_data->buffers = SCCalloc(8, sizeof(SignatureInitDataBuffer));
1958  if (sig->init_data->buffers == NULL) {
1959  SCFree(sig->init_data);
1960  SCFree(sig);
1961  return NULL;
1962  }
1963  sig->init_data->buffers_size = 8;
1964 
1965  /* assign it to -1, so that we can later check if the value has been
1966  * overwritten after the Signature has been parsed, and if it hasn't been
1967  * overwritten, we can then assign the default value of 3 */
1968  sig->prio = -1;
1969 
1970  /* rule interdepency is false, at start */
1971  sig->init_data->is_rule_state_dependant = false;
1972  /* first index is 0 */
1974 
1976  return sig;
1977 }
1978 
1979 /**
1980  * \internal
1981  * \brief Free Metadata list
1982  *
1983  * \param s Pointer to the signature
1984  */
1985 static void SigMetadataFree(Signature *s)
1986 {
1987  SCEnter();
1988 
1989  DetectMetadata *mdata = NULL;
1990  DetectMetadata *next_mdata = NULL;
1991 
1992  if (s == NULL || s->metadata == NULL) {
1993  SCReturn;
1994  }
1995 
1996  SCLogDebug("s %p, s->metadata %p", s, s->metadata);
1997 
1998  for (mdata = s->metadata->list; mdata != NULL;) {
1999  next_mdata = mdata->next;
2000  DetectMetadataFree(mdata);
2001  mdata = next_mdata;
2002  }
2003  SCFree(s->metadata->json_str);
2004  SCFree(s->metadata);
2005  s->metadata = NULL;
2006 
2007  SCReturn;
2008 }
2009 
2010 /**
2011  * \internal
2012  * \brief Free Reference list
2013  *
2014  * \param s Pointer to the signature
2015  */
2016 static void SigRefFree (Signature *s)
2017 {
2018  SCEnter();
2019 
2020  DetectReference *ref = NULL;
2021  DetectReference *next_ref = NULL;
2022 
2023  if (s == NULL) {
2024  SCReturn;
2025  }
2026 
2027  SCLogDebug("s %p, s->references %p", s, s->references);
2028 
2029  for (ref = s->references; ref != NULL;) {
2030  next_ref = ref->next;
2031  DetectReferenceFree(ref);
2032  ref = next_ref;
2033  }
2034 
2035  s->references = NULL;
2036 
2037  SCReturn;
2038 }
2039 
2040 static void SigMatchFreeArrays(DetectEngineCtx *de_ctx, Signature *s, int ctxs)
2041 {
2042  if (s != NULL) {
2043  int type;
2044  for (type = 0; type < DETECT_SM_LIST_MAX; type++) {
2045  if (s->sm_arrays[type] != NULL) {
2046  if (ctxs) {
2047  SigMatchData *smd = s->sm_arrays[type];
2048  while(1) {
2049  if (sigmatch_table[smd->type].Free != NULL) {
2050  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
2051  }
2052  if (smd->is_last)
2053  break;
2054  smd++;
2055  }
2056  }
2057 
2058  SCFree(s->sm_arrays[type]);
2059  }
2060  }
2061  }
2062 }
2063 
2065 {
2066  if (s == NULL)
2067  return;
2068 
2069  int i;
2070 
2071  if (s->init_data && s->init_data->transforms.cnt) {
2072  for(i = 0; i < s->init_data->transforms.cnt; i++) {
2073  if (s->init_data->transforms.transforms[i].options) {
2074  int transform = s->init_data->transforms.transforms[i].transform;
2075  sigmatch_table[transform].Free(
2077  s->init_data->transforms.transforms[i].options = NULL;
2078  }
2079  }
2080  }
2081  if (s->init_data) {
2082  for (i = 0; i < DETECT_SM_LIST_MAX; i++) {
2083  SigMatch *sm = s->init_data->smlists[i];
2084  while (sm != NULL) {
2085  SigMatch *nsm = sm->next;
2086  SigMatchFree(de_ctx, sm);
2087  sm = nsm;
2088  }
2089  }
2090 
2091  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2092  SigMatch *sm = s->init_data->buffers[x].head;
2093  while (sm != NULL) {
2094  SigMatch *nsm = sm->next;
2095  SigMatchFree(de_ctx, sm);
2096  sm = nsm;
2097  }
2098  }
2099  if (s->init_data->cidr_dst != NULL)
2101 
2102  if (s->init_data->cidr_src != NULL)
2104 
2105  SCFree(s->init_data->buffers);
2106  s->init_data->buffers = NULL;
2107  }
2108  SigMatchFreeArrays(de_ctx, s, (s->init_data == NULL));
2109  if (s->init_data) {
2110  SCFree(s->init_data);
2111  s->init_data = NULL;
2112  }
2113 
2114  if (s->sp != NULL) {
2115  DetectPortCleanupList(NULL, s->sp);
2116  }
2117  if (s->dp != NULL) {
2118  DetectPortCleanupList(NULL, s->dp);
2119  }
2120 
2121  if (s->msg != NULL)
2122  SCFree(s->msg);
2123 
2124  if (s->addr_src_match4 != NULL) {
2125  SCFree(s->addr_src_match4);
2126  }
2127  if (s->addr_dst_match4 != NULL) {
2128  SCFree(s->addr_dst_match4);
2129  }
2130  if (s->addr_src_match6 != NULL) {
2131  SCFree(s->addr_src_match6);
2132  }
2133  if (s->addr_dst_match6 != NULL) {
2134  SCFree(s->addr_dst_match6);
2135  }
2136  if (s->sig_str != NULL) {
2137  SCFree(s->sig_str);
2138  }
2139 
2140  SigRefFree(s);
2141  SigMetadataFree(s);
2142 
2144 
2145  SCFree(s);
2146 }
2147 
2148 /**
2149  * \brief this function is used to set multiple possible app-layer protos
2150  * \brief into the current signature (for example ja4 for both tls and quic)
2151  *
2152  * \param s pointer to the Current Signature
2153  * \param alprotos an array terminated by ALPROTO_UNKNOWN
2154  *
2155  * \retval 0 on Success
2156  * \retval -1 on Failure
2157  */
2159 {
2160  if (s->alproto != ALPROTO_UNKNOWN) {
2161  // One alproto was set, check if it matches the new ones proposed
2162  while (*alprotos != ALPROTO_UNKNOWN) {
2163  if (s->alproto == *alprotos) {
2164  // alproto already set to only one
2165  return 0;
2166  }
2167  alprotos++;
2168  }
2169  // alproto already set and not matching the new set of alprotos
2170  return -1;
2171  }
2172  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2173  // check intersection of already used alprotos and new ones
2174  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2175  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2176  break;
2177  }
2178  // first disable the ones that do not match
2179  bool found = false;
2180  const AppProto *args = alprotos;
2181  while (*args != ALPROTO_UNKNOWN) {
2182  if (s->init_data->alprotos[i] == *args) {
2183  found = true;
2184  break;
2185  }
2186  args++;
2187  }
2188  if (!found) {
2190  }
2191  }
2192  // Then put at the beginning every defined protocol
2193  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2194  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2195  for (AppProto j = SIG_ALPROTO_MAX - 1; j > i; j--) {
2196  if (s->init_data->alprotos[j] != ALPROTO_UNKNOWN) {
2197  s->init_data->alprotos[i] = s->init_data->alprotos[j];
2199  break;
2200  }
2201  }
2202  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2203  if (i == 0) {
2204  // there was no intersection
2205  return -1;
2206  } else if (i == 1) {
2207  // intersection is singleton, set it as usual
2208  AppProto alproto = s->init_data->alprotos[0];
2210  return SCDetectSignatureSetAppProto(s, alproto);
2211  }
2212  break;
2213  }
2214  }
2215  }
2216  } else {
2217  if (alprotos[0] == ALPROTO_UNKNOWN) {
2218  // do not allow empty set
2219  return -1;
2220  }
2221  if (alprotos[1] == ALPROTO_UNKNOWN) {
2222  // allow singleton, but call traditional setter
2223  return SCDetectSignatureSetAppProto(s, alprotos[0]);
2224  }
2225  // first time we enforce alprotos
2226  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2227  if (alprotos[i] == ALPROTO_UNKNOWN) {
2228  break;
2229  }
2230  s->init_data->alprotos[i] = alprotos[i];
2231  }
2232  }
2233  return 0;
2234 }
2235 
2237 {
2238  if (!AppProtoIsValid(alproto)) {
2239  SCLogError("invalid alproto %u", alproto);
2240  return -1;
2241  }
2242 
2243  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2244  // Multiple alprotos were set, check if we restrict to one
2245  bool found = false;
2246  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2247  if (s->init_data->alprotos[i] == alproto) {
2248  found = true;
2249  break;
2250  }
2251  }
2252  if (!found) {
2253  // fail if we set to a alproto which was not in the set
2254  return -1;
2255  }
2256  // we will use s->alproto if there is a single alproto and
2257  // we reset s->init_data->alprotos to signal there are no longer multiple alprotos
2259  }
2260 
2261  if (s->alproto != ALPROTO_UNKNOWN) {
2262  alproto = AppProtoCommon(s->alproto, alproto);
2263  if (alproto == ALPROTO_FAILED) {
2264  SCLogError("can't set rule app proto to %s: already set to %s",
2265  AppProtoToString(alproto), AppProtoToString(s->alproto));
2266  return -1;
2267  }
2268  }
2269 
2270  if (AppLayerProtoDetectGetProtoName(alproto) == NULL) {
2271  SCLogError("disabled alproto %s, rule can never match", AppProtoToString(alproto));
2272  return -1;
2273  }
2274  s->alproto = alproto;
2275  s->flags |= SIG_FLAG_APPLAYER;
2276  return 0;
2277 }
2278 
2279 static DetectMatchAddressIPv4 *SigBuildAddressMatchArrayIPv4(
2280  const DetectAddress *head, uint16_t *match4_cnt)
2281 {
2282  uint16_t cnt = 0;
2283 
2284  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2285  cnt++;
2286  }
2287  if (cnt == 0) {
2288  return NULL;
2289  }
2290  DetectMatchAddressIPv4 *addr_match4 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv4));
2291  if (addr_match4 == NULL) {
2292  return NULL;
2293  }
2294 
2295  uint16_t idx = 0;
2296  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2297  addr_match4[idx].ip = SCNtohl(da->ip.addr_data32[0]);
2298  addr_match4[idx].ip2 = SCNtohl(da->ip2.addr_data32[0]);
2299  idx++;
2300  }
2301  *match4_cnt = cnt;
2302  return addr_match4;
2303 }
2304 
2305 static DetectMatchAddressIPv6 *SigBuildAddressMatchArrayIPv6(
2306  const DetectAddress *head, uint16_t *match6_cnt)
2307 {
2308  uint16_t cnt = 0;
2309  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2310  cnt++;
2311  }
2312  if (cnt == 0) {
2313  return NULL;
2314  }
2315 
2316  DetectMatchAddressIPv6 *addr_match6 = SCCalloc(cnt, sizeof(DetectMatchAddressIPv6));
2317  if (addr_match6 == NULL) {
2318  return NULL;
2319  }
2320 
2321  uint16_t idx = 0;
2322  for (const DetectAddress *da = head; da != NULL; da = da->next) {
2323  addr_match6[idx].ip[0] = SCNtohl(da->ip.addr_data32[0]);
2324  addr_match6[idx].ip[1] = SCNtohl(da->ip.addr_data32[1]);
2325  addr_match6[idx].ip[2] = SCNtohl(da->ip.addr_data32[2]);
2326  addr_match6[idx].ip[3] = SCNtohl(da->ip.addr_data32[3]);
2327  addr_match6[idx].ip2[0] = SCNtohl(da->ip2.addr_data32[0]);
2328  addr_match6[idx].ip2[1] = SCNtohl(da->ip2.addr_data32[1]);
2329  addr_match6[idx].ip2[2] = SCNtohl(da->ip2.addr_data32[2]);
2330  addr_match6[idx].ip2[3] = SCNtohl(da->ip2.addr_data32[3]);
2331  idx++;
2332  }
2333  *match6_cnt = cnt;
2334  return addr_match6;
2335 }
2336 
2337 /**
2338  * \internal
2339  * \brief build address match array for cache efficient matching
2340  *
2341  * \param s the signature
2342  */
2343 static void SigBuildAddressMatchArray(Signature *s)
2344 {
2345  /* source addresses */
2346  s->addr_src_match4 =
2347  SigBuildAddressMatchArrayIPv4(s->init_data->src->ipv4_head, &s->addr_src_match4_cnt);
2348  /* destination addresses */
2349  s->addr_dst_match4 =
2350  SigBuildAddressMatchArrayIPv4(s->init_data->dst->ipv4_head, &s->addr_dst_match4_cnt);
2351 
2352  /* source addresses IPv6 */
2353  s->addr_src_match6 =
2354  SigBuildAddressMatchArrayIPv6(s->init_data->src->ipv6_head, &s->addr_src_match6_cnt);
2355  /* destination addresses IPv6 */
2356  s->addr_dst_match6 =
2357  SigBuildAddressMatchArrayIPv6(s->init_data->dst->ipv6_head, &s->addr_dst_match6_cnt);
2358 }
2359 
2360 static int SigMatchListLen(SigMatch *sm)
2361 {
2362  int len = 0;
2363  for (; sm != NULL; sm = sm->next)
2364  len++;
2365 
2366  return len;
2367 }
2368 
2369 /** \brief convert SigMatch list to SigMatchData array
2370  * \note ownership of sm->ctx is transferred to smd->ctx
2371  */
2373 {
2374  int len = SigMatchListLen(head);
2375  if (len == 0)
2376  return NULL;
2377 
2378  SigMatchData *smd = (SigMatchData *)SCCalloc(len, sizeof(SigMatchData));
2379  if (smd == NULL) {
2380  FatalError("initializing the detection engine failed");
2381  }
2382  SigMatchData *out = smd;
2383 
2384  /* Copy sm type and Context into array */
2385  SigMatch *sm = head;
2386  for (; sm != NULL; sm = sm->next, smd++) {
2387  smd->type = sm->type;
2388  smd->ctx = sm->ctx;
2389  sm->ctx = NULL; // SigMatch no longer owns the ctx
2390  smd->is_last = (sm->next == NULL);
2391  }
2392  return out;
2393 }
2394 
2395 extern int g_skip_prefilter;
2396 
2397 static void SigSetupPrefilter(DetectEngineCtx *de_ctx, Signature *s)
2398 {
2399  SCEnter();
2400  SCLogDebug("s %u: set up prefilter/mpm", s->id);
2401  DEBUG_VALIDATE_BUG_ON(s->init_data->mpm_sm != NULL);
2402 
2403  if (s->init_data->prefilter_sm != NULL) {
2404  if (s->init_data->prefilter_sm->type == DETECT_CONTENT) {
2406  if (s->init_data->mpm_sm != NULL) {
2407  s->flags |= SIG_FLAG_PREFILTER;
2408  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2409  SCReturn;
2410  }
2411  /* fall through, this can happen if the mpm doesn't support the pattern */
2412  } else {
2413  s->flags |= SIG_FLAG_PREFILTER;
2414  SCReturn;
2415  }
2416  } else {
2417  SCLogDebug("%u: RetrieveFPForSig", s->id);
2419  if (s->init_data->mpm_sm != NULL) {
2420  s->flags |= SIG_FLAG_PREFILTER;
2421  SCLogDebug("%u: RetrieveFPForSig set", s->id);
2422  SCReturn;
2423  }
2424  }
2425 
2426  SCLogDebug("s %u: no mpm; prefilter? de_ctx->prefilter_setting %u "
2427  "s->init_data->has_possible_prefilter %s",
2429 
2431  SCReturn;
2432 
2435  int prefilter_list = DETECT_TBLSIZE;
2436  /* get the keyword supporting prefilter with the lowest type */
2437  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2438  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2439  if (sigmatch_table[sm->type].SupportsPrefilter != NULL) {
2440  if (sigmatch_table[sm->type].SupportsPrefilter(s)) {
2441  prefilter_list = MIN(prefilter_list, sm->type);
2442  }
2443  }
2444  }
2445  }
2446 
2447  /* apply that keyword as prefilter */
2448  if (prefilter_list != DETECT_TBLSIZE) {
2449  for (int i = 0; i < DETECT_SM_LIST_MAX; i++) {
2450  for (SigMatch *sm = s->init_data->smlists[i]; sm != NULL; sm = sm->next) {
2451  if (sm->type == prefilter_list) {
2452  s->init_data->prefilter_sm = sm;
2453  s->flags |= SIG_FLAG_PREFILTER;
2454  SCLogConfig("sid %u: prefilter is on \"%s\"", s->id,
2455  sigmatch_table[sm->type].name);
2456  break;
2457  }
2458  }
2459  }
2460  }
2461  }
2462  SCReturn;
2463 }
2464 
2465 /** \internal
2466  * \brief check if signature's table requirement is supported by each of the keywords it uses.
2467  */
2468 static bool DetectRuleValidateTable(const Signature *s)
2469 {
2470  if (s->detect_table == 0)
2471  return true;
2472 
2473  const uint8_t table_as_flag = BIT_U8(s->detect_table);
2474 
2475  for (SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL; sm = sm->next) {
2476  const uint8_t kw_tables_supported = sigmatch_table[sm->type].tables;
2477  if (kw_tables_supported != 0 && (kw_tables_supported & table_as_flag) == 0) {
2478  SCLogError("rule %u uses hook \"%s\", but keyword \"%s\" doesn't support this hook",
2480  return false;
2481  }
2482  }
2483  return true;
2484 }
2485 
2486 static bool DetectFirewallRuleValidate(const DetectEngineCtx *de_ctx, const Signature *s)
2487 {
2489  SCLogError("rule %u is loaded as a firewall rule, but does not specify an "
2490  "explicit hook",
2491  s->id);
2492  return false;
2493  }
2494  return true;
2495 }
2496 
2497 static void DetectRuleSetTable(Signature *s)
2498 {
2499  enum DetectTable table;
2500  if (s->flags & SIG_FLAG_FIREWALL) {
2501  if (s->type == SIG_TYPE_PKT) {
2505  else if (s->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT &&
2508  else
2510  } else if (s->type == SIG_TYPE_APP_TX) {
2511  table = DETECT_TABLE_APP_FILTER;
2512  } else {
2513  BUG_ON(1);
2514  }
2515  } else {
2516  // TODO pre_flow/pre_stream
2517  if (s->type != SIG_TYPE_APP_TX) {
2518  table = DETECT_TABLE_PACKET_TD;
2519  } else {
2520  table = DETECT_TABLE_APP_TD;
2521  }
2522  }
2523 
2524  s->detect_table = (uint8_t)table;
2525 }
2526 
2527 static int SigValidateFirewall(const DetectEngineCtx *de_ctx, const Signature *s)
2528 {
2529  if (s->init_data->firewall_rule) {
2530  if (!DetectFirewallRuleValidate(de_ctx, s))
2531  SCReturnInt(0);
2532  }
2533  SCReturnInt(1);
2534 }
2535 
2536 static int SigValidateCheckBuffers(
2537  DetectEngineCtx *de_ctx, const Signature *s, int *ts_excl, int *tc_excl, int *dir_amb)
2538 {
2539  bool has_frame = false;
2540  bool has_app = false;
2541  bool has_pkt = false;
2542  bool has_pmatch = false;
2543 
2544  int nlists = 0;
2545  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2546  nlists = MAX(nlists, (int)s->init_data->buffers[x].id);
2547  }
2548  nlists += (nlists > 0);
2549  SCLogDebug("nlists %d", nlists);
2550 
2551  if (s->init_data->curbuf && s->init_data->curbuf->head == NULL) {
2552  SCLogError("rule %u setup buffer %s but didn't add matches to it", s->id,
2554  SCReturnInt(0);
2555  }
2556 
2557  /* run buffer type validation callbacks if any */
2560  SCReturnInt(0);
2561 
2562  has_pmatch = true;
2563  }
2564 
2565  DEBUG_VALIDATE_BUG_ON(nlists > UINT16_MAX);
2566  struct BufferVsDir {
2567  int ts;
2568  int tc;
2569  } bufdir[nlists + 1];
2570  memset(&bufdir, 0, (nlists + 1) * sizeof(struct BufferVsDir));
2571 
2572  for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
2575  if (bt == NULL) {
2576  DEBUG_VALIDATE_BUG_ON(1); // should be impossible
2577  continue;
2578  }
2579  SCLogDebug("x %u b->id %u name %s", x, b->id, bt->name);
2580  for (const SigMatch *sm = b->head; sm != NULL; sm = sm->next) {
2581  SCLogDebug("sm %u %s", sm->type, sigmatch_table[sm->type].name);
2582  }
2583 
2584  if (b->head == NULL) {
2585  SCLogError("no matches in sticky buffer %s", bt->name);
2586  SCReturnInt(0);
2587  }
2588 
2589  has_frame |= bt->frame;
2590  has_app |= (!bt->frame && !bt->packet);
2591  has_pkt |= bt->packet;
2592 
2593  if ((s->flags & SIG_FLAG_REQUIRE_PACKET) && !bt->packet) {
2594  SCLogError("Signature combines packet "
2595  "specific matches (like dsize, flags, ttl) with stream / "
2596  "state matching by matching on app layer proto (like using "
2597  "http_* keywords).");
2598  SCReturnInt(0);
2599  }
2600 
2602  for (; app != NULL; app = app->next) {
2603  if (app->sm_list == b->id &&
2604  (AppProtoEquals(s->alproto, app->alproto) || s->alproto == 0)) {
2605  SCLogDebug("engine %s dir %d alproto %d",
2607  app->alproto);
2608  SCLogDebug("b->id %d nlists %d", b->id, nlists);
2609 
2610  if (b->only_tc) {
2611  if (app->dir == 1)
2612  (*tc_excl)++;
2613  } else if (b->only_ts) {
2614  if (app->dir == 0)
2615  (*ts_excl)++;
2616  } else {
2617  bufdir[b->id].ts += (app->dir == 0);
2618  bufdir[b->id].tc += (app->dir == 1);
2619  }
2620 
2621  /* only allow rules to use the hook for engines at that
2622  * exact progress for now. */
2624  if ((s->flags & SIG_FLAG_TOSERVER) && (app->dir == 0) &&
2625  app->progress != s->init_data->hook.t.app.app_progress) {
2626  SCLogError("engine progress value %d doesn't match hook %u", app->progress,
2627  s->init_data->hook.t.app.app_progress);
2628  SCReturnInt(0);
2629  }
2630  if ((s->flags & SIG_FLAG_TOCLIENT) && (app->dir == 1) &&
2631  app->progress != s->init_data->hook.t.app.app_progress) {
2632  SCLogError("engine progress value doesn't match hook");
2633  SCReturnInt(0);
2634  }
2635  }
2636  }
2637  }
2638 
2640  SCReturnInt(0);
2641  }
2642 
2644  SCReturnInt(0);
2645  }
2647  SCReturnInt(0);
2648  }
2649  }
2650 
2651  if (has_pmatch && has_frame) {
2652  SCLogError("can't mix pure content and frame inspection");
2653  SCReturnInt(0);
2654  }
2655  if (has_app && has_frame) {
2656  SCLogError("can't mix app-layer buffer and frame inspection");
2657  SCReturnInt(0);
2658  }
2659  if (has_pkt && has_frame) {
2660  SCLogError("can't mix pkt buffer and frame inspection");
2661  SCReturnInt(0);
2662  }
2663 
2664  for (int x = 0; x < nlists; x++) {
2665  if (bufdir[x].ts == 0 && bufdir[x].tc == 0)
2666  continue;
2667  (*ts_excl) += (bufdir[x].ts > 0 && bufdir[x].tc == 0);
2668  (*tc_excl) += (bufdir[x].ts == 0 && bufdir[x].tc > 0);
2669  (*dir_amb) += (bufdir[x].ts > 0 && bufdir[x].tc > 0);
2670 
2671  SCLogDebug("%s/%d: %d/%d", DetectEngineBufferTypeGetNameById(de_ctx, x), x, bufdir[x].ts,
2672  bufdir[x].tc);
2673  }
2674 
2675  SCReturnInt(1);
2676 }
2677 
2678 static int SigValidatePacketStream(const Signature *s)
2679 {
2681  SCLogError("can't mix packet keywords with "
2682  "tcp-stream or flow:only_stream. Invalidating signature.");
2683  SCReturnInt(0);
2684  }
2685  SCReturnInt(1);
2686 }
2687 
2688 static int SigConsolidateDirection(
2689  Signature *s, const int ts_excl, const int tc_excl, const int dir_amb)
2690 {
2691  if (s->flags & SIG_FLAG_TXBOTHDIR) {
2692  if (!ts_excl || !tc_excl) {
2693  SCLogError("rule %u should use both directions, but does not", s->id);
2694  SCReturnInt(0);
2695  }
2696  if (dir_amb) {
2697  SCLogError("rule %u means to use both directions, cannot have keywords ambiguous about "
2698  "directions",
2699  s->id);
2700  SCReturnInt(0);
2701  }
2702  } else if (ts_excl && tc_excl) {
2703  SCLogError(
2704  "rule %u mixes keywords with conflicting directions, a transactional rule with => "
2705  "should be used",
2706  s->id);
2707  SCReturnInt(0);
2708  } else if (ts_excl) {
2709  SCLogDebug("%u: implied rule direction is toserver", s->id);
2711  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2712  SCReturnInt(0);
2713  }
2714  } else if (tc_excl) {
2715  SCLogDebug("%u: implied rule direction is toclient", s->id);
2717  SCLogError("rule %u mixes keywords with conflicting directions", s->id);
2718  SCReturnInt(0);
2719  }
2720  } else if (dir_amb) {
2721  SCLogDebug("%u: rule direction cannot be deduced from keywords", s->id);
2722  }
2723  SCReturnInt(1);
2724 }
2725 
2726 static void SigConsolidateTcpBuffer(Signature *s)
2727 {
2728  /* TCP: corner cases:
2729  * - pkt vs stream vs depth/offset
2730  * - pkt vs stream vs stream_size
2731  */
2732  if (s->proto.proto[IPPROTO_TCP / 8] & (1 << (IPPROTO_TCP % 8))) {
2736  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_PMATCH]; sm != NULL;
2737  sm = sm->next) {
2738  if (sm->type == DETECT_CONTENT &&
2739  (((DetectContentData *)(sm->ctx))->flags &
2742  break;
2743  }
2744  }
2745  /* if stream_size is in use, also inspect packets */
2746  for (const SigMatch *sm = s->init_data->smlists[DETECT_SM_LIST_MATCH]; sm != NULL;
2747  sm = sm->next) {
2748  if (sm->type == DETECT_STREAM_SIZE) {
2750  break;
2751  }
2752  }
2753  }
2754  }
2755  }
2756 }
2757 
2758 static bool SigInspectsFiles(const Signature *s)
2759 {
2760  return ((s->flags & SIG_FLAG_FILESTORE) || s->file_flags != 0 ||
2762 }
2763 
2764 /** \internal
2765  * \brief validate file handling
2766  * \retval 1 good signature
2767  * \retval 0 bad signature
2768  */
2769 static int SigValidateFileHandling(const Signature *s)
2770 {
2771  if (!SigInspectsFiles(s)) {
2772  SCReturnInt(1);
2773  }
2774 
2775  if (s->alproto != ALPROTO_UNKNOWN && !AppLayerParserSupportsFiles(IPPROTO_TCP, s->alproto) &&
2776  !AppLayerParserSupportsFiles(IPPROTO_UDP, s->alproto)) {
2777  SCLogError("protocol %s doesn't "
2778  "support file matching",
2780  SCReturnInt(0);
2781  }
2782  if (s->init_data->alprotos[0] != ALPROTO_UNKNOWN) {
2783  bool found = false;
2784  for (AppProto i = 0; i < SIG_ALPROTO_MAX; i++) {
2785  if (s->init_data->alprotos[i] == ALPROTO_UNKNOWN) {
2786  break;
2787  }
2788  if (AppLayerParserSupportsFiles(IPPROTO_TCP, s->init_data->alprotos[i]) ||
2789  AppLayerParserSupportsFiles(IPPROTO_UDP, s->init_data->alprotos[i])) {
2790  found = true;
2791  break;
2792  }
2793  }
2794  if (!found) {
2795  SCLogError("No protocol support file matching");
2796  SCReturnInt(0);
2797  }
2798  }
2800  SCLogError("protocol HTTP2 doesn't support file name matching");
2801  SCReturnInt(0);
2802  }
2803  SCReturnInt(1);
2804 }
2805 
2806 /**
2807  * \internal
2808  * \brief validate and consolidate parsed signature
2809  *
2810  * \param de_ctx detect engine
2811  * \param s signature to validate and consolidate
2812  *
2813  * \retval 0 invalid
2814  * \retval 1 valid
2815  */
2816 static int SigValidateConsolidate(
2817  DetectEngineCtx *de_ctx, Signature *s, const SignatureParser *parser, const uint8_t dir)
2818 {
2819  SCEnter();
2820 
2821  if (SigValidateFirewall(de_ctx, s) == 0)
2822  SCReturnInt(0);
2823 
2824  if (SigValidatePacketStream(s) == 0) {
2825  SCReturnInt(0);
2826  }
2827 
2828  int ts_excl = 0;
2829  int tc_excl = 0;
2830  int dir_amb = 0;
2831 
2832  if (SigValidateCheckBuffers(de_ctx, s, &ts_excl, &tc_excl, &dir_amb) == 0) {
2833  SCReturnInt(0);
2834  }
2835 
2836  if (SigConsolidateDirection(s, ts_excl, tc_excl, dir_amb) == 0) {
2837  SCReturnInt(0);
2838  }
2839 
2840  SigConsolidateTcpBuffer(s);
2841 
2843  DetectRuleSetTable(s);
2844 
2845  int r = SigValidateFileHandling(s);
2846  if (r == 0) {
2847  SCReturnInt(0);
2848  }
2849  if (SigInspectsFiles(s)) {
2850  if (s->alproto == ALPROTO_HTTP1 || s->alproto == ALPROTO_HTTP) {
2852  }
2853  }
2854  if (DetectRuleValidateTable(s) == false) {
2855  SCReturnInt(0);
2856  }
2857 
2858  if (s->type == SIG_TYPE_IPONLY) {
2859  /* For IPOnly */
2860  if (IPOnlySigParseAddress(de_ctx, s, parser->src, SIG_DIREC_SRC ^ dir) < 0)
2861  SCReturnInt(0);
2862 
2863  if (IPOnlySigParseAddress(de_ctx, s, parser->dst, SIG_DIREC_DST ^ dir) < 0)
2864  SCReturnInt(0);
2865  }
2866  SCReturnInt(1);
2867 }
2868 
2869 /**
2870  * \internal
2871  * \brief Helper function for SigInit().
2872  */
2873 static Signature *SigInitHelper(
2874  DetectEngineCtx *de_ctx, const char *sigstr, uint8_t dir, const bool firewall_rule)
2875 {
2876  SignatureParser parser;
2877  memset(&parser, 0x00, sizeof(parser));
2878 
2879  Signature *sig = SigAlloc();
2880  if (sig == NULL)
2881  goto error;
2882  if (firewall_rule) {
2883  sig->init_data->firewall_rule = true;
2884  sig->flags |= SIG_FLAG_FIREWALL;
2885  }
2886 
2887  sig->sig_str = SCStrdup(sigstr);
2888  if (unlikely(sig->sig_str == NULL)) {
2889  goto error;
2890  }
2891 
2892  /* default gid to 1 */
2893  sig->gid = 1;
2894 
2895  /* We do a first parse of the rule in a requires, or scan-only
2896  * mode. Syntactic errors will be picked up here, but the only
2897  * part of the rule that is validated completely is the "requires"
2898  * keyword. */
2899  int ret = SigParse(de_ctx, sig, sigstr, dir, &parser, true);
2900  if (ret == -4) {
2901  /* Rule requirements not met. */
2902  de_ctx->sigerror_silent = true;
2903  de_ctx->sigerror_ok = true;
2904  de_ctx->sigerror_requires = true;
2905  goto error;
2906  } else if (ret < 0) {
2907  goto error;
2908  }
2909 
2910  /* Check for a SID before continuuing. */
2911  if (sig->id == 0) {
2912  SCLogError("Signature missing required value \"sid\".");
2913  goto error;
2914  }
2915 
2916  /* Now completely parse the rule. */
2917  ret = SigParse(de_ctx, sig, sigstr, dir, &parser, false);
2918  BUG_ON(ret == -4);
2919  if (ret == -3) {
2920  de_ctx->sigerror_silent = true;
2921  de_ctx->sigerror_ok = true;
2922  goto error;
2923  } else if (ret == -2) {
2924  de_ctx->sigerror_silent = true;
2925  goto error;
2926  } else if (ret < 0) {
2927  goto error;
2928  }
2929 
2930  /* signature priority hasn't been overwritten. Using default priority */
2931  if (sig->prio == -1)
2932  sig->prio = DETECT_DEFAULT_PRIO;
2933 
2934  sig->iid = de_ctx->signum;
2935  de_ctx->signum++;
2936 
2937  if (sig->alproto != ALPROTO_UNKNOWN) {
2938  int override_needed = 0;
2939  if (sig->proto.flags & DETECT_PROTO_ANY) {
2940  sig->proto.flags &= ~DETECT_PROTO_ANY;
2941  memset(sig->proto.proto, 0x00, sizeof(sig->proto.proto));
2942  override_needed = 1;
2943  } else {
2944  override_needed = 1;
2945  size_t s = 0;
2946  for (s = 0; s < sizeof(sig->proto.proto); s++) {
2947  if (sig->proto.proto[s] != 0x00) {
2948  override_needed = 0;
2949  break;
2950  }
2951  }
2952  }
2953 
2954  /* at this point if we had alert ip and the ip proto was not
2955  * overridden, we use the ip proto that has been configured
2956  * against the app proto in use. */
2957  if (override_needed)
2959  }
2960 
2961  /* set the packet and app layer flags, but only if the
2962  * app layer flag wasn't already set in which case we
2963  * only consider the app layer */
2964  if (!(sig->flags & SIG_FLAG_APPLAYER)) {
2965  if (sig->init_data->smlists[DETECT_SM_LIST_MATCH] != NULL) {
2967  for ( ; sm != NULL; sm = sm->next) {
2968  if (sigmatch_table[sm->type].Match != NULL)
2970  }
2971  } else {
2973  }
2974  }
2975 
2976  if (sig->init_data->hook.type == SIGNATURE_HOOK_TYPE_PKT) {
2977  if (sig->init_data->hook.t.pkt.ph == SIGNATURE_HOOK_PKT_FLOW_START) {
2978  if ((sig->flags & SIG_FLAG_TOSERVER) != 0) {
2980  }
2981  }
2982  }
2983 
2984  if (!(sig->init_data->init_flags & SIG_FLAG_INIT_FLOW)) {
2985  if ((sig->flags & (SIG_FLAG_TOSERVER|SIG_FLAG_TOCLIENT)) == 0) {
2986  sig->flags |= SIG_FLAG_TOSERVER;
2987  sig->flags |= SIG_FLAG_TOCLIENT;
2988  }
2989  }
2990 
2991  SCLogDebug("sig %"PRIu32" SIG_FLAG_APPLAYER: %s, SIG_FLAG_PACKET: %s",
2992  sig->id, sig->flags & SIG_FLAG_APPLAYER ? "set" : "not set",
2993  sig->init_data->init_flags & SIG_FLAG_INIT_PACKET ? "set" : "not set");
2994 
2995  SigBuildAddressMatchArray(sig);
2996 
2997  /* run buffer type callbacks if any */
2998  for (uint32_t x = 0; x < DETECT_SM_LIST_MAX; x++) {
2999  if (sig->init_data->smlists[x])
3001  }
3002  for (uint32_t x = 0; x < sig->init_data->buffer_index; x++) {
3004  }
3005 
3006  SigSetupPrefilter(de_ctx, sig);
3007 
3008  /* validate signature, SigValidate will report the error reason */
3009  if (SigValidateConsolidate(de_ctx, sig, &parser, dir) == 0) {
3010  goto error;
3011  }
3012 
3013  return sig;
3014 
3015 error:
3016  if (sig != NULL) {
3017  SigFree(de_ctx, sig);
3018  }
3019  return NULL;
3020 }
3021 
3022 /**
3023  * \brief Checks if a signature has the same source and destination
3024  * \param s parsed signature
3025  *
3026  * \retval true if source and destination are the same, false otherwise
3027  */
3028 static bool SigHasSameSourceAndDestination(const Signature *s)
3029 {
3030  if (!(s->flags & SIG_FLAG_SP_ANY) || !(s->flags & SIG_FLAG_DP_ANY)) {
3031  if (!DetectPortListsAreEqual(s->sp, s->dp)) {
3032  return false;
3033  }
3034  }
3035 
3036  if (!(s->flags & SIG_FLAG_SRC_ANY) || !(s->flags & SIG_FLAG_DST_ANY)) {
3039 
3041  return false;
3042  }
3043 
3044  src = s->init_data->src->ipv6_head;
3045  dst = s->init_data->dst->ipv6_head;
3046 
3048  return false;
3049  }
3050  }
3051 
3052  return true;
3053 }
3054 
3055 static Signature *SigInitDo(DetectEngineCtx *de_ctx, const char *sigstr, const bool firewall_rule)
3056 {
3057  SCEnter();
3058 
3059  uint32_t oldsignum = de_ctx->signum;
3060  de_ctx->sigerror_ok = false;
3061  de_ctx->sigerror_silent = false;
3062  de_ctx->sigerror_requires = false;
3063 
3064  Signature *sig = SigInitHelper(de_ctx, sigstr, SIG_DIREC_NORMAL, firewall_rule);
3065  if (sig == NULL) {
3066  goto error;
3067  }
3068 
3070  if (SigHasSameSourceAndDestination(sig)) {
3071  SCLogInfo("Rule with ID %u is bidirectional, but source and destination are the same, "
3072  "treating the rule as unidirectional", sig->id);
3073 
3075  } else {
3076  sig->next = SigInitHelper(de_ctx, sigstr, SIG_DIREC_SWITCHED, firewall_rule);
3077  if (sig->next == NULL) {
3078  goto error;
3079  }
3080  }
3081  }
3082 
3083  SCReturnPtr(sig, "Signature");
3084 
3085 error:
3086  if (sig != NULL) {
3087  SigFree(de_ctx, sig);
3088  }
3089  /* if something failed, restore the old signum count
3090  * since we didn't install it */
3091  de_ctx->signum = oldsignum;
3092 
3093  SCReturnPtr(NULL, "Signature");
3094 }
3095 
3096 /**
3097  * \brief Parses a signature and adds it to the Detection Engine Context.
3098  *
3099  * \param de_ctx Pointer to the Detection Engine Context.
3100  * \param sigstr Pointer to a character string containing the signature to be
3101  * parsed.
3102  *
3103  * \retval Pointer to the Signature instance on success; NULL on failure.
3104  */
3105 Signature *SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
3106 {
3107  return SigInitDo(de_ctx, sigstr, false);
3108 }
3109 
3110 static Signature *DetectFirewallRuleNew(DetectEngineCtx *de_ctx, const char *sigstr)
3111 {
3112  return SigInitDo(de_ctx, sigstr, true);
3113 }
3114 
3115 /**
3116  * \brief The hash free function to be the used by the hash table -
3117  * DetectEngineCtx->dup_sig_hash_table.
3118  *
3119  * \param data Pointer to the data, in our case SigDuplWrapper to be freed.
3120  */
3121 static void DetectParseDupSigFreeFunc(void *data)
3122 {
3123  if (data != NULL)
3124  SCFree(data);
3125 }
3126 
3127 /**
3128  * \brief The hash function to be the used by the hash table -
3129  * DetectEngineCtx->dup_sig_hash_table.
3130  *
3131  * \param ht Pointer to the hash table.
3132  * \param data Pointer to the data, in our case SigDuplWrapper.
3133  * \param datalen Not used in our case.
3134  *
3135  * \retval sw->s->id The generated hash value.
3136  */
3137 static uint32_t DetectParseDupSigHashFunc(HashListTable *ht, void *data, uint16_t datalen)
3138 {
3139  SigDuplWrapper *sw = (SigDuplWrapper *)data;
3140 
3141  return (sw->s->id % ht->array_size);
3142 }
3143 
3144 /**
3145  * \brief The Compare function to be used by the hash table -
3146  * DetectEngineCtx->dup_sig_hash_table.
3147  *
3148  * \param data1 Pointer to the first SigDuplWrapper.
3149  * \param len1 Not used.
3150  * \param data2 Pointer to the second SigDuplWrapper.
3151  * \param len2 Not used.
3152  *
3153  * \retval 1 If the 2 SigDuplWrappers sent as args match.
3154  * \retval 0 If the 2 SigDuplWrappers sent as args do not match.
3155  */
3156 static char DetectParseDupSigCompareFunc(void *data1, uint16_t len1, void *data2,
3157  uint16_t len2)
3158 {
3159  SigDuplWrapper *sw1 = (SigDuplWrapper *)data1;
3160  SigDuplWrapper *sw2 = (SigDuplWrapper *)data2;
3161 
3162  if (sw1 == NULL || sw2 == NULL ||
3163  sw1->s == NULL || sw2->s == NULL)
3164  return 0;
3165 
3166  /* sid and gid match required */
3167  if (sw1->s->id == sw2->s->id && sw1->s->gid == sw2->s->gid) return 1;
3168 
3169  return 0;
3170 }
3171 
3172 /**
3173  * \brief Initializes the hash table that is used to cull duplicate sigs.
3174  *
3175  * \param de_ctx Pointer to the detection engine context.
3176  *
3177  * \retval 0 On success.
3178  * \retval -1 On failure.
3179  */
3181 {
3183  DetectParseDupSigHashFunc,
3184  DetectParseDupSigCompareFunc,
3185  DetectParseDupSigFreeFunc);
3186  if (de_ctx->dup_sig_hash_table == NULL)
3187  return -1;
3188 
3189  return 0;
3190 }
3191 
3192 /**
3193  * \brief Frees the hash table that is used to cull duplicate sigs.
3194  *
3195  * \param de_ctx Pointer to the detection engine context that holds this table.
3196  */
3198 {
3199  if (de_ctx->dup_sig_hash_table != NULL)
3201 
3202  de_ctx->dup_sig_hash_table = NULL;
3203 }
3204 
3205 /**
3206  * \brief Check if a signature is a duplicate.
3207  *
3208  * There are 3 types of return values for this function.
3209  *
3210  * - 0, which indicates that the Signature is not a duplicate
3211  * and has to be added to the detection engine list.
3212  * - 1, Signature is duplicate, and the existing signature in
3213  * the list shouldn't be replaced with this duplicate.
3214  * - 2, Signature is duplicate, and the existing signature in
3215  * the list should be replaced with this duplicate.
3216  *
3217  * \param de_ctx Pointer to the detection engine context.
3218  * \param sig Pointer to the Signature that has to be checked.
3219  *
3220  * \retval 2 If Signature is duplicate and the existing signature in
3221  * the list should be chucked out and replaced with this.
3222  * \retval 1 If Signature is duplicate, and should be chucked out.
3223  * \retval 0 If Signature is not a duplicate.
3224  */
3225 static inline int DetectEngineSignatureIsDuplicate(DetectEngineCtx *de_ctx,
3226  Signature *sig)
3227 {
3228  /* we won't do any NULL checks on the args */
3229 
3230  /* return value */
3231  int ret = 0;
3232 
3233  SigDuplWrapper *sw_dup = NULL;
3234  SigDuplWrapper *sw = NULL;
3235 
3236  /* used for making a duplicate_sig_hash_table entry */
3237  sw = SCCalloc(1, sizeof(SigDuplWrapper));
3238  if (unlikely(sw == NULL)) {
3239  exit(EXIT_FAILURE);
3240  }
3241  sw->s = sig;
3242 
3243  /* check if we have a duplicate entry for this signature */
3244  sw_dup = HashListTableLookup(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3245  /* we don't have a duplicate entry for this sig */
3246  if (sw_dup == NULL) {
3247  /* add it to the hash table */
3248  HashListTableAdd(de_ctx->dup_sig_hash_table, (void *)sw, 0);
3249 
3250  /* add the s_prev entry for the previously loaded sw in the hash_table */
3251  if (de_ctx->sig_list != NULL) {
3252  SigDuplWrapper *sw_old = NULL;
3253  SigDuplWrapper sw_tmp;
3254  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3255 
3256  /* the topmost sig would be the last loaded sig */
3257  sw_tmp.s = de_ctx->sig_list;
3259  (void *)&sw_tmp, 0);
3260  /* sw_old == NULL case is impossible */
3261  sw_old->s_prev = sig;
3262  }
3263 
3264  ret = 0;
3265  goto end;
3266  }
3267 
3268  /* if we have reached here we have a duplicate entry for this signature.
3269  * Check the signature revision. Store the signature with the latest rev
3270  * and discard the other one */
3271  if (sw->s->rev <= sw_dup->s->rev) {
3272  ret = 1;
3273  SCFree(sw);
3274  sw = NULL;
3275  goto end;
3276  }
3277 
3278  /* the new sig is of a newer revision than the one that is already in the
3279  * list. Remove the old sig from the list */
3280  if (sw_dup->s_prev == NULL) {
3281  SigDuplWrapper sw_temp;
3282  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3283  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3284  sw_temp.s = sw_dup->s->next->next;
3285  de_ctx->sig_list = sw_dup->s->next->next;
3286  SigFree(de_ctx, sw_dup->s->next);
3287  } else {
3288  sw_temp.s = sw_dup->s->next;
3289  de_ctx->sig_list = sw_dup->s->next;
3290  }
3291  SigDuplWrapper *sw_next = NULL;
3292  if (sw_temp.s != NULL) {
3294  (void *)&sw_temp, 0);
3295  sw_next->s_prev = sw_dup->s_prev;
3296  }
3297  SigFree(de_ctx, sw_dup->s);
3298  } else {
3299  SigDuplWrapper sw_temp;
3300  memset(&sw_temp, 0, sizeof(SigDuplWrapper));
3301  if (sw_dup->s->init_data->init_flags & SIG_FLAG_INIT_BIDIREC) {
3302  sw_temp.s = sw_dup->s->next->next;
3303  /* If previous signature is bidirectional,
3304  * it has 2 items in the linked list.
3305  * So we need to change next->next instead of next
3306  */
3308  sw_dup->s_prev->next->next = sw_dup->s->next->next;
3309  } else {
3310  sw_dup->s_prev->next = sw_dup->s->next->next;
3311  }
3312  SigFree(de_ctx, sw_dup->s->next);
3313  } else {
3314  sw_temp.s = sw_dup->s->next;
3316  sw_dup->s_prev->next->next = sw_dup->s->next;
3317  } else {
3318  sw_dup->s_prev->next = sw_dup->s->next;
3319  }
3320  }
3321  SigDuplWrapper *sw_next = NULL;
3322  if (sw_temp.s != NULL) {
3324  (void *)&sw_temp, 0);
3325  sw_next->s_prev = sw_dup->s_prev;
3326  }
3327  SigFree(de_ctx, sw_dup->s);
3328  }
3329 
3330  /* make changes to the entry to reflect the presence of the new sig */
3331  sw_dup->s = sig;
3332  sw_dup->s_prev = NULL;
3333 
3334  if (de_ctx->sig_list != NULL) {
3335  SigDuplWrapper sw_tmp;
3336  memset(&sw_tmp, 0, sizeof(SigDuplWrapper));
3337  sw_tmp.s = de_ctx->sig_list;
3339  (void *)&sw_tmp, 0);
3340  if (sw_old->s != sw_dup->s) {
3341  // Link on top of the list if there was another element
3342  sw_old->s_prev = sig;
3343  }
3344  }
3345 
3346  /* this is duplicate, but a duplicate that replaced the existing sig entry */
3347  ret = 2;
3348 
3349  SCFree(sw);
3350 
3351 end:
3352  return ret;
3353 }
3354 
3355 /**
3356  * \brief Parse and append a Signature into the Detection Engine Context
3357  * signature list.
3358  *
3359  * If the signature is bidirectional it should append two signatures
3360  * (with the addresses switched) into the list. Also handle duplicate
3361  * signatures. In case of duplicate sigs, use the ones that have the
3362  * latest revision. We use the sid and the msg to identify duplicate
3363  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3364  *
3365  * \param de_ctx Pointer to the Detection Engine Context.
3366  * \param sigstr Pointer to a character string containing the signature to be
3367  * parsed.
3368  * \param sig_file Pointer to a character string containing the filename from
3369  * which signature is read
3370  * \param lineno Line number from where signature is read
3371  *
3372  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3373  * on success; NULL on failure.
3374  */
3376 {
3377  Signature *sig = DetectFirewallRuleNew(de_ctx, sigstr);
3378  if (sig == NULL) {
3379  return NULL;
3380  }
3381 
3382  /* checking for the status of duplicate signature */
3383  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3384  /* a duplicate signature that should be chucked out. Check the previously
3385  * called function details to understand the different return values */
3386  if (dup_sig == 1) {
3387  SCLogError("Duplicate signature \"%s\"", sigstr);
3388  goto error;
3389  } else if (dup_sig == 2) {
3390  SCLogWarning("Signature with newer revision,"
3391  " so the older sig replaced by this new signature \"%s\"",
3392  sigstr);
3393  }
3394 
3396  if (sig->next != NULL) {
3397  sig->next->next = de_ctx->sig_list;
3398  } else {
3399  goto error;
3400  }
3401  } else {
3402  /* if this sig is the first one, sig_list should be null */
3403  sig->next = de_ctx->sig_list;
3404  }
3405 
3406  de_ctx->sig_list = sig;
3407 
3408  /**
3409  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3410  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3411  * to the cloned signatures with the switched addresses
3412  */
3413  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3414 
3415 error:
3416  /* free the 2nd sig bidir may have set up */
3417  if (sig != NULL && sig->next != NULL) {
3418  SigFree(de_ctx, sig->next);
3419  sig->next = NULL;
3420  }
3421  if (sig != NULL) {
3422  SigFree(de_ctx, sig);
3423  }
3424  return NULL;
3425 }
3426 
3427 /**
3428  * \brief Parse and append a Signature into the Detection Engine Context
3429  * signature list.
3430  *
3431  * If the signature is bidirectional it should append two signatures
3432  * (with the addresses switched) into the list. Also handle duplicate
3433  * signatures. In case of duplicate sigs, use the ones that have the
3434  * latest revision. We use the sid and the msg to identify duplicate
3435  * sigs. If 2 sigs have the same sid and gid, they are duplicates.
3436  *
3437  * \param de_ctx Pointer to the Detection Engine Context.
3438  * \param sigstr Pointer to a character string containing the signature to be
3439  * parsed.
3440  * \param sig_file Pointer to a character string containing the filename from
3441  * which signature is read
3442  * \param lineno Line number from where signature is read
3443  *
3444  * \retval Pointer to the head Signature in the detection engine ctx sig_list
3445  * on success; NULL on failure.
3446  */
3448 {
3449  Signature *sig = SigInit(de_ctx, sigstr);
3450  if (sig == NULL) {
3451  return NULL;
3452  }
3453 
3454  /* checking for the status of duplicate signature */
3455  int dup_sig = DetectEngineSignatureIsDuplicate(de_ctx, sig);
3456  /* a duplicate signature that should be chucked out. Check the previously
3457  * called function details to understand the different return values */
3458  if (dup_sig == 1) {
3459  SCLogError("Duplicate signature \"%s\"", sigstr);
3460  goto error;
3461  } else if (dup_sig == 2) {
3462  SCLogWarning("Signature with newer revision,"
3463  " so the older sig replaced by this new signature \"%s\"",
3464  sigstr);
3465  }
3466 
3468  if (sig->next != NULL) {
3469  sig->next->next = de_ctx->sig_list;
3470  } else {
3471  goto error;
3472  }
3473  } else {
3474  /* if this sig is the first one, sig_list should be null */
3475  sig->next = de_ctx->sig_list;
3476  }
3477 
3478  de_ctx->sig_list = sig;
3479 
3480  /**
3481  * In DetectEngineAppendSig(), the signatures are prepended and we always return the first one
3482  * so if the signature is bidirectional, the returned sig will point through "next" ptr
3483  * to the cloned signatures with the switched addresses
3484  */
3485  return (dup_sig == 0 || dup_sig == 2) ? sig : NULL;
3486 
3487 error:
3488  /* free the 2nd sig bidir may have set up */
3489  if (sig != NULL && sig->next != NULL) {
3490  SigFree(de_ctx, sig->next);
3491  sig->next = NULL;
3492  }
3493  if (sig != NULL) {
3494  SigFree(de_ctx, sig);
3495  }
3496  return NULL;
3497 }
3498 
3499 static DetectParseRegex *g_detect_parse_regex_list = NULL;
3500 
3501 int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str,
3502  int start_offset, int options)
3503 {
3504  *match = pcre2_match_data_create_from_pattern(parse_regex->regex, NULL);
3505  if (*match)
3506  return pcre2_match(parse_regex->regex, (PCRE2_SPTR8)str, strlen(str), options, start_offset,
3507  *match, parse_regex->context);
3508  return -1;
3509 }
3510 
3512 {
3513  if (r->regex) {
3514  pcre2_code_free(r->regex);
3515  }
3516  if (r->context) {
3517  pcre2_match_context_free(r->context);
3518  }
3519 }
3520 
3522 {
3523  DetectParseRegex *r = g_detect_parse_regex_list;
3524  while (r) {
3525  DetectParseRegex *next = r->next;
3526 
3528 
3529  SCFree(r);
3530  r = next;
3531  }
3532  g_detect_parse_regex_list = NULL;
3533 }
3534 
3535 /** \brief add regex and/or study to at exit free list
3536  */
3538 {
3539  DetectParseRegex *r = SCCalloc(1, sizeof(*r));
3540  if (r == NULL) {
3541  FatalError("failed to alloc memory for pcre free list");
3542  }
3543  r->regex = detect_parse->regex;
3544  r->next = g_detect_parse_regex_list;
3545  g_detect_parse_regex_list = r;
3546 }
3547 
3548 bool DetectSetupParseRegexesOpts(const char *parse_str, DetectParseRegex *detect_parse, int opts)
3549 {
3550  int en;
3551  PCRE2_SIZE eo;
3552 
3553  detect_parse->regex =
3554  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3555  if (detect_parse->regex == NULL) {
3556  PCRE2_UCHAR errbuffer[256];
3557  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3558  SCLogError("pcre compile of \"%s\" failed at "
3559  "offset %d: %s",
3560  parse_str, en, errbuffer);
3561  return false;
3562  }
3563  detect_parse->context = pcre2_match_context_create(NULL);
3564  if (detect_parse->context == NULL) {
3565  SCLogError("pcre2 could not create match context");
3566  pcre2_code_free(detect_parse->regex);
3567  detect_parse->regex = NULL;
3568  return false;
3569  }
3570  pcre2_set_match_limit(detect_parse->context, SC_MATCH_LIMIT_DEFAULT);
3571  pcre2_set_recursion_limit(detect_parse->context, SC_MATCH_LIMIT_RECURSION_DEFAULT);
3572  DetectParseRegexAddToFreeList(detect_parse);
3573 
3574  return true;
3575 }
3576 
3577 DetectParseRegex *DetectSetupPCRE2(const char *parse_str, int opts)
3578 {
3579  int en;
3580  PCRE2_SIZE eo;
3581  DetectParseRegex *detect_parse = SCCalloc(1, sizeof(DetectParseRegex));
3582  if (detect_parse == NULL) {
3583  return NULL;
3584  }
3585 
3586  detect_parse->regex =
3587  pcre2_compile((PCRE2_SPTR8)parse_str, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
3588  if (detect_parse->regex == NULL) {
3589  PCRE2_UCHAR errbuffer[256];
3590  pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
3591  SCLogError("pcre2 compile of \"%s\" failed at "
3592  "offset %d: %s",
3593  parse_str, (int)eo, errbuffer);
3594  SCFree(detect_parse);
3595  return NULL;
3596  }
3597 
3598  detect_parse->next = g_detect_parse_regex_list;
3599  g_detect_parse_regex_list = detect_parse;
3600  return detect_parse;
3601 }
3602 
3604  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
3605 {
3606  int r = pcre2_substring_copy_bynumber(match_data, number, buffer, bufflen);
3607  if (r == PCRE2_ERROR_UNSET) {
3608  buffer[0] = 0;
3609  *bufflen = 0;
3610  return 0;
3611  }
3612  return r;
3613 }
3614 
3616  pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR **bufferptr, PCRE2_SIZE *bufflen)
3617 {
3618  int r = pcre2_substring_get_bynumber(match_data, number, bufferptr, bufflen);
3619  if (r == PCRE2_ERROR_UNSET) {
3620  *bufferptr = NULL;
3621  *bufflen = 0;
3622  return 0;
3623  }
3624  return r;
3625 }
3626 
3627 void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
3628 {
3629  if (!DetectSetupParseRegexesOpts(parse_str, detect_parse, 0)) {
3630  FatalError("pcre compile and study failed");
3631  }
3632 }
3633 
3634 /*
3635  * TESTS
3636  */
3637 
3638 #ifdef UNITTESTS
3639 #include "detect-engine-alert.h"
3640 #include "packet.h"
3641 
3642 static int SigParseTest01 (void)
3643 {
3644  int result = 1;
3645  Signature *sig = NULL;
3646 
3648  if (de_ctx == NULL)
3649  goto end;
3650 
3651  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
3652  if (sig == NULL)
3653  result = 0;
3654 
3655 end:
3656  if (sig != NULL) SigFree(de_ctx, sig);
3657  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3658  return result;
3659 }
3660 
3661 static int SigParseTest02 (void)
3662 {
3663  int result = 0;
3664  Signature *sig = NULL;
3665  DetectPort *port = NULL;
3666 
3668 
3669  if (de_ctx == NULL)
3670  goto end;
3671 
3675 
3676  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;)");
3677  if (sig == NULL) {
3678  goto end;
3679  }
3680 
3681  int r = DetectPortParse(de_ctx, &port, "0:20");
3682  if (r < 0)
3683  goto end;
3684 
3685  if (DetectPortCmp(sig->sp, port) == PORT_EQ) {
3686  result = 1;
3687  } else {
3688  DetectPortPrint(port); printf(" != "); DetectPortPrint(sig->sp); printf(": ");
3689  }
3690 
3691 end:
3692  if (port != NULL)
3694  if (sig != NULL)
3695  SigFree(de_ctx, sig);
3696  if (de_ctx != NULL)
3698  return result;
3699 }
3700 
3701 /**
3702  * \test SigParseTest03 test for invalid direction operator in rule
3703  */
3704 static int SigParseTest03 (void)
3705 {
3706  int result = 1;
3707  Signature *sig = NULL;
3708 
3710  if (de_ctx == NULL)
3711  goto end;
3712 
3713  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 any <- !1.2.3.4 any (msg:\"SigParseTest03\"; sid:1;)");
3714  if (sig != NULL) {
3715  result = 0;
3716  printf("expected NULL got sig ptr %p: ",sig);
3717  }
3718 
3719 end:
3720  if (sig != NULL) SigFree(de_ctx, sig);
3721  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3722  return result;
3723 }
3724 
3725 static int SigParseTest04 (void)
3726 {
3727  int result = 1;
3728  Signature *sig = NULL;
3729 
3731  if (de_ctx == NULL)
3732  goto end;
3733 
3734  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024: -> !1.2.3.4 1024: (msg:\"SigParseTest04\"; sid:1;)");
3735  if (sig == NULL)
3736  result = 0;
3737 
3738 end:
3739  if (sig != NULL) SigFree(de_ctx, sig);
3740  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3741  return result;
3742 }
3743 
3744 /** \test Port validation */
3745 static int SigParseTest05 (void)
3746 {
3747  int result = 0;
3748  Signature *sig = NULL;
3749 
3751  if (de_ctx == NULL)
3752  goto end;
3753 
3754  sig = SigInit(de_ctx, "alert tcp 1.2.3.4 1024:65536 -> !1.2.3.4 any (msg:\"SigParseTest05\"; sid:1;)");
3755  if (sig == NULL) {
3756  result = 1;
3757  } else {
3758  printf("signature didn't fail to parse as we expected: ");
3759  }
3760 
3761 end:
3762  if (sig != NULL) SigFree(de_ctx, sig);
3763  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
3764  return result;
3765 }
3766 
3767 /** \test Parsing bug debugging at 2010-03-18 */
3768 static int SigParseTest06 (void)
3769 {
3770  int result = 0;
3771  Signature *sig = NULL;
3772 
3774  if (de_ctx == NULL)
3775  goto end;
3776 
3777  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;)");
3778  if (sig != NULL) {
3779  result = 1;
3780  } else {
3781  printf("signature failed to parse: ");
3782  }
3783 
3784 end:
3785  if (sig != NULL)
3786  SigFree(de_ctx, sig);
3787  if (de_ctx != NULL)
3789  return result;
3790 }
3791 
3792 /**
3793  * \test Parsing duplicate sigs.
3794  */
3795 static int SigParseTest07(void)
3796 {
3797  int result = 0;
3798 
3800  if (de_ctx == NULL)
3801  goto end;
3802 
3803  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3804  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3805 
3806  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL);
3807 
3808 end:
3809  if (de_ctx != NULL)
3811  return result;
3812 }
3813 
3814 /**
3815  * \test Parsing duplicate sigs.
3816  */
3817 static int SigParseTest08(void)
3818 {
3819  int result = 0;
3820 
3822  if (de_ctx == NULL)
3823  goto end;
3824 
3825  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3826  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3827 
3828  result = (de_ctx->sig_list != NULL && de_ctx->sig_list->next == NULL &&
3829  de_ctx->sig_list->rev == 2);
3830 
3831 end:
3832  if (de_ctx != NULL)
3834  return result;
3835 }
3836 
3837 /**
3838  * \test Parsing duplicate sigs.
3839  */
3840 static int SigParseTest09(void)
3841 {
3842  int result = 1;
3843 
3845  if (de_ctx == NULL)
3846  goto end;
3847 
3848  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3849  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:2;)");
3850  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:6;)");
3851  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:4;)");
3852  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3853  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3854  de_ctx->sig_list->rev == 2);
3855  if (result == 0)
3856  goto end;
3857  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3858  de_ctx->sig_list->next->rev == 6);
3859  if (result == 0)
3860  goto end;
3861 
3862  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3863  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3864  de_ctx->sig_list->rev == 2);
3865  if (result == 0)
3866  goto end;
3867  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3868  de_ctx->sig_list->next->rev == 6);
3869  if (result == 0)
3870  goto end;
3871 
3872  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:4;)");
3873  result &= (de_ctx->sig_list != NULL && de_ctx->sig_list->id == 2 &&
3874  de_ctx->sig_list->rev == 4);
3875  if (result == 0)
3876  goto end;
3877  result &= (de_ctx->sig_list->next != NULL && de_ctx->sig_list->next->id == 1 &&
3878  de_ctx->sig_list->next->rev == 6);
3879  if (result == 0)
3880  goto end;
3881 
3882 end:
3883  if (de_ctx != NULL)
3885  return result;
3886 }
3887 
3888 /**
3889  * \test Parsing duplicate sigs.
3890  */
3891 static int SigParseTest10(void)
3892 {
3893  int result = 1;
3894 
3896  if (de_ctx == NULL)
3897  goto end;
3898 
3899  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:1; rev:1;)");
3900  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:1;)");
3901  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:1;)");
3902  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:4; rev:1;)");
3903  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:5; rev:1;)");
3904  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:3; rev:2;)");
3905  DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (msg:\"boo\"; sid:2; rev:2;)");
3906 
3907  result &= ((de_ctx->sig_list->id == 2) &&
3908  (de_ctx->sig_list->next->id == 3) &&
3909  (de_ctx->sig_list->next->next->id == 5) &&
3910  (de_ctx->sig_list->next->next->next->id == 4) &&
3911  (de_ctx->sig_list->next->next->next->next->id == 1));
3912 
3913 end:
3914  if (de_ctx != NULL)
3916  return result;
3917 }
3918 
3919 /**
3920  * \test Parsing sig with trailing space(s) as reported by
3921  * Morgan Cox on oisf-users.
3922  */
3923 static int SigParseTest11(void)
3924 {
3925  int result = 0;
3926 
3928  if (de_ctx == NULL)
3929  goto end;
3930 
3931  Signature *s = NULL;
3932 
3934  "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking the http link\"; sid:1;) ");
3935  if (s == NULL) {
3936  printf("sig 1 didn't parse: ");
3937  goto end;
3938  }
3939 
3940  s = DetectEngineAppendSig(de_ctx, "drop tcp any any -> any 80 (msg:\"Snort_Inline is blocking "
3941  "the http link\"; sid:2;) ");
3942  if (s == NULL) {
3943  printf("sig 2 didn't parse: ");
3944  goto end;
3945  }
3946 
3947  result = 1;
3948 end:
3949  if (de_ctx != NULL)
3951  return result;
3952 }
3953 
3954 /**
3955  * \test file_data with rawbytes
3956  */
3957 static int SigParseTest12(void)
3958 {
3959  int result = 0;
3960 
3962  if (de_ctx == NULL)
3963  goto end;
3964 
3965  Signature *s = NULL;
3966 
3967  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (file_data; content:\"abc\"; rawbytes; sid:1;)");
3968  if (s != NULL) {
3969  printf("sig 1 should have given an error: ");
3970  goto end;
3971  }
3972 
3973  result = 1;
3974 end:
3975  if (de_ctx != NULL)
3977  return result;
3978 }
3979 
3980 /**
3981  * \test packet/stream sig
3982  */
3983 static int SigParseTest13(void)
3984 {
3985  int result = 0;
3986 
3988  if (de_ctx == NULL)
3989  goto end;
3990 
3991  Signature *s = NULL;
3992 
3993  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; sid:1;)");
3994  if (s == NULL) {
3995  printf("sig 1 invalidated: failure");
3996  goto end;
3997  }
3998 
3999  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4000  printf("sig doesn't have stream flag set\n");
4001  goto end;
4002  }
4003 
4004  if (s->flags & SIG_FLAG_REQUIRE_PACKET) {
4005  printf("sig has packet flag set\n");
4006  goto end;
4007  }
4008 
4009  result = 1;
4010 
4011 end:
4012  if (de_ctx != NULL)
4014  return result;
4015 }
4016 
4017 /**
4018  * \test packet/stream sig
4019  */
4020 static int SigParseTest14(void)
4021 {
4022  int result = 0;
4023 
4025  if (de_ctx == NULL)
4026  goto end;
4027 
4028  Signature *s = NULL;
4029 
4030  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; dsize:>0; sid:1;)");
4031  if (s == NULL) {
4032  printf("sig 1 invalidated: failure");
4033  goto end;
4034  }
4035 
4036  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4037  printf("sig doesn't have packet flag set\n");
4038  goto end;
4039  }
4040 
4041  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
4042  printf("sig has stream flag set\n");
4043  goto end;
4044  }
4045 
4046  result = 1;
4047 
4048 end:
4049  if (de_ctx != NULL)
4051  return result;
4052 }
4053 
4054 /**
4055  * \test packet/stream sig
4056  */
4057 static int SigParseTest15(void)
4058 {
4059  int result = 0;
4060 
4062  if (de_ctx == NULL)
4063  goto end;
4064 
4065  Signature *s = NULL;
4066 
4067  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:5; sid:1;)");
4068  if (s == NULL) {
4069  printf("sig 1 invalidated: failure");
4070  goto end;
4071  }
4072 
4073  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4074  printf("sig doesn't have packet flag set\n");
4075  goto end;
4076  }
4077 
4078  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4079  printf("sig doesn't have stream flag set\n");
4080  goto end;
4081  }
4082 
4083  result = 1;
4084 
4085 end:
4086  if (de_ctx != NULL)
4088  return result;
4089 }
4090 
4091 /**
4092  * \test packet/stream sig
4093  */
4094 static int SigParseTest16(void)
4095 {
4096  int result = 0;
4097 
4099  if (de_ctx == NULL)
4100  goto end;
4101 
4102  Signature *s = NULL;
4103 
4104  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; depth:5; sid:1;)");
4105  if (s == NULL) {
4106  printf("sig 1 invalidated: failure");
4107  goto end;
4108  }
4109 
4110  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4111  printf("sig doesn't have packet flag set\n");
4112  goto end;
4113  }
4114 
4115  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4116  printf("sig doesn't have stream flag set\n");
4117  goto end;
4118  }
4119 
4120  result = 1;
4121 
4122 end:
4123  if (de_ctx != NULL)
4125  return result;
4126 }
4127 
4128 /**
4129  * \test packet/stream sig
4130  */
4131 static int SigParseTest17(void)
4132 {
4133  int result = 0;
4134 
4136  if (de_ctx == NULL)
4137  goto end;
4138 
4139  Signature *s = NULL;
4140 
4141  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)");
4142  if (s == NULL) {
4143  printf("sig 1 invalidated: failure");
4144  goto end;
4145  }
4146 
4147  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET)) {
4148  printf("sig doesn't have packet flag set\n");
4149  goto end;
4150  }
4151 
4152  if (!(s->flags & SIG_FLAG_REQUIRE_STREAM)) {
4153  printf("sig doesn't have stream flag set\n");
4154  goto end;
4155  }
4156 
4157  result = 1;
4158 
4159 end:
4160  if (de_ctx != NULL)
4162  return result;
4163 }
4164 
4165 /** \test sid value too large. Bug #779 */
4166 static int SigParseTest18 (void)
4167 {
4168  int result = 0;
4169 
4171  if (de_ctx == NULL)
4172  goto end;
4173 
4174  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:99999999999999999999;)") != NULL)
4175  goto end;
4176 
4177  result = 1;
4178 end:
4179  if (de_ctx != NULL)
4181  return result;
4182 }
4183 
4184 /** \test gid value too large. Related to bug #779 */
4185 static int SigParseTest19 (void)
4186 {
4187  int result = 0;
4188 
4190  if (de_ctx == NULL)
4191  goto end;
4192 
4193  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; gid:99999999999999999999;)") != NULL)
4194  goto end;
4195 
4196  result = 1;
4197 end:
4198  if (de_ctx != NULL)
4200  return result;
4201 }
4202 
4203 /** \test rev value too large. Related to bug #779 */
4204 static int SigParseTest20 (void)
4205 {
4206  int result = 0;
4207 
4209  if (de_ctx == NULL)
4210  goto end;
4211 
4212  if (DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1; rev:99999999999999999999;)") != NULL)
4213  goto end;
4214 
4215  result = 1;
4216 end:
4217  if (de_ctx != NULL)
4219  return result;
4220 }
4221 
4222 /** \test address parsing */
4223 static int SigParseTest21 (void)
4224 {
4225  int result = 0;
4226 
4228  if (de_ctx == NULL)
4229  goto end;
4230 
4231  if (DetectEngineAppendSig(de_ctx, "alert tcp [1.2.3.4, 1.2.3.5] any -> !1.2.3.4 any (sid:1;)") == NULL)
4232  goto end;
4233 
4234  result = 1;
4235 end:
4236  if (de_ctx != NULL)
4238  return result;
4239 }
4240 
4241 /** \test address parsing */
4242 static int SigParseTest22 (void)
4243 {
4244  int result = 0;
4245 
4247  if (de_ctx == NULL)
4248  goto end;
4249 
4250  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)
4251  goto end;
4252 
4253  result = 1;
4254 end:
4255  if (de_ctx != NULL)
4257  return result;
4258 }
4259 
4260 /**
4261  * \test rule ending in carriage return
4262  */
4263 static int SigParseTest23(void)
4264 {
4267 
4268  Signature *s = NULL;
4269 
4270  s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"abc\"; offset:1; depth:5; sid:1;)\r");
4271  FAIL_IF_NULL(s);
4272 
4274  PASS;
4275 }
4276 
4277 /** \test Direction operator validation (invalid) */
4278 static int SigParseBidirecTest06 (void)
4279 {
4280  int result = 1;
4281  Signature *sig = NULL;
4282 
4284  if (de_ctx == NULL)
4285  goto end;
4286 
4287  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any - 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4288  if (sig == NULL)
4289  result = 1;
4290 
4291 end:
4292  if (sig != NULL) SigFree(de_ctx, sig);
4293  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4294  return result;
4295 }
4296 
4297 /** \test Direction operator validation (invalid) */
4298 static int SigParseBidirecTest07 (void)
4299 {
4300  int result = 1;
4301  Signature *sig = NULL;
4302 
4304  if (de_ctx == NULL)
4305  goto end;
4306 
4307  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4308  if (sig == NULL)
4309  result = 1;
4310 
4311 end:
4312  if (sig != NULL) SigFree(de_ctx, sig);
4313  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4314  return result;
4315 }
4316 
4317 /** \test Direction operator validation (invalid) */
4318 static int SigParseBidirecTest08 (void)
4319 {
4320  int result = 1;
4321  Signature *sig = NULL;
4322 
4324  if (de_ctx == NULL)
4325  goto end;
4326 
4327  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any < 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4328  if (sig == NULL)
4329  result = 1;
4330 
4331 end:
4332  if (sig != NULL) SigFree(de_ctx, sig);
4333  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4334  return result;
4335 }
4336 
4337 /** \test Direction operator validation (invalid) */
4338 static int SigParseBidirecTest09 (void)
4339 {
4340  int result = 1;
4341  Signature *sig = NULL;
4342 
4344  if (de_ctx == NULL)
4345  goto end;
4346 
4347  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any > 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4348  if (sig == NULL)
4349  result = 1;
4350 
4351 end:
4352  if (sig != NULL) SigFree(de_ctx, sig);
4353  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4354  return result;
4355 }
4356 
4357 /** \test Direction operator validation (invalid) */
4358 static int SigParseBidirecTest10 (void)
4359 {
4360  int result = 1;
4361  Signature *sig = NULL;
4362 
4364  if (de_ctx == NULL)
4365  goto end;
4366 
4367  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4368  if (sig == NULL)
4369  result = 1;
4370 
4371 end:
4372  if (sig != NULL) SigFree(de_ctx, sig);
4373  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4374  return result;
4375 }
4376 
4377 /** \test Direction operator validation (invalid) */
4378 static int SigParseBidirecTest11 (void)
4379 {
4380  int result = 1;
4381  Signature *sig = NULL;
4382 
4384  if (de_ctx == NULL)
4385  goto end;
4386 
4387  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >- 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4388  if (sig == NULL)
4389  result = 1;
4390 
4391 end:
4392  if (sig != NULL) SigFree(de_ctx, sig);
4393  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4394  return result;
4395 }
4396 
4397 /** \test Direction operator validation (invalid) */
4398 static int SigParseBidirecTest12 (void)
4399 {
4400  int result = 1;
4401  Signature *sig = NULL;
4402 
4404  if (de_ctx == NULL)
4405  goto end;
4406 
4407  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any >< 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4408  if (sig == NULL)
4409  result = 1;
4410 
4411 end:
4412  if (sig != NULL) SigFree(de_ctx, sig);
4413  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4414  return result;
4415 }
4416 
4417 /** \test Direction operator validation (valid) */
4418 static int SigParseBidirecTest13 (void)
4419 {
4420  int result = 1;
4421  Signature *sig = NULL;
4422 
4424  if (de_ctx == NULL)
4425  goto end;
4426 
4427  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4428  if (sig != NULL)
4429  result = 1;
4430 
4431 end:
4432  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4433  return result;
4434 }
4435 
4436 /** \test Direction operator validation (valid) */
4437 static int SigParseBidirecTest14 (void)
4438 {
4439  int result = 1;
4440  Signature *sig = NULL;
4441 
4443  if (de_ctx == NULL)
4444  goto end;
4445 
4446  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> 192.168.1.5 any (msg:\"SigParseBidirecTest05\"; sid:1;)");
4447  if (sig != NULL)
4448  result = 1;
4449 
4450 end:
4451  if (de_ctx != NULL) DetectEngineCtxFree(de_ctx);
4452  return result;
4453 }
4454 
4455 /** \test Ensure that we don't set bidirectional in a
4456  * normal (one direction) Signature
4457  */
4458 static int SigTestBidirec01 (void)
4459 {
4460  Signature *sig = NULL;
4461  int result = 0;
4462 
4464  if (de_ctx == NULL)
4465  goto end;
4466 
4467  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 -> !1.2.3.4 any (msg:\"SigTestBidirec01\"; sid:1;)");
4468  if (sig == NULL)
4469  goto end;
4470  if (sig->next != NULL)
4471  goto end;
4473  goto end;
4474  if (de_ctx->signum != 1)
4475  goto end;
4476 
4477  result = 1;
4478 
4479 end:
4480  if (de_ctx != NULL) {
4484  }
4485  return result;
4486 }
4487 
4488 /** \test Ensure that we set a bidirectional Signature correctly */
4489 static int SigTestBidirec02 (void)
4490 {
4491  int result = 0;
4492  Signature *sig = NULL;
4493  Signature *copy = NULL;
4494 
4496  if (de_ctx == NULL)
4497  goto end;
4498 
4499  de_ctx->flags |= DE_QUIET;
4500 
4501  sig = DetectEngineAppendSig(de_ctx, "alert tcp 1.2.3.4 1024:65535 <> !1.2.3.4 any (msg:\"SigTestBidirec02\"; sid:1;)");
4502  if (sig == NULL)
4503  goto end;
4504  if (de_ctx->sig_list != sig)
4505  goto end;
4507  goto end;
4508  if (sig->next == NULL)
4509  goto end;
4510  if (de_ctx->signum != 2)
4511  goto end;
4512  copy = sig->next;
4513  if (copy->next != NULL)
4514  goto end;
4515  if (!(copy->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4516  goto end;
4517 
4518  result = 1;
4519 
4520 end:
4521  if (de_ctx != NULL) {
4525  }
4526 
4527  return result;
4528 }
4529 
4530 /** \test Ensure that we set a bidirectional Signature correctly
4531 * and we install it with the rest of the signatures, checking
4532 * also that it match with the correct addr directions
4533 */
4534 static int SigTestBidirec03 (void)
4535 {
4536  int result = 0;
4537  Signature *sig = NULL;
4538  Packet *p = NULL;
4539 
4541  if (de_ctx == NULL)
4542  goto end;
4543 
4544  de_ctx->flags |= DE_QUIET;
4545 
4546  const char *sigs[3];
4547  sigs[0] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)";
4548  sigs[1] = "alert tcp any any <> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)";
4549  sigs[2] = "alert tcp any any -> 192.168.1.1 any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)";
4550  UTHAppendSigs(de_ctx, sigs, 3);
4551 
4552  /* Checking that bidirectional rules are set correctly */
4553  sig = de_ctx->sig_list;
4554  if (sig == NULL)
4555  goto end;
4556  if (sig->next == NULL)
4557  goto end;
4558  if (sig->next->next == NULL)
4559  goto end;
4560  if (sig->next->next->next == NULL)
4561  goto end;
4562  if (sig->next->next->next->next != NULL)
4563  goto end;
4564  if (de_ctx->signum != 4)
4565  goto end;
4566 
4567  uint8_t rawpkt1_ether[] = {
4568  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4569  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4570  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4571  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4572  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4573  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4574  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4575  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4576  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4577  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4578  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4579  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4580  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4581  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4582  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4583  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4584  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4585  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4586  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4587  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4588  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4589  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4590  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4591  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4592  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4593  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4594  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4595  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4596  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4597  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4598  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4599  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4600  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4601  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4602  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4603  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4604  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4605  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4606  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4607  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4608  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4609  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4610  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4611  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4612  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4613  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4614  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4615  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4616  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4617  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4618  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4619  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4620  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4621  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4622  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4623 
4625  p = UTHBuildPacketFromEth(rawpkt1_ether, sizeof(rawpkt1_ether));
4626  if (p == NULL) {
4627  SCLogDebug("Error building packet");
4628  goto end;
4629  }
4630  UTHMatchPackets(de_ctx, &p, 1);
4631 
4632  uint32_t sids[3] = {1, 2, 3};
4633  uint32_t results[3] = {1, 1, 1};
4634  result = UTHCheckPacketMatchResults(p, sids, results, 1);
4635 
4636 end:
4637  if (p != NULL) {
4638  PacketFree(p);
4639  }
4641  FlowShutdown();
4642  return result;
4643 }
4644 
4645 /** \test Ensure that we set a bidirectional Signature correctly
4646 * and we install it with the rest of the signatures, checking
4647 * also that it match with the correct addr directions
4648 */
4649 static int SigTestBidirec04 (void)
4650 {
4651  int result = 0;
4652  Signature *sig = NULL;
4653  Packet *p = NULL;
4654 
4656  if (de_ctx == NULL)
4657  goto end;
4658 
4659  de_ctx->flags |= DE_QUIET;
4660 
4661  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 1\"; sid:1;)");
4662  if (sig == NULL)
4663  goto end;
4664  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any <> any any (msg:\"SigTestBidirec03 sid 2 bidirectional\"; sid:2;)");
4665  if (sig == NULL)
4666  goto end;
4667  if ( !(sig->init_data->init_flags & SIG_FLAG_INIT_BIDIREC))
4668  goto end;
4669  if (sig->next == NULL)
4670  goto end;
4671  if (sig->next->next == NULL)
4672  goto end;
4673  if (sig->next->next->next != NULL)
4674  goto end;
4675  if (de_ctx->signum != 3)
4676  goto end;
4677 
4678  sig = DetectEngineAppendSig(de_ctx, "alert tcp 192.168.1.1 any -> any any (msg:\"SigTestBidirec03 sid 3\"; sid:3;)");
4679  if (sig == NULL)
4680  goto end;
4681  if (sig->next == NULL)
4682  goto end;
4683  if (sig->next->next == NULL)
4684  goto end;
4685  if (sig->next->next->next == NULL)
4686  goto end;
4687  if (sig->next->next->next->next != NULL)
4688  goto end;
4689  if (de_ctx->signum != 4)
4690  goto end;
4691 
4692  uint8_t rawpkt1_ether[] = {
4693  0x00,0x50,0x56,0xea,0x00,0xbd,0x00,0x0c,
4694  0x29,0x40,0xc8,0xb5,0x08,0x00,0x45,0x00,
4695  0x01,0xa8,0xb9,0xbb,0x40,0x00,0x40,0x06,
4696  0xe0,0xbf,0xc0,0xa8,0x1c,0x83,0xc0,0xa8,
4697  0x01,0x01,0xb9,0x0a,0x00,0x50,0x6f,0xa2,
4698  0x92,0xed,0x7b,0xc1,0xd3,0x4d,0x50,0x18,
4699  0x16,0xd0,0xa0,0x6f,0x00,0x00,0x47,0x45,
4700  0x54,0x20,0x2f,0x20,0x48,0x54,0x54,0x50,
4701  0x2f,0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,
4702  0x73,0x74,0x3a,0x20,0x31,0x39,0x32,0x2e,
4703  0x31,0x36,0x38,0x2e,0x31,0x2e,0x31,0x0d,
4704  0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,
4705  0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
4706  0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,
4707  0x20,0x28,0x58,0x31,0x31,0x3b,0x20,0x55,
4708  0x3b,0x20,0x4c,0x69,0x6e,0x75,0x78,0x20,
4709  0x78,0x38,0x36,0x5f,0x36,0x34,0x3b,0x20,
4710  0x65,0x6e,0x2d,0x55,0x53,0x3b,0x20,0x72,
4711  0x76,0x3a,0x31,0x2e,0x39,0x2e,0x30,0x2e,
4712  0x31,0x34,0x29,0x20,0x47,0x65,0x63,0x6b,
4713  0x6f,0x2f,0x32,0x30,0x30,0x39,0x30,0x39,
4714  0x30,0x32,0x31,0x37,0x20,0x55,0x62,0x75,
4715  0x6e,0x74,0x75,0x2f,0x39,0x2e,0x30,0x34,
4716  0x20,0x28,0x6a,0x61,0x75,0x6e,0x74,0x79,
4717  0x29,0x20,0x46,0x69,0x72,0x65,0x66,0x6f,
4718  0x78,0x2f,0x33,0x2e,0x30,0x2e,0x31,0x34,
4719  0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,
4720  0x3a,0x20,0x74,0x65,0x78,0x74,0x2f,0x68,
4721  0x74,0x6d,0x6c,0x2c,0x61,0x70,0x70,0x6c,
4722  0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2f,
4723  0x78,0x68,0x74,0x6d,0x6c,0x2b,0x78,0x6d,
4724  0x6c,0x2c,0x61,0x70,0x70,0x6c,0x69,0x63,
4725  0x61,0x74,0x69,0x6f,0x6e,0x2f,0x78,0x6d,
4726  0x6c,0x3b,0x71,0x3d,0x30,0x2e,0x39,0x2c,
4727  0x2a,0x2f,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4728  0x38,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4729  0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,
4730  0x67,0x65,0x3a,0x20,0x65,0x6e,0x2d,0x75,
4731  0x73,0x2c,0x65,0x6e,0x3b,0x71,0x3d,0x30,
4732  0x2e,0x35,0x0d,0x0a,0x41,0x63,0x63,0x65,
4733  0x70,0x74,0x2d,0x45,0x6e,0x63,0x6f,0x64,
4734  0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,
4735  0x70,0x2c,0x64,0x65,0x66,0x6c,0x61,0x74,
4736  0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
4737  0x74,0x2d,0x43,0x68,0x61,0x72,0x73,0x65,
4738  0x74,0x3a,0x20,0x49,0x53,0x4f,0x2d,0x38,
4739  0x38,0x35,0x39,0x2d,0x31,0x2c,0x75,0x74,
4740  0x66,0x2d,0x38,0x3b,0x71,0x3d,0x30,0x2e,
4741  0x37,0x2c,0x2a,0x3b,0x71,0x3d,0x30,0x2e,
4742  0x37,0x0d,0x0a,0x4b,0x65,0x65,0x70,0x2d,
4743  0x41,0x6c,0x69,0x76,0x65,0x3a,0x20,0x33,
4744  0x30,0x30,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
4745  0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,
4746  0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
4747  0x76,0x65,0x0d,0x0a,0x0d,0x0a }; /* end rawpkt1_ether */
4748 
4749  p = PacketGetFromAlloc();
4750  if (unlikely(p == NULL))
4751  return 0;
4753  ThreadVars th_v;
4754  DetectEngineThreadCtx *det_ctx;
4755 
4756  memset(&th_v, 0, sizeof(th_v));
4757  StatsThreadInit(&th_v.stats);
4758 
4760  DecodeEthernet(&th_v, &dtv, p, rawpkt1_ether, sizeof(rawpkt1_ether));
4761  DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
4762 
4763  /* At this point we have a list of 4 signatures. The last one
4764  is a copy of the second one. If we receive a packet
4765  with source 192.168.1.1 80, all the sids should match */
4766 
4768  SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
4769 
4770  /* only sid 2 should match with a packet going to 192.168.1.1 port 80 */
4771  if (PacketAlertCheck(p, 1) <= 0 && PacketAlertCheck(p, 3) <= 0 &&
4772  PacketAlertCheck(p, 2) == 1) {
4773  result = 1;
4774  }
4775 
4776  if (p != NULL) {
4777  PacketRecycle(p);
4778  }
4779  FlowShutdown();
4780  DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
4781 
4782 end:
4783  if (de_ctx != NULL) {
4785  }
4786 
4787  if (p != NULL)
4788  PacketFree(p);
4789  StatsThreadCleanup(&th_v.stats);
4790  return result;
4791 }
4792 
4793 /**
4794  * \test check that we don't allow invalid negation options
4795  */
4796 static int SigParseTestNegation01 (void)
4797 {
4800  de_ctx->flags |= DE_QUIET;
4801  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp !any any -> any any (sid:1;)");
4802  FAIL_IF_NOT_NULL(s);
4804  PASS;
4805 }
4806 
4807 /**
4808  * \test check that we don't allow invalid negation options
4809  */
4810 static int SigParseTestNegation02 (void)
4811 {
4814  de_ctx->flags |= DE_QUIET;
4816  "alert tcp any !any -> any any (msg:\"SigTest41-02 src ip is !any \"; "
4817  "classtype:misc-activity; sid:410002; rev:1;)");
4818  FAIL_IF_NOT_NULL(s);
4820  PASS;
4821 }
4822 /**
4823  * \test check that we don't allow invalid negation options
4824  */
4825 static int SigParseTestNegation03 (void)
4826 {
4829  de_ctx->flags |= DE_QUIET;
4831  "alert tcp any any -> any [80:!80] (msg:\"SigTest41-03 dst port [80:!80] \"; "
4832  "classtype:misc-activity; sid:410003; rev:1;)");
4833  FAIL_IF_NOT_NULL(s);
4835  PASS;
4836 }
4837 /**
4838  * \test check that we don't allow invalid negation options
4839  */
4840 static int SigParseTestNegation04 (void)
4841 {
4842  int result = 0;
4844  Signature *s=NULL;
4845 
4847  if (de_ctx == NULL)
4848  goto end;
4849  de_ctx->flags |= DE_QUIET;
4850 
4851  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;)");
4852  if (s != NULL) {
4853  SigFree(de_ctx, s);
4854  goto end;
4855  }
4856 
4857  result = 1;
4858 end:
4859  if (de_ctx != NULL)
4861  return result;
4862 }
4863 /**
4864  * \test check that we don't allow invalid negation options
4865  */
4866 static int SigParseTestNegation05 (void)
4867 {
4868  int result = 0;
4870  Signature *s=NULL;
4871 
4873  if (de_ctx == NULL)
4874  goto end;
4875  de_ctx->flags |= DE_QUIET;
4876 
4877  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;)");
4878  if (s != NULL) {
4879  SigFree(de_ctx, s);
4880  goto end;
4881  }
4882 
4883  result = 1;
4884 end:
4885  if (de_ctx != NULL)
4887  return result;
4888 }
4889 /**
4890  * \test check that we don't allow invalid negation options
4891  */
4892 static int SigParseTestNegation06 (void)
4893 {
4894  int result = 0;
4896  Signature *s=NULL;
4897 
4899  if (de_ctx == NULL)
4900  goto end;
4901  de_ctx->flags |= DE_QUIET;
4902 
4903  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;)");
4904  if (s != NULL) {
4905  SigFree(de_ctx, s);
4906  goto end;
4907  }
4908 
4909  result = 1;
4910 end:
4911  if (de_ctx != NULL)
4913  return result;
4914 }
4915 
4916 /**
4917  * \test check that we don't allow invalid negation options
4918  */
4919 static int SigParseTestNegation07 (void)
4920 {
4923  de_ctx->flags |= DE_QUIET;
4925  de_ctx, "alert tcp any any -> [192.168.0.2,!192.168.0.0/24] any (sid:410006;)");
4926  FAIL_IF_NOT_NULL(s);
4928  PASS;
4929 }
4930 
4931 /**
4932  * \test check valid negation bug 1079
4933  */
4934 static int SigParseTestNegation08 (void)
4935 {
4936  int result = 0;
4938  Signature *s=NULL;
4939 
4941  if (de_ctx == NULL)
4942  goto end;
4943  de_ctx->flags |= DE_QUIET;
4944 
4946  "alert tcp any any -> [192.168.0.0/16,!192.168.0.0/24] any (sid:410006; rev:1;)");
4947  if (s == NULL) {
4948  goto end;
4949  }
4950 
4951  result = 1;
4952 end:
4953  if (de_ctx != NULL)
4955  return result;
4956 }
4957 
4958 /**
4959  * \test mpm
4960  */
4961 static int SigParseTestMpm01 (void)
4962 {
4963  int result = 0;
4964  Signature *sig = NULL;
4965 
4967  if (de_ctx == NULL)
4968  goto end;
4969 
4970  sig = SigInit(de_ctx, "alert tcp any any -> any any (msg:\"mpm test\"; content:\"abcd\"; sid:1;)");
4971  if (sig == NULL) {
4972  printf("sig failed to init: ");
4973  goto end;
4974  }
4975 
4976  if (sig->init_data->smlists[DETECT_SM_LIST_PMATCH] == NULL) {
4977  printf("sig doesn't have content list: ");
4978  goto end;
4979  }
4980 
4981  result = 1;
4982 end:
4983  if (sig != NULL)
4984  SigFree(de_ctx, sig);
4986  return result;
4987 }
4988 
4989 /**
4990  * \test mpm
4991  */
4992 static int SigParseTestMpm02 (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\"; content:\"abcdef\"; 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 test tls (app layer) rule
5022  */
5023 static int SigParseTestAppLayerTLS01(void)
5024 {
5025  int result = 0;
5027  Signature *s=NULL;
5028 
5030  if (de_ctx == NULL)
5031  goto end;
5032  de_ctx->flags |= DE_QUIET;
5033 
5034  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS01 \"; sid:410006; rev:1;)");
5035  if (s == NULL) {
5036  printf("parsing sig failed: ");
5037  goto end;
5038  }
5039 
5040  if (s->alproto == 0) {
5041  printf("alproto not set: ");
5042  goto end;
5043  }
5044 
5045  result = 1;
5046 end:
5047  if (s != NULL)
5048  SigFree(de_ctx, s);
5049  if (de_ctx != NULL)
5051 
5052  return result;
5053 }
5054 
5055 /**
5056  * \test test tls (app layer) rule
5057  */
5058 static int SigParseTestAppLayerTLS02(void)
5059 {
5060  int result = 0;
5062  Signature *s=NULL;
5063 
5065  if (de_ctx == NULL)
5066  goto end;
5067  de_ctx->flags |= DE_QUIET;
5068 
5069  s = SigInit(de_ctx,"alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS02 \"; tls.version:1.0; sid:410006; rev:1;)");
5070  if (s == NULL) {
5071  printf("parsing sig failed: ");
5072  goto end;
5073  }
5074 
5075  if (s->alproto == 0) {
5076  printf("alproto not set: ");
5077  goto end;
5078  }
5079 
5080  result = 1;
5081 end:
5082  if (s != NULL)
5083  SigFree(de_ctx, s);
5084  if (de_ctx != NULL)
5086  return result;
5087 }
5088 
5089 /**
5090  * \test test tls (app layer) rule
5091  */
5092 static int SigParseTestAppLayerTLS03(void)
5093 {
5096  de_ctx->flags |= DE_QUIET;
5097 
5099  "alert tls any any -> any any (msg:\"SigParseTestAppLayerTLS03 \"; "
5100  "tls.version:2.5; sid:410006; rev:1;)");
5101  FAIL_IF_NOT_NULL(s);
5103  PASS;
5104 }
5105 
5106 static int SigParseTestUnbalancedQuotes01(void)
5107 {
5110  de_ctx->flags |= DE_QUIET;
5112  "alert http any any -> any any (msg:\"SigParseTestUnbalancedQuotes01\"; "
5113  "pcre:\"/\\/[a-z]+\\.php\\?[a-z]+?=\\d{7}&[a-z]+?=\\d{7,8}$/U\" "
5114  "flowbits:set,et.exploitkitlanding; classtype:trojan-activity; sid:2017078; rev:5;)");
5115  FAIL_IF_NOT_NULL(s);
5117  PASS;
5118 }
5119 
5120 static int SigParseTestContentGtDsize01(void)
5121 {
5124  de_ctx->flags |= DE_QUIET;
5125  Signature *s =
5126  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5127  "dsize:21; content:\"0123456789001234567890|00 00|\"; "
5128  "sid:1; rev:1;)");
5129  FAIL_IF_NOT_NULL(s);
5131  PASS;
5132 }
5133 
5134 static int SigParseTestContentGtDsize02(void)
5135 {
5138  de_ctx->flags |= DE_QUIET;
5139  Signature *s =
5140  DetectEngineAppendSig(de_ctx, "alert http any any -> any any ("
5141  "dsize:21; content:\"0123456789|00 00|\"; offset:10; "
5142  "sid:1; rev:1;)");
5143  FAIL_IF_NOT_NULL(s);
5145  PASS;
5146 }
5147 
5148 static int CountSigsWithSid(const DetectEngineCtx *de_ctx, const uint32_t sid)
5149 {
5150  int cnt = 0;
5151  for (Signature *s = de_ctx->sig_list; s != NULL; s = s->next) {
5152  if (sid == s->id)
5153  cnt++;
5154  }
5155  return cnt;
5156 }
5157 
5158 static int SigParseBidirWithSameSrcAndDest01(void)
5159 {
5162  de_ctx->flags |= DE_QUIET;
5163 
5164  Signature *s = DetectEngineAppendSig(de_ctx, "alert tcp any any <> any any (sid:1;)");
5165  FAIL_IF_NULL(s);
5166  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 1);
5168 
5169  s = DetectEngineAppendSig(de_ctx, "alert tcp any [80, 81] <> any [81, 80] (sid:2;)");
5170  FAIL_IF_NULL(s);
5171  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 1);
5173 
5175  "alert tcp [1.2.3.4, 5.6.7.8] [80, 81] <> [5.6.7.8, 1.2.3.4] [81, 80] (sid:3;)");
5176  FAIL_IF_NULL(s);
5177  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 1);
5179 
5181  PASS;
5182 }
5183 
5184 static int SigParseBidirWithSameSrcAndDest02(void)
5185 {
5188  de_ctx->flags |= DE_QUIET;
5189 
5190  // Source is a subset of destination
5192  de_ctx, "alert tcp 1.2.3.4 any <> [1.2.3.4, 5.6.7.8, ::1] any (sid:1;)");
5193  FAIL_IF_NULL(s);
5194  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 1) == 2);
5196 
5197  // Source is a subset of destination
5199  de_ctx, "alert tcp [1.2.3.4, ::1] [80, 81, 82] <> [1.2.3.4, ::1] [80, 81] (sid:2;)");
5200  FAIL_IF_NULL(s);
5201  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 2) == 2);
5203 
5204  // Source intersects with destination
5206  "alert tcp [1.2.3.4, ::1, ABCD:AAAA::1] [80] <> [1.2.3.4, ::1] [80, 81] (sid:3;)");
5207  FAIL_IF_NULL(s);
5208  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 3) == 2);
5210 
5211  // mix in negation, these are the same
5213  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;)");
5214  FAIL_IF_NULL(s);
5215  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 4) == 1);
5217 
5218  // mix in negation, these are not the same
5220  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;)");
5221  FAIL_IF_NULL(s);
5222  FAIL_IF_NOT(CountSigsWithSid(de_ctx, 5) == 2);
5224 
5226  PASS;
5227 }
5228 
5229 static int SigParseTestActionReject(void)
5230 {
5233 
5235  de_ctx, "reject tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5236 #ifdef HAVE_LIBNET11
5237  FAIL_IF_NULL(sig);
5239 #else
5240  FAIL_IF_NOT_NULL(sig);
5241 #endif
5242 
5244  PASS;
5245 }
5246 
5247 static int SigParseTestActionDrop(void)
5248 {
5251 
5253  de_ctx, "drop tcp 1.2.3.4 any -> !1.2.3.4 any (msg:\"SigParseTest01\"; sid:1;)");
5254  FAIL_IF_NULL(sig);
5255  FAIL_IF_NOT(sig->action & ACTION_DROP);
5256 
5258  PASS;
5259 }
5260 
5261 static int SigSetMultiAppProto(void)
5262 {
5263  Signature *s = SigAlloc();
5264  FAIL_IF_NULL(s);
5265 
5266  AppProto alprotos[] = { 1, 2, 3, ALPROTO_UNKNOWN };
5267  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5268 
5269  // check intersection gives multiple entries
5270  alprotos[0] = 3;
5271  alprotos[1] = 2;
5272  alprotos[2] = ALPROTO_UNKNOWN;
5273  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5274  FAIL_IF(s->init_data->alprotos[0] != 3);
5275  FAIL_IF(s->init_data->alprotos[1] != 2);
5277 
5278  // check single after multiple
5281  FAIL_IF(s->alproto != 3);
5282  alprotos[0] = 4;
5283  alprotos[1] = 3;
5284  alprotos[2] = ALPROTO_UNKNOWN;
5285  // check multiple containing singleton
5286  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5287  FAIL_IF(s->alproto != 3);
5288 
5289  // reset
5290  s->alproto = ALPROTO_UNKNOWN;
5291  alprotos[0] = 1;
5292  alprotos[1] = 2;
5293  alprotos[2] = 3;
5294  alprotos[3] = ALPROTO_UNKNOWN;
5295  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5296  // fail if set single not in multiple
5298 
5300  s->alproto = ALPROTO_UNKNOWN;
5301  alprotos[0] = 1;
5302  alprotos[1] = 2;
5303  alprotos[2] = 3;
5304  alprotos[3] = ALPROTO_UNKNOWN;
5305  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5306  alprotos[0] = 4;
5307  alprotos[1] = 5;
5308  alprotos[2] = ALPROTO_UNKNOWN;
5309  // fail if multiple do not have intersection
5310  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5311 
5313  s->alproto = ALPROTO_UNKNOWN;
5314  alprotos[0] = 1;
5315  alprotos[1] = 2;
5316  alprotos[2] = 3;
5317  alprotos[3] = ALPROTO_UNKNOWN;
5318  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5319  alprotos[0] = 3;
5320  alprotos[1] = 4;
5321  alprotos[2] = 5;
5322  alprotos[3] = ALPROTO_UNKNOWN;
5323  // check multiple intersect to singleton
5324  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) < 0);
5325  FAIL_IF(s->alproto != 3);
5326  alprotos[0] = 5;
5327  alprotos[1] = 4;
5328  alprotos[2] = ALPROTO_UNKNOWN;
5329  // fail if multiple do not belong to singleton
5330  FAIL_IF(DetectSignatureSetMultiAppProto(s, alprotos) >= 0);
5331 
5332  SigFree(NULL, s);
5333  PASS;
5334 }
5335 
5336 static int DetectSetupDirection01(void)
5337 {
5338  Signature *s = SigAlloc();
5339  FAIL_IF_NULL(s);
5340  // Basic case : ok
5341  char *str = (char *)"to_client";
5342  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5343  SigFree(NULL, s);
5344  PASS;
5345 }
5346 
5347 static int DetectSetupDirection02(void)
5348 {
5349  Signature *s = SigAlloc();
5350  FAIL_IF_NULL(s);
5351  char *str = (char *)"to_server";
5352  FAIL_IF(DetectSetupDirection(s, &str, true) < 0);
5353  // ok so far
5354  str = (char *)"to_client";
5355  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5356  // fails because we cannot have both to_client and to_server for same signature
5357  SigFree(NULL, s);
5358  PASS;
5359 }
5360 
5361 static int DetectSetupDirection03(void)
5362 {
5363  Signature *s = SigAlloc();
5364  FAIL_IF_NULL(s);
5365  char *str = (char *)"to_client , something";
5366  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5367  FAIL_IF(strcmp(str, "something") != 0);
5368  str = (char *)"to_client,something";
5369  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5370  FAIL_IF(strcmp(str, "something") != 0);
5371  SigFree(NULL, s);
5372  PASS;
5373 }
5374 
5375 static int DetectSetupDirection04(void)
5376 {
5377  Signature *s = SigAlloc();
5378  FAIL_IF_NULL(s);
5379  // invalid case
5380  char *str = (char *)"to_client_toto";
5381  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5382  // test we do not change the string pointer if only_dir is false
5383  str = (char *)"to_client_toto";
5384  FAIL_IF(DetectSetupDirection(s, &str, false) < 0);
5385  FAIL_IF(strcmp(str, "to_client_toto") != 0);
5386  str = (char *)"to_client,something";
5387  // fails because we call with only_dir=true
5388  FAIL_IF(DetectSetupDirection(s, &str, true) >= 0);
5389  SigFree(NULL, s);
5390  PASS;
5391 }
5392 
5393 #endif /* UNITTESTS */
5394 
5395 #ifdef UNITTESTS
5396 void DetectParseRegisterTests (void);
5397 #include "tests/detect-parse.c"
5398 #endif
5399 
5401 {
5402 #ifdef UNITTESTS
5404 
5405  UtRegisterTest("SigParseTest01", SigParseTest01);
5406  UtRegisterTest("SigParseTest02", SigParseTest02);
5407  UtRegisterTest("SigParseTest03", SigParseTest03);
5408  UtRegisterTest("SigParseTest04", SigParseTest04);
5409  UtRegisterTest("SigParseTest05", SigParseTest05);
5410  UtRegisterTest("SigParseTest06", SigParseTest06);
5411  UtRegisterTest("SigParseTest07", SigParseTest07);
5412  UtRegisterTest("SigParseTest08", SigParseTest08);
5413  UtRegisterTest("SigParseTest09", SigParseTest09);
5414  UtRegisterTest("SigParseTest10", SigParseTest10);
5415  UtRegisterTest("SigParseTest11", SigParseTest11);
5416  UtRegisterTest("SigParseTest12", SigParseTest12);
5417  UtRegisterTest("SigParseTest13", SigParseTest13);
5418  UtRegisterTest("SigParseTest14", SigParseTest14);
5419  UtRegisterTest("SigParseTest15", SigParseTest15);
5420  UtRegisterTest("SigParseTest16", SigParseTest16);
5421  UtRegisterTest("SigParseTest17", SigParseTest17);
5422  UtRegisterTest("SigParseTest18", SigParseTest18);
5423  UtRegisterTest("SigParseTest19", SigParseTest19);
5424  UtRegisterTest("SigParseTest20", SigParseTest20);
5425  UtRegisterTest("SigParseTest21 -- address with space", SigParseTest21);
5426  UtRegisterTest("SigParseTest22 -- address with space", SigParseTest22);
5427  UtRegisterTest("SigParseTest23 -- carriage return", SigParseTest23);
5428 
5429  UtRegisterTest("SigParseBidirecTest06", SigParseBidirecTest06);
5430  UtRegisterTest("SigParseBidirecTest07", SigParseBidirecTest07);
5431  UtRegisterTest("SigParseBidirecTest08", SigParseBidirecTest08);
5432  UtRegisterTest("SigParseBidirecTest09", SigParseBidirecTest09);
5433  UtRegisterTest("SigParseBidirecTest10", SigParseBidirecTest10);
5434  UtRegisterTest("SigParseBidirecTest11", SigParseBidirecTest11);
5435  UtRegisterTest("SigParseBidirecTest12", SigParseBidirecTest12);
5436  UtRegisterTest("SigParseBidirecTest13", SigParseBidirecTest13);
5437  UtRegisterTest("SigParseBidirecTest14", SigParseBidirecTest14);
5438  UtRegisterTest("SigTestBidirec01", SigTestBidirec01);
5439  UtRegisterTest("SigTestBidirec02", SigTestBidirec02);
5440  UtRegisterTest("SigTestBidirec03", SigTestBidirec03);
5441  UtRegisterTest("SigTestBidirec04", SigTestBidirec04);
5442  UtRegisterTest("SigParseTestNegation01", SigParseTestNegation01);
5443  UtRegisterTest("SigParseTestNegation02", SigParseTestNegation02);
5444  UtRegisterTest("SigParseTestNegation03", SigParseTestNegation03);
5445  UtRegisterTest("SigParseTestNegation04", SigParseTestNegation04);
5446  UtRegisterTest("SigParseTestNegation05", SigParseTestNegation05);
5447  UtRegisterTest("SigParseTestNegation06", SigParseTestNegation06);
5448  UtRegisterTest("SigParseTestNegation07", SigParseTestNegation07);
5449  UtRegisterTest("SigParseTestNegation08", SigParseTestNegation08);
5450  UtRegisterTest("SigParseTestMpm01", SigParseTestMpm01);
5451  UtRegisterTest("SigParseTestMpm02", SigParseTestMpm02);
5452  UtRegisterTest("SigParseTestAppLayerTLS01", SigParseTestAppLayerTLS01);
5453  UtRegisterTest("SigParseTestAppLayerTLS02", SigParseTestAppLayerTLS02);
5454  UtRegisterTest("SigParseTestAppLayerTLS03", SigParseTestAppLayerTLS03);
5455  UtRegisterTest("SigParseTestUnbalancedQuotes01", SigParseTestUnbalancedQuotes01);
5456 
5457  UtRegisterTest("SigParseTestContentGtDsize01",
5458  SigParseTestContentGtDsize01);
5459  UtRegisterTest("SigParseTestContentGtDsize02",
5460  SigParseTestContentGtDsize02);
5461 
5462  UtRegisterTest("SigParseBidirWithSameSrcAndDest01",
5463  SigParseBidirWithSameSrcAndDest01);
5464  UtRegisterTest("SigParseBidirWithSameSrcAndDest02",
5465  SigParseBidirWithSameSrcAndDest02);
5466  UtRegisterTest("SigParseTestActionReject", SigParseTestActionReject);
5467  UtRegisterTest("SigParseTestActionDrop", SigParseTestActionDrop);
5468 
5469  UtRegisterTest("SigSetMultiAppProto", SigSetMultiAppProto);
5470 
5471  UtRegisterTest("DetectSetupDirection01", DetectSetupDirection01);
5472  UtRegisterTest("DetectSetupDirection02", DetectSetupDirection02);
5473  UtRegisterTest("DetectSetupDirection03", DetectSetupDirection03);
5474  UtRegisterTest("DetectSetupDirection04", DetectSetupDirection04);
5475 
5476 #endif /* UNITTESTS */
5477 }
DetectAddressListsAreEqual
bool DetectAddressListsAreEqual(DetectAddress *list1, DetectAddress *list2)
Checks if two address group lists are equal.
Definition: detect-engine-address.c:348
DetectIPProtoRemoveAllSMs
void DetectIPProtoRemoveAllSMs(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-ipproto.c:430
DETECT_TABLE_APP_TD
@ DETECT_TABLE_APP_TD
Definition: detect.h:559
SignatureParser_
Definition: detect-parse.c:101
SignatureInitData_::max_content_list_id
uint32_t max_content_list_id
Definition: detect.h:653
host.h
SignatureInitData_::rule_state_dependant_sids_idx
uint32_t rule_state_dependant_sids_idx
Definition: detect.h:659
DetectPortCmp
int DetectPortCmp(DetectPort *a, DetectPort *b)
Function that compare port groups.
Definition: detect-engine-port.c:483
DetectEngineAppInspectionEngine_
Definition: detect.h:415
SC_MATCH_LIMIT_DEFAULT
#define SC_MATCH_LIMIT_DEFAULT
Definition: detect-pcre.h:43
DETECT_CONTENT_RELATIVE_NEXT
#define DETECT_CONTENT_RELATIVE_NEXT
Definition: detect-content.h:66
SignatureInitDataBuffer_::head
SigMatch * head
Definition: detect.h:534
SigMatch_::prev
struct SigMatch_ * prev
Definition: detect.h:360
detect-content.h
SignatureInitDataBuffer_::sm_init
bool sm_init
Definition: detect.h:526
len
uint8_t len
Definition: app-layer-dnp3.h:2
ts
uint64_t ts
Definition: source-erf-file.c:55
DetectMetadataHead::json_str
char * json_str
Definition: detect-metadata.h:40
DetectMetadataFree
void DetectMetadataFree(DetectMetadata *mdata)
Free a Metadata object.
Definition: detect-metadata.c:60
AppLayerHtpNeedFileInspection
void AppLayerHtpNeedFileInspection(void)
Sets a flag that informs the HTP app layer that some module in the engine needs the http request file...
Definition: app-layer-htp.c: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
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
DetectParseRegisterTests
void DetectParseRegisterTests(void)
this function registers unit tests for DetectParse
Definition: detect-parse.c:146
SignatureInitData_::smlists
struct SigMatch_ * smlists[DETECT_SM_LIST_MAX]
Definition: detect.h:642
DetectEngineProtoList
void DetectEngineProtoList(void)
Definition: detect-engine-proto.c:70
SignatureHook_
Definition: detect.h:571
DetectParseDupSigHashInit
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3180
SignatureInitData_::list_set
bool list_set
Definition: detect.h:629
Signature_::addr_src_match6
DetectMatchAddressIPv6 * addr_src_match6
Definition: detect.h:711
sigmatch_table
SigTableElmt * sigmatch_table
Definition: detect-parse.c:79
Signature_::sig_str
char * sig_str
Definition: detect.h:745
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
SIG_TYPE_APP_TX
@ SIG_TYPE_APP_TX
Definition: detect.h:77
SigMatchFree
void SigMatchFree(DetectEngineCtx *de_ctx, SigMatch *sm)
free a SigMatch
Definition: detect-parse.c:288
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1448
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:573
DETECT_TABLE_APP_FILTER
@ DETECT_TABLE_APP_FILTER
Definition: detect.h:558
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:440
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
SIGMATCH_STRICT_PARSING
#define SIGMATCH_STRICT_PARSING
Definition: detect.h:1682
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:1461
SignatureInitData_::smlists_tail
struct SigMatch_ * smlists_tail[DETECT_SM_LIST_MAX]
Definition: detect.h:644
DetectEngineBufferRunSetupCallback
void DetectEngineBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
Definition: detect-engine.c:1473
DetectListToHumanString
const char * DetectListToHumanString(int list)
Definition: detect-parse.c:112
SIG_FLAG_INIT_FLOW
#define SIG_FLAG_INIT_FLOW
Definition: detect.h: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:705
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:2158
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:1452
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:625
SignatureInitData_::src_contains_negation
bool src_contains_negation
Definition: detect.h:601
DetectEngineCtx_::sigerror_silent
bool sigerror_silent
Definition: detect.h:1027
DetectParseRegex::context
pcre2_match_context * context
Definition: detect-parse.h:94
Signature_::alproto
AppProto alproto
Definition: detect.h:673
DETECT_TABLE_PACKET_PRE_STREAM
@ DETECT_TABLE_PACKET_PRE_STREAM
Definition: detect.h:555
SignatureInitData_::is_rule_state_dependant
bool is_rule_state_dependant
Definition: detect.h:656
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
SIG_FLAG_INIT_FILEDATA
#define SIG_FLAG_INIT_FILEDATA
Definition: detect.h:299
detect-isdataat.h
SIGMATCH_QUOTES_OPTIONAL
#define SIGMATCH_QUOTES_OPTIONAL
Definition: detect.h:1666
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:366
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:367
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
DetectTable
DetectTable
Definition: detect.h:552
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:3577
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
SigDuplWrapper_::s_prev
Signature * s_prev
Definition: detect-parse.c:97
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
DETECT_PROTO_ANY
#define DETECT_PROTO_ANY
Definition: detect-engine-proto.h:28
DETECT_CONTENT_RAWBYTES
#define DETECT_CONTENT_RAWBYTES
Definition: detect-content.h:38
AppLayerParserGetStateProgressCompletionStatus
int AppLayerParserGetStateProgressCompletionStatus(AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:1140
CASE_CODE_STRING
#define CASE_CODE_STRING(E, S)
TransformData_::options
void * options
Definition: detect.h:387
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:539
SIG_FLAG_INIT_FORCE_TOCLIENT
#define SIG_FLAG_INIT_FORCE_TOCLIENT
Definition: detect.h:300
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:2684
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:329
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:1151
DetectEngineCtx_::sigerror_requires
bool sigerror_requires
Definition: detect.h:1031
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2417
FILE_SIG_NEED_FILENAME
#define FILE_SIG_NEED_FILENAME
Definition: detect.h:320
SignatureInitDataBuffer_::multi_capable
bool multi_capable
Definition: detect.h:529
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:731
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:1065
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:608
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:3197
DetectParsePcreExec
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
Definition: detect-parse.c:3501
DetectBufferType_
Definition: detect.h:448
proto
uint8_t proto
Definition: decode-template.h:0
DetectContentData_
Definition: detect-content.h:93
DetectEngineCtx_::sigerror_ok
bool sigerror_ok
Definition: detect.h:1028
DetectPcreData_::flags
uint16_t flags
Definition: detect-pcre.h:51
SignatureParser_::dp
char dp[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:108
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:56
SCDetectSignatureSetAppProto
int SCDetectSignatureSetAppProto(Signature *s, AppProto alproto)
Definition: detect-parse.c:2236
SIGMATCH_SUPPORT_FIREWALL
#define SIGMATCH_SUPPORT_FIREWALL
Definition: detect.h:1684
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:1421
SigMatchData_
Data needed for Match()
Definition: detect.h:364
SigTableElmt_::Setup
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition: detect.h:1443
DetectFlowSetupImplicit
int DetectFlowSetupImplicit(Signature *s, uint32_t flags)
Definition: detect-flow.c:341
detect-pcre.h
SigMatchData_::type
uint16_t type
Definition: detect.h:365
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:3537
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:898
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:714
DetectMatchAddressIPv6_::ip2
uint32_t ip2[4]
Definition: detect.h:196
SIGNATURE_HOOK_TYPE_APP
@ SIGNATURE_HOOK_TYPE_APP
Definition: detect.h:549
Signature_::next
struct Signature_ * next
Definition: detect.h:750
ACTION_REJECT_DST
#define ACTION_REJECT_DST
Definition: action-globals.h:32
DetectParseFreeRegexes
void DetectParseFreeRegexes(void)
Definition: detect-parse.c:3521
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:423
SIGMATCH_QUOTES_MANDATORY
#define SIGMATCH_QUOTES_MANDATORY
Definition: detect.h:1670
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
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:1138
detect-app-layer-event.h
SIG_TYPE_PKT
@ SIG_TYPE_PKT
Definition: detect.h:72
HashListTableInit
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
Signature_::addr_src_match4
DetectMatchAddressIPv4 * addr_src_match4
Definition: detect.h:708
SigParseRegisterTests
void SigParseRegisterTests(void)
Definition: detect-parse.c:5400
decode.h
FAIL_IF_NOT_NULL
#define FAIL_IF_NOT_NULL(expr)
Fail a test if expression evaluates to non-NULL.
Definition: util-unittest.h:96
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
DetectTableToString
const char * DetectTableToString(enum DetectTable table)
Definition: detect-engine.c:131
DETECT_CONTENT_DISTANCE
#define DETECT_CONTENT_DISTANCE
Definition: detect-content.h:30
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c: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:86
g_alproto_max
AppProto g_alproto_max
Definition: app-layer-protos.c:30
SignatureInitData_::buffers_size
uint32_t buffers_size
Definition: detect.h:649
SigFree
void SigFree(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-parse.c:2064
DetectEngineThreadCtx_
Definition: detect.h:1245
DetectGetLastSMFromMpmLists
SigMatch * DetectGetLastSMFromMpmLists(const DetectEngineCtx *de_ctx, const Signature *s)
get the last SigMatch from lists that support MPM.
Definition: detect-parse.c:526
SIG_TYPE_IPONLY
@ SIG_TYPE_IPONLY
Definition: detect.h:66
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:623
SIGMATCH_SUPPORT_DIR
#define SIGMATCH_SUPPORT_DIR
Definition: detect.h:1686
g_skip_prefilter
int g_skip_prefilter
Definition: detect-engine-mpm.c:1121
SignatureInitData_::src
const DetectAddressHead * src
Definition: detect.h:639
DETECT_SM_LIST_BASE64_DATA
@ DETECT_SM_LIST_BASE64_DATA
Definition: detect.h:124
detect-engine-file.h
SignatureInitData_::mpm_sm_list
int mpm_sm_list
Definition: detect.h:621
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:618
DetectSetupParseRegexes
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
Definition: detect-parse.c:3627
DETECT_CONTENT_DEPTH
#define DETECT_CONTENT_DEPTH
Definition: detect-content.h:33
SignatureInitData_::list
int list
Definition: detect.h:628
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
detect-engine-mpm.h
Signature_::references
DetectReference * references
Definition: detect.h:741
SigTableElmt_::tables
uint8_t tables
Definition: detect.h:1456
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:1112
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:2372
SignatureHookPkt
SignatureHookPkt
Definition: detect.h:538
pkt-var.h
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3418
SigMatch_::next
struct SigMatch_ * next
Definition: detect.h:359
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:554
detect-engine-port.h
SigDuplWrapper_::s
Signature * s
Definition: detect-parse.c:95
DETECT_TABLE_PACKET_FILTER
@ DETECT_TABLE_PACKET_FILTER
Definition: detect.h:556
SigMatchStrictEnabled
bool SigMatchStrictEnabled(const enum DetectKeywordId id)
Definition: detect-parse.c: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:3615
SigInit
Signature * SigInit(DetectEngineCtx *de_ctx, const char *sigstr)
Parses a signature and adds it to the Detection Engine Context.
Definition: detect-parse.c:3105
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:1459
SignatureInitData_::cidr_src
IPOnlyCIDRItem * cidr_src
Definition: detect.h:618
app-layer-parser.h
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:358
DetectReference_
Signature reference list.
Definition: detect-reference.h:30
SignatureInitData_::hook
SignatureHook hook
Definition: detect.h:590
SIGNATURE_HOOK_TYPE_NOT_SET
@ SIGNATURE_HOOK_TYPE_NOT_SET
Definition: detect.h:547
SC_MATCH_LIMIT_RECURSION_DEFAULT
#define SC_MATCH_LIMIT_RECURSION_DEFAULT
Definition: detect-pcre.h:44
DetectProto_::proto
uint8_t proto[256/8]
Definition: detect-engine-proto.h:36
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:317
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2278
Signature_::action
uint8_t action
Definition: detect.h:683
util-profiling.h
util-rule-vars.h
SignatureHookType
SignatureHookType
Definition: detect.h:546
DetectMetadataHead::list
DetectMetadata * list
Definition: detect-metadata.h:41
SCReturn
#define SCReturn
Definition: util-debug.h:286
Signature_::flags
uint32_t flags
Definition: detect.h:669
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:454
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:1924
DETECT_TABLE_PACKET_TD
@ DETECT_TABLE_PACKET_TD
Definition: detect.h:557
SIGMATCH_HANDLE_NEGATION
#define SIGMATCH_HANDLE_NEGATION
Definition: detect.h:1674
DetectBufferType_::name
char name[64]
Definition: detect.h:449
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:747
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:597
SigTableElmt_::Match
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition: detect.h:1423
SignatureInitData_
Definition: detect.h:589
HashListTable_
Definition: util-hashlist.h:37
DetectGetLastSM
SigMatch * DetectGetLastSM(const Signature *s)
Returns the sm with the largest index (added latest) from this sig.
Definition: detect-parse.c:708
SignatureInitData_::dst_contains_negation
bool dst_contains_negation
Definition: detect.h:602
DetectEngineTransforms::transforms
TransformData transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:391
ALPROTO_HTTP2
@ ALPROTO_HTTP2
Definition: app-layer-protos.h:69
Signature_::addr_dst_match6_cnt
uint16_t addr_dst_match6_cnt
Definition: detect.h:695
SIGNATURE_HOOK_PKT_PRE_STREAM
@ SIGNATURE_HOOK_PKT_PRE_STREAM
Definition: detect.h:542
DetectReference_::next
struct DetectReference_ * next
Definition: detect-reference.h:43
SigMatchAlloc
SigMatch * SigMatchAlloc(void)
Definition: detect-parse.c:274
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
DETECT_PCRE
@ DETECT_PCRE
Definition: detect-engine-register.h:73
SIG_ALPROTO_MAX
#define SIG_ALPROTO_MAX
Definition: detect.h:587
Signature_::sp
DetectPort * sp
Definition: detect.h:719
DetectMetadata_
Signature metadata list.
Definition: detect-metadata.h:30
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:2207
DetectEngineBufferTypeSupportsMpmGetById
bool DetectEngineBufferTypeSupportsMpmGetById(const DetectEngineCtx *de_ctx, const int id)
Definition: detect-engine.c:1445
DetectEngineCtx_::dup_sig_hash_table
HashListTable * dup_sig_hash_table
Definition: detect.h:969
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:34
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1331
DetectEngineAppInspectionEngine_::alproto
AppProto alproto
Definition: detect.h:416
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:350
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:535
DetectAddressHead_::ipv6_head
DetectAddress * ipv6_head
Definition: detect.h:185
SIG_DIREC_DST
@ SIG_DIREC_DST
Definition: detect-parse.h:48
DetectBufferType_::frame
bool frame
Definition: detect.h:455
DetectProto_::flags
uint8_t flags
Definition: detect-engine-proto.h:37
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3447
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
Signature_::proto
DetectProto proto
Definition: detect.h:687
SigTableElmt_::alias
const char * alias
Definition: detect.h:1462
suricata-common.h
SigMatch_::idx
uint16_t idx
Definition: detect.h:357
SIG_FLAG_SP_ANY
#define SIG_FLAG_SP_ANY
Definition: detect.h:242
SigMatch_::type
uint16_t type
Definition: detect.h:356
SignatureParser_::protocol
char protocol[DETECT_MAX_RULE_SIZE]
Definition: detect-parse.c:103
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:88
Signature_::file_flags
uint8_t file_flags
Definition: detect.h:684
SIG_FLAG_INIT_FORCE_TOSERVER
#define SIG_FLAG_INIT_FORCE_TOSERVER
Definition: detect.h:301
FlowShutdown
void FlowShutdown(void)
shutdown the flow engine
Definition: flow.c:715
ACTION_SCOPE_HOOK
@ ACTION_SCOPE_HOOK
Definition: action-globals.h:46
Signature_::action_scope
uint8_t action_scope
Definition: detect.h:690
packet.h
ALPROTO_HTTP1
@ ALPROTO_HTTP1
Definition: app-layer-protos.h:36
SignatureInitData_::curbuf
SignatureInitDataBuffer * curbuf
Definition: detect.h:650
SignatureHook_::type
enum SignatureHookType type
Definition: detect.h:572
SIG_DIREC_SWITCHED
@ SIG_DIREC_SWITCHED
Definition: detect-parse.h:41
DETECT_PROTO_ONLY_STREAM
#define DETECT_PROTO_ONLY_STREAM
Definition: detect-engine-proto.h:30
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3657
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:541
DetectMatchAddressIPv4_::ip2
uint32_t ip2
Definition: detect.h:191
Signature_::rev
uint32_t rev
Definition: detect.h:715
SignatureInitData_::sm_cnt
uint16_t sm_cnt
Definition: detect.h:593
util-classification-config.h
SCStrdup
#define SCStrdup(s)
Definition: util-mem.h:56
DetectBsizeValidateContentCallback
bool DetectBsizeValidateContentCallback(const Signature *s, const SignatureInitDataBuffer *b)
Definition: detect-bsize.c:49
FatalError
#define FatalError(...)
Definition: util-debug.h:517
SIGNATURE_HOOK_TYPE_PKT
@ SIGNATURE_HOOK_TYPE_PKT
Definition: detect.h:548
DetectEngineCtx_::sig_list
Signature * sig_list
Definition: detect.h:942
DetectEngineInspectGenericList
uint8_t DetectEngineInspectGenericList(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Definition: detect-engine.c:1946
DetectEngineAppInspectionEngineSignatureFree
void DetectEngineAppInspectionEngineSignatureFree(DetectEngineCtx *de_ctx, Signature *s)
free app inspect engines for a signature
Definition: detect-engine.c:929
ACTION_CONFIG
#define ACTION_CONFIG
Definition: action-globals.h:35
DETECT_SM_LIST_TMATCH
@ DETECT_SM_LIST_TMATCH
Definition: detect.h:129
TransformData_::transform
int transform
Definition: detect.h:386
SignatureParser
struct SignatureParser_ SignatureParser
Signature_::prio
int prio
Definition: detect.h:716
DetectEngineCtx_::sm_types_silent_error
bool * sm_types_silent_error
Definition: detect.h:1113
DetectEngineAppInspectionEngine_::progress
int16_t progress
Definition: detect.h:425
DetectMatchAddressIPv6_::ip
uint32_t ip[4]
Definition: detect.h:195
SIGMATCH_OPTIONAL_OPT
#define SIGMATCH_OPTIONAL_OPT
Definition: detect.h:1663
SignatureInitDataBuffer_::only_ts
bool only_ts
Definition: detect.h:532
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:696
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SignatureInitData_::buffers
SignatureInitDataBuffer * buffers
Definition: detect.h:647
DetectEngineCtx_::app_inspect_engines
DetectEngineAppInspectionEngine * app_inspect_engines
Definition: detect.h:1088
SignatureInitData_::dst
const DetectAddressHead * dst
Definition: detect.h:639
SignatureInitData_::firewall_rule
bool firewall_rule
Definition: detect.h:664
SIGNATURE_HOOK_PKT_ALL
@ SIGNATURE_HOOK_PKT_ALL
Definition: detect.h:543
Signature_::dp
DetectPort * dp
Definition: detect.h:719
str
#define str(s)
Definition: suricata-common.h:308
detect-http-method.h
Signature_::metadata
DetectMetadataHead * metadata
Definition: detect.h:743
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
DETECT_TBLSIZE
int DETECT_TBLSIZE
Definition: detect-engine-register.c:267
Signature_::iid
SigIntId iid
Definition: detect.h:680
head
Flow * head
Definition: flow-hash.h:1
SigMatchListSMBelongsTo
int SigMatchListSMBelongsTo(const Signature *s, const SigMatch *key_sm)
Definition: detect-parse.c:762
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SCNtohl
#define SCNtohl(x)
Definition: suricata-common.h:430
SIGMATCH_INFO_DEPRECATED
#define SIGMATCH_INFO_DEPRECATED
Definition: detect.h:1680
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:1445
Signature_::addr_dst_match6
DetectMatchAddressIPv6 * addr_dst_match6
Definition: detect.h:710
Signature_::id
uint32_t id
Definition: detect.h:713
DETECT_CONTENT_OFFSET
#define DETECT_CONTENT_OFFSET
Definition: detect-content.h:32
DetectMetadata_::next
struct DetectMetadata_ * next
Definition: detect-metadata.h:36
ACTION_SCOPE_PACKET
@ ACTION_SCOPE_PACKET
Definition: action-globals.h:44
detect-engine-iponly.h
detect-parse.h
src
uint16_t src
Definition: app-layer-dnp3.h:5
SignatureInitDataBuffer_::id
uint32_t id
Definition: detect.h:525
Signature_
Signature container.
Definition: detect.h:668
SigMatch_
a single match condition for a signature
Definition: detect.h:355
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:2645
DETECT_PCRE_RELATIVE_NEXT
#define DETECT_PCRE_RELATIVE_NEXT
Definition: detect-pcre.h:34
SignatureInitData_::has_possible_prefilter
bool has_possible_prefilter
Definition: detect.h:605
SignatureSetType
void SignatureSetType(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine-build.c:1645
app-layer-protos.h
SC_Pcre2SubstringCopy
int SC_Pcre2SubstringCopy(pcre2_match_data *match_data, uint32_t number, PCRE2_UCHAR *buffer, PCRE2_SIZE *bufflen)
Definition: detect-parse.c:3603
ACTION_ACCEPT
#define ACTION_ACCEPT
Definition: action-globals.h:36
SIGNATURE_HOOK_PKT_FLOW_START
@ SIGNATURE_HOOK_PKT_FLOW_START
Definition: detect.h:540
DetectEngineTransforms::cnt
int cnt
Definition: detect.h:392
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:417
Signature_::detect_table
uint8_t detect_table
Definition: detect.h:702
DetectParseAddress
const DetectAddressHead * DetectParseAddress(DetectEngineCtx *de_ctx, const char *string, bool *contains_negation)
Definition: detect-engine-address.c:1435
SignatureInitDataBuffer_::only_tc
bool only_tc
Definition: detect.h:531
detect-uricontent.h
DETECT_DEFAULT_PRIO
#define DETECT_DEFAULT_PRIO
Definition: detect.h:52
SIGMATCH_NOOPT
#define SIGMATCH_NOOPT
Definition: detect.h:1653
DetectEngineBufferRunValidateCallback
bool DetectEngineBufferRunValidateCallback(const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
Definition: detect-engine.c:1492
DetectEngineCtx_::sigerror
const char * sigerror
Definition: detect.h:1026
DetectAppLayerInspectEngineRegister
void DetectAppLayerInspectEngineRegister(const char *name, AppProto alproto, uint32_t dir, int progress, InspectEngineFuncPtr Callback, InspectionBufferGetDataPtr GetData)
Registers an app inspection engine.
Definition: detect-engine.c:273
DetectParseFreeRegex
void DetectParseFreeRegex(DetectParseRegex *r)
Definition: detect-parse.c:3511
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:935
SigAlloc
Signature * SigAlloc(void)
Definition: detect-parse.c:1944
SignatureInitData_::transforms
DetectEngineTransforms transforms
Definition: detect.h:631
UTHAppendSigs
int UTHAppendSigs(DetectEngineCtx *de_ctx, const char *sigs[], int numsigs)
UTHAppendSigs: Add sigs to the detection_engine checking for errors.
Definition: util-unittest-helper.c:654
dst
uint16_t dst
Definition: app-layer-dnp3.h:4
Signature_::addr_dst_match4
DetectMatchAddressIPv4 * addr_dst_match4
Definition: detect.h:707
DETECT_CONTENT_REPLACE
#define DETECT_CONTENT_REPLACE
Definition: detect-content.h:51
Signature_::msg
char * msg
Definition: detect.h:736
flow.h
SignatureInitDataBuffer_
Definition: detect.h:524
Signature_::addr_src_match4_cnt
uint16_t addr_src_match4_cnt
Definition: detect.h:694
Signature_::addr_dst_match4_cnt
uint16_t addr_dst_match4_cnt
Definition: detect.h:693
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
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:671
DetectEngineCtx_::signum
uint32_t signum
Definition: detect.h:954
SignatureInitData_::buffer_index
uint32_t buffer_index
Definition: detect.h:648
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:3548
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:3375
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:1367
app-layer.h
SignatureInitData_::alprotos
AppProto alprotos[SIG_ALPROTO_MAX]
Definition: detect.h:612
SCClassConfDeInitContext
void SCClassConfDeInitContext(DetectEngineCtx *de_ctx)
Releases resources used by the Classification Config API.
Definition: util-classification-config.c:190
SIG_FLAG_REQUIRE_PACKET
#define SIG_FLAG_REQUIRE_PACKET
Definition: detect.h:253