Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: xtables: prepare for on-demand hook register

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>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
a67dd266 5f547391

+107 -88
+5 -4
include/linux/netfilter_arp/arp_tables.h
··· 48 48 } 49 49 50 50 extern void *arpt_alloc_initial_table(const struct xt_table *); 51 - extern struct xt_table *arpt_register_table(struct net *net, 52 - const struct xt_table *table, 53 - const struct arpt_replace *repl); 54 - extern void arpt_unregister_table(struct xt_table *table); 51 + int arpt_register_table(struct net *net, const struct xt_table *table, 52 + const struct arpt_replace *repl, 53 + const struct nf_hook_ops *ops, struct xt_table **res); 54 + void arpt_unregister_table(struct net *net, struct xt_table *table, 55 + const struct nf_hook_ops *ops); 55 56 extern unsigned int arpt_do_table(struct sk_buff *skb, 56 57 const struct nf_hook_state *state, 57 58 struct xt_table *table);
+5 -4
include/linux/netfilter_ipv4/ip_tables.h
··· 24 24 25 25 extern void ipt_init(void) __init; 26 26 27 - extern struct xt_table *ipt_register_table(struct net *net, 28 - const struct xt_table *table, 29 - const struct ipt_replace *repl); 30 - extern void ipt_unregister_table(struct net *net, struct xt_table *table); 27 + int ipt_register_table(struct net *net, const struct xt_table *table, 28 + const struct ipt_replace *repl, 29 + const struct nf_hook_ops *ops, struct xt_table **res); 30 + void ipt_unregister_table(struct net *net, struct xt_table *table, 31 + const struct nf_hook_ops *ops); 31 32 32 33 /* Standard entry. */ 33 34 struct ipt_standard {
+5 -4
include/linux/netfilter_ipv6/ip6_tables.h
··· 25 25 extern void ip6t_init(void) __init; 26 26 27 27 extern void *ip6t_alloc_initial_table(const struct xt_table *); 28 - extern struct xt_table *ip6t_register_table(struct net *net, 29 - const struct xt_table *table, 30 - const struct ip6t_replace *repl); 31 - extern void ip6t_unregister_table(struct net *net, struct xt_table *table); 28 + int ip6t_register_table(struct net *net, const struct xt_table *table, 29 + const struct ip6t_replace *repl, 30 + const struct nf_hook_ops *ops, struct xt_table **res); 31 + void ip6t_unregister_table(struct net *net, struct xt_table *table, 32 + const struct nf_hook_ops *ops); 32 33 extern unsigned int ip6t_do_table(struct sk_buff *skb, 33 34 const struct nf_hook_state *state, 34 35 struct xt_table *table);
+14 -11
net/ipv4/netfilter/arp_tables.c
··· 1780 1780 return ret; 1781 1781 } 1782 1782 1783 - struct xt_table *arpt_register_table(struct net *net, 1784 - const struct xt_table *table, 1785 - const struct arpt_replace *repl) 1783 + int arpt_register_table(struct net *net, 1784 + const struct xt_table *table, 1785 + const struct arpt_replace *repl, 1786 + const struct nf_hook_ops *ops, 1787 + struct xt_table **res) 1786 1788 { 1787 1789 int ret; 1788 1790 struct xt_table_info *newinfo; ··· 1793 1791 struct xt_table *new_table; 1794 1792 1795 1793 newinfo = xt_alloc_table_info(repl->size); 1796 - if (!newinfo) { 1797 - ret = -ENOMEM; 1798 - goto out; 1799 - } 1794 + if (!newinfo) 1795 + return -ENOMEM; 1800 1796 1801 1797 loc_cpu_entry = newinfo->entries; 1802 1798 memcpy(loc_cpu_entry, repl->entries, repl->size); ··· 1809 1809 ret = PTR_ERR(new_table); 1810 1810 goto out_free; 1811 1811 } 1812 - return new_table; 1812 + 1813 + WRITE_ONCE(*res, new_table); 1814 + 1815 + return ret; 1813 1816 1814 1817 out_free: 1815 1818 xt_free_table_info(newinfo); 1816 - out: 1817 - return ERR_PTR(ret); 1819 + return ret; 1818 1820 } 1819 1821 1820 - void arpt_unregister_table(struct xt_table *table) 1822 + void arpt_unregister_table(struct net *net, struct xt_table *table, 1823 + const struct nf_hook_ops *ops) 1821 1824 { 1822 1825 struct xt_table_info *private; 1823 1826 void *loc_cpu_entry;
+6 -5
net/ipv4/netfilter/arptable_filter.c
··· 38 38 static int __net_init arptable_filter_net_init(struct net *net) 39 39 { 40 40 struct arpt_replace *repl; 41 - 41 + int err; 42 + 42 43 repl = arpt_alloc_initial_table(&packet_filter); 43 44 if (repl == NULL) 44 45 return -ENOMEM; 45 - net->ipv4.arptable_filter = 46 - arpt_register_table(net, &packet_filter, repl); 46 + err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops, 47 + &net->ipv4.arptable_filter); 47 48 kfree(repl); 48 - return PTR_ERR_OR_ZERO(net->ipv4.arptable_filter); 49 + return err; 49 50 } 50 51 51 52 static void __net_exit arptable_filter_net_exit(struct net *net) 52 53 { 53 - arpt_unregister_table(net->ipv4.arptable_filter); 54 + arpt_unregister_table(net, net->ipv4.arptable_filter, arpfilter_ops); 54 55 } 55 56 56 57 static struct pernet_operations arptable_filter_net_ops = {
+10 -11
net/ipv4/netfilter/ip_tables.c
··· 2062 2062 return ret; 2063 2063 } 2064 2064 2065 - struct xt_table *ipt_register_table(struct net *net, 2066 - const struct xt_table *table, 2067 - const struct ipt_replace *repl) 2065 + int ipt_register_table(struct net *net, const struct xt_table *table, 2066 + const struct ipt_replace *repl, 2067 + const struct nf_hook_ops *ops, struct xt_table **res) 2068 2068 { 2069 2069 int ret; 2070 2070 struct xt_table_info *newinfo; ··· 2073 2073 struct xt_table *new_table; 2074 2074 2075 2075 newinfo = xt_alloc_table_info(repl->size); 2076 - if (!newinfo) { 2077 - ret = -ENOMEM; 2078 - goto out; 2079 - } 2076 + if (!newinfo) 2077 + return -ENOMEM; 2080 2078 2081 2079 loc_cpu_entry = newinfo->entries; 2082 2080 memcpy(loc_cpu_entry, repl->entries, repl->size); ··· 2089 2091 goto out_free; 2090 2092 } 2091 2093 2092 - return new_table; 2094 + WRITE_ONCE(*res, new_table); 2095 + return ret; 2093 2096 2094 2097 out_free: 2095 2098 xt_free_table_info(newinfo); 2096 - out: 2097 - return ERR_PTR(ret); 2099 + return ret; 2098 2100 } 2099 2101 2100 - void ipt_unregister_table(struct net *net, struct xt_table *table) 2102 + void ipt_unregister_table(struct net *net, struct xt_table *table, 2103 + const struct nf_hook_ops *ops) 2101 2104 { 2102 2105 struct xt_table_info *private; 2103 2106 void *loc_cpu_entry;
+5 -4
net/ipv4/netfilter/iptable_filter.c
··· 54 54 static int __net_init iptable_filter_net_init(struct net *net) 55 55 { 56 56 struct ipt_replace *repl; 57 + int err; 57 58 58 59 repl = ipt_alloc_initial_table(&packet_filter); 59 60 if (repl == NULL) ··· 63 62 ((struct ipt_standard *)repl->entries)[1].target.verdict = 64 63 forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; 65 64 66 - net->ipv4.iptable_filter = 67 - ipt_register_table(net, &packet_filter, repl); 65 + err = ipt_register_table(net, &packet_filter, repl, filter_ops, 66 + &net->ipv4.iptable_filter); 68 67 kfree(repl); 69 - return PTR_ERR_OR_ZERO(net->ipv4.iptable_filter); 68 + return err; 70 69 } 71 70 72 71 static void __net_exit iptable_filter_net_exit(struct net *net) 73 72 { 74 - ipt_unregister_table(net, net->ipv4.iptable_filter); 73 + ipt_unregister_table(net, net->ipv4.iptable_filter, filter_ops); 75 74 } 76 75 77 76 static struct pernet_operations iptable_filter_net_ops = {
+5 -4
net/ipv4/netfilter/iptable_mangle.c
··· 96 96 static int __net_init iptable_mangle_net_init(struct net *net) 97 97 { 98 98 struct ipt_replace *repl; 99 + int ret; 99 100 100 101 repl = ipt_alloc_initial_table(&packet_mangler); 101 102 if (repl == NULL) 102 103 return -ENOMEM; 103 - net->ipv4.iptable_mangle = 104 - ipt_register_table(net, &packet_mangler, repl); 104 + ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops, 105 + &net->ipv4.iptable_mangle); 105 106 kfree(repl); 106 - return PTR_ERR_OR_ZERO(net->ipv4.iptable_mangle); 107 + return ret; 107 108 } 108 109 109 110 static void __net_exit iptable_mangle_net_exit(struct net *net) 110 111 { 111 - ipt_unregister_table(net, net->ipv4.iptable_mangle); 112 + ipt_unregister_table(net, net->ipv4.iptable_mangle, mangle_ops); 112 113 } 113 114 114 115 static struct pernet_operations iptable_mangle_net_ops = {
+5 -3
net/ipv4/netfilter/iptable_nat.c
··· 98 98 static int __net_init iptable_nat_net_init(struct net *net) 99 99 { 100 100 struct ipt_replace *repl; 101 + int ret; 101 102 102 103 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); 103 104 if (repl == NULL) 104 105 return -ENOMEM; 105 - net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl); 106 + ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, 107 + nf_nat_ipv4_ops, &net->ipv4.nat_table); 106 108 kfree(repl); 107 - return PTR_ERR_OR_ZERO(net->ipv4.nat_table); 109 + return ret; 108 110 } 109 111 110 112 static void __net_exit iptable_nat_net_exit(struct net *net) 111 113 { 112 - ipt_unregister_table(net, net->ipv4.nat_table); 114 + ipt_unregister_table(net, net->ipv4.nat_table, nf_nat_ipv4_ops); 113 115 } 114 116 115 117 static struct pernet_operations iptable_nat_net_ops = {
+5 -4
net/ipv4/netfilter/iptable_raw.c
··· 37 37 static int __net_init iptable_raw_net_init(struct net *net) 38 38 { 39 39 struct ipt_replace *repl; 40 + int ret; 40 41 41 42 repl = ipt_alloc_initial_table(&packet_raw); 42 43 if (repl == NULL) 43 44 return -ENOMEM; 44 - net->ipv4.iptable_raw = 45 - ipt_register_table(net, &packet_raw, repl); 45 + ret = ipt_register_table(net, &packet_raw, repl, rawtable_ops, 46 + &net->ipv4.iptable_raw); 46 47 kfree(repl); 47 - return PTR_ERR_OR_ZERO(net->ipv4.iptable_raw); 48 + return ret; 48 49 } 49 50 50 51 static void __net_exit iptable_raw_net_exit(struct net *net) 51 52 { 52 - ipt_unregister_table(net, net->ipv4.iptable_raw); 53 + ipt_unregister_table(net, net->ipv4.iptable_raw, rawtable_ops); 53 54 } 54 55 55 56 static struct pernet_operations iptable_raw_net_ops = {
+5 -4
net/ipv4/netfilter/iptable_security.c
··· 54 54 static int __net_init iptable_security_net_init(struct net *net) 55 55 { 56 56 struct ipt_replace *repl; 57 + int ret; 57 58 58 59 repl = ipt_alloc_initial_table(&security_table); 59 60 if (repl == NULL) 60 61 return -ENOMEM; 61 - net->ipv4.iptable_security = 62 - ipt_register_table(net, &security_table, repl); 62 + ret = ipt_register_table(net, &security_table, repl, sectbl_ops, 63 + &net->ipv4.iptable_security); 63 64 kfree(repl); 64 - return PTR_ERR_OR_ZERO(net->ipv4.iptable_security); 65 + return ret; 65 66 } 66 67 67 68 static void __net_exit iptable_security_net_exit(struct net *net) 68 69 { 69 - ipt_unregister_table(net, net->ipv4.iptable_security); 70 + ipt_unregister_table(net, net->ipv4.iptable_security, sectbl_ops); 70 71 } 71 72 72 73 static struct pernet_operations iptable_security_net_ops = {
+12 -11
net/ipv6/netfilter/ip6_tables.c
··· 2071 2071 return ret; 2072 2072 } 2073 2073 2074 - struct xt_table *ip6t_register_table(struct net *net, 2075 - const struct xt_table *table, 2076 - const struct ip6t_replace *repl) 2074 + int ip6t_register_table(struct net *net, const struct xt_table *table, 2075 + const struct ip6t_replace *repl, 2076 + const struct nf_hook_ops *ops, 2077 + struct xt_table **res) 2077 2078 { 2078 2079 int ret; 2079 2080 struct xt_table_info *newinfo; ··· 2083 2082 struct xt_table *new_table; 2084 2083 2085 2084 newinfo = xt_alloc_table_info(repl->size); 2086 - if (!newinfo) { 2087 - ret = -ENOMEM; 2088 - goto out; 2089 - } 2085 + if (!newinfo) 2086 + return -ENOMEM; 2090 2087 2091 2088 loc_cpu_entry = newinfo->entries; 2092 2089 memcpy(loc_cpu_entry, repl->entries, repl->size); ··· 2098 2099 ret = PTR_ERR(new_table); 2099 2100 goto out_free; 2100 2101 } 2101 - return new_table; 2102 + 2103 + WRITE_ONCE(*res, new_table); 2104 + return ret; 2102 2105 2103 2106 out_free: 2104 2107 xt_free_table_info(newinfo); 2105 - out: 2106 - return ERR_PTR(ret); 2108 + return ret; 2107 2109 } 2108 2110 2109 - void ip6t_unregister_table(struct net *net, struct xt_table *table) 2111 + void ip6t_unregister_table(struct net *net, struct xt_table *table, 2112 + const struct nf_hook_ops *ops) 2110 2113 { 2111 2114 struct xt_table_info *private; 2112 2115 void *loc_cpu_entry;
+5 -4
net/ipv6/netfilter/ip6table_filter.c
··· 47 47 static int __net_init ip6table_filter_net_init(struct net *net) 48 48 { 49 49 struct ip6t_replace *repl; 50 + int err; 50 51 51 52 repl = ip6t_alloc_initial_table(&packet_filter); 52 53 if (repl == NULL) ··· 56 55 ((struct ip6t_standard *)repl->entries)[1].target.verdict = 57 56 forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; 58 57 59 - net->ipv6.ip6table_filter = 60 - ip6t_register_table(net, &packet_filter, repl); 58 + err = ip6t_register_table(net, &packet_filter, repl, filter_ops, 59 + &net->ipv6.ip6table_filter); 61 60 kfree(repl); 62 - return PTR_ERR_OR_ZERO(net->ipv6.ip6table_filter); 61 + return err; 63 62 } 64 63 65 64 static void __net_exit ip6table_filter_net_exit(struct net *net) 66 65 { 67 - ip6t_unregister_table(net, net->ipv6.ip6table_filter); 66 + ip6t_unregister_table(net, net->ipv6.ip6table_filter, filter_ops); 68 67 } 69 68 70 69 static struct pernet_operations ip6table_filter_net_ops = {
+5 -4
net/ipv6/netfilter/ip6table_mangle.c
··· 91 91 static int __net_init ip6table_mangle_net_init(struct net *net) 92 92 { 93 93 struct ip6t_replace *repl; 94 + int ret; 94 95 95 96 repl = ip6t_alloc_initial_table(&packet_mangler); 96 97 if (repl == NULL) 97 98 return -ENOMEM; 98 - net->ipv6.ip6table_mangle = 99 - ip6t_register_table(net, &packet_mangler, repl); 99 + ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops, 100 + &net->ipv6.ip6table_mangle); 100 101 kfree(repl); 101 - return PTR_ERR_OR_ZERO(net->ipv6.ip6table_mangle); 102 + return ret; 102 103 } 103 104 104 105 static void __net_exit ip6table_mangle_net_exit(struct net *net) 105 106 { 106 - ip6t_unregister_table(net, net->ipv6.ip6table_mangle); 107 + ip6t_unregister_table(net, net->ipv6.ip6table_mangle, mangle_ops); 107 108 } 108 109 109 110 static struct pernet_operations ip6table_mangle_net_ops = {
+5 -3
net/ipv6/netfilter/ip6table_nat.c
··· 100 100 static int __net_init ip6table_nat_net_init(struct net *net) 101 101 { 102 102 struct ip6t_replace *repl; 103 + int ret; 103 104 104 105 repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); 105 106 if (repl == NULL) 106 107 return -ENOMEM; 107 - net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); 108 + ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl, 109 + nf_nat_ipv6_ops, &net->ipv6.ip6table_nat); 108 110 kfree(repl); 109 - return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat); 111 + return ret; 110 112 } 111 113 112 114 static void __net_exit ip6table_nat_net_exit(struct net *net) 113 115 { 114 - ip6t_unregister_table(net, net->ipv6.ip6table_nat); 116 + ip6t_unregister_table(net, net->ipv6.ip6table_nat, nf_nat_ipv6_ops); 115 117 } 116 118 117 119 static struct pernet_operations ip6table_nat_net_ops = {
+5 -4
net/ipv6/netfilter/ip6table_raw.c
··· 30 30 static int __net_init ip6table_raw_net_init(struct net *net) 31 31 { 32 32 struct ip6t_replace *repl; 33 + int ret; 33 34 34 35 repl = ip6t_alloc_initial_table(&packet_raw); 35 36 if (repl == NULL) 36 37 return -ENOMEM; 37 - net->ipv6.ip6table_raw = 38 - ip6t_register_table(net, &packet_raw, repl); 38 + ret = ip6t_register_table(net, &packet_raw, repl, rawtable_ops, 39 + &net->ipv6.ip6table_raw); 39 40 kfree(repl); 40 - return PTR_ERR_OR_ZERO(net->ipv6.ip6table_raw); 41 + return ret; 41 42 } 42 43 43 44 static void __net_exit ip6table_raw_net_exit(struct net *net) 44 45 { 45 - ip6t_unregister_table(net, net->ipv6.ip6table_raw); 46 + ip6t_unregister_table(net, net->ipv6.ip6table_raw, rawtable_ops); 46 47 } 47 48 48 49 static struct pernet_operations ip6table_raw_net_ops = {
+5 -4
net/ipv6/netfilter/ip6table_security.c
··· 47 47 static int __net_init ip6table_security_net_init(struct net *net) 48 48 { 49 49 struct ip6t_replace *repl; 50 + int ret; 50 51 51 52 repl = ip6t_alloc_initial_table(&security_table); 52 53 if (repl == NULL) 53 54 return -ENOMEM; 54 - net->ipv6.ip6table_security = 55 - ip6t_register_table(net, &security_table, repl); 55 + ret = ip6t_register_table(net, &security_table, repl, sectbl_ops, 56 + &net->ipv6.ip6table_security); 56 57 kfree(repl); 57 - return PTR_ERR_OR_ZERO(net->ipv6.ip6table_security); 58 + return ret; 58 59 } 59 60 60 61 static void __net_exit ip6table_security_net_exit(struct net *net) 61 62 { 62 - ip6t_unregister_table(net, net->ipv6.ip6table_security); 63 + ip6t_unregister_table(net, net->ipv6.ip6table_security, sectbl_ops); 63 64 } 64 65 65 66 static struct pernet_operations ip6table_security_net_ops = {