1 /* Copyright (C) 2016 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 * Prefilter engine
24 *
25 * Prefilter engines have as purpose to check for a critical common part of
26 * a set of rules. If the condition is present in the traffic, the rules
27 * will have to be inspected individually. Otherwise, the rules can be
28 * skipped.
29 *
30 * The best example of this is the MPM. From each rule take a pattern and
31 * add it to the MPM state machine. Inspect that in one step and only
32 * individually inspect the rules that had a match in MPM.
33 *
34 * This prefilter API is designed to abstract this logic so that it becomes
35 * easier to add other types of prefilters.
36 *
37 * The prefilter engines are structured as a simple list of engines. Each
38 * engine checks for a condition using it's callback function and private
39 * data. It then adds the rule match candidates to the PrefilterRuleStore
40 * structure.
41 *
42 * After the engines have run the resulting list of match candidates is
43 * sorted by the rule id's so that the individual inspection happens in
44 * the correct order.
45 */
46
47 #include "suricata-common.h"
48 #include "suricata.h"
49
50 #include "detect-engine-prefilter.h"
51 #include "detect-engine-mpm.h"
52
53 #include "app-layer-parser.h"
54 #include "app-layer-htp.h"
55
56 #include "util-profiling.h"
57 #include "util-validate.h"
58
59 static int PrefilterStoreGetId(DetectEngineCtx *de_ctx,
60 const char *name, void (*FreeFunc)(void *));
61 static const PrefilterStore *PrefilterStoreGetStore(const DetectEngineCtx *de_ctx,
62 const uint32_t id);
63
QuickSortSigIntId(SigIntId * sids,uint32_t n)64 static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n)
65 {
66 if (n < 2)
67 return;
68 SigIntId p = sids[n / 2];
69 SigIntId *l = sids;
70 SigIntId *r = sids + n - 1;
71 while (l <= r) {
72 if (*l < p)
73 l++;
74 else if (*r > p)
75 r--;
76 else {
77 SigIntId t = *l;
78 *l = *r;
79 *r = t;
80 l++;
81 r--;
82 }
83 }
84 QuickSortSigIntId(sids, r - sids + 1);
85 QuickSortSigIntId(l, sids + n - l);
86 }
87
88 /**
89 * \brief run prefilter engines on a transaction
90 */
DetectRunPrefilterTx(DetectEngineThreadCtx * det_ctx,const SigGroupHead * sgh,Packet * p,const uint8_t ipproto,const uint8_t flow_flags,const AppProto alproto,void * alstate,DetectTransaction * tx)91 void DetectRunPrefilterTx(DetectEngineThreadCtx *det_ctx,
92 const SigGroupHead *sgh,
93 Packet *p,
94 const uint8_t ipproto,
95 const uint8_t flow_flags,
96 const AppProto alproto,
97 void *alstate,
98 DetectTransaction *tx)
99 {
100 /* reset rule store */
101 det_ctx->pmq.rule_id_array_cnt = 0;
102
103 SCLogDebug("packet %" PRIu64 " tx %p progress %d tx->prefilter_flags %" PRIx64, p->pcap_cnt,
104 tx->tx_ptr, tx->tx_progress, tx->prefilter_flags);
105
106 PrefilterEngine *engine = sgh->tx_engines;
107 do {
108 if (engine->alproto != alproto)
109 goto next;
110 if (engine->tx_min_progress > tx->tx_progress)
111 goto next;
112 if (tx->tx_progress > engine->tx_min_progress) {
113 if (tx->prefilter_flags & BIT_U64(engine->tx_min_progress)) {
114 goto next;
115 }
116 }
117
118 PREFILTER_PROFILING_START;
119 engine->cb.PrefilterTx(det_ctx, engine->pectx,
120 p, p->flow, tx->tx_ptr, tx->tx_id, flow_flags);
121 PREFILTER_PROFILING_END(det_ctx, engine->gid);
122
123 if (tx->tx_progress > engine->tx_min_progress && engine->is_last_for_progress) {
124 tx->prefilter_flags |= BIT_U64(engine->tx_min_progress);
125 }
126 next:
127 if (engine->is_last)
128 break;
129 engine++;
130 } while (1);
131
132 /* Sort the rule list to lets look at pmq.
133 * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */
134 if (likely(det_ctx->pmq.rule_id_array_cnt > 1)) {
135 PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT1);
136 QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt);
137 PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT1);
138 }
139 }
140
Prefilter(DetectEngineThreadCtx * det_ctx,const SigGroupHead * sgh,Packet * p,const uint8_t flags)141 void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh,
142 Packet *p, const uint8_t flags)
143 {
144 SCEnter();
145
146 if (sgh->pkt_engines) {
147 PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT);
148 /* run packet engines */
149 PrefilterEngine *engine = sgh->pkt_engines;
150 do {
151 PREFILTER_PROFILING_START;
152 engine->cb.Prefilter(det_ctx, p, engine->pectx);
153 PREFILTER_PROFILING_END(det_ctx, engine->gid);
154
155 if (engine->is_last)
156 break;
157 engine++;
158 } while (1);
159 PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT);
160 }
161
162 /* run payload inspecting engines */
163 if (sgh->payload_engines &&
164 (p->payload_len || (p->flags & PKT_DETECT_HAS_STREAMDATA)) &&
165 !(p->flags & PKT_NOPAYLOAD_INSPECTION))
166 {
167 PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD);
168 PrefilterEngine *engine = sgh->payload_engines;
169 while (1) {
170 PREFILTER_PROFILING_START;
171 engine->cb.Prefilter(det_ctx, p, engine->pectx);
172 PREFILTER_PROFILING_END(det_ctx, engine->gid);
173
174 if (engine->is_last)
175 break;
176 engine++;
177 }
178 PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD);
179 }
180
181 /* Sort the rule list to lets look at pmq.
182 * NOTE due to merging of 'stream' pmqs we *MAY* have duplicate entries */
183 if (likely(det_ctx->pmq.rule_id_array_cnt > 1)) {
184 PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_SORT1);
185 QuickSortSigIntId(det_ctx->pmq.rule_id_array, det_ctx->pmq.rule_id_array_cnt);
186 PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_SORT1);
187 }
188 SCReturn;
189 }
190
PrefilterAppendEngine(DetectEngineCtx * de_ctx,SigGroupHead * sgh,void (* PrefilterFunc)(DetectEngineThreadCtx * det_ctx,Packet * p,const void * pectx),void * pectx,void (* FreeFunc)(void * pectx),const char * name)191 int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
192 void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx),
193 void *pectx, void (*FreeFunc)(void *pectx),
194 const char *name)
195 {
196 if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL)
197 return -1;
198
199 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
200 if (e == NULL)
201 return -1;
202 memset(e, 0x00, sizeof(*e));
203
204 e->Prefilter = PrefilterFunc;
205 e->pectx = pectx;
206 e->Free = FreeFunc;
207
208 if (sgh->init->pkt_engines == NULL) {
209 sgh->init->pkt_engines = e;
210 } else {
211 PrefilterEngineList *t = sgh->init->pkt_engines;
212 while (t->next != NULL) {
213 t = t->next;
214 }
215
216 t->next = e;
217 e->id = t->id + 1;
218 }
219
220 e->name = name;
221 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
222 return 0;
223 }
224
PrefilterAppendPayloadEngine(DetectEngineCtx * de_ctx,SigGroupHead * sgh,void (* PrefilterFunc)(DetectEngineThreadCtx * det_ctx,Packet * p,const void * pectx),void * pectx,void (* FreeFunc)(void * pectx),const char * name)225 int PrefilterAppendPayloadEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
226 void (*PrefilterFunc)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx),
227 void *pectx, void (*FreeFunc)(void *pectx),
228 const char *name)
229 {
230 if (sgh == NULL || PrefilterFunc == NULL || pectx == NULL)
231 return -1;
232
233 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
234 if (e == NULL)
235 return -1;
236 memset(e, 0x00, sizeof(*e));
237
238 e->Prefilter = PrefilterFunc;
239 e->pectx = pectx;
240 e->Free = FreeFunc;
241
242 if (sgh->init->payload_engines == NULL) {
243 sgh->init->payload_engines = e;
244 } else {
245 PrefilterEngineList *t = sgh->init->payload_engines;
246 while (t->next != NULL) {
247 t = t->next;
248 }
249
250 t->next = e;
251 e->id = t->id + 1;
252 }
253
254 e->name = name;
255 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
256 return 0;
257 }
258
PrefilterAppendTxEngine(DetectEngineCtx * de_ctx,SigGroupHead * sgh,void (* PrefilterTxFunc)(DetectEngineThreadCtx * det_ctx,const void * pectx,Packet * p,Flow * f,void * tx,const uint64_t idx,const uint8_t flags),AppProto alproto,int tx_min_progress,void * pectx,void (* FreeFunc)(void * pectx),const char * name)259 int PrefilterAppendTxEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
260 void (*PrefilterTxFunc)(DetectEngineThreadCtx *det_ctx, const void *pectx,
261 Packet *p, Flow *f, void *tx,
262 const uint64_t idx, const uint8_t flags),
263 AppProto alproto, int tx_min_progress,
264 void *pectx, void (*FreeFunc)(void *pectx),
265 const char *name)
266 {
267 if (sgh == NULL || PrefilterTxFunc == NULL || pectx == NULL)
268 return -1;
269
270 PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
271 if (e == NULL)
272 return -1;
273 memset(e, 0x00, sizeof(*e));
274
275 e->PrefilterTx = PrefilterTxFunc;
276 e->pectx = pectx;
277 e->alproto = alproto;
278 e->tx_min_progress = tx_min_progress;
279 e->Free = FreeFunc;
280
281 if (sgh->init->tx_engines == NULL) {
282 sgh->init->tx_engines = e;
283 } else {
284 PrefilterEngineList *t = sgh->init->tx_engines;
285 while (t->next != NULL) {
286 t = t->next;
287 }
288
289 t->next = e;
290 e->id = t->id + 1;
291 }
292
293 e->name = name;
294 e->gid = PrefilterStoreGetId(de_ctx, e->name, e->Free);
295 return 0;
296 }
297
PrefilterFreeEngineList(PrefilterEngineList * e)298 static void PrefilterFreeEngineList(PrefilterEngineList *e)
299 {
300 if (e->Free && e->pectx) {
301 e->Free(e->pectx);
302 }
303 SCFreeAligned(e);
304 }
305
PrefilterFreeEnginesList(PrefilterEngineList * list)306 void PrefilterFreeEnginesList(PrefilterEngineList *list)
307 {
308 PrefilterEngineList *t = list;
309
310 while (t != NULL) {
311 PrefilterEngineList *next = t->next;
312 PrefilterFreeEngineList(t);
313 t = next;
314 }
315 }
316
PrefilterFreeEngines(const DetectEngineCtx * de_ctx,PrefilterEngine * list)317 static void PrefilterFreeEngines(const DetectEngineCtx *de_ctx, PrefilterEngine *list)
318 {
319 PrefilterEngine *t = list;
320
321 while (1) {
322 const PrefilterStore *s = PrefilterStoreGetStore(de_ctx, t->gid);
323 if (s && s->FreeFunc && t->pectx) {
324 s->FreeFunc(t->pectx);
325 }
326
327 if (t->is_last)
328 break;
329 t++;
330 }
331 SCFreeAligned(list);
332 }
333
PrefilterCleanupRuleGroup(const DetectEngineCtx * de_ctx,SigGroupHead * sgh)334 void PrefilterCleanupRuleGroup(const DetectEngineCtx *de_ctx, SigGroupHead *sgh)
335 {
336 if (sgh->pkt_engines) {
337 PrefilterFreeEngines(de_ctx, sgh->pkt_engines);
338 sgh->pkt_engines = NULL;
339 }
340 if (sgh->payload_engines) {
341 PrefilterFreeEngines(de_ctx, sgh->payload_engines);
342 sgh->payload_engines = NULL;
343 }
344 if (sgh->tx_engines) {
345 PrefilterFreeEngines(de_ctx, sgh->tx_engines);
346 sgh->tx_engines = NULL;
347 }
348 }
349
PrefilterSetupRuleGroupSortHelper(const void * a,const void * b)350 static int PrefilterSetupRuleGroupSortHelper(const void *a, const void *b)
351 {
352 const PrefilterEngine *s0 = a;
353 const PrefilterEngine *s1 = b;
354 if (s1->tx_min_progress == s0->tx_min_progress) {
355 if (s1->alproto == s0->alproto) {
356 return s0->local_id > s1->local_id ? 1 : -1;
357 } else {
358 return s0->alproto > s1->alproto ? 1 : -1;
359 }
360 } else {
361 return s0->tx_min_progress > s1->tx_min_progress ? 1 : -1;
362 }
363 }
364
PrefilterSetupRuleGroup(DetectEngineCtx * de_ctx,SigGroupHead * sgh)365 void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
366 {
367 int r = PatternMatchPrepareGroup(de_ctx, sgh);
368 if (r != 0) {
369 FatalError(SC_ERR_INITIALIZATION, "failed to set up pattern matching");
370 }
371
372 /* set up engines if needed - when prefilter is set to auto we run
373 * all engines, otherwise only those that have been forced by the
374 * prefilter keyword. */
375 const enum DetectEnginePrefilterSetting setting = de_ctx->prefilter_setting;
376 for (int i = 0; i < DETECT_TBLSIZE; i++)
377 {
378 if (sigmatch_table[i].SetupPrefilter != NULL &&
379 (setting == DETECT_PREFILTER_AUTO ||
380 de_ctx->sm_types_prefilter[i]))
381 {
382 sigmatch_table[i].SetupPrefilter(de_ctx, sgh);
383 }
384 }
385
386 /* we have lists of engines in sgh->init now. Lets setup the
387 * match arrays */
388 PrefilterEngineList *el;
389 if (sgh->init->pkt_engines != NULL) {
390 uint32_t cnt = 0;
391 for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) {
392 cnt++;
393 de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
394 }
395 sgh->pkt_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
396 if (sgh->pkt_engines == NULL) {
397 return;
398 }
399 memset(sgh->pkt_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
400
401 PrefilterEngine *e = sgh->pkt_engines;
402 for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) {
403 e->local_id = el->id;
404 e->cb.Prefilter = el->Prefilter;
405 e->pectx = el->pectx;
406 el->pectx = NULL; // e now owns the ctx
407 e->gid = el->gid;
408 if (el->next == NULL) {
409 e->is_last = TRUE;
410 }
411 e++;
412 }
413 }
414 if (sgh->init->payload_engines != NULL) {
415 uint32_t cnt = 0;
416 for (el = sgh->init->payload_engines ; el != NULL; el = el->next) {
417 cnt++;
418 de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
419 }
420 sgh->payload_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
421 if (sgh->payload_engines == NULL) {
422 return;
423 }
424 memset(sgh->payload_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
425
426 PrefilterEngine *e = sgh->payload_engines;
427 for (el = sgh->init->payload_engines ; el != NULL; el = el->next) {
428 e->local_id = el->id;
429 e->cb.Prefilter = el->Prefilter;
430 e->pectx = el->pectx;
431 el->pectx = NULL; // e now owns the ctx
432 e->gid = el->gid;
433 if (el->next == NULL) {
434 e->is_last = TRUE;
435 }
436 e++;
437 }
438 }
439 if (sgh->init->tx_engines != NULL) {
440 uint32_t cnt = 0;
441 for (el = sgh->init->tx_engines ; el != NULL; el = el->next) {
442 cnt++;
443 de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
444 }
445 sgh->tx_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
446 if (sgh->tx_engines == NULL) {
447 return;
448 }
449 memset(sgh->tx_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
450
451 uint32_t local_id = 0;
452 PrefilterEngine *e = sgh->tx_engines;
453 for (el = sgh->init->tx_engines ; el != NULL; el = el->next) {
454 e->local_id = local_id++;
455 e->alproto = el->alproto;
456 e->tx_min_progress = el->tx_min_progress;
457 e->cb.PrefilterTx = el->PrefilterTx;
458 e->pectx = el->pectx;
459 el->pectx = NULL; // e now owns the ctx
460 e->gid = el->gid;
461 e++;
462 }
463
464 /* sort by tx_min_progress, then alproto, then local_id */
465 qsort(sgh->tx_engines, local_id, sizeof(PrefilterEngine),
466 PrefilterSetupRuleGroupSortHelper);
467 sgh->tx_engines[local_id - 1].is_last = true;
468 sgh->tx_engines[local_id - 1].is_last_for_progress = true;
469
470 PrefilterEngine *engine;
471
472 /* per alproto to set is_last_for_progress per alproto because the inspect
473 * loop skips over engines that are not the correct alproto */
474 for (AppProto a = 1; a < ALPROTO_FAILED; a++) {
475 int last_tx_progress = 0;
476 bool last_tx_progress_set = false;
477 PrefilterEngine *prev_engine = NULL;
478 engine = sgh->tx_engines;
479 do {
480 BUG_ON(engine->tx_min_progress < last_tx_progress);
481 if (engine->alproto == a) {
482 if (last_tx_progress_set && engine->tx_min_progress > last_tx_progress) {
483 if (prev_engine) {
484 prev_engine->is_last_for_progress = true;
485 }
486 }
487
488 last_tx_progress_set = true;
489 prev_engine = engine;
490 } else {
491 if (prev_engine) {
492 prev_engine->is_last_for_progress = true;
493 }
494 }
495 last_tx_progress = engine->tx_min_progress;
496 if (engine->is_last)
497 break;
498 engine++;
499 } while (1);
500 }
501 #ifdef DEBUG
502 SCLogDebug("sgh %p", sgh);
503 engine = sgh->tx_engines;
504 do {
505 SCLogDebug("engine: gid %u alproto %s tx_min_progress %d is_last %s "
506 "is_last_for_progress %s",
507 engine->gid, AppProtoToString(engine->alproto), engine->tx_min_progress,
508 engine->is_last ? "true" : "false",
509 engine->is_last_for_progress ? "true" : "false");
510 if (engine->is_last)
511 break;
512 engine++;
513 } while (1);
514 #endif
515 }
516 }
517
518 /* hash table for assigning a unique id to each engine type. */
519
PrefilterStoreHashFunc(HashListTable * ht,void * data,uint16_t datalen)520 static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen)
521 {
522 PrefilterStore *ctx = data;
523
524 uint32_t hash = strlen(ctx->name);
525 uint16_t u;
526
527 for (u = 0; u < strlen(ctx->name); u++) {
528 hash += ctx->name[u];
529 }
530
531 hash %= ht->array_size;
532 return hash;
533 }
534
PrefilterStoreCompareFunc(void * data1,uint16_t len1,void * data2,uint16_t len2)535 static char PrefilterStoreCompareFunc(void *data1, uint16_t len1,
536 void *data2, uint16_t len2)
537 {
538 PrefilterStore *ctx1 = data1;
539 PrefilterStore *ctx2 = data2;
540 return (strcmp(ctx1->name, ctx2->name) == 0);
541 }
542
PrefilterStoreFreeFunc(void * ptr)543 static void PrefilterStoreFreeFunc(void *ptr)
544 {
545 SCFree(ptr);
546 }
547
PrefilterDeinit(DetectEngineCtx * de_ctx)548 void PrefilterDeinit(DetectEngineCtx *de_ctx)
549 {
550 if (de_ctx->prefilter_hash_table != NULL) {
551 HashListTableFree(de_ctx->prefilter_hash_table);
552 }
553 }
554
PrefilterInit(DetectEngineCtx * de_ctx)555 void PrefilterInit(DetectEngineCtx *de_ctx)
556 {
557 BUG_ON(de_ctx->prefilter_hash_table != NULL);
558
559 de_ctx->prefilter_hash_table = HashListTableInit(256,
560 PrefilterStoreHashFunc,
561 PrefilterStoreCompareFunc,
562 PrefilterStoreFreeFunc);
563 BUG_ON(de_ctx->prefilter_hash_table == NULL);
564 }
565
PrefilterStoreGetId(DetectEngineCtx * de_ctx,const char * name,void (* FreeFunc)(void *))566 static int PrefilterStoreGetId(DetectEngineCtx *de_ctx,
567 const char *name, void (*FreeFunc)(void *))
568 {
569 PrefilterStore ctx = { name, FreeFunc, 0 };
570
571 BUG_ON(de_ctx->prefilter_hash_table == NULL);
572
573 SCLogDebug("looking up %s", name);
574
575 PrefilterStore *rctx = HashListTableLookup(de_ctx->prefilter_hash_table, (void *)&ctx, 0);
576 if (rctx != NULL) {
577 return rctx->id;
578 }
579
580 PrefilterStore *actx = SCCalloc(1, sizeof(*actx));
581 if (actx == NULL) {
582 return -1;
583 }
584
585 actx->name = name;
586 actx->FreeFunc = FreeFunc;
587 actx->id = de_ctx->prefilter_id++;
588 SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id);
589
590 int ret = HashListTableAdd(de_ctx->prefilter_hash_table, actx, 0);
591 if (ret != 0) {
592 SCFree(actx);
593 return -1;
594 }
595
596 int r = actx->id;
597 return r;
598 }
599
600 /** \warning slow */
PrefilterStoreGetStore(const DetectEngineCtx * de_ctx,const uint32_t id)601 static const PrefilterStore *PrefilterStoreGetStore(const DetectEngineCtx *de_ctx,
602 const uint32_t id)
603 {
604
605 const PrefilterStore *store = NULL;
606 if (de_ctx->prefilter_hash_table != NULL) {
607 HashListTableBucket *hb = HashListTableGetListHead(de_ctx->prefilter_hash_table);
608 for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
609 PrefilterStore *ctx = HashListTableGetListData(hb);
610 if (ctx->id == id) {
611 store = ctx;
612 break;
613 }
614 }
615 }
616 return store;
617 }
618
619 #ifdef PROFILING
PrefilterStoreGetName(const uint32_t id)620 const char *PrefilterStoreGetName(const uint32_t id)
621 {
622 return NULL;
623 }
624 #endif
625
626 #include "util-print.h"
627
628 typedef struct PrefilterMpmCtx {
629 int list_id;
630 InspectionBufferGetDataPtr GetData;
631 const MpmCtx *mpm_ctx;
632 const DetectEngineTransforms *transforms;
633 } PrefilterMpmCtx;
634
635 /** \brief Generic Mpm prefilter callback
636 *
637 * \param det_ctx detection engine thread ctx
638 * \param p packet to inspect
639 * \param f flow to inspect
640 * \param txv tx to inspect
641 * \param pectx inspection context
642 */
PrefilterMpm(DetectEngineThreadCtx * det_ctx,const void * pectx,Packet * p,Flow * f,void * txv,const uint64_t idx,const uint8_t flags)643 static void PrefilterMpm(DetectEngineThreadCtx *det_ctx,
644 const void *pectx,
645 Packet *p, Flow *f, void *txv,
646 const uint64_t idx, const uint8_t flags)
647 {
648 SCEnter();
649
650 const PrefilterMpmCtx *ctx = (const PrefilterMpmCtx *)pectx;
651 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
652 SCLogDebug("running on list %d", ctx->list_id);
653
654 InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms,
655 f, flags, txv, ctx->list_id);
656 if (buffer == NULL)
657 return;
658
659 const uint32_t data_len = buffer->inspect_len;
660 const uint8_t *data = buffer->inspect;
661
662 SCLogDebug("mpm'ing buffer:");
663 //PrintRawDataFp(stdout, data, data_len);
664
665 if (data != NULL && data_len >= mpm_ctx->minlen) {
666 (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
667 &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
668 }
669 }
670
PrefilterGenericMpmFree(void * ptr)671 static void PrefilterGenericMpmFree(void *ptr)
672 {
673 SCFree(ptr);
674 }
675
PrefilterGenericMpmRegister(DetectEngineCtx * de_ctx,SigGroupHead * sgh,MpmCtx * mpm_ctx,const DetectBufferMpmRegistery * mpm_reg,int list_id)676 int PrefilterGenericMpmRegister(DetectEngineCtx *de_ctx,
677 SigGroupHead *sgh, MpmCtx *mpm_ctx,
678 const DetectBufferMpmRegistery *mpm_reg, int list_id)
679 {
680 SCEnter();
681 PrefilterMpmCtx *pectx = SCCalloc(1, sizeof(*pectx));
682 if (pectx == NULL)
683 return -1;
684 pectx->list_id = list_id;
685 pectx->GetData = mpm_reg->app_v2.GetData;
686 pectx->mpm_ctx = mpm_ctx;
687 pectx->transforms = &mpm_reg->transforms;
688
689 int r = PrefilterAppendTxEngine(de_ctx, sgh, PrefilterMpm,
690 mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress,
691 pectx, PrefilterGenericMpmFree, mpm_reg->pname);
692 if (r != 0) {
693 SCFree(pectx);
694 }
695 return r;
696 }
697
698 /* generic mpm for pkt engines */
699
700 typedef struct PrefilterMpmPktCtx {
701 int list_id;
702 InspectionBufferGetPktDataPtr GetData;
703 const MpmCtx *mpm_ctx;
704 const DetectEngineTransforms *transforms;
705 } PrefilterMpmPktCtx;
706
707 /** \brief Generic Mpm prefilter callback
708 *
709 * \param det_ctx detection engine thread ctx
710 * \param p packet to inspect
711 * \param f flow to inspect
712 * \param txv tx to inspect
713 * \param pectx inspection context
714 */
PrefilterMpmPkt(DetectEngineThreadCtx * det_ctx,Packet * p,const void * pectx)715 static void PrefilterMpmPkt(DetectEngineThreadCtx *det_ctx,
716 Packet *p, const void *pectx)
717 {
718 SCEnter();
719
720 const PrefilterMpmPktCtx *ctx = (const PrefilterMpmPktCtx *)pectx;
721 const MpmCtx *mpm_ctx = ctx->mpm_ctx;
722 SCLogDebug("running on list %d", ctx->list_id);
723
724 InspectionBuffer *buffer = ctx->GetData(det_ctx, ctx->transforms,
725 p, ctx->list_id);
726 if (buffer == NULL)
727 return;
728
729 const uint32_t data_len = buffer->inspect_len;
730 const uint8_t *data = buffer->inspect;
731
732 SCLogDebug("mpm'ing buffer:");
733 //PrintRawDataFp(stdout, data, data_len);
734
735 if (data != NULL && data_len >= mpm_ctx->minlen) {
736 (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
737 &det_ctx->mtcu, &det_ctx->pmq, data, data_len);
738 }
739 }
740
PrefilterMpmPktFree(void * ptr)741 static void PrefilterMpmPktFree(void *ptr)
742 {
743 SCFree(ptr);
744 }
745
PrefilterGenericMpmPktRegister(DetectEngineCtx * de_ctx,SigGroupHead * sgh,MpmCtx * mpm_ctx,const DetectBufferMpmRegistery * mpm_reg,int list_id)746 int PrefilterGenericMpmPktRegister(DetectEngineCtx *de_ctx,
747 SigGroupHead *sgh, MpmCtx *mpm_ctx,
748 const DetectBufferMpmRegistery *mpm_reg, int list_id)
749 {
750 SCEnter();
751 PrefilterMpmPktCtx *pectx = SCCalloc(1, sizeof(*pectx));
752 if (pectx == NULL)
753 return -1;
754 pectx->list_id = list_id;
755 pectx->GetData = mpm_reg->pkt_v1.GetData;
756 pectx->mpm_ctx = mpm_ctx;
757 pectx->transforms = &mpm_reg->transforms;
758
759 int r = PrefilterAppendEngine(de_ctx, sgh, PrefilterMpmPkt,
760 pectx, PrefilterMpmPktFree, mpm_reg->pname);
761 if (r != 0) {
762 SCFree(pectx);
763 }
764 return r;
765 }
766