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