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