netfilter: xtables: prepare for on-demand hook register
authorFlorian Westphal <fw@strlen.de>
Thu, 25 Feb 2016 09:08:35 +0000 (10:08 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 2 Mar 2016 19:05:23 +0000 (20:05 +0100)
This change prepares for upcoming on-demand xtables hook registration.

We change the protoypes of the register/unregister functions.
A followup patch will then add nf_hook_register/unregister calls
to the iptables one.

Once a hook is registered packets will be picked up, so all assignments
of the form

net->ipv4.iptable_$table = new_table

have to be moved to ip(6)t_register_table, else we can see NULL
net->ipv4.iptable_$table later.

This patch doesn't change functionality; without this the actual change
simply gets too big.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
17 files changed:
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv6/ip6_tables.h
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_nat.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/iptable_security.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_nat.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/netfilter/ip6table_security.c

index 6f074db2f23def7befbf60dd41792e554503db6c..029b95e8924e02bd5e89f305f39b3df13759a6d7 100644 (file)
@@ -48,10 +48,11 @@ struct arpt_error {
 }
 
 extern void *arpt_alloc_initial_table(const struct xt_table *);
-extern struct xt_table *arpt_register_table(struct net *net,
-                                           const struct xt_table *table,
-                                           const struct arpt_replace *repl);
-extern void arpt_unregister_table(struct xt_table *table);
+int arpt_register_table(struct net *net, const struct xt_table *table,
+                       const struct arpt_replace *repl,
+                       const struct nf_hook_ops *ops, struct xt_table **res);
+void arpt_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops);
 extern unsigned int arpt_do_table(struct sk_buff *skb,
                                  const struct nf_hook_state *state,
                                  struct xt_table *table);
index aa598f942c01a8d549302d570d17b6fa95198569..7bfc5893ec314e247693374131a31f0144da20d3 100644 (file)
 
 extern void ipt_init(void) __init;
 
-extern struct xt_table *ipt_register_table(struct net *net,
-                                          const struct xt_table *table,
-                                          const struct ipt_replace *repl);
-extern void ipt_unregister_table(struct net *net, struct xt_table *table);
+int ipt_register_table(struct net *net, const struct xt_table *table,
+                      const struct ipt_replace *repl,
+                      const struct nf_hook_ops *ops, struct xt_table **res);
+void ipt_unregister_table(struct net *net, struct xt_table *table,
+                         const struct nf_hook_ops *ops);
 
 /* Standard entry. */
 struct ipt_standard {
index 0f76e5c674f9920ecc8ccb56635fa4353ea2136c..b21c392d6012837abb89858e1ea407130583b7d9 100644 (file)
 extern void ip6t_init(void) __init;
 
 extern void *ip6t_alloc_initial_table(const struct xt_table *);
-extern struct xt_table *ip6t_register_table(struct net *net,
-                                           const struct xt_table *table,
-                                           const struct ip6t_replace *repl);
-extern void ip6t_unregister_table(struct net *net, struct xt_table *table);
+int ip6t_register_table(struct net *net, const struct xt_table *table,
+                       const struct ip6t_replace *repl,
+                       const struct nf_hook_ops *ops, struct xt_table **res);
+void ip6t_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops);
 extern unsigned int ip6t_do_table(struct sk_buff *skb,
                                  const struct nf_hook_state *state,
                                  struct xt_table *table);
index b488cac9c5ca5496238bcc31a02887362655212b..00eed0852dfcf070f406ef689d6d771dbb734a0d 100644 (file)
@@ -1780,9 +1780,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
        return ret;
 }
 
-struct xt_table *arpt_register_table(struct net *net,
-                                    const struct xt_table *table,
-                                    const struct arpt_replace *repl)
+int arpt_register_table(struct net *net,
+                       const struct xt_table *table,
+                       const struct arpt_replace *repl,
+                       const struct nf_hook_ops *ops,
+                       struct xt_table **res)
 {
        int ret;
        struct xt_table_info *newinfo;
@@ -1791,10 +1793,8 @@ struct xt_table *arpt_register_table(struct net *net,
        struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!newinfo)
+               return -ENOMEM;
 
        loc_cpu_entry = newinfo->entries;
        memcpy(loc_cpu_entry, repl->entries, repl->size);
@@ -1809,15 +1809,18 @@ struct xt_table *arpt_register_table(struct net *net,
                ret = PTR_ERR(new_table);
                goto out_free;
        }
-       return new_table;
+
+       WRITE_ONCE(*res, new_table);
+
+       return ret;
 
 out_free:
        xt_free_table_info(newinfo);
-out:
-       return ERR_PTR(ret);
+       return ret;
 }
 
