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