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