suricata
detect-engine.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 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 
24 #include "suricata-common.h"
25 #include "suricata.h"
26 #include "debug.h"
27 #include "detect.h"
28 #include "flow.h"
29 #include "flow-private.h"
30 #include "flow-util.h"
31 #include "flow-worker.h"
32 #include "conf.h"
33 #include "conf-yaml-loader.h"
34 #include "datasets.h"
35 
36 #include "app-layer-parser.h"
37 #include "app-layer-htp.h"
38 
39 #include "detect-parse.h"
40 #include "detect-engine-sigorder.h"
41 
42 #include "detect-engine-siggroup.h"
43 #include "detect-engine-address.h"
44 #include "detect-engine-port.h"
46 #include "detect-engine-mpm.h"
47 #include "detect-engine-iponly.h"
48 #include "detect-engine-tag.h"
49 
50 #include "detect-engine-file.h"
51 
52 #include "detect-engine.h"
53 #include "detect-engine-state.h"
54 #include "detect-engine-payload.h"
55 #include "detect-byte-extract.h"
56 #include "detect-content.h"
57 #include "detect-uricontent.h"
58 #include "detect-tcphdr.h"
61 
62 #include "detect-engine-loader.h"
63 
65 #include "util-reference-config.h"
66 #include "util-threshold-config.h"
67 #include "util-error.h"
68 #include "util-hash.h"
69 #include "util-byte.h"
70 #include "util-debug.h"
71 #include "util-unittest.h"
72 #include "util-action.h"
73 #include "util-magic.h"
74 #include "util-signal.h"
75 #include "util-spm.h"
76 #include "util-device.h"
77 #include "util-var-name.h"
78 #include "util-profiling.h"
79 #include "util-validate.h"
80 
81 #include "tm-threads.h"
82 #include "runmodes.h"
83 
84 #include "reputation.h"
85 
86 #define DETECT_ENGINE_DEFAULT_INSPECTION_RECURSION_LIMIT 3000
87 
88 static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
89  ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt);
90 
91 static int DetectEngineCtxLoadConf(DetectEngineCtx *);
92 
93 static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER,
94  0, 99, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL, NULL, 0};
95 
96 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
97 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
98 static void TenantIdFree(void *d);
99 static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p);
100 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p);
101 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p);
102 
103 static DetectEngineAppInspectionEngine *g_app_inspect_engines = NULL;
104 static DetectEnginePktInspectionEngine *g_pkt_inspect_engines = NULL;
105 
107 #ifdef UNITTESTS
108  { "TEST", DET_CTX_EVENT_TEST },
109 #endif
110  { "NO_MEMORY", FILE_DECODER_EVENT_NO_MEM },
111  { "INVALID_SWF_LENGTH", FILE_DECODER_EVENT_INVALID_SWF_LENGTH },
112  { "INVALID_SWF_VERSION", FILE_DECODER_EVENT_INVALID_SWF_VERSION },
113  { "Z_DATA_ERROR", FILE_DECODER_EVENT_Z_DATA_ERROR },
114  { "Z_STREAM_ERROR", FILE_DECODER_EVENT_Z_STREAM_ERROR },
115  { "Z_BUF_ERROR", FILE_DECODER_EVENT_Z_BUF_ERROR },
116  { "Z_UNKNOWN_ERROR", FILE_DECODER_EVENT_Z_UNKNOWN_ERROR },
117  { "LZMA_DECODER_ERROR", FILE_DECODER_EVENT_LZMA_DECODER_ERROR },
118  { "LZMA_MEMLIMIT_ERROR", FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR },
119  { "LZMA_OPTIONS_ERROR", FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR },
120  { "LZMA_FORMAT_ERROR", FILE_DECODER_EVENT_LZMA_FORMAT_ERROR },
121  { "LZMA_DATA_ERROR", FILE_DECODER_EVENT_LZMA_DATA_ERROR },
122  { "LZMA_BUF_ERROR", FILE_DECODER_EVENT_LZMA_BUF_ERROR },
123  { "LZMA_UNKNOWN_ERROR", FILE_DECODER_EVENT_LZMA_UNKNOWN_ERROR },
124  {
125  "TOO_MANY_BUFFERS",
127  },
128  { NULL, -1 },
129 };
130 
131 /** \brief register inspect engine at start up time
132  *
133  * \note errors are fatal */
134 void DetectPktInspectEngineRegister(const char *name,
137 {
139  const int sm_list = DetectBufferTypeGetByName(name);
140  if (sm_list == -1) {
142  "failed to register inspect engine %s", name);
143  }
144 
145  if ((sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
146  (Callback == NULL))
147  {
148  SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
149  BUG_ON(1);
150  }
151 
152  DetectEnginePktInspectionEngine *new_engine = SCCalloc(1, sizeof(*new_engine));
153  if (unlikely(new_engine == NULL)) {
155  "failed to register inspect engine %s: %s", name, strerror(errno));
156  }
157  new_engine->sm_list = sm_list;
158  new_engine->sm_list_base = sm_list;
159  new_engine->v1.Callback = Callback;
160  new_engine->v1.GetData = GetPktData;
161 
162  if (g_pkt_inspect_engines == NULL) {
163  g_pkt_inspect_engines = new_engine;
164  } else {
165  DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
166  while (t->next != NULL) {
167  t = t->next;
168  }
169 
170  t->next = new_engine;
171  }
172 }
173 
174 /** \brief register inspect engine at start up time
175  *
176  * \note errors are fatal */
178  AppProto alproto, uint32_t dir, int progress,
179  InspectEngineFuncPtr2 Callback2,
181 {
183  const int sm_list = DetectBufferTypeGetByName(name);
184  if (sm_list == -1) {
186  "failed to register inspect engine %s", name);
187  }
188 
189  if ((alproto >= ALPROTO_FAILED) ||
190  (!(dir == SIG_FLAG_TOSERVER || dir == SIG_FLAG_TOCLIENT)) ||
191  (sm_list < DETECT_SM_LIST_MATCH) || (sm_list >= SHRT_MAX) ||
192  (progress < 0 || progress >= SHRT_MAX) ||
193  (Callback2 == NULL))
194  {
195  SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments");
196  BUG_ON(1);
197  } else if (Callback2 == DetectEngineInspectBufferGeneric && GetData == NULL) {
198  SCLogError(SC_ERR_INVALID_ARGUMENTS, "Invalid arguments: must register "
199  "GetData with DetectEngineInspectBufferGeneric");
200  BUG_ON(1);
201  }
202 
203  int direction;
204  if (dir == SIG_FLAG_TOSERVER) {
205  direction = 0;
206  } else {
207  direction = 1;
208  }
209 
211  if (unlikely(new_engine == NULL)) {
212  exit(EXIT_FAILURE);
213  }
214  memset(new_engine, 0, sizeof(*new_engine));
215  new_engine->alproto = alproto;
216  new_engine->dir = direction;
217  new_engine->sm_list = sm_list;
218  new_engine->sm_list_base = sm_list;
219  new_engine->progress = progress;
220  new_engine->v2.Callback = Callback2;
221  new_engine->v2.GetData = GetData;
222 
223  if (g_app_inspect_engines == NULL) {
224  g_app_inspect_engines = new_engine;
225  } else {
226  DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
227  while (t->next != NULL) {
228  t = t->next;
229  }
230 
231  t->next = new_engine;
232  }
233 }
234 
235 /* copy an inspect engine with transforms to a new list id. */
236 static void DetectAppLayerInspectEngineCopy(
238  int sm_list, int new_list,
239  const DetectEngineTransforms *transforms)
240 {
241  const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
242  while (t) {
243  if (t->sm_list == sm_list) {
245  if (unlikely(new_engine == NULL)) {
246  exit(EXIT_FAILURE);
247  }
248  new_engine->alproto = t->alproto;
249  new_engine->dir = t->dir;
250  new_engine->sm_list = new_list; /* use new list id */
251  new_engine->sm_list_base = sm_list;
252  new_engine->progress = t->progress;
253  new_engine->v2 = t->v2;
254  new_engine->v2.transforms = transforms; /* assign transforms */
255 
256  if (de_ctx->app_inspect_engines == NULL) {
257  de_ctx->app_inspect_engines = new_engine;
258  } else {
260  while (list->next != NULL) {
261  list = list->next;
262  }
263 
264  list->next = new_engine;
265  }
266  }
267  t = t->next;
268  }
269 }
270 
271 /* copy inspect engines from global registrations to de_ctx list */
272 static void DetectAppLayerInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
273 {
274  const DetectEngineAppInspectionEngine *t = g_app_inspect_engines;
275  while (t) {
277  if (unlikely(new_engine == NULL)) {
278  exit(EXIT_FAILURE);
279  }
280  new_engine->alproto = t->alproto;
281  new_engine->dir = t->dir;
282  new_engine->sm_list = t->sm_list;
283  new_engine->sm_list_base = t->sm_list;
284  new_engine->progress = t->progress;
285  new_engine->v2 = t->v2;
286 
287  if (de_ctx->app_inspect_engines == NULL) {
288  de_ctx->app_inspect_engines = new_engine;
289  } else {
291  while (list->next != NULL) {
292  list = list->next;
293  }
294 
295  list->next = new_engine;
296  }
297 
298  t = t->next;
299  }
300 }
301 
302 /* copy an inspect engine with transforms to a new list id. */
303 static void DetectPktInspectEngineCopy(
305  int sm_list, int new_list,
306  const DetectEngineTransforms *transforms)
307 {
308  const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
309  while (t) {
310  if (t->sm_list == sm_list) {
312  if (unlikely(new_engine == NULL)) {
313  exit(EXIT_FAILURE);
314  }
315  new_engine->sm_list = new_list; /* use new list id */
316  new_engine->sm_list_base = sm_list;
317  new_engine->v1 = t->v1;
318  new_engine->v1.transforms = transforms; /* assign transforms */
319 
320  if (de_ctx->pkt_inspect_engines == NULL) {
321  de_ctx->pkt_inspect_engines = new_engine;
322  } else {
324  while (list->next != NULL) {
325  list = list->next;
326  }
327 
328  list->next = new_engine;
329  }
330  }
331  t = t->next;
332  }
333 }
334 
335 /* copy inspect engines from global registrations to de_ctx list */
336 static void DetectPktInspectEngineCopyListToDetectCtx(DetectEngineCtx *de_ctx)
337 {
338  const DetectEnginePktInspectionEngine *t = g_pkt_inspect_engines;
339  while (t) {
340  SCLogDebug("engine %p", t);
342  if (unlikely(new_engine == NULL)) {
343  exit(EXIT_FAILURE);
344  }
345  new_engine->sm_list = t->sm_list;
346  new_engine->sm_list_base = t->sm_list;
347  new_engine->v1 = t->v1;
348 
349  if (de_ctx->pkt_inspect_engines == NULL) {
350  de_ctx->pkt_inspect_engines = new_engine;
351  } else {
353  while (list->next != NULL) {
354  list = list->next;
355  }
356 
357  list->next = new_engine;
358  }
359 
360  t = t->next;
361  }
362 }
363 
364 /** \internal
365  * \brief append the stream inspection
366  *
367  * If stream inspection is MPM, then prepend it.
368  */
369 static void AppendStreamInspectEngine(Signature *s, SigMatchData *stream, int direction, uint32_t id)
370 {
371  bool prepend = false;
372 
374  if (unlikely(new_engine == NULL)) {
375  exit(EXIT_FAILURE);
376  }
378  SCLogDebug("stream is mpm");
379  prepend = true;
380  new_engine->mpm = true;
381  }
382  new_engine->alproto = ALPROTO_UNKNOWN; /* all */
383  new_engine->dir = direction;
384  new_engine->stream = true;
385  new_engine->sm_list = DETECT_SM_LIST_PMATCH;
386  new_engine->sm_list_base = DETECT_SM_LIST_PMATCH;
387  new_engine->smd = stream;
388  new_engine->v2.Callback = DetectEngineInspectStream;
389  new_engine->progress = 0;
390 
391  /* append */
392  if (s->app_inspect == NULL) {
393  s->app_inspect = new_engine;
394  new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
395  } else if (prepend) {
396  new_engine->next = s->app_inspect;
397  s->app_inspect = new_engine;
398  new_engine->id = id;
399 
400  } else {
402  while (a->next != NULL) {
403  a = a->next;
404  }
405 
406  a->next = new_engine;
407  new_engine->id = id;
408  }
409  SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
410 }
411 
412 /**
413  * \note for the file inspect engine, the id DE_STATE_ID_FILE_INSPECT
414  * is assigned.
415  */
417 {
418  const int nlists = s->init_data->smlists_array_size;
419  SigMatchData *ptrs[nlists];
420  memset(&ptrs, 0, (nlists * sizeof(SigMatchData *)));
421 
422  const int mpm_list = s->init_data->mpm_sm ?
424  -1;
425 
426  const int files_id = DetectBufferTypeGetByName("files");
427 
428  /* convert lists to SigMatchData arrays */
429  int i = 0;
430  for (i = DETECT_SM_LIST_DYNAMIC_START; i < nlists; i++) {
431  if (s->init_data->smlists[i] == NULL)
432  continue;
433 
434  ptrs[i] = SigMatchList2DataArray(s->init_data->smlists[i]);
435  SCLogDebug("ptrs[%d] is set", i);
436  }
437 
438  /* set up pkt inspect engines */
440  while (e != NULL) {
441  SCLogDebug("e %p sm_list %u nlists %u ptrs[] %p", e, e->sm_list, nlists, e->sm_list < nlists ? ptrs[e->sm_list] : NULL);
442  if (e->sm_list < nlists && ptrs[e->sm_list] != NULL) {
443  bool prepend = false;
444 
446  if (unlikely(new_engine == NULL)) {
447  exit(EXIT_FAILURE);
448  }
449  if (mpm_list == e->sm_list) {
451  prepend = true;
452  new_engine->mpm = true;
453  }
454 
455  new_engine->sm_list = e->sm_list;
456  new_engine->sm_list_base = e->sm_list_base;
457  new_engine->smd = ptrs[new_engine->sm_list];
458  new_engine->v1 = e->v1;
459  SCLogDebug("sm_list %d new_engine->v1 %p/%p/%p",
460  new_engine->sm_list, new_engine->v1.Callback,
461  new_engine->v1.GetData, new_engine->v1.transforms);
462 
463  if (s->pkt_inspect == NULL) {
464  s->pkt_inspect = new_engine;
465  } else if (prepend) {
466  new_engine->next = s->pkt_inspect;
467  s->pkt_inspect = new_engine;
468  } else {
470  while (a->next != NULL) {
471  a = a->next;
472  }
473  new_engine->next = a->next;
474  a->next = new_engine;
475  }
476  }
477  e = e->next;
478  }
479 
480  bool head_is_mpm = false;
481  uint32_t last_id = DE_STATE_FLAG_BASE;
483  while (t != NULL) {
484  bool prepend = false;
485 
486  if (t->sm_list >= nlists)
487  goto next;
488 
489  if (ptrs[t->sm_list] == NULL)
490  goto next;
491 
492  SCLogDebug("ptrs[%d] is set", t->sm_list);
493 
494  if (t->alproto == ALPROTO_UNKNOWN) {
495  /* special case, inspect engine applies to all protocols */
496  } else if (s->alproto != ALPROTO_UNKNOWN && !AppProtoEquals(s->alproto, t->alproto))
497  goto next;
498 
499  if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
500  if (t->dir == 1)
501  goto next;
502  } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
503  if (t->dir == 0)
504  goto next;
505  }
507  if (unlikely(new_engine == NULL)) {
508  exit(EXIT_FAILURE);
509  }
510  if (mpm_list == t->sm_list) {
512  prepend = true;
513  head_is_mpm = true;
514  new_engine->mpm = true;
515  }
516 
517  new_engine->alproto = t->alproto;
518  new_engine->dir = t->dir;
519  new_engine->sm_list = t->sm_list;
520  new_engine->sm_list_base = t->sm_list_base;
521  new_engine->smd = ptrs[new_engine->sm_list];
522  new_engine->progress = t->progress;
523  new_engine->v2 = t->v2;
524  SCLogDebug("sm_list %d new_engine->v2 %p/%p/%p",
525  new_engine->sm_list, new_engine->v2.Callback,
526  new_engine->v2.GetData, new_engine->v2.transforms);
527 
528  if (s->app_inspect == NULL) {
529  s->app_inspect = new_engine;
530  if (new_engine->sm_list == files_id) {
531  SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
532  new_engine->id = DE_STATE_ID_FILE_INSPECT;
533  } else {
534  new_engine->id = DE_STATE_FLAG_BASE; /* id is used as flag in stateful detect */
535  }
536 
537  /* prepend engine if forced or if our engine has a lower progress. */
538  } else if (prepend || (!head_is_mpm && s->app_inspect->progress > new_engine->progress)) {
539  new_engine->next = s->app_inspect;
540  s->app_inspect = new_engine;
541  if (new_engine->sm_list == files_id) {
542  SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
543  new_engine->id = DE_STATE_ID_FILE_INSPECT;
544  } else {
545  new_engine->id = ++last_id;
546  }
547 
548  } else {
550  while (a->next != NULL) {
551  if (a->next && a->next->progress > new_engine->progress) {
552  break;
553  }
554 
555  a = a->next;
556  }
557 
558  new_engine->next = a->next;
559  a->next = new_engine;
560  if (new_engine->sm_list == files_id) {
561  SCLogDebug("sid %u: engine %p/%u is FILE ENGINE", s->id, new_engine, new_engine->id);
562  new_engine->id = DE_STATE_ID_FILE_INSPECT;
563  } else {
564  new_engine->id = ++last_id;
565  }
566  }
567 
568  SCLogDebug("sid %u: engine %p/%u added", s->id, new_engine, new_engine->id);
569 
571 next:
572  t = t->next;
573  }
574 
577  {
578  /* if engine is added multiple times, we pass it the same list */
580  BUG_ON(stream == NULL);
581  if (s->flags & SIG_FLAG_TOSERVER && !(s->flags & SIG_FLAG_TOCLIENT)) {
582  AppendStreamInspectEngine(s, stream, 0, last_id + 1);
583  } else if (s->flags & SIG_FLAG_TOCLIENT && !(s->flags & SIG_FLAG_TOSERVER)) {
584  AppendStreamInspectEngine(s, stream, 1, last_id + 1);
585  } else {
586  AppendStreamInspectEngine(s, stream, 0, last_id + 1);
587  AppendStreamInspectEngine(s, stream, 1, last_id + 1);
588  }
589 
591  SCLogDebug("set SIG_FLAG_FLUSH on %u", s->id);
592  s->flags |= SIG_FLAG_FLUSH;
593  }
594  }
595 
596 #ifdef DEBUG
598  while (iter) {
599  SCLogDebug("%u: engine %s id %u progress %d %s", s->id,
601  iter->progress,
602  iter->sm_list == mpm_list ? "MPM":"");
603  iter = iter->next;
604  }
605 #endif
606  return 0;
607 }
608 
609 /** \brief free app inspect engines for a signature
610  *
611  * For lists that are registered multiple times, like http_header and
612  * http_cookie, making the engines owner of the lists is complicated.
613  * Multiple engines in a sig may be pointing to the same list. To
614  * address this the 'free' code needs to be extra careful about not
615  * double freeing, so it takes an approach to first fill an array
616  * of the to-free pointers before freeing them.
617  */
619 {
620  int nlists = 0;
621 
623  while (ie) {
624  nlists = MAX(ie->sm_list + 1, nlists);
625  ie = ie->next;
626  }
628  while (e) {
629  nlists = MAX(e->sm_list + 1, nlists);
630  e = e->next;
631  }
632  if (nlists == 0) {
633  BUG_ON(s->pkt_inspect);
634  return;
635  }
636 
637  SigMatchData *ptrs[nlists];
638  memset(&ptrs, 0, (nlists * sizeof(SigMatchData *)));
639 
640  /* free engines and put smd in the array */
641  ie = s->app_inspect;
642  while (ie) {
644  BUG_ON(ptrs[ie->sm_list] != NULL && ptrs[ie->sm_list] != ie->smd);
645  ptrs[ie->sm_list] = ie->smd;
646  SCFree(ie);
647  ie = next;
648  }
649  e = s->pkt_inspect;
650  while (e) {
652  ptrs[e->sm_list] = e->smd;
653  SCFree(e);
654  e = next;
655  }
656 
657  /* free the smds */
658  for (int i = 0; i < nlists; i++)
659  {
660  if (ptrs[i] == NULL)
661  continue;
662 
663  SigMatchData *smd = ptrs[i];
664  while(1) {
665  if (sigmatch_table[smd->type].Free != NULL) {
666  sigmatch_table[smd->type].Free(de_ctx, smd->ctx);
667  }
668  if (smd->is_last)
669  break;
670  smd++;
671  }
672  SCFree(ptrs[i]);
673  }
674 }
675 
676 /* code for registering buffers */
677 
678 #include "util-hash-lookup3.h"
679 
680 static HashListTable *g_buffer_type_hash = NULL;
681 static int g_buffer_type_id = DETECT_SM_LIST_DYNAMIC_START;
682 static int g_buffer_type_reg_closed = 0;
683 
684 static DetectEngineTransforms no_transforms = {
685  .transforms[0] = {0, NULL},
686  .cnt = 0,
687 };
688 
690 {
691  return g_buffer_type_id;
692 }
693 
694 static uint32_t DetectBufferTypeHashFunc(HashListTable *ht, void *data, uint16_t datalen)
695 {
696  const DetectBufferType *map = (DetectBufferType *)data;
697  uint32_t hash = 0;
698 
699  hash = hashlittle_safe(map->string, strlen(map->string), 0);
700  hash += hashlittle_safe((uint8_t *)&map->transforms, sizeof(map->transforms), 0);
701  hash %= ht->array_size;
702 
703  return hash;
704 }
705 
706 static char DetectBufferTypeCompareFunc(void *data1, uint16_t len1, void *data2,
707  uint16_t len2)
708 {
709  DetectBufferType *map1 = (DetectBufferType *)data1;
710  DetectBufferType *map2 = (DetectBufferType *)data2;
711 
712  int r = (strcmp(map1->string, map2->string) == 0);
713  r &= (memcmp((uint8_t *)&map1->transforms, (uint8_t *)&map2->transforms, sizeof(map2->transforms)) == 0);
714  return r;
715 }
716 
717 static void DetectBufferTypeFreeFunc(void *data)
718 {
719  DetectBufferType *map = (DetectBufferType *)data;
720 
721  if (map == NULL) {
722  return;
723  }
724 
725  /* Release transformation option memory, if any */
726  for (int i = 0; i < map->transforms.cnt; i++) {
727  if (map->transforms.transforms[i].options == NULL)
728  continue;
729  if (sigmatch_table[map->transforms.transforms[i].transform].Free == NULL) {
731  "%s allocates transform option memory but has no free routine",
733  continue;
734  }
736  }
737 
738  SCFree(map);
739 }
740 
741 static int DetectBufferTypeInit(void)
742 {
743  BUG_ON(g_buffer_type_hash);
744  g_buffer_type_hash = HashListTableInit(256,
745  DetectBufferTypeHashFunc,
746  DetectBufferTypeCompareFunc,
747  DetectBufferTypeFreeFunc);
748  if (g_buffer_type_hash == NULL)
749  return -1;
750 
751  return 0;
752 }
753 #if 0
754 static void DetectBufferTypeFree(void)
755 {
756  if (g_buffer_type_hash == NULL)
757  return;
758 
759  HashListTableFree(g_buffer_type_hash);
760  g_buffer_type_hash = NULL;
761  return;
762 }
763 #endif
764 static int DetectBufferTypeAdd(const char *string)
765 {
766  DetectBufferType *map = SCCalloc(1, sizeof(*map));
767  if (map == NULL)
768  return -1;
769 
770  map->string = string;
771  map->id = g_buffer_type_id++;
772 
773  BUG_ON(HashListTableAdd(g_buffer_type_hash, (void *)map, 0) != 0);
774  SCLogDebug("buffer %s registered with id %d", map->string, map->id);
775  return map->id;
776 }
777 
778 static DetectBufferType *DetectBufferTypeLookupByName(const char *string)
779 {
780  DetectBufferType map = { (char *)string, NULL, 0, 0, 0, 0, false, NULL, NULL, no_transforms };
781 
782  DetectBufferType *res = HashListTableLookup(g_buffer_type_hash, &map, 0);
783  return res;
784 }
785 
786 int DetectBufferTypeRegister(const char *name)
787 {
788  BUG_ON(g_buffer_type_reg_closed);
789  if (g_buffer_type_hash == NULL)
790  DetectBufferTypeInit();
791 
792  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
793  if (!exists) {
794  return DetectBufferTypeAdd(name);
795  } else {
796  return exists->id;
797  }
798 }
799 
800 void DetectBufferTypeSupportsPacket(const char *name)
801 {
802  BUG_ON(g_buffer_type_reg_closed);
804  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
805  BUG_ON(!exists);
806  exists->packet = true;
807  SCLogDebug("%p %s -- %d supports packet inspection", exists, name, exists->id);
808 }
809 
810 void DetectBufferTypeSupportsMpm(const char *name)
811 {
812  BUG_ON(g_buffer_type_reg_closed);
814  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
815  BUG_ON(!exists);
816  exists->mpm = true;
817  SCLogDebug("%p %s -- %d supports mpm", exists, name, exists->id);
818 }
819 
821 {
822  BUG_ON(g_buffer_type_reg_closed);
824  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
825  BUG_ON(!exists);
826  exists->supports_transforms = true;
827  SCLogDebug("%p %s -- %d supports transformations", exists, name, exists->id);
828 }
829 
830 int DetectBufferTypeGetByName(const char *name)
831 {
832  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
833  if (!exists) {
834  return -1;
835  }
836  return exists->id;
837 }
838 
839 const char *DetectBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
840 {
841  BUG_ON(id < 0 || (uint32_t)id >= de_ctx->buffer_type_map_elements);
842  BUG_ON(de_ctx->buffer_type_map == NULL);
843 
844  if (de_ctx->buffer_type_map[id] == NULL)
845  return NULL;
846 
847  return de_ctx->buffer_type_map[id]->string;
848 }
849 
850 static const DetectBufferType *DetectBufferTypeGetById(const DetectEngineCtx *de_ctx, const int id)
851 {
852  BUG_ON(id < 0 || (uint32_t)id >= de_ctx->buffer_type_map_elements);
853  BUG_ON(de_ctx->buffer_type_map == NULL);
854 
855  return de_ctx->buffer_type_map[id];
856 }
857 
858 void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
859 {
860  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
861  if (!exists) {
862  return;
863  }
864  exists->description = desc;
865 }
866 
868 {
869  const DetectBufferType *exists = DetectBufferTypeGetById(de_ctx, id);
870  if (!exists) {
871  return NULL;
872  }
873  return exists->description;
874 }
875 
876 const char *DetectBufferTypeGetDescriptionByName(const char *name)
877 {
878  const DetectBufferType *exists = DetectBufferTypeLookupByName(name);
879  if (!exists) {
880  return NULL;
881  }
882  return exists->description;
883 }
884 
886 {
887  const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
888  if (map == NULL)
889  return false;
890  SCLogDebug("map %p id %d packet? %d", map, id, map->packet);
891  return map->packet;
892 }
893 
895 {
896  const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
897  if (map == NULL)
898  return false;
899  SCLogDebug("map %p id %d mpm? %d", map, id, map->mpm);
900  return map->mpm;
901 }
902 
904  void (*SetupCallback)(const DetectEngineCtx *, Signature *))
905 {
906  BUG_ON(g_buffer_type_reg_closed);
908  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
909  BUG_ON(!exists);
910  exists->SetupCallback = SetupCallback;
911 }
912 
914  const int id, Signature *s)
915 {
916  const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
917  if (map && map->SetupCallback) {
918  map->SetupCallback(de_ctx, s);
919  }
920 }
921 
923  bool (*ValidateCallback)(const Signature *, const char **sigerror))
924 {
925  BUG_ON(g_buffer_type_reg_closed);
927  DetectBufferType *exists = DetectBufferTypeLookupByName(name);
928  BUG_ON(!exists);
929  exists->ValidateCallback = ValidateCallback;
930 }
931 
933  const int id, const Signature *s, const char **sigerror)
934 {
935  const DetectBufferType *map = DetectBufferTypeGetById(de_ctx, id);
936  if (map && map->ValidateCallback) {
937  return map->ValidateCallback(s, sigerror);
938  }
939  return true;
940 }
941 
942 int DetectBufferSetActiveList(Signature *s, const int list)
943 {
944  BUG_ON(s->init_data == NULL);
945 
946  if (s->init_data->list && s->init_data->transforms.cnt) {
947  return -1;
948  }
949  s->init_data->list = list;
950  s->init_data->list_set = true;
951 
952  return 0;
953 }
954 
956 {
957  BUG_ON(s->init_data == NULL);
958 
959  if (s->init_data->list && s->init_data->transforms.cnt) {
960  if (s->init_data->list == DETECT_SM_LIST_NOTSET ||
962  SCLogError(SC_ERR_INVALID_SIGNATURE, "previous transforms not consumed "
963  "(list: %u, transform_cnt %u)", s->init_data->list,
964  s->init_data->transforms.cnt);
965  SCReturnInt(-1);
966  }
967 
968  SCLogDebug("buffer %d has transform(s) registered: %d",
972  if (new_list == -1) {
973  SCReturnInt(-1);
974  }
975  SCLogDebug("new_list %d", new_list);
976  s->init_data->list = new_list;
977  s->init_data->list_set = false;
978  // reset transforms now that we've set up the list
979  s->init_data->transforms.cnt = 0;
980  }
981 
982  SCReturnInt(0);
983 }
984 
986 {
987  /* single buffers */
988  for (uint32_t i = 0; i < det_ctx->inspect.to_clear_idx; i++)
989  {
990  const uint32_t idx = det_ctx->inspect.to_clear_queue[i];
991  InspectionBuffer *buffer = &det_ctx->inspect.buffers[idx];
992  buffer->inspect = NULL;
993  }
994  det_ctx->inspect.to_clear_idx = 0;
995 
996  /* multi buffers */
997  for (uint32_t i = 0; i < det_ctx->multi_inspect.to_clear_idx; i++)
998  {
999  const uint32_t idx = det_ctx->multi_inspect.to_clear_queue[i];
1000  InspectionBufferMultipleForList *mbuffer = &det_ctx->multi_inspect.buffers[idx];
1001  for (uint32_t x = 0; x <= mbuffer->max; x++) {
1002  InspectionBuffer *buffer = &mbuffer->inspection_buffers[x];
1003  buffer->inspect = NULL;
1004  }
1005  mbuffer->init = 0;
1006  mbuffer->max = 0;
1007  }
1008  det_ctx->multi_inspect.to_clear_idx = 0;
1009 }
1010 
1012 {
1013  return &det_ctx->inspect.buffers[list_id];
1014 }
1015 
1016 static InspectionBufferMultipleForList *InspectionBufferGetMulti(
1017  DetectEngineThreadCtx *det_ctx, const int list_id)
1018 {
1019  InspectionBufferMultipleForList *buffer = &det_ctx->multi_inspect.buffers[list_id];
1020  if (!buffer->init) {
1021  det_ctx->multi_inspect.to_clear_queue[det_ctx->multi_inspect.to_clear_idx++] = list_id;
1022  buffer->init = 1;
1023  }
1024  return buffer;
1025 }
1026 
1027 /** \brief for a InspectionBufferMultipleForList get a InspectionBuffer
1028  * \param fb the multiple buffer array
1029  * \param local_id the index to get a buffer
1030  * \param buffer the inspect buffer or NULL in case of error */
1032  DetectEngineThreadCtx *det_ctx, const int list_id, const uint32_t local_id)
1033 {
1034  if (unlikely(local_id >= 1024)) {
1036  return NULL;
1037  }
1038 
1039  InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
1040 
1041  if (local_id >= fb->size) {
1042  uint32_t old_size = fb->size;
1043  uint32_t new_size = local_id + 1;
1044  uint32_t grow_by = new_size - old_size;
1045  SCLogDebug("size is %u, need %u, so growing by %u", old_size, new_size, grow_by);
1046 
1047  SCLogDebug("fb->inspection_buffers %p", fb->inspection_buffers);
1048  void *ptr = SCRealloc(fb->inspection_buffers, (local_id + 1) * sizeof(InspectionBuffer));
1049  if (ptr == NULL)
1050  return NULL;
1051 
1052  InspectionBuffer *to_zero = (InspectionBuffer *)ptr + old_size;
1053  SCLogDebug("ptr %p to_zero %p", ptr, to_zero);
1054  memset((uint8_t *)to_zero, 0, (grow_by * sizeof(InspectionBuffer)));
1055  fb->inspection_buffers = ptr;
1056  fb->size = new_size;
1057  }
1058 
1059  fb->max = MAX(fb->max, local_id);
1060  InspectionBuffer *buffer = &fb->inspection_buffers[local_id];
1061  SCLogDebug("using file_data buffer %p", buffer);
1062 #ifdef DEBUG_VALIDATION
1063  buffer->multi = true;
1064 #endif
1065  return buffer;
1066 }
1067 
1068 void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
1069 {
1070  memset(buffer, 0, sizeof(*buffer));
1071  buffer->buf = SCCalloc(initial_size, sizeof(uint8_t));
1072  if (buffer->buf != NULL) {
1073  buffer->size = initial_size;
1074  }
1075 }
1076 
1077 /** \brief setup the buffer with our initial data */
1079  const uint8_t *data, const uint32_t data_len)
1080 {
1081  DEBUG_VALIDATE_BUG_ON(!buffer->multi);
1082  buffer->inspect = buffer->orig = data;
1083  buffer->inspect_len = buffer->orig_len = data_len;
1084  buffer->len = 0;
1085 
1086  InspectionBufferApplyTransforms(buffer, transforms);
1087 }
1088 
1089 /** \brief setup the buffer with our initial data */
1090 void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id,
1091  InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len)
1092 {
1093  DEBUG_VALIDATE_BUG_ON(buffer->multi);
1094  if (buffer->inspect == NULL) {
1095 #ifdef UNITTESTS
1096  if (det_ctx && list_id != -1)
1097 #endif
1098  det_ctx->inspect.to_clear_queue[det_ctx->inspect.to_clear_idx++] = list_id;
1099  }
1100  buffer->inspect = buffer->orig = data;
1101  buffer->inspect_len = buffer->orig_len = data_len;
1102  buffer->len = 0;
1103 }
1104 
1106 {
1107  if (buffer->buf != NULL) {
1108  SCFree(buffer->buf);
1109  }
1110  memset(buffer, 0, sizeof(*buffer));
1111 }
1112 
1113 /**
1114  * \brief make sure that the buffer has at least 'min_size' bytes
1115  * Expand the buffer if necessary
1116  */
1117 void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
1118 {
1119  if (likely(buffer->size >= min_size))
1120  return;
1121 
1122  uint32_t new_size = (buffer->size == 0) ? 4096 : buffer->size;
1123  while (new_size < min_size) {
1124  new_size *= 2;
1125  }
1126 
1127  void *ptr = SCRealloc(buffer->buf, new_size);
1128  if (ptr != NULL) {
1129  buffer->buf = ptr;
1130  buffer->size = new_size;
1131  }
1132 }
1133 
1134 void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len)
1135 {
1136  InspectionBufferCheckAndExpand(buffer, buf_len);
1137 
1138  if (buffer->size) {
1139  uint32_t copy_size = MIN(buf_len, buffer->size);
1140  memcpy(buffer->buf, buf, copy_size);
1141  buffer->inspect = buffer->buf;
1142  buffer->inspect_len = copy_size;
1143  }
1144 }
1145 
1146 /** \brief Check content byte array compatibility with transforms
1147  *
1148  * The "content" array is presented to the transforms so that each
1149  * transform may validate that it's compatible with the transform.
1150  *
1151  * When a transform indicates the byte array is incompatible, none of the
1152  * subsequent transforms, if any, are invoked. This means the first positive
1153  * validation result terminates the loop.
1154  *
1155  * \param de_ctx Detection engine context.
1156  * \param sm_list The SM list id.
1157  * \param content The byte array being validated
1158  * \param namestr returns the name of the transform that is incompatible with
1159  * content.
1160  *
1161  * \retval true (false) If any of the transforms indicate the byte array is
1162  * (is not) compatible.
1163  **/
1165  const uint8_t *content, uint16_t content_len, const char **namestr)
1166 {
1167  const DetectBufferType *dbt = DetectBufferTypeGetById(de_ctx, sm_list);
1168  BUG_ON(dbt == NULL);
1169 
1170  for (int i = 0; i < dbt->transforms.cnt; i++) {
1171  const TransformData *t = &dbt->transforms.transforms[i];
1173  continue;
1174 
1175  if (sigmatch_table[t->transform].TransformValidate(content, content_len, t->options)) {
1176  continue;
1177  }
1178 
1179  if (namestr) {
1180  *namestr = sigmatch_table[t->transform].name;
1181  }
1182 
1183  return false;
1184  }
1185 
1186  return true;
1187 }
1188 
1190  const DetectEngineTransforms *transforms)
1191 {
1192  if (transforms) {
1193  for (int i = 0; i < DETECT_TRANSFORMS_MAX; i++) {
1194  const int id = transforms->transforms[i].transform;
1195  if (id == 0)
1196  break;
1197  BUG_ON(sigmatch_table[id].Transform == NULL);
1198  sigmatch_table[id].Transform(buffer, transforms->transforms[i].options);
1199  SCLogDebug("applied transform %s", sigmatch_table[id].name);
1200  }
1201  }
1202 }
1203 
1204 static void DetectBufferTypeSetupDetectEngine(DetectEngineCtx *de_ctx)
1205 {
1206  const int size = g_buffer_type_id;
1207  BUG_ON(!(size > 0));
1208 
1209  de_ctx->buffer_type_map = SCCalloc(size, sizeof(DetectBufferType *));
1212  SCLogDebug("de_ctx->buffer_type_map %p with %u members", de_ctx->buffer_type_map, size);
1213 
1214  SCLogDebug("DETECT_SM_LIST_DYNAMIC_START %u", DETECT_SM_LIST_DYNAMIC_START);
1215  HashListTableBucket *b = HashListTableGetListHead(g_buffer_type_hash);
1216  while (b) {
1218  de_ctx->buffer_type_map[map->id] = map;
1219  SCLogDebug("name %s id %d mpm %s packet %s -- %s. "
1220  "Callbacks: Setup %p Validate %p", map->string, map->id,
1221  map->mpm ? "true" : "false", map->packet ? "true" : "false",
1222  map->description, map->SetupCallback, map->ValidateCallback);
1223  b = HashListTableGetListNext(b);
1224  }
1225 
1227  DetectBufferTypeHashFunc,
1228  DetectBufferTypeCompareFunc,
1229  DetectBufferTypeFreeFunc);
1230  if (de_ctx->buffer_type_hash == NULL) {
1231  BUG_ON(1);
1232  }
1233  de_ctx->buffer_type_id = g_buffer_type_id;
1234 
1237  DetectAppLayerInspectEngineCopyListToDetectCtx(de_ctx);
1239  DetectPktInspectEngineCopyListToDetectCtx(de_ctx);
1240 }
1241 
1242 static void DetectBufferTypeFreeDetectEngine(DetectEngineCtx *de_ctx)
1243 {
1244  if (de_ctx) {
1245  if (de_ctx->buffer_type_map)
1247  if (de_ctx->buffer_type_hash)
1249 
1251  while (ilist) {
1253  SCFree(ilist);
1254  ilist = next;
1255  }
1257  while (mlist) {
1259  SCFree(mlist);
1260  mlist = next;
1261  }
1263  while (plist) {
1265  SCFree(plist);
1266  plist = next;
1267  }
1269  while (pmlist) {
1270  DetectBufferMpmRegistery *next = pmlist->next;
1271  SCFree(pmlist);
1272  pmlist = next;
1273  }
1275  }
1276 }
1277 
1279 {
1280  BUG_ON(g_buffer_type_hash == NULL);
1281 
1282  g_buffer_type_reg_closed = 1;
1283 }
1284 
1286  TransformData *transforms, int transform_cnt)
1287 {
1288  const DetectBufferType *base_map = DetectBufferTypeGetById(de_ctx, id);
1289  if (!base_map) {
1290  return -1;
1291  }
1292  if (!base_map->supports_transforms) {
1293  SCLogError(SC_ERR_INVALID_SIGNATURE, "buffer '%s' does not support transformations",
1294  base_map->string);
1295  return -1;
1296  }
1297 
1298  SCLogDebug("base_map %s", base_map->string);
1299 
1301  memset(&t, 0, sizeof(t));
1302  for (int i = 0; i < transform_cnt; i++) {
1303  t.transforms[i] = transforms[i];
1304  }
1305  t.cnt = transform_cnt;
1306 
1307  DetectBufferType lookup_map = { (char *)base_map->string, NULL, 0, 0, 0, 0, false, NULL, NULL, t };
1309 
1310  SCLogDebug("res %p", res);
1311  if (res != NULL) {
1312  return res->id;
1313  }
1314 
1315  DetectBufferType *map = SCCalloc(1, sizeof(*map));
1316  if (map == NULL)
1317  return -1;
1318 
1319  map->string = base_map->string;
1320  map->id = de_ctx->buffer_type_id++;
1321  map->parent_id = base_map->id;
1322  map->transforms = t;
1323  map->mpm = base_map->mpm;
1324  map->packet = base_map->packet;
1325  map->SetupCallback = base_map->SetupCallback;
1326  map->ValidateCallback = base_map->ValidateCallback;
1327  if (map->packet) {
1329  map->id, map->parent_id, &map->transforms);
1330  } else {
1332  map->id, map->parent_id, &map->transforms);
1333  }
1334 
1335  BUG_ON(HashListTableAdd(de_ctx->buffer_type_hash, (void *)map, 0) != 0);
1336  SCLogDebug("buffer %s registered with id %d, parent %d", map->string, map->id, map->parent_id);
1337 
1338  if (map->id >= 0 && (uint32_t)map->id >= de_ctx->buffer_type_map_elements) {
1339  void *ptr = SCRealloc(de_ctx->buffer_type_map, (map->id + 1) * sizeof(DetectBufferType *));
1340  BUG_ON(ptr == NULL);
1341  SCLogDebug("de_ctx->buffer_type_map resized to %u (was %u)", (map->id + 1), de_ctx->buffer_type_map_elements);
1342  de_ctx->buffer_type_map = ptr;
1343  de_ctx->buffer_type_map[map->id] = map;
1344  de_ctx->buffer_type_map_elements = map->id + 1;
1345 
1346  if (map->packet) {
1347  DetectPktInspectEngineCopy(de_ctx, map->parent_id, map->id,
1348  &map->transforms);
1349  } else {
1350  DetectAppLayerInspectEngineCopy(de_ctx, map->parent_id, map->id,
1351  &map->transforms);
1352  }
1353  }
1354  return map->id;
1355 }
1356 
1357 /* returns false if no match, true if match */
1358 static int DetectEngineInspectRulePacketMatches(
1359  DetectEngineThreadCtx *det_ctx,
1360  const DetectEnginePktInspectionEngine *engine,
1361  const Signature *s,
1362  Packet *p, uint8_t *_alert_flags)
1363 {
1364  SCEnter();
1365 
1366  /* run the packet match functions */
1368  const SigMatchData *smd = s->sm_arrays[DETECT_SM_LIST_MATCH];
1369 
1370  SCLogDebug("running match functions, sm %p", smd);
1371  while (1) {
1373  if (sigmatch_table[smd->type].Match(det_ctx, p, s, smd->ctx) <= 0) {
1374  KEYWORD_PROFILING_END(det_ctx, smd->type, 0);
1375  SCLogDebug("no match");
1376  return false;
1377  }
1378  KEYWORD_PROFILING_END(det_ctx, smd->type, 1);
1379  if (smd->is_last) {
1380  SCLogDebug("match and is_last");
1381  break;
1382  }
1383  smd++;
1384  }
1385  return true;
1386 }
1387 
1388 static int DetectEngineInspectRulePayloadMatches(
1389  DetectEngineThreadCtx *det_ctx,
1390  const DetectEnginePktInspectionEngine *engine,
1391  const Signature *s, Packet *p, uint8_t *alert_flags)
1392 {
1393  SCEnter();
1394 
1395  DetectEngineCtx *de_ctx = det_ctx->de_ctx;
1396 
1398  /* if we have stream msgs, inspect against those first,
1399  * but not for a "dsize" signature */
1400  if (s->flags & SIG_FLAG_REQUIRE_STREAM) {
1401  int pmatch = 0;
1402  if (p->flags & PKT_DETECT_HAS_STREAMDATA) {
1403  pmatch = DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, p);
1404  if (pmatch) {
1406  /* Tell the engine that this reassembled stream can drop the
1407  * rest of the pkts with no further inspection */
1408  if (s->action & ACTION_DROP)
1409  *alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
1410 
1411  *alert_flags |= PACKET_ALERT_FLAG_STREAM_MATCH;
1412  }
1413  }
1414  /* no match? then inspect packet payload */
1415  if (pmatch == 0) {
1416  SCLogDebug("no match in stream, fall back to packet payload");
1417 
1418  /* skip if we don't have to inspect the packet and segment was
1419  * added to stream */
1420  if (!(s->flags & SIG_FLAG_REQUIRE_PACKET) && (p->flags & PKT_STREAM_ADD)) {
1421  return false;
1422  }
1423  if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1424  return false;
1425  }
1426  }
1427  } else {
1428  if (DetectEngineInspectPacketPayload(de_ctx, det_ctx, s, p->flow, p) != 1) {
1429  return false;
1430  }
1431  }
1432  return true;
1433 }
1434 
1436  DetectEngineThreadCtx *det_ctx, const Signature *s,
1437  Flow *f, Packet *p,
1438  uint8_t *alert_flags)
1439 {
1440  SCEnter();
1441 
1442  for (DetectEnginePktInspectionEngine *e = s->pkt_inspect; e != NULL; e = e->next) {
1443  if (e->v1.Callback(det_ctx, e, s, p, alert_flags) == false) {
1444  SCLogDebug("sid %u: e %p Callback returned false", s->id, e);
1445  return false;
1446  }
1447  SCLogDebug("sid %u: e %p Callback returned true", s->id, e);
1448  }
1449 
1450  SCLogDebug("sid %u: returning true", s->id);
1451  return true;
1452 }
1453 
1454 /**
1455  * \param data pointer to SigMatchData. Allowed to be NULL.
1456  */
1457 static int DetectEnginePktInspectionAppend(Signature *s, InspectionBufferPktInspectFunc Callback,
1458  SigMatchData *data, const int list_id)
1459 {
1460  DetectEnginePktInspectionEngine *e = SCCalloc(1, sizeof(*e));
1461  if (e == NULL)
1462  return -1;
1463 
1464  e->mpm = (SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == list_id);
1465  e->sm_list = list_id;
1466  e->sm_list_base = list_id;
1467  e->v1.Callback = Callback;
1468  e->smd = data;
1469 
1470  if (s->pkt_inspect == NULL) {
1471  s->pkt_inspect = e;
1472  } else {
1474  while (a->next != NULL) {
1475  a = a->next;
1476  }
1477  a->next = e;
1478  }
1479  return 0;
1480 }
1481 
1483 {
1484  /* only handle PMATCH here if we're not an app inspect rule */
1486  if (DetectEnginePktInspectionAppend(
1487  s, DetectEngineInspectRulePayloadMatches, NULL, DETECT_SM_LIST_PMATCH) < 0)
1488  return -1;
1489  SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id);
1490  }
1491 
1492  if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
1493  if (DetectEnginePktInspectionAppend(
1494  s, DetectEngineInspectRulePacketMatches, NULL, DETECT_SM_LIST_MATCH) < 0)
1495  return -1;
1496  SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id);
1497  }
1498 
1499  return 0;
1500 }
1501 
1502 /* code to control the main thread to do a reload */
1503 
1505  IDLE, /**< ready to start a reload */
1506  RELOAD, /**< command main thread to do the reload */
1507 };
1508 
1509 
1510 typedef struct DetectEngineSyncer_ {
1514 
1515 static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE };
1516 
1517 /* tell main to start reloading */
1519 {
1520  int r = 0;
1521  SCMutexLock(&detect_sync.m);
1522  if (detect_sync.state == IDLE) {
1523  detect_sync.state = RELOAD;
1524  } else {
1525  r = -1;
1526  }
1527  SCMutexUnlock(&detect_sync.m);
1528  return r;
1529 }
1530 
1531 /* main thread checks this to see if it should start */
1533 {
1534  int r = 0;
1535  SCMutexLock(&detect_sync.m);
1536  if (detect_sync.state == RELOAD) {
1537  r = 1;
1538  }
1539  SCMutexUnlock(&detect_sync.m);
1540  return r;
1541 }
1542 
1543 /* main thread sets done when it's done */
1545 {
1546  SCMutexLock(&detect_sync.m);
1547  detect_sync.state = IDLE;
1548  SCMutexUnlock(&detect_sync.m);
1549 }
1550 
1551 /* caller loops this until it returns 1 */
1553 {
1554  int r = 0;
1555  SCMutexLock(&detect_sync.m);
1556  if (detect_sync.state == IDLE) {
1557  r = 1;
1558  }
1559  SCMutexUnlock(&detect_sync.m);
1560  return r;
1561 }
1562 
1563 /** \brief Do the content inspection & validation for a signature
1564  *
1565  * \param de_ctx Detection engine context
1566  * \param det_ctx Detection engine thread context
1567  * \param s Signature to inspect
1568  * \param sm SigMatch to inspect
1569  * \param f Flow
1570  * \param flags app layer flags
1571  * \param state App layer state
1572  *
1573  * \retval 0 no match
1574  * \retval 1 match
1575  */
1577  const Signature *s, const SigMatchData *smd, Flow *f, const uint8_t flags, void *alstate,
1578  void *txv, uint64_t tx_id)
1579 {
1580  SCLogDebug("running match functions, sm %p", smd);
1581  if (smd != NULL) {
1582  while (1) {
1583  int match = 0;
1585  match = sigmatch_table[smd->type].
1586  AppLayerTxMatch(det_ctx, f, flags, alstate, txv, s, smd->ctx);
1587  KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1));
1588  if (match == 0)
1590  if (match == 2) {
1592  }
1593 
1594  if (smd->is_last)
1595  break;
1596  smd++;
1597  }
1598  }
1599 
1601 }
1602 
1603 
1604 /**
1605  * \brief Do the content inspection & validation for a signature
1606  *
1607  * \param de_ctx Detection engine context
1608  * \param det_ctx Detection engine thread context
1609  * \param s Signature to inspect
1610  * \param f Flow
1611  * \param flags app layer flags
1612  * \param state App layer state
1613  *
1614  * \retval 0 no match.
1615  * \retval 1 match.
1616  * \retval 2 Sig can't match.
1617  */
1620  const DetectEngineAppInspectionEngine *engine,
1621  const Signature *s,
1622  Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
1623 {
1624  const int list_id = engine->sm_list;
1625  SCLogDebug("running inspect on %d", list_id);
1626 
1627  const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress);
1628 
1629  SCLogDebug("list %d mpm? %s transforms %p",
1630  engine->sm_list, engine->mpm ? "true" : "false", engine->v2.transforms);
1631 
1632  /* if prefilter didn't already run, we need to consider transformations */
1633  const DetectEngineTransforms *transforms = NULL;
1634  if (!engine->mpm) {
1635  transforms = engine->v2.transforms;
1636  }
1637 
1638  const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms,
1639  f, flags, txv, list_id);
1640  if (unlikely(buffer == NULL)) {
1643  }
1644 
1645  const uint32_t data_len = buffer->inspect_len;
1646  const uint8_t *data = buffer->inspect;
1647  const uint64_t offset = buffer->inspect_offset;
1648 
1649  uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0;
1650  ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0);
1651  ci_flags |= buffer->flags;
1652 
1653  det_ctx->discontinue_matching = 0;
1654  det_ctx->buffer_offset = 0;
1655  det_ctx->inspection_recursion_counter = 0;
1656 
1657  /* Inspect all the uricontents fetched on each
1658  * transaction at the app layer */
1659  int r = DetectEngineContentInspection(de_ctx, det_ctx,
1660  s, engine->smd,
1661  NULL, f,
1662  (uint8_t *)data, data_len, offset, ci_flags,
1664  if (r == 1) {
1666  } else {
1669  }
1670 }
1671 
1672 /**
1673  * \brief Do the content inspection & validation for a signature
1674  *
1675  * \param de_ctx Detection engine context
1676  * \param det_ctx Detection engine thread context
1677  * \param s Signature to inspect
1678  * \param p Packet
1679  *
1680  * \retval 0 no match.
1681  * \retval 1 match.
1682  */
1684  DetectEngineThreadCtx *det_ctx,
1685  const DetectEnginePktInspectionEngine *engine,
1686  const Signature *s, Packet *p, uint8_t *_alert_flags)
1687 {
1688  const int list_id = engine->sm_list;
1689  SCLogDebug("running inspect on %d", list_id);
1690 
1691  SCLogDebug("list %d transforms %p",
1692  engine->sm_list, engine->v1.transforms);
1693 
1694  /* if prefilter didn't already run, we need to consider transformations */
1695  const DetectEngineTransforms *transforms = NULL;
1696  if (!engine->mpm) {
1697  transforms = engine->v1.transforms;
1698  }
1699 
1700  const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p,
1701  list_id);
1702  if (unlikely(buffer == NULL)) {
1704  }
1705 
1706  const uint32_t data_len = buffer->inspect_len;
1707  const uint8_t *data = buffer->inspect;
1708  const uint64_t offset = 0;
1709 
1710  uint8_t ci_flags = DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END;
1711  ci_flags |= buffer->flags;
1712 
1713  det_ctx->discontinue_matching = 0;
1714  det_ctx->buffer_offset = 0;
1715  det_ctx->inspection_recursion_counter = 0;
1716 
1717  /* Inspect all the uricontents fetched on each
1718  * transaction at the app layer */
1719  int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx,
1720  s, engine->smd,
1721  p, p->flow,
1722  (uint8_t *)data, data_len, offset, ci_flags,
1724  if (r == 1) {
1726  } else {
1728  }
1729 }
1730 
1731 
1732 /* nudge capture loops to wake up */
1733 static void BreakCapture(void)
1734 {
1736  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1737  if ((tv->tmm_flags & TM_FLAG_RECEIVE_TM) == 0) {
1738  continue;
1739  }
1740  /* find the correct slot */
1741  for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1742  if (suricata_ctl_flags != 0) {
1744  return;
1745  }
1746 
1747  TmModule *tm = TmModuleGetById(s->tm_id);
1748  if (!(tm->flags & TM_FLAG_RECEIVE_TM)) {
1749  continue;
1750  }
1751 
1752  /* signal capture method that we need a packet. */
1754  /* if the method supports it, BreakLoop. Otherwise we rely on
1755  * the capture method's recv timeout */
1756  if (tm->PktAcqLoop && tm->PktAcqBreakLoop) {
1757  tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(s->slot_data));
1758  }
1759  break;
1760  }
1761  }
1763 }
1764 
1765 /** \internal
1766  * \brief inject a pseudo packet into each detect thread that doesn't use the
1767  * new det_ctx yet
1768  */
1769 static void InjectPackets(ThreadVars **detect_tvs,
1770  DetectEngineThreadCtx **new_det_ctx,
1771  int no_of_detect_tvs)
1772 {
1773  /* inject a fake packet if the detect thread isn't using the new ctx yet,
1774  * this speeds up the process */
1775  for (int i = 0; i < no_of_detect_tvs; i++) {
1776  if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1777  if (detect_tvs[i]->inq != NULL) {
1778  Packet *p = PacketGetFromAlloc();
1779  if (p != NULL) {
1782  PacketQueue *q = detect_tvs[i]->inq->pq;
1783  SCMutexLock(&q->mutex_q);
1784  PacketEnqueue(q, p);
1785  SCCondSignal(&q->cond_q);
1786  SCMutexUnlock(&q->mutex_q);
1787  }
1788  }
1789  }
1790  }
1791 }
1792 
1793 /** \internal
1794  * \brief Update detect threads with new detect engine
1795  *
1796  * Atomically update each detect thread with a new thread context
1797  * that is associated to the new detection engine(s).
1798  *
1799  * If called in unix socket mode, it's possible that we don't have
1800  * detect threads yet.
1801  *
1802  * \retval -1 error
1803  * \retval 0 no detection threads
1804  * \retval 1 successful reload
1805  */
1806 static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
1807 {
1808  SCEnter();
1809  uint32_t i = 0;
1810 
1811  /* count detect threads in use */
1812  uint32_t no_of_detect_tvs = TmThreadCountThreadsByTmmFlags(TM_FLAG_DETECT_TM);
1813  /* can be zero in unix socket mode */
1814  if (no_of_detect_tvs == 0) {
1815  return 0;
1816  }
1817 
1818  /* prepare swap structures */
1819  DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
1820  DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
1821  ThreadVars *detect_tvs[no_of_detect_tvs];
1822  memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1823  memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1824  memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *)));
1825 
1826  /* start the process of swapping detect threads ctxs */
1827 
1828  /* get reference to tv's and setup new_det_ctx array */
1830  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1831  if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1832  continue;
1833  }
1834  for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1835  TmModule *tm = TmModuleGetById(s->tm_id);
1836  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1837  continue;
1838  }
1839 
1840  if (suricata_ctl_flags != 0) {
1842  goto error;
1843  }
1844 
1845  old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(s->slot_data));
1846  detect_tvs[i] = tv;
1847 
1848  new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
1849  if (new_det_ctx[i] == NULL) {
1850  SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init "
1851  "failure in live rule swap. Let's get out of here");
1853  goto error;
1854  }
1855  SCLogDebug("live rule swap created new det_ctx - %p and de_ctx "
1856  "- %p\n", new_det_ctx[i], new_de_ctx);
1857  i++;
1858  break;
1859  }
1860  }
1861  BUG_ON(i != no_of_detect_tvs);
1862 
1863  /* atomically replace the det_ctx data */
1864  i = 0;
1865  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1866  if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1867  continue;
1868  }
1869  for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1870  TmModule *tm = TmModuleGetById(s->tm_id);
1871  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1872  continue;
1873  }
1874  SCLogDebug("swapping new det_ctx - %p with older one - %p",
1875  new_det_ctx[i], SC_ATOMIC_GET(s->slot_data));
1876  FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(s->slot_data), new_det_ctx[i++]);
1877  break;
1878  }
1879  }
1881 
1882  /* threads now all have new data, however they may not have started using
1883  * it and may still use the old data */
1884 
1885  SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, "
1886  "along with the new de_ctx", no_of_detect_tvs);
1887 
1888  InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs);
1889 
1890  for (i = 0; i < no_of_detect_tvs; i++) {
1891  int break_out = 0;
1892  usleep(1000);
1893  while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1894  if (suricata_ctl_flags != 0) {
1895  break_out = 1;
1896  break;
1897  }
1898 
1899  BreakCapture();
1900  usleep(1000);
1901  }
1902  if (break_out)
1903  break;
1904  SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]);
1905  }
1906 
1907  /* this is to make sure that if someone initiated shutdown during a live
1908  * rule swap, the live rule swap won't clean up the old det_ctx and
1909  * de_ctx, till all detect threads have stopped working and sitting
1910  * silently after setting RUNNING_DONE flag and while waiting for
1911  * THV_DEINIT flag */
1912  if (i != no_of_detect_tvs) { // not all threads we swapped
1913  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1914  if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1915  continue;
1916  }
1917 
1919  usleep(100);
1920  }
1921  }
1922  }
1923 
1924  /* free all the ctxs */
1925  for (i = 0; i < no_of_detect_tvs; i++) {
1926  SCLogDebug("Freeing old_det_ctx - %p used by detect",
1927  old_det_ctx[i]);
1928  DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
1929  }
1930 
1932 
1933  return 1;
1934 
1935  error:
1936  for (i = 0; i < no_of_detect_tvs; i++) {
1937  if (new_det_ctx[i] != NULL)
1938  DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]);
1939  }
1940  return -1;
1941 }
1942 
1943 static DetectEngineCtx *DetectEngineCtxInitReal(enum DetectEngineType type, const char *prefix)
1944 {
1946  if (unlikely(de_ctx == NULL))
1947  goto error;
1948 
1949  memset(de_ctx,0,sizeof(DetectEngineCtx));
1950  memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
1951  TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
1952  de_ctx->sigerror = NULL;
1953  de_ctx->type = type;
1954 
1957  SCLogDebug("stub %u with version %u", type, de_ctx->version);
1958  return de_ctx;
1959  }
1960 
1961  if (prefix != NULL) {
1962  strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix));
1963  }
1964 
1965  if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) {
1966  SCLogDebug("ConfGetBool could not load the value.");
1967  }
1968 
1971  SCLogConfig("pattern matchers: MPM: %s, SPM: %s",
1974 
1976  if (de_ctx->spm_global_thread_ctx == NULL) {
1977  SCLogDebug("Unable to alloc SpmGlobalThreadCtx.");
1978  goto error;
1979  }
1980 
1981  if (DetectEngineCtxLoadConf(de_ctx) == -1) {
1982  goto error;
1983  }
1984 
1991  DetectBufferTypeSetupDetectEngine(de_ctx);
1992 
1993  /* init iprep... ignore errors for now */
1994  (void)SRepInit(de_ctx);
1995 
1998 
1999  if (ActionInitConfig() < 0) {
2000  goto error;
2001  }
2002 
2005  SCLogDebug("dectx with version %u", de_ctx->version);
2006  return de_ctx;
2007 error:
2008  if (de_ctx != NULL) {
2010  }
2011  return NULL;
2012 
2013 }
2014 
2016 {
2017  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_MT_STUB, NULL);
2018 }
2019 
2021 {
2022  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_DD_STUB, NULL);
2023 }
2024 
2026 {
2027  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, NULL);
2028 }
2029 
2031 {
2032  if (prefix == NULL || strlen(prefix) == 0)
2033  return DetectEngineCtxInit();
2034  else
2035  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, prefix);
2036 }
2037 
2038 static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
2039 {
2041  while (item) {
2043  SCFree(item);
2044  item = next;
2045  }
2046  de_ctx->keyword_list = NULL;
2047 }
2048 
2049 static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
2050 {
2051  SigString *item = NULL;
2052  SigString *sitem;
2053 
2054  TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
2055  SCFree(item->filename);
2056  SCFree(item->sig_str);
2057  if (item->sig_error) {
2058  SCFree(item->sig_error);
2059  }
2060  TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
2061  SCFree(item);
2062  }
2063 }
2064 
2065 /**
2066  * \brief Free a DetectEngineCtx::
2067  *
2068  * \param de_ctx DetectEngineCtx:: to be freed
2069  */
2071 {
2072 
2073  if (de_ctx == NULL)
2074  return;
2075 
2076 #ifdef PROFILING
2077  if (de_ctx->profile_ctx != NULL) {
2079  de_ctx->profile_ctx = NULL;
2080  }
2081  if (de_ctx->profile_keyword_ctx != NULL) {
2082  SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx);
2083 // de_ctx->profile_keyword_ctx = NULL;
2084  }
2085  if (de_ctx->profile_sgh_ctx != NULL) {
2087  }
2089 #endif
2090 
2091  /* Normally the hashes are freed elsewhere, but
2092  * to be sure look at them again here.
2093  */
2100  if (de_ctx->sig_array)
2102 
2105 
2107 
2109 
2111 
2112  DetectEngineCtxFreeThreadKeywordData(de_ctx);
2114  DetectEngineCtxFreeFailedSigs(de_ctx);
2115 
2118 
2119  /* if we have a config prefix, remove the config from the tree */
2120  if (strlen(de_ctx->config_prefix) > 0) {
2121  /* remove config */
2123  if (node != NULL) {
2124  ConfNodeRemove(node); /* frees node */
2125  }
2126 #if 0
2127  ConfDump();
2128 #endif
2129  }
2130 
2133 
2134  DetectBufferTypeFreeDetectEngine(de_ctx);
2135  /* freed our var name hash */
2137 
2138  SCFree(de_ctx);
2139  //DetectAddressGroupPrintMemory();
2140  //DetectSigGroupPrintMemory();
2141  //DetectPortPrintMemory();
2142 }
2143 
2144 /** \brief Function that load DetectEngineCtx config for grouping sigs
2145  * used by the engine
2146  * \retval 0 if no config provided, 1 if config was provided
2147  * and loaded successfully
2148  */
2149 static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx)
2150 {
2151  uint8_t profile = ENGINE_PROFILE_MEDIUM;
2152  const char *max_uniq_toclient_groups_str = NULL;
2153  const char *max_uniq_toserver_groups_str = NULL;
2154  const char *sgh_mpm_context = NULL;
2155  const char *de_ctx_profile = NULL;
2156 
2157  (void)ConfGet("detect.profile", &de_ctx_profile);
2158  (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context);
2159 
2160  ConfNode *de_ctx_custom = ConfGetNode("detect-engine");
2161  ConfNode *opt = NULL;
2162 
2163  if (de_ctx_custom != NULL) {
2164  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2165  if (de_ctx_profile == NULL) {
2166  if (opt->val && strcmp(opt->val, "profile") == 0) {
2167  de_ctx_profile = opt->head.tqh_first->val;
2168  }
2169  }
2170 
2171  if (sgh_mpm_context == NULL) {
2172  if (opt->val && strcmp(opt->val, "sgh-mpm-context") == 0) {
2173  sgh_mpm_context = opt->head.tqh_first->val;
2174  }
2175  }
2176  }
2177  }
2178 
2179  if (de_ctx_profile != NULL) {
2180  if (strcmp(de_ctx_profile, "low") == 0 ||
2181  strcmp(de_ctx_profile, "lowest") == 0) { // legacy
2182  profile = ENGINE_PROFILE_LOW;
2183  } else if (strcmp(de_ctx_profile, "medium") == 0) {
2184  profile = ENGINE_PROFILE_MEDIUM;
2185  } else if (strcmp(de_ctx_profile, "high") == 0 ||
2186  strcmp(de_ctx_profile, "highest") == 0) { // legacy
2187  profile = ENGINE_PROFILE_HIGH;
2188  } else if (strcmp(de_ctx_profile, "custom") == 0) {
2189  profile = ENGINE_PROFILE_CUSTOM;
2190  } else {
2192  "invalid value for detect.profile: '%s'. "
2193  "Valid options: low, medium, high and custom.",
2194  de_ctx_profile);
2195  return -1;
2196  }
2197 
2198  SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
2199  } else {
2200  SCLogDebug("Profile for detection engine groups not provided "
2201  "at suricata.yaml. Using default (\"medium\").");
2202  }
2203 
2204  /* detect-engine.sgh-mpm-context option parsing */
2205  if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) {
2206  /* for now, since we still haven't implemented any intelligence into
2207  * understanding the patterns and distributing mpm_ctx across sgh */
2209 #ifdef BUILD_HYPERSCAN
2210  de_ctx->mpm_matcher == MPM_HS ||
2211 #endif
2214  } else {
2216  }
2217  } else {
2218  if (strcmp(sgh_mpm_context, "single") == 0) {
2220  } else if (strcmp(sgh_mpm_context, "full") == 0) {
2222  } else {
2223  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "You have supplied an "
2224  "invalid conf value for detect-engine.sgh-mpm-context-"
2225  "%s", sgh_mpm_context);
2226  exit(EXIT_FAILURE);
2227  }
2228  }
2229 
2230  if (run_mode == RUNMODE_UNITTEST) {
2232  }
2233 
2234  /* parse profile custom-values */
2235  opt = NULL;
2236  switch (profile) {
2237  case ENGINE_PROFILE_LOW:
2240  break;
2241 
2242  case ENGINE_PROFILE_HIGH:
2245  break;
2246 
2247  case ENGINE_PROFILE_CUSTOM:
2248  (void)ConfGet("detect.custom-values.toclient-groups",
2249  &max_uniq_toclient_groups_str);
2250  (void)ConfGet("detect.custom-values.toserver-groups",
2251  &max_uniq_toserver_groups_str);
2252 
2253  if (de_ctx_custom != NULL) {
2254  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2255  if (opt->val && strcmp(opt->val, "custom-values") == 0) {
2256  if (max_uniq_toclient_groups_str == NULL) {
2257  max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2258  (opt->head.tqh_first, "toclient-sp-groups");
2259  }
2260  if (max_uniq_toclient_groups_str == NULL) {
2261  max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2262  (opt->head.tqh_first, "toclient-groups");
2263  }
2264  if (max_uniq_toserver_groups_str == NULL) {
2265  max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2266  (opt->head.tqh_first, "toserver-dp-groups");
2267  }
2268  if (max_uniq_toserver_groups_str == NULL) {
2269  max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2270  (opt->head.tqh_first, "toserver-groups");
2271  }
2272  }
2273  }
2274  }
2275  if (max_uniq_toclient_groups_str != NULL) {
2277  strlen(max_uniq_toclient_groups_str),
2278  (const char *)max_uniq_toclient_groups_str) <= 0)
2279  {
2281 
2282  SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
2283  "toclient-groups failed, using %u",
2284  max_uniq_toclient_groups_str,
2286  }
2287  } else {
2289  }
2290  SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups);
2291 
2292  if (max_uniq_toserver_groups_str != NULL) {
2294  strlen(max_uniq_toserver_groups_str),
2295  (const char *)max_uniq_toserver_groups_str) <= 0)
2296  {
2298 
2299  SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
2300  "toserver-groups failed, using %u",
2301  max_uniq_toserver_groups_str,
2303  }
2304  } else {
2306  }
2307  SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups);
2308  break;
2309 
2310  /* Default (or no config provided) is profile medium */
2311  case ENGINE_PROFILE_MEDIUM:
2313  default:
2316  break;
2317  }
2318 
2319  intmax_t value = 0;
2320  if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1)
2321  {
2322  if (value >= 0 && value <= INT_MAX) {
2323  de_ctx->inspection_recursion_limit = (int)value;
2324  }
2325 
2326  /* fall back to old config parsing */
2327  } else {
2328  ConfNode *insp_recursion_limit_node = NULL;
2329  char *insp_recursion_limit = NULL;
2330 
2331  if (de_ctx_custom != NULL) {
2332  opt = NULL;
2333  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2334  if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0)
2335  continue;
2336 
2337  insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val);
2338  if (insp_recursion_limit_node == NULL) {
2339  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf "
2340  "entry for detect-engine:inspection-recursion-limit");
2341  break;
2342  }
2343  insp_recursion_limit = insp_recursion_limit_node->val;
2344  SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s",
2345  insp_recursion_limit_node->name, insp_recursion_limit_node->val);
2346  break;
2347  }
2348 
2349  if (insp_recursion_limit != NULL) {
2351  0, (const char *)insp_recursion_limit) < 0) {
2352  SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid value for "
2353  "detect-engine.inspection-recursion-limit: %s "
2354  "resetting to %d", insp_recursion_limit,
2358  }
2359  } else {
2362  }
2363  }
2364  }
2365 
2368 
2369  SCLogDebug("de_ctx->inspection_recursion_limit: %d",
2371 
2372  /* parse port grouping whitelisting settings */
2373 
2374  const char *ports = NULL;
2375  (void)ConfGet("detect.grouping.tcp-whitelist", &ports);
2376  if (ports) {
2377  SCLogConfig("grouping: tcp-whitelist %s", ports);
2378  } else {
2379  ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080";
2380  SCLogConfig("grouping: tcp-whitelist (default) %s", ports);
2381 
2382  }
2383  if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) {
2384  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2385  "for detect.grouping.tcp-whitelist", ports);
2386  }
2388  for ( ; x != NULL; x = x->next) {
2389  if (x->port != x->port2) {
2390  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2391  "for detect.grouping.tcp-whitelist: only single ports allowed", ports);
2393  de_ctx->tcp_whitelist = NULL;
2394  break;
2395  }
2396  }
2397 
2398  ports = NULL;
2399  (void)ConfGet("detect.grouping.udp-whitelist", &ports);
2400  if (ports) {
2401  SCLogConfig("grouping: udp-whitelist %s", ports);
2402  } else {
2403  ports = "53, 135, 5060";
2404  SCLogConfig("grouping: udp-whitelist (default) %s", ports);
2405 
2406  }
2407  if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) {
2408  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2409  "forr detect.grouping.udp-whitelist", ports);
2410  }
2411  for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) {
2412  if (x->port != x->port2) {
2413  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2414  "for detect.grouping.udp-whitelist: only single ports allowed", ports);
2416  de_ctx->udp_whitelist = NULL;
2417  break;
2418  }
2419  }
2420 
2422  const char *pf_setting = NULL;
2423  if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) {
2424  if (strcasecmp(pf_setting, "mpm") == 0) {
2426  } else if (strcasecmp(pf_setting, "auto") == 0) {
2428  }
2429  }
2430  switch (de_ctx->prefilter_setting) {
2431  case DETECT_PREFILTER_MPM:
2432  SCLogConfig("prefilter engines: MPM");
2433  break;
2434  case DETECT_PREFILTER_AUTO:
2435  SCLogConfig("prefilter engines: MPM and keywords");
2436  break;
2437  }
2438 
2439  return 0;
2440 }
2441 
2442 /*
2443  * getting & (re)setting the internal sig i
2444  */
2445 
2446 //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx)
2447 //{
2448 // return de_ctx->signum;
2449 //}
2450 
2452 {
2453  de_ctx->signum = 0;
2454 }
2455 
2456 static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2457 {
2458  const DetectEngineMasterCtx *master = &g_master_de_ctx;
2459 
2460  if (master->keyword_id > 0) {
2461  // coverity[suspicious_sizeof : FALSE]
2462  det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *));
2463  if (det_ctx->global_keyword_ctxs_array == NULL) {
2464  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2465  return TM_ECODE_FAILED;
2466  }
2467  det_ctx->global_keyword_ctxs_size = master->keyword_id;
2468 
2469  const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2470  while (item) {
2471  det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2472  if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) {
2473  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2474  "for keyword \"%s\" failed", item->name);
2475  return TM_ECODE_FAILED;
2476  }
2477  item = item->next;
2478  }
2479  }
2480  return TM_ECODE_OK;
2481 }
2482 
2483 static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2484 {
2485  if (det_ctx->global_keyword_ctxs_array == NULL ||
2486  det_ctx->global_keyword_ctxs_size == 0) {
2487  return;
2488  }
2489 
2490  const DetectEngineMasterCtx *master = &g_master_de_ctx;
2491  if (master->keyword_id > 0) {
2492  const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2493  while (item) {
2494  if (det_ctx->global_keyword_ctxs_array[item->id] != NULL)
2495  item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]);
2496 
2497  item = item->next;
2498  }
2499  det_ctx->global_keyword_ctxs_size = 0;
2501  det_ctx->global_keyword_ctxs_array = NULL;
2502  }
2503 }
2504 
2505 static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2506 {
2507  if (de_ctx->keyword_id > 0) {
2508  // coverity[suspicious_sizeof : FALSE]
2509  det_ctx->keyword_ctxs_array = SCMalloc(de_ctx->keyword_id * sizeof(void *));
2510  if (det_ctx->keyword_ctxs_array == NULL) {
2511  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2512  return TM_ECODE_FAILED;
2513  }
2514 
2515  memset(det_ctx->keyword_ctxs_array, 0x00, de_ctx->keyword_id * sizeof(void *));
2516 
2517  det_ctx->keyword_ctxs_size = de_ctx->keyword_id;
2518 
2520  while (item) {
2521  det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2522  if (det_ctx->keyword_ctxs_array[item->id] == NULL) {
2523  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2524  "for keyword \"%s\" failed", item->name);
2525  return TM_ECODE_FAILED;
2526  }
2527  item = item->next;
2528  }
2529  }
2530  return TM_ECODE_OK;
2531 }
2532 
2533 static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2534 {
2535  if (de_ctx->keyword_id > 0) {
2537  while (item) {
2538  if (det_ctx->keyword_ctxs_array[item->id] != NULL)
2539  item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
2540 
2541  item = item->next;
2542  }
2543  det_ctx->keyword_ctxs_size = 0;
2544  SCFree(det_ctx->keyword_ctxs_array);
2545  det_ctx->keyword_ctxs_array = NULL;
2546  }
2547 }
2548 
2549 /** NOTE: master MUST be locked before calling this */
2550 static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
2551 {
2552  DetectEngineMasterCtx *master = &g_master_de_ctx;
2553  DetectEngineTenantMapping *map_array = NULL;
2554  uint32_t map_array_size = 0;
2555  uint32_t map_cnt = 0;
2556  int max_tenant_id = 0;
2557  DetectEngineCtx *list = master->list;
2558  HashTable *mt_det_ctxs_hash = NULL;
2559 
2560  if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
2561  SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: "
2562  "set using multi-detect.selector");
2563  return TM_ECODE_FAILED;
2564  }
2565 
2566  uint32_t tcnt = 0;
2567  while (list) {
2568  if (list->tenant_id > max_tenant_id)
2569  max_tenant_id = list->tenant_id;
2570 
2571  list = list->next;
2572  tcnt++;
2573  }
2574 
2575  mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
2576  if (mt_det_ctxs_hash == NULL) {
2577  goto error;
2578  }
2579 
2580  if (tcnt == 0) {
2581  SCLogInfo("no tenants left, or none registered yet");
2582  } else {
2583  max_tenant_id++;
2584 
2586  while (map) {
2587  map_cnt++;
2588  map = map->next;
2589  }
2590 
2591  if (map_cnt > 0) {
2592  map_array_size = map_cnt + 1;
2593 
2594  map_array = SCCalloc(map_array_size, sizeof(*map_array));
2595  if (map_array == NULL)
2596  goto error;
2597 
2598  /* fill the array */
2599  map_cnt = 0;
2600  map = master->tenant_mapping_list;
2601  while (map) {
2602  if (map_cnt >= map_array_size) {
2603  goto error;
2604  }
2605  map_array[map_cnt].traffic_id = map->traffic_id;
2606  map_array[map_cnt].tenant_id = map->tenant_id;
2607  map_cnt++;
2608  map = map->next;
2609  }
2610 
2611  }
2612 
2613  /* set up hash for tenant lookup */
2614  list = master->list;
2615  while (list) {
2616  SCLogDebug("tenant-id %u", list->tenant_id);
2617  if (list->tenant_id != 0) {
2618  DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
2619  if (mt_det_ctx == NULL)
2620  goto error;
2621  if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) {
2622  goto error;
2623  }
2624  }
2625  list = list->next;
2626  }
2627  }
2628 
2629  det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
2630  mt_det_ctxs_hash = NULL;
2631 
2632  det_ctx->mt_det_ctxs_cnt = max_tenant_id;
2633 
2634  det_ctx->tenant_array = map_array;
2635  det_ctx->tenant_array_size = map_array_size;
2636 
2637  switch (master->tenant_selector) {
2639  SCLogDebug("TENANT_SELECTOR_UNKNOWN");
2640  break;
2641  case TENANT_SELECTOR_VLAN:
2642  det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
2643  SCLogDebug("TENANT_SELECTOR_VLAN");
2644  break;
2646  det_ctx->TenantGetId = DetectEngineTentantGetIdFromLivedev;
2647  SCLogDebug("TENANT_SELECTOR_LIVEDEV");
2648  break;
2650  det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
2651  SCLogDebug("TENANT_SELECTOR_DIRECT");
2652  break;
2653  }
2654 
2655  return TM_ECODE_OK;
2656 error:
2657  if (map_array != NULL)
2658  SCFree(map_array);
2659  if (mt_det_ctxs_hash != NULL)
2660  HashTableFree(mt_det_ctxs_hash);
2661 
2662  return TM_ECODE_FAILED;
2663 }
2664 
2665 /** \internal
2666  * \brief Helper for DetectThread setup functions
2667  */
2668 static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2669 {
2673 
2674  PmqSetup(&det_ctx->pmq);
2675 
2677  if (det_ctx->spm_thread_ctx == NULL) {
2678  return TM_ECODE_FAILED;
2679  }
2680 
2681  /* sized to the max of our sgh settings. A max setting of 0 implies that all
2682  * sgh's have: sgh->non_pf_store_cnt == 0 */
2683  if (de_ctx->non_pf_store_cnt_max > 0) {
2685  BUG_ON(det_ctx->non_pf_id_array == NULL);
2686  }
2687 
2688  /* IP-ONLY */
2690 
2691  /* DeState */
2692  if (de_ctx->sig_array_len > 0) {
2693  det_ctx->match_array_len = de_ctx->sig_array_len;
2694  det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *));
2695  if (det_ctx->match_array == NULL) {
2696  return TM_ECODE_FAILED;
2697  }
2698  memset(det_ctx->match_array, 0,
2699  det_ctx->match_array_len * sizeof(Signature *));
2700 
2702  }
2703 
2704  /* byte_extract storage */
2705  det_ctx->byte_values = SCMalloc(sizeof(*det_ctx->byte_values) *
2707  if (det_ctx->byte_values == NULL) {
2708  return TM_ECODE_FAILED;
2709  }
2710 
2711  /* Allocate space for base64 decoded data. */
2714  if (det_ctx->base64_decoded == NULL) {
2715  return TM_ECODE_FAILED;
2716  }
2718  det_ctx->base64_decoded_len = 0;
2719  }
2720 
2722  det_ctx->inspect.buffers = SCCalloc(det_ctx->inspect.buffers_size, sizeof(InspectionBuffer));
2723  if (det_ctx->inspect.buffers == NULL) {
2724  return TM_ECODE_FAILED;
2725  }
2726  det_ctx->inspect.to_clear_queue = SCCalloc(det_ctx->inspect.buffers_size, sizeof(uint32_t));
2727  if (det_ctx->inspect.to_clear_queue == NULL) {
2728  return TM_ECODE_FAILED;
2729  }
2730  det_ctx->inspect.to_clear_idx = 0;
2731 
2734  if (det_ctx->multi_inspect.buffers == NULL) {
2735  return TM_ECODE_FAILED;
2736  }
2737  det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t));
2738  if (det_ctx->multi_inspect.to_clear_queue == NULL) {
2739  return TM_ECODE_FAILED;
2740  }
2741  det_ctx->multi_inspect.to_clear_idx = 0;
2742 
2743 
2744  DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
2745  DetectEngineThreadCtxInitGlobalKeywords(det_ctx);
2746 #ifdef PROFILING
2751 #endif
2752  SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect);
2753 
2754  return TM_ECODE_OK;
2755 }
2756 
2757 /** \brief initialize thread specific detection engine context
2758  *
2759  * \note there is a special case when using delayed detect. In this case the
2760  * function is called twice per thread. The first time the rules are not
2761  * yet loaded. de_ctx->delayed_detect_initialized will be 0. The 2nd
2762  * time they will be loaded. de_ctx->delayed_detect_initialized will be 1.
2763  * This is needed to do the per thread counter registration before the
2764  * packet runtime starts. In delayed detect mode, the first call will
2765  * return a NULL ptr through the data ptr.
2766  *
2767  * \param tv ThreadVars for this thread
2768  * \param initdata pointer to de_ctx
2769  * \param data[out] pointer to store our thread detection ctx
2770  *
2771  * \retval TM_ECODE_OK if all went well
2772  * \retval TM_ECODE_FAILED on serious errors
2773  */
2774 TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
2775 {
2777  if (unlikely(det_ctx == NULL))
2778  return TM_ECODE_FAILED;
2779  memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2780 
2781  det_ctx->tv = tv;
2782  det_ctx->de_ctx = DetectEngineGetCurrent();
2783  if (det_ctx->de_ctx == NULL) {
2784 #ifdef UNITTESTS
2785  if (RunmodeIsUnittests()) {
2786  det_ctx->de_ctx = (DetectEngineCtx *)initdata;
2787  } else {
2788  DetectEngineThreadCtxDeinit(tv, det_ctx);
2789  return TM_ECODE_FAILED;
2790  }
2791 #else
2792  DetectEngineThreadCtxDeinit(tv, det_ctx);
2793  return TM_ECODE_FAILED;
2794 #endif
2795  }
2796 
2797  if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2798  det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2799  {
2800  if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2801  DetectEngineThreadCtxDeinit(tv, det_ctx);
2802  return TM_ECODE_FAILED;
2803  }
2804  }
2805 
2806  /** alert counter setup */
2807  det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2808 #ifdef PROFILING
2809  det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2810  det_ctx->counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2811  det_ctx->counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2812  det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2813 #endif
2814 
2816  if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2817  DetectEngineThreadCtxDeinit(tv, det_ctx);
2818  return TM_ECODE_FAILED;
2819  }
2820  }
2821 
2822  /* pass thread data back to caller */
2823  *data = (void *)det_ctx;
2824 
2825  return TM_ECODE_OK;
2826 }
2827 
2828 /**
2829  * \internal
2830  * \brief initialize a det_ctx for reload cases
2831  * \param new_de_ctx the new detection engine
2832  * \param mt flag to indicate if MT should be set up for this det_ctx
2833  * this should only be done for the 'root' det_ctx
2834  *
2835  * \retval det_ctx detection engine thread ctx or NULL in case of error
2836  */
2837 static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
2838  ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
2839 {
2841  if (unlikely(det_ctx == NULL))
2842  return NULL;
2843  memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2844 
2845  det_ctx->tenant_id = new_de_ctx->tenant_id;
2846  det_ctx->tv = tv;
2847  det_ctx->de_ctx = DetectEngineReference(new_de_ctx);
2848  if (det_ctx->de_ctx == NULL) {
2849  SCFree(det_ctx);
2850  return NULL;
2851  }
2852 
2853  /* most of the init happens here */
2854  if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2855  det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2856  {
2857  if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2858  DetectEngineDeReference(&det_ctx->de_ctx);
2859  SCFree(det_ctx);
2860  return NULL;
2861  }
2862  }
2863 
2864  /** alert counter setup */
2865  det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2866 #ifdef PROFILING
2867  uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2868  uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2869  uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2870  uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2871  det_ctx->counter_mpm_list = counter_mpm_list;
2872  det_ctx->counter_nonmpm_list = counter_nonmpm_list;
2873  det_ctx->counter_fnonmpm_list = counter_fnonmpm_list;
2874  det_ctx->counter_match_list = counter_match_list;
2875 #endif
2876 
2877  if (mt && DetectEngineMultiTenantEnabled()) {
2878  if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2879  DetectEngineDeReference(&det_ctx->de_ctx);
2880  SCFree(det_ctx);
2881  return NULL;
2882  }
2883  }
2884 
2885  return det_ctx;
2886 }
2887 
2888 static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
2889 {
2890 #if DEBUG
2891  SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt);
2892 
2893  SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size);
2894  SCLogDebug("STREAM MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size);
2895 
2896  SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size);
2897  SCLogDebug("STREAM SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size);
2898 #endif
2899 
2900  if (det_ctx->tenant_array != NULL) {
2901  SCFree(det_ctx->tenant_array);
2902  det_ctx->tenant_array = NULL;
2903  }
2904 
2905 #ifdef PROFILING
2909  SCProfilingSghThreadCleanup(det_ctx);
2910 #endif
2911 
2913 
2914  /** \todo get rid of this static */
2915  if (det_ctx->de_ctx != NULL) {
2916  PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
2917  PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher);
2918  PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
2919  }
2920 
2921  PmqFree(&det_ctx->pmq);
2922 
2923  if (det_ctx->spm_thread_ctx != NULL) {
2925  }
2926 
2927  if (det_ctx->non_pf_id_array != NULL)
2928  SCFree(det_ctx->non_pf_id_array);
2929 
2930  if (det_ctx->match_array != NULL)
2931  SCFree(det_ctx->match_array);
2932 
2934 
2935  if (det_ctx->byte_values != NULL)
2936  SCFree(det_ctx->byte_values);
2937 
2938  /* Decoded base64 data. */
2939  if (det_ctx->base64_decoded != NULL) {
2940  SCFree(det_ctx->base64_decoded);
2941  }
2942 
2943  if (det_ctx->inspect.buffers) {
2944  for (uint32_t i = 0; i < det_ctx->inspect.buffers_size; i++) {
2945  InspectionBufferFree(&det_ctx->inspect.buffers[i]);
2946  }
2947  SCFree(det_ctx->inspect.buffers);
2948  }
2949  if (det_ctx->inspect.to_clear_queue) {
2950  SCFree(det_ctx->inspect.to_clear_queue);
2951  }
2952  if (det_ctx->multi_inspect.buffers) {
2953  for (uint32_t i = 0; i < det_ctx->multi_inspect.buffers_size; i++) {
2955  for (uint32_t x = 0; x < fb->size; x++) {
2957  }
2959  }
2960  SCFree(det_ctx->multi_inspect.buffers);
2961  }
2962  if (det_ctx->multi_inspect.to_clear_queue) {
2964  }
2965 
2966  DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx);
2967  if (det_ctx->de_ctx != NULL) {
2968  DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
2969 #ifdef UNITTESTS
2970  if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0)
2971  DetectEngineDeReference(&det_ctx->de_ctx);
2972 #else
2973  DetectEngineDeReference(&det_ctx->de_ctx);
2974 #endif
2975  }
2976 
2978 
2979  SCFree(det_ctx);
2980 }
2981 
2983 {
2984  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
2985 
2986  if (det_ctx == NULL) {
2987  SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL");
2988  return TM_ECODE_OK;
2989  }
2990 
2991  if (det_ctx->mt_det_ctxs_hash != NULL) {
2992  HashTableFree(det_ctx->mt_det_ctxs_hash);
2993  det_ctx->mt_det_ctxs_hash = NULL;
2994  }
2995  DetectEngineThreadCtxFree(det_ctx);
2996 
2997  return TM_ECODE_OK;
2998 }
2999 
3001 {
3002  /* XXX */
3003  PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
3004  PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
3005 }
3006 
3007 /** \brief Register Thread keyword context Funcs
3008  *
3009  * \param de_ctx detection engine to register in
3010  * \param name keyword name for error printing
3011  * \param InitFunc function ptr
3012  * \param data keyword init data to pass to Func. Can be NULL.
3013  * \param FreeFunc function ptr
3014  * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct)
3015  *
3016  * \retval id for retrieval of ctx at runtime
3017  * \retval -1 on error
3018  *
3019  * \note make sure "data" remains valid and it free'd elsewhere. It's
3020  * recommended to store it in the keywords global ctx so that
3021  * it's freed when the de_ctx is freed.
3022  */
3023 int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode)
3024 {
3025  BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL);
3026 
3027  if (mode) {
3029  while (item != NULL) {
3030  if (strcmp(name, item->name) == 0) {
3031  return item->id;
3032  }
3033 
3034  item = item->next;
3035  }
3036  }
3037 
3039  if (unlikely(item == NULL))
3040  return -1;
3041  memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem));
3042 
3043  item->InitFunc = InitFunc;
3044  item->FreeFunc = FreeFunc;
3045  item->data = data;
3046  item->name = name;
3047 
3048  item->next = de_ctx->keyword_list;
3049  de_ctx->keyword_list = item;
3050  item->id = de_ctx->keyword_id++;
3051 
3052  return item->id;
3053 }
3054 
3055 /** \brief Remove Thread keyword context registration
3056  *
3057  * \param de_ctx detection engine to deregister from
3058  * \param det_ctx detection engine thread context to deregister from
3059  * \param data keyword init data to pass to Func. Can be NULL.
3060  * \param name keyword name for error printing
3061  *
3062  * \retval 1 Item unregistered
3063  * \retval 0 otherwise
3064  *
3065  * \note make sure "data" remains valid and it free'd elsewhere. It's
3066  * recommended to store it in the keywords global ctx so that
3067  * it's freed when the de_ctx is freed.
3068  */
3070  DetectEngineThreadCtx *det_ctx, void *data, const char *name)
3071 {
3072  BUG_ON(de_ctx == NULL);
3073 
3075  DetectEngineThreadKeywordCtxItem *prev_item = NULL;
3076  while (item != NULL) {
3077  if (strcmp(name, item->name) == 0 && (data == item->data)) {
3078  if (prev_item == NULL)
3079  de_ctx->keyword_list = item->next;
3080  else
3081  prev_item->next = item->next;
3082  if (det_ctx)
3083  item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
3084  SCFree(item);
3085  return 1;
3086  }
3087  prev_item = item;
3088  item = item->next;
3089  }
3090  return 0;
3091 }
3092 /** \brief Retrieve thread local keyword ctx by id
3093  *
3094  * \param det_ctx detection engine thread ctx to retrieve the ctx from
3095  * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3096  * keyword init.
3097  *
3098  * \retval ctx or NULL on error
3099  */
3101 {
3102  if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL)
3103  return NULL;
3104 
3105  return det_ctx->keyword_ctxs_array[id];
3106 }
3107 
3108 
3109 /** \brief Register Thread keyword context Funcs (Global)
3110  *
3111  * IDs stay static over reloads and between tenants
3112  *
3113  * \param name keyword name for error printing
3114  * \param InitFunc function ptr
3115  * \param FreeFunc function ptr
3116  *
3117  * \retval id for retrieval of ctx at runtime
3118  * \retval -1 on error
3119  */
3121  void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *))
3122 {
3123  int id;
3124  BUG_ON(InitFunc == NULL || FreeFunc == NULL);
3125 
3126  DetectEngineMasterCtx *master = &g_master_de_ctx;
3127 
3128  /* if already registered, return existing id */
3130  while (item != NULL) {
3131  if (strcmp(name, item->name) == 0) {
3132  id = item->id;
3133  return id;
3134  }
3135 
3136  item = item->next;
3137  }
3138 
3139  item = SCCalloc(1, sizeof(*item));
3140  if (unlikely(item == NULL)) {
3141  return -1;
3142  }
3143  item->InitFunc = InitFunc;
3144  item->FreeFunc = FreeFunc;
3145  item->name = name;
3146  item->data = data;
3147 
3148  item->next = master->keyword_list;
3149  master->keyword_list = item;
3150  item->id = master->keyword_id++;
3151 
3152  id = item->id;
3153  return id;
3154 }
3155 
3156 /** \brief Retrieve thread local keyword ctx by id
3157  *
3158  * \param det_ctx detection engine thread ctx to retrieve the ctx from
3159  * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3160  * keyword init.
3161  *
3162  * \retval ctx or NULL on error
3163  */
3165 {
3166  if (id < 0 || id > det_ctx->global_keyword_ctxs_size ||
3167  det_ctx->global_keyword_ctxs_array == NULL) {
3168  return NULL;
3169  }
3170 
3171  return det_ctx->global_keyword_ctxs_array[id];
3172 }
3173 
3174 /** \brief Check if detection is enabled
3175  * \retval bool true or false */
3177 {
3178  DetectEngineMasterCtx *master = &g_master_de_ctx;
3179  SCMutexLock(&master->lock);
3180 
3181  if (master->list == NULL) {
3182  SCMutexUnlock(&master->lock);
3183  return 0;
3184  }
3185 
3186  SCMutexUnlock(&master->lock);
3187  return 1;
3188 }
3189 
3191 {
3192  uint32_t version;
3193  DetectEngineMasterCtx *master = &g_master_de_ctx;
3194  SCMutexLock(&master->lock);
3195  version = master->version;
3196  SCMutexUnlock(&master->lock);
3197  return version;
3198 }
3199 
3201 {
3202  DetectEngineMasterCtx *master = &g_master_de_ctx;
3203  SCMutexLock(&master->lock);
3204  master->version++;
3205  SCLogDebug("master version now %u", master->version);
3206  SCMutexUnlock(&master->lock);
3207 }
3208 
3210 {
3211  DetectEngineMasterCtx *master = &g_master_de_ctx;
3212  SCMutexLock(&master->lock);
3213 
3214  DetectEngineCtx *de_ctx = master->list;
3215  while (de_ctx) {
3219  {
3220  de_ctx->ref_cnt++;
3221  SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt);
3222  SCMutexUnlock(&master->lock);
3223  return de_ctx;
3224  }
3225  de_ctx = de_ctx->next;
3226  }
3227 
3228  SCMutexUnlock(&master->lock);
3229  return NULL;
3230 }
3231 
3233 {
3234  if (de_ctx == NULL)
3235  return NULL;
3236  de_ctx->ref_cnt++;
3237  return de_ctx;
3238 }
3239 
3240 /** TODO locking? Not needed if this is a one time setting at startup */
3242 {
3243  DetectEngineMasterCtx *master = &g_master_de_ctx;
3244  return (master->multi_tenant_enabled);
3245 }
3246 
3247 /** \internal
3248  * \brief load a tenant from a yaml file
3249  *
3250  * \param tenant_id the tenant id by which the config is known
3251  * \param filename full path of a yaml file
3252  * \param loader_id id of loader thread or -1
3253  *
3254  * \retval 0 ok
3255  * \retval -1 failed
3256  */
3257 static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id)
3258 {
3259  DetectEngineCtx *de_ctx = NULL;
3260  char prefix[64];
3261 
3262  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3263 
3264 #ifdef OS_WIN32
3265  struct _stat st;
3266  if(_stat(filename, &st) != 0) {
3267 #else
3268  struct stat st;
3269  if(stat(filename, &st) != 0) {
3270 #endif /* OS_WIN32 */
3271  SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename);
3272  goto error;
3273  }
3274 
3275  de_ctx = DetectEngineGetByTenantId(tenant_id);
3276  if (de_ctx != NULL) {
3277  SCLogError(SC_ERR_MT_DUPLICATE_TENANT, "tenant %u already registered",
3278  tenant_id);
3280  goto error;
3281  }
3282 
3283  ConfNode *node = ConfGetNode(prefix);
3284  if (node == NULL) {
3285  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
3286  goto error;
3287  }
3288 
3290  if (de_ctx == NULL) {
3291  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3292  "context failed.");
3293  goto error;
3294  }
3295  SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
3296 
3298  de_ctx->tenant_id = tenant_id;
3299  de_ctx->loader_id = loader_id;
3300 
3301  if (SigLoadSignatures(de_ctx, NULL, 0) < 0) {
3302  SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
3303  goto error;
3304  }
3305 
3307 
3308  return 0;
3309 
3310 error:
3311  if (de_ctx != NULL) {
3313  }
3314  return -1;
3315 }
3316 
3317 static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt)
3318 {
3319  DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3320  if (old_de_ctx == NULL) {
3321  SCLogError(SC_ERR_INITIALIZATION, "tenant detect engine not found");
3322  return -1;
3323  }
3324 
3325  char prefix[64];
3326  snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
3327  reload_cnt++;
3328  SCLogDebug("prefix %s", prefix);
3329 
3330  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
3331  SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml");
3332  goto error;
3333  }
3334 
3335  ConfNode *node = ConfGetNode(prefix);
3336  if (node == NULL) {
3337  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
3338  goto error;
3339  }
3340 
3341  DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3342  if (new_de_ctx == NULL) {
3343  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3344  "context failed.");
3345  goto error;
3346  }
3347  SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix);
3348 
3349  new_de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
3350  new_de_ctx->tenant_id = tenant_id;
3351  new_de_ctx->loader_id = old_de_ctx->loader_id;
3352 
3353  if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) {
3354  SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
3355  goto error;
3356  }
3357 
3358  DetectEngineAddToMaster(new_de_ctx);
3359 
3360  /* move to free list */
3361  DetectEngineMoveToFreeList(old_de_ctx);
3362  DetectEngineDeReference(&old_de_ctx);
3363  return 0;
3364 
3365 error:
3366  DetectEngineDeReference(&old_de_ctx);
3367  return -1;
3368 }
3369 
3370 
3371 typedef struct TenantLoaderCtx_ {
3372  uint32_t tenant_id;
3373  int reload_cnt; /**< used by reload */
3374  const char *yaml;
3376 
3377 static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
3378 {
3379  TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3380 
3381  SCLogDebug("loader %d", loader_id);
3382  if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
3383  return -1;
3384  }
3385  return 0;
3386 }
3387 
3388 static int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml)
3389 {
3390  TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3391  if (t == NULL)
3392  return -ENOMEM;
3393 
3394  t->tenant_id = tenant_id;
3395  t->yaml = yaml;
3396 
3397  return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t);
3398 }
3399 
3400 static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id)
3401 {
3402  TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3403 
3404  SCLogDebug("loader_id %d", loader_id);
3405 
3406  if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) {
3407  return -1;
3408  }
3409  return 0;
3410 }
3411 
3412 static int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt)
3413 {
3414  DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3415  if (old_de_ctx == NULL)
3416  return -ENOENT;
3417  int loader_id = old_de_ctx->loader_id;
3418  DetectEngineDeReference(&old_de_ctx);
3419 
3420  TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3421  if (t == NULL)
3422  return -ENOMEM;
3423 
3424  t->tenant_id = tenant_id;
3425  t->yaml = yaml;
3426  t->reload_cnt = reload_cnt;
3427 
3428  SCLogDebug("loader_id %d", loader_id);
3429 
3430  return DetectLoaderQueueTask(loader_id, DetectLoaderFuncReloadTenant, t);
3431 }
3432 
3433 /** \brief Load a tenant and wait for loading to complete
3434  */
3435 int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
3436 {
3437  int r = DetectLoaderSetupLoadTenant(tenant_id, yaml);
3438  if (r < 0)
3439  return r;
3440 
3441  if (DetectLoadersSync() != 0)
3442  return -1;
3443 
3444  return 0;
3445 }
3446 
3447 /** \brief Reload a tenant and wait for loading to complete
3448  */
3449 int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
3450 {
3451  int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt);
3452  if (r < 0)
3453  return r;
3454 
3455  if (DetectLoadersSync() != 0)
3456  return -1;
3457 
3458  return 0;
3459 }
3460 
3461 static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
3462  bool failure_fatal)
3463 {
3464  ConfNode *mapping_node = NULL;
3465 
3466  int mapping_cnt = 0;
3467  if (mappings_root_node != NULL) {
3468  TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3469  ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3470  if (tenant_id_node == NULL)
3471  goto bad_mapping;
3472  ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
3473  if (device_node == NULL)
3474  goto bad_mapping;
3475 
3476  uint32_t tenant_id = 0;
3477  if (StringParseUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3478  tenant_id_node->val) < 0)
3479  {
3480  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3481  "of %s is invalid", tenant_id_node->val);
3482  goto bad_mapping;
3483  }
3484 
3485  const char *dev = device_node->val;
3486  LiveDevice *ld = LiveGetDevice(dev);
3487  if (ld == NULL) {
3488  SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s not found", dev);
3489  goto bad_mapping;
3490  }
3491 
3492  if (ld->tenant_id_set) {
3493  SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s already mapped to tenant-id %u",
3494  dev, ld->tenant_id);
3495  goto bad_mapping;
3496  }
3497 
3498  ld->tenant_id = tenant_id;
3499  ld->tenant_id_set = true;
3500 
3501  if (DetectEngineTentantRegisterLivedev(tenant_id, ld->id) != 0) {
3502  goto error;
3503  }
3504 
3505  SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
3506  mapping_cnt++;
3507  continue;
3508 
3509  bad_mapping:
3510  if (failure_fatal)
3511  goto error;
3512  }
3513  }
3514  SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
3515  return mapping_cnt;
3516 
3517 error:
3518  return 0;
3519 }
3520 
3521 static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
3522  bool failure_fatal)
3523 {
3524  ConfNode *mapping_node = NULL;
3525 
3526  int mapping_cnt = 0;
3527  if (mappings_root_node != NULL) {
3528  TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3529  ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3530  if (tenant_id_node == NULL)
3531  goto bad_mapping;
3532  ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
3533  if (vlan_id_node == NULL)
3534  goto bad_mapping;
3535 
3536  uint32_t tenant_id = 0;
3537  if (StringParseUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3538  tenant_id_node->val) < 0)
3539  {
3540  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3541  "of %s is invalid", tenant_id_node->val);
3542  goto bad_mapping;
3543  }
3544 
3545  uint16_t vlan_id = 0;
3546  if (StringParseUint16(&vlan_id, 10, strlen(vlan_id_node->val),
3547  vlan_id_node->val) < 0)
3548  {
3550  "of %s is invalid", vlan_id_node->val);
3551  goto bad_mapping;
3552  }
3553  if (vlan_id == 0 || vlan_id >= 4095) {
3555  "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
3556  goto bad_mapping;
3557  }
3558 
3559  if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
3560  goto error;
3561  }
3562  SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
3563  mapping_cnt++;
3564  continue;
3565 
3566  bad_mapping:
3567  if (failure_fatal)
3568  goto error;
3569  }
3570  }
3571  return mapping_cnt;
3572 
3573 error:
3574  return 0;
3575 }
3576 
3577 /**
3578  * \brief setup multi-detect / multi-tenancy
3579  *
3580  * See if MT is enabled. If so, setup the selector, tenants and mappings.
3581  * Tenants and mappings are optional, and can also dynamically be added
3582  * and removed from the unix socket.
3583  */
3585 {
3587  DetectEngineMasterCtx *master = &g_master_de_ctx;
3588 
3589  int unix_socket = ConfUnixSocketIsEnable();
3590 
3591  int failure_fatal = 0;
3592  (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal);
3593 
3594  int enabled = 0;
3595  (void)ConfGetBool("multi-detect.enabled", &enabled);
3596  if (enabled == 1) {
3601 
3602  SCMutexLock(&master->lock);
3603  master->multi_tenant_enabled = 1;
3604 
3605  const char *handler = NULL;
3606  if (ConfGet("multi-detect.selector", &handler) == 1) {
3607  SCLogConfig("multi-tenant selector type %s", handler);
3608 
3609  if (strcmp(handler, "vlan") == 0) {
3610  tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
3611 
3612  int vlanbool = 0;
3613  if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
3614  SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, "
3615  "can't use multi-detect selector 'vlan'");
3616  SCMutexUnlock(&master->lock);
3617  goto error;
3618  }
3619 
3620  } else if (strcmp(handler, "direct") == 0) {
3621  tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
3622  } else if (strcmp(handler, "device") == 0) {
3623  tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
3624  if (EngineModeIsIPS()) {
3626  "multi-tenant 'device' mode not supported for IPS");
3627  SCMutexUnlock(&master->lock);
3628  goto error;
3629  }
3630 
3631  } else {
3632  SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
3633  "multi-detect.selector", handler);
3634  SCMutexUnlock(&master->lock);
3635  goto error;
3636  }
3637  }
3638  SCMutexUnlock(&master->lock);
3639  SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler);
3640 
3641  /* traffic -- tenant mappings */
3642  ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
3643 
3644  if (tenant_selector == TENANT_SELECTOR_VLAN) {
3645  int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
3646  failure_fatal);
3647  if (mapping_cnt == 0) {
3648  /* no mappings are valid when we're in unix socket mode,
3649  * they can be added on the fly. Otherwise warn/error
3650  * depending on failure_fatal */
3651 
3652  if (unix_socket) {
3653  SCLogNotice("no tenant traffic mappings defined, "
3654  "tenants won't be used until mappings are added");
3655  } else {
3656  if (failure_fatal) {
3657  SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3658  goto error;
3659  } else {
3660  SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3661  }
3662  }
3663  }
3664  } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
3665  int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
3666  failure_fatal);
3667  if (mapping_cnt == 0) {
3668  if (failure_fatal) {
3669  SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3670  goto error;
3671  } else {
3672  SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3673  }
3674  }
3675  }
3676 
3677  /* tenants */
3678  ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants");
3679  ConfNode *tenant_node = NULL;
3680 
3681  if (tenants_root_node != NULL) {
3682  TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
3683  ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id");
3684  if (id_node == NULL) {
3685  goto bad_tenant;
3686  }
3687  ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml");
3688  if (yaml_node == NULL) {
3689  goto bad_tenant;
3690  }
3691 
3692  uint32_t tenant_id = 0;
3693  if (StringParseUint32(&tenant_id, 10, strlen(id_node->val),
3694  id_node->val) < 0)
3695  {
3696  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id "
3697  "of %s is invalid", id_node->val);
3698  goto bad_tenant;
3699  }
3700  SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val);
3701 
3702  /* setup the yaml in this loop so that it's not done by the loader
3703  * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
3704  char prefix[64];
3705  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3706  if (ConfYamlLoadFileWithPrefix(yaml_node->val, prefix) != 0) {
3707  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", yaml_node->val);
3708  goto bad_tenant;
3709  }
3710 
3711  int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val);
3712  if (r < 0) {
3713  /* error logged already */
3714  goto bad_tenant;
3715  }
3716  continue;
3717 
3718  bad_tenant:
3719  if (failure_fatal)
3720  goto error;
3721  }
3722  }
3723 
3724  /* wait for our loaders to complete their tasks */
3725  if (DetectLoadersSync() != 0) {
3726  goto error;
3727  }
3728 
3730 
3731  } else {
3732  SCLogDebug("multi-detect not enabled (multi tenancy)");
3733  }
3734  return 0;
3735 error:
3736  return -1;
3737 }
3738 
3739 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)
3740 {
3741  const DetectEngineThreadCtx *det_ctx = ctx;
3742  uint32_t x = 0;
3743  uint32_t vlan_id = 0;
3744 
3745  if (p->vlan_idx == 0)
3746  return 0;
3747 
3748  vlan_id = p->vlan_id[0];
3749 
3750  if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0)
3751  return 0;
3752 
3753  /* not very efficient, but for now we're targeting only limited amounts.
3754  * Can use hash/tree approach later. */
3755  for (x = 0; x < det_ctx->tenant_array_size; x++) {
3756  if (det_ctx->tenant_array[x].traffic_id == vlan_id)
3757  return det_ctx->tenant_array[x].tenant_id;
3758  }
3759 
3760  return 0;
3761 }
3762 
3763 static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p)
3764 {
3765  const DetectEngineThreadCtx *det_ctx = ctx;
3766  const LiveDevice *ld = p->livedev;
3767 
3768  if (ld == NULL || det_ctx == NULL)
3769  return 0;
3770 
3771  SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
3772  return ld->tenant_id;
3773 }
3774 
3775 static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector,
3776  uint32_t tenant_id, uint32_t traffic_id)
3777 {
3778  DetectEngineMasterCtx *master = &g_master_de_ctx;
3779  SCMutexLock(&master->lock);
3780 
3781  if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) {
3782  SCLogInfo("conflicting selector already set");
3783  SCMutexUnlock(&master->lock);
3784  return -1;
3785  }
3786 
3788  while (m) {
3789  if (m->traffic_id == traffic_id) {
3790  SCLogInfo("traffic id already registered");
3791  SCMutexUnlock(&master->lock);
3792  return -1;
3793  }
3794  m = m->next;
3795  }
3796 
3797  DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map));
3798  if (map == NULL) {
3799  SCLogInfo("memory fail");
3800  SCMutexUnlock(&master->lock);
3801  return -1;
3802  }
3803  map->traffic_id = traffic_id;
3804  map->tenant_id = tenant_id;
3805 
3806  map->next = master->tenant_mapping_list;
3807  master->tenant_mapping_list = map;
3808 
3809  master->tenant_selector = selector;
3810 
3811  SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
3812  SCMutexUnlock(&master->lock);
3813  return 0;
3814 }
3815 
3816 static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelectors selector,
3817  uint32_t tenant_id, uint32_t traffic_id)
3818 {
3819  DetectEngineMasterCtx *master = &g_master_de_ctx;
3820  SCMutexLock(&master->lock);
3821 
3822  if (master->tenant_mapping_list == NULL) {
3823  SCMutexUnlock(&master->lock);
3824  return -1;
3825  }
3826 
3827  DetectEngineTenantMapping *prev = NULL;
3829  while (map) {
3830  if (map->traffic_id == traffic_id &&
3831  map->tenant_id == tenant_id)
3832  {
3833  if (prev != NULL)
3834  prev->next = map->next;
3835  else
3836  master->tenant_mapping_list = map->next;
3837 
3838  map->next = NULL;
3839  SCFree(map);
3840  SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id);
3841  SCMutexUnlock(&master->lock);
3842  return 0;
3843  }
3844  prev = map;
3845  map = map->next;
3846  }
3847 
3848  SCMutexUnlock(&master->lock);
3849  return -1;
3850 }
3851 
3852 int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
3853 {
3854  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
3855 }
3856 
3857 int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3858 {
3859  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3860 }
3861 
3862 int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3863 {
3864  return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3865 }
3866 
3868 {
3869  SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3870  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3871 }
3872 
3874 {
3875  SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3876  return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3877 }
3878 
3879 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p)
3880 {
3881  return p->pcap_v.tenant_id;
3882 }
3883 
3885 {
3886  DetectEngineMasterCtx *master = &g_master_de_ctx;
3887  SCMutexLock(&master->lock);
3888 
3889  if (master->list == NULL) {
3890  SCMutexUnlock(&master->lock);
3891  return NULL;
3892  }
3893 
3894  DetectEngineCtx *de_ctx = master->list;
3895  while (de_ctx) {
3897  de_ctx->tenant_id == tenant_id)
3898  {
3899  de_ctx->ref_cnt++;
3900  break;
3901  }
3902 
3903  de_ctx = de_ctx->next;
3904  }
3905 
3906  SCMutexUnlock(&master->lock);
3907  return de_ctx;
3908 }
3909 
3911 {
3912  BUG_ON((*de_ctx)->ref_cnt == 0);
3913  (*de_ctx)->ref_cnt--;
3914  *de_ctx = NULL;
3915 }
3916 
3917 static int DetectEngineAddToList(DetectEngineCtx *instance)
3918 {
3919  DetectEngineMasterCtx *master = &g_master_de_ctx;
3920 
3921  if (instance == NULL)
3922  return -1;
3923 
3924  if (master->list == NULL) {
3925  master->list = instance;
3926  } else {
3927  instance->next = master->list;
3928  master->list = instance;
3929  }
3930 
3931  return 0;
3932 }
3933 
3935 {
3936  int r;
3937 
3938  if (de_ctx == NULL)
3939  return -1;
3940 
3941  SCLogDebug("adding de_ctx %p to master", de_ctx);
3942 
3943  DetectEngineMasterCtx *master = &g_master_de_ctx;
3944  SCMutexLock(&master->lock);
3945  r = DetectEngineAddToList(de_ctx);
3946  SCMutexUnlock(&master->lock);
3947  return r;
3948 }
3949 
3951 {
3952  DetectEngineMasterCtx *master = &g_master_de_ctx;
3953 
3954  SCMutexLock(&master->lock);
3955  DetectEngineCtx *instance = master->list;
3956  if (instance == NULL) {
3957  SCMutexUnlock(&master->lock);
3958  return -1;
3959  }
3960 
3961  /* remove from active list */
3962  if (instance == de_ctx) {
3963  master->list = instance->next;
3964  } else {
3965  DetectEngineCtx *prev = instance;
3966  instance = instance->next; /* already checked first element */
3967 
3968  while (instance) {
3969  DetectEngineCtx *next = instance->next;
3970 
3971  if (instance == de_ctx) {
3972  prev->next = instance->next;
3973  break;
3974  }
3975 
3976  prev = instance;
3977  instance = next;
3978  }
3979  if (instance == NULL) {
3980  SCMutexUnlock(&master->lock);
3981  return -1;
3982  }
3983  }
3984 
3985  /* instance is now detached from list */
3986  instance->next = NULL;
3987 
3988  /* add to free list */
3989  if (master->free_list == NULL) {
3990  master->free_list = instance;
3991  } else {
3992  instance->next = master->free_list;
3993  master->free_list = instance;
3994  }
3995  SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt);
3996 
3997  SCMutexUnlock(&master->lock);
3998  return 0;
3999 }
4000 
4002 {
4003  DetectEngineMasterCtx *master = &g_master_de_ctx;
4004  SCMutexLock(&master->lock);
4005 
4006  DetectEngineCtx *prev = NULL;
4007  DetectEngineCtx *instance = master->free_list;
4008  while (instance) {
4009  DetectEngineCtx *next = instance->next;
4010 
4011  SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
4012 
4013  if (instance->ref_cnt == 0) {
4014  if (prev == NULL) {
4015  master->free_list = next;
4016  } else {
4017  prev->next = next;
4018  }
4019 
4020  SCLogDebug("freeing detect engine %p", instance);
4021  DetectEngineCtxFree(instance);
4022  instance = NULL;
4023  }
4024 
4025  prev = instance;
4026  instance = next;
4027  }
4028  SCMutexUnlock(&master->lock);
4029 }
4030 
4031 static int reloads = 0;
4032 
4033 /** \brief Reload the detection engine
4034  *
4035  * \param filename YAML file to load for the detect config
4036  *
4037  * \retval -1 error
4038  * \retval 0 ok
4039  */
4041 {
4042  DetectEngineCtx *new_de_ctx = NULL;
4043  DetectEngineCtx *old_de_ctx = NULL;
4044 
4045  char prefix[128];
4046  memset(prefix, 0, sizeof(prefix));
4047 
4048  SCLogNotice("rule reload starting");
4049 
4050  if (suri->conf_filename != NULL) {
4051  snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++);
4052  if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) {
4053  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s",
4054  suri->conf_filename);
4055  return -1;
4056  }
4057 
4058  ConfNode *node = ConfGetNode(prefix);
4059  if (node == NULL) {
4060  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s",
4061  suri->conf_filename);
4062  return -1;
4063  }
4064 #if 0
4065  ConfDump();
4066 #endif
4067  }
4068 
4069  /* get a reference to the current de_ctx */
4070  old_de_ctx = DetectEngineGetCurrent();
4071  if (old_de_ctx == NULL)
4072  return -1;
4073  SCLogDebug("get ref to old_de_ctx %p", old_de_ctx);
4074  DatasetReload();
4075 
4076  /* only reload a regular 'normal' and 'delayed detect stub' detect engines */
4077  if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
4078  old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB))
4079  {
4080  DetectEngineDeReference(&old_de_ctx);
4081  SCLogNotice("rule reload complete");
4082  return -1;
4083  }
4084 
4085  /* get new detection engine */
4086  new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
4087  if (new_de_ctx == NULL) {
4088  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
4089  "context failed.");
4090  DetectEngineDeReference(&old_de_ctx);
4091  return -1;
4092  }
4093  if (SigLoadSignatures(new_de_ctx,
4094  suri->sig_file, suri->sig_file_exclusive) != 0) {
4095  DetectEngineCtxFree(new_de_ctx);
4096  DetectEngineDeReference(&old_de_ctx);
4097  return -1;
4098  }
4099  SCLogDebug("set up new_de_ctx %p", new_de_ctx);
4100 
4101  /* add to master */
4102  DetectEngineAddToMaster(new_de_ctx);
4103 
4104  /* move to old free list */
4105  DetectEngineMoveToFreeList(old_de_ctx);
4106  DetectEngineDeReference(&old_de_ctx);
4107 
4108  SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx);
4109  /* update the threads */
4110  DetectEngineReloadThreads(new_de_ctx);
4111  SCLogDebug("threads now run new_de_ctx %p", new_de_ctx);
4112 
4113  /* walk free list, freeing the old_de_ctx */
4115 
4117 
4119 
4120  SCLogDebug("old_de_ctx should have been freed");
4121 
4122  SCLogNotice("rule reload complete");
4123  return 0;
4124 }
4125 
4126 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len)
4127 {
4128  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
4129  return det_ctx->tenant_id % h->array_size;
4130 }
4131 
4132 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len)
4133 {
4136  return (det1->tenant_id == det2->tenant_id);
4137 }
4138 
4139 static void TenantIdFree(void *d)
4140 {
4141  DetectEngineThreadCtxFree(d);
4142 }
4143 
4145 {
4146  DetectEngineMasterCtx *master = &g_master_de_ctx;
4147  SCMutexLock(&master->lock);
4148 
4149  if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
4150  SCLogInfo("error, no tenant selector");
4151  SCMutexUnlock(&master->lock);
4152  return -1;
4153  }
4154 
4155  DetectEngineCtx *stub_de_ctx = NULL;
4156  DetectEngineCtx *list = master->list;
4157  for ( ; list != NULL; list = list->next) {
4158  SCLogDebug("list %p tenant %u", list, list->tenant_id);
4159 
4160  if (list->type == DETECT_ENGINE_TYPE_NORMAL ||
4161  list->type == DETECT_ENGINE_TYPE_MT_STUB ||
4163  {
4164  stub_de_ctx = list;
4165  break;
4166  }
4167  }
4168  if (stub_de_ctx == NULL) {
4169  stub_de_ctx = DetectEngineCtxInitStubForMT();
4170  if (stub_de_ctx == NULL) {
4171  SCMutexUnlock(&master->lock);
4172  return -1;
4173  }
4174 
4175  if (master->list == NULL) {
4176  master->list = stub_de_ctx;
4177  } else {
4178  stub_de_ctx->next = master->list;
4179  master->list = stub_de_ctx;
4180  }
4181  }
4182 
4183  /* update the threads */
4184  SCLogDebug("MT reload starting");
4185  DetectEngineReloadThreads(stub_de_ctx);
4186  SCLogDebug("MT reload done");
4187 
4188  SCMutexUnlock(&master->lock);
4189 
4190  /* walk free list, freeing the old_de_ctx */
4192 
4193  SCLogDebug("old_de_ctx should have been freed");
4194  return 0;
4195 }
4196 
4197 static int g_parse_metadata = 0;
4198 
4200 {
4201  g_parse_metadata = 1;
4202 }
4203 
4205 {
4206  g_parse_metadata = 0;
4207 }
4208 
4210 {
4211  return g_parse_metadata;
4212 }
4213 
4215 {
4216  switch (type) {
4217  case DETECT_SM_LIST_MATCH:
4218  return "packet";
4219  case DETECT_SM_LIST_PMATCH:
4220  return "packet/stream payload";
4221 
4222  case DETECT_SM_LIST_TMATCH:
4223  return "tag";
4224 
4226  return "base64_data";
4227 
4229  return "post-match";
4230 
4232  return "suppress";
4234  return "threshold";
4235 
4236  case DETECT_SM_LIST_MAX:
4237  return "max (internal)";
4238  }
4239  return "error";
4240 }
4241 
4242 /* events api */
4244 {
4246  det_ctx->events++;
4247 }
4248 
4250 {
4251  return det_ctx->decoder_events;
4252 }
4253 
4254 int DetectEngineGetEventInfo(const char *event_name, int *event_id,
4255  AppLayerEventType *event_type)
4256 {
4257  *event_id = SCMapEnumNameToValue(event_name, det_ctx_event_table);
4258  if (*event_id == -1) {
4259  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
4260  "det_ctx's enum map table.", event_name);
4261  /* this should be treated as fatal */
4262  return -1;
4263  }
4264  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
4265 
4266  return 0;
4267 }
4268 
4269 /*************************************Unittest*********************************/
4270 
4271 #ifdef UNITTESTS
4272 
4273 static int DetectEngineInitYamlConf(const char *conf)
4274 {
4276  ConfInit();
4277  return ConfYamlLoadString(conf, strlen(conf));
4278 }
4279 
4280 static void DetectEngineDeInitYamlConf(void)
4281 {
4282  ConfDeInit();
4284 
4285  return;
4286 }
4287 
4288 static int DetectEngineTest01(void)
4289 {
4290  const char *conf =
4291  "%YAML 1.1\n"
4292  "---\n"
4293  "detect-engine:\n"
4294  " - profile: medium\n"
4295  " - custom-values:\n"
4296  " toclient_src_groups: 2\n"
4297  " toclient_dst_groups: 2\n"
4298  " toclient_sp_groups: 2\n"
4299  " toclient_dp_groups: 3\n"
4300  " toserver_src_groups: 2\n"
4301  " toserver_dst_groups: 4\n"
4302  " toserver_sp_groups: 2\n"
4303  " toserver_dp_groups: 25\n"
4304  " - inspection-recursion-limit: 0\n";
4305 
4306  DetectEngineCtx *de_ctx = NULL;
4307  int result = 0;
4308 
4309  if (DetectEngineInitYamlConf(conf) == -1)
4310  return 0;
4312  if (de_ctx == NULL)
4313  goto end;
4314 
4315  result = (de_ctx->inspection_recursion_limit == -1);
4316 
4317  end:
4318  if (de_ctx != NULL)
4320 
4321  DetectEngineDeInitYamlConf();
4322 
4323  return result;
4324 }
4325 
4326 static int DetectEngineTest02(void)
4327 {
4328  const char *conf =
4329  "%YAML 1.1\n"
4330  "---\n"
4331  "detect-engine:\n"
4332  " - profile: medium\n"
4333  " - custom-values:\n"
4334  " toclient_src_groups: 2\n"
4335  " toclient_dst_groups: 2\n"
4336  " toclient_sp_groups: 2\n"
4337  " toclient_dp_groups: 3\n"
4338  " toserver_src_groups: 2\n"
4339  " toserver_dst_groups: 4\n"
4340  " toserver_sp_groups: 2\n"
4341  " toserver_dp_groups: 25\n"
4342  " - inspection-recursion-limit:\n";
4343 
4344  DetectEngineCtx *de_ctx = NULL;
4345  int result = 0;
4346 
4347  if (DetectEngineInitYamlConf(conf) == -1)
4348  return 0;
4350  if (de_ctx == NULL)
4351  goto end;
4352 
4354 
4355  end:
4356  if (de_ctx != NULL)
4358 
4359  DetectEngineDeInitYamlConf();
4360 
4361  return result;
4362 }
4363 
4364 static int DetectEngineTest03(void)
4365 {
4366  const char *conf =
4367  "%YAML 1.1\n"
4368  "---\n"
4369  "detect-engine:\n"
4370  " - profile: medium\n"
4371  " - custom-values:\n"
4372  " toclient_src_groups: 2\n"
4373  " toclient_dst_groups: 2\n"
4374  " toclient_sp_groups: 2\n"
4375  " toclient_dp_groups: 3\n"
4376  " toserver_src_groups: 2\n"
4377  " toserver_dst_groups: 4\n"
4378  " toserver_sp_groups: 2\n"
4379  " toserver_dp_groups: 25\n";
4380 
4381  DetectEngineCtx *de_ctx = NULL;
4382  int result = 0;
4383 
4384  if (DetectEngineInitYamlConf(conf) == -1)
4385  return 0;
4387  if (de_ctx == NULL)
4388  goto end;
4389 
4390  result = (de_ctx->inspection_recursion_limit ==
4392 
4393  end:
4394  if (de_ctx != NULL)
4396 
4397  DetectEngineDeInitYamlConf();
4398 
4399  return result;
4400 }
4401 
4402 static int DetectEngineTest04(void)
4403 {
4404  const char *conf =
4405  "%YAML 1.1\n"
4406  "---\n"
4407  "detect-engine:\n"
4408  " - profile: medium\n"
4409  " - custom-values:\n"
4410  " toclient_src_groups: 2\n"
4411  " toclient_dst_groups: 2\n"
4412  " toclient_sp_groups: 2\n"
4413  " toclient_dp_groups: 3\n"
4414  " toserver_src_groups: 2\n"
4415  " toserver_dst_groups: 4\n"
4416  " toserver_sp_groups: 2\n"
4417  " toserver_dp_groups: 25\n"
4418  " - inspection-recursion-limit: 10\n";
4419 
4420  DetectEngineCtx *de_ctx = NULL;
4421  int result = 0;
4422 
4423  if (DetectEngineInitYamlConf(conf) == -1)
4424  return 0;
4426  if (de_ctx == NULL)
4427  goto end;
4428 
4429  result = (de_ctx->inspection_recursion_limit == 10);
4430 
4431  end:
4432  if (de_ctx != NULL)
4434 
4435  DetectEngineDeInitYamlConf();
4436 
4437  return result;
4438 }
4439 
4440 static int DetectEngineTest08(void)
4441 {
4442  const char *conf =
4443  "%YAML 1.1\n"
4444  "---\n"
4445  "detect-engine:\n"
4446  " - profile: custom\n"
4447  " - custom-values:\n"
4448  " toclient-groups: 23\n"
4449  " toserver-groups: 27\n";
4450 
4451  DetectEngineCtx *de_ctx = NULL;
4452  int result = 0;
4453 
4454  if (DetectEngineInitYamlConf(conf) == -1)
4455  return 0;
4457  if (de_ctx == NULL)
4458  goto end;
4459 
4460  if (de_ctx->max_uniq_toclient_groups == 23 &&
4462  result = 1;
4463 
4464  end:
4465  if (de_ctx != NULL)
4467 
4468  DetectEngineDeInitYamlConf();
4469 
4470  return result;
4471 }
4472 
4473 /** \test bug 892 bad values */
4474 static int DetectEngineTest09(void)
4475 {
4476  const char *conf =
4477  "%YAML 1.1\n"
4478  "---\n"
4479  "detect-engine:\n"
4480  " - profile: custom\n"
4481  " - custom-values:\n"
4482  " toclient-groups: BA\n"
4483  " toserver-groups: BA\n"
4484  " - inspection-recursion-limit: 10\n";
4485 
4486  DetectEngineCtx *de_ctx = NULL;
4487  int result = 0;
4488 
4489  if (DetectEngineInitYamlConf(conf) == -1)
4490  return 0;
4492  if (de_ctx == NULL)
4493  goto end;
4494 
4495  if (de_ctx->max_uniq_toclient_groups == 20 &&
4497  result = 1;
4498 
4499  end:
4500  if (de_ctx != NULL)
4502 
4503  DetectEngineDeInitYamlConf();
4504 
4505  return result;
4506 }
4507 
4508 #endif
4509 
4511 {
4512 #ifdef UNITTESTS
4513  UtRegisterTest("DetectEngineTest01", DetectEngineTest01);
4514  UtRegisterTest("DetectEngineTest02", DetectEngineTest02);
4515  UtRegisterTest("DetectEngineTest03", DetectEngineTest03);
4516  UtRegisterTest("DetectEngineTest04", DetectEngineTest04);
4517  UtRegisterTest("DetectEngineTest08", DetectEngineTest08);
4518  UtRegisterTest("DetectEngineTest09", DetectEngineTest09);
4519 #endif
4520  return;
4521 }
DetectEngineThreadCtx_::byte_values
uint64_t * byte_values
Definition: detect.h:1112
DetectEngineAppInspectionEngine_::stream
bool stream
Definition: detect.h:402
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
DE_STATE_ID_FILE_INSPECT
#define DE_STATE_ID_FILE_INSPECT
Definition: detect-engine-state.h:60
SCProfilingSghThreadCleanup
void SCProfilingSghThreadCleanup(DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-rulegroups.c:356
DetectEngineTenantMapping_
Definition: detect.h:1411
util-byte.h
tm-threads.h
ConfGetInt
int ConfGetInt(const char *name, intmax_t *val)
Retrieve a configuration value as an integer.
Definition: conf.c:436
DetectEngineCtx_::tenant_id
int tenant_id
Definition: detect.h:761
DetectEngineAppInspectionEngine_
Definition: detect.h:397
DetectBufferType_::supports_transforms
bool supports_transforms
Definition: detect.h:426
DetectEngineSyncer_::m
SCMutex m
Definition: detect-engine.c:1511
DetectEngineAppInspectionEngine_::mpm
bool mpm
Definition: detect.h:401
DetectBufferType_::mpm
bool mpm
Definition: detect.h:424
detect-content.h
DetectEngineThreadCtx_::buffer_offset
uint32_t buffer_offset
Definition: detect.h:1032
DetectEngineIPOnlyThreadDeinit
void DetectEngineIPOnlyThreadDeinit(DetectEngineIPOnlyThreadCtx *io_tctx)
Deinitialize the IP Only thread detection engine context.
Definition: detect-engine-iponly.c:962
detect-engine.h
DetectEngineResetMaxSigId
void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:2451
DetectEngineMTApply
int DetectEngineMTApply(void)
Definition: detect-engine.c:4144
StringParseUint16
int StringParseUint16(uint16_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:336
SCProfilingKeywordDestroyCtx
void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx)
Definition: util-profiling-keywords.c:277
PACKET_ALERT_FLAG_STREAM_MATCH
#define PACKET_ALERT_FLAG_STREAM_MATCH
Definition: decode.h:292
DETECT_SM_LIST_PMATCH
@ DETECT_SM_LIST_PMATCH
Definition: detect.h:90
DetectEngineThreadCtx_::to_clear_idx
uint32_t to_clear_idx
Definition: detect.h:1053
DetectEngineTentantRegisterPcapFile
int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id)
Definition: detect-engine.c:3867
SC_ERR_MT_DUPLICATE_TENANT
@ SC_ERR_MT_DUPLICATE_TENANT
Definition: util-error.h:300
SCProfilingKeywordThreadCleanup
void SCProfilingKeywordThreadCleanup(DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-keywords.c:350
SCProfilingSghThreadSetup
void SCProfilingSghThreadSetup(SCProfileSghDetectCtx *ctx, DetectEngineThreadCtx *det_ctx)
Definition: util-profiling-rulegroups.c:319
DetectParseDupSigHashInit
int DetectParseDupSigHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:2181
SignatureInitData_::list_set
bool list_set
Definition: detect.h:495
RELOAD
@ RELOAD
Definition: detect-engine.c:1506
DetectLoaderThreadSpawn
void DetectLoaderThreadSpawn(void)
spawn the detect loader manager thread
Definition: detect-engine-loader.c:618
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
DetectEngineDeReference
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
Definition: detect-engine.c:3910
DETECT_CI_FLAGS_START
#define DETECT_CI_FLAGS_START
Definition: detect-engine-content-inspection.h:38
LiveDevice_::id
int id
Definition: util-device.h:45
RUNMODE_UNITTEST
@ RUNMODE_UNITTEST
Definition: runmodes.h:39
SC_ERR_INVALID_VALUE
@ SC_ERR_INVALID_VALUE
Definition: util-error.h:160
SigTableElmt_::Free
void(* Free)(DetectEngineCtx *, void *)
Definition: detect.h:1192
DetectEngineMustParseMetadata
int DetectEngineMustParseMetadata(void)
Definition: detect-engine.c:4209
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:370
MpmFactoryDeRegisterAllMpmCtxProfiles
void MpmFactoryDeRegisterAllMpmCtxProfiles(DetectEngineCtx *de_ctx)
Definition: util-mpm.c:229
DetectEngineThreadCtx_::counter_match_list
uint16_t counter_match_list
Definition: detect.h:1045
flow-util.h
DetectEnginePktInspectionEngine
Definition: detect.h:449
DetectEngineMasterCtx_::tenant_mapping_list
DetectEngineTenantMapping * tenant_mapping_list
Definition: detect.h:1442
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
DetectEngineAppInspectionEngine_::next
struct DetectEngineAppInspectionEngine_ * next
Definition: detect.h:416
detect-engine-siggroup.h
DetectEngineInspectGenericList
int DetectEngineInspectGenericList(const DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, const uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
Do the content inspection & validation for a signature.
Definition: detect-engine.c:1576
SigTableElmt_::name
const char * name
Definition: detect.h:1202
Packet_::vlan_id
uint16_t vlan_id[2]
Definition: decode.h:443
DetectEngineMasterCtx_::list
DetectEngineCtx * list
Definition: detect.h:1431
DetectEngineCtxInitWithPrefix
DetectEngineCtx * DetectEngineCtxInitWithPrefix(const char *prefix)
Definition: detect-engine.c:2030
MpmStoreFree
void MpmStoreFree(DetectEngineCtx *de_ctx)
Frees the hash table - DetectEngineCtx->mpm_hash_table, allocated by MpmStoreInit() function.
Definition: detect-engine-mpm.c:1185
ConfNode_::val
char * val
Definition: conf.h:34
ConfGetBool
int ConfGetBool(const char *name, int *val)
Retrieve a configuration value as an boolen.
Definition: conf.c:516
DetectEngineCtx_::type
enum DetectEngineType type
Definition: detect.h:890
DetectEnginePruneFreeList
void DetectEnginePruneFreeList(void)
Definition: detect-engine.c:4001
DetectThreadCtxGetKeywordThreadCtx
void * DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
Retrieve thread local keyword ctx by id.
Definition: detect-engine.c:3100
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
DetectEngineTransforms
Definition: detect.h:378
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SIG_FLAG_INIT_NEED_FLUSH
#define SIG_FLAG_INIT_NEED_FLUSH
Definition: detect.h:263
MpmTableElmt_::name
const char * name
Definition: util-mpm.h:144
DetectEngineTentantUnregisterVlanId
int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
Definition: detect-engine.c:3862
DetectEngineCtxInitStubForDD
DetectEngineCtx * DetectEngineCtxInitStubForDD(void)
Definition: detect-engine.c:2020
KEYWORD_PROFILING_SET_LIST
#define KEYWORD_PROFILING_SET_LIST(ctx, list)
Definition: util-profiling.h:65
DetectEngineCtx_::max_uniq_toclient_groups
uint16_t max_uniq_toclient_groups
Definition: detect.h:815
FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR
@ FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR
Definition: detect.h:1223
IDLE
@ IDLE
Definition: detect-engine.c:1505
DetectEngineCtx_::ref_cnt
uint32_t ref_cnt
Definition: detect.h:893
Signature_::alproto
AppProto alproto
Definition: detect.h:521
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
SigString_
Definition: detect.h:710
TmThreadsSetFlag
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition: tm-threads.c:97
DetectEngineCtx_::non_pf_store_cnt_max
uint32_t non_pf_store_cnt_max
Definition: detect.h:780
PacketEnqueue
void PacketEnqueue(PacketQueue *q, Packet *p)
Definition: packet-queue.c:173
DetectEngineGetByTenantId
DetectEngineCtx * DetectEngineGetByTenantId(int tenant_id)
Definition: detect-engine.c:3884
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
DetectPort_::port
uint16_t port
Definition: detect.h:192
TM_FLAG_DETECT_TM
#define TM_FLAG_DETECT_TM
Definition: tm-modules.h:34
DetectEnginePktInspectionEngine::v1
struct DetectEnginePktInspectionEngine::@84 v1
SCClassConfLoadClassficationConfigFile
void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
Definition: util-classification-config.c:527
PacketQueue_
simple fifo queue for packets with mutex and cond Calling the mutex or triggering the cond is respons...
Definition: packet-queue.h:47
Flow_::proto
uint8_t proto
Definition: flow.h:372
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:77
DETECT_SM_LIST_DYNAMIC_START
@ DETECT_SM_LIST_DYNAMIC_START
Definition: detect.h:109
AppLayerParserGetStateProgress
int AppLayerParserGetStateProgress(uint8_t ipproto, AppProto alproto, void *alstate, uint8_t flags)
get the progress value for a tx/protocol
Definition: app-layer-parser.c:1053
DetectEngineThreadCtx_::decoder_events
AppLayerDecoderEvents * decoder_events
Definition: detect.h:1139
SigMatchData_::ctx
SigMatchCtx * ctx
Definition: detect.h:332
InspectionBuffer
Definition: detect.h:344
DetectEngineThreadKeywordCtxItem_::InitFunc
void *(* InitFunc)(void *)
Definition: detect.h:728
Packet_::flags
uint32_t flags
Definition: decode.h:451
DETECT_EVENT_TOO_MANY_BUFFERS
@ DETECT_EVENT_TOO_MANY_BUFFERS
Definition: detect.h:1229
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:175
DetectEngineAppInspectionEngine_::GetData
InspectionBufferGetDataPtr GetData
Definition: detect.h:408
DetectEngineThreadKeywordCtxItem_
Definition: detect.h:727
Tmq_::pq
PacketQueue * pq
Definition: tm-queues.h:35
Packet_::vlan_idx
uint8_t vlan_idx
Definition: decode.h:444
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:350
DETECT_SM_LIST_THRESHOLD
@ DETECT_SM_LIST_THRESHOLD
Definition: detect.h:104
AppLayerEventType
enum AppLayerEventType_ AppLayerEventType
DetectBufferTypeRegisterSetupCallback
void DetectBufferTypeRegisterSetupCallback(const char *name, void(*SetupCallback)(const DetectEngineCtx *, Signature *))
Definition: detect-engine.c:903
DetectEngineThreadKeywordCtxItem_::data
void * data
Definition: detect.h:730
DetectEngineThreadCtx_::pmq
PrefilterRuleStore pmq
Definition: detect.h:1102
util-hash.h
InspectionBufferGetDataPtr
InspectionBuffer *(* InspectionBufferGetDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id)
Definition: detect.h:384
DetectEngineReloadTenantBlocking
int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
Reload a tenant and wait for loading to complete.
Definition: detect-engine.c:3449
FILE_DECODER_EVENT_LZMA_DATA_ERROR
@ FILE_DECODER_EVENT_LZMA_DATA_ERROR
Definition: detect.h:1225
LiveDevice_
Definition: util-device.h:40
DetectEngineCtx_::inspection_recursion_limit
int inspection_recursion_limit
Definition: detect.h:829
SpmTableElmt_::name
const char * name
Definition: util-spm.h:62
LiveDevice_::tenant_id_set
bool tenant_id_set
Definition: util-device.h:43
DetectAddressMapFree
void DetectAddressMapFree(DetectEngineCtx *de_ctx)
Definition: detect-engine-address.c:1391
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:757
DetectEngineReloadSetIdle
void DetectEngineReloadSetIdle(void)
Definition: detect-engine.c:1544
ConfYamlLoadFileWithPrefix
int ConfYamlLoadFileWithPrefix(const char *filename, const char *prefix)
Load configuration from a YAML file, insert in tree at 'prefix'.
Definition: conf-yaml-loader.c:506
DetectEnginePktInspectionEngine::smd
SigMatchData * smd
Definition: detect.h:450
DetectMetadataHashInit
int DetectMetadataHashInit(DetectEngineCtx *de_ctx)
Definition: detect-metadata.c:69
DetectEngineThreadCtx_::global_keyword_ctxs_array
void ** global_keyword_ctxs_array
Definition: detect.h:1133
DetectEngineInspectStream
int DetectEngineInspectStream(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)
inspect engine for stateful rules
Definition: detect-engine-payload.c:317
DetectEngineGetCurrent
DetectEngineCtx * DetectEngineGetCurrent(void)
Definition: detect-engine.c:3209
SC_ERR_INVALID_SIGNATURE
@ SC_ERR_INVALID_SIGNATURE
Definition: util-error.h:69
TransformData_::options
void * options
Definition: detect.h:375
StringParseInt32
int StringParseInt32(int32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:613
TmThreadCountThreadsByTmmFlags
uint32_t TmThreadCountThreadsByTmmFlags(uint8_t flags)
returns a count of all the threads that match the flag
Definition: tm-threads.c:2037
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:290
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
InspectionBuffer::orig
const uint8_t * orig
Definition: detect.h:357
SC_ERR_MT_NO_SELECTOR
@ SC_ERR_MT_NO_SELECTOR
Definition: util-error.h:299
DetectEngineAddToMaster
int DetectEngineAddToMaster(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:3934
InspectionBufferGetPktDataPtr
InspectionBuffer *(* InspectionBufferGetPktDataPtr)(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Packet *p, const int list_id)
Definition: detect.h:444
SCSigSignatureOrderingModuleCleanup
void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *de_ctx)
De-registers all the signature ordering functions registered.
Definition: detect-engine-sigorder.c:808
DetectEngineCtx_::keyword_id
int keyword_id
Definition: detect.h:869
TenantLoaderCtx_::yaml
const char * yaml
Definition: detect-engine.c:3374
PrefilterDeinit
void PrefilterDeinit(DetectEngineCtx *de_ctx)
Definition: detect-engine-prefilter.c:483
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
util-var-name.h
SIG_FLAG_REQUIRE_STREAM
#define SIG_FLAG_REQUIRE_STREAM
Definition: detect.h:224
ConfDump
void ConfDump(void)
Dump configuration to stdout.
Definition: conf.c:779
HashTable_
Definition: util-hash.h:35
DetectEngineThreadCtx_::flags
uint16_t flags
Definition: detect.h:1068
DetectEngineTenantMapping_::next
struct DetectEngineTenantMapping_ * next
Definition: detect.h:1417
DetectEngineSetEvent
void DetectEngineSetEvent(DetectEngineThreadCtx *det_ctx, uint8_t e)
Definition: detect-engine.c:4243
DetectEngineThreadCtx_::buffers_size
uint32_t buffers_size
Definition: detect.h:1052
MIN
#define MIN(x, y)
Definition: suricata-common.h:372
AppLayerDecoderEventsFreeEvents
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
Definition: app-layer-events.c:148
DetectBufferRunValidateCallback
bool DetectBufferRunValidateCallback(const DetectEngineCtx *de_ctx, const int id, const Signature *s, const char **sigerror)
Definition: detect-engine.c:932
DetectEngineCtx_::profile_sgh_ctx
struct SCProfileSghDetectCtx_ * profile_sgh_ctx
Definition: detect.h:883
tv_root
ThreadVars * tv_root[TVT_MAX]
Definition: tm-threads.c:78
VarNameStoreActivateStaging
void VarNameStoreActivateStaging(void)
Definition: util-var-name.c:340
DetectPort_::next
struct DetectPort_ * next
Definition: detect.h:205
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *de_ctx)
Free a DetectEngineCtx::
Definition: detect-engine.c:2070
DetectEngineAppInspectionEngine_::sm_list_base
uint16_t sm_list_base
Definition: detect.h:404
DetectBufferMpmRegistery_
one time registration of keywords at start up
Definition: detect.h:600
InspectionBuffer::size
uint32_t size
Definition: detect.h:354
DetectEngineThreadCtx_::spm_thread_ctx
SpmThreadCtx * spm_thread_ctx
Definition: detect.h:1106
FILE_DECODER_EVENT_LZMA_BUF_ERROR
@ FILE_DECODER_EVENT_LZMA_BUF_ERROR
Definition: detect.h:1226
InspectionBuffer::flags
uint8_t flags
Definition: detect.h:348
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
Signature_::sm_arrays
SigMatchData * sm_arrays[DETECT_SM_LIST_MAX]
Definition: detect.h:570
SCInstance_::conf_filename
const char * conf_filename
Definition: suricata.h:159
DetectEngineCtx_::prefilter_setting
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:901
SignatureInitData_::init_flags
uint32_t init_flags
Definition: detect.h:482
DetectParseDupSigHashFree
void DetectParseDupSigHashFree(DetectEngineCtx *de_ctx)
Frees the hash table that is used to cull duplicate sigs.
Definition: detect-parse.c:2198
DetectBufferType_
Definition: detect.h:419
m
SCMutex m
Definition: flow-hash.h:6
DetectEngineGetVersion
uint32_t DetectEngineGetVersion(void)
Definition: detect-engine.c:3190
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:40
DetectEngineContentInspection
int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, const uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode)
Run the actual payload match functions.
Definition: detect-engine-content-inspection.c:102
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:248
SC_ERR_DETECT_PREPARE
@ SC_ERR_DETECT_PREPARE
Definition: util-error.h:205
detect-engine-payload.h
DetectBufferGetActiveList
int DetectBufferGetActiveList(DetectEngineCtx *de_ctx, Signature *s)
Definition: detect-engine.c:955
SIG_FLAG_TOCLIENT
#define SIG_FLAG_TOCLIENT
Definition: detect.h:237
MPM_AC_KS
@ MPM_AC_KS
Definition: util-mpm.h:37
MAX
#define MAX(x, y)
Definition: suricata-common.h:376
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
SigMatchData_
Data needed for Match()
Definition: detect.h:329
InspectionBufferMultipleForList::init
uint32_t init
Definition: detect.h:370
DetectEngineCtx_::mpm_matcher
uint16_t mpm_matcher
Definition: detect.h:806
KEYWORD_PROFILING_START
#define KEYWORD_PROFILING_START
Definition: util-profiling.h:69
DetectEngineThreadCtx_::counter_fnonmpm_list
uint16_t counter_fnonmpm_list
Definition: detect.h:1044
DetectEngineCtx_::version
uint32_t version
Definition: detect.h:851
SC_ERR_INVALID_ARGUMENTS
@ SC_ERR_INVALID_ARGUMENTS
Definition: util-error.h:82
DETECT_TRANSFORMS_MAX
#define DETECT_TRANSFORMS_MAX
Definition: detect.h:58
InspectionBuffer::orig_len
uint32_t orig_len
Definition: detect.h:356
DetectPort_::port2
uint16_t port2
Definition: detect.h:193
ThresholdHashInit
void ThresholdHashInit(DetectEngineCtx *de_ctx)
Init threshold context hash tables.
Definition: detect-engine-threshold.c:645
DetectEngineThreadCtx_::counter_nonmpm_list
uint16_t counter_nonmpm_list
Definition: detect.h:1043
DetectEngineThreadCtx_::events
uint16_t events
Definition: detect.h:1140
detect-engine-prefilter.h
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:34
DetectEngineThreadCtx_::mtcu
MpmThreadCtx mtcu
Definition: detect.h:1100
util-unittest.h
TransformData_
Definition: detect.h:373
MPM_AC
@ MPM_AC
Definition: util-mpm.h:35
InspectionBufferGet
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
Definition: detect-engine.c:1011
FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR
@ FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR
Definition: detect.h:1222
APP_LAYER_EVENT_TYPE_TRANSACTION
@ APP_LAYER_EVENT_TYPE_TRANSACTION
Definition: app-layer-events.h:57
DetectBufferTypeCloseRegistration
void DetectBufferTypeCloseRegistration(void)
Definition: detect-engine.c:1278
DetectEnginePktInspectionEngine::transforms
const DetectEngineTransforms * transforms
Definition: detect.h:458
TmModule_::PktAcqLoop
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition: tm-modules.h:54
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:80
HashTableFree
void HashTableFree(HashTable *ht)
Definition: util-hash.c:79
DetectEngineCtx_::app_mpms_list
DetectBufferMpmRegistery * app_mpms_list
Definition: detect.h:925
TenantLoaderCtx_
Definition: detect-engine.c:3371
DetectBufferTypeGetByName
int DetectBufferTypeGetByName(const char *name)
Definition: detect-engine.c:830
KEYWORD_PROFILING_END
#define KEYWORD_PROFILING_END(ctx, type, m)
Definition: util-profiling.h:83
DetectBufferTypeSupportsPacket
void DetectBufferTypeSupportsPacket(const char *name)
Definition: detect-engine.c:800
HashListTableAdd
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:116
DetectEngineThreadCtx_::mtcs
MpmThreadCtx mtcs
Definition: detect.h:1101
HashTable_::array_size
uint32_t array_size
Definition: util-hash.h:37
SigGroupHeadHashInit
int SigGroupHeadHashInit(DetectEngineCtx *de_ctx)
Initializes the hash table in the detection engine context to hold the SigGroupHeads.
Definition: detect-engine-siggroup.c:256
SCRConfDeInitContext
void SCRConfDeInitContext(DetectEngineCtx *de_ctx)
Releases de_ctx resources related to Reference Config API.
Definition: util-reference-config.c:190
InspectionBufferMultipleForList::size
uint32_t size
Definition: detect.h:368
DetectEngineCtx_::udp_whitelist
DetectPort * udp_whitelist
Definition: detect.h:906
DetectEngineThreadCtx_::mt_det_ctxs_hash
HashTable * mt_det_ctxs_hash
Definition: detect.h:1019
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
DetectBufferType_::string
const char * string
Definition: detect.h:420
DetectEnginePktInspectionRun
bool DetectEnginePktInspectionRun(ThreadVars *tv, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, Packet *p, uint8_t *alert_flags)
Definition: detect-engine.c:1435
DETECT_PREFILTER_AUTO
@ DETECT_PREFILTER_AUTO
Definition: detect.h:739
DetectEngineThreadCtx_::keyword_ctxs_size
int keyword_ctxs_size
Definition: detect.h:1130
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
DetectAppLayerMpmRegisterByParentId
void DetectAppLayerMpmRegisterByParentId(DetectEngineCtx *de_ctx, const int id, const int parent_id, DetectEngineTransforms *transforms)
copy a mpm engine from parent_id, add in transforms
Definition: detect-engine-mpm.c:145
TVT_PPT
@ TVT_PPT
Definition: tm-threads-common.h:87
SigString_::sig_error
char * sig_error
Definition: detect.h:713
TmThreadContinueDetectLoaderThreads
void TmThreadContinueDetectLoaderThreads()
Unpauses all threads present in tv_root.
Definition: detect-engine-loader.c:523
DetectEngineAppInspectionEngine_::id
uint8_t id
Definition: detect.h:400
PacketQueue_::mutex_q
SCMutex mutex_q
Definition: packet-queue.h:54
THV_RUNNING_DONE
#define THV_RUNNING_DONE
Definition: threadvars.h:47
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1170
util-signal.h
DetectEngineAppInspectionEngine_::sm_list
uint16_t sm_list
Definition: detect.h:403
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
TENANT_SELECTOR_UNKNOWN
@ TENANT_SELECTOR_UNKNOWN
Definition: detect.h:1405
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:330
InspectionBufferInit
void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size)
Definition: detect-engine.c:1068
DetectEngineMultiTenantEnabled
int DetectEngineMultiTenantEnabled(void)
Definition: detect-engine.c:3241
HashListTableGetListNext
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
DetectEngineTenantMapping_::tenant_id
uint32_t tenant_id
Definition: detect.h:1412
InspectionBufferMultipleForList
Definition: detect.h:366
ThreadVars_::tmm_flags
uint8_t tmm_flags
Definition: threadvars.h:79
DETECT_SM_LIST_POSTMATCH
@ DETECT_SM_LIST_POSTMATCH
Definition: detect.h:98
ConfNodeRemove
void ConfNodeRemove(ConfNode *node)
Remove (and SCFree) the provided configuration node.
Definition: conf.c:667
SIG_FLAG_TOSERVER
#define SIG_FLAG_TOSERVER
Definition: detect.h:236
app-layer-htp.h
DetectEngineTenantSelectors
DetectEngineTenantSelectors
Definition: detect.h:1404
DetectPortParse
int DetectPortParse(const DetectEngineCtx *de_ctx, DetectPort **head, const char *str)
Function for parsing port strings.
Definition: detect-engine-port.c:1243
InspectionBufferPktInspectFunc
int(* InspectionBufferPktInspectFunc)(struct DetectEngineThreadCtx_ *, const struct DetectEnginePktInspectionEngine *engine, const struct Signature_ *s, Packet *p, uint8_t *alert_flags)
Definition: detect.h:437
datasets.h
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
FILE_DECODER_EVENT_LZMA_FORMAT_ERROR
@ FILE_DECODER_EVENT_LZMA_FORMAT_ERROR
Definition: detect.h:1224
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:412
SigTableElmt_::TransformValidate
bool(* TransformValidate)(const uint8_t *content, uint16_t content_len, void *context)
Definition: detect.h:1184
util-device.h
util-debug.h
DetectBufferTypeRegisterValidateCallback
void DetectBufferTypeRegisterValidateCallback(const char *name, bool(*ValidateCallback)(const Signature *, const char **sigerror))
Definition: detect-engine.c:922
DetectEngineMoveToFreeList
int DetectEngineMoveToFreeList(DetectEngineCtx *de_ctx)
Definition: detect-engine.c:3950
type
uint8_t type
Definition: decode-icmpv4.h:0
VarNameStoreFree
void VarNameStoreFree(uint32_t de_ctx_version)
Definition: util-var-name.c:364
SC_ERR_CONF_YAML_ERROR
@ SC_ERR_CONF_YAML_ERROR
Definition: util-error.h:274
util-error.h
ENGINE_PROFILE_HIGH
@ ENGINE_PROFILE_HIGH
Definition: detect.h:953
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
SCProfilingPrefilterDestroyCtx
void SCProfilingPrefilterDestroyCtx(DetectEngineCtx *de_ctx)
Definition: util-profiling-prefilter.c:222
DetectEnginePktInspectionEngine::sm_list
uint16_t sm_list
Definition: detect.h:452
DetectEngineThreadCtx_::match_array_len
uint32_t match_array_len
Definition: detect.h:1086
TmModule_::PktAcqBreakLoop
TmEcode(* PktAcqBreakLoop)(ThreadVars *, void *)
Definition: tm-modules.h:57
DetectEngineInspectPacketPayload
int DetectEngineInspectPacketPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, Packet *p)
Do the content inspection & validation for a signature.
Definition: detect-engine-payload.c:150
DetectMpmInitializePktMpms
void DetectMpmInitializePktMpms(DetectEngineCtx *de_ctx)
Definition: detect-engine-mpm.c:378
DetectEngineThreadCtx_
Definition: detect.h:1001
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1126
DetectUnregisterThreadCtxFuncs
int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, void *data, const char *name)
Remove Thread keyword context registration.
Definition: detect-engine.c:3069
det_ctx_event_table
SCEnumCharMap det_ctx_event_table[]
Definition: detect-engine.c:106
DetectLoadersInit
void DetectLoadersInit(void)
Definition: detect-engine-loader.c:472
ThreadVars_::tm_slots
struct TmSlot_ * tm_slots
Definition: threadvars.h:96
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:489
ENGINE_PROFILE_MEDIUM
@ ENGINE_PROFILE_MEDIUM
Definition: detect.h:952
ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL
@ ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL
Definition: detect.h:960
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
DETECT_SM_LIST_BASE64_DATA
@ DETECT_SM_LIST_BASE64_DATA
Definition: detect.h:95
SIG_FLAG_FLUSH
#define SIG_FLAG_FLUSH
Definition: detect.h:228
DetectEngineThreadKeywordCtxItem_::id
int id
Definition: detect.h:732
PKT_PSEUDO_STREAM_END
#define PKT_PSEUDO_STREAM_END
Definition: decode.h:1130
DetectEngineThreadCtx_::buffers
InspectionBuffer * buffers
Definition: detect.h:1051
detect-engine-file.h
DetectEngineMasterCtx_::keyword_list
DetectEngineThreadKeywordCtxItem * keyword_list
Definition: detect.h:1447
LiveGetDevice
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:278
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
flow-worker.h
DetectEngineMasterCtx_::tenant_selector
enum DetectEngineTenantSelectors tenant_selector
Definition: detect.h:1438
FILE_DECODER_EVENT_INVALID_SWF_LENGTH
@ FILE_DECODER_EVENT_INVALID_SWF_LENGTH
Definition: detect.h:1215
SigLoadSignatures
int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_exclusive)
Load signatures.
Definition: detect-engine-loader.c:276
DetectPktInspectEngineRegister
void DetectPktInspectEngineRegister(const char *name, InspectionBufferGetPktDataPtr GetPktData, InspectionBufferPktInspectFunc Callback)
register inspect engine at start up time
Definition: detect-engine.c:134
InspectionBufferCheckAndExpand
void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size)
make sure that the buffer has at least 'min_size' bytes Expand the buffer if necessary
Definition: detect-engine.c:1117
DetectEngineInspectStreamPayload
int DetectEngineInspectStreamPayload(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, Flow *f, Packet *p)
Do the content inspection & validation for a signature on the raw stream.
Definition: detect-engine-payload.c:263
util-reference-config.h
DetectBufferTypeValidateTransform
bool DetectBufferTypeValidateTransform(DetectEngineCtx *de_ctx, int sm_list, const uint8_t *content, uint16_t content_len, const char **namestr)
Check content byte array compatibility with transforms.
Definition: detect-engine.c:1164
DetectEngineCtx_::buffer_type_id
int buffer_type_id
Definition: detect.h:920
Packet_::pcap_v
PcapPacketVars pcap_v
Definition: decode.h:491
SignatureInitData_::list
int list
Definition: detect.h:494
Signature_::pkt_inspect
DetectEnginePktInspectionEngine * pkt_inspect
Definition: detect.h:566
VarNameStoreSetupStaging
int VarNameStoreSetupStaging(uint32_t de_ctx_version)
setup staging store. Include current store if there is one.
Definition: util-var-name.c:247
SCEnter
#define SCEnter(...)
Definition: util-debug.h:300
detect-engine-mpm.h
DetectMetadataHashFree
void DetectMetadataHashFree(DetectEngineCtx *de_ctx)
Definition: detect-metadata.c:80
DetectBufferTypeMaxId
int DetectBufferTypeMaxId(void)
Definition: detect-engine.c:689
DatasetPostReloadCleanup
void DatasetPostReloadCleanup(void)
Definition: datasets.c:577
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineEnabled
int DetectEngineEnabled(void)
Check if detection is enabled.
Definition: detect-engine.c:3176
SC_ERR_MT_NO_MAPPING
@ SC_ERR_MT_NO_MAPPING
Definition: util-error.h:304
SigMatchList2DataArray
SigMatchData * SigMatchList2DataArray(SigMatch *head)
convert SigMatch list to SigMatchData array
Definition: detect-parse.c:1630
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:2774
DetectEngineReloadIsIdle
int DetectEngineReloadIsIdle(void)
Definition: detect-engine.c:1552
DETECT_ENGINE_INSPECT_SIG_MATCH
#define DETECT_ENGINE_INSPECT_SIG_MATCH
Definition: detect-engine-state.h:39
PKT_DETECT_HAS_STREAMDATA
#define PKT_DETECT_HAS_STREAMDATA
Definition: decode.h:1158
DET_CTX_EVENT_TEST
@ DET_CTX_EVENT_TEST
Definition: detect.h:1212
SigMatchData_::type
uint8_t type
Definition: detect.h:330
ENGINE_PROFILE_UNKNOWN
@ ENGINE_PROFILE_UNKNOWN
Definition: detect.h:950
detect-engine-port.h
LiveDevice_::tenant_id
uint32_t tenant_id
Definition: util-device.h:53
InspectionBuffer::inspect_offset
uint64_t inspect_offset
Definition: detect.h:346
DetectEngineMasterCtx_::free_list
DetectEngineCtx * free_list
Definition: detect.h:1436
DetectEngineSyncState
DetectEngineSyncState
Definition: detect-engine.c:1504
ENGINE_PROFILE_CUSTOM
@ ENGINE_PROFILE_CUSTOM
Definition: detect.h:954
LiveDevice_::dev
char * dev
Definition: util-device.h:41
PatternMatchThreadPrepare
void PatternMatchThreadPrepare(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
Definition: detect-engine-mpm.c:678
ConfYamlLoadString
int ConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:475
DetectEngineThreadKeywordCtxItem_::next
struct DetectEngineThreadKeywordCtxItem_ * next
Definition: detect.h:731
DETECT_SM_LIST_MATCH
@ DETECT_SM_LIST_MATCH
Definition: detect.h:89
HashTableAdd
int HashTableAdd(HashTable *ht, void *data, uint16_t datalen)
Definition: util-hash.c:113
DetectPort_
Port structure for detection engine.
Definition: detect.h:191
SC_ERR_INVALID_ARGUMENT
@ SC_ERR_INVALID_ARGUMENT
Definition: util-error.h:43
InspectionBuffer::buf
uint8_t * buf
Definition: detect.h:353
app-layer-parser.h
Signature_::app_inspect
DetectEngineAppInspectionEngine * app_inspect
Definition: detect.h:565
DetectBufferType_::ValidateCallback
bool(* ValidateCallback)(const struct Signature_ *, const char **sigerror)
Definition: detect.h:428
ThreadVars_::next
struct ThreadVars_ * next
Definition: threadvars.h:123
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:277
hashlittle_safe
uint32_t hashlittle_safe(const void *key, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:484
DetectEngineThreadCtx_::base64_decoded_len
int base64_decoded_len
Definition: detect.h:1136
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:1956
detect-engine-tag.h
Signature_::action
uint8_t action
Definition: detect.h:530
util-profiling.h
DetectEngineThreadCtxInfo
void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx)
Definition: detect-engine.c:3000
tv_root_lock
SCMutex tv_root_lock
Definition: tm-threads.c:81
DetectEngineCtx_::profile_ctx
struct SCProfileDetectCtx_ * profile_ctx
Definition: detect.h:879
DetectEngineLoadTenantBlocking
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
Load a tenant and wait for loading to complete.
Definition: detect-engine.c:3435
TmModuleDetectLoaderRegister
void TmModuleDetectLoaderRegister(void)
Definition: detect-engine-loader.c:643
Signature_::flags
uint32_t flags
Definition: detect.h:518
MPM_HS
@ MPM_HS
Definition: util-mpm.h:38
PACKET_ALERT_FLAG_DROP_FLOW
#define PACKET_ALERT_FLAG_DROP_FLOW
Definition: decode.h:288
DetectEngineInspectBufferGeneric
int DetectEngineInspectBufferGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const 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