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