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