diff --git a/configure.ac b/configure.ac index a846ec20e5..9372052098 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ AC_CHECK_HEADERS([sys/time.h time.h unistd.h]) AC_CHECK_HEADERS([sys/ioctl.h linux/if_ether.h linux/if_packet.h linux/filter.h]) AC_CHECK_HEADERS([linux/ethtool.h linux/sockios.h]) + AC_CHECK_HEADER(glob.h,,[AC_ERROR(glob.h not found ...)]) AC_CHECK_HEADERS([sys/socket.h net/if.h sys/mman.h linux/if_arp.h], [], [], [[#ifdef HAVE_SYS_SOCKET_H diff --git a/src/detect.c b/src/detect.c index b3bdbe16f5..4069a5d5b9 100644 --- a/src/detect.c +++ b/src/detect.c @@ -199,6 +199,10 @@ #include "runmodes.h" +#include + +extern int rule_reload; + extern int engine_analysis; static int fp_engine_analysis_set = 0; static int rule_engine_analysis_set = 0; @@ -287,8 +291,9 @@ char *DetectLoadCompleteSigPath(const DetectEngineCtx *de_ctx, char *sig_file) * \brief Load a file with signatures * \param de_ctx Pointer to the detection engine context * \param sig_file Filename to load signatures from - * \param sigs_tot Will store number of signatures processed in the file - * \retval Number of rules loaded successfully, -1 on error + * \param goodsigs_tot Will store number of valid signatures in the file + * \param badsigs_tot Will store number of invalid signatures in the file + * \retval 0 on success, -1 on error */ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, int *goodsigs, int *badsigs) @@ -302,11 +307,6 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, (*goodsigs) = 0; (*badsigs) = 0; - if (sig_file == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); - return -1; - } - FILE *fp = fopen(sig_file, "r"); if (fp == NULL) { SCLogError(SC_ERR_OPENING_RULE_FILE, "opening rule file %s:" @@ -373,15 +373,65 @@ static int DetectLoadSigFile(DetectEngineCtx *de_ctx, char *sig_file, } fclose(fp); - (*goodsigs) = good; - (*badsigs) = bad; + *goodsigs = good; + *badsigs = bad; return 0; } +/** + * \brief Expands wildcards and reads signatures from each matching file + * \param de_ctx Pointer to the detection engine context + * \param sig_file Filename (or pattern) holding signatures + * \retval -1 on error + */ +static int ProcessSigFiles(DetectEngineCtx *de_ctx, char *pattern, + SigFileLoaderStat *st, int *good_sigs, int *bad_sigs) +{ + if (pattern == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, "opening rule file null"); + return -1; + } + + glob_t files; + int r = glob(pattern, 0, NULL, &files); + + if (r == GLOB_NOMATCH) { + SCLogWarning(SC_ERR_NO_RULES, "No rule files match the pattern %s", pattern); + ++(st->bad_files); + return -1; + } else if (r != 0) { + SCLogError(SC_ERR_OPENING_RULE_FILE, "error expanding template %s: %s", + pattern, strerror(errno)); + return -1; + } + + for (size_t i = 0; i < (size_t)files.gl_pathc; i++) { + char *fname = files.gl_pathv[i]; + SCLogInfo("Loading rule file: %s", fname); + r = DetectLoadSigFile(de_ctx, fname, good_sigs, bad_sigs); + if (r < 0) { + ++(st->bad_files); + } + + ++(st->total_files); + + if (*good_sigs == 0) { + SCLogWarning(SC_ERR_NO_RULES, + "No rules loaded from %s", fname); + } + + st->good_sigs_total += *good_sigs; + st->bad_sigs_total += *bad_sigs; + } + + globfree(&files); + return r; +} + /** * \brief Load signatures * \param de_ctx Pointer to the detection engine context - * \param sig_file Filename holding signatures + * \param sig_file Filename (or pattern) holding signatures * \param sig_file_exclusive File passed in 'sig_file' should be loaded exclusively. * \retval -1 on error */ @@ -391,20 +441,14 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl ConfNode *rule_files; ConfNode *file = NULL; + SigFileLoaderStat sig_stat; int ret = 0; - int r = 0; - int cntf = 0; char *sfile = NULL; - - int goodsigs = 0; - int badsigs = 0; - - int badfiles = 0; - - int goodtotal = 0; - int badtotal = 0; - char varname[128] = "rule-files"; + int good_sigs = 0; + int bad_sigs = 0; + + memset(&sig_stat, 0, sizeof(SigFileLoaderStat)); if (strlen(de_ctx->config_prefix) > 0) { snprintf(varname, sizeof(varname), "%s.rule-files", @@ -428,21 +472,9 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl else { TAILQ_FOREACH(file, &rule_files->head, next) { sfile = DetectLoadCompleteSigPath(de_ctx, file->val); - SCLogDebug("Loading rule file: %s", sfile); - - cntf++; - r = DetectLoadSigFile(de_ctx, sfile, &goodsigs, &badsigs); - if (r < 0) { - badfiles++; - } - if (goodsigs == 0) { - SCLogWarning(SC_ERR_NO_RULES, - "No rules loaded from %s", sfile); - } + good_sigs = bad_sigs = 0; + ProcessSigFiles(de_ctx, sfile, &sig_stat, &good_sigs, &bad_sigs); SCFree(sfile); - - goodtotal += goodsigs; - badtotal += badsigs; } } } @@ -451,33 +483,35 @@ int SigLoadSignatures(DetectEngineCtx *de_ctx, char *sig_file, int sig_file_excl /* If a Signature file is specified from commandline, parse it too */ if (sig_file != NULL) { SCLogInfo("Loading rule file: %s", sig_file); - cntf++; - r = DetectLoadSigFile(de_ctx, sig_file, &goodsigs, &badsigs); - if (r < 0) { - badfiles++; + ++sig_stat.total_files; + + if (ProcessSigFiles(de_ctx, sig_file, &sig_stat, &good_sigs, &bad_sigs) != 0) { + ++sig_stat.bad_files; } - if (goodsigs == 0) { + + if (good_sigs == 0) { SCLogWarning(SC_ERR_NO_RULES, "No rules loaded from %s", sig_file); } - goodtotal += goodsigs; - badtotal += badsigs; + sig_stat.good_sigs_total += good_sigs; + sig_stat.bad_sigs_total += bad_sigs; } /* now we should have signatures to work with */ - if (goodsigs <= 0) { - if (cntf > 0) { - SCLogWarning(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", cntf); + if (sig_stat.good_sigs_total <= 0) { + if (sig_stat.total_files > 0) { + SCLogWarning(SC_ERR_NO_RULES_LOADED, "%d rule files specified, but no rule was loaded at all!", sig_stat.total_files); } else { SCLogInfo("No signatures supplied."); goto end; } } else { /* we report the total of files and rules successfully loaded and failed */ - SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", cntf, goodtotal, badtotal); + SCLogInfo("%" PRId32 " rule files processed. %" PRId32 " rules successfully loaded, %" PRId32 " rules failed", + sig_stat.total_files, sig_stat.good_sigs_total, sig_stat.bad_sigs_total); } - if ((badtotal || badfiles) && de_ctx->failure_fatal) { + if ((sig_stat.bad_sigs_total || sig_stat.bad_files) && de_ctx->failure_fatal) { ret = -1; goto end; } diff --git a/src/detect.h b/src/detect.h index 3b5ff6005c..fbed549fe1 100644 --- a/src/detect.h +++ b/src/detect.h @@ -1078,6 +1078,14 @@ typedef struct DetectEngineMasterCtx_ { DetectEngineCtx *free_list; } DetectEngineMasterCtx; +/** \brief Signature loader statistics */ +typedef struct SigFileLoaderStat_ { + int bad_files; + int total_files; + int good_sigs_total; + int bad_sigs_total; +} SigFileLoaderStat; + /** Remember to add the options in SignatureIsIPOnly() at detect.c otherwise it wont be part of a signature group */ enum {