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->mpm = (SigMatchListSMBelongsTo(s, s->init_data->mpm_sm) == list_id);
1435  e->sm_list = list_id;
1436  e->sm_list_base = list_id;
1437  e->v1.Callback = Callback;
1438  e->smd = data;
1439 
1440  if (s->pkt_inspect == NULL) {
1441  s->pkt_inspect = e;
1442  } else {
1444  while (a->next != NULL) {
1445  a = a->next;
1446  }
1447  a->next = e;
1448  }
1449  return 0;
1450 }
1451 
1453 {
1454  /* only handle PMATCH here if we're not an app inspect rule */
1456  if (DetectEnginePktInspectionAppend(
1457  s, DetectEngineInspectRulePayloadMatches, NULL, DETECT_SM_LIST_PMATCH) < 0)
1458  return -1;
1459  SCLogDebug("sid %u: DetectEngineInspectRulePayloadMatches appended", s->id);
1460  }
1461 
1462  if (s->sm_arrays[DETECT_SM_LIST_MATCH]) {
1463  if (DetectEnginePktInspectionAppend(
1464  s, DetectEngineInspectRulePacketMatches, NULL, DETECT_SM_LIST_MATCH) < 0)
1465  return -1;
1466  SCLogDebug("sid %u: DetectEngineInspectRulePacketMatches appended", s->id);
1467  }
1468 
1469  return 0;
1470 }
1471 
1472 /* code to control the main thread to do a reload */
1473 
1475  IDLE, /**< ready to start a reload */
1476  RELOAD, /**< command main thread to do the reload */
1477 };
1478 
1479 
1480 typedef struct DetectEngineSyncer_ {
1484 
1485 static DetectEngineSyncer detect_sync = { SCMUTEX_INITIALIZER, IDLE };
1486 
1487 /* tell main to start reloading */
1489 {
1490  int r = 0;
1491  SCMutexLock(&detect_sync.m);
1492  if (detect_sync.state == IDLE) {
1493  detect_sync.state = RELOAD;
1494  } else {
1495  r = -1;
1496  }
1497  SCMutexUnlock(&detect_sync.m);
1498  return r;
1499 }
1500 
1501 /* main thread checks this to see if it should start */
1503 {
1504  int r = 0;
1505  SCMutexLock(&detect_sync.m);
1506  if (detect_sync.state == RELOAD) {
1507  r = 1;
1508  }
1509  SCMutexUnlock(&detect_sync.m);
1510  return r;
1511 }
1512 
1513 /* main thread sets done when it's done */
1515 {
1516  SCMutexLock(&detect_sync.m);
1517  detect_sync.state = IDLE;
1518  SCMutexUnlock(&detect_sync.m);
1519 }
1520 
1521 /* caller loops this until it returns 1 */
1523 {
1524  int r = 0;
1525  SCMutexLock(&detect_sync.m);
1526  if (detect_sync.state == IDLE) {
1527  r = 1;
1528  }
1529  SCMutexUnlock(&detect_sync.m);
1530  return r;
1531 }
1532 
1533 /** \brief Do the content inspection & validation for a signature
1534  *
1535  * \param de_ctx Detection engine context
1536  * \param det_ctx Detection engine thread context
1537  * \param s Signature to inspect
1538  * \param sm SigMatch to inspect
1539  * \param f Flow
1540  * \param flags app layer flags
1541  * \param state App layer state
1542  *
1543  * \retval 0 no match
1544  * \retval 1 match
1545  */
1547  const Signature *s, const SigMatchData *smd, Flow *f, const uint8_t flags, void *alstate,
1548  void *txv, uint64_t tx_id)
1549 {
1550  SCLogDebug("running match functions, sm %p", smd);
1551  if (smd != NULL) {
1552  while (1) {
1553  int match = 0;
1555  match = sigmatch_table[smd->type].
1556  AppLayerTxMatch(det_ctx, f, flags, alstate, txv, s, smd->ctx);
1557  KEYWORD_PROFILING_END(det_ctx, smd->type, (match == 1));
1558  if (match == 0)
1560  if (match == 2) {
1562  }
1563 
1564  if (smd->is_last)
1565  break;
1566  smd++;
1567  }
1568  }
1569 
1571 }
1572 
1573 
1574 /**
1575  * \brief Do the content inspection & validation for a signature
1576  *
1577  * \param de_ctx Detection engine context
1578  * \param det_ctx Detection engine thread context
1579  * \param s Signature to inspect
1580  * \param f Flow
1581  * \param flags app layer flags
1582  * \param state App layer state
1583  *
1584  * \retval 0 no match.
1585  * \retval 1 match.
1586  * \retval 2 Sig can't match.
1587  */
1590  const DetectEngineAppInspectionEngine *engine,
1591  const Signature *s,
1592  Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
1593 {
1594  const int list_id = engine->sm_list;
1595  SCLogDebug("running inspect on %d", list_id);
1596 
1597  const bool eof = (AppLayerParserGetStateProgress(f->proto, f->alproto, txv, flags) > engine->progress);
1598 
1599  SCLogDebug("list %d mpm? %s transforms %p",
1600  engine->sm_list, engine->mpm ? "true" : "false", engine->v2.transforms);
1601 
1602  /* if prefilter didn't already run, we need to consider transformations */
1603  const DetectEngineTransforms *transforms = NULL;
1604  if (!engine->mpm) {
1605  transforms = engine->v2.transforms;
1606  }
1607 
1608  const InspectionBuffer *buffer = engine->v2.GetData(det_ctx, transforms,
1609  f, flags, txv, list_id);
1610  if (unlikely(buffer == NULL)) {
1613  }
1614 
1615  const uint32_t data_len = buffer->inspect_len;
1616  const uint8_t *data = buffer->inspect;
1617  const uint64_t offset = buffer->inspect_offset;
1618 
1619  uint8_t ci_flags = eof ? DETECT_CI_FLAGS_END : 0;
1620  ci_flags |= (offset == 0 ? DETECT_CI_FLAGS_START : 0);
1621  ci_flags |= buffer->flags;
1622 
1623  det_ctx->discontinue_matching = 0;
1624  det_ctx->buffer_offset = 0;
1625  det_ctx->inspection_recursion_counter = 0;
1626 
1627  /* Inspect all the uricontents fetched on each
1628  * transaction at the app layer */
1629  int r = DetectEngineContentInspection(de_ctx, det_ctx,
1630  s, engine->smd,
1631  NULL, f,
1632  (uint8_t *)data, data_len, offset, ci_flags,
1634  if (r == 1) {
1636  } else {
1639  }
1640 }
1641 
1642 /**
1643  * \brief Do the content inspection & validation for a signature
1644  *
1645  * \param de_ctx Detection engine context
1646  * \param det_ctx Detection engine thread context
1647  * \param s Signature to inspect
1648  * \param p Packet
1649  *
1650  * \retval 0 no match.
1651  * \retval 1 match.
1652  */
1654  DetectEngineThreadCtx *det_ctx,
1655  const DetectEnginePktInspectionEngine *engine,
1656  const Signature *s, Packet *p, uint8_t *_alert_flags)
1657 {
1658  const int list_id = engine->sm_list;
1659  SCLogDebug("running inspect on %d", list_id);
1660 
1661  SCLogDebug("list %d transforms %p",
1662  engine->sm_list, engine->v1.transforms);
1663 
1664  /* if prefilter didn't already run, we need to consider transformations */
1665  const DetectEngineTransforms *transforms = NULL;
1666  if (!engine->mpm) {
1667  transforms = engine->v1.transforms;
1668  }
1669 
1670  const InspectionBuffer *buffer = engine->v1.GetData(det_ctx, transforms, p,
1671  list_id);
1672  if (unlikely(buffer == NULL)) {
1674  }
1675 
1676  const uint32_t data_len = buffer->inspect_len;
1677  const uint8_t *data = buffer->inspect;
1678  const uint64_t offset = 0;
1679 
1680  uint8_t ci_flags = DETECT_CI_FLAGS_START|DETECT_CI_FLAGS_END;
1681  ci_flags |= buffer->flags;
1682 
1683  det_ctx->discontinue_matching = 0;
1684  det_ctx->buffer_offset = 0;
1685  det_ctx->inspection_recursion_counter = 0;
1686 
1687  /* Inspect all the uricontents fetched on each
1688  * transaction at the app layer */
1689  int r = DetectEngineContentInspection(det_ctx->de_ctx, det_ctx,
1690  s, engine->smd,
1691  p, p->flow,
1692  (uint8_t *)data, data_len, offset, ci_flags,
1694  if (r == 1) {
1696  } else {
1698  }
1699 }
1700 
1701 
1702 /* nudge capture loops to wake up */
1703 static void BreakCapture(void)
1704 {
1706  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1707  if ((tv->tmm_flags & TM_FLAG_RECEIVE_TM) == 0) {
1708  continue;
1709  }
1710  /* find the correct slot */
1711  for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1712  if (suricata_ctl_flags != 0) {
1714  return;
1715  }
1716 
1717  TmModule *tm = TmModuleGetById(s->tm_id);
1718  if (!(tm->flags & TM_FLAG_RECEIVE_TM)) {
1719  continue;
1720  }
1721 
1722  /* signal capture method that we need a packet. */
1724  /* if the method supports it, BreakLoop. Otherwise we rely on
1725  * the capture method's recv timeout */
1726  if (tm->PktAcqLoop && tm->PktAcqBreakLoop) {
1727  tm->PktAcqBreakLoop(tv, SC_ATOMIC_GET(s->slot_data));
1728  }
1729  break;
1730  }
1731  }
1733 }
1734 
1735 /** \internal
1736  * \brief inject a pseudo packet into each detect thread that doesn't use the
1737  * new det_ctx yet
1738  */
1739 static void InjectPackets(ThreadVars **detect_tvs,
1740  DetectEngineThreadCtx **new_det_ctx,
1741  int no_of_detect_tvs)
1742 {
1743  /* inject a fake packet if the detect thread isn't using the new ctx yet,
1744  * this speeds up the process */
1745  for (int i = 0; i < no_of_detect_tvs; i++) {
1746  if (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1747  if (detect_tvs[i]->inq != NULL) {
1748  Packet *p = PacketGetFromAlloc();
1749  if (p != NULL) {
1752  PacketQueue *q = detect_tvs[i]->inq->pq;
1753  SCMutexLock(&q->mutex_q);
1754  PacketEnqueue(q, p);
1755  SCCondSignal(&q->cond_q);
1756  SCMutexUnlock(&q->mutex_q);
1757  }
1758  }
1759  }
1760  }
1761 }
1762 
1763 /** \internal
1764  * \brief Update detect threads with new detect engine
1765  *
1766  * Atomically update each detect thread with a new thread context
1767  * that is associated to the new detection engine(s).
1768  *
1769  * If called in unix socket mode, it's possible that we don't have
1770  * detect threads yet.
1771  *
1772  * \retval -1 error
1773  * \retval 0 no detection threads
1774  * \retval 1 successful reload
1775  */
1776 static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
1777 {
1778  SCEnter();
1779  uint32_t i = 0;
1780 
1781  /* count detect threads in use */
1782  uint32_t no_of_detect_tvs = TmThreadCountThreadsByTmmFlags(TM_FLAG_DETECT_TM);
1783  /* can be zero in unix socket mode */
1784  if (no_of_detect_tvs == 0) {
1785  return 0;
1786  }
1787 
1788  /* prepare swap structures */
1789  DetectEngineThreadCtx *old_det_ctx[no_of_detect_tvs];
1790  DetectEngineThreadCtx *new_det_ctx[no_of_detect_tvs];
1791  ThreadVars *detect_tvs[no_of_detect_tvs];
1792  memset(old_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1793  memset(new_det_ctx, 0x00, (no_of_detect_tvs * sizeof(DetectEngineThreadCtx *)));
1794  memset(detect_tvs, 0x00, (no_of_detect_tvs * sizeof(ThreadVars *)));
1795 
1796  /* start the process of swapping detect threads ctxs */
1797 
1798  /* get reference to tv's and setup new_det_ctx array */
1800  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1801  if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1802  continue;
1803  }
1804  for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1805  TmModule *tm = TmModuleGetById(s->tm_id);
1806  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1807  continue;
1808  }
1809 
1810  if (suricata_ctl_flags != 0) {
1812  goto error;
1813  }
1814 
1815  old_det_ctx[i] = FlowWorkerGetDetectCtxPtr(SC_ATOMIC_GET(s->slot_data));
1816  detect_tvs[i] = tv;
1817 
1818  new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
1819  if (new_det_ctx[i] == NULL) {
1820  SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init "
1821  "failure in live rule swap. Let's get out of here");
1823  goto error;
1824  }
1825  SCLogDebug("live rule swap created new det_ctx - %p and de_ctx "
1826  "- %p\n", new_det_ctx[i], new_de_ctx);
1827  i++;
1828  break;
1829  }
1830  }
1831  BUG_ON(i != no_of_detect_tvs);
1832 
1833  /* atomically replace the det_ctx data */
1834  i = 0;
1835  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1836  if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1837  continue;
1838  }
1839  for (TmSlot *s = tv->tm_slots; s != NULL; s = s->slot_next) {
1840  TmModule *tm = TmModuleGetById(s->tm_id);
1841  if (!(tm->flags & TM_FLAG_DETECT_TM)) {
1842  continue;
1843  }
1844  SCLogDebug("swapping new det_ctx - %p with older one - %p",
1845  new_det_ctx[i], SC_ATOMIC_GET(s->slot_data));
1846  FlowWorkerReplaceDetectCtx(SC_ATOMIC_GET(s->slot_data), new_det_ctx[i++]);
1847  break;
1848  }
1849  }
1851 
1852  /* threads now all have new data, however they may not have started using
1853  * it and may still use the old data */
1854 
1855  SCLogDebug("Live rule swap has swapped %d old det_ctx's with new ones, "
1856  "along with the new de_ctx", no_of_detect_tvs);
1857 
1858  InjectPackets(detect_tvs, new_det_ctx, no_of_detect_tvs);
1859 
1860  for (i = 0; i < no_of_detect_tvs; i++) {
1861  int break_out = 0;
1862  usleep(1000);
1863  while (SC_ATOMIC_GET(new_det_ctx[i]->so_far_used_by_detect) != 1) {
1864  if (suricata_ctl_flags != 0) {
1865  break_out = 1;
1866  break;
1867  }
1868 
1869  BreakCapture();
1870  usleep(1000);
1871  }
1872  if (break_out)
1873  break;
1874  SCLogDebug("new_det_ctx - %p used by detect engine", new_det_ctx[i]);
1875  }
1876 
1877  /* this is to make sure that if someone initiated shutdown during a live
1878  * rule swap, the live rule swap won't clean up the old det_ctx and
1879  * de_ctx, till all detect threads have stopped working and sitting
1880  * silently after setting RUNNING_DONE flag and while waiting for
1881  * THV_DEINIT flag */
1882  if (i != no_of_detect_tvs) { // not all threads we swapped
1883  for (ThreadVars *tv = tv_root[TVT_PPT]; tv != NULL; tv = tv->next) {
1884  if ((tv->tmm_flags & TM_FLAG_DETECT_TM) == 0) {
1885  continue;
1886  }
1887 
1889  usleep(100);
1890  }
1891  }
1892  }
1893 
1894  /* free all the ctxs */
1895  for (i = 0; i < no_of_detect_tvs; i++) {
1896  SCLogDebug("Freeing old_det_ctx - %p used by detect",
1897  old_det_ctx[i]);
1898  DetectEngineThreadCtxDeinit(NULL, old_det_ctx[i]);
1899  }
1900 
1902 
1903  return 1;
1904 
1905  error:
1906  for (i = 0; i < no_of_detect_tvs; i++) {
1907  if (new_det_ctx[i] != NULL)
1908  DetectEngineThreadCtxDeinit(NULL, new_det_ctx[i]);
1909  }
1910  return -1;
1911 }
1912 
1913 static DetectEngineCtx *DetectEngineCtxInitReal(enum DetectEngineType type, const char *prefix)
1914 {
1916  if (unlikely(de_ctx == NULL))
1917  goto error;
1918 
1919  memset(de_ctx,0,sizeof(DetectEngineCtx));
1920  memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
1921  TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
1922  de_ctx->sigerror = NULL;
1923  de_ctx->type = type;
1924 
1927  SCLogDebug("stub %u with version %u", type, de_ctx->version);
1928  return de_ctx;
1929  }
1930 
1931  if (prefix != NULL) {
1932  strlcpy(de_ctx->config_prefix, prefix, sizeof(de_ctx->config_prefix));
1933  }
1934 
1935  if (ConfGetBool("engine.init-failure-fatal", (int *)&(de_ctx->failure_fatal)) != 1) {
1936  SCLogDebug("ConfGetBool could not load the value.");
1937  }
1938 
1941  SCLogConfig("pattern matchers: MPM: %s, SPM: %s",
1944 
1946  if (de_ctx->spm_global_thread_ctx == NULL) {
1947  SCLogDebug("Unable to alloc SpmGlobalThreadCtx.");
1948  goto error;
1949  }
1950 
1951  if (DetectEngineCtxLoadConf(de_ctx) == -1) {
1952  goto error;
1953  }
1954 
1961  DetectBufferTypeSetupDetectEngine(de_ctx);
1962 
1963  /* init iprep... ignore errors for now */
1964  (void)SRepInit(de_ctx);
1965 
1968 
1969  if (ActionInitConfig() < 0) {
1970  goto error;
1971  }
1972 
1975  SCLogDebug("dectx with version %u", de_ctx->version);
1976  return de_ctx;
1977 error:
1978  if (de_ctx != NULL) {
1980  }
1981  return NULL;
1982 
1983 }
1984 
1986 {
1987  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_MT_STUB, NULL);
1988 }
1989 
1991 {
1992  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_DD_STUB, NULL);
1993 }
1994 
1996 {
1997  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, NULL);
1998 }
1999 
2001 {
2002  if (prefix == NULL || strlen(prefix) == 0)
2003  return DetectEngineCtxInit();
2004  else
2005  return DetectEngineCtxInitReal(DETECT_ENGINE_TYPE_NORMAL, prefix);
2006 }
2007 
2008 static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
2009 {
2011  while (item) {
2013  SCFree(item);
2014  item = next;
2015  }
2016  de_ctx->keyword_list = NULL;
2017 }
2018 
2019 static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
2020 {
2021  SigString *item = NULL;
2022  SigString *sitem;
2023 
2024  TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
2025  SCFree(item->filename);
2026  SCFree(item->sig_str);
2027  if (item->sig_error) {
2028  SCFree(item->sig_error);
2029  }
2030  TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
2031  SCFree(item);
2032  }
2033 }
2034 
2035 /**
2036  * \brief Free a DetectEngineCtx::
2037  *
2038  * \param de_ctx DetectEngineCtx:: to be freed
2039  */
2041 {
2042 
2043  if (de_ctx == NULL)
2044  return;
2045 
2046 #ifdef PROFILING
2047  if (de_ctx->profile_ctx != NULL) {
2049  de_ctx->profile_ctx = NULL;
2050  }
2051  if (de_ctx->profile_keyword_ctx != NULL) {
2052  SCProfilingKeywordDestroyCtx(de_ctx);//->profile_keyword_ctx);
2053 // de_ctx->profile_keyword_ctx = NULL;
2054  }
2055  if (de_ctx->profile_sgh_ctx != NULL) {
2057  }
2059 #endif
2060 
2061  /* Normally the hashes are freed elsewhere, but
2062  * to be sure look at them again here.
2063  */
2070  if (de_ctx->sig_array)
2072 
2075 
2077 
2079 
2081 
2082  DetectEngineCtxFreeThreadKeywordData(de_ctx);
2084  DetectEngineCtxFreeFailedSigs(de_ctx);
2085 
2088 
2089  /* if we have a config prefix, remove the config from the tree */
2090  if (strlen(de_ctx->config_prefix) > 0) {
2091  /* remove config */
2093  if (node != NULL) {
2094  ConfNodeRemove(node); /* frees node */
2095  }
2096 #if 0
2097  ConfDump();
2098 #endif
2099  }
2100 
2103 
2104  DetectBufferTypeFreeDetectEngine(de_ctx);
2105  /* freed our var name hash */
2107 
2108  SCFree(de_ctx);
2109  //DetectAddressGroupPrintMemory();
2110  //DetectSigGroupPrintMemory();
2111  //DetectPortPrintMemory();
2112 }
2113 
2114 /** \brief Function that load DetectEngineCtx config for grouping sigs
2115  * used by the engine
2116  * \retval 0 if no config provided, 1 if config was provided
2117  * and loaded successfully
2118  */
2119 static int DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx)
2120 {
2121  uint8_t profile = ENGINE_PROFILE_MEDIUM;
2122  const char *max_uniq_toclient_groups_str = NULL;
2123  const char *max_uniq_toserver_groups_str = NULL;
2124  const char *sgh_mpm_context = NULL;
2125  const char *de_ctx_profile = NULL;
2126 
2127  (void)ConfGet("detect.profile", &de_ctx_profile);
2128  (void)ConfGet("detect.sgh-mpm-context", &sgh_mpm_context);
2129 
2130  ConfNode *de_ctx_custom = ConfGetNode("detect-engine");
2131  ConfNode *opt = NULL;
2132 
2133  if (de_ctx_custom != NULL) {
2134  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2135  if (de_ctx_profile == NULL) {
2136  if (opt->val && strcmp(opt->val, "profile") == 0) {
2137  de_ctx_profile = opt->head.tqh_first->val;
2138  }
2139  }
2140 
2141  if (sgh_mpm_context == NULL) {
2142  if (opt->val && strcmp(opt->val, "sgh-mpm-context") == 0) {
2143  sgh_mpm_context = opt->head.tqh_first->val;
2144  }
2145  }
2146  }
2147  }
2148 
2149  if (de_ctx_profile != NULL) {
2150  if (strcmp(de_ctx_profile, "low") == 0 ||
2151  strcmp(de_ctx_profile, "lowest") == 0) { // legacy
2152  profile = ENGINE_PROFILE_LOW;
2153  } else if (strcmp(de_ctx_profile, "medium") == 0) {
2154  profile = ENGINE_PROFILE_MEDIUM;
2155  } else if (strcmp(de_ctx_profile, "high") == 0 ||
2156  strcmp(de_ctx_profile, "highest") == 0) { // legacy
2157  profile = ENGINE_PROFILE_HIGH;
2158  } else if (strcmp(de_ctx_profile, "custom") == 0) {
2159  profile = ENGINE_PROFILE_CUSTOM;
2160  } else {
2162  "invalid value for detect.profile: '%s'. "
2163  "Valid options: low, medium, high and custom.",
2164  de_ctx_profile);
2165  return -1;
2166  }
2167 
2168  SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
2169  } else {
2170  SCLogDebug("Profile for detection engine groups not provided "
2171  "at suricata.yaml. Using default (\"medium\").");
2172  }
2173 
2174  /* detect-engine.sgh-mpm-context option parsing */
2175  if (sgh_mpm_context == NULL || strcmp(sgh_mpm_context, "auto") == 0) {
2176  /* for now, since we still haven't implemented any intelligence into
2177  * understanding the patterns and distributing mpm_ctx across sgh */
2179 #ifdef BUILD_HYPERSCAN
2180  de_ctx->mpm_matcher == MPM_HS ||
2181 #endif
2184  } else {
2186  }
2187  } else {
2188  if (strcmp(sgh_mpm_context, "single") == 0) {
2190  } else if (strcmp(sgh_mpm_context, "full") == 0) {
2192  } else {
2193  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "You have supplied an "
2194  "invalid conf value for detect-engine.sgh-mpm-context-"
2195  "%s", sgh_mpm_context);
2196  exit(EXIT_FAILURE);
2197  }
2198  }
2199 
2200  if (run_mode == RUNMODE_UNITTEST) {
2202  }
2203 
2204  /* parse profile custom-values */
2205  opt = NULL;
2206  switch (profile) {
2207  case ENGINE_PROFILE_LOW:
2210  break;
2211 
2212  case ENGINE_PROFILE_HIGH:
2215  break;
2216 
2217  case ENGINE_PROFILE_CUSTOM:
2218  (void)ConfGet("detect.custom-values.toclient-groups",
2219  &max_uniq_toclient_groups_str);
2220  (void)ConfGet("detect.custom-values.toserver-groups",
2221  &max_uniq_toserver_groups_str);
2222 
2223  if (de_ctx_custom != NULL) {
2224  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2225  if (opt->val && strcmp(opt->val, "custom-values") == 0) {
2226  if (max_uniq_toclient_groups_str == NULL) {
2227  max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2228  (opt->head.tqh_first, "toclient-sp-groups");
2229  }
2230  if (max_uniq_toclient_groups_str == NULL) {
2231  max_uniq_toclient_groups_str = (char *)ConfNodeLookupChildValue
2232  (opt->head.tqh_first, "toclient-groups");
2233  }
2234  if (max_uniq_toserver_groups_str == NULL) {
2235  max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2236  (opt->head.tqh_first, "toserver-dp-groups");
2237  }
2238  if (max_uniq_toserver_groups_str == NULL) {
2239  max_uniq_toserver_groups_str = (char *)ConfNodeLookupChildValue
2240  (opt->head.tqh_first, "toserver-groups");
2241  }
2242  }
2243  }
2244  }
2245  if (max_uniq_toclient_groups_str != NULL) {
2247  strlen(max_uniq_toclient_groups_str),
2248  (const char *)max_uniq_toclient_groups_str) <= 0)
2249  {
2251 
2252  SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
2253  "toclient-groups failed, using %u",
2254  max_uniq_toclient_groups_str,
2256  }
2257  } else {
2259  }
2260  SCLogConfig("toclient-groups %u", de_ctx->max_uniq_toclient_groups);
2261 
2262  if (max_uniq_toserver_groups_str != NULL) {
2264  strlen(max_uniq_toserver_groups_str),
2265  (const char *)max_uniq_toserver_groups_str) <= 0)
2266  {
2268 
2269  SCLogWarning(SC_ERR_SIZE_PARSE, "parsing '%s' for "
2270  "toserver-groups failed, using %u",
2271  max_uniq_toserver_groups_str,
2273  }
2274  } else {
2276  }
2277  SCLogConfig("toserver-groups %u", de_ctx->max_uniq_toserver_groups);
2278  break;
2279 
2280  /* Default (or no config provided) is profile medium */
2281  case ENGINE_PROFILE_MEDIUM:
2283  default:
2286  break;
2287  }
2288 
2289  intmax_t value = 0;
2290  if (ConfGetInt("detect.inspection-recursion-limit", &value) == 1)
2291  {
2292  if (value >= 0 && value <= INT_MAX) {
2293  de_ctx->inspection_recursion_limit = (int)value;
2294  }
2295 
2296  /* fall back to old config parsing */
2297  } else {
2298  ConfNode *insp_recursion_limit_node = NULL;
2299  char *insp_recursion_limit = NULL;
2300 
2301  if (de_ctx_custom != NULL) {
2302  opt = NULL;
2303  TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
2304  if (opt->val && strcmp(opt->val, "inspection-recursion-limit") != 0)
2305  continue;
2306 
2307  insp_recursion_limit_node = ConfNodeLookupChild(opt, opt->val);
2308  if (insp_recursion_limit_node == NULL) {
2309  SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Error retrieving conf "
2310  "entry for detect-engine:inspection-recursion-limit");
2311  break;
2312  }
2313  insp_recursion_limit = insp_recursion_limit_node->val;
2314  SCLogDebug("Found detect-engine.inspection-recursion-limit - %s:%s",
2315  insp_recursion_limit_node->name, insp_recursion_limit_node->val);
2316  break;
2317  }
2318 
2319  if (insp_recursion_limit != NULL) {
2321  0, (const char *)insp_recursion_limit) < 0) {
2322  SCLogWarning(SC_ERR_INVALID_VALUE, "Invalid value for "
2323  "detect-engine.inspection-recursion-limit: %s "
2324  "resetting to %d", insp_recursion_limit,
2328  }
2329  } else {
2332  }
2333  }
2334  }
2335 
2338 
2339  SCLogDebug("de_ctx->inspection_recursion_limit: %d",
2341 
2342  /* parse port grouping whitelisting settings */
2343 
2344  const char *ports = NULL;
2345  (void)ConfGet("detect.grouping.tcp-whitelist", &ports);
2346  if (ports) {
2347  SCLogConfig("grouping: tcp-whitelist %s", ports);
2348  } else {
2349  ports = "53, 80, 139, 443, 445, 1433, 3306, 3389, 6666, 6667, 8080";
2350  SCLogConfig("grouping: tcp-whitelist (default) %s", ports);
2351 
2352  }
2353  if (DetectPortParse(de_ctx, &de_ctx->tcp_whitelist, ports) != 0) {
2354  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2355  "for detect.grouping.tcp-whitelist", ports);
2356  }
2358  for ( ; x != NULL; x = x->next) {
2359  if (x->port != x->port2) {
2360  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2361  "for detect.grouping.tcp-whitelist: only single ports allowed", ports);
2363  de_ctx->tcp_whitelist = NULL;
2364  break;
2365  }
2366  }
2367 
2368  ports = NULL;
2369  (void)ConfGet("detect.grouping.udp-whitelist", &ports);
2370  if (ports) {
2371  SCLogConfig("grouping: udp-whitelist %s", ports);
2372  } else {
2373  ports = "53, 135, 5060";
2374  SCLogConfig("grouping: udp-whitelist (default) %s", ports);
2375 
2376  }
2377  if (DetectPortParse(de_ctx, &de_ctx->udp_whitelist, ports) != 0) {
2378  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2379  "forr detect.grouping.udp-whitelist", ports);
2380  }
2381  for (x = de_ctx->udp_whitelist; x != NULL; x = x->next) {
2382  if (x->port != x->port2) {
2383  SCLogWarning(SC_ERR_INVALID_YAML_CONF_ENTRY, "'%s' is not a valid value "
2384  "for detect.grouping.udp-whitelist: only single ports allowed", ports);
2386  de_ctx->udp_whitelist = NULL;
2387  break;
2388  }
2389  }
2390 
2392  const char *pf_setting = NULL;
2393  if (ConfGet("detect.prefilter.default", &pf_setting) == 1 && pf_setting) {
2394  if (strcasecmp(pf_setting, "mpm") == 0) {
2396  } else if (strcasecmp(pf_setting, "auto") == 0) {
2398  }
2399  }
2400  switch (de_ctx->prefilter_setting) {
2401  case DETECT_PREFILTER_MPM:
2402  SCLogConfig("prefilter engines: MPM");
2403  break;
2404  case DETECT_PREFILTER_AUTO:
2405  SCLogConfig("prefilter engines: MPM and keywords");
2406  break;
2407  }
2408 
2409  return 0;
2410 }
2411 
2412 /*
2413  * getting & (re)setting the internal sig i
2414  */
2415 
2416 //inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx)
2417 //{
2418 // return de_ctx->signum;
2419 //}
2420 
2422 {
2423  de_ctx->signum = 0;
2424 }
2425 
2426 static int DetectEngineThreadCtxInitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2427 {
2428  const DetectEngineMasterCtx *master = &g_master_de_ctx;
2429 
2430  if (master->keyword_id > 0) {
2431  // coverity[suspicious_sizeof : FALSE]
2432  det_ctx->global_keyword_ctxs_array = (void **)SCCalloc(master->keyword_id, sizeof(void *));
2433  if (det_ctx->global_keyword_ctxs_array == NULL) {
2434  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2435  return TM_ECODE_FAILED;
2436  }
2437  det_ctx->global_keyword_ctxs_size = master->keyword_id;
2438 
2439  const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2440  while (item) {
2441  det_ctx->global_keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2442  if (det_ctx->global_keyword_ctxs_array[item->id] == NULL) {
2443  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2444  "for keyword \"%s\" failed", item->name);
2445  return TM_ECODE_FAILED;
2446  }
2447  item = item->next;
2448  }
2449  }
2450  return TM_ECODE_OK;
2451 }
2452 
2453 static void DetectEngineThreadCtxDeinitGlobalKeywords(DetectEngineThreadCtx *det_ctx)
2454 {
2455  if (det_ctx->global_keyword_ctxs_array == NULL ||
2456  det_ctx->global_keyword_ctxs_size == 0) {
2457  return;
2458  }
2459 
2460  const DetectEngineMasterCtx *master = &g_master_de_ctx;
2461  if (master->keyword_id > 0) {
2462  const DetectEngineThreadKeywordCtxItem *item = master->keyword_list;
2463  while (item) {
2464  if (det_ctx->global_keyword_ctxs_array[item->id] != NULL)
2465  item->FreeFunc(det_ctx->global_keyword_ctxs_array[item->id]);
2466 
2467  item = item->next;
2468  }
2469  det_ctx->global_keyword_ctxs_size = 0;
2471  det_ctx->global_keyword_ctxs_array = NULL;
2472  }
2473 }
2474 
2475 static int DetectEngineThreadCtxInitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2476 {
2477  if (de_ctx->keyword_id > 0) {
2478  // coverity[suspicious_sizeof : FALSE]
2479  det_ctx->keyword_ctxs_array = SCMalloc(de_ctx->keyword_id * sizeof(void *));
2480  if (det_ctx->keyword_ctxs_array == NULL) {
2481  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx");
2482  return TM_ECODE_FAILED;
2483  }
2484 
2485  memset(det_ctx->keyword_ctxs_array, 0x00, de_ctx->keyword_id * sizeof(void *));
2486 
2487  det_ctx->keyword_ctxs_size = de_ctx->keyword_id;
2488 
2490  while (item) {
2491  det_ctx->keyword_ctxs_array[item->id] = item->InitFunc(item->data);
2492  if (det_ctx->keyword_ctxs_array[item->id] == NULL) {
2493  SCLogError(SC_ERR_DETECT_PREPARE, "setting up thread local detect ctx "
2494  "for keyword \"%s\" failed", item->name);
2495  return TM_ECODE_FAILED;
2496  }
2497  item = item->next;
2498  }
2499  }
2500  return TM_ECODE_OK;
2501 }
2502 
2503 static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2504 {
2505  if (de_ctx->keyword_id > 0) {
2507  while (item) {
2508  if (det_ctx->keyword_ctxs_array[item->id] != NULL)
2509  item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
2510 
2511  item = item->next;
2512  }
2513  det_ctx->keyword_ctxs_size = 0;
2514  SCFree(det_ctx->keyword_ctxs_array);
2515  det_ctx->keyword_ctxs_array = NULL;
2516  }
2517 }
2518 
2519 /** NOTE: master MUST be locked before calling this */
2520 static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
2521 {
2522  DetectEngineMasterCtx *master = &g_master_de_ctx;
2523  DetectEngineTenantMapping *map_array = NULL;
2524  uint32_t map_array_size = 0;
2525  uint32_t map_cnt = 0;
2526  int max_tenant_id = 0;
2527  DetectEngineCtx *list = master->list;
2528  HashTable *mt_det_ctxs_hash = NULL;
2529 
2530  if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
2531  SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: "
2532  "set using multi-detect.selector");
2533  return TM_ECODE_FAILED;
2534  }
2535 
2536  uint32_t tcnt = 0;
2537  while (list) {
2538  if (list->tenant_id > max_tenant_id)
2539  max_tenant_id = list->tenant_id;
2540 
2541  list = list->next;
2542  tcnt++;
2543  }
2544 
2545  mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
2546  if (mt_det_ctxs_hash == NULL) {
2547  goto error;
2548  }
2549 
2550  if (tcnt == 0) {
2551  SCLogInfo("no tenants left, or none registered yet");
2552  } else {
2553  max_tenant_id++;
2554 
2556  while (map) {
2557  map_cnt++;
2558  map = map->next;
2559  }
2560 
2561  if (map_cnt > 0) {
2562  map_array_size = map_cnt + 1;
2563 
2564  map_array = SCCalloc(map_array_size, sizeof(*map_array));
2565  if (map_array == NULL)
2566  goto error;
2567 
2568  /* fill the array */
2569  map_cnt = 0;
2570  map = master->tenant_mapping_list;
2571  while (map) {
2572  if (map_cnt >= map_array_size) {
2573  goto error;
2574  }
2575  map_array[map_cnt].traffic_id = map->traffic_id;
2576  map_array[map_cnt].tenant_id = map->tenant_id;
2577  map_cnt++;
2578  map = map->next;
2579  }
2580 
2581  }
2582 
2583  /* set up hash for tenant lookup */
2584  list = master->list;
2585  while (list) {
2586  SCLogDebug("tenant-id %u", list->tenant_id);
2587  if (list->tenant_id != 0) {
2588  DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
2589  if (mt_det_ctx == NULL)
2590  goto error;
2591  if (HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0) {
2592  goto error;
2593  }
2594  }
2595  list = list->next;
2596  }
2597  }
2598 
2599  det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
2600  mt_det_ctxs_hash = NULL;
2601 
2602  det_ctx->mt_det_ctxs_cnt = max_tenant_id;
2603 
2604  det_ctx->tenant_array = map_array;
2605  det_ctx->tenant_array_size = map_array_size;
2606 
2607  switch (master->tenant_selector) {
2609  SCLogDebug("TENANT_SELECTOR_UNKNOWN");
2610  break;
2611  case TENANT_SELECTOR_VLAN:
2612  det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
2613  SCLogDebug("TENANT_SELECTOR_VLAN");
2614  break;
2616  det_ctx->TenantGetId = DetectEngineTentantGetIdFromLivedev;
2617  SCLogDebug("TENANT_SELECTOR_LIVEDEV");
2618  break;
2620  det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
2621  SCLogDebug("TENANT_SELECTOR_DIRECT");
2622  break;
2623  }
2624 
2625  return TM_ECODE_OK;
2626 error:
2627  if (map_array != NULL)
2628  SCFree(map_array);
2629  if (mt_det_ctxs_hash != NULL)
2630  HashTableFree(mt_det_ctxs_hash);
2631 
2632  return TM_ECODE_FAILED;
2633 }
2634 
2635 /** \internal
2636  * \brief Helper for DetectThread setup functions
2637  */
2638 static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx)
2639 {
2643 
2644  PmqSetup(&det_ctx->pmq);
2645 
2647  if (det_ctx->spm_thread_ctx == NULL) {
2648  return TM_ECODE_FAILED;
2649  }
2650 
2651  /* sized to the max of our sgh settings. A max setting of 0 implies that all
2652  * sgh's have: sgh->non_pf_store_cnt == 0 */
2653  if (de_ctx->non_pf_store_cnt_max > 0) {
2655  BUG_ON(det_ctx->non_pf_id_array == NULL);
2656  }
2657 
2658  /* IP-ONLY */
2660 
2661  /* DeState */
2662  if (de_ctx->sig_array_len > 0) {
2663  det_ctx->match_array_len = de_ctx->sig_array_len;
2664  det_ctx->match_array = SCMalloc(det_ctx->match_array_len * sizeof(Signature *));
2665  if (det_ctx->match_array == NULL) {
2666  return TM_ECODE_FAILED;
2667  }
2668  memset(det_ctx->match_array, 0,
2669  det_ctx->match_array_len * sizeof(Signature *));
2670 
2672  }
2673 
2674  /* byte_extract storage */
2675  det_ctx->byte_values = SCMalloc(sizeof(*det_ctx->byte_values) *
2677  if (det_ctx->byte_values == NULL) {
2678  return TM_ECODE_FAILED;
2679  }
2680 
2681  /* Allocate space for base64 decoded data. */
2684  if (det_ctx->base64_decoded == NULL) {
2685  return TM_ECODE_FAILED;
2686  }
2688  det_ctx->base64_decoded_len = 0;
2689  }
2690 
2692  det_ctx->inspect.buffers = SCCalloc(det_ctx->inspect.buffers_size, sizeof(InspectionBuffer));
2693  if (det_ctx->inspect.buffers == NULL) {
2694  return TM_ECODE_FAILED;
2695  }
2696  det_ctx->inspect.to_clear_queue = SCCalloc(det_ctx->inspect.buffers_size, sizeof(uint32_t));
2697  if (det_ctx->inspect.to_clear_queue == NULL) {
2698  return TM_ECODE_FAILED;
2699  }
2700  det_ctx->inspect.to_clear_idx = 0;
2701 
2704  if (det_ctx->multi_inspect.buffers == NULL) {
2705  return TM_ECODE_FAILED;
2706  }
2707  det_ctx->multi_inspect.to_clear_queue = SCCalloc(det_ctx->multi_inspect.buffers_size, sizeof(uint32_t));
2708  if (det_ctx->multi_inspect.to_clear_queue == NULL) {
2709  return TM_ECODE_FAILED;
2710  }
2711  det_ctx->multi_inspect.to_clear_idx = 0;
2712 
2713 
2714  DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
2715  DetectEngineThreadCtxInitGlobalKeywords(det_ctx);
2716 #ifdef PROFILING
2721 #endif
2722  SC_ATOMIC_INIT(det_ctx->so_far_used_by_detect);
2723 
2724  return TM_ECODE_OK;
2725 }
2726 
2727 /** \brief initialize thread specific detection engine context
2728  *
2729  * \note there is a special case when using delayed detect. In this case the
2730  * function is called twice per thread. The first time the rules are not
2731  * yet loaded. de_ctx->delayed_detect_initialized will be 0. The 2nd
2732  * time they will be loaded. de_ctx->delayed_detect_initialized will be 1.
2733  * This is needed to do the per thread counter registration before the
2734  * packet runtime starts. In delayed detect mode, the first call will
2735  * return a NULL ptr through the data ptr.
2736  *
2737  * \param tv ThreadVars for this thread
2738  * \param initdata pointer to de_ctx
2739  * \param data[out] pointer to store our thread detection ctx
2740  *
2741  * \retval TM_ECODE_OK if all went well
2742  * \retval TM_ECODE_FAILED on serious errors
2743  */
2744 TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
2745 {
2747  if (unlikely(det_ctx == NULL))
2748  return TM_ECODE_FAILED;
2749  memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2750 
2751  det_ctx->tv = tv;
2752  det_ctx->de_ctx = DetectEngineGetCurrent();
2753  if (det_ctx->de_ctx == NULL) {
2754 #ifdef UNITTESTS
2755  if (RunmodeIsUnittests()) {
2756  det_ctx->de_ctx = (DetectEngineCtx *)initdata;
2757  } else {
2758  DetectEngineThreadCtxDeinit(tv, det_ctx);
2759  return TM_ECODE_FAILED;
2760  }
2761 #else
2762  DetectEngineThreadCtxDeinit(tv, det_ctx);
2763  return TM_ECODE_FAILED;
2764 #endif
2765  }
2766 
2767  if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2768  det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2769  {
2770  if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2771  DetectEngineThreadCtxDeinit(tv, det_ctx);
2772  return TM_ECODE_FAILED;
2773  }
2774  }
2775 
2776  /** alert counter setup */
2777  det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2778 #ifdef PROFILING
2779  det_ctx->counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2780  det_ctx->counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2781  det_ctx->counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2782  det_ctx->counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2783 #endif
2784 
2786  if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2787  DetectEngineThreadCtxDeinit(tv, det_ctx);
2788  return TM_ECODE_FAILED;
2789  }
2790  }
2791 
2792  /* pass thread data back to caller */
2793  *data = (void *)det_ctx;
2794 
2795  return TM_ECODE_OK;
2796 }
2797 
2798 /**
2799  * \internal
2800  * \brief initialize a det_ctx for reload cases
2801  * \param new_de_ctx the new detection engine
2802  * \param mt flag to indicate if MT should be set up for this det_ctx
2803  * this should only be done for the 'root' det_ctx
2804  *
2805  * \retval det_ctx detection engine thread ctx or NULL in case of error
2806  */
2807 static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
2808  ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
2809 {
2811  if (unlikely(det_ctx == NULL))
2812  return NULL;
2813  memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
2814 
2815  det_ctx->tenant_id = new_de_ctx->tenant_id;
2816  det_ctx->tv = tv;
2817  det_ctx->de_ctx = DetectEngineReference(new_de_ctx);
2818  if (det_ctx->de_ctx == NULL) {
2819  SCFree(det_ctx);
2820  return NULL;
2821  }
2822 
2823  /* most of the init happens here */
2824  if (det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
2825  det_ctx->de_ctx->type == DETECT_ENGINE_TYPE_TENANT)
2826  {
2827  if (ThreadCtxDoInit(det_ctx->de_ctx, det_ctx) != TM_ECODE_OK) {
2828  DetectEngineDeReference(&det_ctx->de_ctx);
2829  SCFree(det_ctx);
2830  return NULL;
2831  }
2832  }
2833 
2834  /** alert counter setup */
2835  det_ctx->counter_alerts = StatsRegisterCounter("detect.alert", tv);
2836 #ifdef PROFILING
2837  uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
2838  uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
2839  uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
2840  uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
2841  det_ctx->counter_mpm_list = counter_mpm_list;
2842  det_ctx->counter_nonmpm_list = counter_nonmpm_list;
2843  det_ctx->counter_fnonmpm_list = counter_fnonmpm_list;
2844  det_ctx->counter_match_list = counter_match_list;
2845 #endif
2846 
2847  if (mt && DetectEngineMultiTenantEnabled()) {
2848  if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
2849  DetectEngineDeReference(&det_ctx->de_ctx);
2850  SCFree(det_ctx);
2851  return NULL;
2852  }
2853  }
2854 
2855  return det_ctx;
2856 }
2857 
2858 static void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
2859 {
2860 #if DEBUG
2861  SCLogDebug("PACKET PKT_STREAM_ADD: %"PRIu64, det_ctx->pkt_stream_add_cnt);
2862 
2863  SCLogDebug("PAYLOAD MPM %"PRIu64"/%"PRIu64, det_ctx->payload_mpm_cnt, det_ctx->payload_mpm_size);
2864  SCLogDebug("STREAM MPM %"PRIu64"/%"PRIu64, det_ctx->stream_mpm_cnt, det_ctx->stream_mpm_size);
2865 
2866  SCLogDebug("PAYLOAD SIG %"PRIu64"/%"PRIu64, det_ctx->payload_persig_cnt, det_ctx->payload_persig_size);
2867  SCLogDebug("STREAM SIG %"PRIu64"/%"PRIu64, det_ctx->stream_persig_cnt, det_ctx->stream_persig_size);
2868 #endif
2869 
2870  if (det_ctx->tenant_array != NULL) {
2871  SCFree(det_ctx->tenant_array);
2872  det_ctx->tenant_array = NULL;
2873  }
2874 
2875 #ifdef PROFILING
2879  SCProfilingSghThreadCleanup(det_ctx);
2880 #endif
2881 
2883 
2884  /** \todo get rid of this static */
2885  if (det_ctx->de_ctx != NULL) {
2886  PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
2887  PatternMatchThreadDestroy(&det_ctx->mtcs, det_ctx->de_ctx->mpm_matcher);
2888  PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
2889  }
2890 
2891  PmqFree(&det_ctx->pmq);
2892 
2893  if (det_ctx->spm_thread_ctx != NULL) {
2895  }
2896 
2897  if (det_ctx->non_pf_id_array != NULL)
2898  SCFree(det_ctx->non_pf_id_array);
2899 
2900  if (det_ctx->match_array != NULL)
2901  SCFree(det_ctx->match_array);
2902 
2904 
2905  if (det_ctx->byte_values != NULL)
2906  SCFree(det_ctx->byte_values);
2907 
2908  /* Decoded base64 data. */
2909  if (det_ctx->base64_decoded != NULL) {
2910  SCFree(det_ctx->base64_decoded);
2911  }
2912 
2913  if (det_ctx->inspect.buffers) {
2914  for (uint32_t i = 0; i < det_ctx->inspect.buffers_size; i++) {
2915  InspectionBufferFree(&det_ctx->inspect.buffers[i]);
2916  }
2917  SCFree(det_ctx->inspect.buffers);
2918  }
2919  if (det_ctx->inspect.to_clear_queue) {
2920  SCFree(det_ctx->inspect.to_clear_queue);
2921  }
2922  if (det_ctx->multi_inspect.buffers) {
2923  for (uint32_t i = 0; i < det_ctx->multi_inspect.buffers_size; i++) {
2925  for (uint32_t x = 0; x < fb->size; x++) {
2927  }
2929  }
2930  SCFree(det_ctx->multi_inspect.buffers);
2931  }
2932  if (det_ctx->multi_inspect.to_clear_queue) {
2934  }
2935 
2936  DetectEngineThreadCtxDeinitGlobalKeywords(det_ctx);
2937  if (det_ctx->de_ctx != NULL) {
2938  DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
2939 #ifdef UNITTESTS
2940  if (!RunmodeIsUnittests() || det_ctx->de_ctx->ref_cnt > 0)
2941  DetectEngineDeReference(&det_ctx->de_ctx);
2942 #else
2943  DetectEngineDeReference(&det_ctx->de_ctx);
2944 #endif
2945  }
2946 
2948 
2949  SCFree(det_ctx);
2950 }
2951 
2953 {
2954  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
2955 
2956  if (det_ctx == NULL) {
2957  SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL");
2958  return TM_ECODE_OK;
2959  }
2960 
2961  if (det_ctx->mt_det_ctxs_hash != NULL) {
2962  HashTableFree(det_ctx->mt_det_ctxs_hash);
2963  det_ctx->mt_det_ctxs_hash = NULL;
2964  }
2965  DetectEngineThreadCtxFree(det_ctx);
2966 
2967  return TM_ECODE_OK;
2968 }
2969 
2971 {
2972  /* XXX */
2973  PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
2974  PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
2975 }
2976 
2977 /** \brief Register Thread keyword context Funcs
2978  *
2979  * \param de_ctx detection engine to register in
2980  * \param name keyword name for error printing
2981  * \param InitFunc function ptr
2982  * \param data keyword init data to pass to Func. Can be NULL.
2983  * \param FreeFunc function ptr
2984  * \param mode 0 normal (ctx per keyword instance) 1 shared (one ctx per det_ct)
2985  *
2986  * \retval id for retrieval of ctx at runtime
2987  * \retval -1 on error
2988  *
2989  * \note make sure "data" remains valid and it free'd elsewhere. It's
2990  * recommended to store it in the keywords global ctx so that
2991  * it's freed when the de_ctx is freed.
2992  */
2993 int DetectRegisterThreadCtxFuncs(DetectEngineCtx *de_ctx, const char *name, void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *), int mode)
2994 {
2995  BUG_ON(de_ctx == NULL || InitFunc == NULL || FreeFunc == NULL);
2996 
2997  if (mode) {
2999  while (item != NULL) {
3000  if (strcmp(name, item->name) == 0) {
3001  return item->id;
3002  }
3003 
3004  item = item->next;
3005  }
3006  }
3007 
3009  if (unlikely(item == NULL))
3010  return -1;
3011  memset(item, 0x00, sizeof(DetectEngineThreadKeywordCtxItem));
3012 
3013  item->InitFunc = InitFunc;
3014  item->FreeFunc = FreeFunc;
3015  item->data = data;
3016  item->name = name;
3017 
3018  item->next = de_ctx->keyword_list;
3019  de_ctx->keyword_list = item;
3020  item->id = de_ctx->keyword_id++;
3021 
3022  return item->id;
3023 }
3024 
3025 /** \brief Remove Thread keyword context registration
3026  *
3027  * \param de_ctx detection engine to deregister from
3028  * \param det_ctx detection engine thread context to deregister from
3029  * \param data keyword init data to pass to Func. Can be NULL.
3030  * \param name keyword name for error printing
3031  *
3032  * \retval 1 Item unregistered
3033  * \retval 0 otherwise
3034  *
3035  * \note make sure "data" remains valid and it free'd elsewhere. It's
3036  * recommended to store it in the keywords global ctx so that
3037  * it's freed when the de_ctx is freed.
3038  */
3040  DetectEngineThreadCtx *det_ctx, void *data, const char *name)
3041 {
3042  BUG_ON(de_ctx == NULL);
3043 
3045  DetectEngineThreadKeywordCtxItem *prev_item = NULL;
3046  while (item != NULL) {
3047  if (strcmp(name, item->name) == 0 && (data == item->data)) {
3048  if (prev_item == NULL)
3049  de_ctx->keyword_list = item->next;
3050  else
3051  prev_item->next = item->next;
3052  if (det_ctx)
3053  item->FreeFunc(det_ctx->keyword_ctxs_array[item->id]);
3054  SCFree(item);
3055  return 1;
3056  }
3057  prev_item = item;
3058  item = item->next;
3059  }
3060  return 0;
3061 }
3062 /** \brief Retrieve thread local keyword ctx by id
3063  *
3064  * \param det_ctx detection engine thread ctx to retrieve the ctx from
3065  * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3066  * keyword init.
3067  *
3068  * \retval ctx or NULL on error
3069  */
3071 {
3072  if (id < 0 || id > det_ctx->keyword_ctxs_size || det_ctx->keyword_ctxs_array == NULL)
3073  return NULL;
3074 
3075  return det_ctx->keyword_ctxs_array[id];
3076 }
3077 
3078 
3079 /** \brief Register Thread keyword context Funcs (Global)
3080  *
3081  * IDs stay static over reloads and between tenants
3082  *
3083  * \param name keyword name for error printing
3084  * \param InitFunc function ptr
3085  * \param FreeFunc function ptr
3086  *
3087  * \retval id for retrieval of ctx at runtime
3088  * \retval -1 on error
3089  */
3091  void *(*InitFunc)(void *), void *data, void (*FreeFunc)(void *))
3092 {
3093  int id;
3094  BUG_ON(InitFunc == NULL || FreeFunc == NULL);
3095 
3096  DetectEngineMasterCtx *master = &g_master_de_ctx;
3097 
3098  /* if already registered, return existing id */
3100  while (item != NULL) {
3101  if (strcmp(name, item->name) == 0) {
3102  id = item->id;
3103  return id;
3104  }
3105 
3106  item = item->next;
3107  }
3108 
3109  item = SCCalloc(1, sizeof(*item));
3110  if (unlikely(item == NULL)) {
3111  return -1;
3112  }
3113  item->InitFunc = InitFunc;
3114  item->FreeFunc = FreeFunc;
3115  item->name = name;
3116  item->data = data;
3117 
3118  item->next = master->keyword_list;
3119  master->keyword_list = item;
3120  item->id = master->keyword_id++;
3121 
3122  id = item->id;
3123  return id;
3124 }
3125 
3126 /** \brief Retrieve thread local keyword ctx by id
3127  *
3128  * \param det_ctx detection engine thread ctx to retrieve the ctx from
3129  * \param id id of the ctx returned by DetectRegisterThreadCtxInitFunc at
3130  * keyword init.
3131  *
3132  * \retval ctx or NULL on error
3133  */
3135 {
3136  if (id < 0 || id > det_ctx->global_keyword_ctxs_size ||
3137  det_ctx->global_keyword_ctxs_array == NULL) {
3138  return NULL;
3139  }
3140 
3141  return det_ctx->global_keyword_ctxs_array[id];
3142 }
3143 
3144 /** \brief Check if detection is enabled
3145  * \retval bool true or false */
3147 {
3148  DetectEngineMasterCtx *master = &g_master_de_ctx;
3149  SCMutexLock(&master->lock);
3150 
3151  if (master->list == NULL) {
3152  SCMutexUnlock(&master->lock);
3153  return 0;
3154  }
3155 
3156  SCMutexUnlock(&master->lock);
3157  return 1;
3158 }
3159 
3161 {
3162  uint32_t version;
3163  DetectEngineMasterCtx *master = &g_master_de_ctx;
3164  SCMutexLock(&master->lock);
3165  version = master->version;
3166  SCMutexUnlock(&master->lock);
3167  return version;
3168 }
3169 
3171 {
3172  DetectEngineMasterCtx *master = &g_master_de_ctx;
3173  SCMutexLock(&master->lock);
3174  master->version++;
3175  SCLogDebug("master version now %u", master->version);
3176  SCMutexUnlock(&master->lock);
3177 }
3178 
3180 {
3181  DetectEngineMasterCtx *master = &g_master_de_ctx;
3182  SCMutexLock(&master->lock);
3183 
3184  DetectEngineCtx *de_ctx = master->list;
3185  while (de_ctx) {
3189  {
3190  de_ctx->ref_cnt++;
3191  SCLogDebug("de_ctx %p ref_cnt %u", de_ctx, de_ctx->ref_cnt);
3192  SCMutexUnlock(&master->lock);
3193  return de_ctx;
3194  }
3195  de_ctx = de_ctx->next;
3196  }
3197 
3198  SCMutexUnlock(&master->lock);
3199  return NULL;
3200 }
3201 
3203 {
3204  if (de_ctx == NULL)
3205  return NULL;
3206  de_ctx->ref_cnt++;
3207  return de_ctx;
3208 }
3209 
3210 /** TODO locking? Not needed if this is a one time setting at startup */
3212 {
3213  DetectEngineMasterCtx *master = &g_master_de_ctx;
3214  return (master->multi_tenant_enabled);
3215 }
3216 
3217 /** \internal
3218  * \brief load a tenant from a yaml file
3219  *
3220  * \param tenant_id the tenant id by which the config is known
3221  * \param filename full path of a yaml file
3222  * \param loader_id id of loader thread or -1
3223  *
3224  * \retval 0 ok
3225  * \retval -1 failed
3226  */
3227 static int DetectEngineMultiTenantLoadTenant(uint32_t tenant_id, const char *filename, int loader_id)
3228 {
3229  DetectEngineCtx *de_ctx = NULL;
3230  char prefix[64];
3231 
3232  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3233 
3234 #ifdef OS_WIN32
3235  struct _stat st;
3236  if(_stat(filename, &st) != 0) {
3237 #else
3238  struct stat st;
3239  if(stat(filename, &st) != 0) {
3240 #endif /* OS_WIN32 */
3241  SCLogError(SC_ERR_FOPEN, "failed to stat file %s", filename);
3242  goto error;
3243  }
3244 
3245  de_ctx = DetectEngineGetByTenantId(tenant_id);
3246  if (de_ctx != NULL) {
3247  SCLogError(SC_ERR_MT_DUPLICATE_TENANT, "tenant %u already registered",
3248  tenant_id);
3250  goto error;
3251  }
3252 
3253  ConfNode *node = ConfGetNode(prefix);
3254  if (node == NULL) {
3255  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
3256  goto error;
3257  }
3258 
3260  if (de_ctx == NULL) {
3261  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3262  "context failed.");
3263  goto error;
3264  }
3265  SCLogDebug("de_ctx %p with prefix %s", de_ctx, de_ctx->config_prefix);
3266 
3268  de_ctx->tenant_id = tenant_id;
3269  de_ctx->loader_id = loader_id;
3270 
3271  if (SigLoadSignatures(de_ctx, NULL, 0) < 0) {
3272  SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
3273  goto error;
3274  }
3275 
3277 
3278  return 0;
3279 
3280 error:
3281  if (de_ctx != NULL) {
3283  }
3284  return -1;
3285 }
3286 
3287 static int DetectEngineMultiTenantReloadTenant(uint32_t tenant_id, const char *filename, int reload_cnt)
3288 {
3289  DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3290  if (old_de_ctx == NULL) {
3291  SCLogError(SC_ERR_INITIALIZATION, "tenant detect engine not found");
3292  return -1;
3293  }
3294 
3295  char prefix[64];
3296  snprintf(prefix, sizeof(prefix), "multi-detect.%d.reload.%d", tenant_id, reload_cnt);
3297  reload_cnt++;
3298  SCLogDebug("prefix %s", prefix);
3299 
3300  if (ConfYamlLoadFileWithPrefix(filename, prefix) != 0) {
3301  SCLogError(SC_ERR_INITIALIZATION,"failed to load yaml");
3302  goto error;
3303  }
3304 
3305  ConfNode *node = ConfGetNode(prefix);
3306  if (node == NULL) {
3307  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s", filename);
3308  goto error;
3309  }
3310 
3311  DetectEngineCtx *new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
3312  if (new_de_ctx == NULL) {
3313  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
3314  "context failed.");
3315  goto error;
3316  }
3317  SCLogDebug("de_ctx %p with prefix %s", new_de_ctx, new_de_ctx->config_prefix);
3318 
3319  new_de_ctx->type = DETECT_ENGINE_TYPE_TENANT;
3320  new_de_ctx->tenant_id = tenant_id;
3321  new_de_ctx->loader_id = old_de_ctx->loader_id;
3322 
3323  if (SigLoadSignatures(new_de_ctx, NULL, 0) < 0) {
3324  SCLogError(SC_ERR_NO_RULES_LOADED, "Loading signatures failed.");
3325  goto error;
3326  }
3327 
3328  DetectEngineAddToMaster(new_de_ctx);
3329 
3330  /* move to free list */
3331  DetectEngineMoveToFreeList(old_de_ctx);
3332  DetectEngineDeReference(&old_de_ctx);
3333  return 0;
3334 
3335 error:
3336  DetectEngineDeReference(&old_de_ctx);
3337  return -1;
3338 }
3339 
3340 
3341 typedef struct TenantLoaderCtx_ {
3342  uint32_t tenant_id;
3343  int reload_cnt; /**< used by reload */
3344  const char *yaml;
3346 
3347 static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
3348 {
3349  TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3350 
3351  SCLogDebug("loader %d", loader_id);
3352  if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
3353  return -1;
3354  }
3355  return 0;
3356 }
3357 
3358 static int DetectLoaderSetupLoadTenant(uint32_t tenant_id, const char *yaml)
3359 {
3360  TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3361  if (t == NULL)
3362  return -ENOMEM;
3363 
3364  t->tenant_id = tenant_id;
3365  t->yaml = yaml;
3366 
3367  return DetectLoaderQueueTask(-1, DetectLoaderFuncLoadTenant, t);
3368 }
3369 
3370 static int DetectLoaderFuncReloadTenant(void *vctx, int loader_id)
3371 {
3372  TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
3373 
3374  SCLogDebug("loader_id %d", loader_id);
3375 
3376  if (DetectEngineMultiTenantReloadTenant(ctx->tenant_id, ctx->yaml, ctx->reload_cnt) != 0) {
3377  return -1;
3378  }
3379  return 0;
3380 }
3381 
3382 static int DetectLoaderSetupReloadTenant(uint32_t tenant_id, const char *yaml, int reload_cnt)
3383 {
3384  DetectEngineCtx *old_de_ctx = DetectEngineGetByTenantId(tenant_id);
3385  if (old_de_ctx == NULL)
3386  return -ENOENT;
3387  int loader_id = old_de_ctx->loader_id;
3388  DetectEngineDeReference(&old_de_ctx);
3389 
3390  TenantLoaderCtx *t = SCCalloc(1, sizeof(*t));
3391  if (t == NULL)
3392  return -ENOMEM;
3393 
3394  t->tenant_id = tenant_id;
3395  t->yaml = yaml;
3396  t->reload_cnt = reload_cnt;
3397 
3398  SCLogDebug("loader_id %d", loader_id);
3399 
3400  return DetectLoaderQueueTask(loader_id, DetectLoaderFuncReloadTenant, t);
3401 }
3402 
3403 /** \brief Load a tenant and wait for loading to complete
3404  */
3405 int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
3406 {
3407  int r = DetectLoaderSetupLoadTenant(tenant_id, yaml);
3408  if (r < 0)
3409  return r;
3410 
3411  if (DetectLoadersSync() != 0)
3412  return -1;
3413 
3414  return 0;
3415 }
3416 
3417 /** \brief Reload a tenant and wait for loading to complete
3418  */
3419 int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int reload_cnt)
3420 {
3421  int r = DetectLoaderSetupReloadTenant(tenant_id, yaml, reload_cnt);
3422  if (r < 0)
3423  return r;
3424 
3425  if (DetectLoadersSync() != 0)
3426  return -1;
3427 
3428  return 0;
3429 }
3430 
3431 static int DetectEngineMultiTenantSetupLoadLivedevMappings(const ConfNode *mappings_root_node,
3432  bool failure_fatal)
3433 {
3434  ConfNode *mapping_node = NULL;
3435 
3436  int mapping_cnt = 0;
3437  if (mappings_root_node != NULL) {
3438  TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3439  ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3440  if (tenant_id_node == NULL)
3441  goto bad_mapping;
3442  ConfNode *device_node = ConfNodeLookupChild(mapping_node, "device");
3443  if (device_node == NULL)
3444  goto bad_mapping;
3445 
3446  uint32_t tenant_id = 0;
3447  if (StringParseUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3448  tenant_id_node->val) < 0)
3449  {
3450  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3451  "of %s is invalid", tenant_id_node->val);
3452  goto bad_mapping;
3453  }
3454 
3455  const char *dev = device_node->val;
3456  LiveDevice *ld = LiveGetDevice(dev);
3457  if (ld == NULL) {
3458  SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s not found", dev);
3459  goto bad_mapping;
3460  }
3461 
3462  if (ld->tenant_id_set) {
3463  SCLogWarning(SC_ERR_MT_NO_MAPPING, "device %s already mapped to tenant-id %u",
3464  dev, ld->tenant_id);
3465  goto bad_mapping;
3466  }
3467 
3468  ld->tenant_id = tenant_id;
3469  ld->tenant_id_set = true;
3470 
3471  if (DetectEngineTentantRegisterLivedev(tenant_id, ld->id) != 0) {
3472  goto error;
3473  }
3474 
3475  SCLogConfig("device %s connected to tenant-id %u", dev, tenant_id);
3476  mapping_cnt++;
3477  continue;
3478 
3479  bad_mapping:
3480  if (failure_fatal)
3481  goto error;
3482  }
3483  }
3484  SCLogConfig("%d device - tenant-id mappings defined", mapping_cnt);
3485  return mapping_cnt;
3486 
3487 error:
3488  return 0;
3489 }
3490 
3491 static int DetectEngineMultiTenantSetupLoadVlanMappings(const ConfNode *mappings_root_node,
3492  bool failure_fatal)
3493 {
3494  ConfNode *mapping_node = NULL;
3495 
3496  int mapping_cnt = 0;
3497  if (mappings_root_node != NULL) {
3498  TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
3499  ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
3500  if (tenant_id_node == NULL)
3501  goto bad_mapping;
3502  ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
3503  if (vlan_id_node == NULL)
3504  goto bad_mapping;
3505 
3506  uint32_t tenant_id = 0;
3507  if (StringParseUint32(&tenant_id, 10, strlen(tenant_id_node->val),
3508  tenant_id_node->val) < 0)
3509  {
3510  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
3511  "of %s is invalid", tenant_id_node->val);
3512  goto bad_mapping;
3513  }
3514 
3515  uint16_t vlan_id = 0;
3516  if (StringParseUint16(&vlan_id, 10, strlen(vlan_id_node->val),
3517  vlan_id_node->val) < 0)
3518  {
3520  "of %s is invalid", vlan_id_node->val);
3521  goto bad_mapping;
3522  }
3523  if (vlan_id == 0 || vlan_id >= 4095) {
3525  "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
3526  goto bad_mapping;
3527  }
3528 
3529  if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
3530  goto error;
3531  }
3532  SCLogConfig("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
3533  mapping_cnt++;
3534  continue;
3535 
3536  bad_mapping:
3537  if (failure_fatal)
3538  goto error;
3539  }
3540  }
3541  return mapping_cnt;
3542 
3543 error:
3544  return 0;
3545 }
3546 
3547 /**
3548  * \brief setup multi-detect / multi-tenancy
3549  *
3550  * See if MT is enabled. If so, setup the selector, tenants and mappings.
3551  * Tenants and mappings are optional, and can also dynamically be added
3552  * and removed from the unix socket.
3553  */
3555 {
3557  DetectEngineMasterCtx *master = &g_master_de_ctx;
3558 
3559  int unix_socket = ConfUnixSocketIsEnable();
3560 
3561  int failure_fatal = 0;
3562  (void)ConfGetBool("engine.init-failure-fatal", &failure_fatal);
3563 
3564  int enabled = 0;
3565  (void)ConfGetBool("multi-detect.enabled", &enabled);
3566  if (enabled == 1) {
3571 
3572  SCMutexLock(&master->lock);
3573  master->multi_tenant_enabled = 1;
3574 
3575  const char *handler = NULL;
3576  if (ConfGet("multi-detect.selector", &handler) == 1) {
3577  SCLogConfig("multi-tenant selector type %s", handler);
3578 
3579  if (strcmp(handler, "vlan") == 0) {
3580  tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
3581 
3582  int vlanbool = 0;
3583  if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
3584  SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, "
3585  "can't use multi-detect selector 'vlan'");
3586  SCMutexUnlock(&master->lock);
3587  goto error;
3588  }
3589 
3590  } else if (strcmp(handler, "direct") == 0) {
3591  tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
3592  } else if (strcmp(handler, "device") == 0) {
3593  tenant_selector = master->tenant_selector = TENANT_SELECTOR_LIVEDEV;
3594  if (EngineModeIsIPS()) {
3596  "multi-tenant 'device' mode not supported for IPS");
3597  SCMutexUnlock(&master->lock);
3598  goto error;
3599  }
3600 
3601  } else {
3602  SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
3603  "multi-detect.selector", handler);
3604  SCMutexUnlock(&master->lock);
3605  goto error;
3606  }
3607  }
3608  SCMutexUnlock(&master->lock);
3609  SCLogConfig("multi-detect is enabled (multi tenancy). Selector: %s", handler);
3610 
3611  /* traffic -- tenant mappings */
3612  ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
3613 
3614  if (tenant_selector == TENANT_SELECTOR_VLAN) {
3615  int mapping_cnt = DetectEngineMultiTenantSetupLoadVlanMappings(mappings_root_node,
3616  failure_fatal);
3617  if (mapping_cnt == 0) {
3618  /* no mappings are valid when we're in unix socket mode,
3619  * they can be added on the fly. Otherwise warn/error
3620  * depending on failure_fatal */
3621 
3622  if (unix_socket) {
3623  SCLogNotice("no tenant traffic mappings defined, "
3624  "tenants won't be used until mappings are added");
3625  } else {
3626  if (failure_fatal) {
3627  SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3628  goto error;
3629  } else {
3630  SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3631  }
3632  }
3633  }
3634  } else if (tenant_selector == TENANT_SELECTOR_LIVEDEV) {
3635  int mapping_cnt = DetectEngineMultiTenantSetupLoadLivedevMappings(mappings_root_node,
3636  failure_fatal);
3637  if (mapping_cnt == 0) {
3638  if (failure_fatal) {
3639  SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3640  goto error;
3641  } else {
3642  SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
3643  }
3644  }
3645  }
3646 
3647  /* tenants */
3648  ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants");
3649  ConfNode *tenant_node = NULL;
3650 
3651  if (tenants_root_node != NULL) {
3652  TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
3653  ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id");
3654  if (id_node == NULL) {
3655  goto bad_tenant;
3656  }
3657  ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml");
3658  if (yaml_node == NULL) {
3659  goto bad_tenant;
3660  }
3661 
3662  uint32_t tenant_id = 0;
3663  if (StringParseUint32(&tenant_id, 10, strlen(id_node->val),
3664  id_node->val) < 0)
3665  {
3666  SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant_id "
3667  "of %s is invalid", id_node->val);
3668  goto bad_tenant;
3669  }
3670  SCLogDebug("tenant id: %u, %s", tenant_id, yaml_node->val);
3671 
3672  /* setup the yaml in this loop so that it's not done by the loader
3673  * threads. ConfYamlLoadFileWithPrefix is not thread safe. */
3674  char prefix[64];
3675  snprintf(prefix, sizeof(prefix), "multi-detect.%d", tenant_id);
3676  if (ConfYamlLoadFileWithPrefix(yaml_node->val, prefix) != 0) {
3677  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s", yaml_node->val);
3678  goto bad_tenant;
3679  }
3680 
3681  int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val);
3682  if (r < 0) {
3683  /* error logged already */
3684  goto bad_tenant;
3685  }
3686  continue;
3687 
3688  bad_tenant:
3689  if (failure_fatal)
3690  goto error;
3691  }
3692  }
3693 
3694  /* wait for our loaders to complete their tasks */
3695  if (DetectLoadersSync() != 0) {
3696  goto error;
3697  }
3698 
3700 
3701  } else {
3702  SCLogDebug("multi-detect not enabled (multi tenancy)");
3703  }
3704  return 0;
3705 error:
3706  return -1;
3707 }
3708 
3709 static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)
3710 {
3711  const DetectEngineThreadCtx *det_ctx = ctx;
3712  uint32_t x = 0;
3713  uint32_t vlan_id = 0;
3714 
3715  if (p->vlan_idx == 0)
3716  return 0;
3717 
3718  vlan_id = p->vlan_id[0];
3719 
3720  if (det_ctx == NULL || det_ctx->tenant_array == NULL || det_ctx->tenant_array_size == 0)
3721  return 0;
3722 
3723  /* not very efficient, but for now we're targeting only limited amounts.
3724  * Can use hash/tree approach later. */
3725  for (x = 0; x < det_ctx->tenant_array_size; x++) {
3726  if (det_ctx->tenant_array[x].traffic_id == vlan_id)
3727  return det_ctx->tenant_array[x].tenant_id;
3728  }
3729 
3730  return 0;
3731 }
3732 
3733 static uint32_t DetectEngineTentantGetIdFromLivedev(const void *ctx, const Packet *p)
3734 {
3735  const DetectEngineThreadCtx *det_ctx = ctx;
3736  const LiveDevice *ld = p->livedev;
3737 
3738  if (ld == NULL || det_ctx == NULL)
3739  return 0;
3740 
3741  SCLogDebug("using tenant-id %u for packet on device %s", ld->tenant_id, ld->dev);
3742  return ld->tenant_id;
3743 }
3744 
3745 static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors selector,
3746  uint32_t tenant_id, uint32_t traffic_id)
3747 {
3748  DetectEngineMasterCtx *master = &g_master_de_ctx;
3749  SCMutexLock(&master->lock);
3750 
3751  if (!(master->tenant_selector == TENANT_SELECTOR_UNKNOWN || master->tenant_selector == selector)) {
3752  SCLogInfo("conflicting selector already set");
3753  SCMutexUnlock(&master->lock);
3754  return -1;
3755  }
3756 
3758  while (m) {
3759  if (m->traffic_id == traffic_id) {
3760  SCLogInfo("traffic id already registered");
3761  SCMutexUnlock(&master->lock);
3762  return -1;
3763  }
3764  m = m->next;
3765  }
3766 
3767  DetectEngineTenantMapping *map = SCCalloc(1, sizeof(*map));
3768  if (map == NULL) {
3769  SCLogInfo("memory fail");
3770  SCMutexUnlock(&master->lock);
3771  return -1;
3772  }
3773  map->traffic_id = traffic_id;
3774  map->tenant_id = tenant_id;
3775 
3776  map->next = master->tenant_mapping_list;
3777  master->tenant_mapping_list = map;
3778 
3779  master->tenant_selector = selector;
3780 
3781  SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
3782  SCMutexUnlock(&master->lock);
3783  return 0;
3784 }
3785 
3786 static int DetectEngineTentantUnregisterSelector(enum DetectEngineTenantSelectors selector,
3787  uint32_t tenant_id, uint32_t traffic_id)
3788 {
3789  DetectEngineMasterCtx *master = &g_master_de_ctx;
3790  SCMutexLock(&master->lock);
3791 
3792  if (master->tenant_mapping_list == NULL) {
3793  SCMutexUnlock(&master->lock);
3794  return -1;
3795  }
3796 
3797  DetectEngineTenantMapping *prev = NULL;
3799  while (map) {
3800  if (map->traffic_id == traffic_id &&
3801  map->tenant_id == tenant_id)
3802  {
3803  if (prev != NULL)
3804  prev->next = map->next;
3805  else
3806  master->tenant_mapping_list = map->next;
3807 
3808  map->next = NULL;
3809  SCFree(map);
3810  SCLogInfo("tenant handler %u %u %u unregistered", selector, tenant_id, traffic_id);
3811  SCMutexUnlock(&master->lock);
3812  return 0;
3813  }
3814  prev = map;
3815  map = map->next;
3816  }
3817 
3818  SCMutexUnlock(&master->lock);
3819  return -1;
3820 }
3821 
3822 int DetectEngineTentantRegisterLivedev(uint32_t tenant_id, int device_id)
3823 {
3824  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_LIVEDEV, tenant_id, (uint32_t)device_id);
3825 }
3826 
3827 int DetectEngineTentantRegisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3828 {
3829  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3830 }
3831 
3832 int DetectEngineTentantUnregisterVlanId(uint32_t tenant_id, uint16_t vlan_id)
3833 {
3834  return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_VLAN, tenant_id, (uint32_t)vlan_id);
3835 }
3836 
3838 {
3839  SCLogInfo("registering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3840  return DetectEngineTentantRegisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3841 }
3842 
3844 {
3845  SCLogInfo("unregistering %u %d 0", TENANT_SELECTOR_DIRECT, tenant_id);
3846  return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
3847 }
3848 
3849 static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p)
3850 {
3851  return p->pcap_v.tenant_id;
3852 }
3853 
3855 {
3856  DetectEngineMasterCtx *master = &g_master_de_ctx;
3857  SCMutexLock(&master->lock);
3858 
3859  if (master->list == NULL) {
3860  SCMutexUnlock(&master->lock);
3861  return NULL;
3862  }
3863 
3864  DetectEngineCtx *de_ctx = master->list;
3865  while (de_ctx) {
3867  de_ctx->tenant_id == tenant_id)
3868  {
3869  de_ctx->ref_cnt++;
3870  break;
3871  }
3872 
3873  de_ctx = de_ctx->next;
3874  }
3875 
3876  SCMutexUnlock(&master->lock);
3877  return de_ctx;
3878 }
3879 
3881 {
3882  BUG_ON((*de_ctx)->ref_cnt == 0);
3883  (*de_ctx)->ref_cnt--;
3884  *de_ctx = NULL;
3885 }
3886 
3887 static int DetectEngineAddToList(DetectEngineCtx *instance)
3888 {
3889  DetectEngineMasterCtx *master = &g_master_de_ctx;
3890 
3891  if (instance == NULL)
3892  return -1;
3893 
3894  if (master->list == NULL) {
3895  master->list = instance;
3896  } else {
3897  instance->next = master->list;
3898  master->list = instance;
3899  }
3900 
3901  return 0;
3902 }
3903 
3905 {
3906  int r;
3907 
3908  if (de_ctx == NULL)
3909  return -1;
3910 
3911  SCLogDebug("adding de_ctx %p to master", de_ctx);
3912 
3913  DetectEngineMasterCtx *master = &g_master_de_ctx;
3914  SCMutexLock(&master->lock);
3915  r = DetectEngineAddToList(de_ctx);
3916  SCMutexUnlock(&master->lock);
3917  return r;
3918 }
3919 
3921 {
3922  DetectEngineMasterCtx *master = &g_master_de_ctx;
3923 
3924  SCMutexLock(&master->lock);
3925  DetectEngineCtx *instance = master->list;
3926  if (instance == NULL) {
3927  SCMutexUnlock(&master->lock);
3928  return -1;
3929  }
3930 
3931  /* remove from active list */
3932  if (instance == de_ctx) {
3933  master->list = instance->next;
3934  } else {
3935  DetectEngineCtx *prev = instance;
3936  instance = instance->next; /* already checked first element */
3937 
3938  while (instance) {
3939  DetectEngineCtx *next = instance->next;
3940 
3941  if (instance == de_ctx) {
3942  prev->next = instance->next;
3943  break;
3944  }
3945 
3946  prev = instance;
3947  instance = next;
3948  }
3949  if (instance == NULL) {
3950  SCMutexUnlock(&master->lock);
3951  return -1;
3952  }
3953  }
3954 
3955  /* instance is now detached from list */
3956  instance->next = NULL;
3957 
3958  /* add to free list */
3959  if (master->free_list == NULL) {
3960  master->free_list = instance;
3961  } else {
3962  instance->next = master->free_list;
3963  master->free_list = instance;
3964  }
3965  SCLogDebug("detect engine %p moved to free list (%u refs)", de_ctx, de_ctx->ref_cnt);
3966 
3967  SCMutexUnlock(&master->lock);
3968  return 0;
3969 }
3970 
3972 {
3973  DetectEngineMasterCtx *master = &g_master_de_ctx;
3974  SCMutexLock(&master->lock);
3975 
3976  DetectEngineCtx *prev = NULL;
3977  DetectEngineCtx *instance = master->free_list;
3978  while (instance) {
3979  DetectEngineCtx *next = instance->next;
3980 
3981  SCLogDebug("detect engine %p has %u ref(s)", instance, instance->ref_cnt);
3982 
3983  if (instance->ref_cnt == 0) {
3984  if (prev == NULL) {
3985  master->free_list = next;
3986  } else {
3987  prev->next = next;
3988  }
3989 
3990  SCLogDebug("freeing detect engine %p", instance);
3991  DetectEngineCtxFree(instance);
3992  instance = NULL;
3993  }
3994 
3995  prev = instance;
3996  instance = next;
3997  }
3998  SCMutexUnlock(&master->lock);
3999 }
4000 
4001 static int reloads = 0;
4002 
4003 /** \brief Reload the detection engine
4004  *
4005  * \param filename YAML file to load for the detect config
4006  *
4007  * \retval -1 error
4008  * \retval 0 ok
4009  */
4011 {
4012  DetectEngineCtx *new_de_ctx = NULL;
4013  DetectEngineCtx *old_de_ctx = NULL;
4014 
4015  char prefix[128];
4016  memset(prefix, 0, sizeof(prefix));
4017 
4018  SCLogNotice("rule reload starting");
4019 
4020  if (suri->conf_filename != NULL) {
4021  snprintf(prefix, sizeof(prefix), "detect-engine-reloads.%d", reloads++);
4022  if (ConfYamlLoadFileWithPrefix(suri->conf_filename, prefix) != 0) {
4023  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to load yaml %s",
4024  suri->conf_filename);
4025  return -1;
4026  }
4027 
4028  ConfNode *node = ConfGetNode(prefix);
4029  if (node == NULL) {
4030  SCLogError(SC_ERR_CONF_YAML_ERROR, "failed to properly setup yaml %s",
4031  suri->conf_filename);
4032  return -1;
4033  }
4034 #if 0
4035  ConfDump();
4036 #endif
4037  }
4038 
4039  /* get a reference to the current de_ctx */
4040  old_de_ctx = DetectEngineGetCurrent();
4041  if (old_de_ctx == NULL)
4042  return -1;
4043  SCLogDebug("get ref to old_de_ctx %p", old_de_ctx);
4044  DatasetReload();
4045 
4046  /* only reload a regular 'normal' and 'delayed detect stub' detect engines */
4047  if (!(old_de_ctx->type == DETECT_ENGINE_TYPE_NORMAL ||
4048  old_de_ctx->type == DETECT_ENGINE_TYPE_DD_STUB))
4049  {
4050  DetectEngineDeReference(&old_de_ctx);
4051  SCLogNotice("rule reload complete");
4052  return -1;
4053  }
4054 
4055  /* get new detection engine */
4056  new_de_ctx = DetectEngineCtxInitWithPrefix(prefix);
4057  if (new_de_ctx == NULL) {
4058  SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
4059  "context failed.");
4060  DetectEngineDeReference(&old_de_ctx);
4061  return -1;
4062  }
4063  if (SigLoadSignatures(new_de_ctx,
4064  suri->sig_file, suri->sig_file_exclusive) != 0) {
4065  DetectEngineCtxFree(new_de_ctx);
4066  DetectEngineDeReference(&old_de_ctx);
4067  return -1;
4068  }
4069  SCLogDebug("set up new_de_ctx %p", new_de_ctx);
4070 
4071  /* add to master */
4072  DetectEngineAddToMaster(new_de_ctx);
4073 
4074  /* move to old free list */
4075  DetectEngineMoveToFreeList(old_de_ctx);
4076  DetectEngineDeReference(&old_de_ctx);
4077 
4078  SCLogDebug("going to reload the threads to use new_de_ctx %p", new_de_ctx);
4079  /* update the threads */
4080  DetectEngineReloadThreads(new_de_ctx);
4081  SCLogDebug("threads now run new_de_ctx %p", new_de_ctx);
4082 
4083  /* walk free list, freeing the old_de_ctx */
4085 
4087 
4089 
4090  SCLogDebug("old_de_ctx should have been freed");
4091 
4092  SCLogNotice("rule reload complete");
4093  return 0;
4094 }
4095 
4096 static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len)
4097 {
4098  DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
4099  return det_ctx->tenant_id % h->array_size;
4100 }
4101 
4102 static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len)
4103 {
4106  return (det1->tenant_id == det2->tenant_id);
4107 }
4108 
4109 static void TenantIdFree(void *d)
4110 {
4111  DetectEngineThreadCtxFree(d);
4112 }
4113 
4115 {
4116  DetectEngineMasterCtx *master = &g_master_de_ctx;
4117  SCMutexLock(&master->lock);
4118 
4119  if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
4120  SCLogInfo("error, no tenant selector");
4121  SCMutexUnlock(&master->lock);
4122  return -1;
4123  }
4124 
4125  DetectEngineCtx *stub_de_ctx = NULL;
4126  DetectEngineCtx *list = master->list;
4127  for ( ; list != NULL; list = list->next) {
4128  SCLogDebug("list %p tenant %u", list, list->tenant_id);
4129 
4130  if (list->type == DETECT_ENGINE_TYPE_NORMAL ||
4131  list->type == DETECT_ENGINE_TYPE_MT_STUB ||
4133  {
4134  stub_de_ctx = list;
4135  break;
4136  }
4137  }
4138  if (stub_de_ctx == NULL) {
4139  stub_de_ctx = DetectEngineCtxInitStubForMT();
4140  if (stub_de_ctx == NULL) {
4141  SCMutexUnlock(&master->lock);
4142  return -1;
4143  }
4144 
4145  if (master->list == NULL) {
4146  master->list = stub_de_ctx;
4147  } else {
4148  stub_de_ctx->next = master->list;
4149  master->list = stub_de_ctx;
4150  }
4151  }
4152 
4153  /* update the threads */
4154  SCLogDebug("MT reload starting");
4155  DetectEngineReloadThreads(stub_de_ctx);
4156  SCLogDebug("MT reload done");
4157 
4158  SCMutexUnlock(&master->lock);
4159 
4160  /* walk free list, freeing the old_de_ctx */
4162 
4163  SCLogDebug("old_de_ctx should have been freed");
4164  return 0;
4165 }
4166 
4167 static int g_parse_metadata = 0;
4168 
4170 {
4171  g_parse_metadata = 1;
4172 }
4173 
4175 {
4176  g_parse_metadata = 0;
4177 }
4178 
4180 {
4181  return g_parse_metadata;
4182 }
4183 
4185 {
4186  switch (type) {
4187  case DETECT_SM_LIST_MATCH:
4188  return "packet";
4189  case DETECT_SM_LIST_PMATCH:
4190  return "packet/stream payload";
4191 
4192  case DETECT_SM_LIST_TMATCH:
4193  return "tag";
4194 
4196  return "base64_data";
4197 
4199  return "post-match";
4200 
4202  return "suppress";
4204  return "threshold";
4205 
4206  case DETECT_SM_LIST_MAX:
4207  return "max (internal)";
4208  }
4209  return "error";
4210 }
4211 
4212 /* events api */
4214 {
4216  det_ctx->events++;
4217 }
4218 
4220 {
4221  return det_ctx->decoder_events;
4222 }
4223 
4224 int DetectEngineGetEventInfo(const char *event_name, int *event_id,
4225  AppLayerEventType *event_type)
4226 {
4227  *event_id = SCMapEnumNameToValue(event_name, det_ctx_event_table);
4228  if (*event_id == -1) {
4229  SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
4230  "det_ctx's enum map table.", event_name);
4231  /* this should be treated as fatal */
4232  return -1;
4233  }
4234  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
4235 
4236  return 0;
4237 }
4238 
4239 /*************************************Unittest*********************************/
4240 
4241 #ifdef UNITTESTS
4242 
4243 static int DetectEngineInitYamlConf(const char *conf)
4244 {
4246  ConfInit();
4247  return ConfYamlLoadString(conf, strlen(conf));
4248 }
4249 
4250 static void DetectEngineDeInitYamlConf(void)
4251 {
4252  ConfDeInit();
4254 
4255  return;
4256 }
4257 
4258 static int DetectEngineTest01(void)
4259 {
4260  const char *conf =
4261  "%YAML 1.1\n"
4262  "---\n"
4263  "detect-engine:\n"
4264  " - profile: medium\n"
4265  " - custom-values:\n"
4266  " toclient_src_groups: 2\n"
4267  " toclient_dst_groups: 2\n"
4268  " toclient_sp_groups: 2\n"
4269  " toclient_dp_groups: 3\n"
4270  " toserver_src_groups: 2\n"
4271  " toserver_dst_groups: 4\n"
4272  " toserver_sp_groups: 2\n"
4273  " toserver_dp_groups: 25\n"
4274  " - inspection-recursion-limit: 0\n";
4275 
4276  DetectEngineCtx *de_ctx = NULL;
4277  int result = 0;
4278 
4279  if (DetectEngineInitYamlConf(conf) == -1)
4280  return 0;
4282  if (de_ctx == NULL)
4283  goto end;
4284 
4285  result = (de_ctx->inspection_recursion_limit == -1);
4286 
4287  end:
4288  if (de_ctx != NULL)
4290 
4291  DetectEngineDeInitYamlConf();
4292 
4293  return result;
4294 }
4295 
4296 static int DetectEngineTest02(void)
4297 {
4298  const char *conf =
4299  "%YAML 1.1\n"
4300  "---\n"
4301  "detect-engine:\n"
4302  " - profile: medium\n"
4303  " - custom-values:\n"
4304  " toclient_src_groups: 2\n"
4305  " toclient_dst_groups: 2\n"
4306  " toclient_sp_groups: 2\n"
4307  " toclient_dp_groups: 3\n"
4308  " toserver_src_groups: 2\n"
4309  " toserver_dst_groups: 4\n"
4310  " toserver_sp_groups: 2\n"
4311  " toserver_dp_groups: 25\n"
4312  " - inspection-recursion-limit:\n";
4313 
4314  DetectEngineCtx *de_ctx = NULL;
4315  int result = 0;
4316 
4317  if (DetectEngineInitYamlConf(conf) == -1)
4318  return 0;
4320  if (de_ctx == NULL)
4321  goto end;
4322 
4324 
4325  end:
4326  if (de_ctx != NULL)
4328 
4329  DetectEngineDeInitYamlConf();
4330 
4331  return result;
4332 }
4333 
4334 static int DetectEngineTest03(void)
4335 {
4336  const char *conf =
4337  "%YAML 1.1\n"
4338  "---\n"
4339  "detect-engine:\n"
4340  " - profile: medium\n"
4341  " - custom-values:\n"
4342  " toclient_src_groups: 2\n"
4343  " toclient_dst_groups: 2\n"
4344  " toclient_sp_groups: 2\n"
4345  " toclient_dp_groups: 3\n"
4346  " toserver_src_groups: 2\n"
4347  " toserver_dst_groups: 4\n"
4348  " toserver_sp_groups: 2\n"
4349  " toserver_dp_groups: 25\n";
4350 
4351  DetectEngineCtx *de_ctx = NULL;
4352  int result = 0;
4353 
4354  if (DetectEngineInitYamlConf(conf) == -1)
4355  return 0;
4357  if (de_ctx == NULL)
4358  goto end;
4359 
4360  result = (de_ctx->inspection_recursion_limit ==
4362 
4363  end:
4364  if (de_ctx != NULL)
4366 
4367  DetectEngineDeInitYamlConf();
4368 
4369  return result;
4370 }
4371 
4372 static int DetectEngineTest04(void)
4373 {
4374  const char *conf =
4375  "%YAML 1.1\n"
4376  "---\n"
4377  "detect-engine:\n"
4378  " - profile: medium\n"
4379  " - custom-values:\n"
4380  " toclient_src_groups: 2\n"
4381  " toclient_dst_groups: 2\n"
4382  " toclient_sp_groups: 2\n"
4383  " toclient_dp_groups: 3\n"
4384  " toserver_src_groups: 2\n"
4385  " toserver_dst_groups: 4\n"
4386  " toserver_sp_groups: 2\n"
4387  " toserver_dp_groups: 25\n"
4388  " - inspection-recursion-limit: 10\n";
4389 
4390  DetectEngineCtx *de_ctx = NULL;
4391  int result = 0;
4392 
4393  if (DetectEngineInitYamlConf(conf) == -1)
4394  return 0;
4396  if (de_ctx == NULL)
4397  goto end;
4398 
4399  result = (de_ctx->inspection_recursion_limit == 10);
4400 
4401  end:
4402  if (de_ctx != NULL)
4404 
4405  DetectEngineDeInitYamlConf();
4406 
4407  return result;
4408 }
4409 
4410 static int DetectEngineTest08(void)
4411 {
4412  const char *conf =
4413  "%YAML 1.1\n"
4414  "---\n"
4415  "detect-engine:\n"
4416  " - profile: custom\n"
4417  " - custom-values:\n"
4418  " toclient-groups: 23\n"
4419  " toserver-groups: 27\n";
4420 
4421  DetectEngineCtx *de_ctx = NULL;
4422  int result = 0;
4423 
4424  if (DetectEngineInitYamlConf(conf) == -1)
4425  return 0;
4427  if (de_ctx == NULL)
4428  goto end;
4429 
4430  if (de_ctx->max_uniq_toclient_groups == 23 &&
4432  result = 1;
4433 
4434  end:
4435  if (de_ctx != NULL)
4437 
4438  DetectEngineDeInitYamlConf();
4439 
4440  return result;
4441 }
4442 
4443 /** \test bug 892 bad values */
4444 static int DetectEngineTest09(void)
4445 {
4446  const char *conf =
4447  "%YAML 1.1\n"
4448  "---\n"
4449  "detect-engine:\n"
4450  " - profile: custom\n"
4451  " - custom-values:\n"
4452  " toclient-groups: BA\n"
4453  " toserver-groups: BA\n"
4454  " - inspection-recursion-limit: 10\n";
4455 
4456  DetectEngineCtx *de_ctx = NULL;
4457  int result = 0;
4458 
4459  if (DetectEngineInitYamlConf(conf) == -1)
4460  return 0;
4462  if (de_ctx == NULL)
4463  goto end;
4464 
4465  if (de_ctx->max_uniq_toclient_groups == 20 &&
4467  result = 1;
4468 
4469  end:
4470  if (de_ctx != NULL)
4472 
4473  DetectEngineDeInitYamlConf();
4474 
4475  return result;
4476 }
4477 
4478 #endif
4479 
4481 {
4482 #ifdef UNITTESTS
4483  UtRegisterTest("DetectEngineTest01", DetectEngineTest01);
4484  UtRegisterTest("DetectEngineTest02", DetectEngineTest02);
4485  UtRegisterTest("DetectEngineTest03", DetectEngineTest03);
4486  UtRegisterTest("DetectEngineTest04", DetectEngineTest04);
4487  UtRegisterTest("DetectEngineTest08", DetectEngineTest08);
4488  UtRegisterTest("DetectEngineTest09", DetectEngineTest09);
4489 #endif
4490  return;
4491 }
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
DetectBufferType_::supports_transforms
bool supports_transforms
Definition: detect.h:424
DetectEngineSyncer_::m
SCMutex m
Definition: detect-engine.c:1481
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:2421
DetectEngineMTApply
int DetectEngineMTApply(void)
Definition: detect-engine.c:4114
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:292
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:3837
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:2177
SignatureInitData_::list_set
bool list_set
Definition: detect.h:493
RELOAD
@ RELOAD
Definition: detect-engine.c:1476
DetectLoaderThreadSpawn
void DetectLoaderThreadSpawn(void)
spawn the detect loader manager thread
Definition: detect-engine-loader.c:618
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
DetectEngineDeReference
void DetectEngineDeReference(DetectEngineCtx **de_ctx)
Definition: detect-engine.c:3880
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
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:4179
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:1546
SigTableElmt_::name
const char * name
Definition: detect.h:1200
Packet_::vlan_id
uint16_t vlan_id[2]
Definition: decode.h:443
DetectEngineMasterCtx_::list
DetectEngineCtx * list
Definition: detect.h:1427
DetectEngineCtxInitWithPrefix
DetectEngineCtx * DetectEngineCtxInitWithPrefix(const char *prefix)
Definition: detect-engine.c:2000
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:3971
DetectThreadCtxGetKeywordThreadCtx
void * DetectThreadCtxGetKeywordThreadCtx(DetectEngineThreadCtx *det_ctx, int id)
Retrieve thread local keyword ctx by id.
Definition: detect-engine.c:3070
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:3832
DetectEngineCtxInitStubForDD
DetectEngineCtx * DetectEngineCtxInitStubForDD(void)
Definition: detect-engine.c:1990
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
FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR
@ FILE_DECODER_EVENT_LZMA_OPTIONS_ERROR
Definition: detect.h:1221
IDLE
@ IDLE
Definition: detect-engine.c:1475
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
TmThreadsSetFlag
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition: tm-threads.c:97
DetectEngineCtx_::non_pf_store_cnt_max
uint32_t non_pf_store_cnt_max
Definition: detect.h:778
PacketEnqueue
void PacketEnqueue(PacketQueue *q, Packet *p)
Definition: packet-queue.c:173
DetectEngineGetByTenantId
DetectEngineCtx * DetectEngineGetByTenantId(int tenant_id)
Definition: detect-engine.c:3854
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
DetectEnginePktInspectionEngine::v1
struct DetectEnginePktInspectionEngine::@84 v1
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:372
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:1055
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:451
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:444
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:350
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:3419
FILE_DECODER_EVENT_LZMA_DATA_ERROR
@ FILE_DECODER_EVENT_LZMA_DATA_ERROR
Definition: detect.h:1223
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:1391
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:755
DetectEngineReloadSetIdle
void DetectEngineReloadSetIdle(void)
Definition: detect-engine.c:1514
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:506
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:3179
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:3904
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:3344
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:4213
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:2040
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
FILE_DECODER_EVENT_LZMA_BUF_ERROR
@ FILE_DECODER_EVENT_LZMA_BUF_ERROR
Definition: detect.h:1224
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:2194
DetectBufferType_
Definition: detect.h:417
m
SCMutex m
Definition: flow-hash.h:6
DetectEngineGetVersion
uint32_t DetectEngineGetVersion(void)
Definition: detect-engine.c:3160
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
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
MPM_AC_KS
@ MPM_AC_KS
Definition: util-mpm.h:37
MAX
#define MAX(x, y)
Definition: suricata-common.h:376
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
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
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
MPM_AC
@ MPM_AC
Definition: util-mpm.h:35
InspectionBufferGet
InspectionBuffer * InspectionBufferGet(DetectEngineThreadCtx *det_ctx, const int list_id)
Definition: detect-engine.c:1006
FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR
@ FILE_DECODER_EVENT_LZMA_MEMLIMIT_ERROR
Definition: detect.h:1220
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
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:3341
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
TVT_PPT
@ TVT_PPT
Definition: tm-threads-common.h:87
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:523
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:1170
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:3211
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
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
FILE_DECODER_EVENT_LZMA_FORMAT_ERROR
@ FILE_DECODER_EVENT_LZMA_FORMAT_ERROR
Definition: detect.h:1222
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:3920
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
ENGINE_PROFILE_HIGH
@ ENGINE_PROFILE_HIGH
Definition: detect.h:951
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
PKT_STREAM_ADD
#define PKT_STREAM_ADD
Definition: decode.h:1126
DetectUnregisterThreadCtxFuncs
int DetectUnregisterThreadCtxFuncs(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, void *data, const char *name)
Remove Thread keyword context registration.
Definition: detect-engine.c:3039
det_ctx_event_table
SCEnumCharMap det_ctx_event_table[]
Definition: detect-engine.c:105
DetectLoadersInit
void DetectLoadersInit(void)
Definition: detect-engine-loader.c:472
ThreadVars_::tm_slots
struct TmSlot_ * tm_slots
Definition: threadvars.h:96
SignatureInitData_::mpm_sm
SigMatch * mpm_sm
Definition: detect.h:487
ENGINE_PROFILE_MEDIUM
@ ENGINE_PROFILE_MEDIUM
Definition: detect.h:950
ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL
@ ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL
Definition: detect.h:958
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:1130
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
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
flow-worker.h
DetectEngineMasterCtx_::tenant_selector
enum DetectEngineTenantSelectors tenant_selector
Definition: detect.h:1434
FILE_DECODER_EVENT_INVALID_SWF_LENGTH
@ FILE_DECODER_EVENT_INVALID_SWF_LENGTH
Definition: detect.h:1213
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:491
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
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineEnabled
int DetectEngineEnabled(void)
Check if detection is enabled.
Definition: detect-engine.c:3146
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:1630
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:2744
DetectEngineReloadIsIdle
int DetectEngineReloadIsIdle(void)
Definition: detect-engine.c:1522
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:1158
DET_CTX_EVENT_TEST
@ DET_CTX_EVENT_TEST
Definition: detect.h:1210
SigMatchData_::type
uint8_t type
Definition: detect.h:330
ENGINE_PROFILE_UNKNOWN
@ ENGINE_PROFILE_UNKNOWN
Definition: detect.h:948
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
DetectEngineMasterCtx_::free_list
DetectEngineCtx * free_list
Definition: detect.h:1432
DetectEngineSyncState
DetectEngineSyncState
Definition: detect-engine.c:1474
ENGINE_PROFILE_CUSTOM
@ ENGINE_PROFILE_CUSTOM
Definition: detect.h:952
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:475
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
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:2970
tv_root_lock
SCMutex tv_root_lock
Definition: tm-threads.c:81
DetectEngineCtx_::profile_ctx
struct SCProfileDetectCtx_ * profile_ctx
Definition: detect.h:877
DetectEngineLoadTenantBlocking
int DetectEngineLoadTenantBlocking(uint32_t tenant_id, const char *yaml)
Load a tenant and wait for loading to complete.
Definition: detect-engine.c:3405
TmModuleDetectLoaderRegister
void TmModuleDetectLoaderRegister(void)
Definition: detect-engine-loader.c:643
Signature_::flags
uint32_t flags
Definition: detect.h:516
MPM_HS
@ MPM_HS
Definition: util-mpm.h:38
PACKET_ALERT_FLAG_DROP_FLOW
#define PACKET_ALERT_FLAG_DROP_FLOW
Definition: decode.h:288
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:1588
SC_ERR_FOPEN
@ SC_ERR_FOPEN
Definition: util-error.h:74
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:1995
RuleMatchCandidateTxArrayFree
void RuleMatchCandidateTxArrayFree(DetectEngineThreadCtx *det_ctx)
Definition: detect.c:976
Packet_
Definition: decode.h:416
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
DetectEngineAppInspectionEngine_::Callback
InspectEngineFuncPtr2 Callback
Definition: detect.h:407
SCProfilingRuleThreadCleanup
void SCProfilingRuleThreadCleanup(DetectEngineThreadCtx *det_ctx)
Definition: