[syslog-ng] [PATCH] filter: Implement an in-list() filter
Gergely Nagy
algernon at balabit.hu
Wed Sep 4 16:11:17 CEST 2013
The in-list filter allows us to do simple file-based black- or
whitelisting. The syntax is:
filter f_whitelist { in-list("/path/to/file.list", value("PROGRAM")); };
Implementing a blacklist is as simple as negating the in-list() filter.
The filter works by pulling in the whole file (one entry per line) and
putting it into a tree structure, and comparing against that on eval.
Signed-off-by: Gergely Nagy <algernon at balabit.hu>
---
Makefile.am | 2 +
lib/filter/Makefile.am | 2 +
lib/filter/filter-expr-grammar.ym | 21 ++++++-
lib/filter/filter-expr-parser.c | 1 +
lib/filter/filter-in-list.c | 95 +++++++++++++++++++++++++++++++
lib/filter/filter-in-list.h | 33 +++++++++++
lib/filter/tests/Makefile.am | 13 ++++-
lib/filter/tests/test.list | 1 +
lib/filter/tests/test_filters_in_list.c | 53 +++++++++++++++++
9 files changed, 215 insertions(+), 6 deletions(-)
create mode 100644 lib/filter/filter-in-list.c
create mode 100644 lib/filter/filter-in-list.h
create mode 100644 lib/filter/tests/test.list
create mode 100644 lib/filter/tests/test_filters_in_list.c
diff --git a/Makefile.am b/Makefile.am
index 265de8d..345ee76 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,8 @@
SUBDIRS =
AM_MAKEFLAGS = --no-print-directory
+AM_TESTS_ENVIRONMENT = top_srcdir="$(top_srcdir)"
+
ACLOCAL_AMFLAGS = -I m4 --install
EXTRA_DIST = ${BUILT_SOURCES} VERSION \
diff --git a/lib/filter/Makefile.am b/lib/filter/Makefile.am
index 7425491..aeb4f2b 100644
--- a/lib/filter/Makefile.am
+++ b/lib/filter/Makefile.am
@@ -2,6 +2,7 @@ filter_headers = \
lib/filter/filter-expr.h \
lib/filter/filter-op.h \
lib/filter/filter-cmp.h \
+ lib/filter/filter-in-list.h \
lib/filter/filter-tags.h \
lib/filter/filter-netmask.h \
lib/filter/filter-call.h \
@@ -14,6 +15,7 @@ filter_sources = \
lib/filter/filter-expr.c \
lib/filter/filter-op.c \
lib/filter/filter-cmp.c \
+ lib/filter/filter-in-list.c \
lib/filter/filter-tags.c \
lib/filter/filter-netmask.c \
lib/filter/filter-call.c \
diff --git a/lib/filter/filter-expr-grammar.ym b/lib/filter/filter-expr-grammar.ym
index 1d4fec4..a41932b 100644
--- a/lib/filter/filter-expr-grammar.ym
+++ b/lib/filter/filter-expr-grammar.ym
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002-2011 BalaBit IT Ltd, Budapest, Hungary
+ * Copyright (c) 2002-2013 BalaBit IT Ltd, Budapest, Hungary
* Copyright (c) 1998-2011 Balázs Scheidler
*
* This library is free software; you can redistribute it and/or
@@ -34,6 +34,7 @@
#include "filter/filter-netmask.h"
#include "filter/filter-op.h"
#include "filter/filter-cmp.h"
+#include "filter/filter-in-list.h"
#include "filter/filter-tags.h"
#include "filter/filter-call.h"
#include "filter/filter-re.h"
@@ -55,7 +56,7 @@ FilterRE *last_re_filter;
/* INCLUDE_DECLS */
-%token KW_PROGRAM
+%token KW_PROGRAM KW_IN_LIST
%left ';'
%left KW_OR
@@ -96,7 +97,21 @@ filter_simple_expr
| KW_FILTER '(' string ')' { $$ = filter_call_new($3, configuration); free($3); }
| KW_NETMASK '(' string ')' { $$ = filter_netmask_new($3); free($3); }
| KW_TAGS '(' string_list ')' { $$ = filter_tags_new($3); }
- | KW_PROGRAM '(' string
+ | KW_IN_LIST '(' string string ')'
+ {
+ const gchar *p = $4;
+ if (p[0] == '$')
+ {
+ msg_warning("Value references in filters should not use the '$' prefix, those are only needed in templates",
+ evt_tag_str("value", $4),
+ NULL);
+ p++;
+ }
+ $$ = filter_in_list_new($3, p);
+ free($3);
+ free($4);
+ }
+ | KW_PROGRAM '(' string
{
last_re_filter = (FilterRE *) filter_re_new(LM_V_PROGRAM);
}
diff --git a/lib/filter/filter-expr-parser.c b/lib/filter/filter-expr-parser.c
index c2c2e7b..781220a 100644
--- a/lib/filter/filter-expr-parser.c
+++ b/lib/filter/filter-expr-parser.c
@@ -55,6 +55,7 @@ static CfgLexerKeyword filter_expr_keywords[] = {
{ "match", KW_MATCH },
{ "netmask", KW_NETMASK },
{ "tags", KW_TAGS, 0x0301 },
+ { "in_list", KW_IN_LIST, 0x0305 },
{ "type", KW_TYPE, 0x0300 },
{ "value", KW_VALUE, 0x0300 },
diff --git a/lib/filter/filter-in-list.c b/lib/filter/filter-in-list.c
new file mode 100644
index 0000000..6736196
--- /dev/null
+++ b/lib/filter/filter-in-list.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013 BalaBit IT Ltd, Budapest, Hungary
+ * Copyright (c) 2013 Gergely Nagy <algernon at balabit.hu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * As an additional exemption you are allowed to compile & link against the
+ * OpenSSL libraries as published by the OpenSSL project. See the file
+ * COPYING for details.
+ *
+ */
+
+#include "filter-in-list.h"
+#include "logmsg.h"
+#include "misc.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct _FilterInList
+{
+ FilterExprNode super;
+ NVHandle value_handle;
+ GTree *tree;
+} FilterInList;
+
+static gboolean
+filter_in_list_eval(FilterExprNode *s, LogMessage **msgs, gint num_msg)
+{
+ FilterInList *self = (FilterInList *)s;
+ LogMessage *msg = msgs[0];
+ const gchar *value;
+ gssize len = 0;
+
+ value = log_msg_get_value(msg, self->value_handle, &len);
+ APPEND_ZERO(value, value, len);
+
+ return (g_tree_lookup(self->tree, value) != NULL) ^ s->comp;
+}
+
+static void
+filter_in_list_free(FilterExprNode *s)
+{
+ FilterInList *self = (FilterInList *)s;
+
+ g_tree_unref(self->tree);
+}
+
+FilterExprNode *
+filter_in_list_new(const gchar *list_file, const gchar *property)
+{
+ FilterInList *self;
+ FILE *stream;
+ size_t n;
+ gchar *line = NULL;
+
+ stream = fopen(list_file, "r");
+ if (!stream)
+ {
+ msg_error("Error opening in-list filter list file",
+ evt_tag_str("file", list_file),
+ evt_tag_errno("errno", errno),
+ NULL);
+ return NULL;
+ }
+
+ self = g_new0(FilterInList, 1);
+ filter_expr_node_init(&self->super);
+ self->value_handle = log_msg_get_value_handle(property);
+ self->tree = g_tree_new((GCompareFunc) strcmp);
+
+ while (getline(&line, &n, stream) != -1)
+ {
+ line[strlen(line) - 1] = '\0';
+ g_tree_insert(self->tree, line, GINT_TO_POINTER(1));
+ line = NULL;
+ }
+ fclose(stream);
+
+ self->super.eval = filter_in_list_eval;
+ self->super.free_fn = filter_in_list_free;
+ return &self->super;
+}
diff --git a/lib/filter/filter-in-list.h b/lib/filter/filter-in-list.h
new file mode 100644
index 0000000..9cf3c0d
--- /dev/null
+++ b/lib/filter/filter-in-list.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 BalaBit IT Ltd, Budapest, Hungary
+ * Copyright (c) 2013 Gergely Nagy <algernon at balabit.hu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * As an additional exemption you are allowed to compile & link against the
+ * OpenSSL libraries as published by the OpenSSL project. See the file
+ * COPYING for details.
+ *
+ */
+
+#ifndef FILTER_IN_LIST_H_INCLUDED
+#define FILTER_IN_LIST_H_INCLUDED
+
+#include "filter-expr.h"
+
+FilterExprNode *filter_in_list_new(const gchar *list_file,
+ const gchar *property);
+
+#endif
diff --git a/lib/filter/tests/Makefile.am b/lib/filter/tests/Makefile.am
index 2b1e11a..3d72441 100644
--- a/lib/filter/tests/Makefile.am
+++ b/lib/filter/tests/Makefile.am
@@ -1,13 +1,20 @@
lib_filter_tests_TESTS = \
- lib/filter/tests/test_filters
+ lib/filter/tests/test_filters \
+ lib/filter/tests/test_filters_in_list
check_PROGRAMS += ${lib_filter_tests_TESTS}
lib_filter_tests_test_filters_CFLAGS = $(TEST_CFLAGS) \
-I${top_srcdir}/lib/filter/tests
-
lib_filter_tests_test_filters_LDADD = $(TEST_LDADD) \
$(PREOPEN_SYSLOGFORMAT)
-
lib_filter_tests_test_filters_SOURCES = \
lib/filter/tests/test_filters.c
+
+lib_filter_tests_test_filters_in_list_CFLAGS = $(TEST_CFLAGS) \
+ -I${top_srcdir}/lib/filter/tests
+lib_filter_tests_test_filters_in_list_LDADD = $(TEST_LDADD) \
+ $(PREOPEN_SYSLOGFORMAT)
+
+EXTRA_DIST += \
+ lib/filter/tests/test.list
diff --git a/lib/filter/tests/test.list b/lib/filter/tests/test.list
new file mode 100644
index 0000000..dca8351
--- /dev/null
+++ b/lib/filter/tests/test.list
@@ -0,0 +1 @@
+test-program
diff --git a/lib/filter/tests/test_filters_in_list.c b/lib/filter/tests/test_filters_in_list.c
new file mode 100644
index 0000000..9844fa2
--- /dev/null
+++ b/lib/filter/tests/test_filters_in_list.c
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <glib.h>
+
+#include "cfg.h"
+#include "messages.h"
+#include "syslog-names.h"
+#include "logmsg.h"
+#include "apphook.h"
+#include "plugin.h"
+#include "filter/filter-in-list.h"
+
+#include "testutils.h"
+
+static MsgFormatOptions parse_options;
+
+static LogMessage *
+create_test_message (void)
+{
+ const gchar *log_message = "<15>Sep 4 15:03:55 localhost test-program[3086]: some random message";
+
+ return log_msg_new(log_message, strlen(log_message), NULL, &parse_options);
+}
+
+int
+main(int argc G_GNUC_UNUSED, char *argv[] G_GNUC_UNUSED)
+{
+ LogMessage *msg;
+ FilterExprNode *filter_node;
+ char *top_srcdir = getenv("top_srcdir");
+ gchar *list_file;
+
+ app_startup();
+
+ configuration = cfg_new(0x0305);
+ plugin_load_module("syslogformat", configuration, NULL);
+ msg_format_options_defaults(&parse_options);
+ msg_format_options_init(&parse_options, configuration);
+
+ assert_not_null(top_srcdir, "The $top_srcdir environment variable MUST NOT be empty!");
+
+ list_file = g_strdup_printf("%s/lib/filter/tests/test.list", top_srcdir);
+ filter_node = filter_in_list_new(list_file, "PROGRAM");
+ assert_not_null(filter_node, "Constructing an in-list filter");
+ g_free (list_file);
+
+ msg = create_test_message();
+
+ assert_true(filter_expr_eval(filter_node, msg), "in-list filter matches");
+
+ app_shutdown();
+
+ return 0;
+}
--
1.7.10.4
More information about the syslog-ng
mailing list