implement blackhole filters for logwatch, and stop applying filters after the first hit
--- a/config.lua Sun Apr 12 22:19:54 2009 +0300
+++ b/config.lua Sun Apr 12 23:27:15 2009 +0300
@@ -4,28 +4,57 @@
--
-- match all lines and output them as-is
-local function logwatch_filter_all ()
- return { pat=nil, fmt=nil }
+local function logwatch_filter_all (name)
+ return { name=name }
end
-- match using a regex pattern, but output the full line
-local function logwatch_filter_raw (pat)
- return { pat=pat, fmt=nil }
+local function logwatch_filter_raw (name, pat)
+ return { name=name, pat=pat }
end
-- match using a regexp pattern, and output a formatted line
-local function logwatch_filter (pat, fmt)
- return { pat=pat, fmt=fmt }
+local function logwatch_filter (name, pat, fmt)
+ return { name=name, pat=pat, fmt=fmt }
end
+-- match using a regexp pattern, and do *not* output
+local function logwatch_filter_blackhole (name, pat)
+ return { name=name, pat=pat, channel_is_null=true }
+end
+
+logwatch_timestamp_pat = "\\w{3} [0-9 ]\\d \\d{2}:\\d{2}:\\d{2}"
+
-- match auth.log sudo entries
-local function logwatch_filter_sudo ()
- return logwatch_filter(
- "(?P<hostname>\\S+)\\s+sudo:\\s*(?P<username>\\S+) : TTY=(?P<tty>\\S+) ; PWD=(?P<pwd>.+?) ; USER=(?P<target_user>\\S+) ; COMMAND=(?P<command>.*)",
+local function logwatch_filter_sudo (name)
+ return logwatch_filter(name,
+ "^" .. logwatch_timestamp_pat .. " (?P<hostname>\\S+)\\s+sudo:\\s*(?P<username>\\S+) : TTY=(?P<tty>\\S+) ; PWD=(?P<pwd>.+?) ; USER=(?P<target_user>\\S+) ; COMMAND=(?P<command>.*)$",
"{username}:{tty} - {target_user}@{hostname}:{pwd} - {command:r}"
)
end
+-- filter out the prefixed timestamp from lines
+local function logwatch_filter_strip_timestamp (name)
+ return logwatch_filter(name,
+ "^" .. logwatch_timestamp_pat .. " (?P<line>.+)$",
+ "{line}"
+ )
+end
+
+-- filter out auth.log cron messages
+local function logwatch_filter_no_cron (name)
+ return logwatch_filter_blackhole(name,
+ "^" .. logwatch_timestamp_pat .. " \\S+\\s+(CRON|su)\\[\\d+\\]: pam_unix\\(\\w+:\\w+\\): session (opened|closed) for user \\w+( by \\(uid=\\d+\\))?$"
+ )
+end
+
+-- filter out auth.log 'su for nobody by root' messages
+local function logwatch_filter_no_su_nobody (name)
+ return logwatch_filter_blackhole(name,
+ "^" .. logwatch_timestamp_pat .. " \\S+\\s+su\\[\\d+\\]: (Successful su for nobody by root|\\+ \\?\\?\\? root:nobody)$"
+ )
+end
+
--
-- Procedural config
--
@@ -71,8 +100,14 @@
module:conf("source_fifo", fifo_path)
source_name = fifo_path
- for filter_name, filter in pairs(settings.filters) do
- module:conf("filter", filter_name, source_name, filter.pat, filter.fmt, settings.channel)
+ for i, filter in ipairs(settings.filters) do
+ if filter.channel_is_null then
+ channel = nil
+ else
+ channel = settings.channel
+ end
+
+ module:conf("filter", filter.name, source_name, filter.pat, filter.fmt, channel)
end
end
end
@@ -116,11 +151,13 @@
channel = "PVLNet/#test",
filters = {
- ["test.foo"] = logwatch_filter_raw("foo"),
- ["test.sudo"] = logwatch_filter_sudo(),
+ logwatch_filter_raw ("test.foo", "foo" ),
+ logwatch_filter_sudo ("test.sudo" ),
+ logwatch_filter_no_cron ("test.no_cron" ),
+ logwatch_filter_no_su_nobody ("test.no_cron_su" ),
+ logwatch_filter_strip_timestamp ("test.all" )
}
},
},
}
-
--- a/src/error.c Sun Apr 12 22:19:54 2009 +0300
+++ b/src/error.c Sun Apr 12 23:27:15 2009 +0300
@@ -86,6 +86,10 @@
{ ERR_LUA_ERR, "lua: error handling error", ERR_EXTRA_STR },
{ ERR_LUA_FILE, "lua: error loading file", ERR_EXTRA_STR },
{ _ERR_INVALID, NULL, 0 }
+}, _pcre_error_desc[] = {
+ { ERR_PCRE_COMPILE, "pcre_compile", ERR_EXTRA_STR },
+ { ERR_PCRE_EXEC, "pcre_exec", ERR_EXTRA_STR },
+ { _ERR_INVALID, NULL, 0 }
};
/**
@@ -99,6 +103,7 @@
_config_error_desc,
_module_error_desc,
_lua_error_desc,
+ _pcre_error_desc,
NULL
};
--- a/src/irc_chan.c Sun Apr 12 22:19:54 2009 +0300
+++ b/src/irc_chan.c Sun Apr 12 23:27:15 2009 +0300
@@ -8,7 +8,7 @@
const char* irc_chan_name (struct irc_chan *chan)
{
- return chan->info.channel;
+ return chan ? chan->info.channel : "NULL";
}
/**
--- a/src/irc_net.c Sun Apr 12 22:19:54 2009 +0300
+++ b/src/irc_net.c Sun Apr 12 23:27:15 2009 +0300
@@ -7,7 +7,7 @@
const char* irc_net_name (struct irc_net *net)
{
- return net->info.network;
+ return net ? net->info.network : NULL;
}
/**
--- a/src/module.c Sun Apr 12 22:19:54 2009 +0300
+++ b/src/module.c Sun Apr 12 23:27:15 2009 +0300
@@ -102,7 +102,7 @@
const char* module_name (struct module *module)
{
- return module->info.name;
+ return module ? module->info.name : NULL;
}
/**
--- a/src/modules/logwatch.c Sun Apr 12 22:19:54 2009 +0300
+++ b/src/modules/logwatch.c Sun Apr 12 23:27:15 2009 +0300
@@ -50,11 +50,17 @@
{
const struct logwatch_filter *filter;
struct error_info err;
+ int ret;
// apply each filter
TAILQ_FOREACH(filter, &ctx->filters, logwatch_filters) {
- if (logwatch_filter_apply(filter, source, line, &err))
+ // apply it
+ if ((ret = logwatch_filter_apply(filter, source, line, &err)) < 0)
log_warn("logwatch_filter_apply(%s, %s, %s): %s", filter->name, source->name, line, error_msg(&err));
+
+ // blackhole?
+ if (ret > 0)
+ break;
}
}
@@ -101,7 +107,7 @@
struct logwatch_filter *filter;
const struct logwatch_source *source = NULL;
- struct logwatch_chan *chan;
+ struct logwatch_chan *chan = NULL;
const char *name, *source_name, *pattern, *format;
struct irc_chan *irc_chan;
@@ -123,7 +129,7 @@
RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown logwatch_source name");
// lookup channel
- if ((chan = logwatch_get_chan(ctx, irc_chan)) == NULL)
+ if (irc_chan && (chan = logwatch_get_chan(ctx, irc_chan)) == NULL)
RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "logwatch_get_chan failed");
log_info("add filter: name=%s, source=%s, pattern=%s, format=%s, chan=%s",
@@ -155,11 +161,11 @@
"using the given format expression (or pass through directly), and finally send the output to the given channel. "
"If a filter with the same name already exists, it will be replaced.",
- CONFIG_PARAM( "name", CONFIG_STRING, "filter name", false ),
- CONFIG_PARAM( "source", CONFIG_STRING, "optional logwatch_source to use", true ),
- CONFIG_PARAM( "pattern", CONFIG_STRING, "optional regular expression pattern", true ),
- CONFIG_PARAM( "format", CONFIG_STRING, "optional output format", true ),
- CONFIG_PARAM( "chan", CONFIG_IRC_CHAN, "channel to send output to", false )
+ CONFIG_PARAM( "name", CONFIG_STRING, "filter name", false ),
+ CONFIG_PARAM( "source", CONFIG_STRING, "optional logwatch_source to use", true ),
+ CONFIG_PARAM( "pattern", CONFIG_STRING, "optional regular expression pattern", true ),
+ CONFIG_PARAM( "format", CONFIG_STRING, "optional output format", true ),
+ CONFIG_PARAM( "chan", CONFIG_IRC_CHAN, "channel to send output to, or NULL to blackhole", true)
)
);
--- a/src/modules/logwatch.h Sun Apr 12 22:19:54 2009 +0300
+++ b/src/modules/logwatch.h Sun Apr 12 23:27:15 2009 +0300
@@ -194,9 +194,11 @@
void logwatch_filter_destroy (struct logwatch_filter *filter);
/**
- * Pass the given line (from the given source) through the given filter
+ * Pass the given line (from the given source) through the given filter.
+ *
+ * Returns 0 if the next filter should be tried, >0 if no more filters should be processed, and -err_t on error.
*/
-err_t logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err);
+int logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err);
/**
* Remove any filters registered with the given source
--- a/src/modules/logwatch_filter.c Sun Apr 12 22:19:54 2009 +0300
+++ b/src/modules/logwatch_filter.c Sun Apr 12 23:27:15 2009 +0300
@@ -69,16 +69,17 @@
void logwatch_filter_destroy (struct logwatch_filter *filter)
{
- // remove it if it's registered
if (filter->ctx)
+ // unreigster
TAILQ_REMOVE(&filter->ctx->filters, filter, logwatch_filters);
// this if is probably not needed
if (filter->regexp)
pcre_free(filter->regexp);
- // release the logwatch_chan ref
- logwatch_chan_put(filter->chan);
+ if (filter->chan)
+ // release the logwatch_chan ref
+ logwatch_chan_put(filter->chan);
// free misc
free(filter->format);
@@ -151,7 +152,7 @@
// length of output line prefix
#define LOGWATCH_FILTER_OUT_PREFIX_LEN 16
-err_t logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err)
+int logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err)
{
int ovec[LOGWATCH_FILTER_OVEC_ITEMS], ret;
char buf[LOGWATCH_FILTER_OUT_MAX + 1], *buf_ptr = buf;
@@ -161,23 +162,24 @@
// discard based on source?
if (filter->source && source != filter->source)
- return SUCCESS;
+ return 0;
// match against the regexp?
if (filter->regexp && (ret = pcre_exec(filter->regexp, NULL, line, strlen(line), 0, 0, ovec, LOGWATCH_FILTER_OVEC_ITEMS)) <= 0) {
if (ret == PCRE_ERROR_NOMATCH)
// no match, ignore
- return SUCCESS;
-
- else if (ret == 0)
- // too many match groups
- return SET_ERROR(err, -1);
+ return 0;
else
// misc. error
- RETURN_SET_ERROR_EXTRA(err, ERR_PCRE_EXEC, ret);
+ // XXX: might be 0 for too many groups
+ JUMP_SET_ERROR_EXTRA(err, ERR_PCRE_EXEC, ret);
}
+ // blackhole?
+ if (!filter->chan)
+ return 1;
+
// format?
if (filter->format) {
// setup the ctx
@@ -206,10 +208,10 @@
if ((ERROR_CODE(err) = logwatch_chan_msg(filter->chan, "[%s] %s", filter->name, buf)))
goto error;
- // ok
- return SUCCESS;
+ // ok, stop here
+ return 1;
error:
- return ERROR_CODE(err);
+ return -ERROR_CODE(err);
}