diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-10-10 17:28:33 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-10-14 12:00:59 -0400 |
commit | 99633ab29b2131b68089a6c7f60458390860e044 (patch) | |
tree | eb7e2ecd9ed875ed4d3a050b95ed3d77bbde762b | |
parent | eb31628e37a0a4e01fffd79dcc7f815d2357f53a (diff) |
netfilter: nf_tables: complete net namespace support
Register family per netnamespace to ensure that sets are
only visible in its approapriate namespace.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/net/net_namespace.h | 4 | ||||
-rw-r--r-- | include/net/netfilter/nf_tables.h | 4 | ||||
-rw-r--r-- | include/net/netns/nftables.h | 15 | ||||
-rw-r--r-- | net/bridge/netfilter/nf_tables_bridge.c | 32 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_tables_ipv4.c | 32 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_tables_ipv6.c | 33 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 83 |
7 files changed, 168 insertions, 35 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index bcc4a8ed4450..da68c9a90ac5 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 22 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
23 | #include <net/netns/conntrack.h> | 23 | #include <net/netns/conntrack.h> |
24 | #endif | 24 | #endif |
25 | #include <net/netns/nftables.h> | ||
25 | #include <net/netns/xfrm.h> | 26 | #include <net/netns/xfrm.h> |
26 | 27 | ||
27 | struct user_namespace; | 28 | struct user_namespace; |
@@ -101,6 +102,9 @@ struct net { | |||
101 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 102 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
102 | struct netns_ct ct; | 103 | struct netns_ct ct; |
103 | #endif | 104 | #endif |
105 | #if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE) | ||
106 | struct netns_nftables nft; | ||
107 | #endif | ||
104 | #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) | 108 | #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) |
105 | struct netns_nf_frag nf_frag; | 109 | struct netns_nf_frag nf_frag; |
106 | #endif | 110 | #endif |
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index a68f45f0fe2e..d3272e943aac 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -68,6 +68,7 @@ static inline void nft_data_debug(const struct nft_data *data) | |||
68 | /** | 68 | /** |
69 | * struct nft_ctx - nf_tables rule/set context | 69 | * struct nft_ctx - nf_tables rule/set context |
70 | * | 70 | * |
71 | * @net: net namespace | ||
71 | * @skb: netlink skb | 72 | * @skb: netlink skb |
72 | * @nlh: netlink message header | 73 | * @nlh: netlink message header |
73 | * @afi: address family info | 74 | * @afi: address family info |
@@ -76,6 +77,7 @@ static inline void nft_data_debug(const struct nft_data *data) | |||
76 | * @nla: netlink attributes | 77 | * @nla: netlink attributes |
77 | */ | 78 | */ |
78 | struct nft_ctx { | 79 | struct nft_ctx { |
80 | struct net *net; | ||
79 | const struct sk_buff *skb; | 81 | const struct sk_buff *skb; |
80 | const struct nlmsghdr *nlh; | 82 | const struct nlmsghdr *nlh; |
81 | const struct nft_af_info *afi; | 83 | const struct nft_af_info *afi; |
@@ -462,7 +464,7 @@ struct nft_af_info { | |||
462 | nf_hookfn *hooks[NF_MAX_HOOKS]; | 464 | nf_hookfn *hooks[NF_MAX_HOOKS]; |
463 | }; | 465 | }; |
464 | 466 | ||
465 | extern int nft_register_afinfo(struct nft_af_info *); | 467 | extern int nft_register_afinfo(struct net *, struct nft_af_info *); |
466 | extern void nft_unregister_afinfo(struct nft_af_info *); | 468 | extern void nft_unregister_afinfo(struct nft_af_info *); |
467 | 469 | ||
468 | struct nf_chain_type { | 470 | struct nf_chain_type { |
diff --git a/include/net/netns/nftables.h b/include/net/netns/nftables.h new file mode 100644 index 000000000000..a98b1c5d9913 --- /dev/null +++ b/include/net/netns/nftables.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef _NETNS_NFTABLES_H_ | ||
2 | #define _NETNS_NFTABLES_H_ | ||
3 | |||
4 | #include <linux/list.h> | ||
5 | |||
6 | struct nft_af_info; | ||
7 | |||
8 | struct netns_nftables { | ||
9 | struct list_head af_info; | ||
10 | struct nft_af_info *ipv4; | ||
11 | struct nft_af_info *ipv6; | ||
12 | struct nft_af_info *bridge; | ||
13 | }; | ||
14 | |||
15 | #endif | ||
diff --git a/net/bridge/netfilter/nf_tables_bridge.c b/net/bridge/netfilter/nf_tables_bridge.c index bc5c21c911c0..e8cb016fa34d 100644 --- a/net/bridge/netfilter/nf_tables_bridge.c +++ b/net/bridge/netfilter/nf_tables_bridge.c | |||
@@ -19,14 +19,42 @@ static struct nft_af_info nft_af_bridge __read_mostly = { | |||
19 | .owner = THIS_MODULE, | 19 | .owner = THIS_MODULE, |
20 | }; | 20 | }; |
21 | 21 | ||
22 | static int nf_tables_bridge_init_net(struct net *net) | ||
23 | { | ||
24 | net->nft.bridge = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); | ||
25 | if (net->nft.bridge == NULL) | ||
26 | return -ENOMEM; | ||
27 | |||
28 | memcpy(net->nft.bridge, &nft_af_bridge, sizeof(nft_af_bridge)); | ||
29 | |||
30 | if (nft_register_afinfo(net, net->nft.bridge) < 0) | ||
31 | goto err; | ||
32 | |||
33 | return 0; | ||
34 | err: | ||
35 | kfree(net->nft.bridge); | ||
36 | return -ENOMEM; | ||
37 | } | ||
38 | |||
39 | static void nf_tables_bridge_exit_net(struct net *net) | ||
40 | { | ||
41 | nft_unregister_afinfo(net->nft.bridge); | ||
42 | kfree(net->nft.bridge); | ||
43 | } | ||
44 | |||
45 | static struct pernet_operations nf_tables_bridge_net_ops = { | ||
46 | .init = nf_tables_bridge_init_net, | ||
47 | .exit = nf_tables_bridge_exit_net, | ||
48 | }; | ||
49 | |||
22 | static int __init nf_tables_bridge_init(void) | 50 | static int __init nf_tables_bridge_init(void) |
23 | { | 51 | { |
24 | return nft_register_afinfo(&nft_af_bridge); | 52 | return register_pernet_subsys(&nf_tables_bridge_net_ops); |
25 | } | 53 | } |
26 | 54 | ||
27 | static void __exit nf_tables_bridge_exit(void) | 55 | static void __exit nf_tables_bridge_exit(void) |
28 | { | 56 | { |
29 | nft_unregister_afinfo(&nft_af_bridge); | 57 | return unregister_pernet_subsys(&nf_tables_bridge_net_ops); |
30 | } | 58 | } |
31 | 59 | ||
32 | module_init(nf_tables_bridge_init); | 60 | module_init(nf_tables_bridge_init); |
diff --git a/net/ipv4/netfilter/nf_tables_ipv4.c b/net/ipv4/netfilter/nf_tables_ipv4.c index c61cffb9b760..8f7536be1322 100644 --- a/net/ipv4/netfilter/nf_tables_ipv4.c +++ b/net/ipv4/netfilter/nf_tables_ipv4.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/ip.h> | 14 | #include <linux/ip.h> |
15 | #include <linux/netfilter_ipv4.h> | 15 | #include <linux/netfilter_ipv4.h> |
16 | #include <net/netfilter/nf_tables.h> | 16 | #include <net/netfilter/nf_tables.h> |
17 | #include <net/net_namespace.h> | ||
17 | #include <net/ip.h> | 18 | #include <net/ip.h> |
18 | #include <net/net_namespace.h> | 19 | #include <net/net_namespace.h> |
19 | #include <net/netfilter/nf_tables_ipv4.h> | 20 | #include <net/netfilter/nf_tables_ipv4.h> |
@@ -47,6 +48,33 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = { | |||
47 | }, | 48 | }, |
48 | }; | 49 | }; |
49 | 50 | ||
51 | static int nf_tables_ipv4_init_net(struct net *net) | ||
52 | { | ||
53 | net->nft.ipv4 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); | ||
54 | if (net->nft.ipv4 == NULL) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | memcpy(net->nft.ipv4, &nft_af_ipv4, sizeof(nft_af_ipv4)); | ||
58 | |||
59 | if (nft_register_afinfo(net, net->nft.ipv4) < 0) | ||
60 | goto err; | ||
61 | |||
62 | return 0; | ||
63 | err: | ||
64 | kfree(net->nft.ipv4); | ||
65 | return -ENOMEM; | ||
66 | } | ||
67 | |||
68 | static void nf_tables_ipv4_exit_net(struct net *net) | ||
69 | { | ||
70 | nft_unregister_afinfo(net->nft.ipv4); | ||
71 | kfree(net->nft.ipv4); | ||
72 | } | ||
73 | |||
74 | static struct pernet_operations nf_tables_ipv4_net_ops = { | ||
75 | .init = nf_tables_ipv4_init_net, | ||
76 | .exit = nf_tables_ipv4_exit_net, | ||
77 | }; | ||
50 | 78 | ||
51 | static unsigned int | 79 | static unsigned int |
52 | nft_do_chain_ipv4(const struct nf_hook_ops *ops, | 80 | nft_do_chain_ipv4(const struct nf_hook_ops *ops, |
@@ -83,12 +111,12 @@ static struct nf_chain_type filter_ipv4 = { | |||
83 | static int __init nf_tables_ipv4_init(void) | 111 | static int __init nf_tables_ipv4_init(void) |
84 | { | 112 | { |
85 | nft_register_chain_type(&filter_ipv4); | 113 | nft_register_chain_type(&filter_ipv4); |
86 | return nft_register_afinfo(&nft_af_ipv4); | 114 | return register_pernet_subsys(&nf_tables_ipv4_net_ops); |
87 | } | 115 | } |
88 | 116 | ||
89 | static void __exit nf_tables_ipv4_exit(void) | 117 | static void __exit nf_tables_ipv4_exit(void) |
90 | { | 118 | { |
91 | nft_unregister_afinfo(&nft_af_ipv4); | 119 | unregister_pernet_subsys(&nf_tables_ipv4_net_ops); |
92 | nft_unregister_chain_type(&filter_ipv4); | 120 | nft_unregister_chain_type(&filter_ipv4); |
93 | } | 121 | } |
94 | 122 | ||
diff --git a/net/ipv6/netfilter/nf_tables_ipv6.c b/net/ipv6/netfilter/nf_tables_ipv6.c index 42f905a808a3..d77db8a13505 100644 --- a/net/ipv6/netfilter/nf_tables_ipv6.c +++ b/net/ipv6/netfilter/nf_tables_ipv6.c | |||
@@ -45,6 +45,34 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = { | |||
45 | }, | 45 | }, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static int nf_tables_ipv6_init_net(struct net *net) | ||
49 | { | ||
50 | net->nft.ipv6 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL); | ||
51 | if (net->nft.ipv6 == NULL) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | memcpy(net->nft.ipv6, &nft_af_ipv6, sizeof(nft_af_ipv6)); | ||
55 | |||
56 | if (nft_register_afinfo(net, net->nft.ipv6) < 0) | ||
57 | goto err; | ||
58 | |||
59 | return 0; | ||
60 | err: | ||
61 | kfree(net->nft.ipv6); | ||
62 | return -ENOMEM; | ||
63 | } | ||
64 | |||
65 | static void nf_tables_ipv6_exit_net(struct net *net) | ||
66 | { | ||
67 | nft_unregister_afinfo(net->nft.ipv6); | ||
68 | kfree(net->nft.ipv6); | ||
69 | } | ||
70 | |||
71 | static struct pernet_operations nf_tables_ipv6_net_ops = { | ||
72 | .init = nf_tables_ipv6_init_net, | ||
73 | .exit = nf_tables_ipv6_exit_net, | ||
74 | }; | ||
75 | |||
48 | static unsigned int | 76 | static unsigned int |
49 | nft_do_chain_ipv6(const struct nf_hook_ops *ops, | 77 | nft_do_chain_ipv6(const struct nf_hook_ops *ops, |
50 | struct sk_buff *skb, | 78 | struct sk_buff *skb, |
@@ -82,11 +110,12 @@ static struct nf_chain_type filter_ipv6 = { | |||
82 | static int __init nf_tables_ipv6_init(void) | 110 | static int __init nf_tables_ipv6_init(void) |
83 | { | 111 | { |
84 | nft_register_chain_type(&filter_ipv6); | 112 | nft_register_chain_type(&filter_ipv6); |
85 | return nft_register_afinfo(&nft_af_ipv6); | 113 | return register_pernet_subsys(&nf_tables_ipv6_net_ops); |
86 | } | 114 | } |
115 | |||
87 | static void __exit nf_tables_ipv6_exit(void) | 116 | static void __exit nf_tables_ipv6_exit(void) |
88 | { | 117 | { |
89 | nft_unregister_afinfo(&nft_af_ipv6); | 118 | unregister_pernet_subsys(&nf_tables_ipv6_net_ops); |
90 | nft_unregister_chain_type(&filter_ipv6); | 119 | nft_unregister_chain_type(&filter_ipv6); |
91 | } | 120 | } |
92 | 121 | ||
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index a4dd7ce5ec3e..e1ee85047ec1 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -18,9 +18,9 @@ | |||
18 | #include <linux/netfilter/nf_tables.h> | 18 | #include <linux/netfilter/nf_tables.h> |
19 | #include <net/netfilter/nf_tables_core.h> | 19 | #include <net/netfilter/nf_tables_core.h> |
20 | #include <net/netfilter/nf_tables.h> | 20 | #include <net/netfilter/nf_tables.h> |
21 | #include <net/net_namespace.h> | ||
21 | #include <net/sock.h> | 22 | #include <net/sock.h> |
22 | 23 | ||
23 | static LIST_HEAD(nf_tables_afinfo); | ||
24 | static LIST_HEAD(nf_tables_expressions); | 24 | static LIST_HEAD(nf_tables_expressions); |
25 | 25 | ||
26 | /** | 26 | /** |
@@ -31,11 +31,11 @@ static LIST_HEAD(nf_tables_expressions); | |||
31 | * Register the address family for use with nf_tables. Returns zero on | 31 | * Register the address family for use with nf_tables. Returns zero on |
32 | * success or a negative errno code otherwise. | 32 | * success or a negative errno code otherwise. |
33 | */ | 33 | */ |
34 | int nft_register_afinfo(struct nft_af_info *afi) | 34 | int nft_register_afinfo(struct net *net, struct nft_af_info *afi) |
35 | { | 35 | { |
36 | INIT_LIST_HEAD(&afi->tables); | 36 | INIT_LIST_HEAD(&afi->tables); |
37 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 37 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
38 | list_add_tail(&afi->list, &nf_tables_afinfo); | 38 | list_add_tail(&afi->list, &net->nft.af_info); |
39 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 39 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
40 | return 0; | 40 | return 0; |
41 | } | 41 | } |
@@ -56,22 +56,23 @@ void nft_unregister_afinfo(struct nft_af_info *afi) | |||
56 | } | 56 | } |
57 | EXPORT_SYMBOL_GPL(nft_unregister_afinfo); | 57 | EXPORT_SYMBOL_GPL(nft_unregister_afinfo); |
58 | 58 | ||
59 | static struct nft_af_info *nft_afinfo_lookup(int family) | 59 | static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family) |
60 | { | 60 | { |
61 | struct nft_af_info *afi; | 61 | struct nft_af_info *afi; |
62 | 62 | ||
63 | list_for_each_entry(afi, &nf_tables_afinfo, list) { | 63 | list_for_each_entry(afi, &net->nft.af_info, list) { |
64 | if (afi->family == family) | 64 | if (afi->family == family) |
65 | return afi; | 65 | return afi; |
66 | } | 66 | } |
67 | return NULL; | 67 | return NULL; |
68 | } | 68 | } |
69 | 69 | ||
70 | static struct nft_af_info *nf_tables_afinfo_lookup(int family, bool autoload) | 70 | static struct nft_af_info * |
71 | nf_tables_afinfo_lookup(struct net *net, int family, bool autoload) | ||
71 | { | 72 | { |
72 | struct nft_af_info *afi; | 73 | struct nft_af_info *afi; |
73 | 74 | ||
74 | afi = nft_afinfo_lookup(family); | 75 | afi = nft_afinfo_lookup(net, family); |
75 | if (afi != NULL) | 76 | if (afi != NULL) |
76 | return afi; | 77 | return afi; |
77 | #ifdef CONFIG_MODULES | 78 | #ifdef CONFIG_MODULES |
@@ -79,7 +80,7 @@ static struct nft_af_info *nf_tables_afinfo_lookup(int family, bool autoload) | |||
79 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); | 80 | nfnl_unlock(NFNL_SUBSYS_NFTABLES); |
80 | request_module("nft-afinfo-%u", family); | 81 | request_module("nft-afinfo-%u", family); |
81 | nfnl_lock(NFNL_SUBSYS_NFTABLES); | 82 | nfnl_lock(NFNL_SUBSYS_NFTABLES); |
82 | afi = nft_afinfo_lookup(family); | 83 | afi = nft_afinfo_lookup(net, family); |
83 | if (afi != NULL) | 84 | if (afi != NULL) |
84 | return ERR_PTR(-EAGAIN); | 85 | return ERR_PTR(-EAGAIN); |
85 | } | 86 | } |
@@ -232,9 +233,10 @@ static int nf_tables_dump_tables(struct sk_buff *skb, | |||
232 | const struct nft_af_info *afi; | 233 | const struct nft_af_info *afi; |
233 | const struct nft_table *table; | 234 | const struct nft_table *table; |
234 | unsigned int idx = 0, s_idx = cb->args[0]; | 235 | unsigned int idx = 0, s_idx = cb->args[0]; |
236 | struct net *net = sock_net(skb->sk); | ||
235 | int family = nfmsg->nfgen_family; | 237 | int family = nfmsg->nfgen_family; |
236 | 238 | ||
237 | list_for_each_entry(afi, &nf_tables_afinfo, list) { | 239 | list_for_each_entry(afi, &net->nft.af_info, list) { |
238 | if (family != NFPROTO_UNSPEC && family != afi->family) | 240 | if (family != NFPROTO_UNSPEC && family != afi->family) |
239 | continue; | 241 | continue; |
240 | 242 | ||
@@ -268,6 +270,7 @@ static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb, | |||
268 | const struct nft_af_info *afi; | 270 | const struct nft_af_info *afi; |
269 | const struct nft_table *table; | 271 | const struct nft_table *table; |
270 | struct sk_buff *skb2; | 272 | struct sk_buff *skb2; |
273 | struct net *net = sock_net(skb->sk); | ||
271 | int family = nfmsg->nfgen_family; | 274 | int family = nfmsg->nfgen_family; |
272 | int err; | 275 | int err; |
273 | 276 | ||
@@ -278,7 +281,7 @@ static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb, | |||
278 | return netlink_dump_start(nlsk, skb, nlh, &c); | 281 | return netlink_dump_start(nlsk, skb, nlh, &c); |
279 | } | 282 | } |
280 | 283 | ||
281 | afi = nf_tables_afinfo_lookup(family, false); | 284 | afi = nf_tables_afinfo_lookup(net, family, false); |
282 | if (IS_ERR(afi)) | 285 | if (IS_ERR(afi)) |
283 | return PTR_ERR(afi); | 286 | return PTR_ERR(afi); |
284 | 287 | ||
@@ -379,9 +382,10 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, | |||
379 | const struct nlattr *name; | 382 | const struct nlattr *name; |
380 | struct nft_af_info *afi; | 383 | struct nft_af_info *afi; |
381 | struct nft_table *table; | 384 | struct nft_table *table; |
385 | struct net *net = sock_net(skb->sk); | ||
382 | int family = nfmsg->nfgen_family; | 386 | int family = nfmsg->nfgen_family; |
383 | 387 | ||
384 | afi = nf_tables_afinfo_lookup(family, true); | 388 | afi = nf_tables_afinfo_lookup(net, family, true); |
385 | if (IS_ERR(afi)) | 389 | if (IS_ERR(afi)) |
386 | return PTR_ERR(afi); | 390 | return PTR_ERR(afi); |
387 | 391 | ||
@@ -433,9 +437,10 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, | |||
433 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 437 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
434 | struct nft_af_info *afi; | 438 | struct nft_af_info *afi; |
435 | struct nft_table *table; | 439 | struct nft_table *table; |
440 | struct net *net = sock_net(skb->sk); | ||
436 | int family = nfmsg->nfgen_family; | 441 | int family = nfmsg->nfgen_family; |
437 | 442 | ||
438 | afi = nf_tables_afinfo_lookup(family, false); | 443 | afi = nf_tables_afinfo_lookup(net, family, false); |
439 | if (IS_ERR(afi)) | 444 | if (IS_ERR(afi)) |
440 | return PTR_ERR(afi); | 445 | return PTR_ERR(afi); |
441 | 446 | ||
@@ -663,9 +668,10 @@ static int nf_tables_dump_chains(struct sk_buff *skb, | |||
663 | const struct nft_table *table; | 668 | const struct nft_table *table; |
664 | const struct nft_chain *chain; | 669 | const struct nft_chain *chain; |
665 | unsigned int idx = 0, s_idx = cb->args[0]; | 670 | unsigned int idx = 0, s_idx = cb->args[0]; |
671 | struct net *net = sock_net(skb->sk); | ||
666 | int family = nfmsg->nfgen_family; | 672 | int family = nfmsg->nfgen_family; |
667 | 673 | ||
668 | list_for_each_entry(afi, &nf_tables_afinfo, list) { | 674 | list_for_each_entry(afi, &net->nft.af_info, list) { |
669 | if (family != NFPROTO_UNSPEC && family != afi->family) | 675 | if (family != NFPROTO_UNSPEC && family != afi->family) |
670 | continue; | 676 | continue; |
671 | 677 | ||
@@ -702,6 +708,7 @@ static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb, | |||
702 | const struct nft_table *table; | 708 | const struct nft_table *table; |
703 | const struct nft_chain *chain; | 709 | const struct nft_chain *chain; |
704 | struct sk_buff *skb2; | 710 | struct sk_buff *skb2; |
711 | struct net *net = sock_net(skb->sk); | ||
705 | int family = nfmsg->nfgen_family; | 712 | int family = nfmsg->nfgen_family; |
706 | int err; | 713 | int err; |
707 | 714 | ||
@@ -712,7 +719,7 @@ static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb, | |||
712 | return netlink_dump_start(nlsk, skb, nlh, &c); | 719 | return netlink_dump_start(nlsk, skb, nlh, &c); |
713 | } | 720 | } |
714 | 721 | ||
715 | afi = nf_tables_afinfo_lookup(family, false); | 722 | afi = nf_tables_afinfo_lookup(net, family, false); |
716 | if (IS_ERR(afi)) | 723 | if (IS_ERR(afi)) |
717 | return PTR_ERR(afi); | 724 | return PTR_ERR(afi); |
718 | 725 | ||
@@ -813,6 +820,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
813 | struct nft_chain *chain; | 820 | struct nft_chain *chain; |
814 | struct nft_base_chain *basechain = NULL; | 821 | struct nft_base_chain *basechain = NULL; |
815 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; | 822 | struct nlattr *ha[NFTA_HOOK_MAX + 1]; |
823 | struct net *net = sock_net(skb->sk); | ||
816 | int family = nfmsg->nfgen_family; | 824 | int family = nfmsg->nfgen_family; |
817 | u64 handle = 0; | 825 | u64 handle = 0; |
818 | int err; | 826 | int err; |
@@ -820,7 +828,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb, | |||
820 | 828 | ||
821 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; | 829 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; |
822 | 830 | ||
823 | afi = nf_tables_afinfo_lookup(family, true); | 831 | afi = nf_tables_afinfo_lookup(net, family, true); |
824 | if (IS_ERR(afi)) | 832 | if (IS_ERR(afi)) |
825 | return PTR_ERR(afi); | 833 | return PTR_ERR(afi); |
826 | 834 | ||
@@ -1010,9 +1018,10 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb, | |||
1010 | const struct nft_af_info *afi; | 1018 | const struct nft_af_info *afi; |
1011 | struct nft_table *table; | 1019 | struct nft_table *table; |
1012 | struct nft_chain *chain; | 1020 | struct nft_chain *chain; |
1021 | struct net *net = sock_net(skb->sk); | ||
1013 | int family = nfmsg->nfgen_family; | 1022 | int family = nfmsg->nfgen_family; |
1014 | 1023 | ||
1015 | afi = nf_tables_afinfo_lookup(family, false); | 1024 | afi = nf_tables_afinfo_lookup(net, family, false); |
1016 | if (IS_ERR(afi)) | 1025 | if (IS_ERR(afi)) |
1017 | return PTR_ERR(afi); | 1026 | return PTR_ERR(afi); |
1018 | 1027 | ||
@@ -1050,6 +1059,7 @@ static void nft_ctx_init(struct nft_ctx *ctx, | |||
1050 | const struct nft_chain *chain, | 1059 | const struct nft_chain *chain, |
1051 | const struct nlattr * const *nla) | 1060 | const struct nlattr * const *nla) |
1052 | { | 1061 | { |
1062 | ctx->net = sock_net(skb->sk); | ||
1053 | ctx->skb = skb; | 1063 | ctx->skb = skb; |
1054 | ctx->nlh = nlh; | 1064 | ctx->nlh = nlh; |
1055 | ctx->afi = afi; | 1065 | ctx->afi = afi; |
@@ -1361,9 +1371,10 @@ static int nf_tables_dump_rules(struct sk_buff *skb, | |||
1361 | const struct nft_chain *chain; | 1371 | const struct nft_chain *chain; |
1362 | const struct nft_rule *rule; | 1372 | const struct nft_rule *rule; |
1363 | unsigned int idx = 0, s_idx = cb->args[0]; | 1373 | unsigned int idx = 0, s_idx = cb->args[0]; |
1374 | struct net *net = sock_net(skb->sk); | ||
1364 | int family = nfmsg->nfgen_family; | 1375 | int family = nfmsg->nfgen_family; |
1365 | 1376 | ||
1366 | list_for_each_entry(afi, &nf_tables_afinfo, list) { | 1377 | list_for_each_entry(afi, &net->nft.af_info, list) { |
1367 | if (family != NFPROTO_UNSPEC && family != afi->family) | 1378 | if (family != NFPROTO_UNSPEC && family != afi->family) |
1368 | continue; | 1379 | continue; |
1369 | 1380 | ||
@@ -1402,6 +1413,7 @@ static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb, | |||
1402 | const struct nft_chain *chain; | 1413 | const struct nft_chain *chain; |
1403 | const struct nft_rule *rule; | 1414 | const struct nft_rule *rule; |
1404 | struct sk_buff *skb2; | 1415 | struct sk_buff *skb2; |
1416 | struct net *net = sock_net(skb->sk); | ||
1405 | int family = nfmsg->nfgen_family; | 1417 | int family = nfmsg->nfgen_family; |
1406 | int err; | 1418 | int err; |
1407 | 1419 | ||
@@ -1412,7 +1424,7 @@ static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb, | |||
1412 | return netlink_dump_start(nlsk, skb, nlh, &c); | 1424 | return netlink_dump_start(nlsk, skb, nlh, &c); |
1413 | } | 1425 | } |
1414 | 1426 | ||
1415 | afi = nf_tables_afinfo_lookup(family, false); | 1427 | afi = nf_tables_afinfo_lookup(net, family, false); |
1416 | if (IS_ERR(afi)) | 1428 | if (IS_ERR(afi)) |
1417 | return PTR_ERR(afi); | 1429 | return PTR_ERR(afi); |
1418 | 1430 | ||
@@ -1477,6 +1489,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
1477 | { | 1489 | { |
1478 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 1490 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
1479 | const struct nft_af_info *afi; | 1491 | const struct nft_af_info *afi; |
1492 | struct net *net = sock_net(skb->sk); | ||
1480 | struct nft_table *table; | 1493 | struct nft_table *table; |
1481 | struct nft_chain *chain; | 1494 | struct nft_chain *chain; |
1482 | struct nft_rule *rule, *old_rule = NULL; | 1495 | struct nft_rule *rule, *old_rule = NULL; |
@@ -1490,7 +1503,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
1490 | 1503 | ||
1491 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; | 1504 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; |
1492 | 1505 | ||
1493 | afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, create); | 1506 | afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create); |
1494 | if (IS_ERR(afi)) | 1507 | if (IS_ERR(afi)) |
1495 | return PTR_ERR(afi); | 1508 | return PTR_ERR(afi); |
1496 | 1509 | ||
@@ -1585,12 +1598,13 @@ static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb, | |||
1585 | { | 1598 | { |
1586 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 1599 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
1587 | const struct nft_af_info *afi; | 1600 | const struct nft_af_info *afi; |
1601 | struct net *net = sock_net(skb->sk); | ||
1588 | const struct nft_table *table; | 1602 | const struct nft_table *table; |
1589 | struct nft_chain *chain; | 1603 | struct nft_chain *chain; |
1590 | struct nft_rule *rule, *tmp; | 1604 | struct nft_rule *rule, *tmp; |
1591 | int family = nfmsg->nfgen_family; | 1605 | int family = nfmsg->nfgen_family; |
1592 | 1606 | ||
1593 | afi = nf_tables_afinfo_lookup(family, false); | 1607 | afi = nf_tables_afinfo_lookup(net, family, false); |
1594 | if (IS_ERR(afi)) | 1608 | if (IS_ERR(afi)) |
1595 | return PTR_ERR(afi); | 1609 | return PTR_ERR(afi); |
1596 | 1610 | ||
@@ -1697,11 +1711,12 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, | |||
1697 | const struct nlmsghdr *nlh, | 1711 | const struct nlmsghdr *nlh, |
1698 | const struct nlattr * const nla[]) | 1712 | const struct nlattr * const nla[]) |
1699 | { | 1713 | { |
1714 | struct net *net = sock_net(skb->sk); | ||
1700 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 1715 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
1701 | const struct nft_af_info *afi; | 1716 | const struct nft_af_info *afi; |
1702 | const struct nft_table *table = NULL; | 1717 | const struct nft_table *table = NULL; |
1703 | 1718 | ||
1704 | afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, false); | 1719 | afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); |
1705 | if (IS_ERR(afi)) | 1720 | if (IS_ERR(afi)) |
1706 | return PTR_ERR(afi); | 1721 | return PTR_ERR(afi); |
1707 | 1722 | ||
@@ -1818,12 +1833,11 @@ static int nf_tables_set_notify(const struct nft_ctx *ctx, | |||
1818 | { | 1833 | { |
1819 | struct sk_buff *skb; | 1834 | struct sk_buff *skb; |
1820 | u32 portid = NETLINK_CB(ctx->skb).portid; | 1835 | u32 portid = NETLINK_CB(ctx->skb).portid; |
1821 | struct net *net = sock_net(ctx->skb->sk); | ||
1822 | bool report; | 1836 | bool report; |
1823 | int err; | 1837 | int err; |
1824 | 1838 | ||
1825 | report = nlmsg_report(ctx->nlh); | 1839 | report = nlmsg_report(ctx->nlh); |
1826 | if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) | 1840 | if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES)) |
1827 | return 0; | 1841 | return 0; |
1828 | 1842 | ||
1829 | err = -ENOBUFS; | 1843 | err = -ENOBUFS; |
@@ -1837,11 +1851,11 @@ static int nf_tables_set_notify(const struct nft_ctx *ctx, | |||
1837 | goto err; | 1851 | goto err; |
1838 | } | 1852 | } |
1839 | 1853 | ||
1840 | err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report, | 1854 | err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report, |
1841 | GFP_KERNEL); | 1855 | GFP_KERNEL); |
1842 | err: | 1856 | err: |
1843 | if (err < 0) | 1857 | if (err < 0) |
1844 | nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err); | 1858 | nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err); |
1845 | return err; | 1859 | return err; |
1846 | } | 1860 | } |
1847 | 1861 | ||
@@ -1974,6 +1988,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
1974 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 1988 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
1975 | const struct nft_set_ops *ops; | 1989 | const struct nft_set_ops *ops; |
1976 | const struct nft_af_info *afi; | 1990 | const struct nft_af_info *afi; |
1991 | struct net *net = sock_net(skb->sk); | ||
1977 | struct nft_table *table; | 1992 | struct nft_table *table; |
1978 | struct nft_set *set; | 1993 | struct nft_set *set; |
1979 | struct nft_ctx ctx; | 1994 | struct nft_ctx ctx; |
@@ -2032,7 +2047,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
2032 | 2047 | ||
2033 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; | 2048 | create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; |
2034 | 2049 | ||
2035 | afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, create); | 2050 | afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create); |
2036 | if (IS_ERR(afi)) | 2051 | if (IS_ERR(afi)) |
2037 | return PTR_ERR(afi); | 2052 | return PTR_ERR(afi); |
2038 | 2053 | ||
@@ -2219,8 +2234,9 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, | |||
2219 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); | 2234 | const struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
2220 | const struct nft_af_info *afi; | 2235 | const struct nft_af_info *afi; |
2221 | const struct nft_table *table; | 2236 | const struct nft_table *table; |
2237 | struct net *net = sock_net(skb->sk); | ||
2222 | 2238 | ||
2223 | afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, false); | 2239 | afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false); |
2224 | if (IS_ERR(afi)) | 2240 | if (IS_ERR(afi)) |
2225 | return PTR_ERR(afi); | 2241 | return PTR_ERR(afi); |
2226 | 2242 | ||
@@ -3011,6 +3027,16 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data, | |||
3011 | } | 3027 | } |
3012 | EXPORT_SYMBOL_GPL(nft_data_dump); | 3028 | EXPORT_SYMBOL_GPL(nft_data_dump); |
3013 | 3029 | ||
3030 | static int nf_tables_init_net(struct net *net) | ||
3031 | { | ||
3032 | INIT_LIST_HEAD(&net->nft.af_info); | ||
3033 | return 0; | ||
3034 | } | ||
3035 | |||
3036 | static struct pernet_operations nf_tables_net_ops = { | ||
3037 | .init = nf_tables_init_net, | ||
3038 | }; | ||
3039 | |||
3014 | static int __init nf_tables_module_init(void) | 3040 | static int __init nf_tables_module_init(void) |
3015 | { | 3041 | { |
3016 | int err; | 3042 | int err; |
@@ -3031,7 +3057,7 @@ static int __init nf_tables_module_init(void) | |||
3031 | goto err3; | 3057 | goto err3; |
3032 | 3058 | ||
3033 | pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n"); | 3059 | pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n"); |
3034 | return 0; | 3060 | return register_pernet_subsys(&nf_tables_net_ops); |
3035 | err3: | 3061 | err3: |
3036 | nf_tables_core_module_exit(); | 3062 | nf_tables_core_module_exit(); |
3037 | err2: | 3063 | err2: |
@@ -3042,6 +3068,7 @@ err1: | |||
3042 | 3068 | ||
3043 | static void __exit nf_tables_module_exit(void) | 3069 | static void __exit nf_tables_module_exit(void) |
3044 | { | 3070 | { |
3071 | unregister_pernet_subsys(&nf_tables_net_ops); | ||
3045 | nfnetlink_subsys_unregister(&nf_tables_subsys); | 3072 | nfnetlink_subsys_unregister(&nf_tables_subsys); |
3046 | nf_tables_core_module_exit(); | 3073 | nf_tables_core_module_exit(); |
3047 | kfree(info); | 3074 | kfree(info); |