[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