-void arpt_unregister_table(struct xt_table *table)
+void arpt_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
index 1897ee1609202f326a98f96536a00acd96204a13..4c02416925764a5c871a1bb2ba532404859b2bdf 100644 (file)
@@ -38,19 +38,20 @@ static struct nf_hook_ops *arpfilter_ops __read_mostly;
 static int __net_init arptable_filter_net_init(struct net *net)
 {
        struct arpt_replace *repl;
-       
+       int err;
+
        repl = arpt_alloc_initial_table(&packet_filter);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.arptable_filter =
-               arpt_register_table(net, &packet_filter, repl);
+       err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops,
+                                 &net->ipv4.arptable_filter);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter);
+       return err;
 }
 
 static void __net_exit arptable_filter_net_exit(struct net *net)
 {
-       arpt_unregister_table(net->ipv4.arptable_filter);
+       arpt_unregister_table(net, net->ipv4.arptable_filter, arpfilter_ops);
 }
 
 static struct pernet_operations arptable_filter_net_ops = {
index b99affad6ba1f4939e10f676a06f92cd27c32add..1eb4fe5b47028690b28c16098c573f5742a05447 100644 (file)
@@ -2062,9 +2062,9 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-struct xt_table *ipt_register_table(struct net *net,
-                                   const struct xt_table *table,
-                                   const struct ipt_replace *repl)
+int ipt_register_table(struct net *net, const struct xt_table *table,
+                      const struct ipt_replace *repl,
+                      const struct nf_hook_ops *ops, struct xt_table **res)
 {
        int ret;
        struct xt_table_info *newinfo;
@@ -2073,10 +2073,8 @@ struct xt_table *ipt_register_table(struct net *net,
        struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!newinfo)
+               return -ENOMEM;
 
        loc_cpu_entry = newinfo->entries;
        memcpy(loc_cpu_entry, repl->entries, repl->size);
@@ -2091,15 +2089,16 @@ struct xt_table *ipt_register_table(struct net *net,
                goto out_free;
        }
 
-       return new_table;
+       WRITE_ONCE(*res, new_table);
+       return ret;
 
 out_free:
        xt_free_table_info(newinfo);
-out:
-       return ERR_PTR(ret);
+       return ret;
 }
 
-void ipt_unregister_table(struct net *net, struct xt_table *table)
+void ipt_unregister_table(struct net *net, struct xt_table *table,
+                         const struct nf_hook_ops *ops)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
index 397ef2dd133ed56f9edb3146e30ee46f99a3f50d..3fbe4acacb2770f6aa31fce05ef7e0c6ab8d4551 100644 (file)
@@ -54,6 +54,7 @@ module_param(forward, bool, 0000);
 static int __net_init iptable_filter_net_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int err;
 
        repl = ipt_alloc_initial_table(&packet_filter);
        if (repl == NULL)
@@ -62,15 +63,15 @@ static int __net_init iptable_filter_net_init(struct net *net)
        ((struct ipt_standard *)repl->entries)[1].target.verdict =
                forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
-       net->ipv4.iptable_filter =
-               ipt_register_table(net, &packet_filter, repl);
+       err = ipt_register_table(net, &packet_filter, repl, filter_ops,
+                                &net->ipv4.iptable_filter);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter);
+       return err;
 }
 
 static void __net_exit iptable_filter_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_filter);
+       ipt_unregister_table(net, net->ipv4.iptable_filter, filter_ops);
 }
 
 static struct pernet_operations iptable_filter_net_ops = {
index ba5d392a13c41c74501cc2b76805d04a06b2675e..668e79166b812b5d6a5617dff53eaaa5d6bc7839 100644 (file)
@@ -96,19 +96,20 @@ static struct nf_hook_ops *mangle_ops __read_mostly;
 static int __net_init iptable_mangle_net_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
 
        repl = ipt_alloc_initial_table(&packet_mangler);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.iptable_mangle =
-               ipt_register_table(net, &packet_mangler, repl);
+       ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops,
+                                &net->ipv4.iptable_mangle);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle);
+       return ret;
 }
 
 static void __net_exit iptable_mangle_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_mangle);
