detect: save invalid rules

This keeps the invalid rules in string format into a list,
added in DetectEngineCtx.
pull/2871/merge
Giuseppe Longo 11 years ago committed by Victor Julien
parent e17b9616ab
commit 1328ecb8f6

@ -389,6 +389,7 @@ util-decode-asn1.c util-decode-asn1.h \
util-decode-der.c util-decode-der.h \ util-decode-der.c util-decode-der.h \
util-decode-der-get.c util-decode-der-get.h \ util-decode-der-get.c util-decode-der-get.h \
util-decode-mime.c util-decode-mime.h \ util-decode-mime.c util-decode-mime.h \
util-detect.c util-detect.h \
util-device.c util-device.h \ util-device.c util-device.h \
util-enum.c util-enum.h \ util-enum.c util-enum.h \
util-error.c util-error.h \ util-error.c util-error.h \

@ -369,7 +369,7 @@ typedef struct DetectBufferType_ {
_Bool mpm; _Bool mpm;
_Bool packet; /**< compat to packet matches */ _Bool packet; /**< compat to packet matches */
void (*SetupCallback)(Signature *); void (*SetupCallback)(Signature *);
_Bool (*ValidateCallback)(const Signature *); _Bool (*ValidateCallback)(const Signature *, const char **sigerror);
} DetectBufferType; } DetectBufferType;
static DetectBufferType **g_buffer_type_map = NULL; static DetectBufferType **g_buffer_type_map = NULL;
@ -579,7 +579,7 @@ void DetectBufferRunSetupCallback(const int id, Signature *s)
} }
void DetectBufferTypeRegisterValidateCallback(const char *name, void DetectBufferTypeRegisterValidateCallback(const char *name,
_Bool (*ValidateCallback)(const Signature *)) _Bool (*ValidateCallback)(const Signature *, const char **sigerror))
{ {
BUG_ON(g_buffer_type_reg_closed); BUG_ON(g_buffer_type_reg_closed);
DetectBufferTypeRegister(name); DetectBufferTypeRegister(name);
@ -588,11 +588,11 @@ void DetectBufferTypeRegisterValidateCallback(const char *name,
exists->ValidateCallback = ValidateCallback; exists->ValidateCallback = ValidateCallback;
} }
_Bool DetectBufferRunValidateCallback(const int id, const Signature *s) _Bool DetectBufferRunValidateCallback(const int id, const Signature *s, const char **sigerror)
{ {
const DetectBufferType *map = DetectBufferTypeGetById(id); const DetectBufferType *map = DetectBufferTypeGetById(id);
if (map && map->ValidateCallback) { if (map && map->ValidateCallback) {
return map->ValidateCallback(s); return map->ValidateCallback(s, sigerror);
} }
return TRUE; return TRUE;
} }
@ -1000,6 +1000,8 @@ static DetectEngineCtx *DetectEngineCtxInitReal(int minimal, const char *prefix)
memset(de_ctx,0,sizeof(DetectEngineCtx)); memset(de_ctx,0,sizeof(DetectEngineCtx));
memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat)); memset(&de_ctx->sig_stat, 0, sizeof(SigFileLoaderStat));
TAILQ_INIT(&de_ctx->sig_stat.failed_sigs);
de_ctx->sigerror = NULL;
if (minimal) { if (minimal) {
de_ctx->minimal = 1; de_ctx->minimal = 1;
@ -1098,6 +1100,22 @@ static void DetectEngineCtxFreeThreadKeywordData(DetectEngineCtx *de_ctx)
de_ctx->keyword_list = NULL; de_ctx->keyword_list = NULL;
} }
static void DetectEngineCtxFreeFailedSigs(DetectEngineCtx *de_ctx)
{
SigString *item = NULL;
SigString *sitem;
TAILQ_FOREACH_SAFE(item, &de_ctx->sig_stat.failed_sigs, next, sitem) {
SCFree(item->filename);
SCFree(item->sig_str);
if (item->sig_error) {
SCFree(item->sig_error);
}
TAILQ_REMOVE(&de_ctx->sig_stat.failed_sigs, item, next);
SCFree(item);
}
}
/** /**
* \brief Free a DetectEngineCtx:: * \brief Free a DetectEngineCtx::
* *
@ -1148,6 +1166,7 @@ void DetectEngineCtxFree(DetectEngineCtx *de_ctx)
DetectEngineCtxFreeThreadKeywordData(de_ctx); DetectEngineCtxFreeThreadKeywordData(de_ctx);
SRepDestroy(de_ctx); SRepDestroy(de_ctx);
DetectEngineCtxFreeFailedSigs(de_ctx);
DetectAddressMapFree(de_ctx); DetectAddressMapFree(de_ctx);

@ -44,8 +44,8 @@ void DetectBufferTypeRegisterSetupCallback(const char *name,
void (*Callback)(Signature *)); void (*Callback)(Signature *));
void DetectBufferRunSetupCallback(const int id, Signature *s); void DetectBufferRunSetupCallback(const int id, Signature *s);
void DetectBufferTypeRegisterValidateCallback(const char *name, void DetectBufferTypeRegisterValidateCallback(const char *name,
_Bool (*ValidateCallback)(const Signature *)); _Bool (*ValidateCallback)(const Signature *, const char **sigerror));
_Bool DetectBufferRunValidateCallback(const int id, const Signature *s); _Bool DetectBufferRunValidateCallback(const int id, const Signature *s, const char **sigerror);
/* prototypes */ /* prototypes */
DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix); DetectEngineCtx *DetectEngineCtxInitWithPrefix(const char *prefix);

