c6ffe5b32558987995774a34031af287911f5f6c
[openwrt/staging/yousong.git] / target / linux / generic-2.4 / patches / 611-netfilter_condition.patch
1 Index: linux-2.4.35.4/Documentation/Configure.help
2 ===================================================================
3 --- linux-2.4.35.4.orig/Documentation/Configure.help
4 +++ linux-2.4.35.4/Documentation/Configure.help
5 @@ -2979,6 +2979,14 @@ CONFIG_IP_NF_MATCH_TOS
6 If you want to compile it as a module, say M here and read
7 <file:Documentation/modules.txt>. If unsure, say `N'.
8
9 +Condition variable match support
10 +CONFIG_IP_NF_MATCH_CONDITION
11 + This option allows you to match firewall rules against condition
12 + variables stored in the /proc/net/ipt_condition directory.
13 +
14 + If you want to compile it as a module, say M here and read
15 + Documentation/modules.txt. If unsure, say `N'.
16 +
17 conntrack match support
18 CONFIG_IP_NF_MATCH_CONNTRACK
19 This is a general conntrack match module, a superset of the state match.
20 @@ -3354,6 +3362,14 @@ CONFIG_IP6_NF_MATCH_MARK
21 If you want to compile it as a module, say M here and read
22 <file:Documentation/modules.txt>. If unsure, say `N'.
23
24 +Condition variable match support
25 +CONFIG_IP6_NF_MATCH_CONDITION
26 + This option allows you to match firewall rules against condition
27 + variables stored in the /proc/net/ipt_condition directory.
28 +
29 + If you want to compile it as a module, say M here and read
30 + Documentation/modules.txt. If unsure, say `N'.
31 +
32 Multiple port match support
33 CONFIG_IP6_NF_MATCH_MULTIPORT
34 Multiport matching allows you to match TCP or UDP packets based on
35 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ipt_condition.h
36 ===================================================================
37 --- /dev/null
38 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ipt_condition.h
39 @@ -0,0 +1,11 @@
40 +#ifndef __IPT_CONDITION_MATCH__
41 +#define __IPT_CONDITION_MATCH__
42 +
43 +#define CONDITION_NAME_LEN 32
44 +
45 +struct condition_info {
46 + char name[CONDITION_NAME_LEN];
47 + int invert;
48 +};
49 +
50 +#endif
51 Index: linux-2.4.35.4/include/linux/netfilter_ipv6/ip6t_condition.h
52 ===================================================================
53 --- /dev/null
54 +++ linux-2.4.35.4/include/linux/netfilter_ipv6/ip6t_condition.h
55 @@ -0,0 +1,11 @@
56 +#ifndef __IP6T_CONDITION_MATCH__
57 +#define __IP6T_CONDITION_MATCH__
58 +
59 +#define CONDITION6_NAME_LEN 32
60 +
61 +struct condition6_info {
62 + char name[CONDITION6_NAME_LEN];
63 + int invert;
64 +};
65 +
66 +#endif
67 Index: linux-2.4.35.4/net/ipv4/netfilter/Config.in
68 ===================================================================
69 --- linux-2.4.35.4.orig/net/ipv4/netfilter/Config.in
70 +++ linux-2.4.35.4/net/ipv4/netfilter/Config.in
71 @@ -43,6 +43,7 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ];
72 dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
73 dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
74 dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
75 + dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES
76 dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES
77 dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
78 dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES
79 Index: linux-2.4.35.4/net/ipv4/netfilter/Makefile
80 ===================================================================
81 --- linux-2.4.35.4.orig/net/ipv4/netfilter/Makefile
82 +++ linux-2.4.35.4/net/ipv4/netfilter/Makefile
83 @@ -94,6 +94,7 @@ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt
84 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
85 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
86 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
87 +obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o
88
89 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
90
91 Index: linux-2.4.35.4/net/ipv4/netfilter/ipt_condition.c
92 ===================================================================
93 --- /dev/null
94 +++ linux-2.4.35.4/net/ipv4/netfilter/ipt_condition.c
95 @@ -0,0 +1,256 @@
96 +/*-------------------------------------------*\
97 +| Netfilter Condition Module |
98 +| |
99 +| Description: This module allows firewall |
100 +| rules to match using condition variables |
101 +| stored in /proc files. |
102 +| |
103 +| Author: Stephane Ouellette 2002-10-22 |
104 +| <ouellettes@videotron.ca> |
105 +| |
106 +| History: |
107 +| 2003-02-10 Second version with improved |
108 +| locking and simplified code. |
109 +| |
110 +| This software is distributed under the |
111 +| terms of the GNU GPL. |
112 +\*-------------------------------------------*/
113 +
114 +#include<linux/module.h>
115 +#include<linux/proc_fs.h>
116 +#include<linux/spinlock.h>
117 +#include<linux/string.h>
118 +#include<asm/atomic.h>
119 +#include<linux/netfilter_ipv4/ip_tables.h>
120 +#include<linux/netfilter_ipv4/ipt_condition.h>
121 +
122 +
123 +#ifndef CONFIG_PROC_FS
124 +#error "Proc file system support is required for this module"
125 +#endif
126 +
127 +
128 +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
129 +MODULE_DESCRIPTION("Allows rules to match against condition variables");
130 +MODULE_LICENSE("GPL");
131 +
132 +
133 +struct condition_variable {
134 + struct condition_variable *next;
135 + struct proc_dir_entry *status_proc;
136 + atomic_t refcount;
137 + int enabled; /* TRUE == 1, FALSE == 0 */
138 +};
139 +
140 +
141 +static rwlock_t list_lock;
142 +static struct condition_variable *head = NULL;
143 +static struct proc_dir_entry *proc_net_condition = NULL;
144 +
145 +
146 +static int
147 +ipt_condition_read_info(char *buffer, char **start, off_t offset,
148 + int length, int *eof, void *data)
149 +{
150 + struct condition_variable *var =
151 + (struct condition_variable *) data;
152 +
153 + if (offset == 0) {
154 + *start = buffer;
155 + buffer[0] = (var->enabled) ? '1' : '0';
156 + buffer[1] = '\n';
157 + return 2;
158 + }
159 +
160 + *eof = 1;
161 + return 0;
162 +}
163 +
164 +
165 +static int
166 +ipt_condition_write_info(struct file *file, const char *buffer,
167 + unsigned long length, void *data)
168 +{
169 + struct condition_variable *var =
170 + (struct condition_variable *) data;
171 +
172 + if (length) {
173 + /* Match only on the first character */
174 + switch (buffer[0]) {
175 + case '0':
176 + var->enabled = 0;
177 + break;
178 + case '1':
179 + var->enabled = 1;
180 + }
181 + }
182 +
183 + return (int) length;
184 +}
185 +
186 +
187 +static int
188 +match(const struct sk_buff *skb, const struct net_device *in,
189 + const struct net_device *out, const void *matchinfo, int offset,
190 + const void *hdr, u_int16_t datalen, int *hotdrop)
191 +{
192 + const struct condition_info *info =
193 + (const struct condition_info *) matchinfo;
194 + struct condition_variable *var;
195 + int condition_status = 0;
196 +
197 + read_lock(&list_lock);
198 +
199 + for (var = head; var; var = var->next) {
200 + if (strcmp(info->name, var->status_proc->name) == 0) {
201 + condition_status = var->enabled;
202 + break;
203 + }
204 + }
205 +
206 + read_unlock(&list_lock);
207 +
208 + return condition_status ^ info->invert;
209 +}
210 +
211 +
212 +
213 +static int
214 +checkentry(const char *tablename, const struct ipt_ip *ip,
215 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
216 +{
217 + struct condition_info *info = (struct condition_info *) matchinfo;
218 + struct condition_variable *var, *newvar;
219 +
220 + if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
221 + return 0;
222 +
223 + /* The first step is to check if the condition variable already exists. */
224 + /* Here, a read lock is sufficient because we won't change the list */
225 + read_lock(&list_lock);
226 +
227 + for (var = head; var; var = var->next) {
228 + if (strcmp(info->name, var->status_proc->name) == 0) {
229 + atomic_inc(&var->refcount);
230 + read_unlock(&list_lock);
231 + return 1;
232 + }
233 + }
234 +
235 + read_unlock(&list_lock);
236 +
237 + /* At this point, we need to allocate a new condition variable */
238 + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
239 +
240 + if (!newvar)
241 + return -ENOMEM;
242 +
243 + /* Create the condition variable's proc file entry */
244 + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
245 +
246 + if (!newvar->status_proc) {
247 + /*
248 + * There are two possibilities:
249 + * 1- Another condition variable with the same name has been created, which is valid.
250 + * 2- There was a memory allocation error.
251 + */
252 + kfree(newvar);
253 + read_lock(&list_lock);
254 +
255 + for (var = head; var; var = var->next) {
256 + if (strcmp(info->name, var->status_proc->name) == 0) {
257 + atomic_inc(&var->refcount);
258 + read_unlock(&list_lock);
259 + return 1;
260 + }
261 + }
262 +
263 + read_unlock(&list_lock);
264 + return -ENOMEM;
265 + }
266 +
267 + atomic_set(&newvar->refcount, 1);
268 + newvar->enabled = 0;
269 + newvar->status_proc->owner = THIS_MODULE;
270 + newvar->status_proc->data = newvar;
271 + wmb();
272 + newvar->status_proc->read_proc = ipt_condition_read_info;
273 + newvar->status_proc->write_proc = ipt_condition_write_info;
274 +
275 + write_lock(&list_lock);
276 +
277 + newvar->next = head;
278 + head = newvar;
279 +
280 + write_unlock(&list_lock);
281 +
282 + return 1;
283 +}
284 +
285 +
286 +static void
287 +destroy(void *matchinfo, unsigned int matchsize)
288 +{
289 + struct condition_info *info = (struct condition_info *) matchinfo;
290 + struct condition_variable *var, *prev = NULL;
291 +
292 + if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
293 + return;
294 +
295 + write_lock(&list_lock);
296 +
297 + for (var = head; var && strcmp(info->name, var->status_proc->name);
298 + prev = var, var = var->next);
299 +
300 + if (var && atomic_dec_and_test(&var->refcount)) {
301 + if (prev)
302 + prev->next = var->next;
303 + else
304 + head = var->next;
305 +
306 + write_unlock(&list_lock);
307 + remove_proc_entry(var->status_proc->name, proc_net_condition);
308 + kfree(var);
309 + } else
310 + write_unlock(&list_lock);
311 +}
312 +
313 +
314 +static struct ipt_match condition_match = {
315 + .name = "condition",
316 + .match = &match,
317 + .checkentry = &checkentry,
318 + .destroy = &destroy,
319 + .me = THIS_MODULE
320 +};
321 +
322 +
323 +static int __init
324 +init(void)
325 +{
326 + int errorcode;
327 +
328 + rwlock_init(&list_lock);
329 + proc_net_condition = proc_mkdir("ipt_condition", proc_net);
330 +
331 + if (proc_net_condition) {
332 + errorcode = ipt_register_match(&condition_match);
333 +
334 + if (errorcode)
335 + remove_proc_entry("ipt_condition", proc_net);
336 + } else
337 + errorcode = -EACCES;
338 +
339 + return errorcode;
340 +}
341 +
342 +
343 +static void __exit
344 +fini(void)
345 +{
346 + ipt_unregister_match(&condition_match);
347 + remove_proc_entry("ipt_condition", proc_net);
348 +}
349 +
350 +module_init(init);
351 +module_exit(fini);
352 Index: linux-2.4.35.4/net/ipv6/netfilter/Config.in
353 ===================================================================
354 --- linux-2.4.35.4.orig/net/ipv6/netfilter/Config.in
355 +++ linux-2.4.35.4/net/ipv6/netfilter/Config.in
356 @@ -17,6 +17,7 @@ tristate 'IP6 tables support (required f
357 if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
358 # The simple matches.
359 dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES
360 + dep_tristate ' condition match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES
361 dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
362 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
363 dep_tristate ' Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES
364 Index: linux-2.4.35.4/net/ipv6/netfilter/Makefile
365 ===================================================================
366 --- linux-2.4.35.4.orig/net/ipv6/netfilter/Makefile
367 +++ linux-2.4.35.4/net/ipv6/netfilter/Makefile
368 @@ -14,6 +14,7 @@ export-objs := ip6_tables.o
369 # Link order matters here.
370 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
371 obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
372 +obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o
373 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
374 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
375 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
376 Index: linux-2.4.35.4/net/ipv6/netfilter/ip6t_condition.c
377 ===================================================================
378 --- /dev/null
379 +++ linux-2.4.35.4/net/ipv6/netfilter/ip6t_condition.c
380 @@ -0,0 +1,254 @@
381 +/*-------------------------------------------*\
382 +| Netfilter Condition Module for IPv6 |
383 +| |
384 +| Description: This module allows firewall |
385 +| rules to match using condition variables |
386 +| stored in /proc files. |
387 +| |
388 +| Author: Stephane Ouellette 2003-02-10 |
389 +| <ouellettes@videotron.ca> |
390 +| |
391 +| This software is distributed under the |
392 +| terms of the GNU GPL. |
393 +\*-------------------------------------------*/
394 +
395 +#include<linux/module.h>
396 +#include<linux/proc_fs.h>
397 +#include<linux/spinlock.h>
398 +#include<linux/string.h>
399 +#include<asm/atomic.h>
400 +#include<linux/netfilter_ipv6/ip6_tables.h>
401 +#include<linux/netfilter_ipv6/ip6t_condition.h>
402 +
403 +
404 +#ifndef CONFIG_PROC_FS
405 +#error "Proc file system support is required for this module"
406 +#endif
407 +
408 +
409 +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
410 +MODULE_DESCRIPTION("Allows rules to match against condition variables");
411 +MODULE_LICENSE("GPL");
412 +
413 +
414 +struct condition_variable {
415 + struct condition_variable *next;
416 + struct proc_dir_entry *status_proc;
417 + atomic_t refcount;
418 + int enabled; /* TRUE == 1, FALSE == 0 */
419 +};
420 +
421 +
422 +static rwlock_t list_lock;
423 +static struct condition_variable *head = NULL;
424 +static struct proc_dir_entry *proc_net_condition = NULL;
425 +
426 +
427 +static int
428 +ipt_condition_read_info(char *buffer, char **start, off_t offset,
429 + int length, int *eof, void *data)
430 +{
431 + struct condition_variable *var =
432 + (struct condition_variable *) data;
433 +
434 + if (offset == 0) {
435 + *start = buffer;
436 + buffer[0] = (var->enabled) ? '1' : '0';
437 + buffer[1] = '\n';
438 + return 2;
439 + }
440 +
441 + *eof = 1;
442 + return 0;
443 +}
444 +
445 +
446 +static int
447 +ipt_condition_write_info(struct file *file, const char *buffer,
448 + unsigned long length, void *data)
449 +{
450 + struct condition_variable *var =
451 + (struct condition_variable *) data;
452 +
453 + if (length) {
454 + /* Match only on the first character */
455 + switch (buffer[0]) {
456 + case '0':
457 + var->enabled = 0;
458 + break;
459 + case '1':
460 + var->enabled = 1;
461 + }
462 + }
463 +
464 + return (int) length;
465 +}
466 +
467 +
468 +static int
469 +match(const struct sk_buff *skb, const struct net_device *in,
470 + const struct net_device *out, const void *matchinfo, int offset,
471 + const void *hdr, u_int16_t datalen, int *hotdrop)
472 +{
473 + const struct condition6_info *info =
474 + (const struct condition6_info *) matchinfo;
475 + struct condition_variable *var;
476 + int condition_status = 0;
477 +
478 + read_lock(&list_lock);
479 +
480 + for (var = head; var; var = var->next) {
481 + if (strcmp(info->name, var->status_proc->name) == 0) {
482 + condition_status = var->enabled;
483 + break;
484 + }
485 + }
486 +
487 + read_unlock(&list_lock);
488 +
489 + return condition_status ^ info->invert;
490 +}
491 +
492 +
493 +
494 +static int
495 +checkentry(const char *tablename, const struct ip6t_ip6 *ip,
496 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
497 +{
498 + struct condition6_info *info =
499 + (struct condition6_info *) matchinfo;
500 + struct condition_variable *var, *newvar;
501 +
502 + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
503 + return 0;
504 +
505 + /* The first step is to check if the condition variable already exists. */
506 + /* Here, a read lock is sufficient because we won't change the list */
507 + read_lock(&list_lock);
508 +
509 + for (var = head; var; var = var->next) {
510 + if (strcmp(info->name, var->status_proc->name) == 0) {
511 + atomic_inc(&var->refcount);
512 + read_unlock(&list_lock);
513 + return 1;
514 + }
515 + }
516 +
517 + read_unlock(&list_lock);
518 +
519 + /* At this point, we need to allocate a new condition variable */
520 + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
521 +
522 + if (!newvar)
523 + return -ENOMEM;
524 +
525 + /* Create the condition variable's proc file entry */
526 + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
527 +
528 + if (!newvar->status_proc) {
529 + /*
530 + * There are two possibilities:
531 + * 1- Another condition variable with the same name has been created, which is valid.
532 + * 2- There was a memory allocation error.
533 + */
534 + kfree(newvar);
535 + read_lock(&list_lock);
536 +
537 + for (var = head; var; var = var->next) {
538 + if (strcmp(info->name, var->status_proc->name) == 0) {
539 + atomic_inc(&var->refcount);
540 + read_unlock(&list_lock);
541 + return 1;
542 + }
543 + }
544 +
545 + read_unlock(&list_lock);
546 + return -ENOMEM;
547 + }
548 +
549 + atomic_set(&newvar->refcount, 1);
550 + newvar->enabled = 0;
551 + newvar->status_proc->owner = THIS_MODULE;
552 + newvar->status_proc->data = newvar;
553 + wmb();
554 + newvar->status_proc->read_proc = ipt_condition_read_info;
555 + newvar->status_proc->write_proc = ipt_condition_write_info;
556 +
557 + write_lock(&list_lock);
558 +
559 + newvar->next = head;
560 + head = newvar;
561 +
562 + write_unlock(&list_lock);
563 +
564 + return 1;
565 +}
566 +
567 +
568 +static void
569 +destroy(void *matchinfo, unsigned int matchsize)
570 +{
571 + struct condition6_info *info =
572 + (struct condition6_info *) matchinfo;
573 + struct condition_variable *var, *prev = NULL;
574 +
575 + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
576 + return;
577 +
578 + write_lock(&list_lock);
579 +
580 + for (var = head; var && strcmp(info->name, var->status_proc->name);
581 + prev = var, var = var->next);
582 +
583 + if (var && atomic_dec_and_test(&var->refcount)) {
584 + if (prev)
585 + prev->next = var->next;
586 + else
587 + head = var->next;
588 +
589 + write_unlock(&list_lock);
590 + remove_proc_entry(var->status_proc->name, proc_net_condition);
591 + kfree(var);
592 + } else
593 + write_unlock(&list_lock);
594 +}
595 +
596 +
597 +static struct ip6t_match condition_match = {
598 + .name = "condition",
599 + .match = &match,
600 + .checkentry = &checkentry,
601 + .destroy = &destroy,
602 + .me = THIS_MODULE
603 +};
604 +
605 +
606 +static int __init
607 +init(void)
608 +{
609 + int errorcode;
610 +
611 + rwlock_init(&list_lock);
612 + proc_net_condition = proc_mkdir("ip6t_condition", proc_net);
613 +
614 + if (proc_net_condition) {
615 + errorcode = ipt_register_match(&condition_match);
616 +
617 + if (errorcode)
618 + remove_proc_entry("ip6t_condition", proc_net);
619 + } else
620 + errorcode = -EACCES;
621 +
622 + return errorcode;
623 +}
624 +
625 +
626 +static void __exit
627 +fini(void)
628 +{
629 + ipt_unregister_match(&condition_match);
630 + remove_proc_entry("ip6t_condition", proc_net);
631 +}
632 +
633 +module_init(init);
634 +module_exit(fini);