pcre: support for clamav styled offsets

pcre: added encompass ('e') option to matcher
remotes/push_mirror/swebb/clamyara^2
Kevin Lin 11 years ago
parent ad0303b992
commit 7ab4eec702
  1. 235
      libclamav/matcher-pcre.c
  2. 19
      libclamav/matcher-pcre.h
  3. 103
      libclamav/matcher.c
  4. 1
      libclamav/matcher.h
  5. 9
      libclamav/readdb.c
  6. 1
      libclamav/regex_pcre.c

@ -30,19 +30,20 @@
#include "clamav.h"
#include "cltypes.h"
#include "others.h"
#include "matcher.h"
#include "matcher-pcre.h"
#include "mpool.h"
#include "regex_pcre.h"
int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *pattern, const char *cflags, const uint32_t *lsigid)
int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *pattern, const char *cflags, const char *offset, const uint32_t *lsigid)
{
struct cli_pcre_meta **newmetatable = NULL, *pm = NULL;
uint32_t pcre_count;
const char *opt;
int ret = CL_SUCCESS, options = 0, rssigs;
if (!root || !trigger || !pattern) {
cli_errmsg("pcre_addpatt: NULL root or NULL trigger or NULL pattern\n");
if (!root || !trigger || !pattern || !offset) {
cli_errmsg("pcre_addpatt: NULL root or NULL trigger or NULL pattern or NULL offset\n");
return CL_ENULLARG;
}
@ -89,6 +90,22 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *
pm->lsigid[0] = lsigid[0];
pm->lsigid[1] = lsigid[1];
/* offset parsing and usage, similar to cli_ac_addsig */
/* type-specific offsets and type-specific scanning handled during scan (cli_target_info stuff?) */
ret = cli_caloff(offset, NULL, root->type, pm->offdata, &(pm->offset_min), &(pm->offset_max));
if (ret != CL_SUCCESS) {
cli_errmsg("cli_pcre_addpatt: cannot calculate offset data: %s for pattern: %s\n", offset, pattern);
cli_pcre_freemeta(pm);
mpool_free(root->mempool, pm);
return ret;
}
if(pm->offdata[0] != CLI_OFF_ANY) {
if(pm->offdata[0] == CLI_OFF_ABSOLUTE)
root->pcre_absoff_num++;
else
root->pcre_reloff_num++;
}
/* parse and add options, also totally not from snort */
if (cflags) {
cli_dbgmsg("cli_pcre_addpatt: parsing pcre compile flags: %s\n", cflags);
@ -100,6 +117,7 @@ int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *
switch (*opt) {
/* no matcher-specific options atm */
case 'g': pm->flags |= CLI_PCRE_GLOBAL; break;
case 'e': pm->flags |= CLI_PCRE_ENCOMPASS; break;
default:
cli_errmsg("cli_pcre_addpatt: unknown/extra pcre option encountered %c\n", *opt);
cli_pcre_freemeta(pm);
@ -168,6 +186,87 @@ int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, lon
return CL_SUCCESS;
}
int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struct cli_target_info *info)
{
/* TODO: fix the relative offset data maintained in cli_ac_data (generate own data?) */
int ret;
unsigned int i;
struct cli_pcre_meta *pm;
uint32_t endoff;
if (!root || !root->pcre_metatable || !data || !info) {
return CL_SUCCESS;
}
/* allocate data structures */
data->shift = (uint32_t *) cli_calloc(root->pcre_metas, sizeof(uint32_t));
if (!data->shift) {
cli_errmsg("cli_pcre_initoff: cannot allocate memory for data->shift\n");
return CL_EMEM;
}
data->offset = (uint32_t *) cli_calloc(root->pcre_metas, sizeof(uint32_t));
if (!data->offset) {
cli_errmsg("cli_pcre_initoff: cannot allocate memory for data->offset\n");
free(data->shift);
return CL_EMEM;
}
/* iterate across all pcre metadata and recalc offsets */
for (i = 0; i < root->pcre_metas; ++i) {
pm = root->pcre_metatable[i];
if (pm->offdata[0] == CLI_OFF_ANY) {
data->offset[i] = 0;
data->shift[i] = 0;
}
else if (pm->offdata[0] == CLI_OFF_ABSOLUTE) {
data->offset[i] = pm->offdata[1];
data->shift[i] = pm->offdata[2];
}
else if (pm->offdata[0] == CLI_OFF_EOF_MINUS) {
data->offset[i] = pm->offdata[1];
data->shift[i] = pm->offdata[2];
}
else {
ret = cli_caloff(NULL, info, root->type, pm->offdata, &data->offset[i], &endoff);
if (ret != CL_SUCCESS) {
cli_errmsg("cli_pcre_recaloff: cannot calculate relative offset in signature for sig[%u,%u]\n", pm->lsigid[0], pm->lsigid[1]);
free(data->shift);
free(data->offset);
return ret;
}
data->shift[i] = endoff-(data->offset[i]);
}
cli_dbgmsg("info->fsize: %lu\n", (long unsigned)info->fsize);
if (pm->offdata[0]>9)
cli_dbgmsg("offdata[0] type: %x\n", pm->offdata[0]);
else
cli_dbgmsg("offdata[0] type: %u\n", pm->offdata[0]);
cli_dbgmsg("offdata[1] offset: %u\n", pm->offdata[1]);
cli_dbgmsg("offdata[2] maxshift: %u\n", pm->offdata[2]);
cli_dbgmsg("offdata[3] section: %u\n", pm->offdata[3]);
cli_dbgmsg("offset_min: %u\n", pm->offset_min);
cli_dbgmsg("offset_max: %u\n", pm->offset_max);
}
for (i = 0; i < root->pcre_metas; ++i) {
cli_dbgmsg("data[%u]: (%u, %u)\n", i, data->offset[i], data->shift[i]);
}
return CL_SUCCESS;
}
void cli_pcre_freeoff(struct cli_pcre_off *data)
{
free(data->offset);
data->offset = NULL;
free(data->shift);
data->shift = NULL;
}
/* this fuction is static in matcher-ac.c; should we open it up to cli or maintain a copy here? */
static inline void lsig_sub_matched(const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t lsigid1, uint32_t lsigid2, uint32_t realoff, int partial)
{
const struct cli_lsig_tdb *tdb = &root->ac_lsigtable[lsigid1]->tdb;
@ -217,15 +316,20 @@ static inline void lsig_sub_matched(const struct cli_matcher *root, struct cli_a
}
}
int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx)
int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, const struct cli_pcre_off *data, cli_ctx *ctx)
{
struct cli_pcre_meta **metatable = root->pcre_metatable, *pm = NULL;
struct cli_pcre_data *pd;
uint32_t adjbuffer, adjshift, adjlength;
unsigned int i, evalcnt;
uint64_t evalids;
uint32_t global;
uint32_t global, encompass;
int rc, offset, ovector[OVECCOUNT];
if (!root->pcre_metatable) {
return CL_SUCCESS;
}
for (i = 0; i < root->pcre_metas; ++i) {
pm = root->pcre_metatable[i];
pd = &(pm->pdata);
@ -235,31 +339,90 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct
if ((strcmp(pm->trigger, PCRE_BYPASS)) && (cli_ac_chklsig(pm->trigger, pm->trigger + strlen(pm->trigger), mdata->lsigcnt[pm->lsigid[0]], &evalcnt, &evalids, 0) != 1))
continue;
global = (pm->flags & CLI_PCRE_GLOBAL);
offset = pd->search_offset;
global = (pm->flags & CLI_PCRE_GLOBAL); /* search for all matches */
encompass = (pm->flags & CLI_PCRE_ENCOMPASS); /* encompass search to offset->offset+maxshift */
offset = pd->search_offset; /* this is usually 0 */
cli_dbgmsg("cli_pcre_scanbuf: triggered %s; running regex /%s/%s\n", pm->trigger, pd->expression, global ? " (global)":"");
/* adjust the buffer sent to cli_pcre_match for offset and maxshift */
if (!data) {
/* default to scanning whole buffer but try to use existing offdata */
if (pm->offdata[0] == CLI_OFF_ABSOLUTE) {
adjbuffer = pm->offdata[1];
adjshift = pm->offdata[2];
}
else if (pm->offdata[0] == CLI_OFF_EOF_MINUS) {
if (length > pm->offdata[1]) {
adjbuffer = length - pm->offdata[1];
adjshift = pm->offdata[2];
}
else {
/* EOF is invalid */
continue;
}
}
else {
/* you could call cli_caloff here but you should call cli_pcre_recaloff before */
adjbuffer = 0;
adjshift = 0;
}
}
else {
adjbuffer = data->offset[i];
adjshift = data->shift[i];
}
/* check the offset bounds */
if (adjbuffer < length) {
/* handle encompass flag */
if (encompass && adjshift != 0 && adjshift != CLI_OFF_NONE) {
if (adjbuffer+adjshift > length)
adjlength = length - adjbuffer;
else
adjlength = adjshift;
}
else {
adjlength = length - adjbuffer;
}
}
else {
/* starting offset is outside bounds of file, skip pcre execution */
cli_dbgmsg("cli_pcre_scanbuf: starting offset is outside bounds of file %u >= %u\n", adjbuffer, length);
continue;
}
cli_dbgmsg("cli_pcre_scanbuf: passed buffer adjusted to %u +%u(%u)[%u]%s\n", adjbuffer, adjlength, adjbuffer+adjlength, adjshift, encompass ? " (encompass)":"");
/* if the global flag is set, loop through the scanning - TODO: how does this affect really big files? */
do {
rc = cli_pcre_match(pd, buffer, length, CLI_PCREMATCH_NOOVERRIDE, offset, ovector, OVECCOUNT);
rc = cli_pcre_match(pd, buffer+adjbuffer, adjlength, offset, 0, ovector, OVECCOUNT);
cli_dbgmsg("cli_pcre_scanbuf: running regex /%s/ returns %d\n", pd->expression, rc);
/* matched, rc shouldn't be >0 unless a full match occurs */
if (rc > 0) {
/* check if we've gone over offset+shift */
if (!encompass && adjshift) {
if (ovector[0] > adjshift) {
/* ignore matched offset (outside of maxshift) */
cli_dbgmsg("cli_pcre_scanbuf: match found outside of maxshift @%u\n", adjbuffer+ovector[0]);
break;
}
}
cli_dbgmsg("cli_pcre_scanbuf: assigning lsigcnt[%d][%d], located @ %d\n",
pm->lsigid[0], pm->lsigid[1], ovector[0]);
pm->lsigid[0], pm->lsigid[1], adjbuffer+ovector[0]);
lsig_sub_matched(root, mdata, pm->lsigid[0], pm->lsigid[1], ovector[0], 0);
lsig_sub_matched(root, mdata, pm->lsigid[0], pm->lsigid[1], adjbuffer+ovector[0], 0);
}
/* move off to the end of the match for next match;
/* move off to the end of the match for next match; offset is relative to adjbuffer
* NOTE: misses matches starting within the last match */
offset = ovector[1];
/* clear the ovector results (they fall through the pcre_match) */
memset(ovector, 0, sizeof(ovector));
} while (global && rc > 0 && offset < length);
} while (global && rc > 0 && offset < adjlength);
/* handle error codes */
if (rc < 0 && rc != PCRE_ERROR_NOMATCH) {
@ -272,53 +435,9 @@ int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct
return CL_SUCCESS;
}
int cli_pcre_ucondscanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx)
int cli_pcre_ucondscanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, struct cli_pcre_off *data, cli_ctx *ctx)
{
struct cli_pcre_meta **metatable = root->pcre_metatable, *pm = NULL;
struct cli_pcre_data *pd;
unsigned int i, evalcnt;
uint64_t evalids;
uint32_t global;
int rc, offset, ovector[OVECCOUNT];
for (i = 0; i < root->pcre_metas; ++i) {
pm = root->pcre_metatable[i];
pd = &(pm->pdata);
global = (pm->flags & CLI_PCRE_GLOBAL);
offset = pd->search_offset;
cli_dbgmsg("cli_pcre_ucondscanbuf: unconditionally running regex /%s/\n", pd->expression);
/* if the global flag is set, loop through the scanning - TODO: how does this affect really big files? */
do {
rc = cli_pcre_match(pd, buffer, length, CLI_PCREMATCH_NOOVERRIDE, offset, ovector, OVECCOUNT);
cli_dbgmsg("cli_pcre_ucondscanbuf: running regex /%s/ returns %d\n", pd->expression, rc);
/* matched, rc shouldn't be >0 unless a full match occurs */
if (rc > 0) {
cli_dbgmsg("cli_pcre_ucondscanbuf: assigning lsigcnt[%d][%d], located @ %d\n",
pm->lsigid[0], pm->lsigid[1], ovector[0]);
lsig_sub_matched(root, mdata, pm->lsigid[0], pm->lsigid[1], ovector[0], 0);
}
/* move off to the end of the match for next match;
* NOTE: misses matches starting within the last match */
offset = ovector[1];
/* clear the ovector results (they fall through the pcre_match) */
memset(ovector, 0, sizeof(ovector));
} while (global && rc > 0 && offset < length);
/* handle error codes */
if (rc < 0 && rc != PCRE_ERROR_NOMATCH) {
cli_errmsg("cli_pcre_ucondscanbuf: cli_pcre_match: pcre_exec: returned error %d\n", rc);
/* TODO: convert the pcre error codes to clamav error codes, handle match_limit and match_limit_recursion exceeded */
return CL_BREAK;
}
}
/* TODO: copy cli_pcre_scanbuf - trigger */
return CL_SUCCESS;
}

@ -37,20 +37,31 @@
#include "regex_pcre.h"
#define PCRE_BYPASS "7374756c747a676574737265676578"
#define CLI_PCRE_GLOBAL 0x00000001 /* g */
#define CLI_PCRE_GLOBAL 0x00000001 /* g */
#define CLI_PCRE_ENCOMPASS 0x00000002 /* e */
struct cli_pcre_meta {
char *trigger;
uint32_t lsigid[2];
struct cli_pcre_data pdata;
/* clamav offset data */
uint32_t offdata[4];
uint32_t offset_min, offset_max;
/* internal flags (bitfield?) */
uint32_t flags;
};
/* figure out where to handle the pcre options: matcher likes addpatt, but it's currently also in build */
int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *pattern, const char *cflags, const uint32_t *lsigid);
/* stores offset data */
struct cli_pcre_off {
uint32_t *offset, *shift;
};
int cli_pcre_addpatt(struct cli_matcher *root, const char *trigger, const char *pattern, const char *cflags, const char *offset, const uint32_t *lsigid);
int cli_pcre_build(struct cli_matcher *root, long long unsigned match_limit, long long unsigned recmatch_limit);
int cli_pcre_ucondscanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx);
int cli_pcre_recaloff(struct cli_matcher *root, struct cli_pcre_off *data, struct cli_target_info *info);
void cli_pcre_freeoff(struct cli_pcre_off *data);
int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, const struct cli_pcre_off *data, cli_ctx *ctx);
int cli_pcre_ucondscanbuf(const unsigned char *buffer, uint32_t length, const struct cli_matcher *root, struct cli_ac_data *mdata, struct cli_pcre_off *data, cli_ctx *ctx);
void cli_pcre_freemeta(struct cli_pcre_meta *pm);
void cli_pcre_freetable(struct cli_matcher *root);
#endif /* HAVE_PCRE */