+       ipt_unregister_table(net, net->ipv4.iptable_mangle, mangle_ops);
 }
 
 static struct pernet_operations iptable_mangle_net_ops = {
index ae2cd275204643ebff64d7537dd617bd3a0eec62..e984f1d3017f89cb832d9e836db69ed7f268200a 100644 (file)
@@ -98,18 +98,20 @@ static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
 static int __net_init iptable_nat_net_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
 
        repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
+       ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
+                                nf_nat_ipv4_ops, &net->ipv4.nat_table);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.nat_table);
+       return ret;
 }
 
 static void __net_exit iptable_nat_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.nat_table);
+       ipt_unregister_table(net, net->ipv4.nat_table, nf_nat_ipv4_ops);
 }
 
 static struct pernet_operations iptable_nat_net_ops = {
index 1ba02811acb0c3d380b2779dd61687b92be51ce8..9d78780a9036fa540ad8b3a35d783e1b491f9319 100644 (file)
@@ -37,19 +37,20 @@ static struct nf_hook_ops *rawtable_ops __read_mostly;
 static int __net_init iptable_raw_net_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
 
        repl = ipt_alloc_initial_table(&packet_raw);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.iptable_raw =
-               ipt_register_table(net, &packet_raw, repl);
+       ret = ipt_register_table(net, &packet_raw, repl, rawtable_ops,
+                                &net->ipv4.iptable_raw);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw);
+       return ret;
 }
 
 static void __net_exit iptable_raw_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_raw);
+       ipt_unregister_table(net, net->ipv4.iptable_raw, rawtable_ops);
 }
 
 static struct pernet_operations iptable_raw_net_ops = {
index c2e23d5e9cd4a8412d38f20eb8ddedf2f32f8aa6..88bc52fb8f4a003868a1508c0d12763243c1d5c3 100644 (file)
@@ -54,19 +54,20 @@ static struct nf_hook_ops *sectbl_ops __read_mostly;
 static int __net_init iptable_security_net_init(struct net *net)
 {
        struct ipt_replace *repl;
+       int ret;
 
        repl = ipt_alloc_initial_table(&security_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv4.iptable_security =
-               ipt_register_table(net, &security_table, repl);
+       ret = ipt_register_table(net, &security_table, repl, sectbl_ops,
+                                &net->ipv4.iptable_security);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv4.iptable_security);
+       return ret;
 }
 
 static void __net_exit iptable_security_net_exit(struct net *net)
 {
-       ipt_unregister_table(net, net->ipv4.iptable_security);
+       ipt_unregister_table(net, net->ipv4.iptable_security, sectbl_ops);
 }
 
 static struct pernet_operations iptable_security_net_ops = {
index 99425cf2819b83ceb33d49af65284cb16fd076ec..052d7447b52e5ea92e646de672ca778f5a7d3178 100644 (file)
@@ -2071,9 +2071,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-struct xt_table *ip6t_register_table(struct net *net,
-                                    const struct xt_table *table,
-                                    const struct ip6t_replace *repl)
+int ip6t_register_table(struct net *net, const struct xt_table *table,
+                       const struct ip6t_replace *repl,
+                       const struct nf_hook_ops *ops,
+                       struct xt_table **res)
 {
        int ret;
        struct xt_table_info *newinfo;
@@ -2082,10 +2083,8 @@ struct xt_table *ip6t_register_table(struct net *net,
        struct xt_table *new_table;
 
        newinfo = xt_alloc_table_info(repl->size);
-       if (!newinfo) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!newinfo)
+               return -ENOMEM;
 
        loc_cpu_entry = newinfo->entries;
        memcpy(loc_cpu_entry, repl->entries, repl->size);
@@ -2099,15 +2098,17 @@ struct xt_table *ip6t_register_table(struct net *net,
                ret = PTR_ERR(new_table);
                goto out_free;
        }
-       return new_table;
+
+       WRITE_ONCE(*res, new_table);
+       return ret;
 
 out_free:
        xt_free_table_info(newinfo);
-out:
-       return ERR_PTR(ret);
+       return ret;
 }
 
-void ip6t_unregister_table(struct net *net, struct xt_table *table)
+void ip6t_unregister_table(struct net *net, struct xt_table *table,
+                          const struct nf_hook_ops *ops)
 {
        struct xt_table_info *private;
        void *loc_cpu_entry;
index 8b277b983ca51886973ab62601d136a0b318f001..d191d54cdf50a93675ebef1ba8226063fcad1d17 100644 (file)
@@ -47,6 +47,7 @@ module_param(forward, bool, 0000);
 static int __net_init ip6table_filter_net_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int err;
 
        repl = ip6t_alloc_initial_table(&packet_filter);
        if (repl == NULL)
@@ -55,15 +56,15 @@ static int __net_init ip6table_filter_net_init(struct net *net)
        ((struct ip6t_standard *)repl->entries)[1].target.verdict =
                forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
 
-       net->ipv6.ip6table_filter =
-               ip6t_register_table(net, &packet_filter, repl);
+       err = ip6t_register_table(net, &packet_filter, repl, filter_ops,
+                                 &net->ipv6.ip6table_filter);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_filter);
+       return err;
 }
 
 static void __net_exit ip6table_filter_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_filter);
