c6ffe5b32558987995774a34031af287911f5f6c
[openwrt.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);