@ -868,53 +868,6 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
}
}
/*lsig '=' op does not work if pcre match occurs after AC matching */
/* cannot save pcre execution state without possible evasion; must scan entire buffer */
/*
#if HAVE_PCRE
if((buff = fmap_need_off_once(map, offset, map->len))) {
if (!ftonly) {
ret = cli_pcre_ucondscanbuf(buff, map->len, groot, &gdata, ctx);
if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
if(info.exeinfo.section)
free(info.exeinfo.section);
cli_hashset_destroy(&info.exeinfo.vinfo);
cl_hash_destroy(md5ctx);
cl_hash_destroy(sha1ctx);
cl_hash_destroy(sha256ctx);
return ret;
}
}
if (troot) {
ret = cli_pcre_ucondscanbuf(buff, map->len, troot, &tdata, ctx);
if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
if(!ftonly)
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
if(info.exeinfo.section)
free(info.exeinfo.section);
cli_hashset_destroy(&info.exeinfo.vinfo);
cl_hash_destroy(md5ctx);
cl_hash_destroy(sha1ctx);
cl_hash_destroy(sha256ctx);
return ret;
}
}
}
#endif /* HAVE_PCRE */
/* end experimental fragment */
while(offset < map->len) {
bytes = MIN(map->len - offset, SCANBUFF);
if(!(buff = fmap_need_off_once(map, offset, bytes)))
@ -1004,12 +957,35 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
offset += bytes - maxpatlen;
}
/*lsig '=' op does not work if pcre match occurs after AC matching */
/* lsig '=' op does not work if pcre match occurs after AC matching */
/* cannot save pcre execution state without possible evasion; must scan entire buffer */
/* however, scanning the whole buffer may require the whole buffer being loaded into memory */
/* this should also be part of matcher_run but it cannot as matcher_run is done on partial buffers */
#if HAVE_PCRE
if((buff = fmap_need_off_once(map, 0, map->len))) {
if (!ftonly) {
ret = cli_pcre_scanbuf(buff, map->len, groot, &gdata, ctx);
struct cli_pcre_off poff;
/* calculate the relative offsets */
ret = cli_pcre_recaloff(groot, &poff, &info);
if (ret != CL_SUCCESS) {
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
if(info.exeinfo.section)
free(info.exeinfo.section);
cli_hashset_destroy(&info.exeinfo.vinfo);
cl_hash_destroy(md5ctx);
cl_hash_destroy(sha1ctx);
cl_hash_destroy(sha256ctx);
return ret;
}
/* scan the full buffer */
ret = cli_pcre_scanbuf(buff, map->len, groot, &gdata, &poff, ctx);
if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
@ -1019,15 +995,39 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
if(info.exeinfo.section)
free(info.exeinfo.section);
cli_pcre_freeoff(&poff);
cli_hashset_destroy(&info.exeinfo.vinfo);
cl_hash_destroy(md5ctx);
cl_hash_destroy(sha1ctx);
cl_hash_destroy(sha256ctx);
return ret;
}
cli_pcre_freeoff(&poff);
}
if (troot) {
ret = cli_pcre_scanbuf(buff, map->len, troot, &tdata, ctx);
struct cli_pcre_off poff;
/* calculate the relative offsets */
ret = cli_pcre_recaloff(troot, &poff, &info);
if (ret != CL_SUCCESS) {
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
if(info.exeinfo.section)
free(info.exeinfo.section);
cli_hashset_destroy(&info.exeinfo.vinfo);
cl_hash_destroy(md5ctx);
cl_hash_destroy(sha1ctx);
cl_hash_destroy(sha256ctx);
return ret;
}
/* scan the full buffer */
ret = cli_pcre_scanbuf(buff, map->len, troot, &tdata, &poff, ctx);
if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
if(!ftonly)
cli_ac_freedata(&gdata);
@ -1039,12 +1039,15 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
if(info.exeinfo.section)
free(info.exeinfo.section);
cli_pcre_freeoff(&poff);
cli_hashset_destroy(&info.exeinfo.vinfo);
cl_hash_destroy(md5ctx);
cl_hash_destroy(sha1ctx);
cl_hash_destroy(sha256ctx);
return ret;
}
cli_pcre_freeoff(&poff);
}
}
#endif /* HAVE_PCRE */

