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