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