@@ -110,6 +110,9 @@ static int __net_init iptable_nat_table_init(struct net *net)
if (net->ipv4.nat_table)
return 0;
+ ret = nf_ct_netns_get(net, NFPROTO_IPV4);
+ if (ret)
+ return ret;
repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
if (repl == NULL)
return -ENOMEM;
@@ -138,6 +141,7 @@ static void __net_exit iptable_nat_net_exit(struct net *net)
nf_unregister_net_hooks(net, nf_nat_ipv4_ops,
ARRAY_SIZE(nf_nat_ipv4_ops));
ipt_unregister_table(net, net->ipv4.nat_table);
+ nf_ct_netns_put(net, NFPROTO_IPV6);
net->ipv4.nat_table = NULL;
}
@@ -112,6 +112,9 @@ static int __net_init ip6table_nat_table_init(struct net *net)
if (net->ipv6.ip6table_nat)
return 0;
+ ret = nf_ct_netns_get(net, NFPROTO_IPV6);
+ if (ret)
+ return ret;
repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
if (repl == NULL)
return -ENOMEM;
@@ -141,6 +144,7 @@ static void __net_exit ip6table_nat_net_exit(struct net *net)
ARRAY_SIZE(nf_nat_ipv6_ops));
ip6t_unregister_table(net, net->ipv6.ip6table_nat);
net->ipv6.ip6table_nat = NULL;
+ nf_ct_netns_put(net, NFPROTO_IPV6);
}
static struct pernet_operations ip6table_nat_net_ops = {
Technically this isn't needed, since MASQUERADE, S/DNAT, etc. targets call functions that in one way or another depend on the conntrack module. However, since the conntrack hooks are now registered in a lazy fashion (i.e., only when needed) a symbol reference is not enough anymore. Thus, when something is added to a nat table, make sure that it will see packets by calling nf_ct_netns_get() which will register the conntrack hooks in the current netns. Another -- more elaborate solution -- is to move this refcounting to all nat targets instead, i.e. S/DNAT, MASQUERADE and NETMAP. However, the nat table is more of a 'configuration database' -- its a sane assumption that if a rule is added to it it does involve one of the targets listed above. Signed-off-by: Florian Westphal <fw@strlen.de> --- net/ipv4/netfilter/iptable_nat.c | 4 ++++ net/ipv6/netfilter/ip6table_nat.c | 4 ++++ 2 files changed, 8 insertions(+)