suricata
detect-engine-prefilter-common.c
Go to the documentation of this file.
1/* Copyright (C) 2007-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#include "suricata-common.h"
21
24
25 uint16_t type; /**< PREFILTER_EXTRA_MATCH_* */
26 uint16_t value;
27
28 uint32_t cnt;
30
31static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen)
32{
34 uint64_t hash = ctx->v1.u64[0] + ctx->v1.u64[1] + ctx->type + ctx->value;
35 hash %= ht->array_size;
36 return (uint32_t)hash;
37}
38
39static char PrefilterPacketHeaderCompareFunc(void *data1, uint16_t len1,
40 void *data2, uint16_t len2)
41{
42 PrefilterPacketHeaderHashCtx *ctx1 = data1;
43 PrefilterPacketHeaderHashCtx *ctx2 = data2;
44 return (ctx1->v1.u64[0] == ctx2->v1.u64[0] &&
45 ctx1->v1.u64[1] == ctx2->v1.u64[1] &&
46 ctx1->type == ctx2->type &&
47 ctx1->value == ctx2->value);
48}
49
50static void PrefilterPacketHeaderFreeFunc(void *ptr)
51{
52 SCFree(ptr);
53}
54
55static void PrefilterPacketHeaderFree(void *pectx)
56{
58 SCFree(ctx->sigs_array);
59 SCFree(ctx);
60}
61
62static void PrefilterPacketU8HashCtxFree(void *vctx)
63{
65 int i;
66 for (i = 0; i < 256; i++) {
67 SigsArray *sa = ctx->array[i];
68 if (sa == NULL)
69 continue;
70 SCFree(sa->sigs);
71 SCFree(sa);
72 }
73 SCFree(ctx);
74}
75
76static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value)
77{
78 if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 &&
79 !(s->sp->flags & PORT_FLAG_NOT))
80 {
82 *value = s->sp->port;
83 } else if (s->alproto != ALPROTO_UNKNOWN) {
85 *value = s->alproto;
86 } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 &&
87 !(s->dp->flags & PORT_FLAG_NOT))
88 {
90 *value = s->dp->port;
91 }
92}
93
94/** \internal
95 */
96static int SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type,
98 bool (*Compare)(PrefilterPacketHeaderValue v, void *),
99 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
100{
101 Signature *s = NULL;
102 uint32_t sig = 0;
103 uint32_t sig_offset = 0;
104
106 if (ctx == NULL)
107 return -1;
108
109 ctx->v1 = hctx->v1;
110 ctx->type = hctx->type;
111 ctx->value = hctx->value;
112
113 ctx->sigs_cnt = hctx->cnt;
114 ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId));
115 if (ctx->sigs_array == NULL) {
116 SCFree(ctx);
117 return -1;
118 }
119
120 for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
121 s = sgh->init->match_array[sig];
122 if (s == NULL)
123 continue;
124 if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
125 continue;
126
127 uint16_t type = 0;
128 uint16_t value = 0;
129 GetExtraMatch(s, &type, &value);
130
131 if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) &&
132 ctx->type == type && ctx->value == value)
133 {
134 SCLogDebug("appending sid %u on %u", s->id, sig_offset);
135 ctx->sigs_array[sig_offset] = s->iid;
136 sig_offset++;
137
139 }
140 }
141
142 SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u",
143 sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value,
144 ctx->sigs_cnt);
145 enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
146 PrefilterAppendEngine(de_ctx, sgh, Match, mask, hook, ctx, PrefilterPacketHeaderFree,
147 sigmatch_table[sm_type].name);
148 return 0;
149}
150
151/** \internal
152 * \brief apply signature to each value */
153static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s)
154{
155 switch (v.u8[0]) {
157 {
158 SigsArray *sa = ctx->array[v.u8[1]];
159 sa->sigs[sa->offset++] = s->iid;
160 break;
161 }
163 {
164 uint8_t x = v.u8[1] - 1;
165 do {
166 SigsArray *sa = ctx->array[x];
167 sa->sigs[sa->offset++] = s->iid;
168 } while (x--);
169
170 break;
171 }
173 {
174 int x = v.u8[1] + 1;
175 do {
176 SigsArray *sa = ctx->array[x];
177 sa->sigs[sa->offset++] = s->iid;
178 } while (++x < 256);
179
180 break;
181 }
183 {
184 int x = v.u8[1] + 1;
185 do {
186 SigsArray *sa = ctx->array[x];
187 sa->sigs[sa->offset++] = s->iid;
188 } while (++x < v.u8[2]);
189
190 break;
191 }
192 }
193}
194
195/** \internal
196 * \brief turn values into a u8 hash map
197 * \todo improve error handling
198 * \todo deduplicate sigs arrays
199 */
200static int SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx,
201 SigGroupHead *sgh, int sm_type, SignatureMask mask, uint32_t *counts,
202 void (*Set)(PrefilterPacketHeaderValue *v, void *),
203 bool (*Compare)(PrefilterPacketHeaderValue v, void *),
204 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
205{
206 Signature *s = NULL;
207 uint32_t sig = 0;
208 uint32_t cnt = 0;
209
211 if (ctx == NULL)
212 return -1;
213
214 int set_cnt = 0;
215 for (int i = 0; i < 256; i++) {
216 if (counts[i] == 0)
217 continue;
218 ctx->array[i] = SCCalloc(1, sizeof(SigsArray));
219 BUG_ON(ctx->array[i] == NULL);
220
221 ctx->array[i]->cnt = counts[i];
222 ctx->array[i]->sigs = SCCalloc(ctx->array[i]->cnt, sizeof(SigIntId));
223 BUG_ON(ctx->array[i]->sigs == NULL);
224 set_cnt++;
225 }
226 if (set_cnt == 0) {
227 /* not an error */
228 PrefilterPacketU8HashCtxFree(ctx);
229 return 0;
230 }
231
232 for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
233 s = sgh->init->match_array[sig];
234 if (s == NULL)
235 continue;
236 if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
237 continue;
238
240 memset(&v, 0, sizeof(v));
241 Set(&v, s->init_data->prefilter_sm->ctx);
242
243 ApplyToU8Hash(ctx, v, s);
245 cnt++;
246 }
247
248 if (cnt) {
249 enum SignatureHookPkt hook = SIGNATURE_HOOK_PKT_NOT_SET; // TODO review
250 PrefilterAppendEngine(de_ctx, sgh, Match, mask, hook, ctx, PrefilterPacketU8HashCtxFree,
251 sigmatch_table[sm_type].name);
252 } else {
253 PrefilterPacketU8HashCtxFree(ctx);
254 }
255 return 0;
256}
257
258/** \internal
259 * \brief setup a engine for each unique value
260 */
261static void SetupSingle(DetectEngineCtx *de_ctx, HashListTable *hash_table, SigGroupHead *sgh,
262 int sm_type, SignatureMask mask, bool (*Compare)(PrefilterPacketHeaderValue v, void *),
263 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
264{
266 for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
268
269 SetupEngineForPacketHeader(de_ctx, sgh, sm_type, mask, ctx, Compare, Match);
270 }
271}
272
273/** \internal
274 * \brief setup a single engine with a hash map for u8 values
275 */
276static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table, SigGroupHead *sgh,
277 int sm_type, SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
278 bool (*Compare)(PrefilterPacketHeaderValue v, void *),
279 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
280{
281 uint32_t counts[256];
282 memset(&counts, 0, sizeof(counts));
283
285 for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
287
288 switch (ctx->v1.u8[0]) {
290 counts[ctx->v1.u8[1]] += ctx->cnt;
291 break;
293 {
294 uint8_t v = ctx->v1.u8[1];
295 while (v > 0) {
296 v--;
297 counts[v] += ctx->cnt;
298 }
299
300 break;
301 }
303 {
304 uint8_t v = ctx->v1.u8[1];
305 while (v < UINT8_MAX) {
306 v++;
307 counts[v] += ctx->cnt;
308 }
309
310 break;
311 }
313 {
314 if (ctx->v1.u8[1] < ctx->v1.u8[2]) {
315 // ctx->v1.u8[1] is not UINT8_MAX
316 uint8_t v = ctx->v1.u8[1] + 1;
317 while (v < ctx->v1.u8[2]) {
318 counts[v] += ctx->cnt;
319 v++;
320 }
321 }
322 break;
323 }
324 }
325 }
326
327 SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(
328 de_ctx, sgh, sm_type, mask, counts, Set, Compare, Match);
329}
330
331static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type,
332 SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
333 bool (*Compare)(PrefilterPacketHeaderValue v, void *),
334 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx), bool u8hash)
335{
336 Signature *s = NULL;
337 uint32_t sig = 0;
338
339 if (sgh == NULL)
340 return 0;
341
342 /* first count how many engines we will need */
343
344 HashListTable *hash_table = HashListTableInit(4096,
345 PrefilterPacketHeaderHashFunc,
346 PrefilterPacketHeaderCompareFunc,
347 PrefilterPacketHeaderFreeFunc);
348 if (hash_table == NULL)
349 return -1;
350
351 for (sig = 0; sig < sgh->init->sig_cnt; sig++) {
352 s = sgh->init->match_array[sig];
353 if (s == NULL)
354 continue;
355 if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
356 continue;
357
359 memset(&ctx, 0, sizeof(ctx));
360 Set(&ctx.v1, s->init_data->prefilter_sm->ctx);
361
362 GetExtraMatch(s, &ctx.type, &ctx.value);
363
364 PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0);
365 if (rctx != 0) {
366 rctx->cnt++;
367 } else {
368 PrefilterPacketHeaderHashCtx *actx = SCCalloc(1, sizeof(*actx));
369 if (actx == NULL)
370 goto error;
371
372 Set(&actx->v1, s->init_data->prefilter_sm->ctx);
373 actx->cnt = 1;
374 actx->type = ctx.type;
375 actx->value = ctx.value;
376
377 int ret = HashListTableAdd(hash_table, actx, 0);
378 if (ret != 0) {
379 SCFree(actx);
380 goto error;
381 }
382 }
383 }
384
385 if (!u8hash) {
386 SetupSingle(de_ctx, hash_table, sgh, sm_type, mask, Compare, Match);
387 } else {
388 SetupU8Hash(de_ctx, hash_table, sgh, sm_type, mask, Set, Compare, Match);
389 }
390
391 HashListTableFree(hash_table);
392 return 0;
393error:
394 HashListTableFree(hash_table);
395 return -1;
396}
397
399 SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
400 bool (*Compare)(PrefilterPacketHeaderValue v, void *),
401 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
402{
403 return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, mask, Set, Compare, Match, true);
404}
405
407 SignatureMask mask, void (*Set)(PrefilterPacketHeaderValue *v, void *),
408 bool (*Compare)(PrefilterPacketHeaderValue v, void *),
409 void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
410{
411 return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type, mask, Set, Compare, Match, false);
412}
@ ALPROTO_UNKNOWN
uint16_t type
#define SignatureMask
Definition decode.h:99
int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, SignatureMask mask, void(*Set)(PrefilterPacketHeaderValue *v, void *), bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
struct PrefilterPacketHeaderHashCtx_ PrefilterPacketHeaderHashCtx
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, SignatureMask mask, void(*Set)(PrefilterPacketHeaderValue *v, void *), bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
#define PREFILTER_EXTRA_MATCH_DSTPORT
#define PREFILTER_EXTRA_MATCH_SRCPORT
#define PREFILTER_EXTRA_MATCH_ALPROTO
#define PREFILTER_U8HASH_MODE_RA
#define PREFILTER_U8HASH_MODE_GT
#define PREFILTER_U8HASH_MODE_EQ
#define PREFILTER_U8HASH_MODE_LT
int PrefilterAppendEngine(DetectEngineCtx *de_ctx, SigGroupHead *sgh, PrefilterPktFn PrefilterFunc, SignatureMask mask, enum SignatureHookPkt hook, void *pectx, void(*FreeFunc)(void *pectx), const char *name)
SigTableElmt * sigmatch_table
SignatureHookPkt
Definition detect.h:538
@ SIGNATURE_HOOK_PKT_NOT_SET
Definition detect.h:539
#define PORT_FLAG_NOT
Definition detect.h:216
#define SIG_FLAG_PREFILTER
Definition detect.h:278
DetectEngineCtx * de_ctx
struct Thresholds ctx
main detection engine ctx
Definition detect.h:932
uint16_t port
Definition detect.h:221
uint16_t port2
Definition detect.h:222
struct DetectPort_ * next
Definition detect.h:234
uint8_t flags
Definition detect.h:224
uint32_t array_size
Signature ** match_array
Definition detect.h:1625
Container for matching data for a signature group.
Definition detect.h:1629
SigGroupHeadInitData * init
Definition detect.h:1646
uint16_t type
Definition detect.h:357
SigMatchCtx * ctx
Definition detect.h:359
SigMatch * prefilter_sm
Definition detect.h:625
Signature container.
Definition detect.h:668
DetectPort * sp
Definition detect.h:719
uint32_t flags
Definition detect.h:669
SignatureInitData * init_data
Definition detect.h:747
SigIntId iid
Definition detect.h:680
AppProto alproto
Definition detect.h:673
DetectPort * dp
Definition detect.h:719
uint32_t id
Definition detect.h:713
#define BUG_ON(x)
#define SigIntId
const char * name
uint32_t cnt
#define SCLogDebug(...)
Definition util-debug.h:275
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
void HashListTableFree(HashListTable *ht)
#define HashListTableGetListData(hb)
#define HashListTableGetListNext(hb)
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53