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[0] + ctx->v1.u64[1] + 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[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 
50 static void PrefilterPacketHeaderFreeFunc(void *ptr)
51 {
52  SCFree(ptr);
53 }
54 
55 static void PrefilterPacketHeaderFree(void *pectx)
56 {
57  PrefilterPacketHeaderCtx *ctx = pectx;
58  SCFree(ctx->sigs_array);
59  SCFree(ctx);
60 }
61 
62 static void PrefilterPacketU8HashCtxFree(void *vctx)
63 {
64  PrefilterPacketU8HashCtx *ctx = vctx;
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 
76 static 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  */
96 static int
97 SetupEngineForPacketHeader(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
98  int sm_type, PrefilterPacketHeaderHashCtx *hctx,
99  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
100  void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
101 {
102  Signature *s = NULL;
103  uint32_t sig = 0;
104  uint32_t sig_offset = 0;
105 
107  if (ctx == NULL)
108  return -1;
109 
110  ctx->v1 = hctx->v1;
111  ctx->type = hctx->type;
112  ctx->value = hctx->value;
113 
114  ctx->sigs_cnt = hctx->cnt;
115  ctx->sigs_array = SCCalloc(ctx->sigs_cnt, sizeof(SigIntId));
116  if (ctx->sigs_array == NULL) {
117  SCFree(ctx);
118  return -1;
119  }
120 
121  for (sig = 0; sig < sgh->sig_cnt; sig++) {
122  s = sgh->match_array[sig];
123  if (s == NULL)
124  continue;
125  if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
126  continue;
127 
128  uint16_t type = 0;
129  uint16_t value = 0;
130  GetExtraMatch(s, &type, &value);
131 
132  if (Compare(ctx->v1, s->init_data->prefilter_sm->ctx) &&
133  ctx->type == type && ctx->value == value)
134  {
135  SCLogDebug("appending sid %u on %u", s->id, sig_offset);
136  ctx->sigs_array[sig_offset] = s->num;
137  sig_offset++;
138 
140  }
141  }
142 
143  SCLogDebug("%s: ctx %p extra type %u extra value %u, sig cnt %u",
144  sigmatch_table[sm_type].name, ctx, ctx->type, ctx->value,
145  ctx->sigs_cnt);
146  PrefilterAppendEngine(de_ctx, sgh, Match, ctx,
147  PrefilterPacketHeaderFree, sigmatch_table[sm_type].name);
148  return 0;
149 }
150 
151 /** \internal
152  * \brief apply signature to each value */
153 static 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->num;
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->num;
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->num;
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->num;
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  */
200 static int
201 SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(DetectEngineCtx *de_ctx,
202  SigGroupHead *sgh, int sm_type, uint32_t *counts,
203  void (*Set)(PrefilterPacketHeaderValue *v, void *),
204  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
205  void (*Match)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx))
206 {
207  Signature *s = NULL;
208  uint32_t sig = 0;
209  uint32_t cnt = 0;
210 
212  if (ctx == NULL)
213  return -1;
214 
215  int i;
216  for (i = 0; i < 256; i++) {
217  if (counts[i] == 0)
218  continue;
219  ctx->array[i] = SCCalloc(1, sizeof(SigsArray));
220  BUG_ON(ctx->array[i] == NULL);
221 
222  ctx->array[i]->cnt = counts[i];
223  ctx->array[i]->sigs = SCCalloc(ctx->array[i]->cnt, sizeof(SigIntId));
224  BUG_ON(ctx->array[i]->sigs == NULL);
225  }
226 
227  for (sig = 0; sig < sgh->sig_cnt; sig++) {
228  s = sgh->match_array[sig];
229  if (s == NULL)
230  continue;
231  if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
232  continue;
233 
235  memset(&v, 0, sizeof(v));
236  Set(&v, s->init_data->prefilter_sm->ctx);
237 
238  ApplyToU8Hash(ctx, v, s);
240  cnt++;
241  }
242 
243  if (cnt) {
244  PrefilterAppendEngine(de_ctx, sgh, Match, ctx,
245  PrefilterPacketU8HashCtxFree,
246  sigmatch_table[sm_type].name);
247  } else {
248  PrefilterPacketU8HashCtxFree(ctx);
249  }
250  return 0;
251 }
252 
253 /** \internal
254  * \brief setup a engine for each unique value
255  */
256 static void SetupSingle(DetectEngineCtx *de_ctx, HashListTable *hash_table,
257  SigGroupHead *sgh, int sm_type,
258  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
259  void (*Match)(DetectEngineThreadCtx *det_ctx,
260  Packet *p, const void *pectx))
261 {
263  for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
265 
266  SetupEngineForPacketHeader(de_ctx, sgh, sm_type,
267  ctx, Compare, Match);
268  }
269 }
270 
271 /** \internal
272  * \brief setup a single engine with a hash map for u8 values
273  */
274 static void SetupU8Hash(DetectEngineCtx *de_ctx, HashListTable *hash_table,
275  SigGroupHead *sgh, int sm_type,
276  void (*Set)(PrefilterPacketHeaderValue *v, void *),
277  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
278  void (*Match)(DetectEngineThreadCtx *det_ctx,
279  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] - 1;
295  do {
296  counts[v] += ctx->cnt;
297  } while (v--);
298 
299  break;
300  }
302  {
303  int v = ctx->v1.u8[1] + 1;
304  do {
305  counts[v] += ctx->cnt;
306  } while (++v < 256);
307 
308  break;
309  }
311  {
312  int v = ctx->v1.u8[1] + 1;
313  do {
314  counts[v] += ctx->cnt;
315  } while (++v < ctx->v1.u8[2]);
316 
317  break;
318  }
319  }
320  }
321 
322  SetupEngineForPacketHeaderPrefilterPacketU8HashCtx(de_ctx, sgh, sm_type,
323  counts, Set, Compare, Match);
324 }
325 
326 static int PrefilterSetupPacketHeaderCommon(DetectEngineCtx *de_ctx,
327  SigGroupHead *sgh, int sm_type,
328  void (*Set)(PrefilterPacketHeaderValue *v, void *),
329  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
330  void (*Match)(DetectEngineThreadCtx *det_ctx,
331  Packet *p, const void *pectx),
332  bool u8hash)
333 {
334  Signature *s = NULL;
335  uint32_t sig = 0;
336 
337  if (sgh == NULL)
338  return 0;
339 
340  /* first count how many engines we will need */
341 
342  HashListTable *hash_table = HashListTableInit(4096,
343  PrefilterPacketHeaderHashFunc,
344  PrefilterPacketHeaderCompareFunc,
345  PrefilterPacketHeaderFreeFunc);
346  if (hash_table == NULL)
347  return -1;
348 
349  for (sig = 0; sig < sgh->sig_cnt; sig++) {
350  s = sgh->match_array[sig];
351  if (s == NULL)
352  continue;
353  if (s->init_data->prefilter_sm == NULL || s->init_data->prefilter_sm->type != sm_type)
354  continue;
355 
357  memset(&ctx, 0, sizeof(ctx));
358  Set(&ctx.v1, s->init_data->prefilter_sm->ctx);
359 
360  GetExtraMatch(s, &ctx.type, &ctx.value);
361 
362  PrefilterPacketHeaderHashCtx *rctx = HashListTableLookup(hash_table, (void *)&ctx, 0);
363  if (rctx != 0) {
364  rctx->cnt++;
365  } else {
366  PrefilterPacketHeaderHashCtx *actx = SCCalloc(1, sizeof(*actx));
367  if (actx == NULL)
368  goto error;
369 
370  Set(&actx->v1, s->init_data->prefilter_sm->ctx);
371  actx->cnt = 1;
372  actx->type = ctx.type;
373  actx->value = ctx.value;
374 
375  int ret = HashListTableAdd(hash_table, actx, 0);
376  if (ret != 0) {
377  SCFree(actx);
378  goto error;
379  }
380  }
381  }
382 
383  if (u8hash == FALSE) {
384  SetupSingle(de_ctx, hash_table, sgh, sm_type, Compare, Match);
385  } else {
386  SetupU8Hash(de_ctx, hash_table, sgh, sm_type, Set, Compare, Match);
387  }
388 
389  HashListTableFree(hash_table);
390  return 0;
391 error:
392  HashListTableFree(hash_table);
393  return -1;
394 }
395 
397  SigGroupHead *sgh, int sm_type,
398  void (*Set)(PrefilterPacketHeaderValue *v, void *),
399  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
400  void (*Match)(DetectEngineThreadCtx *det_ctx,
401  Packet *p, const void *pectx))
402 {
403  return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type,
404  Set, Compare, Match, TRUE);
405 }
406 
408  SigGroupHead *sgh, int sm_type,
409  void (*Set)(PrefilterPacketHeaderValue *v, void *),
410  bool (*Compare)(PrefilterPacketHeaderValue v, void *),
411  void (*Match)(DetectEngineThreadCtx *det_ctx,
412  Packet *p, const void *pectx))
413 {
414  return PrefilterSetupPacketHeaderCommon(de_ctx, sgh, sm_type,
415  Set, Compare, Match, FALSE);
416 }
PrefilterPacketHeaderHashCtx
struct PrefilterPacketHeaderHashCtx_ PrefilterPacketHeaderHashCtx
HashListTableGetListData
#define HashListTableGetListData(hb)
Definition: util-hashlist.h:59
Signature_::num
SigIntId num
Definition: detect.h:538
SigGroupHead_
Container for matching data for a signature group.
Definition: detect.h:1347
SignatureInitData_::prefilter_sm
SigMatch * prefilter_sm
Definition: detect.h:502
PrefilterPacketU8HashCtx_::array
SigsArray * array[256]
Definition: detect-engine-prefilter-common.h:51
Signature_::alproto
AppProto alproto
Definition: detect.h:532
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
DetectPort_::port
uint16_t port
Definition: detect.h:192
PREFILTER_U8HASH_MODE_RA
#define PREFILTER_U8HASH_MODE_RA
Definition: detect-engine-prefilter-common.h:57
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:767
PrefilterPacketHeaderCtx_::sigs_array
SigIntId * sigs_array
Definition: detect-engine-prefilter-common.h:41
HashListTableGetListHead
HashListTableBucket * HashListTableGetListHead(HashListTable *ht)
Definition: util-hashlist.c:290
PrefilterPacketHeaderValue::u8
uint8_t u8[16]
Definition: detect-engine-prefilter-common.h:22
DetectPort_::next
struct DetectPort_ * next
Definition: detect.h:205
PREFILTER_EXTRA_MATCH_SRCPORT
#define PREFILTER_EXTRA_MATCH_SRCPORT
Definition: detect-engine-prefilter-common.h:30
PrefilterPacketHeaderCtx_::sigs_cnt
uint32_t sigs_cnt
Definition: detect-engine-prefilter-common.h:40
HashListTableLookup
void * HashListTableLookup(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:248
DetectPort_::port2
uint16_t port2
Definition: detect.h:193
detect-engine-prefilter.h
SigsArray_::offset
uint32_t offset
Definition: detect-engine-prefilter-common.h:47
DetectPort_::flags
uint8_t flags
Definition: detect.h:195
HashListTableAdd
int HashListTableAdd(HashListTable *ht, void *data, uint16_t datalen)
Definition: util-hashlist.c:116
HashListTable_::array_size
uint32_t array_size
Definition: util-hashlist.h:41
HashListTableGetListNext
#define HashListTableGetListNext(hb)
Definition: util-hashlist.h:58
PrefilterPacketHeaderHashCtx_
Definition: detect-engine-prefilter-common.c:22
HashListTableInit
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
PrefilterPacketHeaderCtx_
Definition: detect-engine-prefilter-common.h:33
PREFILTER_EXTRA_MATCH_DSTPORT
#define PREFILTER_EXTRA_MATCH_DSTPORT
Definition: detect-engine-prefilter-common.h:31
type
uint8_t type
Definition: decode-icmpv4.h:0
PrefilterPacketHeaderCtx_::value
uint16_t value
Definition: detect-engine-prefilter-common.h:37
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:17
DetectEngineThreadCtx_
Definition: detect.h:1010
PrefilterPacketHeaderCtx_::type
uint16_t type
Definition: detect-engine-prefilter-common.h:36
PrefilterPacketHeaderHashCtx_::v1
PrefilterPacketHeaderValue v1
Definition: detect-engine-prefilter-common.c:23
TRUE
#define TRUE
Definition: suricata-common.h:33
SigMatch_::ctx
SigMatchCtx * ctx
Definition: detect.h:323
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:282
SigGroupHead_::sig_cnt
SigIntId sig_cnt
Definition: detect.h:1352
FALSE
#define FALSE
Definition: suricata-common.h:34
Signature_::flags
uint32_t flags
Definition: detect.h:529
Packet_
Definition: decode.h:414
Signature_::init_data
SignatureInitData * init_data
Definition: detect.h:597
HashListTable_
Definition: util-hashlist.h:37
Signature_::sp
DetectPort * sp
Definition: detect.h:567
SigMatch_::type
uint8_t type
Definition: detect.h:321
PrefilterPacketHeaderCtx_::v1
PrefilterPacketHeaderValue v1
Definition: detect-engine-prefilter-common.h:34
PREFILTER_U8HASH_MODE_EQ
#define PREFILTER_U8HASH_MODE_EQ
Definition: detect-engine-prefilter-common.h:54
SigGroupHead_::match_array
Signature ** match_array
Definition: detect.h:1372
SigsArray_::sigs
SigIntId * sigs
Definition: detect-engine-prefilter-common.h:45
suricata-common.h
HashListTableFree
void HashListTableFree(HashListTable *ht)
Definition: util-hashlist.c:82
SigsArray_
Definition: detect-engine-prefilter-common.h:44
sigmatch_table
SigTableElmt sigmatch_table[DETECT_TBLSIZE]
Definition: detect-parse.c:73
PrefilterPacketHeaderValue::u64
uint64_t u64[2]
Definition: detect-engine-prefilter-common.h:25
SigsArray_::cnt
uint32_t cnt
Definition: detect-engine-prefilter-common.h:46
PrefilterSetupPacketHeader
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))
Definition: detect-engine-prefilter-common.c:407
Signature_::dp
DetectPort * dp
Definition: detect.h:567
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Signature_::id
uint32_t id
Definition: detect.h:561
HashListTableBucket_
Definition: util-hashlist.h:28
Signature_
Signature container.
Definition: detect.h:528
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
PREFILTER_U8HASH_MODE_GT
#define PREFILTER_U8HASH_MODE_GT
Definition: detect-engine-prefilter-common.h:56
PORT_FLAG_NOT
#define PORT_FLAG_NOT
Definition: detect.h:187
PrefilterPacketU8HashCtx_
Definition: detect-engine-prefilter-common.h:50
PrefilterPacketHeaderValue
Definition: detect-engine-prefilter-common.h:21
detect-engine-prefilter-common.h
PrefilterAppendEngine
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)
Definition: detect-engine-prefilter.c:189
SigIntId
#define SigIntId
Definition: suricata-common.h:297
PrefilterSetupPacketHeaderU8Hash
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))
Definition: detect-engine-prefilter-common.c:396
PrefilterPacketHeaderHashCtx_::cnt
uint32_t cnt
Definition: detect-engine-prefilter-common.c:28
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SIG_FLAG_PREFILTER
#define SIG_FLAG_PREFILTER
Definition: detect.h:243
PrefilterPacketHeaderHashCtx_::value
uint16_t value
Definition: detect-engine-prefilter-common.c:26
PREFILTER_EXTRA_MATCH_ALPROTO
#define PREFILTER_EXTRA_MATCH_ALPROTO
Definition: detect-engine-prefilter-common.h:29
PrefilterPacketHeaderHashCtx_::type
uint16_t type
Definition: detect-engine-prefilter-common.c:25
PREFILTER_U8HASH_MODE_LT
#define PREFILTER_U8HASH_MODE_LT
Definition: detect-engine-prefilter-common.h:55