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