aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-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
8 files changed, 536 insertions, 418 deletions
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");