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