@ -63,7 +63,7 @@ static int DetectHttpHHSetup(DetectEngineCtx *, Signature *, const char *);
static void DetectHttpHHRegisterTests(void); static void DetectHttpHHRegisterTests(void);
static void DetectHttpHHFree(void *); static void DetectHttpHHFree(void *);
static void DetectHttpHostSetupCallback(Signature *s); static void DetectHttpHostSetupCallback(Signature *s);
static _Bool DetectHttpHostValidateCallback(const Signature *s); static _Bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror);
static int g_http_host_buffer_id = 0; static int g_http_host_buffer_id = 0;
/** /**
@ -126,18 +126,20 @@ static void DetectHttpHostSetupCallback(Signature *s)
s->mask |= SIG_MASK_REQUIRE_HTTP_STATE; s->mask |= SIG_MASK_REQUIRE_HTTP_STATE;
} }
static _Bool DetectHttpHostValidateCallback(const Signature *s) static _Bool DetectHttpHostValidateCallback(const Signature *s, const char **sigerror)
{ {
const SigMatch *sm = s->init_data->smlists[g_http_host_buffer_id]; const SigMatch *sm = s->init_data->smlists[g_http_host_buffer_id];
for ( ; sm != NULL; sm = sm->next) { for ( ; sm != NULL; sm = sm->next) {
if (sm->type == DETECT_CONTENT) { if (sm->type == DETECT_CONTENT) {
DetectContentData *cd = (DetectContentData *)sm->ctx; DetectContentData *cd = (DetectContentData *)sm->ctx;
if (cd->flags & DETECT_CONTENT_NOCASE) { if (cd->flags & DETECT_CONTENT_NOCASE) {
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: http_host keyword " *sigerror = "http_host keyword "
"specified along with \"nocase\". " "specified along with \"nocase\". "
"Since the hostname buffer we match against " "Since the hostname buffer we match against "
"is actually lowercase. So having a " "is actually lowercase. So having a "
"nocase is redundant.", s->id); "nocase is redundant.";
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
return FALSE;
} else { } else {
uint32_t u; uint32_t u;
for (u = 0; u < cd->content_len; u++) { for (u = 0; u < cd->content_len; u++) {
@ -145,11 +147,12 @@ static _Bool DetectHttpHostValidateCallback(const Signature *s)
break; break;
} }
if (u != cd->content_len) { if (u != cd->content_len) {
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: A pattern with " *sigerror = "A pattern with "
"uppercase chars detected for http_host. " "uppercase chars detected for http_host. "
"Since the hostname buffer we match against " "Since the hostname buffer we match against "
"is lowercase only, please specify a " "is lowercase only, please specify a "
"lowercase pattern.", s->id); "lowercase pattern.";
SCLogWarning(SC_WARN_POOR_RULE, "rule %u: %s", s->id, *sigerror);
return FALSE; return FALSE;
} }
} }

@ -65,7 +65,7 @@ static int DetectHttpMethodSetup(DetectEngineCtx *, Signature *, const char *);
void DetectHttpMethodRegisterTests(void); void DetectHttpMethodRegisterTests(void);
void DetectHttpMethodFree(void *); void DetectHttpMethodFree(void *);
static void DetectHttpMethodSetupCallback(Signature *s); static void DetectHttpMethodSetupCallback(Signature *s);
static _Bool DetectHttpMethodValidateCallback(const Signature *s); static _Bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror);
/** /**
* \brief Registration function for keyword: http_method * \brief Registration function for keyword: http_method
@ -144,7 +144,7 @@ static void DetectHttpMethodSetupCallback(Signature *s)
* \retval 1 valid * \retval 1 valid
* \retval 0 invalid * \retval 0 invalid
*/ */
static _Bool DetectHttpMethodValidateCallback(const Signature *s) static _Bool DetectHttpMethodValidateCallback(const Signature *s, const char **sigerror)
{ {
const SigMatch *sm = s->init_data->smlists[g_http_method_buffer_id]; const SigMatch *sm = s->init_data->smlists[g_http_method_buffer_id];
for ( ; sm != NULL; sm = sm->next) { for ( ; sm != NULL; sm = sm->next) {
@ -153,16 +153,20 @@ static _Bool DetectHttpMethodValidateCallback(const Signature *s)
const DetectContentData *cd = (const DetectContentData *)sm->ctx; const DetectContentData *cd = (const DetectContentData *)sm->ctx;
if (cd->content && cd->content_len) { if (cd->content && cd->content_len) {
if (cd->content[cd->content_len-1] == 0x20) { if (cd->content[cd->content_len-1] == 0x20) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing space"); *sigerror = "http_method pattern with trailing space";
SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
return FALSE; return FALSE;
} else if (cd->content[0] == 0x20) { } else if (cd->content[0] == 0x20) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading space"); *sigerror = "http_method pattern with leading space";
SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
return FALSE; return FALSE;
} else if (cd->content[cd->content_len-1] == 0x09) { } else if (cd->content[cd->content_len-1] == 0x09) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with trailing tab"); *sigerror = "http_method pattern with trailing tab";
SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
return FALSE; return FALSE;
} else if (cd->content[0] == 0x09) { } else if (cd->content[0] == 0x09) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "http_method pattern with leading tab"); *sigerror = "http_method pattern with leading tab";
SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
return FALSE; return FALSE;
} }
} }

