From 72dc73e6a5fea722207952d461ae5f444e305d11 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 26 Mar 2008 03:19:47 +0100 Subject: [PATCH 01/12] condition: import 20080125 code base --- extensions/Kbuild | 1 + extensions/Mbuild | 1 + extensions/libxt_condition.c | 90 +++++++++ extensions/libxt_condition.man | 4 + extensions/xt_condition.Kconfig | 6 + extensions/xt_condition.c | 345 ++++++++++++++++++++++++++++++++ extensions/xt_condition.h | 11 + mconfig | 1 + 8 files changed, 459 insertions(+) create mode 100644 extensions/libxt_condition.c create mode 100644 extensions/libxt_condition.man create mode 100644 extensions/xt_condition.Kconfig create mode 100644 extensions/xt_condition.c create mode 100644 extensions/xt_condition.h diff --git a/extensions/Kbuild b/extensions/Kbuild index a88dff5..9a06eb4 100644 --- a/extensions/Kbuild +++ b/extensions/Kbuild @@ -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 diff --git a/extensions/Mbuild b/extensions/Mbuild index 336c3f2..c0060a4 100644 --- a/extensions/Mbuild +++ b/extensions/Mbuild @@ -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 index 0000000..bd520ae --- /dev/null +++ b/extensions/libxt_condition.c @@ -0,0 +1,90 @@ +/* Shared library add-on to iptables for condition match */ +#include +#include +#include +#include +#include +#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 index 0000000..ce2aa95 --- /dev/null +++ b/extensions/libxt_condition.man @@ -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 index 0000000..896a2c9 --- /dev/null +++ b/extensions/xt_condition.Kconfig @@ -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 index 0000000..de990d3 --- /dev/null +++ b/extensions/xt_condition.c @@ -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 | +| | +| Massimiliano Hofer 2006-05-15 | +| | +| | +| 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 and Massimiliano Hofer "); +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 index 0000000..f0706d0 --- /dev/null +++ b/extensions/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/mconfig b/mconfig index dd2e0d5..b78570e 100644 --- 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 From 330c1fe783fc733310b14cac88e196892bbf530d Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 04:23:45 +0200 Subject: [PATCH 02/12] condition: remove version #ifs and compat selectors --- extensions/libxt_condition.c | 2 +- extensions/xt_condition.c | 83 +++++++++--------------------------- 2 files changed, 22 insertions(+), 63 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index bd520ae..f6304c9 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -47,7 +47,7 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags, static void condition_check(unsigned int flags) { - if (!flags) + if (flags == 0) exit_error(PARAMETER_PROBLEM, "Condition match: must specify --condition"); } diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index de990d3..5733cba 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -38,10 +38,12 @@ #ifndef CONFIG_PROC_FS #error "Proc file system support is required for this module" #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +# define proc_net init_net.proc_net +#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; @@ -54,8 +56,6 @@ 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"); @@ -72,7 +72,6 @@ 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, @@ -115,20 +114,11 @@ xt_condition_write_info(struct file *file, const char __user *buffer, 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 +static bool +condition_mt(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) { const struct condition_info *info = (const struct condition_info *) matchinfo; @@ -147,20 +137,10 @@ match(const struct sk_buff *skb, const struct net_device *in, 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 bool +condition_mt_check(const char *tablename, const void *entry, + const struct xt_match *match, void *matchinfo, + unsigned int hook_mask) { static const char * const forbidden_names[]={ "", ".", ".." }; struct condition_info *info = (struct condition_info *) matchinfo; @@ -232,24 +212,12 @@ checkentry(const char *tablename, const void *ip, 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 +static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) { 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) { @@ -273,14 +241,13 @@ destroy(const struct xt_match *match, void *matchinfo) 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, + .match = condition_mt, + .checkentry = condition_mt_check, + .destroy = condition_mt_destroy, .me = THIS_MODULE }; @@ -288,22 +255,19 @@ static struct xt_match condition6_match = { .name = "condition", .family = PF_INET6, .matchsize = sizeof(struct condition_info), - .match = &match, - .checkentry = &checkentry, - .destroy = &destroy, + .match = condition_mt, + .checkentry = condition_mt_check, + .destroy = condition_mt_destroy, .me = THIS_MODULE }; +static const char *const dir_name = "nf_condition"; + 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); @@ -328,17 +292,12 @@ init(void) 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); From 7d0efafdb36675c75ac4f7b0b62df36922e0a587 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 04:31:52 +0200 Subject: [PATCH 03/12] condition: remove casts, add const qualifiers --- extensions/libxt_condition.c | 12 ++++-------- extensions/xt_condition.c | 15 ++++++--------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index f6304c9..f295954 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -21,8 +21,7 @@ static const struct option condition_opts[] = { 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; + struct condition_info *info = (void *)(*match)->data; if (c == 'X') { if (*flags) @@ -55,8 +54,7 @@ static void condition_check(unsigned int flags) 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; + const struct condition_info *info = (const void *)match->data; printf("condition %s%s ", (info->invert) ? "!" : "", info->name); } @@ -64,8 +62,7 @@ static void condition_print(const void *ip, const struct xt_entry_match *match, static void condition_save(const void *ip, const struct xt_entry_match *match) { - const struct condition_info *info = - (const struct condition_info *) match->data; + const struct condition_info *info = (const void *)match->data; printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name); } @@ -83,8 +80,7 @@ static struct xtables_match condition_match = { .extra_opts = condition_opts, }; -void _init(void); -void _init(void) +static void _init(void) { xtables_register_match(&condition_match); } diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index 5733cba..c9e16a3 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -77,8 +77,7 @@ 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; + const struct condition_variable *var = data; buffer[0] = (var->enabled) ? '1' : '0'; buffer[1] = '\n'; @@ -93,8 +92,7 @@ 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; + struct condition_variable *var = data; char newval; if (length>0) { @@ -111,7 +109,7 @@ xt_condition_write_info(struct file *file, const char __user *buffer, } } - return (int) length; + return length; } static bool @@ -120,8 +118,7 @@ condition_mt(const struct sk_buff *skb, const struct net_device *in, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - const struct condition_info *info = - (const struct condition_info *) matchinfo; + const struct condition_info *info = matchinfo; struct condition_variable *var; int condition_status = 0; @@ -143,7 +140,7 @@ condition_mt_check(const char *tablename, const void *entry, unsigned int hook_mask) { static const char * const forbidden_names[]={ "", ".", ".." }; - struct condition_info *info = (struct condition_info *) matchinfo; + const struct condition_info *info = matchinfo; struct list_head *pos; struct condition_variable *var, *newvar; @@ -214,7 +211,7 @@ condition_mt_check(const char *tablename, const void *entry, static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) { - struct condition_info *info = (struct condition_info *) matchinfo; + const struct condition_info *info = matchinfo; struct list_head *pos; struct condition_variable *var; From 24dad368dd306d2e582abaa5491c836117f4b54a Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 04:42:37 +0200 Subject: [PATCH 04/12] condition: use new structure type Use __u8 for the invert flag instead of int. Reduce CONDITION_NAME_LEN from 32 to 31 so that the entire structure can fit into a cacheline. --- extensions/libxt_condition.c | 10 +++++----- extensions/xt_condition.c | 10 +++++----- extensions/xt_condition.h | 8 +++++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index f295954..9f33b83 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -21,7 +21,7 @@ static const struct option condition_opts[] = { 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 = (void *)(*match)->data; + struct xt_condition_mtinfo *info = (void *)(*match)->data; if (c == 'X') { if (*flags) @@ -54,7 +54,7 @@ static void condition_check(unsigned int flags) static void condition_print(const void *ip, const struct xt_entry_match *match, int numeric) { - const struct condition_info *info = (const void *)match->data; + const struct xt_condition_mtinfo *info = (const void *)match->data; printf("condition %s%s ", (info->invert) ? "!" : "", info->name); } @@ -62,7 +62,7 @@ static void condition_print(const void *ip, const struct xt_entry_match *match, static void condition_save(const void *ip, const struct xt_entry_match *match) { - const struct condition_info *info = (const void *)match->data; + const struct xt_condition_mtinfo *info = (const void *)match->data; printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name); } @@ -70,8 +70,8 @@ static void condition_save(const void *ip, const struct xt_entry_match *match) 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)), + .size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), .help = condition_help, .parse = condition_parse, .final_check = condition_check, diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index c9e16a3..089e449 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -118,7 +118,7 @@ condition_mt(const struct sk_buff *skb, const struct net_device *in, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - const struct condition_info *info = matchinfo; + const struct xt_condition_mtinfo *info = matchinfo; struct condition_variable *var; int condition_status = 0; @@ -140,7 +140,7 @@ condition_mt_check(const char *tablename, const void *entry, unsigned int hook_mask) { static const char * const forbidden_names[]={ "", ".", ".." }; - const struct condition_info *info = matchinfo; + const struct xt_condition_mtinfo *info = matchinfo; struct list_head *pos; struct condition_variable *var, *newvar; @@ -211,7 +211,7 @@ condition_mt_check(const char *tablename, const void *entry, static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) { - const struct condition_info *info = matchinfo; + const struct xt_condition_mtinfo *info = matchinfo; struct list_head *pos; struct condition_variable *var; @@ -241,7 +241,7 @@ static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) static struct xt_match condition_match = { .name = "condition", .family = PF_INET, - .matchsize = sizeof(struct condition_info), + .matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), .match = condition_mt, .checkentry = condition_mt_check, .destroy = condition_mt_destroy, @@ -251,7 +251,7 @@ static struct xt_match condition_match = { static struct xt_match condition6_match = { .name = "condition", .family = PF_INET6, - .matchsize = sizeof(struct condition_info), + .matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), .match = condition_mt, .checkentry = condition_mt_check, .destroy = condition_mt_destroy, diff --git a/extensions/xt_condition.h b/extensions/xt_condition.h index f0706d0..f8751ea 100644 --- a/extensions/xt_condition.h +++ b/extensions/xt_condition.h @@ -1,11 +1,13 @@ #ifndef _XT_CONDITION_H #define _XT_CONDITION_H -#define CONDITION_NAME_LEN 32 +enum { + CONDITION_NAME_LEN = 31, +}; -struct condition_info { +struct xt_condition_mtinfo { char name[CONDITION_NAME_LEN]; - int invert; + __u8 invert; }; #endif /* _XT_CONDITION_H */ From 317a944fec22f00d9fab88f5392edb2b4a10e6a9 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 04:45:36 +0200 Subject: [PATCH 05/12] condition: use unique symbol names and rewrite init function Use an array of xt_match for the match vtable. --- extensions/xt_condition.c | 88 ++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 51 deletions(-) diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index 089e449..7c88028 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -73,9 +73,8 @@ 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) +static int condition_proc_read(char __user *buffer, char **start, off_t offset, + int length, int *eof, void *data) { const struct condition_variable *var = data; @@ -87,10 +86,8 @@ xt_condition_read_info(char __user *buffer, char **start, off_t offset, return 2; } - -static int -xt_condition_write_info(struct file *file, const char __user *buffer, - unsigned long length, void *data) +static int condition_proc_write(struct file *file, const char __user *buffer, + unsigned long length, void *data) { struct condition_variable *var = data; char newval; @@ -196,8 +193,8 @@ condition_mt_check(const char *tablename, const void *entry, 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; + newvar->status_proc->read_proc = condition_proc_read; + newvar->status_proc->write_proc = condition_proc_write; list_add_rcu(&newvar->list, &conditions_list); @@ -238,64 +235,53 @@ static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) up(&proc_lock); } -static struct xt_match condition_match = { - .name = "condition", - .family = PF_INET, - .matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), - .match = condition_mt, - .checkentry = condition_mt_check, - .destroy = condition_mt_destroy, - .me = THIS_MODULE -}; - -static struct xt_match condition6_match = { - .name = "condition", - .family = PF_INET6, - .matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), - .match = condition_mt, - .checkentry = condition_mt_check, - .destroy = condition_mt_destroy, - .me = THIS_MODULE +static struct xt_match condition_mt_reg[] __read_mostly = { + { + .name = "condition", + .revision = 0, + .family = PF_INET, + .matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), + .match = condition_mt, + .checkentry = condition_mt_check, + .destroy = condition_mt_destroy, + .me = THIS_MODULE, + }, + { + .name = "condition", + .revision = 0, + .family = PF_INET6, + .matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), + .match = condition_mt, + .checkentry = condition_mt_check, + .destroy = condition_mt_destroy, + .me = THIS_MODULE, + }, }; static const char *const dir_name = "nf_condition"; -static int __init -init(void) +static int __init condition_mt_init(void) { - int errorcode; + int ret; proc_net_condition = proc_mkdir(dir_name, proc_net); - if (proc_net_condition == NULL) { - remove_proc_entry(dir_name, proc_net); + if (proc_net_condition == NULL) return -EACCES; - } - errorcode = xt_register_match(&condition_match); - if (errorcode) { - xt_unregister_match(&condition_match); + ret = xt_register_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg)); + if (ret < 0) { 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 ret; } return 0; } -static void __exit -fini(void) +static void __exit condition_mt_exit(void) { - xt_unregister_match(&condition6_match); - xt_unregister_match(&condition_match); + xt_unregister_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg)); remove_proc_entry(dir_name, proc_net); } -module_init(init); -module_exit(fini); +module_init(condition_mt_init); +module_exit(condition_mt_exit); From 586353342f9b533baf9991ad78d7dfc5a696d098 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 04:51:17 +0200 Subject: [PATCH 06/12] condition: use appropriate types and return values --- extensions/libxt_condition.c | 5 +++-- extensions/xt_condition.c | 27 ++++++++++++++------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index 9f33b83..4189926 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -1,4 +1,5 @@ /* Shared library add-on to iptables for condition match */ +#include #include #include #include @@ -38,10 +39,10 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags, info->invert = invert; *flags = 1; - return 1; + return true; } - return 0; + return false; } static void condition_check(unsigned int flags) diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index 7c88028..c68052b 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -63,7 +63,7 @@ struct condition_variable { struct list_head list; struct proc_dir_entry *status_proc; unsigned int refcount; - int enabled; /* TRUE == 1, FALSE == 0 */ + bool enabled; }; /* proc_lock is a user context only semaphore used for write access */ @@ -81,7 +81,7 @@ static int condition_proc_read(char __user *buffer, char **start, off_t offset, buffer[0] = (var->enabled) ? '1' : '0'; buffer[1] = '\n'; if (length>=2) - *eof = 1; + *eof = true; return 2; } @@ -98,10 +98,10 @@ static int condition_proc_write(struct file *file, const char __user *buffer, /* Match only on the first character */ switch (newval) { case '0': - var->enabled = 0; + var->enabled = false; break; case '1': - var->enabled = 1; + var->enabled = true; break; } } @@ -146,28 +146,29 @@ condition_mt_check(const char *tablename, const void *entry, /* 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; + return false; + /* 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; + return false; /* 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; + return false; /* Let's acquire the lock, check for the condition and add it */ /* or increase the reference counter. */ if (down_interruptible(&proc_lock)) - return -EINTR; + return false; 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; + return true; } } @@ -176,7 +177,7 @@ condition_mt_check(const char *tablename, const void *entry, if (newvar == NULL) { up(&proc_lock); - return -ENOMEM; + return false; } /* Create the condition variable's proc file entry. */ @@ -185,11 +186,11 @@ condition_mt_check(const char *tablename, const void *entry, if (newvar->status_proc == NULL) { kfree(newvar); up(&proc_lock); - return -ENOMEM; + return false; } newvar->refcount = 1; - newvar->enabled = 0; + newvar->enabled = false; newvar->status_proc->owner = THIS_MODULE; newvar->status_proc->data = newvar; wmb(); @@ -203,7 +204,7 @@ condition_mt_check(const char *tablename, const void *entry, up(&proc_lock); - return 1; + return true; } static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) From c9579115c3b83d254f59f82d7259ef99b5ccc527 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 05:00:33 +0200 Subject: [PATCH 07/12] condition: rework condvar name check Use memchr() instead of a for loop to detect '/' in the condvar name. Also unconditionally disallow names starting with a dot. --- extensions/libxt_condition.c | 4 ++-- extensions/xt_condition.c | 23 +++++++---------------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index 4189926..ed4fd32 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -31,8 +31,8 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags, check_inverse(optarg, &invert, &optind, 0); - if (strlen(argv[optind - 1]) < CONDITION_NAME_LEN) - strcpy(info->name, argv[optind - 1]); + if (strlen(optarg) < sizeof(info->name)) + strcpy(info->name, optarg); else exit_error(PARAMETER_PROBLEM, "File name too long"); diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index c68052b..bb37534 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -136,27 +136,18 @@ condition_mt_check(const char *tablename, const void *entry, const struct xt_match *match, void *matchinfo, unsigned int hook_mask) { - static const char * const forbidden_names[]={ "", ".", ".." }; const struct xt_condition_mtinfo *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 false; - - /* We can't handle file names longer than CONDITION_NAME_LEN and */ - /* we want a NULL terminated string. */ - if (i == CONDITION_NAME_LEN) + /* Forbid certain names */ + if (*info->name == '\0' || *info->name == '.' || + info->name[sizeof(info->name)-1] != '\0' || + memchr(info->name, '/', sizeof(info->name)) != NULL) { + printk(KERN_INFO KBUILD_MODNAME ": name not allowed or too " + "long: \"%.*s\"\n", sizeof(info->name), info->name); return false; - - /* 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 false; + } /* Let's acquire the lock, check for the condition and add it */ /* or increase the reference counter. */ From f5f17a27c5cfe88064c6a3d32ecc83c75cf86bb5 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 04:33:26 +0200 Subject: [PATCH 08/12] condition: style cleanup --- extensions/libxt_condition.c | 4 +- extensions/xt_condition.c | 87 +++++++++++++++++------------------- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index ed4fd32..714c256 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -15,8 +15,8 @@ static void condition_help(void) } static const struct option condition_opts[] = { - { .name = "condition", .has_arg = 1, .flag = 0, .val = 'X' }, - { .name = 0 } + {.name = "condition", .has_arg = true, .val = 'X'}, + {NULL}, }; static int condition_parse(int c, char **argv, int invert, unsigned int *flags, diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index bb37534..a3a3544 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -1,61 +1,49 @@ -/*-------------------------------------------*\ -| Netfilter Condition Module | -| | -| Description: This module allows firewall | -| rules to match using condition variables | -| stored in /proc files. | -| | -| Author: Stephane Ouellette 2002-10-22 | -| | -| Massimiliano Hofer 2006-05-15 | -| | -| | -| 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 +/* + * xt_condition + * + * Description: This module allows firewall rules to match using + * condition variables available through procfs. + * + * Authors: + * Stephane Ouellette , 2002-10-22 + * Massimiliano Hofer , 2006-05-15 + * + * This software is distributed under the terms of the GNU GPL. + */ #include +#include #include #include #include -#include #include -#include -#include -#include +#include #include +#include #include "xt_condition.h" #include "compat_xtables.h" #ifndef CONFIG_PROC_FS -#error "Proc file system support is required for this module" +# error "proc file system support is required for this module" #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) # define proc_net init_net.proc_net #endif /* Defaults, these can be overridden on the module command-line. */ -static unsigned int condition_list_perms = 0644; +static unsigned int condition_list_perms = S_IRUGO | S_IWUSR; static unsigned int condition_uid_perms = 0; static unsigned int condition_gid_perms = 0; -MODULE_AUTHOR("Stephane Ouellette and Massimiliano Hofer "); +MODULE_AUTHOR("Stephane Ouellette "); +MODULE_AUTHOR("Massimiliano Hofer "); 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(condition_list_perms, uint, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(condition_list_perms, "permissions on /proc/net/nf_condition/* files"); +module_param(condition_uid_perms, uint, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(condition_uid_perms, "user owner of /proc/net/nf_condition/* files"); +module_param(condition_gid_perms, uint, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(condition_gid_perms, "group owner of /proc/net/nf_condition/* files"); MODULE_ALIAS("ipt_condition"); MODULE_ALIAS("ip6t_condition"); @@ -71,16 +59,16 @@ struct condition_variable { static DECLARE_MUTEX(proc_lock); static LIST_HEAD(conditions_list); -static struct proc_dir_entry *proc_net_condition = NULL; +static struct proc_dir_entry *proc_net_condition; static int condition_proc_read(char __user *buffer, char **start, off_t offset, int length, int *eof, void *data) { const struct condition_variable *var = data; - buffer[0] = (var->enabled) ? '1' : '0'; + buffer[0] = var->enabled ? '1' : '0'; buffer[1] = '\n'; - if (length>=2) + if (length >= 2) *eof = true; return 2; @@ -92,10 +80,10 @@ static int condition_proc_write(struct file *file, const char __user *buffer, struct condition_variable *var = data; char newval; - if (length>0) { + if (length > 0) { if (get_user(newval, buffer) != 0) return -EFAULT; - /* Match only on the first character */ + /* Match only on the first character */ switch (newval) { case '0': var->enabled = false; @@ -149,8 +137,10 @@ condition_mt_check(const char *tablename, const void *entry, return false; } - /* Let's acquire the lock, check for the condition and add it */ - /* or increase the reference counter. */ + /* + * Let's acquire the lock, check for the condition and add it + * or increase the reference counter. + */ if (down_interruptible(&proc_lock)) return false; @@ -213,9 +203,12 @@ static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) 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_rcu() would be good enough, but + * synchronize_net() guarantees that no packet + * will go out with the old rule after + * succesful removal. + */ synchronize_net(); kfree(var); return; From 7dd8b1a678f54af97c4562387ce2f223ea34d5c8 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 05:41:05 +0200 Subject: [PATCH 09/12] condition: reenable IPv6 support in userspace extension --- extensions/libxt_condition.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index 714c256..e4fb9c8 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -68,8 +68,25 @@ static void condition_save(const void *ip, const struct xt_entry_match *match) printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name); } -static struct xtables_match condition_match = { +static struct xtables_match condition_mt4_reg = { .name = "condition", + .revision = 0, + .family = PF_INET, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), + .help = condition_help, + .parse = condition_parse, + .final_check = condition_check, + .print = condition_print, + .save = condition_save, + .extra_opts = condition_opts, +}; + +static struct xtables_match condition_mt6_reg = { + .name = "condition", + .revision = 0, + .family = PF_INET6, .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), @@ -83,5 +100,6 @@ static struct xtables_match condition_match = { static void _init(void) { - xtables_register_match(&condition_match); + xtables_register_match(&condition_mt4_reg); + xtables_register_match(&condition_mt6_reg); } From 75f6f14aaf75e058b9113f14b4ede35dedf6441b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 05:48:57 +0200 Subject: [PATCH 10/12] condition: remove support for nonstandard inversion --- extensions/libxt_condition.c | 9 ++++----- extensions/libxt_condition.man | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index e4fb9c8..1719c58 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -9,9 +9,10 @@ static void condition_help(void) { - printf("condition match options:\n" - "--condition [!] filename " - "Match on boolean value stored in /proc file\n"); + printf( +"condition match options:\n" +"[!] --condition name Match on boolean value stored in procfs file\n" +); } static const struct option condition_opts[] = { @@ -29,8 +30,6 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags, exit_error(PARAMETER_PROBLEM, "Can't specify multiple conditions"); - check_inverse(optarg, &invert, &optind, 0); - if (strlen(optarg) < sizeof(info->name)) strcpy(info->name, optarg); else diff --git a/extensions/libxt_condition.man b/extensions/libxt_condition.man index ce2aa95..c5939ed 100644 --- a/extensions/libxt_condition.man +++ b/extensions/libxt_condition.man @@ -1,4 +1,4 @@ -This matches if a specific /proc filename is '0' or '1'. +This matches if a specific condition variable is (un)set. .TP -.BI "--condition " "[!] \fIfilename\fP" -Match on boolean value stored in /proc/net/ipt_condition/filename file +[\fB!\fP] \fB--condition\fP \fIname\fP +Match on boolean value stored in /proc/net/nf_condition/\fIname\fP. From 32f06cbedfc75cf651aa00012aba0cda4386bd3e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 10:28:36 +0200 Subject: [PATCH 11/12] condition: squash variables --- extensions/xt_condition.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index a3a3544..536ed51 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -126,7 +126,7 @@ condition_mt_check(const char *tablename, const void *entry, { const struct xt_condition_mtinfo *info = matchinfo; struct list_head *pos; - struct condition_variable *var, *newvar; + struct condition_variable *var; /* Forbid certain names */ if (*info->name == '\0' || *info->name == '.' || @@ -154,34 +154,34 @@ condition_mt_check(const char *tablename, const void *entry, } /* At this point, we need to allocate a new condition variable. */ - newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); + var = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); - if (newvar == NULL) { + if (var == NULL) { up(&proc_lock); return false; } /* Create the condition variable's proc file entry. */ - newvar->status_proc = create_proc_entry(info->name, condition_list_perms, proc_net_condition); + var->status_proc = create_proc_entry(info->name, condition_list_perms, proc_net_condition); - if (newvar->status_proc == NULL) { - kfree(newvar); + if (var->status_proc == NULL) { + kfree(var); up(&proc_lock); return false; } - newvar->refcount = 1; - newvar->enabled = false; - newvar->status_proc->owner = THIS_MODULE; - newvar->status_proc->data = newvar; + var->refcount = 1; + var->enabled = false; + var->status_proc->owner = THIS_MODULE; + var->status_proc->data = var; wmb(); - newvar->status_proc->read_proc = condition_proc_read; - newvar->status_proc->write_proc = condition_proc_write; + var->status_proc->read_proc = condition_proc_read; + var->status_proc->write_proc = condition_proc_write; - list_add_rcu(&newvar->list, &conditions_list); + list_add_rcu(&var->list, &conditions_list); - newvar->status_proc->uid = condition_uid_perms; - newvar->status_proc->gid = condition_gid_perms; + var->status_proc->uid = condition_uid_perms; + var->status_proc->gid = condition_gid_perms; up(&proc_lock); From e304252f4b5a05c4affd3cb78dd739a6078a66ba Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 2 Apr 2008 10:19:52 +0200 Subject: [PATCH 12/12] condition: greatly improve processing speed Replace the loop over all possible condvars by a simple deref. This changes the runtime from O(n) to O(1) at the expense of only 8 bytes for rule. --- extensions/libxt_condition.c | 3 +- extensions/xt_condition.c | 58 ++++++++++++++---------------------- extensions/xt_condition.h | 3 ++ 3 files changed, 27 insertions(+), 37 deletions(-) diff --git a/extensions/libxt_condition.c b/extensions/libxt_condition.c index 1719c58..71ad6dc 100644 --- a/extensions/libxt_condition.c +++ b/extensions/libxt_condition.c @@ -1,5 +1,6 @@ /* Shared library add-on to iptables for condition match */ #include +#include #include #include #include @@ -88,7 +89,7 @@ static struct xtables_match condition_mt6_reg = { .family = PF_INET6, .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), - .userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), + .userspacesize = offsetof(struct xt_condition_mtinfo, condvar), .help = condition_help, .parse = condition_parse, .final_check = condition_check, diff --git a/extensions/xt_condition.c b/extensions/xt_condition.c index 536ed51..5bfe242 100644 --- a/extensions/xt_condition.c +++ b/extensions/xt_condition.c @@ -104,19 +104,14 @@ condition_mt(const struct sk_buff *skb, const struct net_device *in, bool *hotdrop) { const struct xt_condition_mtinfo *info = matchinfo; - struct condition_variable *var; - int condition_status = 0; + const struct condition_variable *var = info->condvar; + bool x; 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; - } - } + x = rcu_dereference(var->enabled); rcu_read_unlock(); - return condition_status ^ info->invert; + return x ^ info->invert; } static bool @@ -124,8 +119,7 @@ condition_mt_check(const char *tablename, const void *entry, const struct xt_match *match, void *matchinfo, unsigned int hook_mask) { - const struct xt_condition_mtinfo *info = matchinfo; - struct list_head *pos; + struct xt_condition_mtinfo *info = matchinfo; struct condition_variable *var; /* Forbid certain names */ @@ -144,11 +138,11 @@ condition_mt_check(const char *tablename, const void *entry, if (down_interruptible(&proc_lock)) return false; - list_for_each(pos, &conditions_list) { - var = list_entry(pos, struct condition_variable, list); + list_for_each_entry(var, &conditions_list, list) { if (strcmp(info->name, var->status_proc->name) == 0) { var->refcount++; up(&proc_lock); + info->condvar = var; return true; } } @@ -185,38 +179,30 @@ condition_mt_check(const char *tablename, const void *entry, up(&proc_lock); + info->condvar = var; return true; } static void condition_mt_destroy(const struct xt_match *match, void *matchinfo) { const struct xt_condition_mtinfo *info = matchinfo; - struct list_head *pos; - struct condition_variable *var; + struct condition_variable *var = info->condvar; 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 good enough, but - * synchronize_net() guarantees that no packet - * will go out with the old rule after - * succesful removal. - */ - synchronize_net(); - kfree(var); - return; - } - break; - } + 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 good 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); } diff --git a/extensions/xt_condition.h b/extensions/xt_condition.h index f8751ea..db37a31 100644 --- a/extensions/xt_condition.h +++ b/extensions/xt_condition.h @@ -8,6 +8,9 @@ enum { struct xt_condition_mtinfo { char name[CONDITION_NAME_LEN]; __u8 invert; + + /* Used internally by the kernel */ + void *condvar __attribute__((aligned(8))); }; #endif /* _XT_CONDITION_H */