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