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