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