+       ip6t_unregister_table(net, net->ipv6.ip6table_filter, filter_ops);
 }
 
 static struct pernet_operations ip6table_filter_net_ops = {
index abe278b079322cb929cc16e260722ec49da414d5..fe43d08284bc408fee590d1f7706d0a1d98e6127 100644 (file)
@@ -91,19 +91,20 @@ static struct nf_hook_ops *mangle_ops __read_mostly;
 static int __net_init ip6table_mangle_net_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
 
        repl = ip6t_alloc_initial_table(&packet_mangler);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_mangle =
-               ip6t_register_table(net, &packet_mangler, repl);
+       ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops,
+                                 &net->ipv6.ip6table_mangle);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_mangle);
+       return ret;
 }
 
 static void __net_exit ip6table_mangle_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_mangle);
+       ip6t_unregister_table(net, net->ipv6.ip6table_mangle, mangle_ops);
 }
 
 static struct pernet_operations ip6table_mangle_net_ops = {
index de2a10a565f549bc4ae183d1c5af31d29fb106e4..7f9740e8ef4783f983e9192707f1f17aefa9406d 100644 (file)
@@ -100,18 +100,20 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
 static int __net_init ip6table_nat_net_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
 
        repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
+       ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
+                                 nf_nat_ipv6_ops, &net->ipv6.ip6table_nat);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat);
+       return ret;
 }
 
 static void __net_exit ip6table_nat_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_nat);
+       ip6t_unregister_table(net, net->ipv6.ip6table_nat, nf_nat_ipv6_ops);
 }
 
 static struct pernet_operations ip6table_nat_net_ops = {
index 9021963565c37703ae478c2a39243a1725c92685..5fac433da0697fb8e9861dba83761c3234c526c9 100644 (file)
@@ -30,19 +30,20 @@ static struct nf_hook_ops *rawtable_ops __read_mostly;
 static int __net_init ip6table_raw_net_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
 
        repl = ip6t_alloc_initial_table(&packet_raw);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_raw =
-               ip6t_register_table(net, &packet_raw, repl);
+       ret = ip6t_register_table(net, &packet_raw, repl, rawtable_ops,
+                                 &net->ipv6.ip6table_raw);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_raw);
+       return ret;
 }
 
 static void __net_exit ip6table_raw_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_raw);
+       ip6t_unregister_table(net, net->ipv6.ip6table_raw, rawtable_ops);
 }
 
 static struct pernet_operations ip6table_raw_net_ops = {
index 0d856fedfeb0c2d1ddc97cb5372fc33eda2f102b..cf587453e32222fe8a0a76b99913145df7e2583d 100644 (file)
@@ -47,19 +47,20 @@ static struct nf_hook_ops *sectbl_ops __read_mostly;
 static int __net_init ip6table_security_net_init(struct net *net)
 {
        struct ip6t_replace *repl;
+       int ret;
 
        repl = ip6t_alloc_initial_table(&security_table);
        if (repl == NULL)
                return -ENOMEM;
-       net->ipv6.ip6table_security =
-               ip6t_register_table(net, &security_table, repl);
+       ret = ip6t_register_table(net, &security_table, repl, sectbl_ops,
+                                 &net->ipv6.ip6table_security);
        kfree(repl);
-       return PTR_ERR_OR_ZERO(net->ipv6.ip6table_security);
+       return ret;
 }
 
 static void __net_exit ip6table_security_net_exit(struct net *net)
 {
-       ip6t_unregister_table(net, net->ipv6.ip6table_security);
+       ip6t_unregister_table(net, net->ipv6.ip6table_security, sectbl_ops);
 }
 
 static struct pernet_operations ip6table_security_net_ops = {