@ -63,7 +63,7 @@
static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *); static int DetectHttpRawHeaderSetup(DetectEngineCtx *, Signature *, const char *);
static void DetectHttpRawHeaderRegisterTests(void); static void DetectHttpRawHeaderRegisterTests(void);
static void DetectHttpRawHeaderFree(void *); static void DetectHttpRawHeaderFree(void *);
static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s); static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror);
static void DetectHttpRawHeaderSetupCallback(Signature *s); static void DetectHttpRawHeaderSetupCallback(Signature *s);
static int g_http_raw_header_buffer_id = 0; static int g_http_raw_header_buffer_id = 0;
@ -143,13 +143,15 @@ int DetectHttpRawHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *
ALPROTO_HTTP); ALPROTO_HTTP);
} }
static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s) static _Bool DetectHttpRawHeaderValidateCallback(const Signature *s, const char **sigerror)
{ {
if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) { if ((s->flags & (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) == (SIG_FLAG_TOCLIENT|SIG_FLAG_TOSERVER)) {
SCLogError(SC_ERR_INVALID_SIGNATURE,"http_raw_header signature " *sigerror = "http_raw_header signature "
"without a flow direction. Use flow:to_server for " "without a flow direction. Use flow:to_server for "
"inspecting request headers or flow:to_client for " "inspecting request headers or flow:to_client for "
"inspecting response headers."); "inspecting response headers.";
SCLogError(SC_ERR_INVALID_SIGNATURE, "%s", *sigerror);
SCReturnInt(FALSE); SCReturnInt(FALSE);
} }
return TRUE; return TRUE;

@ -59,7 +59,7 @@
static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, const char *); static int DetectHttpRawUriSetup(DetectEngineCtx *, Signature *, const char *);
static void DetectHttpRawUriRegisterTests(void); static void DetectHttpRawUriRegisterTests(void);
static void DetectHttpRawUriSetupCallback(Signature *s); static void DetectHttpRawUriSetupCallback(Signature *s);
static bool DetectHttpRawUriValidateCallback(const Signature *s); static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **);
static int g_http_raw_uri_buffer_id = 0; static int g_http_raw_uri_buffer_id = 0;
/** /**
@ -113,9 +113,9 @@ static int DetectHttpRawUriSetup(DetectEngineCtx *de_ctx, Signature *s, const ch
ALPROTO_HTTP); ALPROTO_HTTP);
} }
static bool DetectHttpRawUriValidateCallback(const Signature *s) static bool DetectHttpRawUriValidateCallback(const Signature *s, const char **sigerror)
{ {
return DetectUrilenValidateContent(s, g_http_raw_uri_buffer_id); return DetectUrilenValidateContent(s, g_http_raw_uri_buffer_id, sigerror);
} }
static void DetectHttpRawUriSetupCallback(Signature *s) static void DetectHttpRawUriSetupCallback(Signature *s)

@ -59,7 +59,7 @@
static void DetectHttpUriRegisterTests(void); static void DetectHttpUriRegisterTests(void);
static void DetectHttpUriSetupCallback(Signature *s); static void DetectHttpUriSetupCallback(Signature *s);
static bool DetectHttpUriValidateCallback(const Signature *s); static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror);
static int g_http_uri_buffer_id = 0; static int g_http_uri_buffer_id = 0;
@ -117,9 +117,9 @@ int DetectHttpUriSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
ALPROTO_HTTP); ALPROTO_HTTP);
} }
static bool DetectHttpUriValidateCallback(const Signature *s) static bool DetectHttpUriValidateCallback(const Signature *s, const char **sigerror)
{ {
return DetectUrilenValidateContent(s, g_http_uri_buffer_id); return DetectUrilenValidateContent(s, g_http_uri_buffer_id, sigerror);
} }
static void DetectHttpUriSetupCallback(Signature *s) static void DetectHttpUriSetupCallback(Signature *s)

@ -1487,7 +1487,7 @@ static int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
int x; int x;
for (x = 0; x < nlists; x++) { for (x = 0; x < nlists; x++) {
if (s->init_data->smlists[x]) { if (s->init_data->smlists[x]) {
if (DetectBufferRunValidateCallback(x, s) == FALSE) { if (DetectBufferRunValidateCallback(x, s, &de_ctx->sigerror) == FALSE) {
SCReturnInt(0); SCReturnInt(0);
} }
} }

@ -342,7 +342,7 @@ void DetectUrilenApplyToContent(Signature *s, int list)
} }
} }
bool DetectUrilenValidateContent(const Signature *s, int list) bool DetectUrilenValidateContent(const Signature *s, int list, const char **sigerror)
{ {
const SigMatch *sm = s->init_data->smlists[list]; const SigMatch *sm = s->init_data->smlists[list];
for ( ; sm != NULL; sm = sm->next) { for ( ; sm != NULL; sm = sm->next) {
@ -355,6 +355,7 @@ bool DetectUrilenValidateContent(const Signature *s, int list)
} }
if (cd->depth && cd->depth < cd->content_len) { if (cd->depth && cd->depth < cd->content_len) {
*sigerror = "depth or urilen smaller than content len";
SCLogError(SC_ERR_INVALID_SIGNATURE, "depth or urilen %u smaller " SCLogError(SC_ERR_INVALID_SIGNATURE, "depth or urilen %u smaller "
"than content len %u", cd->depth, cd->content_len); "than content len %u", cd->depth, cd->content_len);
return false; return false;

@ -36,7 +36,7 @@ typedef struct DetectUrilenData_ {
uint8_t raw_buffer; uint8_t raw_buffer;
}DetectUrilenData; }DetectUrilenData;
bool DetectUrilenValidateContent(const Signature *s, int list); bool DetectUrilenValidateContent(const Signature *s, int list, const char **);
void DetectUrilenApplyToContent(Signature *s, int list); void DetectUrilenApplyToContent(Signature *s, int list);
int DetectUrilenMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *, int DetectUrilenMatch (ThreadVars *, DetectEngineThreadCtx *, Flow *,
uint8_t, void *, Signature *, SigMatch *); uint8_t, void *, Signature *, SigMatch *);

@ -228,6 +228,7 @@
#include "util-optimize.h" #include "util-optimize.h"
#include "util-path.h" #include "util-path.h"
#include "util-mpm-ac.h" #include "util-mpm-ac.h"
#include "util-detect.h"
#include "runmodes.h" #include "runmodes.h"
#ifdef HAVE_GLOB_H #ifdef HAVE_GLOB_H
@ -372,6 +373,13 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file,
EngineAnalysisRulesFailure(line, sig_file, lineno - multiline); EngineAnalysisRulesFailure(line, sig_file, lineno - multiline);
} }
bad++; bad++;
if (!SigStringAppend(&de_ctx->sig_stat, sig_file, line, de_ctx->sigerror, (lineno - multiline))) {
SCLogError(SC_ERR_MEM_ALLOC, "Error adding sig \"%s\" from "
"file %s at line %"PRId32"", line, sig_file, lineno - multiline);
}
if (de_ctx->sigerror) {
de_ctx->sigerror = NULL;
}
} }
multiline = 0; multiline = 0;
} }

@ -574,8 +574,17 @@ typedef struct ThresholdCtx_ {
uint32_t th_size; uint32_t th_size;
} ThresholdCtx; } ThresholdCtx;
typedef struct SigString_ {
char *filename;
char *sig_str;
char *sig_error;
int line;
TAILQ_ENTRY(SigString_) next;
} SigString;
/** \brief Signature loader statistics */ /** \brief Signature loader statistics */
typedef struct SigFileLoaderStat_ { typedef struct SigFileLoaderStat_ {
TAILQ_HEAD(, SigString_) failed_sigs;
int bad_files; int bad_files;
int total_files; int total_files;
int good_sigs_total; int good_sigs_total;
@ -701,6 +710,7 @@ typedef struct DetectEngineCtx_ {
/** Store rule file and line so that parsers can use them in errors. */ /** Store rule file and line so that parsers can use them in errors. */
char *rule_file; char *rule_file;
int rule_line; int rule_line;
const char *sigerror;
/** list of keywords that need thread local ctxs */ /** list of keywords that need thread local ctxs */
DetectEngineThreadKeywordCtxItem *keyword_list; DetectEngineThreadKeywordCtxItem *keyword_list;

@ -0,0 +1,120 @@
/* Copyright (C) 2017 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Giuseppe Longo <glongo@stamus-networks.com>
*
* Detection engine helper functions
*/
#include "suricata-common.h"
#include "suricata.h"
#include "detect.h"
#include "util-detect.h"
/**
* \brief Allocate SigString list member
*
* \retval Pointer to SigString
*/
SigString *SigStringAlloc(void)
{
SigString *sigstr = SCCalloc(1, sizeof(SigString));
if (unlikely(sigstr == NULL))
return NULL;
sigstr->line = 0;
return sigstr;
}
/**
* \brief Assigns the filename, signature, lineno to SigString list member
*
* \param sig pointer to SigString
* \param sig_file filename that contains the signature
* \param sig_str signature in string format
* \param sig_error signature parsing error
* \param line line line number
*
* \retval 1 on success 0 on failure
*/
static int SigStringAddSig(SigString *sig, const char *sig_file,
const char *sig_str, const char *sig_error,
int line)
{
if (sig_file == NULL || sig_str == NULL) {
return 0;
}
sig->filename = SCStrdup(sig_file);
if (sig->filename == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
return 0;
}
sig->sig_str = SCStrdup(sig_str);
if (sig->sig_str == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
SCFree(sig->filename);
return 0;
}
if (sig_error) {
sig->sig_error = SCStrdup(sig_error);
if (sig->sig_error == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
SCFree(sig->filename);
SCFree(sig->sig_str);
return 0;
}
}
sig->line = line;
return 1;
}
/**
* \brief Append a new list member to SigString list
*
* \param list pointer to the start of the SigString list
* \param sig_file filename that contains the signature
* \param sig_str signature in string format
* \param line line line number
*
* \retval 1 on success 0 on failure
*/
int SigStringAppend(SigFileLoaderStat *sig_stats, const char *sig_file,
const char *sig_str, const char *sig_error, int line)
{
SigString *item = SigStringAlloc();
if (item == NULL) {
return 0;
}
if (!SigStringAddSig(item, sig_file, sig_str, sig_error, line)) {
SCFree(item);
return 0;
}
TAILQ_INSERT_TAIL(&sig_stats->failed_sigs, item, next);
return 1;
}

@ -0,0 +1,28 @@
/* Copyright (C) 2017 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
* \file
*
* \author Giuseppe Longo <glongo@stamus-networks.com>
*
* Detection engine helper functions
*/
SigString *SigStringAlloc(void);
int SigStringAppend(SigFileLoaderStat *sigs_stats, const char *sig_file, const char *sig_str,
const char *sig_error, int line);
Loading…
Cancel
Save