Commit 99633ab2 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

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: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent eb31628e
......@@ -22,6 +22,7 @@
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
#include <net/netns/conntrack.h>
#endif
#include <net/netns/nftables.h>
#include <net/netns/xfrm.h>
struct user_namespace;
......@@ -101,6 +102,9 @@ struct net {
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
#endif
#if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE)
struct netns_nftables nft;
#endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
struct netns_nf_frag nf_frag;
#endif
......
......@@ -68,6 +68,7 @@ static inline void nft_data_debug(const struct nft_data *data)
/**
* struct nft_ctx - nf_tables rule/set context
*
* @net: net namespace
* @skb: netlink skb
* @nlh: netlink message header
* @afi: address family info
......@@ -76,6 +77,7 @@ static inline void nft_data_debug(const struct nft_data *data)
* @nla: netlink attributes
*/
struct nft_ctx {
struct net *net;
const struct sk_buff *skb;
const struct nlmsghdr *nlh;
const struct nft_af_info *afi;
......@@ -462,7 +464,7 @@ struct nft_af_info {
nf_hookfn *hooks[NF_MAX_HOOKS];
};
extern int nft_register_afinfo(struct nft_af_info *);
extern int nft_register_afinfo(struct net *, struct nft_af_info *);
extern void nft_unregister_afinfo(struct nft_af_info *);
struct nf_chain_type {
......
#ifndef _NETNS_NFTABLES_H_
#define _NETNS_NFTABLES_H_
#include <linux/list.h>
struct nft_af_info;
struct netns_nftables {
struct list_head af_info;
struct nft_af_info *ipv4;
struct nft_af_info *ipv6;
struct nft_af_info *bridge;
};
#endif
......@@ -19,14 +19,42 @@ static struct nft_af_info nft_af_bridge __read_mostly = {
.owner = THIS_MODULE,
};
static int nf_tables_bridge_init_net(struct net *net)
{
net->nft.bridge = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.bridge == NULL)
return -ENOMEM;
memcpy(net->nft.bridge, &nft_af_bridge, sizeof(nft_af_bridge));
if (nft_register_afinfo(net, net->nft.bridge) < 0)
goto err;
return 0;
err:
kfree(net->nft.bridge);
return -ENOMEM;
}
static void nf_tables_bridge_exit_net(struct net *net)
{
nft_unregister_afinfo(net->nft.bridge);
kfree(net->nft.bridge);
}
static struct pernet_operations nf_tables_bridge_net_ops = {
.init = nf_tables_bridge_init_net,
.exit = nf_tables_bridge_exit_net,
};
static int __init nf_tables_bridge_init(void)
{
return nft_register_afinfo(&nft_af_bridge);
return register_pernet_subsys(&nf_tables_bridge_net_ops);
}
static void __exit nf_tables_bridge_exit(void)
{
nft_unregister_afinfo(&nft_af_bridge);
return unregister_pernet_subsys(&nf_tables_bridge_net_ops);
}
module_init(nf_tables_bridge_init);
......
......@@ -14,6 +14,7 @@
#include <linux/ip.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_tables.h>
#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/net_namespace.h>
#include <net/netfilter/nf_tables_ipv4.h>
......@@ -47,6 +48,33 @@ static struct nft_af_info nft_af_ipv4 __read_mostly = {
},
};
static int nf_tables_ipv4_init_net(struct net *net)
{
net->nft.ipv4 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.ipv4 == NULL)
return -ENOMEM;
memcpy(net->nft.ipv4, &nft_af_ipv4, sizeof(nft_af_ipv4));
if (nft_register_afinfo(net, net->nft.ipv4) < 0)
goto err;
return 0;
err:
kfree(net->nft.ipv4);
return -ENOMEM;
}
static void nf_tables_ipv4_exit_net(struct net *net)
{
nft_unregister_afinfo(net->nft.ipv4);
kfree(net->nft.ipv4);
}
static struct pernet_operations nf_tables_ipv4_net_ops = {
.init = nf_tables_ipv4_init_net,
.exit = nf_tables_ipv4_exit_net,
};
static unsigned int
nft_do_chain_ipv4(const struct nf_hook_ops *ops,
......@@ -83,12 +111,12 @@ static struct nf_chain_type filter_ipv4 = {
static int __init nf_tables_ipv4_init(void)
{
nft_register_chain_type(&filter_ipv4);
return nft_register_afinfo(&nft_af_ipv4);
return register_pernet_subsys(&nf_tables_ipv4_net_ops);
}
static void __exit nf_tables_ipv4_exit(void)
{
nft_unregister_afinfo(&nft_af_ipv4);
unregister_pernet_subsys(&nf_tables_ipv4_net_ops);
nft_unregister_chain_type(&filter_ipv4);
}
......
......@@ -45,6 +45,34 @@ static struct nft_af_info nft_af_ipv6 __read_mostly = {
},
};
static int nf_tables_ipv6_init_net(struct net *net)
{
net->nft.ipv6 = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.ipv6 == NULL)
return -ENOMEM;
memcpy(net->nft.ipv6, &nft_af_ipv6, sizeof(nft_af_ipv6));
if (nft_register_afinfo(net, net->nft.ipv6) < 0)
goto err;
return 0;
err:
kfree(net->nft.ipv6);
return -ENOMEM;
}
static void nf_tables_ipv6_exit_net(struct net *net)
{
nft_unregister_afinfo(net->nft.ipv6);
kfree(net->nft.ipv6);
}
static struct pernet_operations nf_tables_ipv6_net_ops = {
.init = nf_tables_ipv6_init_net,
.exit = nf_tables_ipv6_exit_net,
};
static unsigned int
nft_do_chain_ipv6(const struct nf_hook_ops *ops,
struct sk_buff *skb,
......@@ -82,11 +110,12 @@ static struct nf_chain_type filter_ipv6 = {
static int __init nf_tables_ipv6_init(void)
{
nft_register_chain_type(&filter_ipv6);
return nft_register_afinfo(&nft_af_ipv6);
return register_pernet_subsys(&nf_tables_ipv6_net_ops);
}
static void __exit nf_tables_ipv6_exit(void)
{
nft_unregister_afinfo(&nft_af_ipv6);
unregister_pernet_subsys(&nf_tables_ipv6_net_ops);
nft_unregister_chain_type(&filter_ipv6);
}
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment