[8.09] kernel: refresh patches
[openwrt/svn-archive/archive.git] / target / linux / generic-2.4 / patches / 611-netfilter_condition.patch
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'.
6
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.
11 +
12 + If you want to compile it as a module, say M here and read
13 + Documentation/modules.txt. If unsure, say `N'.
14 +
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 @@ -3354,6 +3362,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'.
21
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.
26 +
27 + If you want to compile it as a module, say M here and read
28 + Documentation/modules.txt. If unsure, say `N'.
29 +
30 Multiple port match support
31 CONFIG_IP6_NF_MATCH_MULTIPORT
32 Multiport matching allows you to match TCP or UDP packets based on
33 --- /dev/null
34 +++ b/include/linux/netfilter_ipv4/ipt_condition.h
35 @@ -0,0 +1,11 @@
36 +#ifndef __IPT_CONDITION_MATCH__
37 +#define __IPT_CONDITION_MATCH__
38 +
39 +#define CONDITION_NAME_LEN 32
40 +
41 +struct condition_info {
42 + char name[CONDITION_NAME_LEN];
43 + int invert;
44 +};
45 +
46 +#endif
47 --- /dev/null
48 +++ b/include/linux/netfilter_ipv6/ip6t_condition.h
49 @@ -0,0 +1,11 @@
50 +#ifndef __IP6T_CONDITION_MATCH__
51 +#define __IP6T_CONDITION_MATCH__
52 +
53 +#define CONDITION6_NAME_LEN 32
54 +
55 +struct condition6_info {
56 + char name[CONDITION6_NAME_LEN];
57 + int invert;
58 +};
59 +
60 +#endif
61 --- a/net/ipv4/netfilter/Config.in
62 +++ b/net/ipv4/netfilter/Config.in
63 @@ -43,6 +43,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 @@ -94,6 +94,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
78
79 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
80
81 --- /dev/null
82 +++ b/net/ipv4/netfilter/ipt_condition.c
83 @@ -0,0 +1,256 @@
84 +/*-------------------------------------------*\
85 +| Netfilter Condition Module |
86 +| |
87 +| Description: This module allows firewall |
88 +| rules to match using condition variables |
89 +| stored in /proc files. |
90 +| |
91 +| Author: Stephane Ouellette 2002-10-22 |
92 +| <ouellettes@videotron.ca> |
93 +| |
94 +| History: |
95 +| 2003-02-10 Second version with improved |
96 +| locking and simplified code. |
97 +| |
98 +| This software is distributed under the |
99 +| terms of the GNU GPL. |
100 +\*-------------------------------------------*/
101 +
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>
109 +
110 +
111 +#ifndef CONFIG_PROC_FS
112 +#error "Proc file system support is required for this module"
113 +#endif
114 +
115 +
116 +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
117 +MODULE_DESCRIPTION("Allows rules to match against condition variables");
118 +MODULE_LICENSE("GPL");
119 +
120 +
121 +struct condition_variable {
122 + struct condition_variable *next;
123 + struct proc_dir_entry *status_proc;
124 + atomic_t refcount;
125 + int enabled; /* TRUE == 1, FALSE == 0 */
126 +};
127 +
128 +
129 +static rwlock_t list_lock;
130 +static struct condition_variable *head = NULL;
131 +static struct proc_dir_entry *proc_net_condition = NULL;
132 +
133 +
134 +static int
135 +ipt_condition_read_info(char *buffer, char **start, off_t offset,
136 + int length, int *eof, void *data)
137 +{
138 + struct condition_variable *var =
139 + (struct condition_variable *) data;
140 +
141 + if (offset == 0) {
142 + *start = buffer;
143 + buffer[0] = (var->enabled) ? '1' : '0';
144 + buffer[1] = '\n';
145 + return 2;
146 + }
147 +
148 + *eof = 1;
149 + return 0;
150 +}
151 +
152 +
153 +static int
154 +ipt_condition_write_info(struct file *file, const char *buffer,
155 + unsigned long length, void *data)
156 +{
157 + struct condition_variable *var =
158 + (struct condition_variable *) data;
159 +
160 + if (length) {
161 + /* Match only on the first character */
162 + switch (buffer[0]) {
163 + case '0':
164 + var->enabled = 0;
165 + break;
166 + case '1':
167 + var->enabled = 1;
168 + }
169 + }
170 +
171 + return (int) length;
172 +}
173 +
174 +
175 +static int
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)
179 +{
180 + const struct condition_info *info =
181 + (const struct condition_info *) matchinfo;
182 + struct condition_variable *var;
183 + int condition_status = 0;
184 +
185 + read_lock(&list_lock);
186 +
187 + for (var = head; var; var = var->next) {
188 + if (strcmp(info->name, var->status_proc->name) == 0) {
189 + condition_status = var->enabled;
190 + break;
191 + }
192 + }
193 +
194 + read_unlock(&list_lock);
195 +
196 + return condition_status ^ info->invert;
197 +}
198 +
199 +
200 +
201 +static int
202 +checkentry(const char *tablename, const struct ipt_ip *ip,
203 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
204 +{
205 + struct condition_info *info = (struct condition_info *) matchinfo;
206 + struct condition_variable *var, *newvar;
207 +
208 + if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
209 + return 0;
210 +
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);
214 +
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);
219 + return 1;
220 + }
221 + }
222 +
223 + read_unlock(&list_lock);
224 +
225 + /* At this point, we need to allocate a new condition variable */
226 + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
227 +
228 + if (!newvar)
229 + return -ENOMEM;
230 +
231 + /* Create the condition variable's proc file entry */
232 + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
233 +
234 + if (!newvar->status_proc) {
235 + /*
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.
239 + */
240 + kfree(newvar);
241 + read_lock(&list_lock);
242 +
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);
247 + return 1;
248 + }
249 + }
250 +
251 + read_unlock(&list_lock);
252 + return -ENOMEM;
253 + }
254 +
255 + atomic_set(&newvar->refcount, 1);
256 + newvar->enabled = 0;
257 + newvar->status_proc->owner = THIS_MODULE;
258 + newvar->status_proc->data = newvar;
259 + wmb();
260 + newvar->status_proc->read_proc = ipt_condition_read_info;
261 + newvar->status_proc->write_proc = ipt_condition_write_info;
262 +
263 + write_lock(&list_lock);
264 +
265 + newvar->next = head;
266 + head = newvar;
267 +
268 + write_unlock(&list_lock);
269 +
270 + return 1;
271 +}
272 +
273 +
274 +static void
275 +destroy(void *matchinfo, unsigned int matchsize)
276 +{
277 + struct condition_info *info = (struct condition_info *) matchinfo;
278 + struct condition_variable *var, *prev = NULL;
279 +
280 + if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
281 + return;
282 +
283 + write_lock(&list_lock);
284 +
285 + for (var = head; var && strcmp(info->name, var->status_proc->name);
286 + prev = var, var = var->next);
287 +
288 + if (var && atomic_dec_and_test(&var->refcount)) {
289 + if (prev)
290 + prev->next = var->next;
291 + else
292 + head = var->next;
293 +
294 + write_unlock(&list_lock);
295 + remove_proc_entry(var->status_proc->name, proc_net_condition);
296 + kfree(var);
297 + } else
298 + write_unlock(&list_lock);
299 +}
300 +
301 +
302 +static struct ipt_match condition_match = {
303 + .name = "condition",
304 + .match = &match,
305 + .checkentry = &checkentry,
306 + .destroy = &destroy,
307 + .me = THIS_MODULE
308 +};
309 +
310 +
311 +static int __init
312 +init(void)
313 +{
314 + int errorcode;
315 +
316 + rwlock_init(&list_lock);
317 + proc_net_condition = proc_mkdir("ipt_condition", proc_net);
318 +
319 + if (proc_net_condition) {
320 + errorcode = ipt_register_match(&condition_match);
321 +
322 + if (errorcode)
323 + remove_proc_entry("ipt_condition", proc_net);
324 + } else
325 + errorcode = -EACCES;
326 +
327 + return errorcode;
328 +}
329 +
330 +
331 +static void __exit
332 +fini(void)
333 +{
334 + ipt_unregister_match(&condition_match);
335 + remove_proc_entry("ipt_condition", proc_net);
336 +}
337 +
338 +module_init(init);
339 +module_exit(fini);
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
360 --- /dev/null
361 +++ b/net/ipv6/netfilter/ip6t_condition.c
362 @@ -0,0 +1,254 @@
363 +/*-------------------------------------------*\
364 +| Netfilter Condition Module for IPv6 |
365 +| |
366 +| Description: This module allows firewall |
367 +| rules to match using condition variables |
368 +| stored in /proc files. |
369 +| |
370 +| Author: Stephane Ouellette 2003-02-10 |
371 +| <ouellettes@videotron.ca> |
372 +| |
373 +| This software is distributed under the |
374 +| terms of the GNU GPL. |
375 +\*-------------------------------------------*/
376 +
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>
384 +
385 +
386 +#ifndef CONFIG_PROC_FS
387 +#error "Proc file system support is required for this module"
388 +#endif
389 +
390 +
391 +MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
392 +MODULE_DESCRIPTION("Allows rules to match against condition variables");
393 +MODULE_LICENSE("GPL");
394 +
395 +
396 +struct condition_variable {
397 + struct condition_variable *next;
398 + struct proc_dir_entry *status_proc;
399 + atomic_t refcount;
400 + int enabled; /* TRUE == 1, FALSE == 0 */
401 +};
402 +
403 +
404 +static rwlock_t list_lock;
405 +static struct condition_variable *head = NULL;
406 +static struct proc_dir_entry *proc_net_condition = NULL;
407 +
408 +
409 +static int
410 +ipt_condition_read_info(char *buffer, char **start, off_t offset,
411 + int length, int *eof, void *data)
412 +{
413 + struct condition_variable *var =
414 + (struct condition_variable *) data;
415 +
416 + if (offset == 0) {
417 + *start = buffer;
418 + buffer[0] = (var->enabled) ? '1' : '0';
419 + buffer[1] = '\n';
420 + return 2;
421 + }
422 +
423 + *eof = 1;
424 + return 0;
425 +}
426 +
427 +
428 +static int
429 +ipt_condition_write_info(struct file *file, const char *buffer,
430 + unsigned long length, void *data)
431 +{
432 + struct condition_variable *var =
433 + (struct condition_variable *) data;
434 +
435 + if (length) {
436 + /* Match only on the first character */
437 + switch (buffer[0]) {
438 + case '0':
439 + var->enabled = 0;
440 + break;
441 + case '1':
442 + var->enabled = 1;
443 + }
444 + }
445 +
446 + return (int) length;
447 +}
448 +
449 +
450 +static int
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)
454 +{
455 + const struct condition6_info *info =
456 + (const struct condition6_info *) matchinfo;
457 + struct condition_variable *var;
458 + int condition_status = 0;
459 +
460 + read_lock(&list_lock);
461 +
462 + for (var = head; var; var = var->next) {
463 + if (strcmp(info->name, var->status_proc->name) == 0) {
464 + condition_status = var->enabled;
465 + break;
466 + }
467 + }
468 +
469 + read_unlock(&list_lock);
470 +
471 + return condition_status ^ info->invert;
472 +}
473 +
474 +
475 +
476 +static int
477 +checkentry(const char *tablename, const struct ip6t_ip6 *ip,
478 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
479 +{
480 + struct condition6_info *info =
481 + (struct condition6_info *) matchinfo;
482 + struct condition_variable *var, *newvar;
483 +
484 + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
485 + return 0;
486 +
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);
490 +
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);
495 + return 1;
496 + }
497 + }
498 +
499 + read_unlock(&list_lock);
500 +
501 + /* At this point, we need to allocate a new condition variable */
502 + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
503 +
504 + if (!newvar)
505 + return -ENOMEM;
506 +
507 + /* Create the condition variable's proc file entry */
508 + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
509 +
510 + if (!newvar->status_proc) {
511 + /*
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.
515 + */
516 + kfree(newvar);
517 + read_lock(&list_lock);
518 +
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);
523 + return 1;
524 + }
525 + }
526 +
527 + read_unlock(&list_lock);
528 + return -ENOMEM;
529 + }
530 +
531 + atomic_set(&newvar->refcount, 1);
532 + newvar->enabled = 0;
533 + newvar->status_proc->owner = THIS_MODULE;
534 + newvar->status_proc->data = newvar;
535 + wmb();
536 + newvar->status_proc->read_proc = ipt_condition_read_info;
537 + newvar->status_proc->write_proc = ipt_condition_write_info;
538 +
539 + write_lock(&list_lock);
540 +
541 + newvar->next = head;
542 + head = newvar;
543 +
544 + write_unlock(&list_lock);
545 +
546 + return 1;
547 +}
548 +
549 +
550 +static void
551 +destroy(void *matchinfo, unsigned int matchsize)
552 +{
553 + struct condition6_info *info =
554 + (struct condition6_info *) matchinfo;
555 + struct condition_variable *var, *prev = NULL;
556 +
557 + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
558 + return;
559 +
560 + write_lock(&list_lock);
561 +
562 + for (var = head; var && strcmp(info->name, var->status_proc->name);
563 + prev = var, var = var->next);
564 +
565 + if (var && atomic_dec_and_test(&var->refcount)) {
566 + if (prev)
567 + prev->next = var->next;
568 + else
569 + head = var->next;
570 +
571 + write_unlock(&list_lock);
572 + remove_proc_entry(var->status_proc->name, proc_net_condition);
573 + kfree(var);
574 + } else
575 + write_unlock(&list_lock);
576 +}
577 +
578 +
579 +static struct ip6t_match condition_match = {
580 + .name = "condition",
581 + .match = &match,
582 + .checkentry = &checkentry,
583 + .destroy = &destroy,
584 + .me = THIS_MODULE
585 +};
586 +
587 +
588 +static int __init
589 +init(void)
590 +{
591 + int errorcode;
592 +
593 + rwlock_init(&list_lock);
594 + proc_net_condition = proc_mkdir("ip6t_condition", proc_net);
595 +
596 + if (proc_net_condition) {
597 + errorcode = ipt_register_match(&condition_match);
598 +
599 + if (errorcode)
600 + remove_proc_entry("ip6t_condition", proc_net);
601 + } else
602 + errorcode = -EACCES;
603 +
604 + return errorcode;
605 +}
606 +
607 +
608 +static void __exit
609 +fini(void)
610 +{
611 + ipt_unregister_match(&condition_match);
612 + remove_proc_entry("ip6t_condition", proc_net);
613 +}
614 +
615 +module_init(init);
616 +module_exit(fini);