@@ -52,11 +52,13 @@ struct nf_hook_state {
struct net_device *in;
struct net_device *out;
struct sock *sk;
+ struct net *net;
struct list_head *hook_list;
int (*okfn)(struct sock *, struct sk_buff *);
};
static inline void nf_hook_state_init(struct nf_hook_state *p,
+ struct net *net,
struct list_head *hook_list,
unsigned int hook,
int thresh, u_int8_t pf,
@@ -65,6 +67,7 @@ static inline void nf_hook_state_init(struct nf_hook_state *p,
struct sock *sk,
int (*okfn)(struct sock *, struct sk_buff *))
{
+ p->net = net;
p->hook = hook;
p->thresh = thresh;
p->pf = pf;
@@ -118,9 +121,9 @@ struct nf_sockopt_ops {
};
/* Function to register/unregister hook points. */
-int nf_register_hook(struct nf_hook_ops *reg);
+int nf_register_hook(struct net *net, struct nf_hook_ops *reg);
void nf_unregister_hook(struct nf_hook_ops *reg);
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
+int nf_register_hooks(struct net *net, struct nf_hook_ops *reg, unsigned int n);
void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
/* Functions to register get/setsockopt ranges (non-inclusive). You
@@ -128,8 +131,6 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
int nf_register_sockopt(struct nf_sockopt_ops *reg);
void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
-extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
-
#ifdef HAVE_JUMP_LABEL
extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
@@ -150,9 +151,12 @@ static inline bool nf_hook_list_active(struct list_head *nf_hook_list,
}
#endif
-static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
+#include <linux/netdevice.h>
+
+static inline bool nf_hooks_active(struct net *net, u_int8_t pf,
+ unsigned int hook)
{
- return nf_hook_list_active(&nf_hooks[pf][hook], pf, hook);
+ return nf_hook_list_active(&net->nf.hooks[pf][hook], pf, hook);
}
int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state);
@@ -172,11 +176,13 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
int (*okfn)(struct sock *, struct sk_buff *),
int thresh)
{
- if (nf_hooks_active(pf, hook)) {
+ struct net *net = indev ? dev_net(indev) : dev_net(outdev);
+
+ if (nf_hooks_active(net, pf, hook)) {
struct nf_hook_state state;
- nf_hook_state_init(&state, &nf_hooks[pf][hook], hook, thresh,
- pf, indev, outdev, sk, okfn);
+ nf_hook_state_init(&state, net, &net->nf.hooks[pf][hook], hook,
+ thresh, pf, indev, outdev, sk, okfn);
return nf_hook_slow(skb, &state);
}
return 1;
@@ -339,7 +345,8 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, sk, skb, indev, outdev, okfn) (okfn)(sk, skb)
#define NF_HOOK_COND(pf, hook, sk, skb, indev, outdev, okfn, cond) (okfn)(sk, skb)
-static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
+static inline int nf_hook_thresh(struct net *net,
+ u_int8_t pf, unsigned int hook,
struct sock *sk,
struct sk_buff *skb,
struct net_device *indev,
@@ -5,17 +5,17 @@
#include <linux/netdevice.h>
#ifdef CONFIG_NETFILTER_INGRESS
-static inline int nf_hook_ingress_active(struct sk_buff *skb)
+static inline int nf_hook_ingress_active(struct net *net, struct sk_buff *skb)
{
return nf_hook_list_active(&skb->dev->nf_hooks_ingress,
NFPROTO_NETDEV, NF_NETDEV_INGRESS);
}
-static inline int nf_hook_ingress(struct sk_buff *skb)
+static inline int nf_hook_ingress(struct net *net, struct sk_buff *skb)
{
struct nf_hook_state state;
- nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress,
+ nf_hook_state_init(&state, net, &skb->dev->nf_hooks_ingress,
NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV, NULL,
skb->dev, NULL, NULL);
return nf_hook_slow(skb, &state);
@@ -14,5 +14,6 @@ struct netns_nf {
#ifdef CONFIG_SYSCTL
struct ctl_table_header *nf_log_dir_header;
#endif
+ struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
};
#endif
@@ -1246,7 +1246,7 @@ static int __init br_netfilter_init(void)
{
int ret;
- ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops));
+ ret = nf_register_hooks(&init_net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
if (ret < 0)
return ret;
@@ -119,7 +119,8 @@ static int __init ebtable_filter_init(void)
ret = register_pernet_subsys(&frame_filter_net_ops);
if (ret < 0)
return ret;
- ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
+ ret = nf_register_hooks(&init_net, ebt_ops_filter,
+ ARRAY_SIZE(ebt_ops_filter));
if (ret < 0)
unregister_pernet_subsys(&frame_filter_net_ops);
return ret;
@@ -119,7 +119,8 @@ static int __init ebtable_nat_init(void)
ret = register_pernet_subsys(&frame_nat_net_ops);
if (ret < 0)
return ret;
- ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
+ ret = nf_register_hooks(&init_net, ebt_ops_nat,
+ ARRAY_SIZE(ebt_ops_nat));
if (ret < 0)
unregister_pernet_subsys(&frame_nat_net_ops);
return ret;
@@ -3741,13 +3741,15 @@ static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev,
int *ret, struct net_device *orig_dev)
{
#ifdef CONFIG_NETFILTER_INGRESS
- if (nf_hook_ingress_active(skb)) {
+ struct net *net = dev_net(orig_dev);
+
+ if (nf_hook_ingress_active(net, skb)) {
if (*pt_prev) {
*ret = deliver_skb(skb, *pt_prev, orig_dev);
*pt_prev = NULL;
}
- return nf_hook_ingress(skb);
+ return nf_hook_ingress(net, skb);
}
#endif /* CONFIG_NETFILTER_INGRESS */
return 0;
@@ -134,7 +134,7 @@ static int __init dn_rtmsg_init(void)
return -ENOMEM;
}
- rv = nf_register_hook(&dnrmg_ops);
+ rv = nf_register_hook(&init_net, &dnrmg_ops);
if (rv) {
netlink_kernel_release(dnrmg);
}
@@ -767,7 +767,7 @@ static int __init clusterip_tg_init(void)
if (ret < 0)
goto cleanup_subsys;
- ret = nf_register_hook(&cip_arp_ops);
+ ret = nf_register_hook(&init_net, &cip_arp_ops);
if (ret < 0)
goto cleanup_target;
@@ -450,7 +450,7 @@ static int __init synproxy_tg4_init(void)
{
int err;
- err = nf_register_hooks(ipv4_synproxy_ops,
+ err = nf_register_hooks(&init_net, ipv4_synproxy_ops,
ARRAY_SIZE(ipv4_synproxy_ops));
if (err < 0)
goto err1;
@@ -131,7 +131,8 @@ static int __init iptable_nat_init(void)
if (err < 0)
goto err1;
- err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
+ err = nf_register_hooks(&init_net, nf_nat_ipv4_ops,
+ ARRAY_SIZE(nf_nat_ipv4_ops));
if (err < 0)
goto err2;
return 0;
@@ -467,7 +467,7 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
goto cleanup_sockopt;
}
- ret = nf_register_hooks(ipv4_conntrack_ops,
+ ret = nf_register_hooks(&init_net, ipv4_conntrack_ops,
ARRAY_SIZE(ipv4_conntrack_ops));
if (ret < 0) {
pr_err("nf_conntrack_ipv4: can't register hooks.\n");
@@ -110,7 +110,8 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
static int __init nf_defrag_init(void)
{
- return nf_register_hooks(ipv4_defrag_ops, ARRAY_SIZE(ipv4_defrag_ops));
+ return nf_register_hooks(&init_net, ipv4_defrag_ops,
+ ARRAY_SIZE(ipv4_defrag_ops));
}
static void __exit nf_defrag_fini(void)
@@ -473,7 +473,7 @@ static int __init synproxy_tg6_init(void)
{
int err;
- err = nf_register_hooks(ipv6_synproxy_ops,
+ err = nf_register_hooks(&init_net, ipv6_synproxy_ops,
ARRAY_SIZE(ipv6_synproxy_ops));
if (err < 0)
goto err1;
@@ -133,7 +133,8 @@ static int __init ip6table_nat_init(void)
if (err < 0)
goto err1;
- err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops));
+ err = nf_register_hooks(&init_net, nf_nat_ipv6_ops,
+ ARRAY_SIZE(nf_nat_ipv6_ops));
if (err < 0)
goto err2;
return 0;
@@ -407,7 +407,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
if (ret < 0)
goto cleanup_sockopt;
- ret = nf_register_hooks(ipv6_conntrack_ops,
+ ret = nf_register_hooks(&init_net, ipv6_conntrack_ops,
ARRAY_SIZE(ipv6_conntrack_ops));
if (ret < 0) {
pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
@@ -108,7 +108,8 @@ static int __init nf_defrag_init(void)
pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
return ret;
}
- ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
+ ret = nf_register_hooks(&init_net, ipv6_defrag_ops,
+ ARRAY_SIZE(ipv6_defrag_ops));
if (ret < 0) {
pr_err("nf_defrag_ipv6: can't register hooks\n");
goto cleanup_frag6;
@@ -52,9 +52,6 @@ void nf_unregister_afinfo(const struct nf_afinfo *afinfo)
}
EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
-struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
-EXPORT_SYMBOL(nf_hooks);
-
#ifdef HAVE_JUMP_LABEL
struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
EXPORT_SYMBOL(nf_hooks_needed);
@@ -62,7 +59,7 @@ EXPORT_SYMBOL(nf_hooks_needed);
static DEFINE_MUTEX(nf_hook_mutex);
-int nf_register_hook(struct nf_hook_ops *reg)
+int nf_register_hook(struct net *net, struct nf_hook_ops *reg)
{
struct list_head *nf_hook_list;
struct nf_hook_ops *elem;
@@ -80,7 +77,7 @@ int nf_register_hook(struct nf_hook_ops *reg)
#endif
/* Fall through. */
default:
- nf_hook_list = &nf_hooks[reg->pf][reg->hooknum];
+ nf_hook_list = &net->nf.hooks[reg->pf][reg->hooknum];
break;
}
@@ -121,13 +118,13 @@ void nf_unregister_hook(struct nf_hook_ops *reg)
}
EXPORT_SYMBOL(nf_unregister_hook);
-int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
+int nf_register_hooks(struct net *net, struct nf_hook_ops *reg, unsigned int n)
{
unsigned int i;
int err = 0;
for (i = 0; i < n; i++) {
- err = nf_register_hook(®[i]);
+ err = nf_register_hook(net, ®[i]);
if (err)
goto err;
}
@@ -296,6 +293,13 @@ EXPORT_SYMBOL(nf_nat_decode_session_hook);
static int __net_init netfilter_net_init(struct net *net)
{
+ int i, h;
+
+ for (i = 0; i < NFPROTO_NUMPROTO; i++) {
+ for (h = 0; h < NF_MAX_HOOKS; h++)
+ INIT_LIST_HEAD(&net->nf.hooks[i][h]);
+ }
+
#ifdef CONFIG_PROC_FS
net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter",
net->proc_net);
@@ -306,6 +310,7 @@ static int __net_init netfilter_net_init(struct net *net)
return -ENOMEM;
}
#endif
+
return 0;
}
@@ -321,12 +326,7 @@ static struct pernet_operations netfilter_net_ops = {
int __init netfilter_init(void)
{
- int i, h, ret;
-
- for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
- for (h = 0; h < NF_MAX_HOOKS; h++)
- INIT_LIST_HEAD(&nf_hooks[i][h]);
- }
+ int ret;
ret = register_pernet_subsys(&netfilter_net_ops);
if (ret < 0)
@@ -2088,7 +2088,7 @@ static int __init ip_vs_init(void)
if (ret < 0)
goto cleanup_sub;
- ret = nf_register_hooks(ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+ ret = nf_register_hooks(&init_net, ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
if (ret < 0) {
pr_err("can't register hooks.\n");
goto cleanup_dev;
@@ -196,7 +196,7 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
if (verdict == NF_ACCEPT) {
next_hook:
- verdict = nf_iterate(&nf_hooks[entry->state.pf][entry->state.hook],
+ verdict = nf_iterate(entry->state.hook_list,
skb, &entry->state, &elem);
}
@@ -566,7 +566,8 @@ static int nf_tables_table_enable(const struct nft_af_info *afi,
if (!(chain->flags & NFT_BASE_CHAIN))
continue;
- err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
+ err = nf_register_hooks(&init_net, nft_base_chain(chain)->ops,
+ afi->nops);
if (err < 0)
goto err;
@@ -1418,7 +1419,8 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
if (!(table->flags & NFT_TABLE_F_DORMANT) &&
chain->flags & NFT_BASE_CHAIN) {
- err = nf_register_hooks(nft_base_chain(chain)->ops, afi->nops);
+ err = nf_register_hooks(&init_net, nft_base_chain(chain)->ops,
+ afi->nops);
if (err < 0)
goto err1;
}
@@ -1201,7 +1201,7 @@ struct nf_hook_ops *xt_hook_link(const struct xt_table *table, nf_hookfn *fn)
++i;
}
- ret = nf_register_hooks(ops, num_hooks);
+ ret = nf_register_hooks(&init_net, ops, num_hooks);
if (ret < 0) {
kfree(ops);
return ERR_PTR(ret);
@@ -6156,7 +6156,8 @@ static int __init selinux_nf_ip_init(void)
printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
- err = nf_register_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
+ err = nf_register_hooks(&init_net, selinux_nf_ops,
+ ARRAY_SIZE(selinux_nf_ops));
if (err)
panic("SELinux: nf_register_hooks: error %d\n", err);
@@ -6170,7 +6171,8 @@ static void selinux_nf_ip_exit(void)
{
printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
- nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
+ nf_unregister_hooks(&init_net, selinux_nf_ops,
+ ARRAY_SIZE(selinux_nf_ops));
}
#endif
@@ -82,7 +82,8 @@ static int __init smack_nf_ip_init(void)
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
- err = nf_register_hooks(smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
+ err = nf_register_hooks(&init_net, smack_nf_ops,
+ ARRAY_SIZE(smack_nf_ops));
if (err)
pr_info("Smack: nf_register_hooks: error %d\n", err);
This patch modifies the nf_register_hook() and nf_register_hooks() interfaces to allow to register hooks at a pernet level. This starts using init_net for all the existing callers though, so the full conversion of existing netfilter hook clients to comes in follow up patches. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- include/linux/netfilter.h | 27 +++++++++++++++--------- include/linux/netfilter_ingress.h | 6 +++--- include/net/netns/netfilter.h | 1 + net/bridge/br_netfilter.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 3 ++- net/bridge/netfilter/ebtable_nat.c | 3 ++- net/core/dev.c | 6 ++++-- net/decnet/netfilter/dn_rtmsg.c | 2 +- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- net/ipv4/netfilter/ipt_SYNPROXY.c | 2 +- net/ipv4/netfilter/iptable_nat.c | 3 ++- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 2 +- net/ipv4/netfilter/nf_defrag_ipv4.c | 3 ++- net/ipv6/netfilter/ip6t_SYNPROXY.c | 2 +- net/ipv6/netfilter/ip6table_nat.c | 3 ++- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 2 +- net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | 3 ++- net/netfilter/core.c | 26 +++++++++++------------ net/netfilter/ipvs/ip_vs_core.c | 2 +- net/netfilter/nf_queue.c | 2 +- net/netfilter/nf_tables_api.c | 6 ++++-- net/netfilter/x_tables.c | 2 +- security/selinux/hooks.c | 6 ++++-- security/smack/smack_netfilter.c | 3 ++- 24 files changed, 70 insertions(+), 49 deletions(-)