All of lore.kernel.org
 help / color / mirror / Atom feed
From: Massimiliano Hofer <max@nucleus.it>
To: netfilter-devel@lists.netfilter.org
Subject: [PATCH 2/2][priv_data-condition] xt_condition
Date: Mon, 25 Sep 2006 00:42:10 +0200	[thread overview]
Message-ID: <200609250042.10931.max@nucleus.it> (raw)

From fad7ddb4c6c1daa2b2bbd88756a5f88824ff8bdb Mon Sep 17 00:00:00 2001
From: Massimiliano Hofer <max@nucleus.it>
Date: Mon, 25 Sep 2006 00:38:14 +0200
Subject: [PATCH] xt_condition

This patch implements the condition match.
It needs priv_data.

Signed-off-by: Massimiliano Hofer <max@nucleus.it>
---
 include/linux/netfilter/xt_condition.h |   11 +
 net/netfilter/Kconfig                  |   10 +
 net/netfilter/Makefile                 |    1 
 net/netfilter/xt_condition.c           |  292 ++++++++++++++++++++++++++++++++
 4 files changed, 314 insertions(+), 0 deletions(-)

diff --git a/include/linux/netfilter/xt_condition.h b/include/linux/netfilter/xt_condition.h
new file mode 100644
index 0000000..f0706d0
--- /dev/null
+++ b/include/linux/netfilter/xt_condition.h
@@ -0,0 +1,11 @@
+#ifndef _XT_CONDITION_H
+#define _XT_CONDITION_H
+
+#define CONDITION_NAME_LEN  32
+
+struct condition_info {
+	char name[CONDITION_NAME_LEN];
+	int  invert;
+};
+
+#endif /* _XT_CONDITION_H */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 0a28d2c..4b6c9fc 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -228,6 +228,16 @@ config NETFILTER_XT_MATCH_COMMENT
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+config NETFILTER_XT_MATCH_CONDITION
+        tristate  '"condition" match support'
+        depends on NETFILTER_XTABLES && PROC_FS
+        help
+          This option allows you to match firewall rules against condition
+          variables stored in the /proc/net/nf_condition directory.
+
+          If you want to compile it as a module, say M here and read
+          Documentation/modules.txt.  If unsure, say `N'.
+
 config NETFILTER_XT_MATCH_CONNBYTES
 	tristate  '"connbytes" per-connection counter match support'
 	depends on NETFILTER_XTABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index a74be49..1cbd4ac 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTI
 obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_condition.o
diff --git a/net/netfilter/xt_condition.c b/net/netfilter/xt_condition.c
new file mode 100644
index 0000000..ec508dd
--- /dev/null
+++ b/net/netfilter/xt_condition.c
@@ -0,0 +1,292 @@
+/*-------------------------------------------*\
+|          Netfilter Condition Module         |
+|                                             |
+|  Description: This module allows firewall   |
+|    rules to match using condition variables |
+|    stored in /proc files.                   |
+|                                             |
+|  Author: Stephane Ouellette     2002-10-22  |
+|          <ouellettes@videotron.ca>          |
+|          Massimiliano Hofer     2006-05-15  |
+|          <max@nucleus.it>                   |
+|                                             |
+|  History:                                   |
+|    2003-02-10  Second version with improved |
+|                locking and simplified code. |
+|    2006-05-15  2.6.16 adaptations.          |
+|                Locking overhaul.            |
+|                Various bug fixes.           |
+|                                             |
+|  This software is distributed under the     |
+|  terms of the GNU GPL.                      |
+\*-------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/semaphore.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_condition.h>
+
+/* Defaults, these can be overridden on the module command-line. */
+static unsigned int condition_list_perms = 0600;
+static unsigned int condition_uid_perms = 0;
+static unsigned int condition_gid_perms = 0;
+
+MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca> and Massimiliano Hofer <max@nucleus.it>");
+MODULE_DESCRIPTION("Allows rules to match against condition variables");
+MODULE_LICENSE("GPL");
+module_param(condition_list_perms, uint, 0600);
+MODULE_PARM_DESC(condition_list_perms,"permissions on /proc/net/nf_condition/* files");
+module_param(condition_uid_perms, uint, 0600);
+MODULE_PARM_DESC(condition_uid_perms,"user owner of /proc/net/nf_condition/* files");
+module_param(condition_gid_perms, uint, 0600);
+MODULE_PARM_DESC(condition_gid_perms,"group owner of /proc/net/nf_condition/* files");
+MODULE_ALIAS("ipt_condition");
+MODULE_ALIAS("ip6t_condition");
+
+static const char dir_name[]="nf_condition";
+
+struct condition_variable {
+	struct list_head list;
+	struct proc_dir_entry *status_proc;
+	unsigned int refcount;
+        int enabled;   /* TRUE == 1, FALSE == 0 */
+};
+
+/* proc_lock is a user context only semaphore used for write access */
+/*           to the conditions' list.                               */
+static DECLARE_MUTEX(proc_lock);
+
+static LIST_HEAD(conditions_list);
+static struct proc_dir_entry *proc_net_condition = NULL;
+
+static int
+xt_condition_read_info(char __user *buffer, char **start, off_t offset,
+			int length, int *eof, void *data)
+{
+	struct condition_variable *var =
+	    (struct condition_variable *) data;
+
+	buffer[0] = (var->enabled) ? '1' : '0';
+	buffer[1] = '\n';
+	if (length>=2)
+		*eof = 1;
+
+	return 2;
+}
+
+
+static int
+xt_condition_write_info(struct file *file, const char __user *buffer,
+			unsigned long length, void *data)
+{
+	struct condition_variable *var =
+	    (struct condition_variable *) data;
+	char newval;
+
+	if (length>0) {
+		if (get_user(newval, buffer))
+			return -EFAULT;
+	        /* Match only on the first character */
+		switch (newval) {
+		case '0':
+			var->enabled = 0;
+			break;
+		case '1':
+			var->enabled = 1;
+			break;
+		}
+	}
+
+	return (int) length;
+}
+
+
+static int
+match(const struct sk_buff *skb, const struct net_device *in,
+      const struct net_device *out, const struct xt_match *match,
+      const void *matchinfo, int offset,
+      unsigned int protoff, int *hotdrop, void *priv_data)
+{
+	const struct condition_info *info =
+		(const struct condition_info *)matchinfo;
+	struct condition_variable *var=
+		*(struct condition_variable **)priv_data;
+
+	return var->enabled ^ info->invert;
+}
+
+
+static int
+init(const char *tablename, const void *ip,
+     const struct xt_match *match,
+     void *matchinfo,
+     unsigned int hook_mask, void *priv_data)
+{
+	static const char * const forbidden_names[]={ "", ".", ".." };
+	struct condition_info *info = (struct condition_info *) matchinfo;
+	struct list_head *pos;
+	struct condition_variable *var, *newvar;
+
+	int i;
+
+	/* We don't want a '/' in a proc file name. */
+	for (i=0; i < CONDITION_NAME_LEN && info->name[i] != '\0'; i++)
+		if (info->name[i] == '/')
+			return 0;
+	/* We can't handle file names longer than CONDITION_NAME_LEN and */
+	/* we want a NULL terminated string. */
+	if (i == CONDITION_NAME_LEN)
+		return 0;
+
+	/* We don't want certain reserved names. */
+	for (i=0; i < sizeof(forbidden_names)/sizeof(char *); i++)
+		if(strcmp(info->name, forbidden_names[i])==0)
+			return 0;
+
+	/* Let's acquire the lock, check for the condition and add it */
+	/* or increase the reference counter.                         */
+	if (down_interruptible(&proc_lock))
+	   return -EINTR;
+
+	list_for_each(pos, &conditions_list) {
+		var = list_entry(pos, struct condition_variable, list);
+		if (strcmp(info->name, var->status_proc->name) == 0) {
+			var->refcount++;
+			up(&proc_lock);
+			*(struct condition_variable **)priv_data=var;
+			return 1;
+		}
+	}
+
+	/* At this point, we need to allocate a new condition variable. */
+	newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
+
+	if (!newvar) {
+		up(&proc_lock);
+		return -ENOMEM;
+	}
+
+	/* Create the condition variable's proc file entry. */
+	newvar->status_proc = create_proc_entry(info->name, condition_list_perms, proc_net_condition);
+
+	if (!newvar->status_proc) {
+		kfree(newvar);
+		up(&proc_lock);
+		return -ENOMEM;
+	}
+
+	newvar->refcount = 1;
+	newvar->enabled = 0;
+	newvar->status_proc->owner = THIS_MODULE;
+	newvar->status_proc->data = newvar;
+	wmb();
+	newvar->status_proc->read_proc = xt_condition_read_info;
+	newvar->status_proc->write_proc = xt_condition_write_info;
+
+	list_add_rcu(&newvar->list, &conditions_list);
+
+	newvar->status_proc->uid = condition_uid_perms;
+	newvar->status_proc->gid = condition_gid_perms;
+
+	up(&proc_lock);
+
+	*(struct condition_variable **)priv_data=newvar;
+
+	return 1;
+}
+
+
+static void
+destroy(const struct xt_match *match, void *matchinfo, void *priv_data)
+{
+	struct condition_variable *var=
+		*(struct condition_variable **)priv_data;
+
+	BUG_ON(priv_data==NULL);
+	BUG_ON(var==NULL);
+
+	down(&proc_lock);
+
+	if (--var->refcount == 0) {
+		list_del_rcu(&var->list);
+		remove_proc_entry(var->status_proc->name, proc_net_condition);
+		up(&proc_lock);
+		/* synchronize_rcu() would be goog enough, but         */
+		/* synchronize_net() guarantees that no packet will go */
+		/* out with the old rule after succesful removal.      */
+		synchronize_net();
+		kfree(var);
+		return;
+	}
+
+	up(&proc_lock);
+}
+
+
+static struct xt_match condition_match = {
+	.name		= "condition",
+	.family		= AF_INET,
+	.matchsize	= sizeof(struct condition_info),
+	.priv_size	= sizeof(struct condition_variable *),
+	.match		= match,
+	.init		= init,
+	.destroy	= destroy,
+	.me		= THIS_MODULE
+};
+
+static struct xt_match condition6_match = {
+	.name		= "condition",
+	.family		= AF_INET6,
+	.matchsize	= sizeof(struct condition_info),
+	.priv_size	= sizeof(struct condition_variable *),
+	.match		= match,
+	.init		= init,
+	.destroy	= destroy,
+	.me		= THIS_MODULE
+};
+
+static int __init xt_condition_init(void)
+{
+	int errorcode;
+
+	proc_net_condition = proc_mkdir(dir_name, proc_net);
+	if (!proc_net_condition) {
+		remove_proc_entry(dir_name, proc_net);
+		return -EACCES;
+	}
+
+        errorcode = xt_register_match(&condition_match);
+	if (errorcode) {
+		xt_unregister_match(&condition_match);
+		remove_proc_entry(dir_name, proc_net);
+		return errorcode;
+	}
+
+	errorcode = xt_register_match(&condition6_match);
+	if (errorcode) {
+		xt_unregister_match(&condition6_match);
+		xt_unregister_match(&condition_match);
+		remove_proc_entry(dir_name, proc_net);
+		return errorcode;
+	}
+
+	return 0;
+}
+
+
+static void __exit xt_condition_fini(void)
+{
+	xt_unregister_match(&condition6_match);
+	xt_unregister_match(&condition_match);
+	remove_proc_entry(dir_name, proc_net);
+}
+
+module_init(xt_condition_init);
+module_exit(xt_condition_fini);
-- 
1.4.2

                 reply	other threads:[~2006-09-24 22:42 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200609250042.10931.max@nucleus.it \
    --to=max@nucleus.it \
    --cc=netfilter-devel@lists.netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.