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 
1276  det_ctx->discontinue_matching = 0;
1277  det_ctx->buffer_offset = 0;
1278  det_ctx->inspection_recursion_counter = 0;
1279 
1280  /* Inspect all the uricontents fetched on each
1281  * transaction at the app layer */
1282  int r = DetectEngineContentInspection(de_ctx, det_ctx,
1283  s, engine->smd,
1284  f,
1285  (uint8_t *)data, data_len, offset, ci_flags,
1287  if (r == 1) {
1289  } else {
1292  }
1293 }
1294 
1295 
1296 /* nudge capture loops to wake up */
1297 static void BreakCapture(void)
1298 {
1300  ThreadVars *tv = tv_root[TVT_PPT];
1301  while (tv) {
1302  /* find the correct slot */
1303  TmSlot *slots = tv->tm_slots;
1304  while (slots != NULL) {
1305  if (suricata_ctl_flags != 0) {
1307  return;
1308  }
1309 
1310  TmModule *tm = TmModuleGetById(slots->tm_id);
1311  if (!(tm->flags & TM_FLAG_RECEIVE_TM)) {
1312  slots = slots->slot_next;
1313  continue;
1314  }
1315 
1316  /* signal capture method that we need a packet. */
1318  /* if the method supports it, BreakLoop. Otherwise we rely on
1319  * the capture method's recv timeout */
1320  if (tm->PktAcqLoop && tm->PktAcqBreakLoop) {
1321  tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(slots->slot_data));
1322  }
1323 
1324  break;
1325  }
1326  tv = tv->next;
1327  }
1329 }
1330 
1331 /** \internal
1332  * \brief inject a pseudo packet into each detect thread that doesn't use the
1333  * new det_ctx yet
1334  */
1335 static void InjectPackets(ThreadVars **detect_tvs,
1336  DetectEngineThreadCtx **new_det_ctx,
1337  int no_of_detect_tvs)
1338 {
1339  int i;
1340  /* inject a fake packet if the detect thread isn't using the new ctx yet,
1341  * this speeds up the process */
1342  for (i = 0; i < no_of_detect_tvs; i++) {
1343  if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1344  if (detect_tvs[i]->inq != NULL) {
1345  Packet *p = PacketGetFromAlloc();
1346  if (p != NULL) {
1348  PacketQueue *q = &trans_q[detect_tvs[i]->inq->id];
1349  SCMutexLock(&q->mutex_q);
1350  PacketEnqueue(q, p);
1351  SCCondSignal(&q->cond_q);
1352  SCMutexUnlock(&q->mutex_q);
1353  }
1354  }
1355  }
1356  }
1357 }
1358 
1359 /** \internal
1360  * \brief Update detect threads with new detect engine
1361  *
1362  * Atomically update each detect thread with a new thread context
1363  * that is associated to the new detection engine(s).
1364  *
1365  * If called in unix socket mode, it's possible that we don't have
1366  * detect threads yet.
1367  *
1368  * \retval -1 error
1369  * \retval 0 no detection threads
1370  * \retval 1 successful reload
1371  */
1372 static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
1373 {
1374  SCEnter();
1375  int i = 0;
1376  int no_of_detect_tvs = 0;
1377  ThreadVars *tv = NULL;
1378 
1379  /* count detect threads in use */
1381  tv = tv_root[TVT_PPT];
1382  while (tv) {
1383  /* obtain the slots for this TV */
1384  TmSlot *slots = tv->tm_slots;
1385  while (slots != NULL) {
1386  TmModule *tm = TmModuleGetById(slots->tm_id);
1387 
1388  if (suricata_ctl_flags != 0) {
1389  SCLogInfo("rule reload interupted by engine shutdown");
1391  return -1;
1392  }
1393 
1394  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1395  slots = slots->slot_next;
1396  continue;
1397  }
1398  no_of_detect_tvs++;
1399  break;
1400  }
1401 
1402  tv = tv->next;
1403  }
1405 
1406  /* can be zero in unix socket mode */
1407  if (no_of_detect_tvs == 0) {
1408  return 0;
1409  }
1410 
1411  /* prepare swap structures */
1412  DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
1413  DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
1414  ThreadVars *detect_tvs[no_of_detect_tvs];
1415  memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1416  memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1417  memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *)));
1418 
1419  /* start the process of swapping detect threads ctxs */
1420 
1421  /* get reference to tv's and setup new_det_ctx array */
1423  tv = tv_root[TVT_PPT];
1424  while (tv) {
1425  /* obtain the slots for this TV */
1426  TmSlot *slots = tv->tm_slots;
1427  while (slots != NULL) {
1428  TmModule *tm = TmModuleGetById(slots->tm_id);
1429 
1430  if (suricata_ctl_flags != 0) {
1432  goto error;
1433  }
1434 
1435  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1436  slots = slots->slot_next;
1437  continue;
1438  }
1439 
1440  old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(slots->slot_data));
1441  detect_tvs[i] = tv;
1442 
1443  new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
1444  if (new_det_ctx[i] == NULL) {
1445  SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init "
1446  "failure in live rule swap. Let's get out of here");
1448  goto error;
1449  }
1450  SCLogDebug("live rule swap created new det_ctx - %p and de_ctx "
1451  "- %p\n", new_det_ctx[i], new_de_ctx);
1452  i++;
1453  break;
1454  }
1455 
1456  tv = tv->next;
1457  }
1458  BUG_ON(i != no_of_detect_tvs);
1459 
1460  /* atomicly replace the det_ctx data */
1461  i = 0;
1462  tv = tv_root[TVT_PPT];
1463  while (tv) {
1464  /* find the correct slot */
1465  TmSlot *slots = tv->tm_slots;
1466  while (slots != NULL) {
1467  if (suricata_ctl_flags != 0) {
1469  return -1;
1470  }
1471 
1472  TmModule *tm = TmModuleGetById(slots->tm_id);
1473  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1474  slots = slots->slot_next;
1475  continue;
1476  }
1477  SCLogDebug("swapping new det_ctx - %p with older one - %p",
1478  new_det_ctx[i], SC_ATOMIC_GET(slots->slot_data));
1479  FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(slots->slot_data), new_det_ctx[i++]);
1480  break;
1481  }
1482  tv = tv->next;
1483  }
1485 
1486  /* threads now all have new data, however they may not have started using
1487  * it and may still use the old data */
1488 
1489  SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, "
1490  "along with the new de_ctx", no_of_detect_tvs);
1491 
1492  InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs);
1493 
1494  for (i = 0; i < no_of_detect_tvs; i++) {
1495  int break_out = 0;
1496  usleep(1000);
1497  while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1498  if (suricata_ctl_flags != 0) {
1499  break_out = 1;
1500  break;
1501  }
1502 
1503  BreakCapture();
1504  usleep(1000);
1505  }
1506  if (break_out)
1507  break;
1508  SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]);
1509  }
1510 
1511  /* this is to make sure that if someone initiated shutdown during a live
1512  * rule swap, the live rule swap won't clean up the old det_ctx and
1513  * de_ctx, till all detect threads have stopped working and sitting
1514  * silently after setting RUNNING_DONE flag and while waiting for
1515  * THV_DEINIT flag */
1516  if (i != no_of_detect_tvs) { // not all threads we swapped
1517  tv = tv_root[TVT_PPT];
1518  while (tv) {
1519  /* obtain the slots for this TV */
1520  TmSlot *slots = tv->tm_slots;
1521  while (slots != NULL) {
1522  TmModule *tm = TmModuleGetById(slots->tm_id);
1523  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1524  slots = slots->slot_next;
1525  continue;
1526  }
1527 
1528  while (!TmThreadsCheckFlag(tv, THV_RUNNING_DONE)) {
1529  usleep(100);
1530  }
1531 
1532  slots = slots->slot_next;
1533  }
1534 
1535  tv = tv->next;
1536  }
1537  }
1538 
1539  /* free all the ctxs */
1540  for (i = 0; i < no_of_detect_tvs; i++) {
1541  SCLogDebug("Freeing old_det_ctx - %p used by detect",
1542  old_det_ctx[i]);
1543  DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
1544  }
1545 
1547 
1548  return 1;
1549 
1550  error:
1551  for (i = 0; i < no_of_detect_tvs; i++) {
1552  if (new_det_ctx[i] != NULL)
1553  DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]);
1554  }
1555  return -1;
1556 }
1557 
1558 static DetectEngineCtx *DetectEngineCtxInitReal(enum DetectEngineType type, const char *prefix)
1559 {
1560  DetectEngineCtx *de_ctx = SCMalloc(sizeof(DetectEngineCtx));
1561  if (unlikely(de_ctx == NULL))
1562  goto error;
1563 
1564  memset(de_ctx,0,sizeof(DetectEngineCtx));
1565  memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
1566  TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
1567  de_ctx->sigerror = NULL;
1568  de_ctx->type = type;
1569 
1570  if (type == DETECT_ENGINE_TYPE_DD_STUB || type == DETECT_ENGINE_TYPE_MT_STUB) {
1571  de_ctx->version = DetectEngineGetVersion();
1572  SCLogDebug("stub %u with version %u", type, de_ctx->version);
1573  return de_ctx;
1574  }
1575 
1576  if (prefix != NULL) {
1577  strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix));
1578  }
1579 
1580  if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) {
1581  SCLogDebug("ConfGetBool could not load the value.");
1582  }
1583 
1586  SCLogConfig("pattern matchers: MPM: %s, SPM: %s",
1587  mpm_table[de_ctx->mpm_matcher].name,
1588  spm_table[de_ctx->spm_matcher].name);
1589 
1591  if (de_ctx->spm_global_thread_ctx == NULL) {
1592  SCLogDebug("Unable to alloc SpmGlobalThreadCtx.");
1593  goto error;
1594  }
1595 
1596  if (DetectEngineCtxLoadConf(de_ctx) == -1) {
1597  goto error;
1598  }
1599 
1600  SigGroupHeadHashInit(de_ctx);
1601  MpmStoreInit(de_ctx);
1602  ThresholdHashInit(de_ctx);
1603  DetectParseDupSigHashInit(de_ctx);
1604  DetectAddressMapInit(de_ctx);
1605  DetectMetadataHashInit(de_ctx);
1606  DetectBufferTypeSetupDetectEngine(de_ctx);
1607 
1608  /* init iprep... ignore errors for now */
1609  (void)SRepInit(de_ctx);
1610 
1612  SCRConfLoadReferenceConfigFile(de_ctx, NULL);
1613 
1614  if (ActionInitConfig() < 0) {
1615  goto error;
1616  }
1617 
1618  de_ctx->version = DetectEngineGetVersion();
1620  SCLogDebug("dectx with version %u", de_ctx->version);
1621  return de_ctx;
1622 error:
1623  if (de_ctx != NULL) {
1624  DetectEngineCtxFree(de_ctx);
1625  }
1626  return NULL;
1627 
1628 }
1629 
1631 {
1632  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_MT_STUB, NULL);
1633 }
1634 
1636 {
1637  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_DD_STUB, NULL);
1638 }
1639 
1641 {
1642  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, NULL);
1643 }
1644 
1646 {
1647  if (prefix == NULL || strlen(prefix) == 0)
1648  return DetectEngineCtxInit();
1649  else
1650  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, prefix);
1651 }
1652 
1653 static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
1654 {
1656  while (item) {
1658  SCFree(item);
1659  item = next;
1660  }
1661  de_ctx->keyword_list = NULL;
1662 }
1663 
1664 static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
1665 {
1666  SigString *item = NULL;
1667  SigString *sitem;
1668 
1669  TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
1670  SCFree(item->filename);
1671  SCFree(item->sig_str);
1672  if (item->sig_error) {
1673  SCFree(item->sig_error);
1674  }
1675  TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
1676  SCFree(item);
1677  }
1678 }
1679 
1680 /**
1681  * \brief Free a DetectEngineCtx::
1682  *
1683  * \param de_ctx DetectEngineCtx:: to be freed
1684  */
1686 {
1687 
1688  if (de_ctx == NULL)
1689  return;
1690 
1691 #ifdef PROFILING
1692  if (de_ctx->profile_ctx != NULL) {
1694  de_ctx->profile_ctx = NULL;
1695  }
1696  if (de_ctx->profile_keyword_ctx != NULL) {
1697  SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx);
1698 // de_ctx->profile_keyword_ctx = NULL;
1699  }
1700  if (de_ctx->profile_sgh_ctx != NULL) {
1701  SCProfilingSghDestroyCtx(de_ctx);
1702  }
1704 #endif
1705 
1706  /* Normally the hashes are freed elsewhere, but
1707  * to be sure look at them again here.
1708  */
1709  SigGroupHeadHashFree(de_ctx);
1710  MpmStoreFree(de_ctx);
1711  DetectParseDupSigHashFree(de_ctx);
1713  ThresholdContextDestroy(de_ctx);
1714  SigCleanSignatures(de_ctx);
1715  SCFree(de_ctx->app_mpms);
1716  de_ctx->app_mpms = NULL;
1717  if (de_ctx->sig_array)
1718  SCFree(de_ctx->sig_array);
1719 
1720  SCClassConfDeInitContext(de_ctx);
1721  SCRConfDeInitContext(de_ctx);
1722 
1723  SigGroupCleanup(de_ctx);
1724 
1726 
1728 
1729  DetectEngineCtxFreeThreadKeywordData(de_ctx);
1730  SRepDestroy(de_ctx);
1731  DetectEngineCtxFreeFailedSigs(de_ctx);
1732 
1733  DetectAddressMapFree(de_ctx);
1734  DetectMetadataHashFree(de_ctx);
1735 
1736  /* if we have a config prefix, remove the config from the tree */
1737  if (strlen(de_ctx->config_prefix) > 0) {
1738  /* remove config */
1739  ConfNode *node = ConfGetNode(de_ctx->config_prefix);
1740  if (node != NULL) {
1741  ConfNodeRemove(node); /* frees node */
1742  }
1743 #if 0
1744  ConfDump();
1745 #endif
1746  }
1747 
1748  DetectPortCleanupList(de_ctx, de_ctx->tcp_whitelist);
1749  DetectPortCleanupList(de_ctx, de_ctx->udp_whitelist);
1750 
1751  DetectBufferTypeFreeDetectEngine(de_ctx);
1752  /* freed our var name hash */
1753  VarNameStoreFree(de_ctx->version);
1754 
1755  SCFree(de_ctx);
1756  //DetectAddressGroupPrintMemory();
1757  //DetectSigGroupPrintMemory();
1758  //DetectPortPrintMemory();
1759 }
1760 
1761 /** \brief Function that load DetectEngineCtx config for grouping sigs
1762  * used by the engine
1763  * \retval 0 if no config provided, 1 if config was provided
1764  * and loaded successfuly
1765  */
1766 static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx)
1767 {
1768  uint8_t profile = ENGINE_PROFILE_MEDIUM;
1769  const char *max_uniq_toclient_groups_str = NULL;
1770  const char *max_uniq_toserver_groups_str = NULL;
1771  const char *sgh_mpm_context = NULL;
1772  const char *de_ctx_profile = NULL;
1773 
1774  (void)ConfGet("detect.profile", &de_ctx_profile);
1775  (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context);
1776 
1777  ConfNode *de_ctx_custom = ConfGetNode("detect-engine");
1778  ConfNode *opt = NULL;
1779 
1780  if (de_ctx_custom != NULL) {
1781  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
1782  if (de_ctx_profile == NULL) {
1783  if (opt->val && strcmp(opt->val, "profile") == 0) {
1784  de_ctx_profile = opt->head.tqh_first->val;
1785  }
1786  }
1787 
1788  if (sgh_mpm_context == NULL) {
1789  if (opt->val && strcmp(opt->val, "sgh-mpm-context") == 0) {
1790  sgh_mpm_context = opt->head.tqh_first->val;
1791  }
1792  }
1793  }
1794  }
1795 
1796  if (de_ctx_profile != NULL) {
1797  if (strcmp(de_ctx_profile, "low") == 0 ||
1798  strcmp(de_ctx_profile, "lowest") == 0) { // legacy
1799  profile = ENGINE_PROFILE_LOW;
1800  } else if (strcmp(de_ctx_profile, "medium") == 0) {
1801  profile = ENGINE_PROFILE_MEDIUM;
1802  } else if (strcmp(de_ctx_profile, "high") == 0 ||
1803  strcmp(de_ctx_profile, "highest") == 0) { // legacy
1804  profile = ENGINE_PROFILE_HIGH;
1805  } else if (strcmp(de_ctx_profile, "custom") == 0) {
1806  profile = ENGINE_PROFILE_CUSTOM;
1807  } else {
1809  "invalid value for detect.profile: '%s'. "
1810  "Valid options: low, medium, high and custom.",
1811  de_ctx_profile);
1812  return -1;
1813  }
1814 
1815  SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
1816  } else {
1817  SCLogDebug("Profile for detection engine groups not provided "
1818  "at suricata.yaml. Using default (\"medium\").");
1819  }
1820 
1821  /* detect-engine.sgh-mpm-context option parsing */
1822  if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) {
1823  /* for now, since we still haven't implemented any intelligence into
1824  * understanding the patterns and distributing mpm_ctx across sgh */
1825  if (de_ctx->mpm_matcher == MPM_AC || de_ctx->mpm_matcher == MPM_AC_KS ||
1826 #ifdef BUILD_HYPERSCAN
1827  de_ctx->mpm_matcher == MPM_HS ||
1828 #endif
1829  de_ctx->mpm_matcher == MPM_AC_BS) {
1831  } else {
1833  }
1834  } else {
1835  if (strcmp(sgh_mpm_context, "single") == 0) {
1837  } else if (strcmp(sgh_mpm_context, "full") == 0) {
1839  } else {
1840  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "You have supplied an "
1841  "invalid conf value for detect-engine.sgh-mpm-context-"
1842  "%s", sgh_mpm_context);
1843  exit(EXIT_FAILURE);
1844  }
1845  }
1846 
1847  if (run_mode == RUNMODE_UNITTEST) {
1849  }
1850 
1851  /* parse profile custom-values */
1852  opt = NULL;
1853  switch (profile) {
1854  case ENGINE_PROFILE_LOW:
1855  de_ctx->max_uniq_toclient_groups = 15;
1856  de_ctx->max_uniq_toserver_groups = 25;
1857  break;
1858 
1859  case ENGINE_PROFILE_HIGH:
1860  de_ctx->max_uniq_toclient_groups = 75;
1861  de_ctx->max_uniq_toserver_groups = 75;
1862  break;
1863 
1864  case ENGINE_PROFILE_CUSTOM:
1865  (void)ConfGet("detect.custom-values.toclient-groups",
1866  &max_uniq_toclient_groups_str);
1867  (void)ConfGet("detect.custom-values.toserver-groups",
1868  &max_uniq_toserver_groups_str);
1869 
1870  if (de_ctx_custom != NULL) {
1871  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
1872  if (opt->val && strcmp(opt->val, "custom-values") == 0) {
1873  if (max_uniq_toclient_groups_str == NULL) {
1874  max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
1875  (opt->head.tqh_first, "toclient-sp-groups");
1876  }
1877  if (max_uniq_toclient_groups_str == NULL) {
1878  max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
1879  (opt->head.tqh_first, "toclient-groups");
1880  }
1881  if (max_uniq_toserver_groups_str == NULL) {
1882  max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
1883  (opt->head.tqh_first, "toserver-dp-groups");
1884  }
1885  if (max_uniq_toserver_groups_str == NULL) {
1886  max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
1887  (opt->head.tqh_first, "toserver-groups");
1888  }
1889  }
1890  }
1891  }
1892  if (max_uniq_toclient_groups_str != NULL) {
1894  strlen(max_uniq_toclient_groups_str),
1895  (const char *)max_uniq_toclient_groups_str) <= 0)
1896  {
1897  de_ctx->max_uniq_toclient_groups = 20;
1898 
1899  SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
1900  "toclient-groups failed, using %u",
1901  max_uniq_toclient_groups_str,
1902  de_ctx->max_uniq_toclient_groups);
1903  }
1904  } else {
1905  de_ctx->max_uniq_toclient_groups = 20;
1906  }
1907  SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups);
1908 
1909  if (max_uniq_toserver_groups_str != NULL) {
1911  strlen(max_uniq_toserver_groups_str),
1912  (const char *)max_uniq_toserver_groups_str) <= 0)
1913  {
1914  de_ctx->max_uniq_toserver_groups = 40;
1915 
1916  SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
1917  "toserver-groups failed, using %u",
1918  max_uniq_toserver_groups_str,
1919  de_ctx->max_uniq_toserver_groups);
1920  }
1921  } else {
1922  de_ctx->max_uniq_toserver_groups = 40;
1923  }
1924  SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups);
1925  break;
1926 
1927  /* Default (or no config provided) is profile medium */
1928  case ENGINE_PROFILE_MEDIUM:
1930  default:
1931  de_ctx->max_uniq_toclient_groups = 20;
1932  de_ctx->max_uniq_toserver_groups = 40;
1933  break;
1934  }
1935 
1936  intmax_t value = 0;
1937  if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1)
1938  {
1939  if (value >= 0 && value <= INT_MAX) {
1940  de_ctx->inspection_recursion_limit = (int)value;
1941  }
1942 
1943  /* fall back to old config parsing */
1944  } else {
1945  ConfNode *insp_recursion_limit_node = NULL;
1946  char *insp_recursion_limit = NULL;
1947 
1948  if (de_ctx_custom != NULL) {
1949  opt = NULL;
1950  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
1951  if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0)
1952  continue;
1953 
1954  insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val);
1955  if (insp_recursion_limit_node == NULL) {
1956  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf "
1957  "entry for detect-engine:inspection-recursion-limit");
1958  break;
1959  }
1960  insp_recursion_limit = insp_recursion_limit_node->val;
1961  SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s",
1962  insp_recursion_limit_node->name, insp_recursion_limit_node->val);
1963  break;
1964  }
1965 
1966  if (insp_recursion_limit != NULL) {
1967  de_ctx->inspection_recursion_limit = atoi(insp_recursion_limit);
1968  } else {
1969  de_ctx->inspection_recursion_limit =
1971  }
1972  }
1973  }
1974 
1975  if (de_ctx->inspection_recursion_limit == 0)
1976  de_ctx->inspection_recursion_limit = -1;
1977 
1978  SCLogDebug("de_ctx->inspection_recursion_limit: %d",
1979  de_ctx->inspection_recursion_limit);
1980 
1981  /* parse port grouping whitelisting settings */
1982 
1983  const char *ports = NULL;
1984  (void)ConfGet("detect.grouping.tcp-whitelist", &ports);
1985  if (ports) {
1986  SCLogConfig("grouping: tcp-whitelist %s", ports);
1987  } else {
1988  ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080";
1989  SCLogConfig("grouping: tcp-whitelist (default) %s", ports);
1990 
1991  }
1992  if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) {
1993  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
1994  "for detect.grouping.tcp-whitelist", ports);
1995  }
1996  DetectPort *x = de_ctx->tcp_whitelist;
1997  for ( ; x != NULL; x = x->next) {
1998  if (x->port != x->port2) {
1999  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2000  "for detect.grouping.tcp-whitelist: only single ports allowed", ports);
2001  DetectPortCleanupList(de_ctx, de_ctx->tcp_whitelist);
2002  de_ctx->tcp_whitelist = NULL;
2003  break;
2004  }
2005  }
2006 
2007  ports = NULL;
2008  (void)ConfGet("detect.grouping.udp-whitelist", &ports);
2009  if (ports) {
2010  SCLogConfig("grouping: udp-whitelist %s", ports);
2011  } else {
2012  ports = "53, 135, 5060";
2013  SCLogConfig("grouping: udp-whitelist (default) %s", ports);
2014 
2015  }
2016  if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) {
2017  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2018  "forr detect.grouping.udp-whitelist", ports);
2019  }
2020  for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) {
2021  if (x->port != x->port2) {
2022  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2023  "for detect.grouping.udp-whitelist: only single ports allowed", ports);
2024  DetectPortCleanupList(de_ctx, de_ctx->udp_whitelist);
2025  de_ctx->udp_whitelist = NULL;
2026  break;
2027  }
2028  }
2029 
2031  const char *pf_setting = NULL;
2032  if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) {
2033  if (strcasecmp(pf_setting, "mpm") == 0) {
2035  } else if (strcasecmp(pf_setting, "auto") == 0) {
2037  }
2038  }
2039  switch (de_ctx->prefilter_setting) {
2040  case DETECT_PREFILTER_MPM:
2041  SCLogConfig("prefilter engines: MPM");
2042  break;
2043  case DETECT_PREFILTER_AUTO:
2044  SCLogConfig("prefilter engines: MPM and keywords");
2045  break;
2046  }
2047 
2048  return 0;
2049 }
2050 
2051 /*
2052  * getting & (re)setting the internal sig i
2053  */
2054 
2055 //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx)
2056 //{
2057 // return de_ctx->signum;
2058 //}
2059 
2061 {
2062  de_ctx->signum = 0;
2063 }
2064 
2065 static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2066 {
2067  const DetectEngineMasterCtx *master = &g_master_de_ctx;
2068 
2069  if (master->keyword_id > 0) {
2070  // coverity[suspicious_sizeof : FALSE]
2071  det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *));
2072  if (det_ctx->global_keyword_ctxs_array == NULL) {
2073  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2074  return TM_ECODE_FAILED;
2075  }
2076  det_ctx->global_keyword_ctxs_size = master->keyword_id;
2077 
2078  const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2079  while (item) {
2080  det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2081  if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) {
2082  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2083  "for keyword \"%s\" failed", item->name);
2084  return TM_ECODE_FAILED;
2085  }
2086  item = item->next;
2087  }
2088  }
2089  return TM_ECODE_OK;
2090 }
2091 
2092 static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2093 {
2094  if (det_ctx->global_keyword_ctxs_array == NULL ||
2095  det_ctx->global_keyword_ctxs_size == 0) {
2096  return;
2097  }
2098 
2099  const DetectEngineMasterCtx *master = &g_master_de_ctx;
2100  if (master->keyword_id > 0) {
2101  const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2102  while (item) {
2103  if (det_ctx->global_keyword_ctxs_array[item->id] != NULL)
2104  item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]);
2105 
2106  item = item->next;
2107  }
2108  det_ctx->global_keyword_ctxs_size = 0;
2110  det_ctx->global_keyword_ctxs_array = NULL;
2111  }
2112 }
2113 
2114 static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2115 {
2116  if (de_ctx->keyword_id > 0) {
2117  // coverity[suspicious_sizeof : FALSE]
2118  det_ctx->keyword_ctxs_array = SCMalloc(de_ctx->keyword_id * sizeof(void *));
2119  if (det_ctx->keyword_ctxs_array == NULL) {
2120  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2121  return TM_ECODE_FAILED;
2122  }
2123 
2124  memset(det_ctx->keyword_ctxs_array, 0x00, de_ctx->keyword_id * sizeof(void *));
2125 
2126  det_ctx->keyword_ctxs_size = de_ctx->keyword_id;
2127 
2129  while (item) {
2130  det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2131  if (det_ctx->keyword_ctxs_array[item->id] == NULL) {
2132  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2133  "for keyword \"%s\" failed", item->name);
2134  return TM_ECODE_FAILED;
2135  }
2136  item = item->next;
2137  }
2138  }
2139  return TM_ECODE_OK;
2140 }
2141 
2142 static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2143 {
2144  if (de_ctx->keyword_id > 0) {
2146  while (item) {
2147  if (det_ctx->keyword_ctxs_array[item->id] != NULL)
2148  item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
2149 
2150  item = item->next;
2151  }
2152  det_ctx->keyword_ctxs_size = 0;
2153  SCFree(det_ctx->keyword_ctxs_array);
2154  det_ctx->keyword_ctxs_array = NULL;
2155  }
2156 }
2157 
2158 /** NOTE: master MUST be locked before calling this */
2159 static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
2160 {
2161  DetectEngineMasterCtx *master = &g_master_de_ctx;
2162  DetectEngineTenantMapping *map_array = NULL;
2163  uint32_t map_array_size = 0;
2164  uint32_t map_cnt = 0;
2165  int max_tenant_id = 0;
2166  DetectEngineCtx *list = master->list;
2167  HashTable *mt_det_ctxs_hash = NULL;
2168 
2169  if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
2170  SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: "
2171  "set using multi-detect.selector");
2172  return TM_ECODE_FAILED;
2173  }
2174 
2175  uint32_t tcnt = 0;
2176  while (list) {
2177  if (list->tenant_id > max_tenant_id)
2178  max_tenant_id = list->tenant_id;
2179 
2180  list = list->next;
2181  tcnt++;
2182  }
2183 
2184  mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
2185  if (mt_det_ctxs_hash == NULL) {
2186  goto error;
2187  }
2188 
2189  if (tcnt == 0) {
2190  SCLogInfo("no tenants left, or none registered yet");
2191  } else {
2192  max_tenant_id++;
2193 
2195  while (map) {
2196  map_cnt++;
2197  map = map->next;
2198  }
2199 
2200  if (map_cnt > 0) {
2201  map_array_size = map_cnt + 1;
2202 
2203  map_array = SCCalloc(map_array_size, sizeof(*map_array));
2204  if (map_array == NULL)
2205  goto error;
2206 
2207  /* fill the array */
2208  map_cnt = 0;
2209  map = master->tenant_mapping_list;
2210  while (map) {
2211  if (map_cnt >= map_array_size) {
2212  goto error;
2213  }
2214  map_array[map_cnt].traffic_id = map->traffic_id;
2215  map_array[map_cnt].tenant_id = map->tenant_id;
2216  map_cnt++;
2217  map = map->next;
2218  }
2219 
2220  }
2221 
2222  /* set up hash for tenant lookup */
2223  list = master->list;
2224  while (list) {
2225  SCLogDebug("tenant-id %u", list->tenant_id);
2226  if (list->tenant_id != 0) {
2227  DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
2228  if (mt_det_ctx == NULL)
2229  goto error;
2230  if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) {
2231  goto error;
2232  }
2233  }
2234  list = list->next;
2235  }
2236  }
2237 
2238  det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
2239  mt_det_ctxs_hash = NULL;
2240 
2241  det_ctx->mt_det_ctxs_cnt = max_tenant_id;
2242 
2243  det_ctx->tenant_array = map_array;
2244  det_ctx->tenant_array_size = map_array_size;
2245 
2246  switch (master->tenant_selector) {
2248  SCLogDebug("TENANT_SELECTOR_UNKNOWN");
2249  break;
2250  case TENANT_SELECTOR_VLAN:
2251  det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
2252  SCLogDebug("TENANT_SELECTOR_VLAN");
2253  break;
2255  det_ctx->TenantGetId = DetectEngineTentantGetIdFromLivedev;
2256  SCLogDebug("TENANT_SELECTOR_LIVEDEV");
2257  break;
2259  det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
2260  SCLogDebug("TENANT_SELECTOR_DIRECT");
2261  break;
2262  }
2263 
2264  return TM_ECODE_OK;
2265 error:
2266  if (map_array != NULL)
2267  SCFree(map_array);
2268  if (mt_det_ctxs_hash != NULL)
2269  HashTableFree(mt_det_ctxs_hash);
2270 
2271  return TM_ECODE_FAILED;
2272 }
2273 
2274 /** \internal
2275  * \brief Helper for DetectThread setup functions
2276  */
2277 static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2278 {
2279  PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher);
2280  PatternMatchThreadPrepare(&det_ctx->mtcs, de_ctx->mpm_matcher);
2281  PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher);
2282 
2283  PmqSetup(&det_ctx->pmq);
2284 
2286  if (det_ctx->spm_thread_ctx == NULL) {
2287  return TM_ECODE_FAILED;
2288  }
2289 
2290  /* sized to the max of our sgh settings. A max setting of 0 implies that all
2291  * sgh's have: sgh->non_pf_store_cnt == 0 */
2292  if (de_ctx->non_pf_store_cnt_max > 0) {
2293  det_ctx->non_pf_id_array = SCCalloc(de_ctx->non_pf_store_cnt_max, sizeof(SigIntId));
2294  BUG_ON(det_ctx->non_pf_id_array == NULL);
2295  }
2296 
2297  /* IP-ONLY */
2298  DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx);
2299 
2300  /* DeState */
2301  if (de_ctx->sig_array_len > 0) {
2302  det_ctx->match_array_len = de_ctx->sig_array_len;
2303  det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *));
2304  if (det_ctx->match_array == NULL) {
2305  return TM_ECODE_FAILED;
2306  }
2307  memset(det_ctx->match_array, 0,
2308  det_ctx->match_array_len * sizeof(Signature *));
2309 
2310  RuleMatchCandidateTxArrayInit(det_ctx, de_ctx->sig_array_len);
2311  }
2312 
2313  /* byte_extract storage */
2314  det_ctx->bj_values = SCMalloc(sizeof(*det_ctx->bj_values) *
2315  (de_ctx->byte_extract_max_local_id + 1));
2316  if (det_ctx->bj_values == NULL) {
2317  return TM_ECODE_FAILED;
2318  }
2319 
2320  /* Allocate space for base64 decoded data. */
2321  if (de_ctx->base64_decode_max_len) {
2322  det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len);
2323  if (det_ctx->base64_decoded == NULL) {
2324  return TM_ECODE_FAILED;
2325  }
2326  det_ctx->base64_decoded_len_max = de_ctx->base64_decode_max_len;
2327  det_ctx->base64_decoded_len = 0;
2328  }
2329 
2330  det_ctx->inspect.buffers_size = de_ctx->buffer_type_id;
2331  det_ctx->inspect.buffers = SCCalloc(det_ctx->inspect.buffers_size, sizeof(InspectionBuffer));
2332  if (det_ctx->inspect.buffers == NULL) {
2333  return TM_ECODE_FAILED;
2334  }
2335  det_ctx->inspect.to_clear_queue = SCCalloc(det_ctx->inspect.buffers_size, sizeof(uint32_t));
2336  if (det_ctx->inspect.to_clear_queue == NULL) {
2337  return TM_ECODE_FAILED;
2338  }
2339  det_ctx->inspect.to_clear_idx = 0;
2340 
2341  det_ctx->multi_inspect.buffers_size = de_ctx->buffer_type_id;
2343  if (det_ctx->multi_inspect.buffers == NULL) {
2344  return TM_ECODE_FAILED;
2345  }
2346  det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t));
2347  if (det_ctx->multi_inspect.to_clear_queue == NULL) {
2348  return TM_ECODE_FAILED;
2349  }
2350  det_ctx->multi_inspect.to_clear_idx = 0;
2351 
2352 
2353  DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
2354  DetectEngineThreadCtxInitGlobalKeywords(det_ctx);
2355 #ifdef PROFILING
2356  SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx);
2359  SCProfilingSghThreadSetup(de_ctx->profile_sgh_ctx, det_ctx);
2360 #endif
2361  SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect);
2362 
2363  return TM_ECODE_OK;
2364 }
2365 
2366 /** \brief initialize thread specific detection engine context
2367  *
2368  * \note there is a special case when using delayed detect. In this case the
2369  * function is called twice per thread. The first time the rules are not
2370  * yet loaded. de_ctx->delayed_detect_initialized will be 0. The 2nd
2371  * time they will be loaded. de_ctx->delayed_detect_initialized will be 1.
2372  * This is needed to do the per thread counter registration before the
2373  * packet runtime starts. In delayed detect mode, the first call will
2374  * return a NULL ptr through the data ptr.
2375  *
2376  * \param tv ThreadVars for this thread
2377  * \param initdata pointer to de_ctx
2378  * \param data[out] pointer to store our thread detection ctx
2379  *
2380  * \retval TM_ECODE_OK if all went well
2381  * \retval TM_ECODE_FAILED on serious erro
2382  */
2383 TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
2384 {
2386  if (unlikely(det_ctx == NULL))
2387  return TM_ECODE_FAILED;
2388  memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2389 
2390  det_ctx->tv = tv;
2391  det_ctx->de_ctx = DetectEngineGetCurrent();
2392  if (det_ctx->de_ctx == NULL) {
2393 #ifdef UNITTESTS
2394  if (RunmodeIsUnittests()) {
2395  det_ctx->de_ctx = (DetectEngineCtx *)initdata;
2396  } else {
2397  DetectEngineThreadCtxDeinit(tv, det_ctx);
2398  return TM_ECODE_FAILED;
2399  }
2400 #else
2401  DetectEngineThreadCtxDeinit(tv, det_ctx);
2402  return TM_ECODE_FAILED;
2403 #endif
2404  }
2405 
2406  if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2407  det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2408  {
2409  if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2410  DetectEngineThreadCtxDeinit(tv, det_ctx);
2411  return TM_ECODE_FAILED;
2412  }
2413  }
2414 
2415  /** alert counter setup */
2416  det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2417 #ifdef PROFILING
2418  det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2419  det_ctx->counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2420  det_ctx->counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2421  det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2422 #endif
2423 
2425  if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2426  DetectEngineThreadCtxDeinit(tv, det_ctx);
2427  return TM_ECODE_FAILED;
2428  }
2429  }
2430 
2431  /* pass thread data back to caller */
2432  *data = (void *)det_ctx;
2433 
2434  return TM_ECODE_OK;
2435 }
2436 
2437 /**
2438  * \internal
2439  * \brief initialize a det_ctx for reload cases
2440  * \param new_de_ctx the new detection engine
2441  * \param mt flag to indicate if MT should be set up for this det_ctx
2442  * this should only be done for the 'root' det_ctx
2443  *
2444  * \retval det_ctx detection engine thread ctx or NULL in case of error
2445  */
2446 static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
2447  ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
2448 {
2450  if (unlikely(det_ctx == NULL))
2451  return NULL;
2452  memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2453 
2454  det_ctx->tenant_id = new_de_ctx->tenant_id;
2455  det_ctx->tv = tv;
2456  det_ctx->de_ctx = DetectEngineReference(new_de_ctx);
2457  if (det_ctx->de_ctx == NULL) {
2458  SCFree(det_ctx);
2459  return NULL;
2460  }
2461 
2462  /* most of the init happens here */
2463  if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2464  det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2465  {
2466  if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2467  DetectEngineDeReference(&det_ctx->de_ctx);
2468  SCFree(det_ctx);
2469  return NULL;
2470  }
2471  }
2472 
2473  /** alert counter setup */
2474  det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2475 #ifdef PROFILING
2476  uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2477  uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2478  uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2479  uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2480  det_ctx->counter_mpm_list = counter_mpm_list;
2481  det_ctx->counter_nonmpm_list = counter_nonmpm_list;
2482  det_ctx->counter_fnonmpm_list = counter_fnonmpm_list;
2483  det_ctx->counter_match_list = counter_match_list;
2484 #endif
2485 
2486  if (mt && DetectEngineMultiTenantEnabled()) {
2487  if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2488  DetectEngineDeReference(&det_ctx->de_ctx);
2489  SCFree(det_ctx);
2490  return NULL;
2491  }
2492  }
2493 
2494  return det_ctx;
2495 }
2496 
2497 static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
2498 {
2499 #if DEBUG
2500  SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt);
2501 
2502  SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size);
2503  SCLogDebug("STREAM MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size);
2504 
2505  SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size);
2506  SCLogDebug("STREAM SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size);
2507 #endif
2508 
2509  if (det_ctx->tenant_array != NULL) {
2510  SCFree(det_ctx->tenant_array);
2511  det_ctx->tenant_array = NULL;
2512  }
2513 
2514 #ifdef PROFILING
2518  SCProfilingSghThreadCleanup(det_ctx);
2519 #endif
2520 
2522 
2523  /** \todo get rid of this static */
2524  if (det_ctx->de_ctx != NULL) {
2525  PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
2526  PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher);
2527  PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
2528  }
2529 
2530  PmqFree(&det_ctx->pmq);
2531 
2532  if (det_ctx->spm_thread_ctx != NULL) {
2534  }
2535 
2536  if (det_ctx->non_pf_id_array != NULL)
2537  SCFree(det_ctx->non_pf_id_array);
2538 
2539  if (det_ctx->match_array != NULL)
2540  SCFree(det_ctx->match_array);
2541 
2543 
2544  if (det_ctx->bj_values != NULL)
2545  SCFree(det_ctx->bj_values);
2546 
2547  /* Decoded base64 data. */
2548  if (det_ctx->base64_decoded != NULL) {
2549  SCFree(det_ctx->base64_decoded);
2550  }
2551 
2552  if (det_ctx->inspect.buffers) {
2553  for (uint32_t i = 0; i < det_ctx->inspect.buffers_size; i++) {
2554  InspectionBufferFree(&det_ctx->inspect.buffers[i]);
2555  }
2556  SCFree(det_ctx->inspect.buffers);
2557  }
2558  if (det_ctx->inspect.to_clear_queue) {
2559  SCFree(det_ctx->inspect.to_clear_queue);
2560  }
2561  if (det_ctx->multi_inspect.buffers) {
2562  for (uint32_t i = 0; i < det_ctx->multi_inspect.buffers_size; i++) {
2564  for (uint32_t x = 0; x < fb->size; x++) {
2566  }
2568  }
2569  SCFree(det_ctx->multi_inspect.buffers);
2570  }
2571  if (det_ctx->multi_inspect.to_clear_queue) {
2573  }
2574 
2575  DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx);
2576  if (det_ctx->de_ctx != NULL) {
2577  DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
2578 #ifdef UNITTESTS
2579  if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0)
2580  DetectEngineDeReference(&det_ctx->de_ctx);
2581 #else
2582  DetectEngineDeReference(&det_ctx->de_ctx);
2583 #endif
2584  }
2585 
2587 
2588  SCFree(det_ctx);
2589 }
2590 
2592 {
2593  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
2594 
2595  if (det_ctx == NULL) {
2596  SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL");
2597  return TM_ECODE_OK;
2598  }
2599 
2600  if (det_ctx->mt_det_ctxs_hash != NULL) {
2601  HashTableFree(det_ctx->mt_det_ctxs_hash);
2602  det_ctx->mt_det_ctxs_hash = NULL;
2603  }
2604  DetectEngineThreadCtxFree(det_ctx);
2605 
2606  return TM_ECODE_OK;
2607 }
2608 
2610 {
2611  /* XXX */
2612  PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
2613  PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
2614 }
2615 
2616 /** \brief Register Thread keyword context Funcs
2617  *
2618  * \param de_ctx detection engine to register in
2619  * \param name keyword name for error printing
2620  * \param InitFunc function ptr
2621  * \param data keyword init data to pass to Func
2622  * \param FreeFunc function ptr
2623  * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct)
2624  *
2625  * \retval id for retrieval of ctx at runtime
2626  * \retval -1 on error
2627  *
2628  * \note make sure "data" remains valid and it free'd elsewhere. It's
2629  * recommended to store it in the keywords global ctx so that
2630  * it's freed when the de_ctx is freed.
2631  */
2632 int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode)
2633 {
2634  BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL || data == NULL);
2635 
2636  if (mode) {
2638  while (item != NULL) {
2639  if (strcmp(name, item->name) == 0) {
2640  return item->id;
2641  }
2642 
2643  item = item->next;
2644  }
2645  }
2646 
2648  if (unlikely(item == NULL))
2649  return -1;
2650  memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem));
2651 
2652  item->InitFunc = InitFunc;
2653  item->FreeFunc = FreeFunc;
2654  item->data = data;
2655  item->name = name;
2656 
2657  item->next = de_ctx->keyword_list;
2658  de_ctx->keyword_list = item;
2659  item->id = de_ctx->keyword_id++;
2660 
2661  return item->id;
2662 }
2663 
2664 /** \brief Retrieve thread local keyword ctx by id
2665  *
2666  * \param det_ctx detection engine thread ctx to retrieve the ctx from
2667  * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
2668  * keyword init.
2669  *
2670  * \retval ctx or NULL on error
2671  */
2673 {
2674  if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL)
2675  return NULL;
2676 
2677  return det_ctx->keyword_ctxs_array[id];
2678 }
2679 
2680 
2681 /** \brief Register Thread keyword context Funcs (Global)
2682  *
2683  * IDs stay static over reloads and between tenants
2684  *
2685  * \param name keyword name for error printing
2686  * \param InitFunc function ptr
2687  * \param FreeFunc function ptr
2688  *
2689  * \retval id for retrieval of ctx at runtime
2690  * \retval -1 on error
2691  */
2693  void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *))
2694 {
2695  int id;
2696  BUG_ON(InitFunc == NULL || FreeFunc == NULL);
2697 
2698  DetectEngineMasterCtx *master = &g_master_de_ctx;
2699 
2700  /* if already registered, return existing id */
2702  while (item != NULL) {
2703  if (strcmp(name, item->name) == 0) {
2704  id = item->id;
2705  return id;
2706  }
2707 
2708  item = item->next;
2709  }
2710 
2711  item = SCCalloc(1, sizeof(*item));
2712  if (unlikely(item == NULL)) {
2713  return -1;
2714  }
2715  item->InitFunc = InitFunc;
2716  item->FreeFunc = FreeFunc;
2717  item->name = name;
2718  item->data = data;
2719 
2720  item->next = master->keyword_list;
2721  master->keyword_list = item;
2722  item->id = master->keyword_id++;
2723 
2724  id = item->id;
2725  return id;
2726 }
2727 
2728 /** \brief Retrieve thread local keyword ctx by id
2729  *
2730  * \param det_ctx detection engine thread ctx to retrieve the ctx from
2731  * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
2732  * keyword init.
2733  *
2734  * \retval ctx or NULL on error
2735  */
2737 {
2738  if (id < 0 || id > det_ctx->global_keyword_ctxs_size ||
2739  det_ctx->global_keyword_ctxs_array == NULL) {
2740  return NULL;
2741  }
2742 
2743  return det_ctx->global_keyword_ctxs_array[id];
2744 }
2745 
2746 /** \brief Check if detection is enabled
2747  * \retval bool true or false */
2749 {
2750  DetectEngineMasterCtx *master = &g_master_de_ctx;
2751  SCMutexLock(&master->lock);
2752 
2753  if (master->list == NULL) {
2754  SCMutexUnlock(&master->lock);
2755  return 0;
2756  }
2757 
2758  SCMutexUnlock(&master->lock);
2759  return 1;
2760 }
2761 
2763 {
2764  uint32_t version;
2765  DetectEngineMasterCtx *master = &g_master_de_ctx;
2766  SCMutexLock(&master->lock);
2767  version = master->version;
2768  SCMutexUnlock(&master->lock);
2769  return version;
2770 }
2771 
2773 {
2774  DetectEngineMasterCtx *master = &g_master_de_ctx;
2775  SCMutexLock(&master->lock);
2776  master->version++;
2777  SCLogDebug("master version now %u", master->version);
2778  SCMutexUnlock(&master->lock);
2779 }
2780 
2782 {
2783  DetectEngineMasterCtx *master = &g_master_de_ctx;
2784  SCMutexLock(&master->lock);
2785 
2786  DetectEngineCtx *de_ctx = master->list;
2787  while (de_ctx) {
2788  if (de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2789  de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB ||
2790  de_ctx->type == DETECT_ENGINE_TYPE_MT_STUB)
2791  {
2792  de_ctx->ref_cnt++;
2793  SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt);
2794  SCMutexUnlock(&master->lock);
2795  return de_ctx;
2796  }
2797  de_ctx = de_ctx->next;
2798  }
2799 
2800  SCMutexUnlock(&master->lock);
2801  return NULL;
2802 }
2803 
2805 {
2806  if (de_ctx == NULL)
2807  return NULL;
2808  de_ctx->ref_cnt++;
2809  return de_ctx;
2810 }
2811 
2812 /** TODO locking? Not needed if this is a one time setting at startup */
2814 {
2815  DetectEngineMasterCtx *master = &g_master_de_ctx;
2816  return (master->multi_tenant_enabled);
2817 }
2818 
2819 /** \internal
2820  * \brief load a tenant from a yaml file
2821  *
2822  * \param tenant_id the tenant id by which the config is known
2823  * \param filename full path of a yaml file
2824  * \param loader_id id of loader thread or -1
2825  *
2826  * \retval 0 ok
2827  * \retval -1 failed
2828  */
2829 static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id)
2830 {
2831  DetectEngineCtx *de_ctx = NULL;
2832  char prefix[64];
2833 
2834  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
2835 
2836 #ifdef OS_WIN32
2837  struct _stat st;
2838  if(_stat(filename, &st) != 0) {
2839 #else
2840  struct stat st;
2841  if(stat(filename, &st) != 0) {
2842 #endif /* OS_WIN32 */
2843  SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename);
2844  goto error;
2845  }
2846 
2847  de_ctx = DetectEngineGetByTenantId(tenant_id);
2848  if (de_ctx != NULL) {
2849  SCLogError(SC_ERR_MT_DUPLICATE_TENANT, "tenant %u already registered",
2850  tenant_id);
2851  DetectEngineDeReference(&de_ctx);
2852  goto error;
2853  }
2854 
2855  ConfNode *node = ConfGetNode(prefix);
2856  if (node == NULL) {
2857  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
2858  goto error;
2859  }
2860 
2861  de_ctx = DetectEngineCtxInitWithPrefix(prefix);
2862  if (de_ctx == NULL) {
2863  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
2864  "context failed.");
2865  goto error;
2866  }
2867  SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
2868 
2869  de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
2870  de_ctx->tenant_id = tenant_id;
2871  de_ctx->loader_id = loader_id;
2872 
2873  if (SigLoadSignatures(de_ctx, NULL, 0) < 0) {
2874  SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
2875  goto error;
2876  }
2877 
2878  DetectEngineAddToMaster(de_ctx);
2879 
2880  return 0;
2881 
2882 error:
2883  if (de_ctx != NULL) {
2884  DetectEngineCtxFree(de_ctx);
2885  }
2886  return -1;
2887 }
2888 
2889 static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt)
2890 {
2891  DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
2892  if (old_de_ctx == NULL) {
2893  SCLogError(SC_ERR_INITIALIZATION, "tenant detect engine not found");
2894  return -1;
2895  }
2896 
2897  char prefix[64];
2898  snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
2899  reload_cnt++;
2900  SCLogDebug("prefix %s", prefix);
2901 
2902  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
2903  SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml");
2904  goto error;
2905  }
2906 
2907  ConfNode *node = ConfGetNode(prefix);
2908  if (node == NULL) {
2909  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
2910  goto error;
2911  }
2912 
2913  DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
2914  if (new_de_ctx == NULL) {
2915  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
2916  "context failed.");
2917  goto error;
2918  }
2919  SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix);
2920 
2921  new_de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
2922  new_de_ctx->tenant_id = tenant_id;
2923  new_de_ctx->loader_id = old_de_ctx->loader_id;
2924 
2925  if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) {
2926  SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
2927  goto error;
2928  }
2929 
2930  DetectEngineAddToMaster(new_de_ctx);
2931 
2932  /* move to free list */
2933  DetectEngineMoveToFreeList(old_de_ctx);
2934  DetectEngineDeReference(&old_de_ctx);
2935  return 0;
2936 
2937 error:
2938  DetectEngineDeReference(&old_de_ctx);
2939  return -1;
2940 }
2941 
2942 
2943 typedef struct TenantLoaderCtx_ {
2944  uint32_t tenant_id;
2945  int reload_cnt; /**< used by reload */
2946  const char *yaml;
2947 } TenantLoaderCtx;
2948 
2949 static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
2950 {
2951  TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
2952 
2953  SCLogDebug("loader %d", loader_id);
2954  if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
2955  return -1;
2956  }
2957  return 0;
2958 }
2959 
2960 static int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml)
2961 {
2962  TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
2963  if (t == NULL)
2964  return -ENOMEM;
2965 
2966  t->tenant_id = tenant_id;
2967  t->yaml = yaml;
2968 
2969  return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t);
2970 }
2971 
2972 static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id)
2973 {
2974  TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
2975 
2976  SCLogDebug("loader_id %d", loader_id);
2977 
2978  if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) {
2979  return -1;
2980  }
2981  return 0;
2982 }
2983 
2984 static int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt)
2985 {
2986  DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
2987  if (old_de_ctx == NULL)
2988  return -ENOENT;
2989  int loader_id = old_de_ctx->loader_id;
2990  DetectEngineDeReference(&old_de_ctx);
2991 
2992  TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
2993  if (t == NULL)
2994  return -ENOMEM;
2995 
2996  t->tenant_id = tenant_id;
2997  t->yaml = yaml;
2998  t->reload_cnt = reload_cnt;
2999 
3000  SCLogDebug("loader_id %d", loader_id);
3001 
3002  return DetectLoaderQueueTask(loader_id, DetectLoaderFuncReloadTenant, t);
3003 }
3004 
3005 /** \brief Load a tenant and wait for loading to complete
3006  */
3007 int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
3008 {
3009  int r = DetectLoaderSetupLoadTenant(tenant_id, yaml);
3010  if (r < 0)
3011  return r;
3012 
3013  if (DetectLoadersSync() != 0)
3014  return -1;
3015 
3016  return 0;
3017 }
3018 
3019 /** \brief Reload a tenant and wait for loading to complete
3020  */
3021 int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
3022 {
3023  int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt);
3024  if (r < 0)
3025  return r;
3026 
3027  if (DetectLoadersSync() != 0)
3028  return -1;
3029 
3030  return 0;
3031 }
3032 
3033 static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
3034  bool failure_fatal)
3035 {
3036  ConfNode *mapping_node = NULL;
3037 
3038  int mapping_cnt = 0;
3039  if (mappings_root_node != NULL) {
3040  TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3041  ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3042  if (tenant_id_node == NULL)
3043  goto bad_mapping;
3044  ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
3045  if (device_node == NULL)
3046  goto bad_mapping;
3047 
3048  uint32_t tenant_id = 0;
3049  if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3050  tenant_id_node->val) == -1)
3051  {
3052  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3053  "of %s is invalid", tenant_id_node->val);
3054  goto bad_mapping;
3055  }
3056 
3057  const char *dev = device_node->val;
3058  LiveDevice *ld = LiveGetDevice(dev);
3059  if (ld == NULL) {
3060  SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s not found", dev);
3061  goto bad_mapping;
3062  }
3063 
3064  if (ld->tenant_id_set) {
3065  SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s already mapped to tenant-id %u",
3066  dev, ld->tenant_id);
3067  goto bad_mapping;
3068  }
3069 
3070  ld->tenant_id = tenant_id;
3071  ld->tenant_id_set = true;
3072 
3073  if (DetectEngineTentantRegisterLivedev(tenant_id, ld->id) != 0) {
3074  goto error;
3075  }
3076 
3077  SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
3078  mapping_cnt++;
3079  continue;
3080 
3081  bad_mapping:
3082  if (failure_fatal)
3083  goto error;
3084  }
3085  }
3086  SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
3087  return mapping_cnt;
3088 
3089 error:
3090  return 0;
3091 }
3092 
3093 static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
3094  bool failure_fatal)
3095 {
3096  ConfNode *mapping_node = NULL;
3097 
3098  int mapping_cnt = 0;
3099  if (mappings_root_node != NULL) {
3100  TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3101  ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3102  if (tenant_id_node == NULL)
3103  goto bad_mapping;
3104  ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
3105  if (vlan_id_node == NULL)
3106  goto bad_mapping;
3107 
3108  uint32_t tenant_id = 0;
3109  if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3110  tenant_id_node->val) == -1)
3111  {
3112  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3113  "of %s is invalid", tenant_id_node->val);
3114  goto bad_mapping;
3115  }
3116 
3117  uint16_t vlan_id = 0;
3118  if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val),
3119  vlan_id_node->val) == -1)
3120  {
3122  "of %s is invalid", vlan_id_node->val);
3123  goto bad_mapping;
3124  }
3125  if (vlan_id == 0 || vlan_id >= 4095) {
3127  "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
3128  goto bad_mapping;
3129  }
3130 
3131  if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
3132  goto error;
3133  }
3134  SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
3135  mapping_cnt++;
3136  continue;
3137 
3138  bad_mapping:
3139  if (failure_fatal)
3140  goto error;
3141  }
3142  }
3143  return mapping_cnt;
3144 
3145 error:
3146  return 0;
3147 }
3148 
3149 /**
3150  * \brief setup multi-detect / multi-tenancy
3151  *
3152  * See if MT is enabled. If so, setup the selector, tenants and mappings.
3153  * Tenants and mappings are optional, and can also dynamically be added
3154  * and removed from the unix socket.
3155  */
3157 {
3159  DetectEngineMasterCtx *master = &g_master_de_ctx;
3160 
3161  int unix_socket = ConfUnixSocketIsEnable();
3162 
3163  int failure_fatal = 0;
3164  (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal);
3165 
3166  int enabled = 0;
3167  (void)ConfGetBool("multi-detect.enabled", &enabled);
3168  if (enabled == 1) {
3173 
3174  SCMutexLock(&master->lock);
3175  master->multi_tenant_enabled = 1;
3176 
3177  const char *handler = NULL;
3178  if (ConfGet("multi-detect.selector", &handler) == 1) {
3179  SCLogConfig("multi-tenant selector type %s", handler);
3180 
3181  if (strcmp(handler, "vlan") == 0) {
3182  tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
3183 
3184  int vlanbool = 0;
3185  if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
3186  SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, "
3187  "can't use multi-detect selector 'vlan'");
3188  SCMutexUnlock(&master->lock);
3189  goto error;
3190  }
3191 
3192  } else if (strcmp(handler, "direct") == 0) {
3193  tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
3194  } else if (strcmp(handler, "device") == 0) {
3195  tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
3196  if (EngineModeIsIPS()) {
3198  "multi-tenant 'device' mode not supported for IPS");
3199  SCMutexUnlock(&master->lock);
3200  goto error;
3201  }
3202 
3203  } else {
3204  SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
3205  "multi-detect.selector", handler);
3206  SCMutexUnlock(&master->lock);
3207  goto error;
3208  }
3209  }
3210  SCMutexUnlock(&master->lock);
3211  SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler);
3212 
3213  /* traffic -- tenant mappings */
3214  ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
3215 
3216  if (tenant_selector == TENANT_SELECTOR_VLAN) {
3217  int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
3218  failure_fatal);
3219  if (mapping_cnt == 0) {
3220  /* no mappings are valid when we're in unix socket mode,
3221  * they can be added on the fly. Otherwise warn/error
3222  * depending on failure_fatal */
3223 
3224  if (unix_socket) {
3225  SCLogNotice("no tenant traffic mappings defined, "
3226  "tenants won't be used until mappings are added");
3227  } else {
3228  if (failure_fatal) {
3229  SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3230  goto error;
3231  } else {
3232  SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3233  }
3234  }
3235  }
3236  } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
3237  int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
3238  failure_fatal);
3239  if (mapping_cnt == 0) {
3240  if (failure_fatal) {
3241  SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3242  goto error;
3243  } else {
3244  SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3245  }
3246  }
3247  }
3248 
3249  /* tenants */
3250  ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants");
3251  ConfNode *tenant_node = NULL;
3252 
3253  if (tenants_root_node != NULL) {
3254  TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
3255  ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id");
3256  if (id_node == NULL) {
3257  goto bad_tenant;
3258  }
3259  ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml");
3260  if (yaml_node == NULL) {
3261  goto bad_tenant;
3262  }
3263 
3264  uint32_t tenant_id = 0;
3265  if (ByteExtractStringUint32(&tenant_id, 10, strlen(id_node->val),
3266  id_node->val) == -1)
3267  {
3268  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id "
3269  "of %s is invalid", id_node->val);
3270  goto bad_tenant;
3271  }
3272  SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val);
3273 
3274  /* setup the yaml in this loop so that it's not done by the loader
3275  * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
3276  char prefix[64];
3277  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3278  if (ConfYamlLoadFileWithPrefix(yaml_node->val, prefix) != 0) {
3279  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", yaml_node->val);
3280  goto bad_tenant;
3281  }
3282 
3283  int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val);
3284  if (r < 0) {
3285  /* error logged already */
3286  goto bad_tenant;
3287  }
3288  continue;
3289 
3290  bad_tenant:
3291  if (failure_fatal)
3292  goto error;
3293  }
3294  }
3295 
3296  /* wait for our loaders to complete their tasks */
3297  if (DetectLoadersSync() != 0) {
3298  goto error;
3299  }
3300 
3302 
3303  } else {
3304  SCLogDebug("multi-detect not enabled (multi tenancy)");
3305  }
3306  return 0;
3307 error:
3308  return -1;
3309 }
3310 
3311 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)
3312 {
3313  const DetectEngineThreadCtx *det_ctx = ctx;
3314  uint32_t x = 0;
3315  uint32_t vlan_id = 0;
3316 
3317  if (p->vlan_idx == 0)
3318  return 0;
3319 
3320  vlan_id = p->vlan_id[0];
3321 
3322  if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0)
3323  return 0;
3324 
3325  /* not very efficient, but for now we're targeting only limited amounts.
3326  * Can use hash/tree approach later. */
3327  for (x = 0; x < det_ctx->tenant_array_size; x++) {
3328  if (det_ctx->tenant_array[x].traffic_id == vlan_id)
3329  return det_ctx->tenant_array[x].tenant_id;
3330  }
3331 
3332  return 0;
3333 }
3334 
3335 static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p)
3336 {
3337  const DetectEngineThreadCtx *det_ctx = ctx;
3338  const LiveDevice *ld = p->livedev;
3339 
3340  if (ld == NULL || det_ctx == NULL)
3341  return 0;
3342 
3343  SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
3344  return ld->tenant_id;
3345 }
3346 
3347 static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector,
3348  uint32_t tenant_id, uint32_t traffic_id)
3349 {
3350  DetectEngineMasterCtx *master = &g_master_de_ctx;
3351  SCMutexLock(&master->lock);
3352 
3353  if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) {
3354  SCLogInfo("conflicting selector already set");
3355  SCMutexUnlock(&master->lock);
3356  return -1;
3357  }
3358 
3360  while (m) {
3361  if (m->traffic_id == traffic_id) {
3362  SCLogInfo("traffic id already registered");
3363  SCMutexUnlock(&master->lock);
3364  return -1;
3365  }
3366  m = m->next;
3367  }
3368 
3369  DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map));
3370  if (map == NULL) {
3371  SCLogInfo("memory fail");
3372  SCMutexUnlock(&master->lock);
3373  return -1;
3374  }
3375  map->traffic_id = traffic_id;
3376  map->tenant_id = tenant_id;
3377 
3378  map->next = master->tenant_mapping_list;
3379  master->tenant_mapping_list = map;
3380 
3381  master->tenant_selector = selector;
3382 
3383  SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
3384  SCMutexUnlock(&master->lock);
3385  return 0;
3386 }
3387 
3388 static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelectors selector,
3389  uint32_t tenant_id, uint32_t traffic_id)
3390 {
3391  DetectEngineMasterCtx *master = &g_master_de_ctx;
3392  SCMutexLock(&master->lock);
3393 
3394  if (master->tenant_mapping_list == NULL) {
3395  SCMutexUnlock(&master->lock);
3396  return -1;
3397  }
3398 
3399  DetectEngineTenantMapping *prev = NULL;
3401  while (map) {
3402  if (map->traffic_id == traffic_id &&
3403  map->tenant_id == tenant_id)
3404  {
3405  if (prev != NULL)
3406  prev->next = map->next;
3407  else
3408  master->tenant_mapping_list = map->next;
3409 
3410  map->next = NULL;
3411  SCFree(map);
3412  SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id);
3413  SCMutexUnlock(&master->lock);
3414  return 0;
3415  }
3416  prev = map;
3417  map = map->next;
3418  }
3419 
3420  SCMutexUnlock(&master->lock);
3421  return -1;
3422 }
3423 
3424 int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
3425 {
3426  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
3427 }
3428 
3429 int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3430 {
3431  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3432 }
3433 
3434 int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3435 {
3436  return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3437 }
3438 
3440 {
3441  SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3442  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3443 }
3444 
3446 {
3447  SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3448  return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3449 }
3450 
3451 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p)
3452 {
3453  return p->pcap_v.tenant_id;
3454 }
3455 
3457 {
3458  DetectEngineMasterCtx *master = &g_master_de_ctx;
3459  SCMutexLock(&master->lock);
3460 
3461  if (master->list == NULL) {
3462  SCMutexUnlock(&master->lock);
3463  return NULL;
3464  }
3465 
3466  DetectEngineCtx *de_ctx = master->list;
3467  while (de_ctx) {
3468  if (de_ctx->type == DETECT_ENGINE_TYPE_TENANT &&
3469  de_ctx->tenant_id == tenant_id)
3470  {
3471  de_ctx->ref_cnt++;
3472  break;
3473  }
3474 
3475  de_ctx = de_ctx->next;
3476  }
3477 
3478  SCMutexUnlock(&master->lock);
3479  return de_ctx;
3480 }
3481 
3483 {
3484  BUG_ON((*de_ctx)->ref_cnt == 0);
3485  (*de_ctx)->ref_cnt--;
3486  *de_ctx = NULL;
3487 }
3488 
3489 static int DetectEngineAddToList(DetectEngineCtx *instance)
3490 {
3491  DetectEngineMasterCtx *master = &g_master_de_ctx;
3492 
3493  if (instance == NULL)
3494  return -1;
3495 
3496  if (master->list == NULL) {
3497  master->list = instance;
3498  } else {
3499  instance->next = master->list;
3500  master->list = instance;
3501  }
3502 
3503  return 0;
3504 }
3505 
3507 {
3508  int r;
3509 
3510  if (de_ctx == NULL)
3511  return -1;
3512 
3513  SCLogDebug("adding de_ctx %p to master", de_ctx);
3514 
3515  DetectEngineMasterCtx *master = &g_master_de_ctx;
3516  SCMutexLock(&master->lock);
3517  r = DetectEngineAddToList(de_ctx);
3518  SCMutexUnlock(&master->lock);
3519  return r;
3520 }
3521 
3523 {
3524  DetectEngineMasterCtx *master = &g_master_de_ctx;
3525 
3526  SCMutexLock(&master->lock);
3527  DetectEngineCtx *instance = master->list;
3528  if (instance == NULL) {
3529  SCMutexUnlock(&master->lock);
3530  return -1;
3531  }
3532 
3533  /* remove from active list */
3534  if (instance == de_ctx) {
3535  master->list = instance->next;
3536  } else {
3537  DetectEngineCtx *prev = instance;
3538  instance = instance->next; /* already checked first element */
3539 
3540  while (instance) {
3541  DetectEngineCtx *next = instance->next;
3542 
3543  if (instance == de_ctx) {
3544  prev->next = instance->next;
3545  break;
3546  }
3547 
3548  prev = instance;
3549  instance = next;
3550  }
3551  if (instance == NULL) {
3552  SCMutexUnlock(&master->lock);
3553  return -1;
3554  }
3555  }
3556 
3557  /* instance is now detached from list */
3558  instance->next = NULL;
3559 
3560  /* add to free list */
3561  if (master->free_list == NULL) {
3562  master->free_list = instance;
3563  } else {
3564  instance->next = master->free_list;
3565  master->free_list = instance;
3566  }
3567  SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt);
3568 
3569  SCMutexUnlock(&master->lock);
3570  return 0;
3571 }
3572 
3574 {
3575  DetectEngineMasterCtx *master = &g_master_de_ctx;
3576  SCMutexLock(&master->lock);
3577 
3578  DetectEngineCtx *prev = NULL;
3579  DetectEngineCtx *instance = master->free_list;
3580  while (instance) {
3581  DetectEngineCtx *next = instance->next;
3582 
3583  SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
3584 
3585  if (instance->ref_cnt == 0) {
3586  if (prev == NULL) {
3587  master->free_list = next;
3588  } else {
3589  prev->next = next;
3590  }
3591 
3592  SCLogDebug("freeing detect engine %p", instance);
3593  DetectEngineCtxFree(instance);
3594  instance = NULL;
3595  }
3596 
3597  prev = instance;
3598  instance = next;
3599  }
3600  SCMutexUnlock(&master->lock);
3601 }
3602 
3603 static int reloads = 0;
3604 
3605 /** \brief Reload the detection engine
3606  *
3607  * \param filename YAML file to load for the detect config
3608  *
3609  * \retval -1 error
3610  * \retval 0 ok
3611  */
3613 {
3614  DetectEngineCtx *new_de_ctx = NULL;
3615  DetectEngineCtx *old_de_ctx = NULL;
3616 
3617  char prefix[128];
3618  memset(prefix, 0, sizeof(prefix));
3619 
3620  SCLogNotice("rule reload starting");
3621 
3622  if (suri->conf_filename != NULL) {
3623  snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++);
3624  if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) {
3625  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s",
3626  suri->conf_filename);
3627  return -1;
3628  }
3629 
3630  ConfNode *node = ConfGetNode(prefix);
3631  if (node == NULL) {
3632  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s",
3633  suri->conf_filename);
3634  return -1;
3635  }
3636 #if 0
3637  ConfDump();
3638 #endif
3639  }
3640 
3641  /* get a reference to the current de_ctx */
3642  old_de_ctx = DetectEngineGetCurrent();
3643  if (old_de_ctx == NULL)
3644  return -1;
3645  SCLogDebug("get ref to old_de_ctx %p", old_de_ctx);
3646 
3647  /* only reload a regular 'normal' and 'delayed detect stub' detect engines */
3648  if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
3649  old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB))
3650  {
3651  DetectEngineDeReference(&old_de_ctx);
3652  SCLogNotice("rule reload complete");
3653  return -1;
3654  }
3655 
3656  /* get new detection engine */
3657  new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3658  if (new_de_ctx == NULL) {
3659  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3660  "context failed.");
3661  DetectEngineDeReference(&old_de_ctx);
3662  return -1;
3663  }
3664  if (SigLoadSignatures(new_de_ctx,
3665  suri->sig_file, suri->sig_file_exclusive) != 0) {
3666  DetectEngineCtxFree(new_de_ctx);
3667  DetectEngineDeReference(&old_de_ctx);
3668  return -1;
3669  }
3670  SCLogDebug("set up new_de_ctx %p", new_de_ctx);
3671 
3672  /* add to master */
3673  DetectEngineAddToMaster(new_de_ctx);
3674 
3675  /* move to old free list */
3676  DetectEngineMoveToFreeList(old_de_ctx);
3677  DetectEngineDeReference(&old_de_ctx);
3678 
3679  SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx);
3680  /* update the threads */
3681  DetectEngineReloadThreads(new_de_ctx);
3682  SCLogDebug("threads now run new_de_ctx %p", new_de_ctx);
3683 
3684  /* walk free list, freeing the old_de_ctx */
3686 
3688 
3689  SCLogDebug("old_de_ctx should have been freed");
3690 
3691  SCLogNotice("rule reload complete");
3692  return 0;
3693 }
3694 
3695 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len)
3696 {
3697  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
3698  return det_ctx->tenant_id % h->array_size;
3699 }
3700 
3701 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len)
3702 {
3705  return (det1->tenant_id == det2->tenant_id);
3706 }
3707 
3708 static void TenantIdFree(void *d)
3709 {
3710  DetectEngineThreadCtxFree(d);
3711 }
3712 
3714 {
3715  DetectEngineMasterCtx *master = &g_master_de_ctx;
3716  SCMutexLock(&master->lock);
3717 
3718  if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
3719  SCLogInfo("error, no tenant selector");
3720  SCMutexUnlock(&master->lock);
3721  return -1;
3722  }
3723 
3724  DetectEngineCtx *stub_de_ctx = NULL;
3725  DetectEngineCtx *list = master->list;
3726  for ( ; list != NULL; list = list->next) {
3727  SCLogDebug("list %p tenant %u", list, list->tenant_id);
3728 
3729  if (list->type == DETECT_ENGINE_TYPE_NORMAL ||
3730  list->type == DETECT_ENGINE_TYPE_MT_STUB ||
3732  {
3733  stub_de_ctx = list;
3734  break;
3735  }
3736  }
3737  if (stub_de_ctx == NULL) {
3738  stub_de_ctx = DetectEngineCtxInitStubForMT();
3739  if (stub_de_ctx == NULL) {
3740  SCMutexUnlock(&master->lock);
3741  return -1;
3742  }
3743 
3744  if (master->list == NULL) {
3745  master->list = stub_de_ctx;
3746  } else {
3747  stub_de_ctx->next = master->list;
3748  master->list = stub_de_ctx;
3749  }
3750  }
3751 
3752  /* update the threads */
3753  SCLogDebug("MT reload starting");
3754  DetectEngineReloadThreads(stub_de_ctx);
3755  SCLogDebug("MT reload done");
3756 
3757  SCMutexUnlock(&master->lock);
3758 
3759  /* walk free list, freeing the old_de_ctx */
3761 
3762  SCLogDebug("old_de_ctx should have been freed");
3763  return 0;
3764 }
3765 
3766 static int g_parse_metadata = 0;
3767 
3769 {
3770  g_parse_metadata = 1;
3771 }
3772 
3774 {
3775  g_parse_metadata = 0;
3776 }
3777 
3779 {
3780  return g_parse_metadata;
3781 }
3782 
3784 {
3785  switch (type) {
3786  case DETECT_SM_LIST_MATCH:
3787  return "packet";
3788  case DETECT_SM_LIST_PMATCH:
3789  return "packet/stream payload";
3790 
3791  case DETECT_SM_LIST_TMATCH:
3792  return "tag";
3793 
3795  return "base64_data";
3796 
3798  return "post-match";
3799 
3801  return "suppress";
3803  return "threshold";
3804 
3805  case DETECT_SM_LIST_MAX:
3806  return "max (internal)";
3807  }
3808  return "error";
3809 }
3810 
3811 /* events api */
3813 {
3815  det_ctx->events++;
3816 }
3817 
3819 {
3820  return det_ctx->decoder_events;
3821 }
3822 
3823 int DetectEngineGetEventInfo(const char *event_name, int *event_id,
3825 {
3826  *event_id = SCMapEnumNameToValue(event_name, det_ctx_event_table);
3827  if (*event_id == -1) {
3828  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
3829  "det_ctx's enum map table.", event_name);
3830  /* this should be treated as fatal */
3831  return -1;
3832  }
3833  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
3834 
3835  return 0;
3836 }
3837 
3838 /*************************************Unittest*********************************/
3839 
3840 #ifdef UNITTESTS
3841 
3842 static int DetectEngineInitYamlConf(const char *conf)
3843 {
3845  ConfInit();
3846  return ConfYamlLoadString(conf, strlen(conf));
3847 }
3848 
3849 static void DetectEngineDeInitYamlConf(void)
3850 {
3851  ConfDeInit();
3853 
3854  return;
3855 }
3856 
3857 static int DetectEngineTest01(void)
3858 {
3859  const char *conf =
3860  "%YAML 1.1\n"
3861  "---\n"
3862  "detect-engine:\n"
3863  " - profile: medium\n"
3864  " - custom-values:\n"
3865  " toclient_src_groups: 2\n"
3866  " toclient_dst_groups: 2\n"
3867  " toclient_sp_groups: 2\n"
3868  " toclient_dp_groups: 3\n"
3869  " toserver_src_groups: 2\n"
3870  " toserver_dst_groups: 4\n"
3871  " toserver_sp_groups: 2\n"
3872  " toserver_dp_groups: 25\n"
3873  " - inspection-recursion-limit: 0\n";
3874 
3875  DetectEngineCtx *de_ctx = NULL;
3876  int result = 0;
3877 
3878  if (DetectEngineInitYamlConf(conf) == -1)
3879  return 0;
3880  de_ctx = DetectEngineCtxInit();
3881  if (de_ctx == NULL)
3882  goto end;
3883 
3884  result = (de_ctx->inspection_recursion_limit == -1);
3885 
3886  end:
3887  if (de_ctx != NULL)
3888  DetectEngineCtxFree(de_ctx);
3889 
3890  DetectEngineDeInitYamlConf();
3891 
3892  return result;
3893 }
3894 
3895 static int DetectEngineTest02(void)
3896 {
3897  const char *conf =
3898  "%YAML 1.1\n"
3899  "---\n"
3900  "detect-engine:\n"
3901  " - profile: medium\n"
3902  " - custom-values:\n"
3903  " toclient_src_groups: 2\n"
3904  " toclient_dst_groups: 2\n"
3905  " toclient_sp_groups: 2\n"
3906  " toclient_dp_groups: 3\n"
3907  " toserver_src_groups: 2\n"
3908  " toserver_dst_groups: 4\n"
3909  " toserver_sp_groups: 2\n"
3910  " toserver_dp_groups: 25\n"
3911  " - inspection-recursion-limit:\n";
3912 
3913  DetectEngineCtx *de_ctx = NULL;
3914  int result = 0;
3915 
3916  if (DetectEngineInitYamlConf(conf) == -1)
3917  return 0;
3918  de_ctx = DetectEngineCtxInit();
3919  if (de_ctx == NULL)
3920  goto end;
3921 
3922  result = (de_ctx->inspection_recursion_limit == -1);
3923 
3924  end:
3925  if (de_ctx != NULL)
3926  DetectEngineCtxFree(de_ctx);
3927 
3928  DetectEngineDeInitYamlConf();
3929 
3930  return result;
3931 }
3932 
3933 static int DetectEngineTest03(void)
3934 {
3935  const char *conf =
3936  "%YAML 1.1\n"
3937  "---\n"
3938  "detect-engine:\n"
3939  " - profile: medium\n"
3940  " - custom-values:\n"
3941  " toclient_src_groups: 2\n"
3942  " toclient_dst_groups: 2\n"
3943  " toclient_sp_groups: 2\n"
3944  " toclient_dp_groups: 3\n"
3945  " toserver_src_groups: 2\n"
3946  " toserver_dst_groups: 4\n"
3947  " toserver_sp_groups: 2\n"
3948  " toserver_dp_groups: 25\n";
3949 
3950  DetectEngineCtx *de_ctx = NULL;
3951  int result = 0;
3952 
3953  if (DetectEngineInitYamlConf(conf) == -1)
3954  return 0;
3955  de_ctx = DetectEngineCtxInit();
3956  if (de_ctx == NULL)
3957  goto end;
3958 
3959  result = (de_ctx->inspection_recursion_limit ==
3961 
3962  end:
3963  if (de_ctx != NULL)
3964  DetectEngineCtxFree(de_ctx);
3965 
3966  DetectEngineDeInitYamlConf();
3967 
3968  return result;
3969 }
3970 
3971 static int DetectEngineTest04(void)
3972 {
3973  const char *conf =
3974  "%YAML 1.1\n"
3975  "---\n"
3976  "detect-engine:\n"
3977  " - profile: medium\n"
3978  " - custom-values:\n"
3979  " toclient_src_groups: 2\n"
3980  " toclient_dst_groups: 2\n"
3981  " toclient_sp_groups: 2\n"
3982  " toclient_dp_groups: 3\n"
3983  " toserver_src_groups: 2\n"
3984  " toserver_dst_groups: 4\n"
3985  " toserver_sp_groups: 2\n"
3986  " toserver_dp_groups: 25\n"
3987  " - inspection-recursion-limit: 10\n";
3988 
3989  DetectEngineCtx *de_ctx = NULL;
3990  int result = 0;
3991 
3992  if (DetectEngineInitYamlConf(conf) == -1)
3993  return 0;
3994  de_ctx = DetectEngineCtxInit();
3995  if (de_ctx == NULL)
3996  goto end;
3997 
3998  result = (de_ctx->inspection_recursion_limit == 10);
3999 
4000  end:
4001  if (de_ctx != NULL)
4002  DetectEngineCtxFree(de_ctx);
4003 
4004  DetectEngineDeInitYamlConf();
4005 
4006  return result;
4007 }
4008 
4009 static int DetectEngineTest08(void)
4010 {
4011  const char *conf =
4012  "%YAML 1.1\n"
4013  "---\n"
4014  "detect-engine:\n"
4015  " - profile: custom\n"
4016  " - custom-values:\n"
4017  " toclient-groups: 23\n"
4018  " toserver-groups: 27\n";
4019 
4020  DetectEngineCtx *de_ctx = NULL;
4021  int result = 0;
4022 
4023  if (DetectEngineInitYamlConf(conf) == -1)
4024  return 0;
4025  de_ctx = DetectEngineCtxInit();
4026  if (de_ctx == NULL)
4027  goto end;
4028 
4029  if (de_ctx->max_uniq_toclient_groups == 23 &&
4030  de_ctx->max_uniq_toserver_groups == 27)
4031  result = 1;
4032 
4033  end:
4034  if (de_ctx != NULL)
4035  DetectEngineCtxFree(de_ctx);
4036 
4037  DetectEngineDeInitYamlConf();
4038 
4039  return result;
4040 }
4041 
4042 /** \test bug 892 bad values */
4043 static int DetectEngineTest09(void)
4044 {
4045  const char *conf =
4046  "%YAML 1.1\n"
4047  "---\n"
4048  "detect-engine:\n"
4049  " - profile: custom\n"
4050  " - custom-values:\n"
4051  " toclient-groups: BA\n"
4052  " toserver-groups: BA\n"
4053  " - inspection-recursion-limit: 10\n";
4054 
4055  DetectEngineCtx *de_ctx = NULL;
4056  int result = 0;
4057 
4058  if (DetectEngineInitYamlConf(conf) == -1)
4059  return 0;
4060  de_ctx = DetectEngineCtxInit();
4061  if (de_ctx == NULL)
4062  goto end;
4063 
4064  if (de_ctx->max_uniq_toclient_groups == 20 &&
4065  de_ctx->max_uniq_toserver_groups == 40)
4066  result = 1;
4067 
4068  end:
4069  if (de_ctx != NULL)
4070  DetectEngineCtxFree(de_ctx);
4071 
4072  DetectEngineDeInitYamlConf();
4073 
4074  return result;
4075 }
4076 
4077 #endif
4078 
4080 {
4081 #ifdef UNITTESTS
4082  UtRegisterTest("DetectEngineTest01", DetectEngineTest01);
4083  UtRegisterTest("DetectEngineTest02", DetectEngineTest02);
4084  UtRegisterTest("DetectEngineTest03", DetectEngineTest03);
4085  UtRegisterTest("DetectEngineTest04", DetectEngineTest04);
4086  UtRegisterTest("DetectEngineTest08", DetectEngineTest08);
4087  UtRegisterTest("DetectEngineTest09", DetectEngineTest09);
4088 #endif
4089  return;
4090 }
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:1091
struct DetectEngineTenantMapping_ * next
Definition: detect.h:1371
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:1063
enum AppLayerEventType_ AppLayerEventType
const char * description
Definition: detect.h:429
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1406
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:563
uint16_t flags
DetectEngineCtx * DetectEngineCtxInitWithPrefix(const char *prefix)
SpmGlobalThreadCtx * spm_global_thread_ctx
Definition: detect.h:777
void ThresholdHashInit(DetectEngineCtx *de_ctx)
Init threshold context hash tables.
InspectionBufferGetDataPtr GetData
Definition: detect.h:416
#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:738
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:740
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:366
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
uint16_t spm_matcher
Definition: detect.h:773
void *(* InitFunc)(void *)
Definition: detect.h:700
Signature loader statistics.
Definition: detect.h:691
#define SIG_FLAG_INIT_NEED_FLUSH
Definition: detect.h:268
int32_t byte_extract_max_local_id
Definition: detect.h:814
uint32_t tenant_array_size
Definition: detect.h:984
int DetectEngineTentantRegisterPcapFile(uint32_t tenant_id)
#define BUG_ON(x)
const char * string
Definition: detect.h:428
uint8_t flags
Definition: tm-modules.h:70
int PmqSetup(PrefilterRuleStore *)
Setup a pmq.
uint16_t discontinue_matching
Definition: detect.h:1029
uint32_t flags
Definition: detect.h:496
uint32_t event_type
uint8_t proto
Definition: flow.h:343
#define THV_RUNNING_DONE
Definition: threadvars.h:45
uint32_t id
Definition: detect.h:528
#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:1074
uint16_t counter_fnonmpm_list
Definition: detect.h:1006
void SCProfilingKeywordDestroyCtx(DetectEngineCtx *de_ctx)
#define unlikely(expr)
Definition: util-optimize.h:35
DetectPort * tcp_whitelist
Definition: detect.h:869
uint8_t is_last
Definition: detect.h:333
ThreadVars * tv
Definition: detect.h:974
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
DetectEngineCtx * DetectEngineGetCurrent(void)
int transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:373
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:286
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:870
void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx)
Definition: detect.c:1052
DetectMpmAppLayerKeyword * app_mpms
Definition: detect.h:898
int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
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:852
int buffer_type_id
Definition: detect.h:884
one time registration of keywords at start up
Definition: detect.h:570
uint32_t match_array_len
Definition: detect.h:1048
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:293
uint32_t size
Definition: detect.h:353
DetectEngineThreadKeywordCtxItem * keyword_list
Definition: detect.h:832
#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:746
SigIntId * non_pf_id_array
Definition: detect.h:976
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:437
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:1015
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:199
void DetectEngineReloadSetIdle(void)
MpmThreadCtx mtc
Definition: detect.h:1061
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:994
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:1013
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:239
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:815
Signature container.
Definition: detect.h:495
#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:1016
#define SCMutexLock(mut)
const char * sigerror
Definition: detect.h:829
uint32_t signum
Definition: detect.h:742
struct DetectEngineTenantMapping_ * tenant_array
Definition: detect.h:983
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:384
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:1146
uint32_t DetectEngineGetVersion(void)
enum DetectEngineTenantSelectors tenant_selector
Definition: detect.h:1392
struct DetectEngineAppInspectionEngine_::@92 v2
main detection engine ctx
Definition: detect.h:723
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:436
void PmqFree(PrefilterRuleStore *)
Cleanup and free a Pmq.
struct DetectMpmAppLayerRegistery_ * next
Definition: detect.h:593
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:392
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:355
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:939
int DetectLoaderQueueTask(int loader_id, LoaderFunc Func, void *func_ctx)
HashListTable * buffer_type_hash
Definition: detect.h:883
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:1390
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:782
int transforms[DETECT_TRANSFORMS_MAX]
Definition: detect.h:474
#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.
struct SCProfileSghDetectCtx_ * profile_sgh_ctx
Definition: detect.h:847
SCMutex tv_root_lock
Definition: tm-threads.c:82
DetectEngineTenantSelectors
Definition: detect.h:1357
#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:349
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:1154
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:424
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:1002
void SCProfilingPrefilterThreadCleanup(DetectEngineThreadCtx *det_ctx)
uint32_t(* TenantGetId)(const void *, const Packet *p)
Definition: detect.h:986
struct ThreadVars_ * next
Definition: threadvars.h:111
void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx)
char * filename
Definition: detect.h:683
void ConfInit(void)
Initialize the configuration system.
Definition: conf.c:113
uint16_t mpm_matcher
Definition: detect.h:772
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:859
#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:889
#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:1064
const char * conf_filename
Definition: suricata.h:169
int DetectBufferTypeMaxId(void)
SigFileLoaderStat sig_stat
Definition: detect.h:904
void SCClassConfLoadClassficationConfigFile(DetectEngineCtx *de_ctx, FILE *fd)
Loads the Classtype info from the classification.config file.
uint16_t counter_match_list
Definition: detect.h:1007
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:879
struct DetectEngineThreadKeywordCtxItem_ * next
Definition: detect.h:703
HashTable * mt_det_ctxs_hash
Definition: detect.h:981
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:888
DetectEngineSyncState
AppProto alproto
Definition: detect.h:499
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:1396
#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:845
uint16_t max_uniq_toclient_groups
Definition: detect.h:781
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:857
const char * DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
int RunmodeIsUnittests(void)
Definition: suricata.c:259
#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:248
InspectEngineFuncPtr Callback
Definition: detect.h:413
#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:489
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:817
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
DetectEngineCtx * DetectEngineCtxInitStubForMT(void)
uint8_t * buf
Definition: detect.h:351
uint32_t smlists_array_size
Definition: detect.h:487
int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
enum DetectEnginePrefilterSetting prefilter_setting
Definition: detect.h:865
Definition: conf.h:32
void DetectEngineBumpVersion(void)
void(* SetupCallback)(const struct DetectEngineCtx_ *, struct Signature_ *)
Definition: detect.h:435
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:685
DetectEngineCtx * de_ctx
Definition: detect.h:1089
DetectEngineType
Definition: detect.h:714
uint16_t counter_nonmpm_list
Definition: detect.h:1005
DetectBufferType ** buffer_type_map
Definition: detect.h:878
#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:844
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:854
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:459
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:960
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:1062
DetectEngineThreadKeywordCtxItem * keyword_list
Definition: detect.h:1401
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:543
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:725
int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Flow *f, uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode, void *data)
Run the actual payload match functions.
#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:1097
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:968
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:1045
int inspection_recursion_counter
Definition: detect.h:1041
uint32_t inspect_len
Definition: detect.h:348
int DetectEngineReloadStart(void)
void DetectEngineUnsetParseMetadata(void)
void DetectBufferRunSetupCallback(const DetectEngineCtx *de_ctx, const int id, Signature *s)
struct SCProfileDetectCtx_ * profile_ctx
Definition: detect.h:843
uint8_t sgh_mpm_context
Definition: detect.h:785
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:202
void DetectBufferTypeSetDescriptionByName(const char *name, const char *desc)
DetectEngineIPOnlyThreadCtx io_ctx
Definition: detect.h:1071
int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
char * sig_str
Definition: detect.h:684
void PatternMatchThreadPrint(MpmThreadCtx *mpm_thread_ctx, uint16_t mpm_matcher)
int DetectMetadataHashInit(DetectEngineCtx *de_ctx)
bool supports_transforms
Definition: detect.h:434
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:1385
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:404
uint16_t counter_mpm_list
Definition: detect.h:1004
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:1095
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:1068
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:378
const char * DetectBufferTypeGetNameById(const DetectEngineCtx *de_ctx, const int id)
AppLayerDecoderEvents * decoder_events
Definition: detect.h:1101
SigMatch * mpm_sm
Definition: detect.h:466
PcapPacketVars pcap_v
Definition: decode.h:478
Flow data structure.
Definition: flow.h:324
uint32_t base64_decode_max_len
Definition: detect.h:824
uint32_t mt_det_ctxs_cnt
Definition: detect.h:979
#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:1014
void PacketEnqueue(PacketQueue *q, Packet *p)
Definition: packet-queue.c:139
char * sig_file
Definition: suricata.h:139
const DetectEngineTransforms * transforms
Definition: detect.h:419
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:140
void PrefilterInit(DetectEngineCtx *de_ctx)
SigMatchCtx * ctx
Definition: detect.h:334
int inspection_recursion_limit
Definition: detect.h:795
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()