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