]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
condition: import 20080125 code base
authorJan Engelhardt <jengelh@computergmbh.de>
Wed, 26 Mar 2008 02:19:47 +0000 (03:19 +0100)
committerJan Engelhardt <jengelh@computergmbh.de>
Tue, 8 Apr 2008 09:58:33 +0000 (11:58 +0200)
extensions/Kbuild
extensions/Mbuild
extensions/libxt_condition.c [new file with mode: 0644]
extensions/libxt_condition.man [new file with mode: 0644]
extensions/xt_condition.Kconfig [new file with mode: 0644]
extensions/xt_condition.c [new file with mode: 0644]
extensions/xt_condition.h [new file with mode: 0644]
mconfig

index a88dff59ba787b2bdd4d7fb614e8e2b35934701a..9a06eb42b49bde9d18a055d4ee2c81418e30bea5 100644 (file)
@@ -11,6 +11,7 @@ obj-${build_ECHO}    += xt_ECHO.o
 obj-${build_LOGMARK} += xt_LOGMARK.o
 obj-${build_TARPIT}  += xt_TARPIT.o
 obj-${build_TEE}     += xt_TEE.o
+obj-${build_condition} += xt_condition.o
 obj-${build_geoip}    += xt_geoip.o
 obj-${build_portscan} += xt_portscan.o
 
index 336c3f24daf90c83e8d12feb076c1d11387cffec..c0060a45b4073a3caf5b841482a29991cedd2676 100644 (file)
@@ -4,5 +4,6 @@ obj-${build_ECHO}     += libxt_ECHO.so
 obj-${build_LOGMARK}  += libxt_LOGMARK.so
 obj-${build_TARPIT}   += libxt_TARPIT.so
 obj-${build_TEE}      += libxt_TEE.so
+obj-${build_condition} += libxt_condition.so
 obj-${build_geoip}    += libxt_geoip.so
 obj-${build_portscan} += libxt_portscan.so
diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c
new file mode 100644 (file)
index 0000000..bd520ae
--- /dev/null
@@ -0,0 +1,90 @@
+/* Shared library add-on to iptables for condition match */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <xtables.h>
+#include "xt_condition.h"
+
+static void condition_help(void)
+{
+       printf("condition match options:\n"
+              "--condition [!] filename       "
+              "Match on boolean value stored in /proc file\n");
+}
+
+static const struct option condition_opts[] = {
+       { .name = "condition", .has_arg = 1, .flag = 0, .val = 'X' },
+       { .name = 0 }
+};
+
+static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
+                           const void *entry, struct xt_entry_match **match)
+{
+       struct condition_info *info =
+           (struct condition_info *) (*match)->data;
+
+       if (c == 'X') {
+               if (*flags)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Can't specify multiple conditions");
+
+               check_inverse(optarg, &invert, &optind, 0);
+
+               if (strlen(argv[optind - 1]) < CONDITION_NAME_LEN)
+                       strcpy(info->name, argv[optind - 1]);
+               else
+                       exit_error(PARAMETER_PROBLEM,
+                                  "File name too long");
+
+               info->invert = invert;
+               *flags = 1;
+               return 1;
+       }
+
+       return 0;
+}
+
+static void condition_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "Condition match: must specify --condition");
+}
+
+static void condition_print(const void *ip, const struct xt_entry_match *match,
+                            int numeric)
+{
+       const struct condition_info *info =
+           (const struct condition_info *) match->data;
+
+       printf("condition %s%s ", (info->invert) ? "!" : "", info->name);
+}
+
+
+static void condition_save(const void *ip, const struct xt_entry_match *match)
+{
+       const struct condition_info *info =
+           (const struct condition_info *) match->data;
+
+       printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name);
+}
+
+static struct xtables_match condition_match = {
+       .name           = "condition",
+       .version        = XTABLES_VERSION,
+       .size           = XT_ALIGN(sizeof(struct condition_info)),
+       .userspacesize  = XT_ALIGN(sizeof(struct condition_info)),
+       .help           = condition_help,
+       .parse          = condition_parse,
+       .final_check    = condition_check,
+       .print          = condition_print,
+       .save           = condition_save,
+       .extra_opts     = condition_opts,
+};
+
+void _init(void);
+void _init(void)
+{
+       xtables_register_match(&condition_match);
+}
diff --git a/extensions/libxt_condition.man b/extensions/libxt_condition.man
new file mode 100644 (file)
index 0000000..ce2aa95
--- /dev/null
@@ -0,0 +1,4 @@
+This matches if a specific /proc filename is '0' or '1'.
+.TP
+.BI "--condition " "[!] \fIfilename\fP"
+Match on boolean value stored in /proc/net/ipt_condition/filename file
diff --git a/extensions/xt_condition.Kconfig b/extensions/xt_condition.Kconfig
new file mode 100644 (file)
index 0000000..896a2c9
--- /dev/null
@@ -0,0 +1,6 @@
+config NETFILTER_XT_MATCH_CONDITION
+       tristate '"condition" match support'
+       depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
+       ---help---
+       This option allows you to match firewall rules against condition
+       variables stored in the /proc/net/nf_condition directory.
diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c
new file mode 100644 (file)
index 0000000..de990d3
--- /dev/null
@@ -0,0 +1,345 @@
+/*-------------------------------------------*\
+|          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/version.h>
+#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 "xt_condition.h"
+#include "compat_xtables.h"
+
+#ifndef CONFIG_PROC_FS
+#error  "Proc file system support is required for this module"
+#endif
+
+/* Defaults, these can be overridden on the module command-line. */
+static unsigned int condition_list_perms = 0644;
+static unsigned int compat_dir_name = 0;
+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_param(compat_dir_name, bool, 0400);
+MODULE_PARM_DESC(compat_dir_name,"use old style /proc/net/ipt_condition/* files");
+MODULE_ALIAS("ipt_condition");
+MODULE_ALIAS("ip6t_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 const char *dir_name;
+
+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) != 0)
+                       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;
+}
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+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)
+#else
+bool
+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, bool *hotdrop)
+#endif
+{
+       const struct condition_info *info =
+           (const struct condition_info *) matchinfo;
+       struct condition_variable *var;
+       int condition_status = 0;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(var, &conditions_list, list) {
+               if (strcmp(info->name, var->status_proc->name) == 0) {
+                       condition_status = var->enabled;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return condition_status ^ info->invert;
+}
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static int
+#else
+bool
+#endif
+checkentry(const char *tablename, const void *ip,
+          const struct xt_match *match,
+          void *matchinfo,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+          unsigned int matchsize,
+#endif
+          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);
+                       return 1;
+               }
+       }
+
+       /* At this point, we need to allocate a new condition variable. */
+       newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
+
+       if (newvar == NULL) {
+               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 == NULL) {
+               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);
+
+       return 1;
+}
+
+
+static void
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+destroy(const struct xt_match *match, void *matchinfo,
+       unsigned int matchsize)
+#else
+destroy(const struct xt_match *match, void *matchinfo)
+#endif
+{
+       struct condition_info *info = (struct condition_info *) matchinfo;
+       struct list_head *pos;
+       struct condition_variable *var;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+       if (matchsize != XT_ALIGN(sizeof(struct condition_info)))
+               return;
+#endif
+
+       down(&proc_lock);
+
+       list_for_each(pos, &conditions_list) {
+               var = list_entry(pos, struct condition_variable, list);
+               if (strcmp(info->name, var->status_proc->name) == 0) {
+                       if (--var->refcount == 0) {
+                               list_del_rcu(pos);
+                               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;
+                       }
+                       break;
+               }
+       }
+
+       up(&proc_lock);
+}
+
+
+static struct xt_match condition_match = {
+       .name = "condition",
+       .family = PF_INET,
+       .matchsize = sizeof(struct condition_info),
+       .match = &match,
+       .checkentry = &checkentry,
+       .destroy = &destroy,
+       .me = THIS_MODULE
+};
+
+static struct xt_match condition6_match = {
+       .name = "condition",
+       .family = PF_INET6,
+       .matchsize = sizeof(struct condition_info),
+       .match = &match,
+       .checkentry = &checkentry,
+       .destroy = &destroy,
+       .me = THIS_MODULE
+};
+
+static int __init
+init(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+       struct proc_dir_entry * const proc_net=init_net.proc_net;
+#endif
+       int errorcode;
+
+       dir_name = compat_dir_name? "ipt_condition": "nf_condition";
+
+       proc_net_condition = proc_mkdir(dir_name, proc_net);
+       if (proc_net_condition == NULL) {
+               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
+fini(void)
+{
+       xt_unregister_match(&condition6_match);
+       xt_unregister_match(&condition_match);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+       remove_proc_entry(dir_name, init_net.proc_net);
+#else
+       remove_proc_entry(dir_name, proc_net);
+#endif
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/extensions/xt_condition.h b/extensions/xt_condition.h
new file mode 100644 (file)
index 0000000..f0706d0
--- /dev/null
@@ -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/mconfig b/mconfig
index dd2e0d5f3a399f6f8fcca1803bfdcfd5a6ead8cc..b78570e83d583527e7edd97fb28e0830a690e99e 100644 (file)
--- a/mconfig
+++ b/mconfig
@@ -6,5 +6,6 @@ build_ECHO=
 build_LOGMARK=m
 build_TARPIT=m
 build_TEE=m
+build_condition=m
 build_geoip=m
 build_portscan=m