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 
31 static uint32_t PrefilterPacketHeaderHashFunc(HashListTable *ht, void *data, uint16_t datalen)
32 {
33  PrefilterPacketHeaderCtx *ctx = data;
34  uint64_t hash = ctx->v1.u64 + ctx->type + ctx->value;
35  hash %= ht->array_size;
36  return hash;
37 }
38 
39 static 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 == ctx2->v1.u64 &&
45  ctx1->type == ctx2->type &&
46  ctx1->value == ctx2->value);
47 }
48 
49 static void PrefilterPacketHeaderFreeFunc(void *ptr)
50 {
51  SCFree(ptr);
52 }
53 
54 static void PrefilterPacketHeaderFree(void *pectx)
55 {
56  PrefilterPacketHeaderCtx *ctx = pectx;
57  SCFree(ctx->sigs_array);
58  SCFree(ctx);
59 }
60 
61 static void PrefilterPacketU8HashCtxFree(void *vctx)
62 {
63  PrefilterPacketU8HashCtx *ctx = vctx;
64  int i;
65  for (i = 0; i < 256; i++) {
66  SigsArray *sa = ctx->array[i];
67  if (sa == NULL)
68  continue;
69  SCFree(sa->sigs);
70  SCFree(sa);
71  }
72  SCFree(ctx);
73 }
74 
75 static void GetExtraMatch(const Signature *s, uint16_t *type, uint16_t *value)
76 {
77  if (s->sp != NULL && s->sp->next == NULL && s->sp->port == s->sp->port2 &&
78  !(s->sp->flags & PORT_FLAG_NOT))
79  {
81  *value = s->sp->port;
82  } else if (s->alproto != ALPROTO_UNKNOWN) {
84  *value = s->alproto;
85  } else if (s->dp != NULL && s->dp->next == NULL && s->dp->port == s->dp->port2 &&
86  !(s->dp->flags & PORT_FLAG_NOT))
87  {
89  *value = s->dp->port;
90  }
91 }
92 
93 /** \internal
94  */
95 static int
96 SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
97  int sm_type, PrefilterPacketHeaderHashCtx *hctx,
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->sig_cnt; sig++) {
121  s = sgh->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->num;
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  PrefilterAppendEngine(de_ctx, sgh, Match, ctx,
146  PrefilterPacketHeaderFree, sigmatch_table[sm_type].name);
147  return 0;
148 }
149 
150 /** \internal
151  * \brief apply signature to each value */
152 static void ApplyToU8Hash(PrefilterPacketU8HashCtx *ctx, PrefilterPacketHeaderValue v, Signature *s)
153 {
154  switch (v.u8[0]) {
156  {
157  SigsArray *sa = ctx->array[v.u8[1]];
158  sa->sigs[sa->offset++] = s->num;
159  break;
160  }
162  {
163  uint8_t x = v.u8[1] - 1;
164  do {
165  SigsArray *sa = ctx->array[x];
166  sa->sigs[sa->offset++] = s->num;
167  } while (x--);
168 
169  break;
170  }
172  {
173  int x = v.u8[1] + 1;
174  do {
175  SigsArray *sa = ctx->array[x];
176  sa->sigs[sa->offset++] = s->num;
177  } while (++x < 256);
178 
179  break;
180  }
182  {
183  int x = v.u8[1] + 1;
184  do {
185  SigsArray *sa = ctx->array[x];
186  sa->sigs[sa->offset++] = s->num;
187  } while (++x < v.u8[2]);
188 
189  break;
190  }
191  }
192 }
193 
194 /** \internal
195  * \brief turn values into a u8 hash map
196  * \todo improve error handling
197  * \todo deduplicate sigs arrays
198  */
199 static int
200 SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx,
201  SigGroupHead *sgh, int sm_type, 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 i;
215  for (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  }
225 
226  for (sig = 0; sig < sgh->sig_cnt; sig++) {
227  s = sgh->match_array[sig];
228  if (s == NULL)
229  continue;
230  if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
231  continue;
232 
234  memset(&v, 0, sizeof(v));
235  Set(&v, s->init_data->prefilter_sm->ctx);
236 
237  ApplyToU8Hash(ctx, v, s);
239  cnt++;
240  }
241 
242  if (cnt) {
243  PrefilterAppendEngine(de_ctx, sgh, Match, ctx,
244  PrefilterPacketU8HashCtxFree,
245  sigmatch_table[sm_type].name);
246  } else {
247  PrefilterPacketU8HashCtxFree(ctx);
248  }
249  return 0;
250 }
251 
252 /** \internal
253  * \brief setup a engine for each unique value
254  */
255 static void SetupSingle(DetectEngineCtx *de_ctx, HashListTable *hash_table,
256  SigGroupHead *sgh, int sm_type,
257  _Bool (*Compare)(PrefilterPacketHeaderValue v, void *),
258  void (*Match)(DetectEngineThreadCtx *det_ctx,
259  Packet *p, const void *pectx))
260 {
262  for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
264 
265  SetupEngineForPacketHeader(de_ctx, sgh, sm_type,
266  ctx, Compare, Match);
267  }
268 }
269 
270 /** \internal
271  * \brief setup a single engine with a hash map for u8 values
272  */
273 static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table,
274  SigGroupHead *sgh, int sm_type,
275  void (*Set)(PrefilterPacketHeaderValue *v, void *),
276  _Bool (*Compare)(PrefilterPacketHeaderValue v, void *),
277  void (*Match)(DetectEngineThreadCtx *det_ctx,
278  Packet *p, const void *pectx))
279 {
280  uint32_t counts[256];
281  memset(&counts, 0, sizeof(counts));
282 
284  for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
286 
287  switch (ctx->v1.u8[0]) {
289  counts[ctx->v1.u8[1]] += ctx->cnt;
290  break;
292  {
293  uint8_t v = ctx->v1.u8[1] - 1;
294  do {
295  counts[v] += ctx->cnt;
296  } while (v--);
297 
298  break;
299  }
301  {
302  int v = ctx->v1.u8[1] + 1;
303  do {
304  counts[v] += ctx->cnt;
305  } while (++v < 256);
306 
307  break;
308  }
310  {
311  int v = ctx->v1.u8[1] + 1;
312  do {
313  counts[v] += ctx->cnt;
314  } while (++v < ctx->v1.u8[2]);
315 
316  break;
317  }
318  }
319  }
320 
321  SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(de_ctx, sgh, sm_type,
322  counts, Set, Compare, Match);
323 }
324 
325 static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx,
326  SigGroupHead *sgh, int sm_type,
327  void (*Set)(PrefilterPacketHeaderValue *v, void *),
328  _Bool (*Compare)(PrefilterPacketHeaderValue v, void *),
329  void (*Match)(DetectEngineThreadCtx *det_ctx,
330  Packet *p, const void *pectx),
331  _Bool u8hash)
332 {
333  Signature *s = NULL;
334  uint32_t sig = 0;
335 
336  if (sgh == NULL)
337  return 0;
338 
339  /* first count how many engines we will need */
340 
341  HashListTable *hash_table = HashListTableInit(4096,
342  PrefilterPacketHeaderHashFunc,
343  PrefilterPacketHeaderCompareFunc,
344  PrefilterPacketHeaderFreeFunc);
345  if (hash_table == NULL)
346  return -1;
347 
348  for (sig = 0; sig < sgh->sig_cnt; sig++) {
349  s = sgh->match_array[sig];
350  if (s == NULL)
351  continue;
352  if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
353  continue;
354 
356  memset(&ctx, 0, sizeof(ctx));
357  Set(&ctx.v1, s->init_data->prefilter_sm->ctx);
358 
359  GetExtraMatch(s, &ctx.type, &ctx.value);
360 
361  PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0);
362  if (rctx != 0) {
363  rctx->cnt++;
364  } else {
365  PrefilterPacketHeaderHashCtx *actx = SCCalloc(1, sizeof(*actx));
366  if (actx == NULL)
367  goto error;
368 
369  Set(&actx->v1, s->init_data->prefilter_sm->ctx);
370  actx->cnt = 1;
371  actx->type = ctx.type;
372  actx->value = ctx.value;
373 
374  int ret = HashListTableAdd(hash_table, actx, 0);
375  if (ret != 0) {
376  SCFree(actx);
377  goto error;
378  }
379  }
380  }
381 
382  if (u8hash == FALSE) {
383  SetupSingle(de_ctx, hash_table, sgh, sm_type, Compare, Match);
384  } else {
385  SetupU8Hash(de_ctx, hash_table, sgh, sm_type, Set, Compare, Match);
386  }
387 
388  HashListTableFree(hash_table);
389  return 0;
390 error:
391  HashListTableFree(hash_table);
392  return -1;
393 }
394 
396  SigGroupHead *sgh, int sm_type,
397  void (*Set)(PrefilterPacketHeaderValue *v, void *),
398  _Bool (*Compare)(PrefilterPacketHeaderValue v, void *),
399  void (*Match)(DetectEngineThreadCtx *det_ctx,
400  Packet *p, const void *pectx))
401 {
402  return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type,
403  Set, Compare, Match, TRUE);
404 }
405 
407  SigGroupHead *sgh, int sm_type,
408  void (*Set)(PrefilterPacketHeaderValue *v, void *),
409  _Bool (*Compare)(PrefilterPacketHeaderValue v, void *),
410  void (*Match)(DetectEngineThreadCtx *det_ctx,
411  Packet *p, const void *pectx))
412 {
413  return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type,
414  Set, Compare, Match, FALSE);
415 }
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect.h:1403
SigIntId sig_cnt
Definition: detect.h:1300
SignatureInitData * init_data
Definition: detect.h:560
#define SCLogDebug(...)
Definition: util-debug.h:335
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
#define SIG_FLAG_PREFILTER
Definition: detect.h:250
int PrefilterSetupPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void(*Set)(PrefilterPacketHeaderValue *v, void *), _Bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
SigMatch * prefilter_sm
Definition: detect.h:465
#define BUG_ON(x)
uint32_t flags
Definition: detect.h:493
uint32_t id
Definition: detect.h:525
#define FALSE
Signature ** match_array
Definition: detect.h:1320
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
#define PREFILTER_U8HASH_MODE_GT
Container for matching data for a signature group.
Definition: detect.h:1295
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Signature container.
Definition: detect.h:492
#define TRUE
SigIntId num
Definition: detect.h:502
main detection engine ctx
Definition: detect.h:720
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
#define PREFILTER_EXTRA_MATCH_ALPROTO
#define SCCalloc(nm, a)
Definition: util-mem.h:205
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
DetectPort * dp
Definition: detect.h:531
int PrefilterSetupPacketHeaderU8Hash(DetectEngineCtx *de_ctx, SigGroupHead *sgh, int sm_type, void(*Set)(PrefilterPacketHeaderValue *v, void *), _Bool(*Compare)(PrefilterPacketHeaderValue v, void *), void(*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
struct PrefilterPacketHeaderHashCtx_ PrefilterPacketHeaderHashCtx
AppProto alproto
Definition: detect.h:496
HashListTable * HashListTableInit(uint32_t size, uint32_t(*Hash)(struct HashListTable_ *, void *, uint16_t), char(*Compare)(void *, uint16_t, void *, uint16_t), void(*Free)(void *))
Definition: util-hashlist.c:35
#define PORT_FLAG_NOT
Definition: detect.h:194
uint8_t type
Definition: detect.h:325
#define PREFILTER_U8HASH_MODE_RA
#define PREFILTER_U8HASH_MODE_LT
SigMatchCtx * ctx
Definition: detect.h:327
uint8_t flags
Definition: detect.h:202
#define SCFree(a)
Definition: util-mem.h:236
DetectPort * sp
Definition: detect.h:531
uint16_t port
Definition: detect.h:199
#define PREFILTER_EXTRA_MATCH_DSTPORT
struct DetectPort_ * next
Definition: detect.h:212
uint32_t array_size
Definition: util-hashlist.h:41
#define PREFILTER_EXTRA_MATCH_SRCPORT
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
int 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)
uint16_t port2
Definition: detect.h:200
#define PREFILTER_U8HASH_MODE_EQ
#define SigIntId