diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2010-01-18 02:31:00 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-01-18 02:31:00 -0500 |
commit | 7d07d5632b672c892a65882c2a119345fd9596c9 (patch) | |
tree | 8bc3f3c729837a805debdcaee9fe0c439cc6331e | |
parent | f54e9367f8499a9bf6b2afbc0dce63e1d53c525a (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.c | 136 |
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 | ||
81 | static LIST_HEAD(tables); | 82 | struct 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 | |||
92 | static int recent_net_id; | ||
93 | static inline struct recent_net *recent_pernet(struct net *net) | ||
94 | { | ||
95 | return net_generic(net, recent_net_id); | ||
96 | } | ||
97 | |||
82 | static DEFINE_SPINLOCK(recent_lock); | 98 | static DEFINE_SPINLOCK(recent_lock); |
83 | static DEFINE_MUTEX(recent_mutex); | 99 | static 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 | ||
87 | static struct proc_dir_entry *proc_old_dir; | ||
88 | #endif | ||
89 | static struct proc_dir_entry *recent_proc_dir; | ||
90 | static const struct file_operations recent_old_fops, recent_mt_fops; | 102 | static 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 | ||
175 | static struct recent_table *recent_table_lookup(const char *name) | 187 | static 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) | |||
195 | static bool | 208 | static bool |
196 | recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 209 | recent_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 | ||
272 | static bool recent_mt_check(const struct xt_mtchk_param *par) | 287 | static 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; |
341 | out: | 357 | out: |
@@ -345,20 +361,21 @@ out: | |||
345 | 361 | ||
346 | static void recent_mt_destroy(const struct xt_mtdtor_param *par) | 362 | static 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 | |||
628 | static 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 | |||
645 | static 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 | ||
653 | static inline int recent_proc_net_init(struct net *net) | ||
654 | { | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static inline void recent_proc_net_exit(struct net *net) | ||
659 | { | ||
660 | } | ||
610 | #endif /* CONFIG_PROC_FS */ | 661 | #endif /* CONFIG_PROC_FS */ |
611 | 662 | ||
663 | static 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 | |||
671 | static 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 | |||
679 | static 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 | |||
612 | static struct xt_match recent_mt_reg[] __read_mostly = { | 686 | static 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 | ||
666 | static void __exit recent_mt_exit(void) | 726 | static 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 | ||
678 | module_init(recent_mt_init); | 732 | module_init(recent_mt_init); |