You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
suricata/src/util-mpm.c

311 lines
7.8 KiB
C

#include "suricata-common.h"
#include "util-mpm.h"
#include "util-debug.h"
/* include pattern matchers */
#include "util-mpm-wumanber.h"
#include "util-mpm-b2g.h"
#include "util-mpm-b3g.h"
/** \brief Setup a pmq
* \param pmq Pattern matcher queue to be initialized
* \param maxid Max id to be matched on
* \retval -1 error
* \retval 0 ok
*/
int PmqSetup(PatternMatcherQueue *pmq, uint32_t maxid) {
if (pmq == NULL)
return -1;
memset(pmq, 0, sizeof(PatternMatcherQueue));
pmq->sig_id_array = malloc(maxid * sizeof(uint32_t));
if (pmq->sig_id_array == NULL) {
printf("ERROR: could not setup memory for pattern matcher: %s\n", strerror(errno));
return -1;
}
memset(pmq->sig_id_array, 0, maxid * sizeof(uint32_t));
pmq->sig_id_array_cnt = 0;
/* lookup bitarray */
pmq->sig_bitarray = malloc(maxid / 8 + 1);
if (pmq->sig_bitarray == NULL) {
printf("ERROR: could not setup memory for pattern matcher: %s\n", strerror(errno));
return -1;
}
memset(pmq->sig_bitarray, 0, maxid / 8 + 1);
return 0;
}
/** \brief Reset a Pmq for reusage. Meant to be called after a single search.
* \param pmq Pattern matcher to be reset.
*/
void PmqReset(PatternMatcherQueue *pmq) {
uint32_t u;
for (u = 0; u < pmq->sig_id_array_cnt; u++) {
pmq->sig_bitarray[(pmq->sig_id_array[u] / 8)] &= ~(1<<(pmq->sig_id_array[u] % 8));
}
pmq->sig_id_array_cnt = 0;
}
/** \brief Cleanup a Pmq
* \param pmq Pattern matcher queue to be cleaned up.
*/
void PmqCleanup(PatternMatcherQueue *pmq) {
if (pmq == NULL)
return;
if (pmq->sig_id_array != NULL) {
free(pmq->sig_id_array);
pmq->sig_id_array = NULL;
}
if (pmq->sig_bitarray != NULL) {
free(pmq->sig_bitarray);
pmq->sig_bitarray = NULL;
}
pmq->sig_id_array_cnt = 0;
}
/** \brief Cleanup and free a Pmq
* \param pmq Pattern matcher queue to be free'd.
*/
void PmqFree(PatternMatcherQueue *pmq) {
if (pmq == NULL)
return;
PmqCleanup(pmq);
free(pmq);
}
/* cleanup list with all matches
*
* used at search runtime (or actually once per search) */
void
MpmMatchCleanup(MpmThreadCtx *thread_ctx) {
SCLogDebug("mem %" PRIu32 "", thread_ctx->memory_size);
MpmMatch *nxt;
MpmMatch *m = thread_ctx->qlist;
while (m != NULL) {
BUG_ON(m == m->qnext);
nxt = m->qnext;
/* clear the bucket */
m->mb->top = NULL;
m->mb->bot = NULL;
m->mb->len = 0;
thread_ctx->qlist = m->qnext;
/* add to the spare list */
if (thread_ctx->sparelist == NULL) {
thread_ctx->sparelist = m;
m->qnext = NULL;
} else {
m->qnext = thread_ctx->sparelist;
thread_ctx->sparelist = m;
}
m = nxt;
}
}
16 years ago
/** \brief allocate a match
*
* used at search runtime */
inline MpmMatch *
MpmMatchAlloc(MpmThreadCtx *thread_ctx) {
MpmMatch *m = malloc(sizeof(MpmMatch));
if (m == NULL)
return NULL;
thread_ctx->memory_cnt++;
thread_ctx->memory_size += sizeof(MpmMatch);
m->offset = 0;
m->next = NULL;
m->qnext = NULL;
m->mb = NULL;
return m;
}
16 years ago
/** \brief append a match to a bucket
*
* used at search runtime */
17 years ago
inline int
MpmMatchAppend(MpmThreadCtx *thread_ctx, PatternMatcherQueue *pmq, MpmEndMatch *em, MpmMatchBucket *mb, uint16_t offset, uint16_t patlen)
{
17 years ago
/* don't bother looking at sigs that didn't match
16 years ago
* when we scanned. There's no matching anyway. */
17 years ago
if (pmq != NULL && pmq->mode == PMQ_MODE_SEARCH) {
if (!(pmq->sig_bitarray[(em->sig_id / 8)] & (1<<(em->sig_id % 8))))
return 0;
}
16 years ago
/* if our endmatch is set to a single match being enough,
we're not going to add more if we already have one */
if (em->flags & MPM_ENDMATCH_SINGLE && mb->len)
17 years ago
return 0;
/* check offset */
if (offset < em->offset)
return 0;
/* check depth */
if (em->depth && (offset+patlen) > em->depth)
return 0;
17 years ago
/* ok all checks passed, now append the match */
MpmMatch *m;
/* pull a match from the spare list */
if (thread_ctx->sparelist != NULL) {
m = thread_ctx->sparelist;
thread_ctx->sparelist = m->qnext;
} else {
m = MpmMatchAlloc(thread_ctx);
if (m == NULL)
17 years ago
return 0;
}
m->offset = offset;
m->mb = mb;
m->next = NULL;
m->qnext = NULL;
/* append to the mb list */
if (mb->bot == NULL) { /* empty list */
mb->top = m;
mb->bot = m;
} else { /* more items in list */
mb->bot->next = m;
mb->bot = m;
}
mb->len++;
/* put in the queue list */
if (thread_ctx->qlist == NULL) { /* empty list */
thread_ctx->qlist = m;
} else { /* more items in list */
m->qnext = thread_ctx->qlist;
thread_ctx->qlist = m;
}
17 years ago
BUG_ON(m == m->qnext);
17 years ago
if (pmq != NULL) {
/* make sure we only append a sig with a matching pattern once,
* so we won't inspect it more than once. For this we keep a
* bitarray of sig internal id's and flag each sig that matched */
if (!(pmq->sig_bitarray[(em->sig_id / 8)] & (1<<(em->sig_id % 8)))) {
16 years ago
/* flag this sig_id as being added now */
17 years ago
pmq->sig_bitarray[(em->sig_id / 8)] |= (1<<(em->sig_id % 8));
16 years ago
/* append the sig_id to the array with matches */
17 years ago
pmq->sig_id_array[pmq->sig_id_array_cnt] = em->sig_id;
pmq->sig_id_array_cnt++;
}
/* nosearch flag */
if (pmq->mode == PMQ_MODE_SCAN && !(em->flags & MPM_ENDMATCH_NOSEARCH)) {
pmq->searchable++;
}
17 years ago
}
SCLogDebug("len %" PRIu32 " (offset %" PRIu32 ")", mb->len, m->offset);
17 years ago
return 1;
}
void MpmMatchFree(MpmThreadCtx *ctx, MpmMatch *m) {
ctx->memory_cnt--;
ctx->memory_size -= sizeof(MpmMatch);
free(m);
}
void MpmMatchFreeSpares(MpmThreadCtx *mpm_ctx, MpmMatch *m) {
while(m) {
MpmMatch *tm = m->qnext;
MpmMatchFree(mpm_ctx, m);
m = tm;
}
}
/* allocate an endmatch
*
* Only used in the initialization phase */
MpmEndMatch *MpmAllocEndMatch (MpmCtx *ctx)
{
MpmEndMatch *e = malloc(sizeof(MpmEndMatch));
if (e == NULL)
return NULL;
memset(e, 0, sizeof(MpmEndMatch));
ctx->memory_cnt++;
ctx->memory_size += sizeof(MpmEndMatch);
ctx->endmatches++;
return e;
}
/**
* \brief Return the pattern max length of a registered matcher
* \retval 0 if it has no limit
* \retval max_pattern_length of the specified matcher type
* \retval -1 if the type is not registered return -1
*/
int32_t MpmMatcherGetMaxPatternLength(uint16_t matcher) {
if (matcher < MPM_TABLE_SIZE)
return mpm_table[matcher].max_pattern_length;
else
return -1;
}
void MpmEndMatchFree(MpmCtx *ctx, MpmEndMatch *em) {
ctx->memory_cnt--;
ctx->memory_size -= sizeof(MpmEndMatch);
free(em);
}
void MpmEndMatchFreeAll(MpmCtx *mpm_ctx, MpmEndMatch *em) {
while(em) {
MpmEndMatch *tem = em->next;
MpmEndMatchFree(mpm_ctx, em);
em = tem;
}
}
void MpmInitThreadCtx(MpmThreadCtx *mpm_thread_ctx, uint16_t matcher, uint32_t max_id) {
mpm_table[matcher].InitThreadCtx(NULL, mpm_thread_ctx, max_id);
}
void MpmInitCtx (MpmCtx *mpm_ctx, uint16_t matcher) {
mpm_ctx->mpm_type = matcher;
mpm_table[matcher].InitCtx(mpm_ctx);
}
void MpmTableSetup(void) {
memset(mpm_table, 0, sizeof(mpm_table));
MpmWuManberRegister();
MpmB2gRegister();
MpmB3gRegister();
}
void MpmRegisterTests(void) {
16 years ago
#ifdef UNITTESTS
uint16_t i;
for (i = 0; i < MPM_TABLE_SIZE; i++) {
if (mpm_table[i].RegisterUnittests != NULL) {
mpm_table[i].RegisterUnittests();
} else {
printf("Warning: mpm %s has no unittest registration function...", mpm_table[i].name);
}
}
16 years ago
#endif
}