From: Massimiliano Hofer <max@nucleus.it>
To: netfilter-devel@lists.netfilter.org
Cc: Patrick McHardy <kaber@trash.net>
Subject: [PATCH 4/4][data-condition]: condition match
Date: Tue, 5 Dec 2006 23:18:15 +0100 [thread overview]
Message-ID: <200612052318.16324.max@nucleus.it> (raw)
In-Reply-To: <200612052312.28824.max@nucleus.it>
On Tuesday 5 December 2006 11:12 pm, Massimiliano Hofer wrote:
From 51ca538c78b5748a3521a6868cd4239231984bf0 Mon Sep 17 00:00:00 2001
From: Massimiliano Hofer <max@nucleus.it>
Date: Tue, 5 Dec 2006 23:02:29 +0100
Subject: [PATCH] [NETFILTER]: condition match
This patch adds the first match that makes use of the new instance specific data in netfilter.
This module allows you to match firewall rules against condition
variables stored in the /proc/net/nf_condition directory.
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 3a66878..fb4f07b 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -393,6 +393,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 5dc5574..36840e0 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -71,3 +71,4 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STRING)
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.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..91ec4d5
--- /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, void *data, int offset,
+ unsigned int protoff, int *hotdrop)
+{
+ const struct condition_info *info =
+ (const struct condition_info *)matchinfo;
+ struct condition_variable *var=
+ *(struct condition_variable **)data;
+
+ return var->enabled ^ info->invert;
+}
+
+
+static int
+init(const char *tablename, const void *ip,
+ const struct xt_match *match,
+ void *matchinfo, void *data,
+ unsigned int hook_mask)
+{
+ 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 **)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 **)data=newvar;
+
+ return 1;
+}
+
+
+static void
+destroy(const struct xt_match *match, void *matchinfo, void *data)
+{
+ struct condition_variable *var=
+ *(struct condition_variable **)data;
+
+ BUG_ON(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),
+ .datasize = 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),
+ .datasize = 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.3.3
next prev parent reply other threads:[~2006-12-05 22:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-12-05 22:12 [PATCH 0/4][data-condition] Massimiliano Hofer
2006-12-05 22:15 ` [PATCH 1/4][data-condition]: instance data support in matches' prototypes and structures Massimiliano Hofer
2006-12-05 22:16 ` [PATCH 2/4][data-condition]: instance data support in targets' " Massimiliano Hofer
2006-12-05 22:17 ` [PATCH 3/4][data-condition]: instance data support in netfilter core code Massimiliano Hofer
2006-12-05 22:18 ` Massimiliano Hofer [this message]
2006-12-05 22:22 ` [PATCH -/4][data-condition]: userspace code Massimiliano Hofer
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=200612052318.16324.max@nucleus.it \
--to=max@nucleus.it \
--cc=kaber@trash.net \
--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.