1 --- a/Documentation/Configure.help
2 +++ b/Documentation/Configure.help
3 @@ -2979,6 +2979,14 @@ CONFIG_IP_NF_MATCH_TOS
4 If you want to compile it as a module, say M here and read
5 <file:Documentation/modules.txt>. If unsure, say `N'.
7 +Condition variable match support
8 +CONFIG_IP_NF_MATCH_CONDITION
9 + This option allows you to match firewall rules against condition
10 + variables stored in the /proc/net/ipt_condition directory.
12 + If you want to compile it as a module, say M here and read
13 + Documentation/modules.txt. If unsure, say `N'.
15 conntrack match support
16 CONFIG_IP_NF_MATCH_CONNTRACK
17 This is a general conntrack match module, a superset of the state match.
18 @@ -3365,6 +3373,14 @@ CONFIG_IP6_NF_MATCH_MARK
19 If you want to compile it as a module, say M here and read
20 <file:Documentation/modules.txt>. If unsure, say `N'.
22 +Condition variable match support
23 +CONFIG_IP6_NF_MATCH_CONDITION
24 + This option allows you to match firewall rules against condition
25 + variables stored in the /proc/net/ipt_condition directory.
27 + If you want to compile it as a module, say M here and read
28 + Documentation/modules.txt. If unsure, say `N'.
30 Multiple port match support
31 CONFIG_IP6_NF_MATCH_MULTIPORT
32 Multiport matching allows you to match TCP or UDP packets based on
34 +++ b/include/linux/netfilter_ipv4/ipt_condition.h
36 +#ifndef __IPT_CONDITION_MATCH__
37 +#define __IPT_CONDITION_MATCH__
39 +#define CONDITION_NAME_LEN 32
41 +struct condition_info {
42 + char name[CONDITION_NAME_LEN];
48 +++ b/include/linux/netfilter_ipv6/ip6t_condition.h
50 +#ifndef __IP6T_CONDITION_MATCH__
51 +#define __IP6T_CONDITION_MATCH__
53 +#define CONDITION6_NAME_LEN 32
55 +struct condition6_info {
56 + char name[CONDITION6_NAME_LEN];
61 --- a/net/ipv4/netfilter/Config.in
62 +++ b/net/ipv4/netfilter/Config.in
63 @@ -41,6 +41,7 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ];
64 dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
65 dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
66 dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
67 + dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES
68 dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES
69 dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
70 dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES
71 --- a/net/ipv4/netfilter/Makefile
72 +++ b/net/ipv4/netfilter/Makefile
73 @@ -85,6 +85,7 @@ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt
74 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
75 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
76 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
77 +obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o
79 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
82 +++ b/net/ipv4/netfilter/ipt_condition.c
84 +/*-------------------------------------------*\
85 +| Netfilter Condition Module |
87 +| Description: This module allows firewall |
88 +| rules to match using condition variables |
89 +| stored in /proc files. |
91 +| Author: Stephane Ouellette 2002-10-22 |
92 +| <ouellettes@videotron.ca> |
95 +| 2003-02-10 Second version with improved |
96 +| locking and simplified code. |
98 +| This software is distributed under the |
99 +| terms of the GNU GPL. |
100 +\*-------------------------------------------*/
102 +#include<linux/module.h>
103 +#include<linux/proc_fs.h>
104 +#include<linux/spinlock.h>
105 +#include<linux/string.h>
106 +#include<asm/atomic.h>
107 +#include<linux/netfilter_ipv4/ip_tables.h>
108 +#include<linux/netfilter_ipv4/ipt_condition.h>
111 +#ifndef CONFIG_PROC_FS
112 +#error "Proc file system support is required for this module"
116 +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
117 +MODULE_DESCRIPTION("Allows rules to match against condition variables");
118 +MODULE_LICENSE("GPL");
121 +struct condition_variable {
122 + struct condition_variable *next;
123 + struct proc_dir_entry *status_proc;
125 + int enabled; /* TRUE == 1, FALSE == 0 */
129 +static rwlock_t list_lock;
130 +static struct condition_variable *head = NULL;
131 +static struct proc_dir_entry *proc_net_condition = NULL;
135 +ipt_condition_read_info(char *buffer, char **start, off_t offset,
136 + int length, int *eof, void *data)
138 + struct condition_variable *var =
139 + (struct condition_variable *) data;
143 + buffer[0] = (var->enabled) ? '1' : '0';
154 +ipt_condition_write_info(struct file *file, const char *buffer,
155 + unsigned long length, void *data)
157 + struct condition_variable *var =
158 + (struct condition_variable *) data;
161 + /* Match only on the first character */
162 + switch (buffer[0]) {
171 + return (int) length;
176 +match(const struct sk_buff *skb, const struct net_device *in,
177 + const struct net_device *out, const void *matchinfo, int offset,
178 + const void *hdr, u_int16_t datalen, int *hotdrop)
180 + const struct condition_info *info =
181 + (const struct condition_info *) matchinfo;
182 + struct condition_variable *var;
183 + int condition_status = 0;
185 + read_lock(&list_lock);
187 + for (var = head; var; var = var->next) {
188 + if (strcmp(info->name, var->status_proc->name) == 0) {
189 + condition_status = var->enabled;
194 + read_unlock(&list_lock);
196 + return condition_status ^ info->invert;
202 +checkentry(const char *tablename, const struct ipt_ip *ip,
203 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
205 + struct condition_info *info = (struct condition_info *) matchinfo;
206 + struct condition_variable *var, *newvar;
208 + if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
211 + /* The first step is to check if the condition variable already exists. */
212 + /* Here, a read lock is sufficient because we won't change the list */
213 + read_lock(&list_lock);
215 + for (var = head; var; var = var->next) {
216 + if (strcmp(info->name, var->status_proc->name) == 0) {
217 + atomic_inc(&var->refcount);
218 + read_unlock(&list_lock);
223 + read_unlock(&list_lock);
225 + /* At this point, we need to allocate a new condition variable */
226 + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
231 + /* Create the condition variable's proc file entry */
232 + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
234 + if (!newvar->status_proc) {
236 + * There are two possibilities:
237 + * 1- Another condition variable with the same name has been created, which is valid.
238 + * 2- There was a memory allocation error.
241 + read_lock(&list_lock);
243 + for (var = head; var; var = var->next) {
244 + if (strcmp(info->name, var->status_proc->name) == 0) {
245 + atomic_inc(&var->refcount);
246 + read_unlock(&list_lock);
251 + read_unlock(&list_lock);
255 + atomic_set(&newvar->refcount, 1);
256 + newvar->enabled = 0;
257 + newvar->status_proc->owner = THIS_MODULE;
258 + newvar->status_proc->data = newvar;
260 + newvar->status_proc->read_proc = ipt_condition_read_info;
261 + newvar->status_proc->write_proc = ipt_condition_write_info;
263 + write_lock(&list_lock);
265 + newvar->next = head;
268 + write_unlock(&list_lock);
275 +destroy(void *matchinfo, unsigned int matchsize)
277 + struct condition_info *info = (struct condition_info *) matchinfo;
278 + struct condition_variable *var, *prev = NULL;
280 + if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
283 + write_lock(&list_lock);
285 + for (var = head; var && strcmp(info->name, var->status_proc->name);
286 + prev = var, var = var->next);
288 + if (var && atomic_dec_and_test(&var->refcount)) {
290 + prev->next = var->next;
294 + write_unlock(&list_lock);
295 + remove_proc_entry(var->status_proc->name, proc_net_condition);
298 + write_unlock(&list_lock);
302 +static struct ipt_match condition_match = {
303 + .name = "condition",
305 + .checkentry = &checkentry,
306 + .destroy = &destroy,
316 + rwlock_init(&list_lock);
317 + proc_net_condition = proc_mkdir("ipt_condition", proc_net);
319 + if (proc_net_condition) {
320 + errorcode = ipt_register_match(&condition_match);
323 + remove_proc_entry("ipt_condition", proc_net);
325 + errorcode = -EACCES;
334 + ipt_unregister_match(&condition_match);
335 + remove_proc_entry("ipt_condition", proc_net);
340 --- a/net/ipv6/netfilter/Config.in
341 +++ b/net/ipv6/netfilter/Config.in
342 @@ -17,6 +17,7 @@ tristate 'IP6 tables support (required f
343 if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
344 # The simple matches.
345 dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES
346 + dep_tristate ' condition match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES
347 dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
348 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
349 dep_tristate ' Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES
350 --- a/net/ipv6/netfilter/Makefile
351 +++ b/net/ipv6/netfilter/Makefile
352 @@ -14,6 +14,7 @@ export-objs := ip6_tables.o
353 # Link order matters here.
354 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
355 obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
356 +obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o
357 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
358 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
359 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
361 +++ b/net/ipv6/netfilter/ip6t_condition.c
363 +/*-------------------------------------------*\
364 +| Netfilter Condition Module for IPv6 |
366 +| Description: This module allows firewall |
367 +| rules to match using condition variables |
368 +| stored in /proc files. |
370 +| Author: Stephane Ouellette 2003-02-10 |
371 +| <ouellettes@videotron.ca> |
373 +| This software is distributed under the |
374 +| terms of the GNU GPL. |
375 +\*-------------------------------------------*/
377 +#include<linux/module.h>
378 +#include<linux/proc_fs.h>
379 +#include<linux/spinlock.h>
380 +#include<linux/string.h>
381 +#include<asm/atomic.h>
382 +#include<linux/netfilter_ipv6/ip6_tables.h>
383 +#include<linux/netfilter_ipv6/ip6t_condition.h>
386 +#ifndef CONFIG_PROC_FS
387 +#error "Proc file system support is required for this module"
391 +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
392 +MODULE_DESCRIPTION("Allows rules to match against condition variables");
393 +MODULE_LICENSE("GPL");
396 +struct condition_variable {
397 + struct condition_variable *next;
398 + struct proc_dir_entry *status_proc;
400 + int enabled; /* TRUE == 1, FALSE == 0 */
404 +static rwlock_t list_lock;
405 +static struct condition_variable *head = NULL;
406 +static struct proc_dir_entry *proc_net_condition = NULL;
410 +ipt_condition_read_info(char *buffer, char **start, off_t offset,
411 + int length, int *eof, void *data)
413 + struct condition_variable *var =
414 + (struct condition_variable *) data;
418 + buffer[0] = (var->enabled) ? '1' : '0';
429 +ipt_condition_write_info(struct file *file, const char *buffer,
430 + unsigned long length, void *data)
432 + struct condition_variable *var =
433 + (struct condition_variable *) data;
436 + /* Match only on the first character */
437 + switch (buffer[0]) {
446 + return (int) length;
451 +match(const struct sk_buff *skb, const struct net_device *in,
452 + const struct net_device *out, const void *matchinfo, int offset,
453 + const void *hdr, u_int16_t datalen, int *hotdrop)
455 + const struct condition6_info *info =
456 + (const struct condition6_info *) matchinfo;
457 + struct condition_variable *var;
458 + int condition_status = 0;
460 + read_lock(&list_lock);
462 + for (var = head; var; var = var->next) {
463 + if (strcmp(info->name, var->status_proc->name) == 0) {
464 + condition_status = var->enabled;
469 + read_unlock(&list_lock);
471 + return condition_status ^ info->invert;
477 +checkentry(const char *tablename, const struct ip6t_ip6 *ip,
478 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
480 + struct condition6_info *info =
481 + (struct condition6_info *) matchinfo;
482 + struct condition_variable *var, *newvar;
484 + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
487 + /* The first step is to check if the condition variable already exists. */
488 + /* Here, a read lock is sufficient because we won't change the list */
489 + read_lock(&list_lock);
491 + for (var = head; var; var = var->next) {
492 + if (strcmp(info->name, var->status_proc->name) == 0) {
493 + atomic_inc(&var->refcount);
494 + read_unlock(&list_lock);
499 + read_unlock(&list_lock);
501 + /* At this point, we need to allocate a new condition variable */
502 + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
507 + /* Create the condition variable's proc file entry */
508 + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
510 + if (!newvar->status_proc) {
512 + * There are two possibilities:
513 + * 1- Another condition variable with the same name has been created, which is valid.
514 + * 2- There was a memory allocation error.
517 + read_lock(&list_lock);
519 + for (var = head; var; var = var->next) {
520 + if (strcmp(info->name, var->status_proc->name) == 0) {
521 + atomic_inc(&var->refcount);
522 + read_unlock(&list_lock);
527 + read_unlock(&list_lock);
531 + atomic_set(&newvar->refcount, 1);
532 + newvar->enabled = 0;
533 + newvar->status_proc->owner = THIS_MODULE;
534 + newvar->status_proc->data = newvar;
536 + newvar->status_proc->read_proc = ipt_condition_read_info;
537 + newvar->status_proc->write_proc = ipt_condition_write_info;
539 + write_lock(&list_lock);
541 + newvar->next = head;
544 + write_unlock(&list_lock);
551 +destroy(void *matchinfo, unsigned int matchsize)
553 + struct condition6_info *info =
554 + (struct condition6_info *) matchinfo;
555 + struct condition_variable *var, *prev = NULL;
557 + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
560 + write_lock(&list_lock);
562 + for (var = head; var && strcmp(info->name, var->status_proc->name);
563 + prev = var, var = var->next);
565 + if (var && atomic_dec_and_test(&var->refcount)) {
567 + prev->next = var->next;
571 + write_unlock(&list_lock);
572 + remove_proc_entry(var->status_proc->name, proc_net_condition);
575 + write_unlock(&list_lock);
579 +static struct ip6t_match condition_match = {
580 + .name = "condition",
582 + .checkentry = &checkentry,
583 + .destroy = &destroy,
593 + rwlock_init(&list_lock);
594 + proc_net_condition = proc_mkdir("ip6t_condition", proc_net);
596 + if (proc_net_condition) {
597 + errorcode = ipt_register_match(&condition_match);
600 + remove_proc_entry("ip6t_condition", proc_net);
602 + errorcode = -EACCES;
611 + ipt_unregister_match(&condition_match);
612 + remove_proc_entry("ip6t_condition", proc_net);