aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-09-10 15:46:32 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-10 15:46:32 -0400
commit0aac383353693edcd8fc5a82a692bb7e5f60d2fd (patch)
tree53750f41a82c12fb468d360b635bcbd65958ccc9 /net
parentb167a37c7bbc6f7589f439ba7d9a49af5ad37ff5 (diff)
parent9ba1f726bec090399eb9bb9157eb32dedc8e8c45 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== nf-next pull request The following patchset contains Netfilter/IPVS updates for your net-next tree. Regarding nf_tables, most updates focus on consolidating the NAT infrastructure and adding support for masquerading. More specifically, they are: 1) use __u8 instead of u_int8_t in arptables header, from Mike Frysinger. 2) Add support to match by skb->pkttype to the meta expression, from Ana Rey. 3) Add support to match by cpu to the meta expression, also from Ana Rey. 4) A smatch warning about IPSET_ATTR_MARKMASK validation, patch from Vytas Dauksa. 5) Fix netnet and netportnet hash types the range support for IPv4, from Sergey Popovich. 6) Fix missing-field-initializer warnings resolved, from Mark Rustad. 7) Dan Carperter reported possible integer overflows in ipset, from Jozsef Kadlecsick. 8) Filter out accounting objects in nfacct by type, so you can selectively reset quotas, from Alexey Perevalov. 9) Move specific NAT IPv4 functions to the core so x_tables and nf_tables can share the same NAT IPv4 engine. 10) Use the new NAT IPv4 functions from nft_chain_nat_ipv4. 11) Move specific NAT IPv6 functions to the core so x_tables and nf_tables can share the same NAT IPv4 engine. 12) Use the new NAT IPv6 functions from nft_chain_nat_ipv6. 13) Refactor code to add nft_delrule(), which can be reused in the enhancement of the NFT_MSG_DELTABLE to remove a table and its content, from Arturo Borrero. 14) Add a helper function to unregister chain hooks, from Arturo Borrero. 15) A cleanup to rename to nft_delrule_by_chain for consistency with the new nft_*() functions, also from Arturo. 16) Add support to match devgroup to the meta expression, from Ana Rey. 17) Reduce stack usage for IPVS socket option, from Julian Anastasov. 18) Remove unnecessary textsearch state initialization in xt_string, from Bojan Prtvar. 19) Add several helper functions to nf_tables, more work to prepare the enhancement of NFT_MSG_DELTABLE, again from Arturo Borrero. 20) Enhance NFT_MSG_DELTABLE to delete a table and its content, from Arturo Borrero. 21) Support NAT flags in the nat expression to indicate the flavour, eg. random fully, from Arturo. 22) Add missing audit code to ebtables when replacing tables, from Nicolas Dichtel. 23) Generalize the IPv4 masquerading code to allow its re-use from nf_tables, from Arturo. 24) Generalize the IPv6 masquerading code, also from Arturo. 25) Add the new masq expression to support IPv4/IPv6 masquerading from nf_tables, also from Arturo. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/netfilter/ebtables.c15
-rw-r--r--net/ipv4/netfilter/Kconfig13
-rw-r--r--net/ipv4/netfilter/Makefile2
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c108
-rw-r--r--net/ipv4/netfilter/iptable_nat.c233
-rw-r--r--net/ipv4/netfilter/nf_nat_l3proto_ipv4.c199
-rw-r--r--net/ipv4/netfilter/nf_nat_masquerade_ipv4.c153
-rw-r--r--net/ipv4/netfilter/nft_chain_nat_ipv4.c157
-rw-r--r--net/ipv4/netfilter/nft_masq_ipv4.c89
-rw-r--r--net/ipv6/netfilter/Kconfig13
-rw-r--r--net/ipv6/netfilter/Makefile2
-rw-r--r--net/ipv6/netfilter/ip6t_MASQUERADE.c76
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c233
-rw-r--r--net/ipv6/netfilter/nf_nat_l3proto_ipv6.c199
-rw-r--r--net/ipv6/netfilter/nf_nat_masquerade_ipv6.c120
-rw-r--r--net/ipv6/netfilter/nft_chain_nat_ipv6.c165
-rw-r--r--net/ipv6/netfilter/nft_masq_ipv6.c89
-rw-r--r--net/netfilter/Kconfig9
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c4
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c4
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c4
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c8
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c8
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c8
-rw-r--r--net/netfilter/ipset/ip_set_hash_netnet.c13
-rw-r--r--net/netfilter/ipset/ip_set_hash_netportnet.c6
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c111
-rw-r--r--net/netfilter/nf_tables_api.c454
-rw-r--r--net/netfilter/nfnetlink_acct.c54
-rw-r--r--net/netfilter/nft_masq.c59
-rw-r--r--net/netfilter/nft_meta.c45
-rw-r--r--net/netfilter/nft_nat.c16
-rw-r--r--net/netfilter/xt_string.c1
36 files changed, 1608 insertions, 1069 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 6d69631b9f4d..d9a8c05d995d 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -26,6 +26,7 @@
26#include <asm/uaccess.h> 26#include <asm/uaccess.h>
27#include <linux/smp.h> 27#include <linux/smp.h>
28#include <linux/cpumask.h> 28#include <linux/cpumask.h>
29#include <linux/audit.h>
29#include <net/sock.h> 30#include <net/sock.h>
30/* needed for logical [in,out]-dev filtering */ 31/* needed for logical [in,out]-dev filtering */
31#include "../br_private.h" 32#include "../br_private.h"
@@ -1058,6 +1059,20 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
1058 vfree(table); 1059 vfree(table);
1059 1060
1060 vfree(counterstmp); 1061 vfree(counterstmp);
1062
1063#ifdef CONFIG_AUDIT
1064 if (audit_enabled) {
1065 struct audit_buffer *ab;
1066
1067 ab = audit_log_start(current->audit_context, GFP_KERNEL,
1068 AUDIT_NETFILTER_CFG);
1069 if (ab) {
1070 audit_log_format(ab, "table=%s family=%u entries=%u",
1071 repl->name, AF_BRIDGE, repl->nentries);
1072 audit_log_end(ab);
1073 }
1074 }
1075#endif
1061 return ret; 1076 return ret;
1062 1077
1063free_unlock: 1078free_unlock:
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 7cbcaf4f0194..d189c5262bdb 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -232,8 +232,21 @@ config IP_NF_NAT
232 232
233if IP_NF_NAT 233if IP_NF_NAT
234 234
235config NF_NAT_MASQUERADE_IPV4
236 tristate "IPv4 masquerade support"
237 help
238 This is the kernel functionality to provide NAT in the masquerade
239 flavour (automatic source address selection).
240
241config NFT_MASQ_IPV4
242 tristate "IPv4 masquerading support for nf_tables"
243 depends on NF_TABLES_IPV4
244 depends on NFT_MASQ
245 select NF_NAT_MASQUERADE_IPV4
246
235config IP_NF_TARGET_MASQUERADE 247config IP_NF_TARGET_MASQUERADE
236 tristate "MASQUERADE target support" 248 tristate "MASQUERADE target support"
249 select NF_NAT_MASQUERADE_IPV4
237 default m if NETFILTER_ADVANCED=n 250 default m if NETFILTER_ADVANCED=n
238 help 251 help
239 Masquerading is a special case of NAT: all outgoing connections are 252 Masquerading is a special case of NAT: all outgoing connections are
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index edf4af32e9f2..14488cc5fd2c 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_NF_LOG_IPV4) += nf_log_ipv4.o
27obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 27obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
28obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o 28obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
29obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o 29obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
30obj-$(CONFIG_NF_NAT_MASQUERADE_IPV4) += nf_nat_masquerade_ipv4.o
30 31
31# NAT protocols (nf_nat) 32# NAT protocols (nf_nat)
32obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o 33obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
35obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o 36obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o
36obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o 37obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o
37obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o 38obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
39obj-$(CONFIG_NFT_MASQ_IPV4) += nft_masq_ipv4.o
38obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o 40obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
39 41
40# generic IP tables 42# generic IP tables
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index 00352ce0f0de..da7f02a0b868 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -22,6 +22,7 @@
22#include <linux/netfilter_ipv4.h> 22#include <linux/netfilter_ipv4.h>
23#include <linux/netfilter/x_tables.h> 23#include <linux/netfilter/x_tables.h>
24#include <net/netfilter/nf_nat.h> 24#include <net/netfilter/nf_nat.h>
25#include <net/netfilter/ipv4/nf_nat_masquerade.h>
25 26
26MODULE_LICENSE("GPL"); 27MODULE_LICENSE("GPL");
27MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); 28MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -46,103 +47,17 @@ static int masquerade_tg_check(const struct xt_tgchk_param *par)
46static unsigned int 47static unsigned int
47masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par) 48masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
48{ 49{
49 struct nf_conn *ct; 50 struct nf_nat_range range;
50 struct nf_conn_nat *nat;
51 enum ip_conntrack_info ctinfo;
52 struct nf_nat_range newrange;
53 const struct nf_nat_ipv4_multi_range_compat *mr; 51 const struct nf_nat_ipv4_multi_range_compat *mr;
54 const struct rtable *rt;
55 __be32 newsrc, nh;
56
57 NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING);
58
59 ct = nf_ct_get(skb, &ctinfo);
60 nat = nfct_nat(ct);
61
62 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
63 ctinfo == IP_CT_RELATED_REPLY));
64
65 /* Source address is 0.0.0.0 - locally generated packet that is
66 * probably not supposed to be masqueraded.
67 */
68 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
69 return NF_ACCEPT;
70 52
71 mr = par->targinfo; 53 mr = par->targinfo;
72 rt = skb_rtable(skb); 54 range.flags = mr->range[0].flags;
73 nh = rt_nexthop(rt, ip_hdr(skb)->daddr); 55 range.min_proto = mr->range[0].min;
74 newsrc = inet_select_addr(par->out, nh, RT_SCOPE_UNIVERSE); 56 range.max_proto = mr->range[0].max;
75 if (!newsrc) {
76 pr_info("%s ate my IP address\n", par->out->name);
77 return NF_DROP;
78 }
79
80 nat->masq_index = par->out->ifindex;
81
82 /* Transfer from original range. */
83 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
84 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
85 newrange.flags = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
86 newrange.min_addr.ip = newsrc;
87 newrange.max_addr.ip = newsrc;
88 newrange.min_proto = mr->range[0].min;
89 newrange.max_proto = mr->range[0].max;
90 57
91 /* Hand modified range to generic setup. */ 58 return nf_nat_masquerade_ipv4(skb, par->hooknum, &range, par->out);
92 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
93} 59}
94 60
95static int
96device_cmp(struct nf_conn *i, void *ifindex)
97{
98 const struct nf_conn_nat *nat = nfct_nat(i);
99
100 if (!nat)
101 return 0;
102 if (nf_ct_l3num(i) != NFPROTO_IPV4)
103 return 0;
104 return nat->masq_index == (int)(long)ifindex;
105}
106
107static int masq_device_event(struct notifier_block *this,
108 unsigned long event,
109 void *ptr)
110{
111 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
112 struct net *net = dev_net(dev);
113
114 if (event == NETDEV_DOWN) {
115 /* Device was downed. Search entire table for
116 conntracks which were associated with that device,
117 and forget them. */
118 NF_CT_ASSERT(dev->ifindex != 0);
119
120 nf_ct_iterate_cleanup(net, device_cmp,
121 (void *)(long)dev->ifindex, 0, 0);
122 }
123
124 return NOTIFY_DONE;
125}
126
127static int masq_inet_event(struct notifier_block *this,
128 unsigned long event,
129 void *ptr)
130{
131 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
132 struct netdev_notifier_info info;
133
134 netdev_notifier_info_init(&info, dev);
135 return masq_device_event(this, event, &info);
136}
137
138static struct notifier_block masq_dev_notifier = {
139 .notifier_call = masq_device_event,
140};
141
142static struct notifier_block masq_inet_notifier = {
143 .notifier_call = masq_inet_event,
144};
145
146static struct xt_target masquerade_tg_reg __read_mostly = { 61static struct xt_target masquerade_tg_reg __read_mostly = {
147 .name = "MASQUERADE", 62 .name = "MASQUERADE",
148 .family = NFPROTO_IPV4, 63 .family = NFPROTO_IPV4,
@@ -160,12 +75,8 @@ static int __init masquerade_tg_init(void)
160 75
161 ret = xt_register_target(&masquerade_tg_reg); 76 ret = xt_register_target(&masquerade_tg_reg);
162 77
163 if (ret == 0) { 78 if (ret == 0)
164 /* Register for device down reports */ 79 nf_nat_masquerade_ipv4_register_notifier();
165 register_netdevice_notifier(&masq_dev_notifier);
166 /* Register IP address change reports */
167 register_inetaddr_notifier(&masq_inet_notifier);
168 }
169 80
170 return ret; 81 return ret;
171} 82}
@@ -173,8 +84,7 @@ static int __init masquerade_tg_init(void)
173static void __exit masquerade_tg_exit(void) 84static void __exit masquerade_tg_exit(void)
174{ 85{
175 xt_unregister_target(&masquerade_tg_reg); 86 xt_unregister_target(&masquerade_tg_reg);
176 unregister_netdevice_notifier(&masq_dev_notifier); 87 nf_nat_masquerade_ipv4_unregister_notifier();
177 unregister_inetaddr_notifier(&masq_inet_notifier);
178} 88}
179 89
180module_init(masquerade_tg_init); 90module_init(masquerade_tg_init);
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index f1787c04a4dd..6b67d7e9a75d 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -28,222 +28,57 @@ static const struct xt_table nf_nat_ipv4_table = {
28 .af = NFPROTO_IPV4, 28 .af = NFPROTO_IPV4,
29}; 29};
30 30
31static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) 31static unsigned int iptable_nat_do_chain(const struct nf_hook_ops *ops,
32{ 32 struct sk_buff *skb,
33 /* Force range to this IP; let proto decide mapping for 33 const struct net_device *in,
34 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). 34 const struct net_device *out,
35 */ 35 struct nf_conn *ct)
36 struct nf_nat_range range;
37
38 range.flags = 0;
39 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
40 HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
41 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
42 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
43
44 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
45}
46
47static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
48 const struct net_device *in,
49 const struct net_device *out,
50 struct nf_conn *ct)
51{ 36{
52 struct net *net = nf_ct_net(ct); 37 struct net *net = nf_ct_net(ct);
53 unsigned int ret;
54 38
55 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table); 39 return ipt_do_table(skb, ops->hooknum, in, out, net->ipv4.nat_table);
56 if (ret == NF_ACCEPT) {
57 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
58 ret = alloc_null_binding(ct, hooknum);
59 }
60 return ret;
61} 40}
62 41
63static unsigned int 42static unsigned int iptable_nat_ipv4_fn(const struct nf_hook_ops *ops,
64nf_nat_ipv4_fn(const struct nf_hook_ops *ops, 43 struct sk_buff *skb,
65 struct sk_buff *skb, 44 const struct net_device *in,
66 const struct net_device *in, 45 const struct net_device *out,
67 const struct net_device *out, 46 int (*okfn)(struct sk_buff *))
68 int (*okfn)(struct sk_buff *))
69{ 47{
70 struct nf_conn *ct; 48 return nf_nat_ipv4_fn(ops, skb, in, out, iptable_nat_do_chain);
71 enum ip_conntrack_info ctinfo;
72 struct nf_conn_nat *nat;
73 /* maniptype == SRC for postrouting. */
74 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
75
76 /* We never see fragments: conntrack defrags on pre-routing
77 * and local-out, and nf_nat_out protects post-routing.
78 */
79 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb)));
80
81 ct = nf_ct_get(skb, &ctinfo);
82 /* Can't track? It's not due to stress, or conntrack would
83 * have dropped it. Hence it's the user's responsibilty to
84 * packet filter it out, or implement conntrack/NAT for that
85 * protocol. 8) --RR
86 */
87 if (!ct)
88 return NF_ACCEPT;
89
90 /* Don't try to NAT if this packet is not conntracked */
91 if (nf_ct_is_untracked(ct))
92 return NF_ACCEPT;
93
94 nat = nf_ct_nat_ext_add(ct);
95 if (nat == NULL)
96 return NF_ACCEPT;
97
98 switch (ctinfo) {
99 case IP_CT_RELATED:
100 case IP_CT_RELATED_REPLY:
101 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
102 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
103 ops->hooknum))
104 return NF_DROP;
105 else
106 return NF_ACCEPT;
107 }
108 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
109 case IP_CT_NEW:
110 /* Seen it before? This can happen for loopback, retrans,
111 * or local packets.
112 */
113 if (!nf_nat_initialized(ct, maniptype)) {
114 unsigned int ret;
115
116 ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct);
117 if (ret != NF_ACCEPT)
118 return ret;
119 } else {
120 pr_debug("Already setup manip %s for ct %p\n",
121 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
122 ct);
123 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
124 goto oif_changed;
125 }
126 break;
127
128 default:
129 /* ESTABLISHED */
130 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
131 ctinfo == IP_CT_ESTABLISHED_REPLY);
132 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
133 goto oif_changed;
134 }
135
136 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
137
138oif_changed:
139 nf_ct_kill_acct(ct, ctinfo, skb);
140 return NF_DROP;
141} 49}
142 50
143static unsigned int 51static unsigned int iptable_nat_ipv4_in(const struct nf_hook_ops *ops,
144nf_nat_ipv4_in(const struct nf_hook_ops *ops, 52 struct sk_buff *skb,
145 struct sk_buff *skb, 53 const struct net_device *in,
146 const struct net_device *in, 54 const struct net_device *out,
147 const struct net_device *out, 55 int (*okfn)(struct sk_buff *))
148 int (*okfn)(struct sk_buff *))
149{ 56{
150 unsigned int ret; 57 return nf_nat_ipv4_in(ops, skb, in, out, iptable_nat_do_chain);
151 __be32 daddr = ip_hdr(skb)->daddr;
152
153 ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn);
154 if (ret != NF_DROP && ret != NF_STOLEN &&
155 daddr != ip_hdr(skb)->daddr)
156 skb_dst_drop(skb);
157
158 return ret;
159} 58}
160 59
161static unsigned int 60static unsigned int iptable_nat_ipv4_out(const struct nf_hook_ops *ops,
162nf_nat_ipv4_out(const struct nf_hook_ops *ops, 61 struct sk_buff *skb,
163 struct sk_buff *skb, 62 const struct net_device *in,
164 const struct net_device *in, 63 const struct net_device *out,
165 const struct net_device *out, 64 int (*okfn)(struct sk_buff *))
166 int (*okfn)(struct sk_buff *))
167{ 65{
168#ifdef CONFIG_XFRM 66 return nf_nat_ipv4_out(ops, skb, in, out, iptable_nat_do_chain);
169 const struct nf_conn *ct;
170 enum ip_conntrack_info ctinfo;
171 int err;
172#endif
173 unsigned int ret;
174
175 /* root is playing with raw sockets. */
176 if (skb->len < sizeof(struct iphdr) ||
177 ip_hdrlen(skb) < sizeof(struct iphdr))
178 return NF_ACCEPT;
179
180 ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn);
181#ifdef CONFIG_XFRM
182 if (ret != NF_DROP && ret != NF_STOLEN &&
183 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
184 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
185 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
186
187 if ((ct->tuplehash[dir].tuple.src.u3.ip !=
188 ct->tuplehash[!dir].tuple.dst.u3.ip) ||
189 (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
190 ct->tuplehash[dir].tuple.src.u.all !=
191 ct->tuplehash[!dir].tuple.dst.u.all)) {
192 err = nf_xfrm_me_harder(skb, AF_INET);
193 if (err < 0)
194 ret = NF_DROP_ERR(err);
195 }
196 }
197#endif
198 return ret;
199} 67}
200 68
201static unsigned int 69static unsigned int iptable_nat_ipv4_local_fn(const struct nf_hook_ops *ops,
202nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, 70 struct sk_buff *skb,
203 struct sk_buff *skb, 71 const struct net_device *in,
204 const struct net_device *in, 72 const struct net_device *out,
205 const struct net_device *out, 73 int (*okfn)(struct sk_buff *))
206 int (*okfn)(struct sk_buff *))
207{ 74{
208 const struct nf_conn *ct; 75 return nf_nat_ipv4_local_fn(ops, skb, in, out, iptable_nat_do_chain);
209 enum ip_conntrack_info ctinfo;
210 unsigned int ret;
211 int err;
212
213 /* root is playing with raw sockets. */
214 if (skb->len < sizeof(struct iphdr) ||
215 ip_hdrlen(skb) < sizeof(struct iphdr))
216 return NF_ACCEPT;
217
218 ret = nf_nat_ipv4_fn(ops, skb, in, out, okfn);
219 if (ret != NF_DROP && ret != NF_STOLEN &&
220 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
221 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
222
223 if (ct->tuplehash[dir].tuple.dst.u3.ip !=
224 ct->tuplehash[!dir].tuple.src.u3.ip) {
225 err = ip_route_me_harder(skb, RTN_UNSPEC);
226 if (err < 0)
227 ret = NF_DROP_ERR(err);
228 }
229#ifdef CONFIG_XFRM
230 else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
231 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
232 ct->tuplehash[dir].tuple.dst.u.all !=
233 ct->tuplehash[!dir].tuple.src.u.all) {
234 err = nf_xfrm_me_harder(skb, AF_INET);
235 if (err < 0)
236 ret = NF_DROP_ERR(err);
237 }
238#endif
239 }
240 return ret;
241} 76}
242 77
243static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = { 78static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
244 /* Before packet filtering, change destination */ 79 /* Before packet filtering, change destination */
245 { 80 {
246 .hook = nf_nat_ipv4_in, 81 .hook = iptable_nat_ipv4_in,
247 .owner = THIS_MODULE, 82 .owner = THIS_MODULE,
248 .pf = NFPROTO_IPV4, 83 .pf = NFPROTO_IPV4,
249 .hooknum = NF_INET_PRE_ROUTING, 84 .hooknum = NF_INET_PRE_ROUTING,
@@ -251,7 +86,7 @@ static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
251 }, 86 },
252 /* After packet filtering, change source */ 87 /* After packet filtering, change source */
253 { 88 {
254 .hook = nf_nat_ipv4_out, 89 .hook = iptable_nat_ipv4_out,
255 .owner = THIS_MODULE, 90 .owner = THIS_MODULE,
256 .pf = NFPROTO_IPV4, 91 .pf = NFPROTO_IPV4,
257 .hooknum = NF_INET_POST_ROUTING, 92 .hooknum = NF_INET_POST_ROUTING,
@@ -259,7 +94,7 @@ static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
259 }, 94 },
260 /* Before packet filtering, change destination */ 95 /* Before packet filtering, change destination */
261 { 96 {
262 .hook = nf_nat_ipv4_local_fn, 97 .hook = iptable_nat_ipv4_local_fn,
263 .owner = THIS_MODULE, 98 .owner = THIS_MODULE,
264 .pf = NFPROTO_IPV4, 99 .pf = NFPROTO_IPV4,
265 .hooknum = NF_INET_LOCAL_OUT, 100 .hooknum = NF_INET_LOCAL_OUT,
@@ -267,7 +102,7 @@ static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = {
267 }, 102 },
268 /* After packet filtering, change source */ 103 /* After packet filtering, change source */
269 { 104 {
270 .hook = nf_nat_ipv4_fn, 105 .hook = iptable_nat_ipv4_fn,
271 .owner = THIS_MODULE, 106 .owner = THIS_MODULE,
272 .pf = NFPROTO_IPV4, 107 .pf = NFPROTO_IPV4,
273 .hooknum = NF_INET_LOCAL_IN, 108 .hooknum = NF_INET_LOCAL_IN,
diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
index 14f5ccd06337..fc37711e11f3 100644
--- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
@@ -254,6 +254,205 @@ int nf_nat_icmp_reply_translation(struct sk_buff *skb,
254} 254}
255EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); 255EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
256 256
257unsigned int
258nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
259 const struct net_device *in, const struct net_device *out,
260 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
261 struct sk_buff *skb,
262 const struct net_device *in,
263 const struct net_device *out,
264 struct nf_conn *ct))
265{
266 struct nf_conn *ct;
267 enum ip_conntrack_info ctinfo;
268 struct nf_conn_nat *nat;
269 /* maniptype == SRC for postrouting. */
270 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
271
272 /* We never see fragments: conntrack defrags on pre-routing
273 * and local-out, and nf_nat_out protects post-routing.
274 */
275 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb)));
276
277 ct = nf_ct_get(skb, &ctinfo);
278 /* Can't track? It's not due to stress, or conntrack would
279 * have dropped it. Hence it's the user's responsibilty to
280 * packet filter it out, or implement conntrack/NAT for that
281 * protocol. 8) --RR
282 */
283 if (!ct)
284 return NF_ACCEPT;
285
286 /* Don't try to NAT if this packet is not conntracked */
287 if (nf_ct_is_untracked(ct))
288 return NF_ACCEPT;
289
290 nat = nf_ct_nat_ext_add(ct);
291 if (nat == NULL)
292 return NF_ACCEPT;
293
294 switch (ctinfo) {
295 case IP_CT_RELATED:
296 case IP_CT_RELATED_REPLY:
297 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
298 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
299 ops->hooknum))
300 return NF_DROP;
301 else
302 return NF_ACCEPT;
303 }
304 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
305 case IP_CT_NEW:
306 /* Seen it before? This can happen for loopback, retrans,
307 * or local packets.
308 */
309 if (!nf_nat_initialized(ct, maniptype)) {
310 unsigned int ret;
311
312 ret = do_chain(ops, skb, in, out, ct);
313 if (ret != NF_ACCEPT)
314 return ret;
315
316 if (nf_nat_initialized(ct, HOOK2MANIP(ops->hooknum)))
317 break;
318
319 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
320 if (ret != NF_ACCEPT)
321 return ret;
322 } else {
323 pr_debug("Already setup manip %s for ct %p\n",
324 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
325 ct);
326 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
327 goto oif_changed;
328 }
329 break;
330
331 default:
332 /* ESTABLISHED */
333 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
334 ctinfo == IP_CT_ESTABLISHED_REPLY);
335 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
336 goto oif_changed;
337 }
338
339 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
340
341oif_changed:
342 nf_ct_kill_acct(ct, ctinfo, skb);
343 return NF_DROP;
344}
345EXPORT_SYMBOL_GPL(nf_nat_ipv4_fn);
346
347unsigned int
348nf_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb,
349 const struct net_device *in, const struct net_device *out,
350 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
351 struct sk_buff *skb,
352 const struct net_device *in,
353 const struct net_device *out,
354 struct nf_conn *ct))
355{
356 unsigned int ret;
357 __be32 daddr = ip_hdr(skb)->daddr;
358
359 ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain);
360 if (ret != NF_DROP && ret != NF_STOLEN &&
361 daddr != ip_hdr(skb)->daddr)
362 skb_dst_drop(skb);
363
364 return ret;
365}
366EXPORT_SYMBOL_GPL(nf_nat_ipv4_in);
367
368unsigned int
369nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb,
370 const struct net_device *in, const struct net_device *out,
371 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
372 struct sk_buff *skb,
373 const struct net_device *in,
374 const struct net_device *out,
375 struct nf_conn *ct))
376{
377#ifdef CONFIG_XFRM
378 const struct nf_conn *ct;
379 enum ip_conntrack_info ctinfo;
380 int err;
381#endif
382 unsigned int ret;
383
384 /* root is playing with raw sockets. */
385 if (skb->len < sizeof(struct iphdr) ||
386 ip_hdrlen(skb) < sizeof(struct iphdr))
387 return NF_ACCEPT;
388
389 ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain);
390#ifdef CONFIG_XFRM
391 if (ret != NF_DROP && ret != NF_STOLEN &&
392 !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
393 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
394 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
395
396 if ((ct->tuplehash[dir].tuple.src.u3.ip !=
397 ct->tuplehash[!dir].tuple.dst.u3.ip) ||
398 (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
399 ct->tuplehash[dir].tuple.src.u.all !=
400 ct->tuplehash[!dir].tuple.dst.u.all)) {
401 err = nf_xfrm_me_harder(skb, AF_INET);
402 if (err < 0)
403 ret = NF_DROP_ERR(err);
404 }
405 }
406#endif
407 return ret;
408}
409EXPORT_SYMBOL_GPL(nf_nat_ipv4_out);
410
411unsigned int
412nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
413 const struct net_device *in, const struct net_device *out,
414 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
415 struct sk_buff *skb,
416 const struct net_device *in,
417 const struct net_device *out,
418 struct nf_conn *ct))
419{
420 const struct nf_conn *ct;
421 enum ip_conntrack_info ctinfo;
422 unsigned int ret;
423 int err;
424
425 /* root is playing with raw sockets. */
426 if (skb->len < sizeof(struct iphdr) ||
427 ip_hdrlen(skb) < sizeof(struct iphdr))
428 return NF_ACCEPT;
429
430 ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain);
431 if (ret != NF_DROP && ret != NF_STOLEN &&
432 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
433 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
434
435 if (ct->tuplehash[dir].tuple.dst.u3.ip !=
436 ct->tuplehash[!dir].tuple.src.u3.ip) {
437 err = ip_route_me_harder(skb, RTN_UNSPEC);
438 if (err < 0)
439 ret = NF_DROP_ERR(err);
440 }
441#ifdef CONFIG_XFRM
442 else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
443 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
444 ct->tuplehash[dir].tuple.dst.u.all !=
445 ct->tuplehash[!dir].tuple.src.u.all) {
446 err = nf_xfrm_me_harder(skb, AF_INET);
447 if (err < 0)
448 ret = NF_DROP_ERR(err);
449 }
450#endif
451 }
452 return ret;
453}
454EXPORT_SYMBOL_GPL(nf_nat_ipv4_local_fn);
455
257static int __init nf_nat_l3proto_ipv4_init(void) 456static int __init nf_nat_l3proto_ipv4_init(void)
258{ 457{
259 int err; 458 int err;
diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
new file mode 100644
index 000000000000..c6eb42100e9a
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c
@@ -0,0 +1,153 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/types.h>
10#include <linux/module.h>
11#include <linux/atomic.h>
12#include <linux/inetdevice.h>
13#include <linux/ip.h>
14#include <linux/timer.h>
15#include <linux/netfilter.h>
16#include <net/protocol.h>
17#include <net/ip.h>
18#include <net/checksum.h>
19#include <net/route.h>
20#include <linux/netfilter_ipv4.h>
21#include <linux/netfilter/x_tables.h>
22#include <net/netfilter/nf_nat.h>
23#include <net/netfilter/ipv4/nf_nat_masquerade.h>
24
25unsigned int
26nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum,
27 const struct nf_nat_range *range,
28 const struct net_device *out)
29{
30 struct nf_conn *ct;
31 struct nf_conn_nat *nat;
32 enum ip_conntrack_info ctinfo;
33 struct nf_nat_range newrange;
34 const struct rtable *rt;
35 __be32 newsrc, nh;
36
37 NF_CT_ASSERT(hooknum == NF_INET_POST_ROUTING);
38
39 ct = nf_ct_get(skb, &ctinfo);
40 nat = nfct_nat(ct);
41
42 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
43 ctinfo == IP_CT_RELATED_REPLY));
44
45 /* Source address is 0.0.0.0 - locally generated packet that is
46 * probably not supposed to be masqueraded.
47 */
48 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
49 return NF_ACCEPT;
50
51 rt = skb_rtable(skb);
52 nh = rt_nexthop(rt, ip_hdr(skb)->daddr);
53 newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE);
54 if (!newsrc) {
55 pr_info("%s ate my IP address\n", out->name);
56 return NF_DROP;
57 }
58
59 nat->masq_index = out->ifindex;
60
61 /* Transfer from original range. */
62 memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
63 memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
64 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
65 newrange.min_addr.ip = newsrc;
66 newrange.max_addr.ip = newsrc;
67 newrange.min_proto = range->min_proto;
68 newrange.max_proto = range->max_proto;
69
70 /* Hand modified range to generic setup. */
71 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
72}
73EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4);
74
75static int device_cmp(struct nf_conn *i, void *ifindex)
76{
77 const struct nf_conn_nat *nat = nfct_nat(i);
78
79 if (!nat)
80 return 0;
81 if (nf_ct_l3num(i) != NFPROTO_IPV4)
82 return 0;
83 return nat->masq_index == (int)(long)ifindex;
84}
85
86static int masq_device_event(struct notifier_block *this,
87 unsigned long event,
88 void *ptr)
89{
90 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
91 struct net *net = dev_net(dev);
92
93 if (event == NETDEV_DOWN) {
94 /* Device was downed. Search entire table for
95 * conntracks which were associated with that device,
96 * and forget them.
97 */
98 NF_CT_ASSERT(dev->ifindex != 0);
99
100 nf_ct_iterate_cleanup(net, device_cmp,
101 (void *)(long)dev->ifindex, 0, 0);
102 }
103
104 return NOTIFY_DONE;
105}
106
107static int masq_inet_event(struct notifier_block *this,
108 unsigned long event,
109 void *ptr)
110{
111 struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
112 struct netdev_notifier_info info;
113
114 netdev_notifier_info_init(&info, dev);
115 return masq_device_event(this, event, &info);
116}
117
118static struct notifier_block masq_dev_notifier = {
119 .notifier_call = masq_device_event,
120};
121
122static struct notifier_block masq_inet_notifier = {
123 .notifier_call = masq_inet_event,
124};
125
126static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);
127
128void nf_nat_masquerade_ipv4_register_notifier(void)
129{
130 /* check if the notifier was already set */
131 if (atomic_inc_return(&masquerade_notifier_refcount) > 1)
132 return;
133
134 /* Register for device down reports */
135 register_netdevice_notifier(&masq_dev_notifier);
136 /* Register IP address change reports */
137 register_inetaddr_notifier(&masq_inet_notifier);
138}
139EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_register_notifier);
140
141void nf_nat_masquerade_ipv4_unregister_notifier(void)
142{
143 /* check if the notifier still has clients */
144 if (atomic_dec_return(&masquerade_notifier_refcount) > 0)
145 return;
146
147 unregister_netdevice_notifier(&masq_dev_notifier);
148 unregister_inetaddr_notifier(&masq_inet_notifier);
149}
150EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv4_unregister_notifier);
151
152MODULE_LICENSE("GPL");
153MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
index 3964157d826c..df547bf50078 100644
--- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -26,136 +26,53 @@
26#include <net/netfilter/nf_nat_l3proto.h> 26#include <net/netfilter/nf_nat_l3proto.h>
27#include <net/ip.h> 27#include <net/ip.h>
28 28
29/* 29static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops,
30 * NAT chains 30 struct sk_buff *skb,
31 */ 31 const struct net_device *in,
32 32 const struct net_device *out,
33static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, 33 struct nf_conn *ct)
34 struct sk_buff *skb,
35 const struct net_device *in,
36 const struct net_device *out,
37 int (*okfn)(struct sk_buff *))
38{ 34{
39 enum ip_conntrack_info ctinfo;
40 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
41 struct nf_conn_nat *nat;
42 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
43 struct nft_pktinfo pkt; 35 struct nft_pktinfo pkt;
44 unsigned int ret;
45
46 if (ct == NULL || nf_ct_is_untracked(ct))
47 return NF_ACCEPT;
48
49 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
50
51 nat = nf_ct_nat_ext_add(ct);
52 if (nat == NULL)
53 return NF_ACCEPT;
54
55 switch (ctinfo) {
56 case IP_CT_RELATED:
57 case IP_CT_RELATED + IP_CT_IS_REPLY:
58 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
59 if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
60 ops->hooknum))
61 return NF_DROP;
62 else
63 return NF_ACCEPT;
64 }
65 /* Fall through */
66 case IP_CT_NEW:
67 if (nf_nat_initialized(ct, maniptype))
68 break;
69 36
70 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); 37 nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out);
71 38
72 ret = nft_do_chain(&pkt, ops); 39 return nft_do_chain(&pkt, ops);
73 if (ret != NF_ACCEPT)
74 return ret;
75 if (!nf_nat_initialized(ct, maniptype)) {
76 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
77 if (ret != NF_ACCEPT)
78 return ret;
79 }
80 default:
81 break;
82 }
83
84 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
85} 40}
86 41
87static unsigned int nf_nat_prerouting(const struct nf_hook_ops *ops, 42static unsigned int nft_nat_ipv4_fn(const struct nf_hook_ops *ops,
88 struct sk_buff *skb, 43 struct sk_buff *skb,
89 const struct net_device *in, 44 const struct net_device *in,
90 const struct net_device *out, 45 const struct net_device *out,
91 int (*okfn)(struct sk_buff *)) 46 int (*okfn)(struct sk_buff *))
92{ 47{
93 __be32 daddr = ip_hdr(skb)->daddr; 48 return nf_nat_ipv4_fn(ops, skb, in, out, nft_nat_do_chain);
94 unsigned int ret;
95
96 ret = nf_nat_fn(ops, skb, in, out, okfn);
97 if (ret != NF_DROP && ret != NF_STOLEN &&
98 ip_hdr(skb)->daddr != daddr) {
99 skb_dst_drop(skb);
100 }
101 return ret;
102} 49}
103 50
104static unsigned int nf_nat_postrouting(const struct nf_hook_ops *ops, 51static unsigned int nft_nat_ipv4_in(const struct nf_hook_ops *ops,
105 struct sk_buff *skb, 52 struct sk_buff *skb,
106 const struct net_device *in, 53 const struct net_device *in,
107 const struct net_device *out, 54 const struct net_device *out,
108 int (*okfn)(struct sk_buff *)) 55 int (*okfn)(struct sk_buff *))
109{ 56{
110 enum ip_conntrack_info ctinfo __maybe_unused; 57 return nf_nat_ipv4_in(ops, skb, in, out, nft_nat_do_chain);
111 const struct nf_conn *ct __maybe_unused;
112 unsigned int ret;
113
114 ret = nf_nat_fn(ops, skb, in, out, okfn);
115#ifdef CONFIG_XFRM
116 if (ret != NF_DROP && ret != NF_STOLEN &&
117 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
118 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
119
120 if (ct->tuplehash[dir].tuple.src.u3.ip !=
121 ct->tuplehash[!dir].tuple.dst.u3.ip ||
122 ct->tuplehash[dir].tuple.src.u.all !=
123 ct->tuplehash[!dir].tuple.dst.u.all)
124 return nf_xfrm_me_harder(skb, AF_INET) == 0 ?
125 ret : NF_DROP;
126 }
127#endif
128 return ret;
129} 58}
130 59
131static unsigned int nf_nat_output(const struct nf_hook_ops *ops, 60static unsigned int nft_nat_ipv4_out(const struct nf_hook_ops *ops,
132 struct sk_buff *skb, 61 struct sk_buff *skb,
133 const struct net_device *in, 62 const struct net_device *in,
134 const struct net_device *out, 63 const struct net_device *out,
135 int (*okfn)(struct sk_buff *)) 64 int (*okfn)(struct sk_buff *))
136{ 65{
137 enum ip_conntrack_info ctinfo; 66 return nf_nat_ipv4_out(ops, skb, in, out, nft_nat_do_chain);
138 const struct nf_conn *ct; 67}
139 unsigned int ret;
140
141 ret = nf_nat_fn(ops, skb, in, out, okfn);
142 if (ret != NF_DROP && ret != NF_STOLEN &&
143 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
144 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
145 68
146 if (ct->tuplehash[dir].tuple.dst.u3.ip != 69static unsigned int nft_nat_ipv4_local_fn(const struct nf_hook_ops *ops,
147 ct->tuplehash[!dir].tuple.src.u3.ip) { 70 struct sk_buff *skb,
148 if (ip_route_me_harder(skb, RTN_UNSPEC)) 71 const struct net_device *in,
149 ret = NF_DROP; 72 const struct net_device *out,
150 } 73 int (*okfn)(struct sk_buff *))
151#ifdef CONFIG_XFRM 74{
152 else if (ct->tuplehash[dir].tuple.dst.u.all != 75 return nf_nat_ipv4_local_fn(ops, skb, in, out, nft_nat_do_chain);
153 ct->tuplehash[!dir].tuple.src.u.all)
154 if (nf_xfrm_me_harder(skb, AF_INET))
155 ret = NF_DROP;
156#endif
157 }
158 return ret;
159} 76}
160 77
161static const struct nf_chain_type nft_chain_nat_ipv4 = { 78static const struct nf_chain_type nft_chain_nat_ipv4 = {
@@ -168,10 +85,10 @@ static const struct nf_chain_type nft_chain_nat_ipv4 = {
168 (1 << NF_INET_LOCAL_OUT) | 85 (1 << NF_INET_LOCAL_OUT) |
169 (1 << NF_INET_LOCAL_IN), 86 (1 << NF_INET_LOCAL_IN),
170 .hooks = { 87 .hooks = {
171 [NF_INET_PRE_ROUTING] = nf_nat_prerouting, 88 [NF_INET_PRE_ROUTING] = nft_nat_ipv4_in,
172 [NF_INET_POST_ROUTING] = nf_nat_postrouting, 89 [NF_INET_POST_ROUTING] = nft_nat_ipv4_out,
173 [NF_INET_LOCAL_OUT] = nf_nat_output, 90 [NF_INET_LOCAL_OUT] = nft_nat_ipv4_local_fn,
174 [NF_INET_LOCAL_IN] = nf_nat_fn, 91 [NF_INET_LOCAL_IN] = nft_nat_ipv4_fn,
175 }, 92 },
176}; 93};
177 94
diff --git a/net/ipv4/netfilter/nft_masq_ipv4.c b/net/ipv4/netfilter/nft_masq_ipv4.c
new file mode 100644
index 000000000000..6ea1d207b6a5
--- /dev/null
+++ b/net/ipv4/netfilter/nft_masq_ipv4.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/netlink.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nft_masq.h>
17#include <net/netfilter/ipv4/nf_nat_masquerade.h>
18
19static void nft_masq_ipv4_eval(const struct nft_expr *expr,
20 struct nft_data data[NFT_REG_MAX + 1],
21 const struct nft_pktinfo *pkt)
22{
23 struct nft_masq *priv = nft_expr_priv(expr);
24 struct nf_nat_range range;
25 unsigned int verdict;
26
27 range.flags = priv->flags;
28
29 verdict = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum,
30 &range, pkt->out);
31
32 data[NFT_REG_VERDICT].verdict = verdict;
33}
34
35static int nft_masq_ipv4_init(const struct nft_ctx *ctx,
36 const struct nft_expr *expr,
37 const struct nlattr * const tb[])
38{
39 int err;
40
41 err = nft_masq_init(ctx, expr, tb);
42 if (err < 0)
43 return err;
44
45 nf_nat_masquerade_ipv4_register_notifier();
46 return 0;
47}
48
49static void nft_masq_ipv4_destroy(const struct nft_ctx *ctx,
50 const struct nft_expr *expr)
51{
52 nf_nat_masquerade_ipv4_unregister_notifier();
53}
54
55static struct nft_expr_type nft_masq_ipv4_type;
56static const struct nft_expr_ops nft_masq_ipv4_ops = {
57 .type = &nft_masq_ipv4_type,
58 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
59 .eval = nft_masq_ipv4_eval,
60 .init = nft_masq_ipv4_init,
61 .destroy = nft_masq_ipv4_destroy,
62 .dump = nft_masq_dump,
63};
64
65static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
66 .family = NFPROTO_IPV4,
67 .name = "masq",
68 .ops = &nft_masq_ipv4_ops,
69 .policy = nft_masq_policy,
70 .maxattr = NFTA_MASQ_MAX,
71 .owner = THIS_MODULE,
72};
73
74static int __init nft_masq_ipv4_module_init(void)
75{
76 return nft_register_expr(&nft_masq_ipv4_type);
77}
78
79static void __exit nft_masq_ipv4_module_exit(void)
80{
81 nft_unregister_expr(&nft_masq_ipv4_type);
82}
83
84module_init(nft_masq_ipv4_module_init);
85module_exit(nft_masq_ipv4_module_exit);
86
87MODULE_LICENSE("GPL");
88MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
89MODULE_ALIAS_NFT_AF_EXPR(AF_INET, "masq");
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 2812816aabdc..a8f25306a46a 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -258,8 +258,21 @@ config IP6_NF_NAT
258 258
259if IP6_NF_NAT 259if IP6_NF_NAT
260 260
261config NF_NAT_MASQUERADE_IPV6
262 tristate "IPv6 masquerade support"
263 help
264 This is the kernel functionality to provide NAT in the masquerade
265 flavour (automatic source address selection) for IPv6.
266
267config NFT_MASQ_IPV6
268 tristate "IPv6 masquerade support for nf_tables"
269 depends on NF_TABLES_IPV6
270 depends on NFT_MASQ
271 select NF_NAT_MASQUERADE_IPV6
272
261config IP6_NF_TARGET_MASQUERADE 273config IP6_NF_TARGET_MASQUERADE
262 tristate "MASQUERADE target support" 274 tristate "MASQUERADE target support"
275 select NF_NAT_MASQUERADE_IPV6
263 help 276 help
264 Masquerading is a special case of NAT: all outgoing connections are 277 Masquerading is a special case of NAT: all outgoing connections are
265 changed to seem to come from a particular interface's address, and 278 changed to seem to come from a particular interface's address, and
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index c3d3286db4bb..0f7e5b3f328d 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
18 18
19nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o 19nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o
20obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o 20obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
21obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o
21 22
22# defrag 23# defrag
23nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o 24nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
@@ -31,6 +32,7 @@ obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
31obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o 32obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
32obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o 33obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
33obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o 34obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
35obj-$(CONFIG_NFT_MASQ_IPV6) += nft_masq_ipv6.o
34 36
35# matches 37# matches
36obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o 38obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c
index 3e4e92d5e157..7f9f45d829d2 100644
--- a/net/ipv6/netfilter/ip6t_MASQUERADE.c
+++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c
@@ -19,33 +19,12 @@
19#include <net/netfilter/nf_nat.h> 19#include <net/netfilter/nf_nat.h>
20#include <net/addrconf.h> 20#include <net/addrconf.h>
21#include <net/ipv6.h> 21#include <net/ipv6.h>
22#include <net/netfilter/ipv6/nf_nat_masquerade.h>
22 23
23static unsigned int 24static unsigned int
24masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par) 25masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
25{ 26{
26 const struct nf_nat_range *range = par->targinfo; 27 return nf_nat_masquerade_ipv6(skb, par->targinfo, par->out);
27 enum ip_conntrack_info ctinfo;
28 struct in6_addr src;
29 struct nf_conn *ct;
30 struct nf_nat_range newrange;
31
32 ct = nf_ct_get(skb, &ctinfo);
33 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
34 ctinfo == IP_CT_RELATED_REPLY));
35
36 if (ipv6_dev_get_saddr(dev_net(par->out), par->out,
37 &ipv6_hdr(skb)->daddr, 0, &src) < 0)
38 return NF_DROP;
39
40 nfct_nat(ct)->masq_index = par->out->ifindex;
41
42 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
43 newrange.min_addr.in6 = src;
44 newrange.max_addr.in6 = src;
45 newrange.min_proto = range->min_proto;
46 newrange.max_proto = range->max_proto;
47
48 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
49} 28}
50 29
51static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) 30static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
@@ -57,48 +36,6 @@ static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
57 return 0; 36 return 0;
58} 37}
59 38
60static int device_cmp(struct nf_conn *ct, void *ifindex)
61{
62 const struct nf_conn_nat *nat = nfct_nat(ct);
63
64 if (!nat)
65 return 0;
66 if (nf_ct_l3num(ct) != NFPROTO_IPV6)
67 return 0;
68 return nat->masq_index == (int)(long)ifindex;
69}
70
71static int masq_device_event(struct notifier_block *this,
72 unsigned long event, void *ptr)
73{
74 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
75 struct net *net = dev_net(dev);
76
77 if (event == NETDEV_DOWN)
78 nf_ct_iterate_cleanup(net, device_cmp,
79 (void *)(long)dev->ifindex, 0, 0);
80
81 return NOTIFY_DONE;
82}
83
84static struct notifier_block masq_dev_notifier = {
85 .notifier_call = masq_device_event,
86};
87
88static int masq_inet_event(struct notifier_block *this,
89 unsigned long event, void *ptr)
90{
91 struct inet6_ifaddr *ifa = ptr;
92 struct netdev_notifier_info info;
93
94 netdev_notifier_info_init(&info, ifa->idev->dev);
95 return masq_device_event(this, event, &info);
96}
97
98static struct notifier_block masq_inet_notifier = {
99 .notifier_call = masq_inet_event,
100};
101
102static struct xt_target masquerade_tg6_reg __read_mostly = { 39static struct xt_target masquerade_tg6_reg __read_mostly = {
103 .name = "MASQUERADE", 40 .name = "MASQUERADE",
104 .family = NFPROTO_IPV6, 41 .family = NFPROTO_IPV6,
@@ -115,17 +52,14 @@ static int __init masquerade_tg6_init(void)
115 int err; 52 int err;
116 53
117 err = xt_register_target(&masquerade_tg6_reg); 54 err = xt_register_target(&masquerade_tg6_reg);
118 if (err == 0) { 55 if (err == 0)
119 register_netdevice_notifier(&masq_dev_notifier); 56 nf_nat_masquerade_ipv6_register_notifier();
120 register_inet6addr_notifier(&masq_inet_notifier);
121 }
122 57
123 return err; 58 return err;
124} 59}
125static void __exit masquerade_tg6_exit(void) 60static void __exit masquerade_tg6_exit(void)
126{ 61{
127 unregister_inet6addr_notifier(&masq_inet_notifier); 62 nf_nat_masquerade_ipv6_unregister_notifier();
128 unregister_netdevice_notifier(&masq_dev_notifier);
129 xt_unregister_target(&masquerade_tg6_reg); 63 xt_unregister_target(&masquerade_tg6_reg);
130} 64}
131 65
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index 387d8b8fc18d..b0634ac996b7 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -30,222 +30,57 @@ static const struct xt_table nf_nat_ipv6_table = {
30 .af = NFPROTO_IPV6, 30 .af = NFPROTO_IPV6,
31}; 31};
32 32
33static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) 33static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops,
34{ 34 struct sk_buff *skb,
35 /* Force range to this IP; let proto decide mapping for 35 const struct net_device *in,
36 * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). 36 const struct net_device *out,
37 */ 37 struct nf_conn *ct)
38 struct nf_nat_range range;
39
40 range.flags = 0;
41 pr_debug("Allocating NULL binding for %p (%pI6)\n", ct,
42 HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
43 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6 :
44 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6);
45
46 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
47}
48
49static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
50 const struct net_device *in,
51 const struct net_device *out,
52 struct nf_conn *ct)
53{ 38{
54 struct net *net = nf_ct_net(ct); 39 struct net *net = nf_ct_net(ct);
55 unsigned int ret;
56 40
57 ret = ip6t_do_table(skb, hooknum, in, out, net->ipv6.ip6table_nat); 41 return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat);
58 if (ret == NF_ACCEPT) {
59 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
60 ret = alloc_null_binding(ct, hooknum);
61 }
62 return ret;
63} 42}
64 43
65static unsigned int 44static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops,
66nf_nat_ipv6_fn(const struct nf_hook_ops *ops, 45 struct sk_buff *skb,
67 struct sk_buff *skb, 46 const struct net_device *in,
68 const struct net_device *in, 47 const struct net_device *out,
69 const struct net_device *out, 48 int (*okfn)(struct sk_buff *))
70 int (*okfn)(struct sk_buff *))
71{ 49{
72 struct nf_conn *ct; 50 return nf_nat_ipv6_fn(ops, skb, in, out, ip6table_nat_do_chain);
73 enum ip_conntrack_info ctinfo;
74 struct nf_conn_nat *nat;
75 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
76 __be16 frag_off;
77 int hdrlen;
78 u8 nexthdr;
79
80 ct = nf_ct_get(skb, &ctinfo);
81 /* Can't track? It's not due to stress, or conntrack would
82 * have dropped it. Hence it's the user's responsibilty to
83 * packet filter it out, or implement conntrack/NAT for that
84 * protocol. 8) --RR
85 */
86 if (!ct)
87 return NF_ACCEPT;
88
89 /* Don't try to NAT if this packet is not conntracked */
90 if (nf_ct_is_untracked(ct))
91 return NF_ACCEPT;
92
93 nat = nf_ct_nat_ext_add(ct);
94 if (nat == NULL)
95 return NF_ACCEPT;
96
97 switch (ctinfo) {
98 case IP_CT_RELATED:
99 case IP_CT_RELATED_REPLY:
100 nexthdr = ipv6_hdr(skb)->nexthdr;
101 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
102 &nexthdr, &frag_off);
103
104 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
105 if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
106 ops->hooknum,
107 hdrlen))
108 return NF_DROP;
109 else
110 return NF_ACCEPT;
111 }
112 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
113 case IP_CT_NEW:
114 /* Seen it before? This can happen for loopback, retrans,
115 * or local packets.
116 */
117 if (!nf_nat_initialized(ct, maniptype)) {
118 unsigned int ret;
119
120 ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct);
121 if (ret != NF_ACCEPT)
122 return ret;
123 } else {
124 pr_debug("Already setup manip %s for ct %p\n",
125 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
126 ct);
127 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
128 goto oif_changed;
129 }
130 break;
131
132 default:
133 /* ESTABLISHED */
134 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
135 ctinfo == IP_CT_ESTABLISHED_REPLY);
136 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
137 goto oif_changed;
138 }
139
140 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
141
142oif_changed:
143 nf_ct_kill_acct(ct, ctinfo, skb);
144 return NF_DROP;
145} 51}
146 52
147static unsigned int 53static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops,
148nf_nat_ipv6_in(const struct nf_hook_ops *ops, 54 struct sk_buff *skb,
149 struct sk_buff *skb, 55 const struct net_device *in,
150 const struct net_device *in, 56 const struct net_device *out,
151 const struct net_device *out, 57 int (*okfn)(struct sk_buff *))
152 int (*okfn)(struct sk_buff *))
153{ 58{
154 unsigned int ret; 59 return nf_nat_ipv6_in(ops, skb, in, out, ip6table_nat_do_chain);
155 struct in6_addr daddr = ipv6_hdr(skb)->daddr;
156
157 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
158 if (ret != NF_DROP && ret != NF_STOLEN &&
159 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
160 skb_dst_drop(skb);
161
162 return ret;
163} 60}
164 61
165static unsigned int 62static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops,
166nf_nat_ipv6_out(const struct nf_hook_ops *ops, 63 struct sk_buff *skb,
167 struct sk_buff *skb, 64 const struct net_device *in,
168 const struct net_device *in, 65 const struct net_device *out,
169 const struct net_device *out, 66 int (*okfn)(struct sk_buff *))
170 int (*okfn)(struct sk_buff *))
171{ 67{
172#ifdef CONFIG_XFRM 68 return nf_nat_ipv6_out(ops, skb, in, out, ip6table_nat_do_chain);
173 const struct nf_conn *ct;
174 enum ip_conntrack_info ctinfo;
175 int err;
176#endif
177 unsigned int ret;
178
179 /* root is playing with raw sockets. */
180 if (skb->len < sizeof(struct ipv6hdr))
181 return NF_ACCEPT;
182
183 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
184#ifdef CONFIG_XFRM
185 if (ret != NF_DROP && ret != NF_STOLEN &&
186 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
187 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
188 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
189
190 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
191 &ct->tuplehash[!dir].tuple.dst.u3) ||
192 (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
193 ct->tuplehash[dir].tuple.src.u.all !=
194 ct->tuplehash[!dir].tuple.dst.u.all)) {
195 err = nf_xfrm_me_harder(skb, AF_INET6);
196 if (err < 0)
197 ret = NF_DROP_ERR(err);
198 }
199 }
200#endif
201 return ret;
202} 69}
203 70
204static unsigned int 71static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops,
205nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, 72 struct sk_buff *skb,
206 struct sk_buff *skb, 73 const struct net_device *in,
207 const struct net_device *in, 74 const struct net_device *out,
208 const struct net_device *out, 75 int (*okfn)(struct sk_buff *))
209 int (*okfn)(struct sk_buff *))
210{ 76{
211 const struct nf_conn *ct; 77 return nf_nat_ipv6_local_fn(ops, skb, in, out, ip6table_nat_do_chain);
212 enum ip_conntrack_info ctinfo;
213 unsigned int ret;
214 int err;
215
216 /* root is playing with raw sockets. */
217 if (skb->len < sizeof(struct ipv6hdr))
218 return NF_ACCEPT;
219
220 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
221 if (ret != NF_DROP && ret != NF_STOLEN &&
222 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
223 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
224
225 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
226 &ct->tuplehash[!dir].tuple.src.u3)) {
227 err = ip6_route_me_harder(skb);
228 if (err < 0)
229 ret = NF_DROP_ERR(err);
230 }
231#ifdef CONFIG_XFRM
232 else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
233 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
234 ct->tuplehash[dir].tuple.dst.u.all !=
235 ct->tuplehash[!dir].tuple.src.u.all) {
236 err = nf_xfrm_me_harder(skb, AF_INET6);
237 if (err < 0)
238 ret = NF_DROP_ERR(err);
239 }
240#endif
241 }
242 return ret;
243} 78}
244 79
245static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { 80static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
246 /* Before packet filtering, change destination */ 81 /* Before packet filtering, change destination */
247 { 82 {
248 .hook = nf_nat_ipv6_in, 83 .hook = ip6table_nat_in,
249 .owner = THIS_MODULE, 84 .owner = THIS_MODULE,
250 .pf = NFPROTO_IPV6, 85 .pf = NFPROTO_IPV6,
251 .hooknum = NF_INET_PRE_ROUTING, 86 .hooknum = NF_INET_PRE_ROUTING,
@@ -253,7 +88,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
253 }, 88 },
254 /* After packet filtering, change source */ 89 /* After packet filtering, change source */
255 { 90 {
256 .hook = nf_nat_ipv6_out, 91 .hook = ip6table_nat_out,
257 .owner = THIS_MODULE, 92 .owner = THIS_MODULE,
258 .pf = NFPROTO_IPV6, 93 .pf = NFPROTO_IPV6,
259 .hooknum = NF_INET_POST_ROUTING, 94 .hooknum = NF_INET_POST_ROUTING,
@@ -261,7 +96,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
261 }, 96 },
262 /* Before packet filtering, change destination */ 97 /* Before packet filtering, change destination */
263 { 98 {
264 .hook = nf_nat_ipv6_local_fn, 99 .hook = ip6table_nat_local_fn,
265 .owner = THIS_MODULE, 100 .owner = THIS_MODULE,
266 .pf = NFPROTO_IPV6, 101 .pf = NFPROTO_IPV6,
267 .hooknum = NF_INET_LOCAL_OUT, 102 .hooknum = NF_INET_LOCAL_OUT,
@@ -269,7 +104,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = {
269 }, 104 },
270 /* After packet filtering, change source */ 105 /* After packet filtering, change source */
271 { 106 {
272 .hook = nf_nat_ipv6_fn, 107 .hook = ip6table_nat_fn,
273 .owner = THIS_MODULE, 108 .owner = THIS_MODULE,
274 .pf = NFPROTO_IPV6, 109 .pf = NFPROTO_IPV6,
275 .hooknum = NF_INET_LOCAL_IN, 110 .hooknum = NF_INET_LOCAL_IN,
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
index fc8e49b2ff3e..c5812e1c1ffb 100644
--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
@@ -261,6 +261,205 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
261} 261}
262EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); 262EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation);
263 263
264unsigned int
265nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
266 const struct net_device *in, const struct net_device *out,
267 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
268 struct sk_buff *skb,
269 const struct net_device *in,
270 const struct net_device *out,
271 struct nf_conn *ct))
272{
273 struct nf_conn *ct;
274 enum ip_conntrack_info ctinfo;
275 struct nf_conn_nat *nat;
276 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
277 __be16 frag_off;
278 int hdrlen;
279 u8 nexthdr;
280
281 ct = nf_ct_get(skb, &ctinfo);
282 /* Can't track? It's not due to stress, or conntrack would
283 * have dropped it. Hence it's the user's responsibilty to
284 * packet filter it out, or implement conntrack/NAT for that
285 * protocol. 8) --RR
286 */
287 if (!ct)
288 return NF_ACCEPT;
289
290 /* Don't try to NAT if this packet is not conntracked */
291 if (nf_ct_is_untracked(ct))
292 return NF_ACCEPT;
293
294 nat = nf_ct_nat_ext_add(ct);
295 if (nat == NULL)
296 return NF_ACCEPT;
297
298 switch (ctinfo) {
299 case IP_CT_RELATED:
300 case IP_CT_RELATED_REPLY:
301 nexthdr = ipv6_hdr(skb)->nexthdr;
302 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
303 &nexthdr, &frag_off);
304
305 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
306 if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
307 ops->hooknum,
308 hdrlen))
309 return NF_DROP;
310 else
311 return NF_ACCEPT;
312 }
313 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
314 case IP_CT_NEW:
315 /* Seen it before? This can happen for loopback, retrans,
316 * or local packets.
317 */
318 if (!nf_nat_initialized(ct, maniptype)) {
319 unsigned int ret;
320
321 ret = do_chain(ops, skb, in, out, ct);
322 if (ret != NF_ACCEPT)
323 return ret;
324
325 if (nf_nat_initialized(ct, HOOK2MANIP(ops->hooknum)))
326 break;
327
328 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
329 if (ret != NF_ACCEPT)
330 return ret;
331 } else {
332 pr_debug("Already setup manip %s for ct %p\n",
333 maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
334 ct);
335 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
336 goto oif_changed;
337 }
338 break;
339
340 default:
341 /* ESTABLISHED */
342 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
343 ctinfo == IP_CT_ESTABLISHED_REPLY);
344 if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out))
345 goto oif_changed;
346 }
347
348 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
349
350oif_changed:
351 nf_ct_kill_acct(ct, ctinfo, skb);
352 return NF_DROP;
353}
354EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn);
355
356unsigned int
357nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb,
358 const struct net_device *in, const struct net_device *out,
359 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
360 struct sk_buff *skb,
361 const struct net_device *in,
362 const struct net_device *out,
363 struct nf_conn *ct))
364{
365 unsigned int ret;
366 struct in6_addr daddr = ipv6_hdr(skb)->daddr;
367
368 ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain);
369 if (ret != NF_DROP && ret != NF_STOLEN &&
370 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
371 skb_dst_drop(skb);
372
373 return ret;
374}
375EXPORT_SYMBOL_GPL(nf_nat_ipv6_in);
376
377unsigned int
378nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb,
379 const struct net_device *in, const struct net_device *out,
380 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
381 struct sk_buff *skb,
382 const struct net_device *in,
383 const struct net_device *out,
384 struct nf_conn *ct))
385{
386#ifdef CONFIG_XFRM
387 const struct nf_conn *ct;
388 enum ip_conntrack_info ctinfo;
389 int err;
390#endif
391 unsigned int ret;
392
393 /* root is playing with raw sockets. */
394 if (skb->len < sizeof(struct ipv6hdr))
395 return NF_ACCEPT;
396
397 ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain);
398#ifdef CONFIG_XFRM
399 if (ret != NF_DROP && ret != NF_STOLEN &&
400 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
401 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
402 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
403
404 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
405 &ct->tuplehash[!dir].tuple.dst.u3) ||
406 (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
407 ct->tuplehash[dir].tuple.src.u.all !=
408 ct->tuplehash[!dir].tuple.dst.u.all)) {
409 err = nf_xfrm_me_harder(skb, AF_INET6);
410 if (err < 0)
411 ret = NF_DROP_ERR(err);
412 }
413 }
414#endif
415 return ret;
416}
417EXPORT_SYMBOL_GPL(nf_nat_ipv6_out);
418
419unsigned int
420nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
421 const struct net_device *in, const struct net_device *out,
422 unsigned int (*do_chain)(const struct nf_hook_ops *ops,
423 struct sk_buff *skb,
424 const struct net_device *in,
425 const struct net_device *out,
426 struct nf_conn *ct))
427{
428 const struct nf_conn *ct;
429 enum ip_conntrack_info ctinfo;
430 unsigned int ret;
431 int err;
432
433 /* root is playing with raw sockets. */
434 if (skb->len < sizeof(struct ipv6hdr))
435 return NF_ACCEPT;
436
437 ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain);
438 if (ret != NF_DROP && ret != NF_STOLEN &&
439 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
440 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
441
442 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
443 &ct->tuplehash[!dir].tuple.src.u3)) {
444 err = ip6_route_me_harder(skb);
445 if (err < 0)
446 ret = NF_DROP_ERR(err);
447 }
448#ifdef CONFIG_XFRM
449 else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
450 ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
451 ct->tuplehash[dir].tuple.dst.u.all !=
452 ct->tuplehash[!dir].tuple.src.u.all) {
453 err = nf_xfrm_me_harder(skb, AF_INET6);
454 if (err < 0)
455 ret = NF_DROP_ERR(err);
456 }
457#endif
458 }
459 return ret;
460}
461EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn);
462
264static int __init nf_nat_l3proto_ipv6_init(void) 463static int __init nf_nat_l3proto_ipv6_init(void)
265{ 464{
266 int err; 465 int err;
diff --git a/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c
new file mode 100644
index 000000000000..7745609665cd
--- /dev/null
+++ b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c
@@ -0,0 +1,120 @@
1/*
2 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
9 * NAT funded by Astaro.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/atomic.h>
15#include <linux/netdevice.h>
16#include <linux/ipv6.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter_ipv6.h>
19#include <net/netfilter/nf_nat.h>
20#include <net/addrconf.h>
21#include <net/ipv6.h>
22#include <net/netfilter/ipv6/nf_nat_masquerade.h>
23
24unsigned int
25nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range,
26 const struct net_device *out)
27{
28 enum ip_conntrack_info ctinfo;
29 struct in6_addr src;
30 struct nf_conn *ct;
31 struct nf_nat_range newrange;
32
33 ct = nf_ct_get(skb, &ctinfo);
34 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
35 ctinfo == IP_CT_RELATED_REPLY));
36
37 if (ipv6_dev_get_saddr(dev_net(out), out,
38 &ipv6_hdr(skb)->daddr, 0, &src) < 0)
39 return NF_DROP;
40
41 nfct_nat(ct)->masq_index = out->ifindex;
42
43 newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
44 newrange.min_addr.in6 = src;
45 newrange.max_addr.in6 = src;
46 newrange.min_proto = range->min_proto;
47 newrange.max_proto = range->max_proto;
48
49 return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
50}
51EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6);
52
53static int device_cmp(struct nf_conn *ct, void *ifindex)
54{
55 const struct nf_conn_nat *nat = nfct_nat(ct);
56
57 if (!nat)
58 return 0;
59 if (nf_ct_l3num(ct) != NFPROTO_IPV6)
60 return 0;
61 return nat->masq_index == (int)(long)ifindex;
62}
63
64static int masq_device_event(struct notifier_block *this,
65 unsigned long event, void *ptr)
66{
67 const struct net_device *dev = netdev_notifier_info_to_dev(ptr);
68 struct net *net = dev_net(dev);
69
70 if (event == NETDEV_DOWN)
71 nf_ct_iterate_cleanup(net, device_cmp,
72 (void *)(long)dev->ifindex, 0, 0);
73
74 return NOTIFY_DONE;
75}
76
77static struct notifier_block masq_dev_notifier = {
78 .notifier_call = masq_device_event,
79};
80
81static int masq_inet_event(struct notifier_block *this,
82 unsigned long event, void *ptr)
83{
84 struct inet6_ifaddr *ifa = ptr;
85 struct netdev_notifier_info info;
86
87 netdev_notifier_info_init(&info, ifa->idev->dev);
88 return masq_device_event(this, event, &info);
89}
90
91static struct notifier_block masq_inet_notifier = {
92 .notifier_call = masq_inet_event,
93};
94
95static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0);
96
97void nf_nat_masquerade_ipv6_register_notifier(void)
98{
99 /* check if the notifier is already set */
100 if (atomic_inc_return(&masquerade_notifier_refcount) > 1)
101 return;
102
103 register_netdevice_notifier(&masq_dev_notifier);
104 register_inet6addr_notifier(&masq_inet_notifier);
105}
106EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier);
107
108void nf_nat_masquerade_ipv6_unregister_notifier(void)
109{
110 /* check if the notifier still has clients */
111 if (atomic_dec_return(&masquerade_notifier_refcount) > 0)
112 return;
113
114 unregister_inet6addr_notifier(&masq_inet_notifier);
115 unregister_netdevice_notifier(&masq_dev_notifier);
116}
117EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier);
118
119MODULE_LICENSE("GPL");
120MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
index d189fcb437fe..1c4b75dd425b 100644
--- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c
+++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
@@ -24,144 +24,53 @@
24#include <net/netfilter/nf_nat_l3proto.h> 24#include <net/netfilter/nf_nat_l3proto.h>
25#include <net/ipv6.h> 25#include <net/ipv6.h>
26 26
27/* 27static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops,
28 * IPv6 NAT chains 28 struct sk_buff *skb,
29 */ 29 const struct net_device *in,
30 30 const struct net_device *out,
31static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, 31 struct nf_conn *ct)
32 struct sk_buff *skb,
33 const struct net_device *in,
34 const struct net_device *out,
35 int (*okfn)(struct sk_buff *))
36{ 32{
37 enum ip_conntrack_info ctinfo;
38 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
39 struct nf_conn_nat *nat;
40 enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
41 __be16 frag_off;
42 int hdrlen;
43 u8 nexthdr;
44 struct nft_pktinfo pkt; 33 struct nft_pktinfo pkt;
45 unsigned int ret;
46
47 if (ct == NULL || nf_ct_is_untracked(ct))
48 return NF_ACCEPT;
49
50 nat = nf_ct_nat_ext_add(ct);
51 if (nat == NULL)
52 return NF_ACCEPT;
53
54 switch (ctinfo) {
55 case IP_CT_RELATED:
56 case IP_CT_RELATED + IP_CT_IS_REPLY:
57 nexthdr = ipv6_hdr(skb)->nexthdr;
58 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
59 &nexthdr, &frag_off);
60
61 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
62 if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
63 ops->hooknum,
64 hdrlen))
65 return NF_DROP;
66 else
67 return NF_ACCEPT;
68 }
69 /* Fall through */
70 case IP_CT_NEW:
71 if (nf_nat_initialized(ct, maniptype))
72 break;
73
74 nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
75 34
76 ret = nft_do_chain(&pkt, ops); 35 nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
77 if (ret != NF_ACCEPT)
78 return ret;
79 if (!nf_nat_initialized(ct, maniptype)) {
80 ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
81 if (ret != NF_ACCEPT)
82 return ret;
83 }
84 default:
85 break;
86 }
87 36
88 return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); 37 return nft_do_chain(&pkt, ops);
89} 38}
90 39
91static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops, 40static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops,
92 struct sk_buff *skb, 41 struct sk_buff *skb,
93 const struct net_device *in, 42 const struct net_device *in,
94 const struct net_device *out, 43 const struct net_device *out,
95 int (*okfn)(struct sk_buff *)) 44 int (*okfn)(struct sk_buff *))
96{ 45{
97 struct in6_addr daddr = ipv6_hdr(skb)->daddr; 46 return nf_nat_ipv6_fn(ops, skb, in, out, nft_nat_do_chain);
98 unsigned int ret;
99
100 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
101 if (ret != NF_DROP && ret != NF_STOLEN &&
102 ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
103 skb_dst_drop(skb);
104
105 return ret;
106} 47}
107 48
108static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops, 49static unsigned int nft_nat_ipv6_in(const struct nf_hook_ops *ops,
109 struct sk_buff *skb, 50 struct sk_buff *skb,
110 const struct net_device *in, 51 const struct net_device *in,
111 const struct net_device *out, 52 const struct net_device *out,
112 int (*okfn)(struct sk_buff *)) 53 int (*okfn)(struct sk_buff *))
113{ 54{
114 enum ip_conntrack_info ctinfo __maybe_unused; 55 return nf_nat_ipv6_in(ops, skb, in, out, nft_nat_do_chain);
115 const struct nf_conn *ct __maybe_unused;
116 unsigned int ret;
117
118 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
119#ifdef CONFIG_XFRM
120 if (ret != NF_DROP && ret != NF_STOLEN &&
121 !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
122 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
123 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
124
125 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
126 &ct->tuplehash[!dir].tuple.dst.u3) ||
127 (ct->tuplehash[dir].tuple.src.u.all !=
128 ct->tuplehash[!dir].tuple.dst.u.all))
129 if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
130 ret = NF_DROP;
131 }
132#endif
133 return ret;
134} 56}
135 57
136static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, 58static unsigned int nft_nat_ipv6_out(const struct nf_hook_ops *ops,
137 struct sk_buff *skb, 59 struct sk_buff *skb,
138 const struct net_device *in, 60 const struct net_device *in,
139 const struct net_device *out, 61 const struct net_device *out,
140 int (*okfn)(struct sk_buff *)) 62 int (*okfn)(struct sk_buff *))
141{ 63{
142 enum ip_conntrack_info ctinfo; 64 return nf_nat_ipv6_out(ops, skb, in, out, nft_nat_do_chain);
143 const struct nf_conn *ct; 65}
144 unsigned int ret;
145
146 ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
147 if (ret != NF_DROP && ret != NF_STOLEN &&
148 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
149 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
150 66
151 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, 67static unsigned int nft_nat_ipv6_local_fn(const struct nf_hook_ops *ops,
152 &ct->tuplehash[!dir].tuple.src.u3)) { 68 struct sk_buff *skb,
153 if (ip6_route_me_harder(skb)) 69 const struct net_device *in,
154 ret = NF_DROP; 70 const struct net_device *out,
155 } 71 int (*okfn)(struct sk_buff *))
156#ifdef CONFIG_XFRM 72{
157 else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 73 return nf_nat_ipv6_local_fn(ops, skb, in, out, nft_nat_do_chain);
158 ct->tuplehash[dir].tuple.dst.u.all !=
159 ct->tuplehash[!dir].tuple.src.u.all)
160 if (nf_xfrm_me_harder(skb, AF_INET6))
161 ret = NF_DROP;
162#endif
163 }
164 return ret;
165} 74}
166 75
167static const struct nf_chain_type nft_chain_nat_ipv6 = { 76static const struct nf_chain_type nft_chain_nat_ipv6 = {
@@ -174,10 +83,10 @@ static const struct nf_chain_type nft_chain_nat_ipv6 = {
174 (1 << NF_INET_LOCAL_OUT) | 83 (1 << NF_INET_LOCAL_OUT) |
175 (1 << NF_INET_LOCAL_IN), 84 (1 << NF_INET_LOCAL_IN),
176 .hooks = { 85 .hooks = {
177 [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, 86 [NF_INET_PRE_ROUTING] = nft_nat_ipv6_in,
178 [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, 87 [NF_INET_POST_ROUTING] = nft_nat_ipv6_out,
179 [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, 88 [NF_INET_LOCAL_OUT] = nft_nat_ipv6_local_fn,
180 [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, 89 [NF_INET_LOCAL_IN] = nft_nat_ipv6_fn,
181 }, 90 },
182}; 91};
183 92
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c
new file mode 100644
index 000000000000..4e51334ef6b7
--- /dev/null
+++ b/net/ipv6/netfilter/nft_masq_ipv6.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/netlink.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nft_masq.h>
18#include <net/netfilter/ipv6/nf_nat_masquerade.h>
19
20static void nft_masq_ipv6_eval(const struct nft_expr *expr,
21 struct nft_data data[NFT_REG_MAX + 1],
22 const struct nft_pktinfo *pkt)
23{
24 struct nft_masq *priv = nft_expr_priv(expr);
25 struct nf_nat_range range;
26 unsigned int verdict;
27
28 range.flags = priv->flags;
29
30 verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
31
32 data[NFT_REG_VERDICT].verdict = verdict;
33}
34
35static int nft_masq_ipv6_init(const struct nft_ctx *ctx,
36 const struct nft_expr *expr,
37 const struct nlattr * const tb[])
38{
39 int err;
40
41 err = nft_masq_init(ctx, expr, tb);
42 if (err < 0)
43 return err;
44
45 nf_nat_masquerade_ipv6_register_notifier();
46 return 0;
47}
48
49static void nft_masq_ipv6_destroy(const struct nft_ctx *ctx,
50 const struct nft_expr *expr)
51{
52 nf_nat_masquerade_ipv6_unregister_notifier();
53}
54
55static struct nft_expr_type nft_masq_ipv6_type;
56static const struct nft_expr_ops nft_masq_ipv6_ops = {
57 .type = &nft_masq_ipv6_type,
58 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
59 .eval = nft_masq_ipv6_eval,
60 .init = nft_masq_ipv6_init,
61 .destroy = nft_masq_ipv6_destroy,
62 .dump = nft_masq_dump,
63};
64
65static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
66 .family = NFPROTO_IPV6,
67 .name = "masq",
68 .ops = &nft_masq_ipv6_ops,
69 .policy = nft_masq_policy,
70 .maxattr = NFTA_MASQ_MAX,
71 .owner = THIS_MODULE,
72};
73
74static int __init nft_masq_ipv6_module_init(void)
75{
76 return nft_register_expr(&nft_masq_ipv6_type);
77}
78
79static void __exit nft_masq_ipv6_module_exit(void)
80{
81 nft_unregister_expr(&nft_masq_ipv6_type);
82}
83
84module_init(nft_masq_ipv6_module_init);
85module_exit(nft_masq_ipv6_module_exit);
86
87MODULE_LICENSE("GPL");
88MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
89MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "masq");
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index b5c1d3aadb41..608d18986923 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -496,6 +496,15 @@ config NFT_LIMIT
496 This option adds the "limit" expression that you can use to 496 This option adds the "limit" expression that you can use to
497 ratelimit rule matchings. 497 ratelimit rule matchings.
498 498
499config NFT_MASQ
500 depends on NF_TABLES
501 depends on NF_CONNTRACK
502 depends on NF_NAT
503 tristate "Netfilter nf_tables masquerade support"
504 help
505 This option adds the "masquerade" expression that you can use
506 to perform NAT in the masquerade flavour.
507
499config NFT_NAT 508config NFT_NAT
500 depends on NF_TABLES 509 depends on NF_TABLES
501 depends on NF_CONNTRACK 510 depends on NF_CONNTRACK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index fad5fdba34e5..a9571be3f791 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o
87obj-$(CONFIG_NFT_HASH) += nft_hash.o 87obj-$(CONFIG_NFT_HASH) += nft_hash.o
88obj-$(CONFIG_NFT_COUNTER) += nft_counter.o 88obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
89obj-$(CONFIG_NFT_LOG) += nft_log.o 89obj-$(CONFIG_NFT_LOG) += nft_log.o
90obj-$(CONFIG_NFT_MASQ) += nft_masq.o
90 91
91# generic X tables 92# generic X tables
92obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o 93obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index 6f1f9f494808..dafdb39ef042 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -112,7 +112,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
112{ 112{
113 struct bitmap_ip *map = set->data; 113 struct bitmap_ip *map = set->data;
114 ipset_adtfn adtfn = set->variant->adt[adt]; 114 ipset_adtfn adtfn = set->variant->adt[adt];
115 struct bitmap_ip_adt_elem e = { }; 115 struct bitmap_ip_adt_elem e = { .id = 0 };
116 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 116 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
117 u32 ip; 117 u32 ip;
118 118
@@ -132,7 +132,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
132 struct bitmap_ip *map = set->data; 132 struct bitmap_ip *map = set->data;
133 ipset_adtfn adtfn = set->variant->adt[adt]; 133 ipset_adtfn adtfn = set->variant->adt[adt];
134 u32 ip = 0, ip_to = 0; 134 u32 ip = 0, ip_to = 0;
135 struct bitmap_ip_adt_elem e = { }; 135 struct bitmap_ip_adt_elem e = { .id = 0 };
136 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 136 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
137 int ret = 0; 137 int ret = 0;
138 138
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 740eabededd9..dbad505e79e3 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -203,7 +203,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
203{ 203{
204 struct bitmap_ipmac *map = set->data; 204 struct bitmap_ipmac *map = set->data;
205 ipset_adtfn adtfn = set->variant->adt[adt]; 205 ipset_adtfn adtfn = set->variant->adt[adt];
206 struct bitmap_ipmac_adt_elem e = {}; 206 struct bitmap_ipmac_adt_elem e = { .id = 0 };
207 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 207 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
208 u32 ip; 208 u32 ip;
209 209
@@ -232,7 +232,7 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
232{ 232{
233 const struct bitmap_ipmac *map = set->data; 233 const struct bitmap_ipmac *map = set->data;
234 ipset_adtfn adtfn = set->variant->adt[adt]; 234 ipset_adtfn adtfn = set->variant->adt[adt];
235 struct bitmap_ipmac_adt_elem e = {}; 235 struct bitmap_ipmac_adt_elem e = { .id = 0 };
236 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 236 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
237 u32 ip = 0; 237 u32 ip = 0;
238 int ret = 0; 238 int ret = 0;
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index cf99676e69f8..a4b65ae1986c 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -104,7 +104,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
104{ 104{
105 struct bitmap_port *map = set->data; 105 struct bitmap_port *map = set->data;
106 ipset_adtfn adtfn = set->variant->adt[adt]; 106 ipset_adtfn adtfn = set->variant->adt[adt];
107 struct bitmap_port_adt_elem e = {}; 107 struct bitmap_port_adt_elem e = { .id = 0 };
108 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 108 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
109 __be16 __port; 109 __be16 __port;
110 u16 port = 0; 110 u16 port = 0;
@@ -129,7 +129,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
129{ 129{
130 struct bitmap_port *map = set->data; 130 struct bitmap_port *map = set->data;
131 ipset_adtfn adtfn = set->variant->adt[adt]; 131 ipset_adtfn adtfn = set->variant->adt[adt];
132 struct bitmap_port_adt_elem e = {}; 132 struct bitmap_port_adt_elem e = { .id = 0 };
133 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 133 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
134 u32 port; /* wraparound */ 134 u32 port; /* wraparound */
135 u16 port_to; 135 u16 port_to;
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 80f49dfba555..8a38890cbe5e 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -1093,7 +1093,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
1093 if (tb[IPSET_ATTR_MARKMASK]) { 1093 if (tb[IPSET_ATTR_MARKMASK]) {
1094 markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK])); 1094 markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK]));
1095 1095
1096 if ((markmask > 4294967295u) || markmask == 0) 1096 if (markmask == 0)
1097 return -IPSET_ERR_INVALID_MARKMASK; 1097 return -IPSET_ERR_INVALID_MARKMASK;
1098 } 1098 }
1099#endif 1099#endif
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index dd40607f878e..e52739938533 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -84,7 +84,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
84{ 84{
85 const struct hash_ip *h = set->data; 85 const struct hash_ip *h = set->data;
86 ipset_adtfn adtfn = set->variant->adt[adt]; 86 ipset_adtfn adtfn = set->variant->adt[adt];
87 struct hash_ip4_elem e = {}; 87 struct hash_ip4_elem e = { 0 };
88 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 88 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
89 __be32 ip; 89 __be32 ip;
90 90
@@ -103,7 +103,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
103{ 103{
104 const struct hash_ip *h = set->data; 104 const struct hash_ip *h = set->data;
105 ipset_adtfn adtfn = set->variant->adt[adt]; 105 ipset_adtfn adtfn = set->variant->adt[adt];
106 struct hash_ip4_elem e = {}; 106 struct hash_ip4_elem e = { 0 };
107 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 107 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
108 u32 ip = 0, ip_to = 0, hosts; 108 u32 ip = 0, ip_to = 0, hosts;
109 int ret = 0; 109 int ret = 0;
@@ -222,7 +222,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
222{ 222{
223 const struct hash_ip *h = set->data; 223 const struct hash_ip *h = set->data;
224 ipset_adtfn adtfn = set->variant->adt[adt]; 224 ipset_adtfn adtfn = set->variant->adt[adt];
225 struct hash_ip6_elem e = {}; 225 struct hash_ip6_elem e = { { .all = { 0 } } };
226 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 226 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
227 227
228 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 228 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
@@ -239,7 +239,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
239{ 239{
240 const struct hash_ip *h = set->data; 240 const struct hash_ip *h = set->data;
241 ipset_adtfn adtfn = set->variant->adt[adt]; 241 ipset_adtfn adtfn = set->variant->adt[adt];
242 struct hash_ip6_elem e = {}; 242 struct hash_ip6_elem e = { { .all = { 0 } } };
243 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 243 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
244 int ret; 244 int ret;
245 245
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 7597b82a8b03..f37a5ae8a5e0 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -94,7 +94,7 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
94 enum ipset_adt adt, struct ip_set_adt_opt *opt) 94 enum ipset_adt adt, struct ip_set_adt_opt *opt)
95{ 95{
96 ipset_adtfn adtfn = set->variant->adt[adt]; 96 ipset_adtfn adtfn = set->variant->adt[adt];
97 struct hash_ipport4_elem e = { }; 97 struct hash_ipport4_elem e = { .ip = 0 };
98 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 98 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
99 99
100 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 100 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
@@ -111,7 +111,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
111{ 111{
112 const struct hash_ipport *h = set->data; 112 const struct hash_ipport *h = set->data;
113 ipset_adtfn adtfn = set->variant->adt[adt]; 113 ipset_adtfn adtfn = set->variant->adt[adt];
114 struct hash_ipport4_elem e = { }; 114 struct hash_ipport4_elem e = { .ip = 0 };
115 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 115 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
116 u32 ip, ip_to = 0, p = 0, port, port_to; 116 u32 ip, ip_to = 0, p = 0, port, port_to;
117 bool with_ports = false; 117 bool with_ports = false;
@@ -258,7 +258,7 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
258 enum ipset_adt adt, struct ip_set_adt_opt *opt) 258 enum ipset_adt adt, struct ip_set_adt_opt *opt)
259{ 259{
260 ipset_adtfn adtfn = set->variant->adt[adt]; 260 ipset_adtfn adtfn = set->variant->adt[adt];
261 struct hash_ipport6_elem e = { }; 261 struct hash_ipport6_elem e = { .ip = { .all = { 0 } } };
262 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 262 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
263 263
264 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 264 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
@@ -275,7 +275,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
275{ 275{
276 const struct hash_ipport *h = set->data; 276 const struct hash_ipport *h = set->data;
277 ipset_adtfn adtfn = set->variant->adt[adt]; 277 ipset_adtfn adtfn = set->variant->adt[adt];
278 struct hash_ipport6_elem e = { }; 278 struct hash_ipport6_elem e = { .ip = { .all = { 0 } } };
279 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 279 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
280 u32 port, port_to; 280 u32 port, port_to;
281 bool with_ports = false; 281 bool with_ports = false;
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 672655ffd573..41ef00eda874 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -95,7 +95,7 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
95 enum ipset_adt adt, struct ip_set_adt_opt *opt) 95 enum ipset_adt adt, struct ip_set_adt_opt *opt)
96{ 96{
97 ipset_adtfn adtfn = set->variant->adt[adt]; 97 ipset_adtfn adtfn = set->variant->adt[adt];
98 struct hash_ipportip4_elem e = { }; 98 struct hash_ipportip4_elem e = { .ip = 0 };
99 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 99 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
100 100
101 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 101 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
@@ -113,7 +113,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
113{ 113{
114 const struct hash_ipportip *h = set->data; 114 const struct hash_ipportip *h = set->data;
115 ipset_adtfn adtfn = set->variant->adt[adt]; 115 ipset_adtfn adtfn = set->variant->adt[adt];
116 struct hash_ipportip4_elem e = { }; 116 struct hash_ipportip4_elem e = { .ip = 0 };
117 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 117 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
118 u32 ip, ip_to = 0, p = 0, port, port_to; 118 u32 ip, ip_to = 0, p = 0, port, port_to;
119 bool with_ports = false; 119 bool with_ports = false;
@@ -265,7 +265,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
265 enum ipset_adt adt, struct ip_set_adt_opt *opt) 265 enum ipset_adt adt, struct ip_set_adt_opt *opt)
266{ 266{
267 ipset_adtfn adtfn = set->variant->adt[adt]; 267 ipset_adtfn adtfn = set->variant->adt[adt];
268 struct hash_ipportip6_elem e = { }; 268 struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } };
269 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 269 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
270 270
271 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 271 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
@@ -283,7 +283,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
283{ 283{
284 const struct hash_ipportip *h = set->data; 284 const struct hash_ipportip *h = set->data;
285 ipset_adtfn adtfn = set->variant->adt[adt]; 285 ipset_adtfn adtfn = set->variant->adt[adt];
286 struct hash_ipportip6_elem e = { }; 286 struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } };
287 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 287 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
288 u32 port, port_to; 288 u32 port, port_to;
289 bool with_ports = false; 289 bool with_ports = false;
diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
index 3e99987e4bf2..96b131366e7b 100644
--- a/net/netfilter/ipset/ip_set_hash_netnet.c
+++ b/net/netfilter/ipset/ip_set_hash_netnet.c
@@ -203,7 +203,7 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
203 flags |= (IPSET_FLAG_NOMATCH << 16); 203 flags |= (IPSET_FLAG_NOMATCH << 16);
204 } 204 }
205 205
206 if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] && 206 if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] ||
207 tb[IPSET_ATTR_IP2_TO])) { 207 tb[IPSET_ATTR_IP2_TO])) {
208 e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); 208 e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
209 e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); 209 e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1]));
@@ -219,9 +219,10 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
219 return ret; 219 return ret;
220 if (ip_to < ip) 220 if (ip_to < ip)
221 swap(ip, ip_to); 221 swap(ip, ip_to);
222 if (ip + UINT_MAX == ip_to) 222 if (unlikely(ip + UINT_MAX == ip_to))
223 return -IPSET_ERR_HASH_RANGE; 223 return -IPSET_ERR_HASH_RANGE;
224 } 224 } else
225 ip_set_mask_from_to(ip, ip_to, e.cidr[0]);
225 226
226 ip2_to = ip2_from; 227 ip2_to = ip2_from;
227 if (tb[IPSET_ATTR_IP2_TO]) { 228 if (tb[IPSET_ATTR_IP2_TO]) {
@@ -230,10 +231,10 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
230 return ret; 231 return ret;
231 if (ip2_to < ip2_from) 232 if (ip2_to < ip2_from)
232 swap(ip2_from, ip2_to); 233 swap(ip2_from, ip2_to);
233 if (ip2_from + UINT_MAX == ip2_to) 234 if (unlikely(ip2_from + UINT_MAX == ip2_to))
234 return -IPSET_ERR_HASH_RANGE; 235 return -IPSET_ERR_HASH_RANGE;
235 236 } else
236 } 237 ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
237 238
238 if (retried) 239 if (retried)
239 ip = ntohl(h->next.ip[0]); 240 ip = ntohl(h->next.ip[0]);
diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
index c0d2ba73f8b2..2f0034347189 100644
--- a/net/netfilter/ipset/ip_set_hash_netportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_netportnet.c
@@ -257,7 +257,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
257 swap(ip, ip_to); 257 swap(ip, ip_to);
258 if (unlikely(ip + UINT_MAX == ip_to)) 258 if (unlikely(ip + UINT_MAX == ip_to))
259 return -IPSET_ERR_HASH_RANGE; 259 return -IPSET_ERR_HASH_RANGE;
260 } 260 } else
261 ip_set_mask_from_to(ip, ip_to, e.cidr[0]);
261 262
262 port_to = port = ntohs(e.port); 263 port_to = port = ntohs(e.port);
263 if (tb[IPSET_ATTR_PORT_TO]) { 264 if (tb[IPSET_ATTR_PORT_TO]) {
@@ -275,7 +276,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
275 swap(ip2_from, ip2_to); 276 swap(ip2_from, ip2_to);
276 if (unlikely(ip2_from + UINT_MAX == ip2_to)) 277 if (unlikely(ip2_from + UINT_MAX == ip2_to))
277 return -IPSET_ERR_HASH_RANGE; 278 return -IPSET_ERR_HASH_RANGE;
278 } 279 } else
280 ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
279 281
280 if (retried) 282 if (retried)
281 ip = ntohl(h->next.ip[0]); 283 ip = ntohl(h->next.ip[0]);
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 3e2317f3cf68..f87adbad6076 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -597,7 +597,9 @@ init_list_set(struct net *net, struct ip_set *set, u32 size)
597 struct set_elem *e; 597 struct set_elem *e;
598 u32 i; 598 u32 i;
599 599
600 map = kzalloc(sizeof(*map) + size * set->dsize, GFP_KERNEL); 600 map = kzalloc(sizeof(*map) +
601 min_t(u32, size, IP_SET_LIST_MAX_SIZE) * set->dsize,
602 GFP_KERNEL);
601 if (!map) 603 if (!map)
602 return false; 604 return false;
603 605
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index fd3f444a4f96..bd2b208ba56c 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2179,29 +2179,41 @@ static int ip_vs_set_timeout(struct net *net, struct ip_vs_timeout_user *u)
2179 return 0; 2179 return 0;
2180} 2180}
2181 2181
2182#define CMDID(cmd) (cmd - IP_VS_BASE_CTL)
2182 2183
2183#define SET_CMDID(cmd) (cmd - IP_VS_BASE_CTL) 2184struct ip_vs_svcdest_user {
2184#define SERVICE_ARG_LEN (sizeof(struct ip_vs_service_user)) 2185 struct ip_vs_service_user s;
2185#define SVCDEST_ARG_LEN (sizeof(struct ip_vs_service_user) + \ 2186 struct ip_vs_dest_user d;
2186 sizeof(struct ip_vs_dest_user))
2187#define TIMEOUT_ARG_LEN (sizeof(struct ip_vs_timeout_user))
2188#define DAEMON_ARG_LEN (sizeof(struct ip_vs_daemon_user))
2189#define MAX_ARG_LEN SVCDEST_ARG_LEN
2190
2191static const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = {
2192 [SET_CMDID(IP_VS_SO_SET_ADD)] = SERVICE_ARG_LEN,
2193 [SET_CMDID(IP_VS_SO_SET_EDIT)] = SERVICE_ARG_LEN,
2194 [SET_CMDID(IP_VS_SO_SET_DEL)] = SERVICE_ARG_LEN,
2195 [SET_CMDID(IP_VS_SO_SET_FLUSH)] = 0,
2196 [SET_CMDID(IP_VS_SO_SET_ADDDEST)] = SVCDEST_ARG_LEN,
2197 [SET_CMDID(IP_VS_SO_SET_DELDEST)] = SVCDEST_ARG_LEN,
2198 [SET_CMDID(IP_VS_SO_SET_EDITDEST)] = SVCDEST_ARG_LEN,
2199 [SET_CMDID(IP_VS_SO_SET_TIMEOUT)] = TIMEOUT_ARG_LEN,
2200 [SET_CMDID(IP_VS_SO_SET_STARTDAEMON)] = DAEMON_ARG_LEN,
2201 [SET_CMDID(IP_VS_SO_SET_STOPDAEMON)] = DAEMON_ARG_LEN,
2202 [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN,
2203}; 2187};
2204 2188
2189static const unsigned char set_arglen[CMDID(IP_VS_SO_SET_MAX) + 1] = {
2190 [CMDID(IP_VS_SO_SET_ADD)] = sizeof(struct ip_vs_service_user),
2191 [CMDID(IP_VS_SO_SET_EDIT)] = sizeof(struct ip_vs_service_user),
2192 [CMDID(IP_VS_SO_SET_DEL)] = sizeof(struct ip_vs_service_user),
2193 [CMDID(IP_VS_SO_SET_ADDDEST)] = sizeof(struct ip_vs_svcdest_user),
2194 [CMDID(IP_VS_SO_SET_DELDEST)] = sizeof(struct ip_vs_svcdest_user),
2195 [CMDID(IP_VS_SO_SET_EDITDEST)] = sizeof(struct ip_vs_svcdest_user),
2196 [CMDID(IP_VS_SO_SET_TIMEOUT)] = sizeof(struct ip_vs_timeout_user),
2197 [CMDID(IP_VS_SO_SET_STARTDAEMON)] = sizeof(struct ip_vs_daemon_user),
2198 [CMDID(IP_VS_SO_SET_STOPDAEMON)] = sizeof(struct ip_vs_daemon_user),
2199 [CMDID(IP_VS_SO_SET_ZERO)] = sizeof(struct ip_vs_service_user),
2200};
2201
2202union ip_vs_set_arglen {
2203 struct ip_vs_service_user field_IP_VS_SO_SET_ADD;
2204 struct ip_vs_service_user field_IP_VS_SO_SET_EDIT;
2205 struct ip_vs_service_user field_IP_VS_SO_SET_DEL;
2206 struct ip_vs_svcdest_user field_IP_VS_SO_SET_ADDDEST;
2207 struct ip_vs_svcdest_user field_IP_VS_SO_SET_DELDEST;
2208 struct ip_vs_svcdest_user field_IP_VS_SO_SET_EDITDEST;
2209 struct ip_vs_timeout_user field_IP_VS_SO_SET_TIMEOUT;
2210 struct ip_vs_daemon_user field_IP_VS_SO_SET_STARTDAEMON;
2211 struct ip_vs_daemon_user field_IP_VS_SO_SET_STOPDAEMON;
2212 struct ip_vs_service_user field_IP_VS_SO_SET_ZERO;
2213};
2214
2215#define MAX_SET_ARGLEN sizeof(union ip_vs_set_arglen)
2216
2205static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc, 2217static void ip_vs_copy_usvc_compat(struct ip_vs_service_user_kern *usvc,
2206 struct ip_vs_service_user *usvc_compat) 2218 struct ip_vs_service_user *usvc_compat)
2207{ 2219{
@@ -2239,7 +2251,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2239{ 2251{
2240 struct net *net = sock_net(sk); 2252 struct net *net = sock_net(sk);
2241 int ret; 2253 int ret;
2242 unsigned char arg[MAX_ARG_LEN]; 2254 unsigned char arg[MAX_SET_ARGLEN];
2243 struct ip_vs_service_user *usvc_compat; 2255 struct ip_vs_service_user *usvc_compat;
2244 struct ip_vs_service_user_kern usvc; 2256 struct ip_vs_service_user_kern usvc;
2245 struct ip_vs_service *svc; 2257 struct ip_vs_service *svc;
@@ -2247,16 +2259,15 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
2247 struct ip_vs_dest_user_kern udest; 2259 struct ip_vs_dest_user_kern udest;
2248 struct netns_ipvs *ipvs = net_ipvs(net); 2260 struct netns_ipvs *ipvs = net_ipvs(net);
2249 2261
2262 BUILD_BUG_ON(sizeof(arg) > 255);
2250 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2263 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2251 return -EPERM; 2264 return -EPERM;
2252 2265
2253 if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_SET_MAX) 2266 if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_SET_MAX)
2254 return -EINVAL; 2267 return -EINVAL;
2255 if (len < 0 || len > MAX_ARG_LEN) 2268 if (len != set_arglen[CMDID(cmd)]) {
2256 return -EINVAL; 2269 IP_VS_DBG(1, "set_ctl: len %u != %u\n",
2257 if (len != set_arglen[SET_CMDID(cmd)]) { 2270 len, set_arglen[CMDID(cmd)]);
2258 pr_err("set_ctl: len %u != %u\n",
2259 len, set_arglen[SET_CMDID(cmd)]);
2260 return -EINVAL; 2271 return -EINVAL;
2261 } 2272 }
2262 2273
@@ -2512,51 +2523,51 @@ __ip_vs_get_timeouts(struct net *net, struct ip_vs_timeout_user *u)
2512#endif 2523#endif
2513} 2524}
2514 2525
2526static const unsigned char get_arglen[CMDID(IP_VS_SO_GET_MAX) + 1] = {
2527 [CMDID(IP_VS_SO_GET_VERSION)] = 64,
2528 [CMDID(IP_VS_SO_GET_INFO)] = sizeof(struct ip_vs_getinfo),
2529 [CMDID(IP_VS_SO_GET_SERVICES)] = sizeof(struct ip_vs_get_services),
2530 [CMDID(IP_VS_SO_GET_SERVICE)] = sizeof(struct ip_vs_service_entry),
2531 [CMDID(IP_VS_SO_GET_DESTS)] = sizeof(struct ip_vs_get_dests),
2532 [CMDID(IP_VS_SO_GET_TIMEOUT)] = sizeof(struct ip_vs_timeout_user),
2533 [CMDID(IP_VS_SO_GET_DAEMON)] = 2 * sizeof(struct ip_vs_daemon_user),
2534};
2515 2535
2516#define GET_CMDID(cmd) (cmd - IP_VS_BASE_CTL) 2536union ip_vs_get_arglen {
2517#define GET_INFO_ARG_LEN (sizeof(struct ip_vs_getinfo)) 2537 char field_IP_VS_SO_GET_VERSION[64];
2518#define GET_SERVICES_ARG_LEN (sizeof(struct ip_vs_get_services)) 2538 struct ip_vs_getinfo field_IP_VS_SO_GET_INFO;
2519#define GET_SERVICE_ARG_LEN (sizeof(struct ip_vs_service_entry)) 2539 struct ip_vs_get_services field_IP_VS_SO_GET_SERVICES;
2520#define GET_DESTS_ARG_LEN (sizeof(struct ip_vs_get_dests)) 2540 struct ip_vs_service_entry field_IP_VS_SO_GET_SERVICE;
2521#define GET_TIMEOUT_ARG_LEN (sizeof(struct ip_vs_timeout_user)) 2541 struct ip_vs_get_dests field_IP_VS_SO_GET_DESTS;
2522#define GET_DAEMON_ARG_LEN (sizeof(struct ip_vs_daemon_user) * 2) 2542 struct ip_vs_timeout_user field_IP_VS_SO_GET_TIMEOUT;
2523 2543 struct ip_vs_daemon_user field_IP_VS_SO_GET_DAEMON[2];
2524static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = {
2525 [GET_CMDID(IP_VS_SO_GET_VERSION)] = 64,
2526 [GET_CMDID(IP_VS_SO_GET_INFO)] = GET_INFO_ARG_LEN,
2527 [GET_CMDID(IP_VS_SO_GET_SERVICES)] = GET_SERVICES_ARG_LEN,
2528 [GET_CMDID(IP_VS_SO_GET_SERVICE)] = GET_SERVICE_ARG_LEN,
2529 [GET_CMDID(IP_VS_SO_GET_DESTS)] = GET_DESTS_ARG_LEN,
2530 [GET_CMDID(IP_VS_SO_GET_TIMEOUT)] = GET_TIMEOUT_ARG_LEN,
2531 [GET_CMDID(IP_VS_SO_GET_DAEMON)] = GET_DAEMON_ARG_LEN,
2532}; 2544};
2533 2545
2546#define MAX_GET_ARGLEN sizeof(union ip_vs_get_arglen)
2547
2534static int 2548static int
2535do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) 2549do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
2536{ 2550{
2537 unsigned char arg[128]; 2551 unsigned char arg[MAX_GET_ARGLEN];
2538 int ret = 0; 2552 int ret = 0;
2539 unsigned int copylen; 2553 unsigned int copylen;
2540 struct net *net = sock_net(sk); 2554 struct net *net = sock_net(sk);
2541 struct netns_ipvs *ipvs = net_ipvs(net); 2555 struct netns_ipvs *ipvs = net_ipvs(net);
2542 2556
2543 BUG_ON(!net); 2557 BUG_ON(!net);
2558 BUILD_BUG_ON(sizeof(arg) > 255);
2544 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) 2559 if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
2545 return -EPERM; 2560 return -EPERM;
2546 2561
2547 if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_GET_MAX) 2562 if (cmd < IP_VS_BASE_CTL || cmd > IP_VS_SO_GET_MAX)
2548 return -EINVAL; 2563 return -EINVAL;
2549 2564
2550 if (*len < get_arglen[GET_CMDID(cmd)]) { 2565 copylen = get_arglen[CMDID(cmd)];
2551 pr_err("get_ctl: len %u < %u\n", 2566 if (*len < (int) copylen) {
2552 *len, get_arglen[GET_CMDID(cmd)]); 2567 IP_VS_DBG(1, "get_ctl: len %d < %u\n", *len, copylen);
2553 return -EINVAL; 2568 return -EINVAL;
2554 } 2569 }
2555 2570
2556 copylen = get_arglen[GET_CMDID(cmd)];
2557 if (copylen > 128)
2558 return -EINVAL;
2559
2560 if (copy_from_user(arg, user, copylen) != 0) 2571 if (copy_from_user(arg, user, copylen) != 0)
2561 return -EFAULT; 2572 return -EFAULT;
2562 /* 2573 /*
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index deeb95fb7028..82374601577e 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -127,6 +127,204 @@ static void nft_trans_destroy(struct nft_trans *trans)
127 kfree(trans); 127 kfree(trans);
128} 128}
129 129
130static void nf_tables_unregister_hooks(const struct nft_table *table,
131 const struct nft_chain *chain,
132 unsigned int hook_nops)
133{
134 if (!(table->flags & NFT_TABLE_F_DORMANT) &&
135 chain->flags & NFT_BASE_CHAIN)
136 nf_unregister_hooks(nft_base_chain(chain)->ops, hook_nops);
137}
138
139/* Internal table flags */
140#define NFT_TABLE_INACTIVE (1 << 15)
141
142static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
143{
144 struct nft_trans *trans;
145
146 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_table));
147 if (trans == NULL)
148 return -ENOMEM;
149
150 if (msg_type == NFT_MSG_NEWTABLE)
151 ctx->table->flags |= NFT_TABLE_INACTIVE;
152
153 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
154 return 0;
155}
156
157static int nft_deltable(struct nft_ctx *ctx)
158{
159 int err;
160
161 err = nft_trans_table_add(ctx, NFT_MSG_DELTABLE);
162 if (err < 0)
163 return err;
164
165 list_del_rcu(&ctx->table->list);
166 return err;
167}
168
169static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
170{
171 struct nft_trans *trans;
172
173 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain));
174 if (trans == NULL)
175 return -ENOMEM;
176
177 if (msg_type == NFT_MSG_NEWCHAIN)
178 ctx->chain->flags |= NFT_CHAIN_INACTIVE;
179
180 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
181 return 0;
182}
183
184static int nft_delchain(struct nft_ctx *ctx)
185{
186 int err;
187
188 err = nft_trans_chain_add(ctx, NFT_MSG_DELCHAIN);
189 if (err < 0)
190 return err;
191
192 ctx->table->use--;
193 list_del_rcu(&ctx->chain->list);
194
195 return err;
196}
197
198static inline bool
199nft_rule_is_active(struct net *net, const struct nft_rule *rule)
200{
201 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
202}
203
204static inline int gencursor_next(struct net *net)
205{
206 return net->nft.gencursor+1 == 1 ? 1 : 0;
207}
208
209static inline int
210nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
211{
212 return (rule->genmask & (1 << gencursor_next(net))) == 0;
213}
214
215static inline void
216nft_rule_activate_next(struct net *net, struct nft_rule *rule)
217{
218 /* Now inactive, will be active in the future */
219 rule->genmask = (1 << net->nft.gencursor);
220}
221
222static inline void
223nft_rule_deactivate_next(struct net *net, struct nft_rule *rule)
224{
225 rule->genmask = (1 << gencursor_next(net));
226}
227
228static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
229{
230 rule->genmask = 0;
231}
232
233static int
234nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
235{
236 /* You cannot delete the same rule twice */
237 if (nft_rule_is_active_next(ctx->net, rule)) {
238 nft_rule_deactivate_next(ctx->net, rule);
239 ctx->chain->use--;
240 return 0;
241 }
242 return -ENOENT;
243}
244
245static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type,
246 struct nft_rule *rule)
247{
248 struct nft_trans *trans;
249
250 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule));
251 if (trans == NULL)
252 return NULL;
253
254 nft_trans_rule(trans) = rule;
255 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
256
257 return trans;
258}
259
260static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
261{
262 struct nft_trans *trans;
263 int err;
264
265 trans = nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule);
266 if (trans == NULL)
267 return -ENOMEM;
268
269 err = nf_tables_delrule_deactivate(ctx, rule);
270 if (err < 0) {
271 nft_trans_destroy(trans);
272 return err;
273 }
274
275 return 0;
276}
277
278static int nft_delrule_by_chain(struct nft_ctx *ctx)
279{
280 struct nft_rule *rule;
281 int err;
282
283 list_for_each_entry(rule, &ctx->chain->rules, list) {
284 err = nft_delrule(ctx, rule);
285 if (err < 0)
286 return err;
287 }
288 return 0;
289}
290
291/* Internal set flag */
292#define NFT_SET_INACTIVE (1 << 15)
293
294static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
295 struct nft_set *set)
296{
297 struct nft_trans *trans;
298
299 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set));
300 if (trans == NULL)
301 return -ENOMEM;
302
303 if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
304 nft_trans_set_id(trans) =
305 ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
306 set->flags |= NFT_SET_INACTIVE;
307 }
308 nft_trans_set(trans) = set;
309 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
310
311 return 0;
312}
313
314static int nft_delset(struct nft_ctx *ctx, struct nft_set *set)
315{
316 int err;
317
318 err = nft_trans_set_add(ctx, NFT_MSG_DELSET, set);
319 if (err < 0)
320 return err;
321
322 list_del_rcu(&set->list);
323 ctx->table->use--;
324
325 return err;
326}
327
130/* 328/*
131 * Tables 329 * Tables
132 */ 330 */
@@ -309,9 +507,6 @@ done:
309 return skb->len; 507 return skb->len;
310} 508}
311 509
312/* Internal table flags */
313#define NFT_TABLE_INACTIVE (1 << 15)
314
315static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb, 510static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
316 const struct nlmsghdr *nlh, 511 const struct nlmsghdr *nlh,
317 const struct nlattr * const nla[]) 512 const struct nlattr * const nla[])
@@ -443,21 +638,6 @@ err:
443 return ret; 638 return ret;
444} 639}
445 640
446static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
447{
448 struct nft_trans *trans;
449
450 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_table));
451 if (trans == NULL)
452 return -ENOMEM;
453
454 if (msg_type == NFT_MSG_NEWTABLE)
455 ctx->table->flags |= NFT_TABLE_INACTIVE;
456
457 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
458 return 0;
459}
460
461static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb, 641static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
462 const struct nlmsghdr *nlh, 642 const struct nlmsghdr *nlh,
463 const struct nlattr * const nla[]) 643 const struct nlattr * const nla[])
@@ -527,6 +707,67 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
527 return 0; 707 return 0;
528} 708}
529 709
710static int nft_flush_table(struct nft_ctx *ctx)
711{
712 int err;
713 struct nft_chain *chain, *nc;
714 struct nft_set *set, *ns;
715
716 list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
717 ctx->chain = chain;
718
719 err = nft_delrule_by_chain(ctx);
720 if (err < 0)
721 goto out;
722
723 err = nft_delchain(ctx);
724 if (err < 0)
725 goto out;
726 }
727
728 list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
729 if (set->flags & NFT_SET_ANONYMOUS &&
730 !list_empty(&set->bindings))
731 continue;
732
733 err = nft_delset(ctx, set);
734 if (err < 0)
735 goto out;
736 }
737
738 err = nft_deltable(ctx);
739out:
740 return err;
741}
742
743static int nft_flush(struct nft_ctx *ctx, int family)
744{
745 struct nft_af_info *afi;
746 struct nft_table *table, *nt;
747 const struct nlattr * const *nla = ctx->nla;
748 int err = 0;
749
750 list_for_each_entry(afi, &ctx->net->nft.af_info, list) {
751 if (family != AF_UNSPEC && afi->family != family)
752 continue;
753
754 ctx->afi = afi;
755 list_for_each_entry_safe(table, nt, &afi->tables, list) {
756 if (nla[NFTA_TABLE_NAME] &&
757 nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0)
758 continue;
759
760 ctx->table = table;
761
762 err = nft_flush_table(ctx);
763 if (err < 0)
764 goto out;
765 }
766 }
767out:
768 return err;
769}
770
530static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb, 771static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
531 const struct nlmsghdr *nlh, 772 const struct nlmsghdr *nlh,
532 const struct nlattr * const nla[]) 773 const struct nlattr * const nla[])
@@ -535,9 +776,13 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
535 struct nft_af_info *afi; 776 struct nft_af_info *afi;
536 struct nft_table *table; 777 struct nft_table *table;
537 struct net *net = sock_net(skb->sk); 778 struct net *net = sock_net(skb->sk);
538 int family = nfmsg->nfgen_family, err; 779 int family = nfmsg->nfgen_family;
539 struct nft_ctx ctx; 780 struct nft_ctx ctx;
540 781
782 nft_ctx_init(&ctx, skb, nlh, NULL, NULL, NULL, nla);
783 if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
784 return nft_flush(&ctx, family);
785
541 afi = nf_tables_afinfo_lookup(net, family, false); 786 afi = nf_tables_afinfo_lookup(net, family, false);
542 if (IS_ERR(afi)) 787 if (IS_ERR(afi))
543 return PTR_ERR(afi); 788 return PTR_ERR(afi);
@@ -547,16 +792,11 @@ static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
547 return PTR_ERR(table); 792 return PTR_ERR(table);
548 if (table->flags & NFT_TABLE_INACTIVE) 793 if (table->flags & NFT_TABLE_INACTIVE)
549 return -ENOENT; 794 return -ENOENT;
550 if (table->use > 0)
551 return -EBUSY;
552 795
553 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla); 796 ctx.afi = afi;
554 err = nft_trans_table_add(&ctx, NFT_MSG_DELTABLE); 797 ctx.table = table;
555 if (err < 0)
556 return err;
557 798
558 list_del_rcu(&table->list); 799 return nft_flush_table(&ctx);
559 return 0;
560} 800}
561 801
562static void nf_tables_table_destroy(struct nft_ctx *ctx) 802static void nf_tables_table_destroy(struct nft_ctx *ctx)
@@ -913,21 +1153,6 @@ static void nft_chain_stats_replace(struct nft_base_chain *chain,
913 rcu_assign_pointer(chain->stats, newstats); 1153 rcu_assign_pointer(chain->stats, newstats);
914} 1154}
915 1155
916static int nft_trans_chain_add(struct nft_ctx *ctx, int msg_type)
917{
918 struct nft_trans *trans;
919
920 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_chain));
921 if (trans == NULL)
922 return -ENOMEM;
923
924 if (msg_type == NFT_MSG_NEWCHAIN)
925 ctx->chain->flags |= NFT_CHAIN_INACTIVE;
926
927 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
928 return 0;
929}
930
931static void nf_tables_chain_destroy(struct nft_chain *chain) 1156static void nf_tables_chain_destroy(struct nft_chain *chain)
932{ 1157{
933 BUG_ON(chain->use > 0); 1158 BUG_ON(chain->use > 0);
@@ -1157,11 +1382,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
1157 list_add_tail_rcu(&chain->list, &table->chains); 1382 list_add_tail_rcu(&chain->list, &table->chains);
1158 return 0; 1383 return 0;
1159err2: 1384err2:
1160 if (!(table->flags & NFT_TABLE_F_DORMANT) && 1385 nf_tables_unregister_hooks(table, chain, afi->nops);
1161 chain->flags & NFT_BASE_CHAIN) {
1162 nf_unregister_hooks(nft_base_chain(chain)->ops,
1163 afi->nops);
1164 }
1165err1: 1386err1:
1166 nf_tables_chain_destroy(chain); 1387 nf_tables_chain_destroy(chain);
1167 return err; 1388 return err;
@@ -1178,7 +1399,6 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1178 struct net *net = sock_net(skb->sk); 1399 struct net *net = sock_net(skb->sk);
1179 int family = nfmsg->nfgen_family; 1400 int family = nfmsg->nfgen_family;
1180 struct nft_ctx ctx; 1401 struct nft_ctx ctx;
1181 int err;
1182 1402
1183 afi = nf_tables_afinfo_lookup(net, family, false); 1403 afi = nf_tables_afinfo_lookup(net, family, false);
1184 if (IS_ERR(afi)) 1404 if (IS_ERR(afi))
@@ -1199,13 +1419,8 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
1199 return -EBUSY; 1419 return -EBUSY;
1200 1420
1201 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla); 1421 nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
1202 err = nft_trans_chain_add(&ctx, NFT_MSG_DELCHAIN);
1203 if (err < 0)
1204 return err;
1205 1422
1206 table->use--; 1423 return nft_delchain(&ctx);
1207 list_del_rcu(&chain->list);
1208 return 0;
1209} 1424}
1210 1425
1211/* 1426/*
@@ -1527,41 +1742,6 @@ err:
1527 return err; 1742 return err;
1528} 1743}
1529 1744
1530static inline bool
1531nft_rule_is_active(struct net *net, const struct nft_rule *rule)
1532{
1533 return (rule->genmask & (1 << net->nft.gencursor)) == 0;
1534}
1535
1536static inline int gencursor_next(struct net *net)
1537{
1538 return net->nft.gencursor+1 == 1 ? 1 : 0;
1539}
1540
1541static inline int
1542nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
1543{
1544 return (rule->genmask & (1 << gencursor_next(net))) == 0;
1545}
1546
1547static inline void
1548nft_rule_activate_next(struct net *net, struct nft_rule *rule)
1549{
1550 /* Now inactive, will be active in the future */
1551 rule->genmask = (1 << net->nft.gencursor);
1552}
1553
1554static inline void
1555nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
1556{
1557 rule->genmask = (1 << gencursor_next(net));
1558}
1559
1560static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
1561{
1562 rule->genmask = 0;
1563}
1564
1565static int nf_tables_dump_rules(struct sk_buff *skb, 1745static int nf_tables_dump_rules(struct sk_buff *skb,
1566 struct netlink_callback *cb) 1746 struct netlink_callback *cb)
1567{ 1747{
@@ -1687,21 +1867,6 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
1687 kfree(rule); 1867 kfree(rule);
1688} 1868}
1689 1869
1690static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type,
1691 struct nft_rule *rule)
1692{
1693 struct nft_trans *trans;
1694
1695 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_rule));
1696 if (trans == NULL)
1697 return NULL;
1698
1699 nft_trans_rule(trans) = rule;
1700 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
1701
1702 return trans;
1703}
1704
1705#define NFT_RULE_MAXEXPRS 128 1870#define NFT_RULE_MAXEXPRS 128
1706 1871
1707static struct nft_expr_info *info; 1872static struct nft_expr_info *info;
@@ -1823,7 +1988,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1823 err = -ENOMEM; 1988 err = -ENOMEM;
1824 goto err2; 1989 goto err2;
1825 } 1990 }
1826 nft_rule_disactivate_next(net, old_rule); 1991 nft_rule_deactivate_next(net, old_rule);
1827 chain->use--; 1992 chain->use--;
1828 list_add_tail_rcu(&rule->list, &old_rule->list); 1993 list_add_tail_rcu(&rule->list, &old_rule->list);
1829 } else { 1994 } else {
@@ -1867,33 +2032,6 @@ err1:
1867 return err; 2032 return err;
1868} 2033}
1869 2034
1870static int
1871nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
1872{
1873 /* You cannot delete the same rule twice */
1874 if (nft_rule_is_active_next(ctx->net, rule)) {
1875 if (nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule) == NULL)
1876 return -ENOMEM;
1877 nft_rule_disactivate_next(ctx->net, rule);
1878 ctx->chain->use--;
1879 return 0;
1880 }
1881 return -ENOENT;
1882}
1883
1884static int nf_table_delrule_by_chain(struct nft_ctx *ctx)
1885{
1886 struct nft_rule *rule;
1887 int err;
1888
1889 list_for_each_entry(rule, &ctx->chain->rules, list) {
1890 err = nf_tables_delrule_one(ctx, rule);
1891 if (err < 0)
1892 return err;
1893 }
1894 return 0;
1895}
1896
1897static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb, 2035static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1898 const struct nlmsghdr *nlh, 2036 const struct nlmsghdr *nlh,
1899 const struct nlattr * const nla[]) 2037 const struct nlattr * const nla[])
@@ -1932,14 +2070,14 @@ static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1932 if (IS_ERR(rule)) 2070 if (IS_ERR(rule))
1933 return PTR_ERR(rule); 2071 return PTR_ERR(rule);
1934 2072
1935 err = nf_tables_delrule_one(&ctx, rule); 2073 err = nft_delrule(&ctx, rule);
1936 } else { 2074 } else {
1937 err = nf_table_delrule_by_chain(&ctx); 2075 err = nft_delrule_by_chain(&ctx);
1938 } 2076 }
1939 } else { 2077 } else {
1940 list_for_each_entry(chain, &table->chains, list) { 2078 list_for_each_entry(chain, &table->chains, list) {
1941 ctx.chain = chain; 2079 ctx.chain = chain;
1942 err = nf_table_delrule_by_chain(&ctx); 2080 err = nft_delrule_by_chain(&ctx);
1943 if (err < 0) 2081 if (err < 0)
1944 break; 2082 break;
1945 } 2083 }
@@ -2322,8 +2460,6 @@ static int nf_tables_dump_sets_done(struct netlink_callback *cb)
2322 return 0; 2460 return 0;
2323} 2461}
2324 2462
2325#define NFT_SET_INACTIVE (1 << 15) /* Internal set flag */
2326
2327static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb, 2463static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
2328 const struct nlmsghdr *nlh, 2464 const struct nlmsghdr *nlh,
2329 const struct nlattr * const nla[]) 2465 const struct nlattr * const nla[])
@@ -2398,26 +2534,6 @@ static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
2398 return 0; 2534 return 0;
2399} 2535}
2400 2536
2401static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
2402 struct nft_set *set)
2403{
2404 struct nft_trans *trans;
2405
2406 trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set));
2407 if (trans == NULL)
2408 return -ENOMEM;
2409
2410 if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
2411 nft_trans_set_id(trans) =
2412 ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
2413 set->flags |= NFT_SET_INACTIVE;
2414 }
2415 nft_trans_set(trans) = set;
2416 list_add_tail(&trans->list, &ctx->net->nft.commit_list);
2417
2418 return 0;
2419}
2420
2421static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, 2537static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
2422 const struct nlmsghdr *nlh, 2538 const struct nlmsghdr *nlh,
2423 const struct nlattr * const nla[]) 2539 const struct nlattr * const nla[])
@@ -2611,13 +2727,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
2611 if (!list_empty(&set->bindings)) 2727 if (!list_empty(&set->bindings))
2612 return -EBUSY; 2728 return -EBUSY;
2613 2729
2614 err = nft_trans_set_add(&ctx, NFT_MSG_DELSET, set); 2730 return nft_delset(&ctx, set);
2615 if (err < 0)
2616 return err;
2617
2618 list_del_rcu(&set->list);
2619 ctx.table->use--;
2620 return 0;
2621} 2731}
2622 2732
2623static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx, 2733static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
@@ -3352,11 +3462,9 @@ static int nf_tables_commit(struct sk_buff *skb)
3352 break; 3462 break;
3353 case NFT_MSG_DELCHAIN: 3463 case NFT_MSG_DELCHAIN:
3354 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); 3464 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
3355 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && 3465 nf_tables_unregister_hooks(trans->ctx.table,
3356 trans->ctx.chain->flags & NFT_BASE_CHAIN) { 3466 trans->ctx.chain,
3357 nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops, 3467 trans->ctx.afi->nops);
3358 trans->ctx.afi->nops);
3359 }
3360 break; 3468 break;
3361 case NFT_MSG_NEWRULE: 3469 case NFT_MSG_NEWRULE:
3362 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans)); 3470 nft_rule_clear(trans->ctx.net, nft_trans_rule(trans));
@@ -3479,11 +3587,9 @@ static int nf_tables_abort(struct sk_buff *skb)
3479 } else { 3587 } else {
3480 trans->ctx.table->use--; 3588 trans->ctx.table->use--;
3481 list_del_rcu(&trans->ctx.chain->list); 3589 list_del_rcu(&trans->ctx.chain->list);
3482 if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT) && 3590 nf_tables_unregister_hooks(trans->ctx.table,
3483 trans->ctx.chain->flags & NFT_BASE_CHAIN) { 3591 trans->ctx.chain,
3484 nf_unregister_hooks(nft_base_chain(trans->ctx.chain)->ops, 3592 trans->ctx.afi->nops);
3485 trans->ctx.afi->nops);
3486 }
3487 } 3593 }
3488 break; 3594 break;
3489 case NFT_MSG_DELCHAIN: 3595 case NFT_MSG_DELCHAIN:
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 3ea0eacbd970..c18af2f63eef 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -40,6 +40,11 @@ struct nf_acct {
40 char data[0]; 40 char data[0];
41}; 41};
42 42
43struct nfacct_filter {
44 u32 value;
45 u32 mask;
46};
47
43#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) 48#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
44#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ 49#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
45 50
@@ -181,6 +186,7 @@ static int
181nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb) 186nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
182{ 187{
183 struct nf_acct *cur, *last; 188 struct nf_acct *cur, *last;
189 const struct nfacct_filter *filter = cb->data;
184 190
185 if (cb->args[2]) 191 if (cb->args[2])
186 return 0; 192 return 0;
@@ -197,6 +203,10 @@ nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
197 203
198 last = NULL; 204 last = NULL;
199 } 205 }
206
207 if (filter && (cur->flags & filter->mask) != filter->value)
208 continue;
209
200 if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid, 210 if (nfnl_acct_fill_info(skb, NETLINK_CB(cb->skb).portid,
201 cb->nlh->nlmsg_seq, 211 cb->nlh->nlmsg_seq,
202 NFNL_MSG_TYPE(cb->nlh->nlmsg_type), 212 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
@@ -211,6 +221,38 @@ nfnl_acct_dump(struct sk_buff *skb, struct netlink_callback *cb)
211 return skb->len; 221 return skb->len;
212} 222}
213 223
224static int nfnl_acct_done(struct netlink_callback *cb)
225{
226 kfree(cb->data);
227 return 0;
228}
229
230static const struct nla_policy filter_policy[NFACCT_FILTER_MAX + 1] = {
231 [NFACCT_FILTER_MASK] = { .type = NLA_U32 },
232 [NFACCT_FILTER_VALUE] = { .type = NLA_U32 },
233};
234
235static struct nfacct_filter *
236nfacct_filter_alloc(const struct nlattr * const attr)
237{
238 struct nfacct_filter *filter;
239 struct nlattr *tb[NFACCT_FILTER_MAX + 1];
240 int err;
241
242 err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy);
243 if (err < 0)
244 return ERR_PTR(err);
245
246 filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
247 if (!filter)
248 return ERR_PTR(-ENOMEM);
249
250 filter->mask = ntohl(nla_get_be32(tb[NFACCT_FILTER_MASK]));
251 filter->value = ntohl(nla_get_be32(tb[NFACCT_FILTER_VALUE]));
252
253 return filter;
254}
255
214static int 256static int
215nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb, 257nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
216 const struct nlmsghdr *nlh, const struct nlattr * const tb[]) 258 const struct nlmsghdr *nlh, const struct nlattr * const tb[])
@@ -222,7 +264,18 @@ nfnl_acct_get(struct sock *nfnl, struct sk_buff *skb,
222 if (nlh->nlmsg_flags & NLM_F_DUMP) { 264 if (nlh->nlmsg_flags & NLM_F_DUMP) {
223 struct netlink_dump_control c = { 265 struct netlink_dump_control c = {
224 .dump = nfnl_acct_dump, 266 .dump = nfnl_acct_dump,
267 .done = nfnl_acct_done,
225 }; 268 };
269
270 if (tb[NFACCT_FILTER]) {
271 struct nfacct_filter *filter;
272
273 filter = nfacct_filter_alloc(tb[NFACCT_FILTER]);
274 if (IS_ERR(filter))
275 return PTR_ERR(filter);
276
277 c.data = filter;
278 }
226 return netlink_dump_start(nfnl, skb, nlh, &c); 279 return netlink_dump_start(nfnl, skb, nlh, &c);
227 } 280 }
228 281
@@ -314,6 +367,7 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
314 [NFACCT_PKTS] = { .type = NLA_U64 }, 367 [NFACCT_PKTS] = { .type = NLA_U64 },
315 [NFACCT_FLAGS] = { .type = NLA_U32 }, 368 [NFACCT_FLAGS] = { .type = NLA_U32 },
316 [NFACCT_QUOTA] = { .type = NLA_U64 }, 369 [NFACCT_QUOTA] = { .type = NLA_U64 },
370 [NFACCT_FILTER] = {.type = NLA_NESTED },
317}; 371};
318 372
319static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { 373static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c
new file mode 100644
index 000000000000..6637bab00567
--- /dev/null
+++ b/net/netfilter/nft_masq.c
@@ -0,0 +1,59 @@
1/*
2 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/netlink.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter/nf_tables.h>
15#include <net/netfilter/nf_tables.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nft_masq.h>
18
19const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
20 [NFTA_MASQ_FLAGS] = { .type = NLA_U32 },
21};
22EXPORT_SYMBOL_GPL(nft_masq_policy);
23
24int nft_masq_init(const struct nft_ctx *ctx,
25 const struct nft_expr *expr,
26 const struct nlattr * const tb[])
27{
28 struct nft_masq *priv = nft_expr_priv(expr);
29
30 if (tb[NFTA_MASQ_FLAGS] == NULL)
31 return 0;
32
33 priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
34 if (priv->flags & ~NF_NAT_RANGE_MASK)
35 return -EINVAL;
36
37 return 0;
38}
39EXPORT_SYMBOL_GPL(nft_masq_init);
40
41int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
42{
43 const struct nft_masq *priv = nft_expr_priv(expr);
44
45 if (priv->flags == 0)
46 return 0;
47
48 if (nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
49 goto nla_put_failure;
50
51 return 0;
52
53nla_put_failure:
54 return -1;
55}
56EXPORT_SYMBOL_GPL(nft_masq_dump);
57
58MODULE_LICENSE("GPL");
59MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 852b178c6ae7..1e7c076ca63a 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -14,6 +14,10 @@
14#include <linux/netlink.h> 14#include <linux/netlink.h>
15#include <linux/netfilter.h> 15#include <linux/netfilter.h>
16#include <linux/netfilter/nf_tables.h> 16#include <linux/netfilter/nf_tables.h>
17#include <linux/in.h>
18#include <linux/ip.h>
19#include <linux/ipv6.h>
20#include <linux/smp.h>
17#include <net/dst.h> 21#include <net/dst.h>
18#include <net/sock.h> 22#include <net/sock.h>
19#include <net/tcp_states.h> /* for TCP_TIME_WAIT */ 23#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
@@ -124,6 +128,43 @@ void nft_meta_get_eval(const struct nft_expr *expr,
124 dest->data[0] = skb->secmark; 128 dest->data[0] = skb->secmark;
125 break; 129 break;
126#endif 130#endif
131 case NFT_META_PKTTYPE:
132 if (skb->pkt_type != PACKET_LOOPBACK) {
133 dest->data[0] = skb->pkt_type;
134 break;
135 }
136
137 switch (pkt->ops->pf) {
138 case NFPROTO_IPV4:
139 if (ipv4_is_multicast(ip_hdr(skb)->daddr))
140 dest->data[0] = PACKET_MULTICAST;
141 else
142 dest->data[0] = PACKET_BROADCAST;
143 break;
144 case NFPROTO_IPV6:
145 if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
146 dest->data[0] = PACKET_MULTICAST;
147 else
148 dest->data[0] = PACKET_BROADCAST;
149 break;
150 default:
151 WARN_ON(1);
152 goto err;
153 }
154 break;
155 case NFT_META_CPU:
156 dest->data[0] = smp_processor_id();
157 break;
158 case NFT_META_IIFGROUP:
159 if (in == NULL)
160 goto err;
161 dest->data[0] = in->group;
162 break;
163 case NFT_META_OIFGROUP:
164 if (out == NULL)
165 goto err;
166 dest->data[0] = out->group;
167 break;
127 default: 168 default:
128 WARN_ON(1); 169 WARN_ON(1);
129 goto err; 170 goto err;
@@ -195,6 +236,10 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
195#ifdef CONFIG_NETWORK_SECMARK 236#ifdef CONFIG_NETWORK_SECMARK
196 case NFT_META_SECMARK: 237 case NFT_META_SECMARK:
197#endif 238#endif
239 case NFT_META_PKTTYPE:
240 case NFT_META_CPU:
241 case NFT_META_IIFGROUP:
242 case NFT_META_OIFGROUP:
198 break; 243 break;
199 default: 244 default:
200 return -EOPNOTSUPP; 245 return -EOPNOTSUPP;
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
index 79ff58cd36dc..799550b476fb 100644
--- a/net/netfilter/nft_nat.c
+++ b/net/netfilter/nft_nat.c
@@ -33,6 +33,7 @@ struct nft_nat {
33 enum nft_registers sreg_proto_max:8; 33 enum nft_registers sreg_proto_max:8;
34 enum nf_nat_manip_type type:8; 34 enum nf_nat_manip_type type:8;
35 u8 family; 35 u8 family;
36 u16 flags;
36}; 37};
37 38
38static void nft_nat_eval(const struct nft_expr *expr, 39static void nft_nat_eval(const struct nft_expr *expr,
@@ -71,6 +72,8 @@ static void nft_nat_eval(const struct nft_expr *expr,
71 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; 72 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
72 } 73 }
73 74
75 range.flags |= priv->flags;
76
74 data[NFT_REG_VERDICT].verdict = 77 data[NFT_REG_VERDICT].verdict =
75 nf_nat_setup_info(ct, &range, priv->type); 78 nf_nat_setup_info(ct, &range, priv->type);
76} 79}
@@ -82,6 +85,7 @@ static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
82 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 }, 85 [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 },
83 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 }, 86 [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
84 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 }, 87 [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
88 [NFTA_NAT_FLAGS] = { .type = NLA_U32 },
85}; 89};
86 90
87static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 91static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
@@ -149,6 +153,12 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
149 } else 153 } else
150 priv->sreg_proto_max = priv->sreg_proto_min; 154 priv->sreg_proto_max = priv->sreg_proto_min;
151 155
156 if (tb[NFTA_NAT_FLAGS]) {
157 priv->flags = ntohl(nla_get_be32(tb[NFTA_NAT_FLAGS]));
158 if (priv->flags & ~NF_NAT_RANGE_MASK)
159 return -EINVAL;
160 }
161
152 return 0; 162 return 0;
153} 163}
154 164
@@ -183,6 +193,12 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
183 htonl(priv->sreg_proto_max))) 193 htonl(priv->sreg_proto_max)))
184 goto nla_put_failure; 194 goto nla_put_failure;
185 } 195 }
196
197 if (priv->flags != 0) {
198 if (nla_put_be32(skb, NFTA_NAT_FLAGS, htonl(priv->flags)))
199 goto nla_put_failure;
200 }
201
186 return 0; 202 return 0;
187 203
188nla_put_failure: 204nla_put_failure:
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index d3c48b14ab94..5699adb97652 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -29,7 +29,6 @@ string_mt(const struct sk_buff *skb, struct xt_action_param *par)
29 struct ts_state state; 29 struct ts_state state;
30 bool invert; 30 bool invert;
31 31
32 memset(&state, 0, sizeof(struct ts_state));
33 invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT; 32 invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT;
34 33
35 return (skb_find_text((struct sk_buff *)skb, conf->from_offset, 34 return (skb_find_text((struct sk_buff *)skb, conf->from_offset,