aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2010-01-18 02:31:00 -0500
committerPatrick McHardy <kaber@trash.net>2010-01-18 02:31:00 -0500
commit7d07d5632b672c892a65882c2a119345fd9596c9 (patch)
tree8bc3f3c729837a805debdcaee9fe0c439cc6331e
parentf54e9367f8499a9bf6b2afbc0dce63e1d53c525a (diff)
netfilter: xt_recent: netns support
Make recent table list per-netns. Make proc files per-netns. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--net/netfilter/xt_recent.c136
1 files changed, 95 insertions, 41 deletions
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 768d01ff1fea..203333107367 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -28,6 +28,7 @@
28#include <linux/skbuff.h> 28#include <linux/skbuff.h>
29#include <linux/inet.h> 29#include <linux/inet.h>
30#include <net/net_namespace.h> 30#include <net/net_namespace.h>
31#include <net/netns/generic.h>
31 32
32#include <linux/netfilter/x_tables.h> 33#include <linux/netfilter/x_tables.h>
33#include <linux/netfilter/xt_recent.h> 34#include <linux/netfilter/xt_recent.h>
@@ -78,15 +79,26 @@ struct recent_table {
78 struct list_head iphash[0]; 79 struct list_head iphash[0];
79}; 80};
80 81
81static LIST_HEAD(tables); 82struct recent_net {
83 struct list_head tables;
84#ifdef CONFIG_PROC_FS
85 struct proc_dir_entry *xt_recent;
86#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
87 struct proc_dir_entry *ipt_recent;
88#endif
89#endif
90};
91
92static int recent_net_id;
93static inline struct recent_net *recent_pernet(struct net *net)
94{
95 return net_generic(net, recent_net_id);
96}
97
82static DEFINE_SPINLOCK(recent_lock); 98static DEFINE_SPINLOCK(recent_lock);
83static DEFINE_MUTEX(recent_mutex); 99static DEFINE_MUTEX(recent_mutex);
84 100
85#ifdef CONFIG_PROC_FS 101#ifdef CONFIG_PROC_FS
86#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
87static struct proc_dir_entry *proc_old_dir;
88#endif
89static struct proc_dir_entry *recent_proc_dir;
90static const struct file_operations recent_old_fops, recent_mt_fops; 102static const struct file_operations recent_old_fops, recent_mt_fops;
91#endif 103#endif
92 104
@@ -172,11 +184,12 @@ static void recent_entry_update(struct recent_table *t, struct recent_entry *e)
172 list_move_tail(&e->lru_list, &t->lru_list); 184 list_move_tail(&e->lru_list, &t->lru_list);
173} 185}
174 186
175static struct recent_table *recent_table_lookup(const char *name) 187static struct recent_table *recent_table_lookup(struct recent_net *recent_net,
188 const char *name)
176{ 189{
177 struct recent_table *t; 190 struct recent_table *t;
178 191
179 list_for_each_entry(t, &tables, list) 192 list_for_each_entry(t, &recent_net->tables, list)
180 if (!strcmp(t->name, name)) 193 if (!strcmp(t->name, name))
181 return t; 194 return t;
182 return NULL; 195 return NULL;
@@ -195,6 +208,8 @@ static void recent_table_flush(struct recent_table *t)
195static bool 208static bool
196recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) 209recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
197{ 210{
211 struct net *net = dev_net(par->in ? par->in : par->out);
212 struct recent_net *recent_net = recent_pernet(net);
198 const struct xt_recent_mtinfo *info = par->matchinfo; 213 const struct xt_recent_mtinfo *info = par->matchinfo;
199 struct recent_table *t; 214 struct recent_table *t;
200 struct recent_entry *e; 215 struct recent_entry *e;
@@ -227,7 +242,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
227 ttl++; 242 ttl++;
228 243
229 spin_lock_bh(&recent_lock); 244 spin_lock_bh(&recent_lock);
230 t = recent_table_lookup(info->name); 245 t = recent_table_lookup(recent_net, info->name);
231 e = recent_entry_lookup(t, &addr, par->match->family, 246 e = recent_entry_lookup(t, &addr, par->match->family,
232 (info->check_set & XT_RECENT_TTL) ? ttl : 0); 247 (info->check_set & XT_RECENT_TTL) ? ttl : 0);
233 if (e == NULL) { 248 if (e == NULL) {
@@ -271,6 +286,7 @@ out:
271 286
272static bool recent_mt_check(const struct xt_mtchk_param *par) 287static bool recent_mt_check(const struct xt_mtchk_param *par)
273{ 288{
289 struct recent_net *recent_net = recent_pernet(par->net);
274 const struct xt_recent_mtinfo *info = par->matchinfo; 290 const struct xt_recent_mtinfo *info = par->matchinfo;
275 struct recent_table *t; 291 struct recent_table *t;
276#ifdef CONFIG_PROC_FS 292#ifdef CONFIG_PROC_FS
@@ -297,7 +313,7 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
297 return false; 313 return false;
298 314
299 mutex_lock(&recent_mutex); 315 mutex_lock(&recent_mutex);
300 t = recent_table_lookup(info->name); 316 t = recent_table_lookup(recent_net, info->name);
301 if (t != NULL) { 317 if (t != NULL) {
302 t->refcnt++; 318 t->refcnt++;
303 ret = true; 319 ret = true;
@@ -314,7 +330,7 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
314 for (i = 0; i < ip_list_hash_size; i++) 330 for (i = 0; i < ip_list_hash_size; i++)
315 INIT_LIST_HEAD(&t->iphash[i]); 331 INIT_LIST_HEAD(&t->iphash[i]);
316#ifdef CONFIG_PROC_FS 332#ifdef CONFIG_PROC_FS
317 pde = proc_create_data(t->name, ip_list_perms, recent_proc_dir, 333 pde = proc_create_data(t->name, ip_list_perms, recent_net->xt_recent,
318 &recent_mt_fops, t); 334 &recent_mt_fops, t);
319 if (pde == NULL) { 335 if (pde == NULL) {
320 kfree(t); 336 kfree(t);
@@ -323,10 +339,10 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
323 pde->uid = ip_list_uid; 339 pde->uid = ip_list_uid;
324 pde->gid = ip_list_gid; 340 pde->gid = ip_list_gid;
325#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT 341#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
326 pde = proc_create_data(t->name, ip_list_perms, proc_old_dir, 342 pde = proc_create_data(t->name, ip_list_perms, recent_net->ipt_recent,
327 &recent_old_fops, t); 343 &recent_old_fops, t);
328 if (pde == NULL) { 344 if (pde == NULL) {
329 remove_proc_entry(t->name, proc_old_dir); 345 remove_proc_entry(t->name, recent_net->xt_recent);
330 kfree(t); 346 kfree(t);
331 goto out; 347 goto out;
332 } 348 }
@@ -335,7 +351,7 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
335#endif 351#endif
336#endif 352#endif
337 spin_lock_bh(&recent_lock); 353 spin_lock_bh(&recent_lock);
338 list_add_tail(&t->list, &tables); 354 list_add_tail(&t->list, &recent_net->tables);
339 spin_unlock_bh(&recent_lock); 355 spin_unlock_bh(&recent_lock);
340 ret = true; 356 ret = true;
341out: 357out:
@@ -345,20 +361,21 @@ out:
345 361
346static void recent_mt_destroy(const struct xt_mtdtor_param *par) 362static void recent_mt_destroy(const struct xt_mtdtor_param *par)
347{ 363{
364 struct recent_net *recent_net = recent_pernet(par->net);
348 const struct xt_recent_mtinfo *info = par->matchinfo; 365 const struct xt_recent_mtinfo *info = par->matchinfo;
349 struct recent_table *t; 366 struct recent_table *t;
350 367
351 mutex_lock(&recent_mutex); 368 mutex_lock(&recent_mutex);
352 t = recent_table_lookup(info->name); 369 t = recent_table_lookup(recent_net, info->name);
353 if (--t->refcnt == 0) { 370 if (--t->refcnt == 0) {
354 spin_lock_bh(&recent_lock); 371 spin_lock_bh(&recent_lock);
355 list_del(&t->list); 372 list_del(&t->list);
356 spin_unlock_bh(&recent_lock); 373 spin_unlock_bh(&recent_lock);
357#ifdef CONFIG_PROC_FS 374#ifdef CONFIG_PROC_FS
358#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT 375#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
359 remove_proc_entry(t->name, proc_old_dir); 376 remove_proc_entry(t->name, recent_net->ipt_recent);
360#endif 377#endif
361 remove_proc_entry(t->name, recent_proc_dir); 378 remove_proc_entry(t->name, recent_net->xt_recent);
362#endif 379#endif
363 recent_table_flush(t); 380 recent_table_flush(t);
364 kfree(t); 381 kfree(t);
@@ -607,8 +624,65 @@ static const struct file_operations recent_mt_fops = {
607 .release = seq_release_private, 624 .release = seq_release_private,
608 .owner = THIS_MODULE, 625 .owner = THIS_MODULE,
609}; 626};
627
628static int __net_init recent_proc_net_init(struct net *net)
629{
630 struct recent_net *recent_net = recent_pernet(net);
631
632 recent_net->xt_recent = proc_mkdir("xt_recent", net->proc_net);
633 if (!recent_net->xt_recent)
634 return -ENOMEM;
635#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
636 recent_net->ipt_recent = proc_mkdir("ipt_recent", net->proc_net);
637 if (!recent_net->ipt_recent) {
638 proc_net_remove(net, "xt_recent");
639 return -ENOMEM;
640 }
641#endif
642 return 0;
643}
644
645static void __net_exit recent_proc_net_exit(struct net *net)
646{
647#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
648 proc_net_remove(net, "ipt_recent");
649#endif
650 proc_net_remove(net, "xt_recent");
651}
652#else
653static inline int recent_proc_net_init(struct net *net)
654{
655 return 0;
656}
657
658static inline void recent_proc_net_exit(struct net *net)
659{
660}
610#endif /* CONFIG_PROC_FS */ 661#endif /* CONFIG_PROC_FS */
611 662
663static int __net_init recent_net_init(struct net *net)
664{
665 struct recent_net *recent_net = recent_pernet(net);
666
667 INIT_LIST_HEAD(&recent_net->tables);
668 return recent_proc_net_init(net);
669}
670
671static void __net_exit recent_net_exit(struct net *net)
672{
673 struct recent_net *recent_net = recent_pernet(net);
674
675 BUG_ON(!list_empty(&recent_net->tables));
676 recent_proc_net_exit(net);
677}
678
679static struct pernet_operations recent_net_ops = {
680 .init = recent_net_init,
681 .exit = recent_net_exit,
682 .id = &recent_net_id,
683 .size = sizeof(struct recent_net),
684};
685
612static struct xt_match recent_mt_reg[] __read_mostly = { 686static struct xt_match recent_mt_reg[] __read_mostly = {
613 { 687 {
614 .name = "recent", 688 .name = "recent",
@@ -640,39 +714,19 @@ static int __init recent_mt_init(void)
640 return -EINVAL; 714 return -EINVAL;
641 ip_list_hash_size = 1 << fls(ip_list_tot); 715 ip_list_hash_size = 1 << fls(ip_list_tot);
642 716
643 err = xt_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); 717 err = register_pernet_subsys(&recent_net_ops);
644#ifdef CONFIG_PROC_FS
645 if (err) 718 if (err)
646 return err; 719 return err;
647 recent_proc_dir = proc_mkdir("xt_recent", init_net.proc_net); 720 err = xt_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
648 if (recent_proc_dir == NULL) { 721 if (err)
649 xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); 722 unregister_pernet_subsys(&recent_net_ops);
650 err = -ENOMEM;
651 }
652#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
653 if (err < 0)
654 return err;
655 proc_old_dir = proc_mkdir("ipt_recent", init_net.proc_net);
656 if (proc_old_dir == NULL) {
657 remove_proc_entry("xt_recent", init_net.proc_net);
658 xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
659 err = -ENOMEM;
660 }
661#endif
662#endif
663 return err; 723 return err;
664} 724}
665 725
666static void __exit recent_mt_exit(void) 726static void __exit recent_mt_exit(void)
667{ 727{
668 BUG_ON(!list_empty(&tables));
669 xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); 728 xt_unregister_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg));
670#ifdef CONFIG_PROC_FS 729 unregister_pernet_subsys(&recent_net_ops);
671#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
672 remove_proc_entry("ipt_recent", init_net.proc_net);
673#endif
674 remove_proc_entry("xt_recent", init_net.proc_net);
675#endif
676} 730}
677 731
678module_init(recent_mt_init); 732module_init(recent_mt_init);