@ -114,6 +114,7 @@ struct cli_matcher {
#if HAVE_PCRE
uint32_t pcre_metas;
struct cli_pcre_meta **pcre_metatable;
uint32_t pcre_reloff_num, pcre_absoff_num;
#endif
#ifdef USE_MPOOL

@ -214,11 +214,10 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
cflags = NULL;
}
cli_dbgmsg("trigger %s; regex %s; cflags %s\n", trigger, regex, cflags);
cli_dbgmsg("trigger %s; regex %s; cflags %s; offset %s\n", trigger, regex, cflags, offset);
/* normal trigger */
cli_dbgmsg("pcre regex detected: %s on trigger: %s with cflags: %s\n", regex, trigger, cflags);
ret = cli_pcre_addpatt(root, trigger, regex, cflags, lsigid);
cli_dbgmsg("pcre regex detected: %s on trigger: %s with cflags: %s @offset: %s\n", regex, trigger, cflags, offset);
ret = cli_pcre_addpatt(root, trigger, regex, cflags, offset, lsigid);
free(trigger);
free(regex);
@ -3509,7 +3508,7 @@ int cl_engine_compile(struct cl_engine *engine)
if((ret = cli_pcre_build(root, engine->pcre_match_limit, engine->pcre_recmatch_limit)))
return ret;
cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u PCREs: %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->maxpatlen, root->pcre_metas, root->ac_only ? "(ac_only mode)" : "");
cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) PCREs: %u (reloff: %u, absoff: %u) maxpatlen %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->pcre_metas, root->pcre_reloff_num, root->pcre_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : "");
#else
cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u PCREs: 0 (disabled) %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : "");
#endif

@ -36,6 +36,7 @@
/* TODO: redefine pcre_malloc and pcre_free */
/* TODO: function is kinda pointless, remove? */
int cli_pcre_parse(struct cli_pcre_data *pd, const char *pattern)
{
if (!pd || !pattern) {

Loading…
Cancel
Save