scsi: core: Avoid that system resume triggers a kernel warning
[linux-2.6-microblaze.git] / net / ipv4 / netfilter / nf_nat_l3proto_ipv4.c
1 /*
2  * (C) 1999-2001 Paul `Rusty' Russell
3  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
4  * (C) 2011 Patrick McHardy <kaber@trash.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/types.h>
12 #include <linux/module.h>
13 #include <linux/skbuff.h>
14 #include <linux/ip.h>
15 #include <linux/icmp.h>
16 #include <linux/netfilter.h>
17 #include <linux/netfilter_ipv4.h>
18 #include <net/secure_seq.h>
19 #include <net/checksum.h>
20 #include <net/route.h>
21 #include <net/ip.h>
22
23 #include <net/netfilter/nf_conntrack_core.h>
24 #include <net/netfilter/nf_conntrack.h>
25 #include <net/netfilter/nf_nat_core.h>
26 #include <net/netfilter/nf_nat_l3proto.h>
27 #include <net/netfilter/nf_nat_l4proto.h>
28
29 static const struct nf_nat_l3proto nf_nat_l3proto_ipv4;
30
31 #ifdef CONFIG_XFRM
32 static void nf_nat_ipv4_decode_session(struct sk_buff *skb,
33                                        const struct nf_conn *ct,
34                                        enum ip_conntrack_dir dir,
35                                        unsigned long statusbit,
36                                        struct flowi *fl)
37 {
38         const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
39         struct flowi4 *fl4 = &fl->u.ip4;
40
41         if (ct->status & statusbit) {
42                 fl4->daddr = t->dst.u3.ip;
43                 if (t->dst.protonum == IPPROTO_TCP ||
44                     t->dst.protonum == IPPROTO_UDP ||
45                     t->dst.protonum == IPPROTO_UDPLITE ||
46                     t->dst.protonum == IPPROTO_DCCP ||
47                     t->dst.protonum == IPPROTO_SCTP)
48                         fl4->fl4_dport = t->dst.u.all;
49         }
50
51         statusbit ^= IPS_NAT_MASK;
52
53         if (ct->status & statusbit) {
54                 fl4->saddr = t->src.u3.ip;
55                 if (t->dst.protonum == IPPROTO_TCP ||
56                     t->dst.protonum == IPPROTO_UDP ||
57                     t->dst.protonum == IPPROTO_UDPLITE ||
58                     t->dst.protonum == IPPROTO_DCCP ||
59                     t->dst.protonum == IPPROTO_SCTP)
60                         fl4->fl4_sport = t->src.u.all;
61         }
62 }
63 #endif /* CONFIG_XFRM */
64
65 static bool nf_nat_ipv4_manip_pkt(struct sk_buff *skb,
66                                   unsigned int iphdroff,
67                                   const struct nf_conntrack_tuple *target,
68                                   enum nf_nat_manip_type maniptype)
69 {
70         struct iphdr *iph;
71         unsigned int hdroff;
72
73         if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
74                 return false;
75
76         iph = (void *)skb->data + iphdroff;
77         hdroff = iphdroff + iph->ihl * 4;
78
79         if (!nf_nat_l4proto_manip_pkt(skb, &nf_nat_l3proto_ipv4, iphdroff,
80                                       hdroff, target, maniptype))
81                 return false;
82         iph = (void *)skb->data + iphdroff;
83
84         if (maniptype == NF_NAT_MANIP_SRC) {
85                 csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
86                 iph->saddr = target->src.u3.ip;
87         } else {
88                 csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
89                 iph->daddr = target->dst.u3.ip;
90         }
91         return true;
92 }
93
94 static void nf_nat_ipv4_csum_update(struct sk_buff *skb,
95                                     unsigned int iphdroff, __sum16 *check,
96                                     const struct nf_conntrack_tuple *t,
97                                     enum nf_nat_manip_type maniptype)
98 {
99         struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
100         __be32 oldip, newip;
101
102         if (maniptype == NF_NAT_MANIP_SRC) {
103                 oldip = iph->saddr;
104                 newip = t->src.u3.ip;
105         } else {
106                 oldip = iph->daddr;
107                 newip = t->dst.u3.ip;
108         }
109         inet_proto_csum_replace4(check, skb, oldip, newip, true);
110 }
111
112 static void nf_nat_ipv4_csum_recalc(struct sk_buff *skb,
113                                     u8 proto, void *data, __sum16 *check,
114                                     int datalen, int oldlen)
115 {
116         if (skb->ip_summed != CHECKSUM_PARTIAL) {
117                 const struct iphdr *iph = ip_hdr(skb);
118
119                 skb->ip_summed = CHECKSUM_PARTIAL;
120                 skb->csum_start = skb_headroom(skb) + skb_network_offset(skb) +
121                         ip_hdrlen(skb);
122                 skb->csum_offset = (void *)check - data;
123                 *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, datalen,
124                                             proto, 0);
125         } else
126                 inet_proto_csum_replace2(check, skb,
127                                          htons(oldlen), htons(datalen), true);
128 }
129
130 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
131 static int nf_nat_ipv4_nlattr_to_range(struct nlattr *tb[],
132                                        struct nf_nat_range2 *range)
133 {
134         if (tb[CTA_NAT_V4_MINIP]) {
135                 range->min_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MINIP]);
136                 range->flags |= NF_NAT_RANGE_MAP_IPS;
137         }
138
139         if (tb[CTA_NAT_V4_MAXIP])
140                 range->max_addr.ip = nla_get_be32(tb[CTA_NAT_V4_MAXIP]);
141         else
142                 range->max_addr.ip = range->min_addr.ip;
143
144         return 0;
145 }
146 #endif
147
148 static const struct nf_nat_l3proto nf_nat_l3proto_ipv4 = {
149         .l3proto                = NFPROTO_IPV4,
150         .manip_pkt              = nf_nat_ipv4_manip_pkt,
151         .csum_update            = nf_nat_ipv4_csum_update,
152         .csum_recalc            = nf_nat_ipv4_csum_recalc,
153 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
154         .nlattr_to_range        = nf_nat_ipv4_nlattr_to_range,
155 #endif
156 #ifdef CONFIG_XFRM
157         .decode_session         = nf_nat_ipv4_decode_session,
158 #endif
159 };
160
161 int nf_nat_icmp_reply_translation(struct sk_buff *skb,
162                                   struct nf_conn *ct,
163                                   enum ip_conntrack_info ctinfo,
164                                   unsigned int hooknum)
165 {
166         struct {
167                 struct icmphdr  icmp;
168                 struct iphdr    ip;
169         } *inside;
170         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
171         enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
172         unsigned int hdrlen = ip_hdrlen(skb);
173         struct nf_conntrack_tuple target;
174         unsigned long statusbit;
175
176         WARN_ON(ctinfo != IP_CT_RELATED && ctinfo != IP_CT_RELATED_REPLY);
177
178         if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
179                 return 0;
180         if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
181                 return 0;
182
183         inside = (void *)skb->data + hdrlen;
184         if (inside->icmp.type == ICMP_REDIRECT) {
185                 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
186                         return 0;
187                 if (ct->status & IPS_NAT_MASK)
188                         return 0;
189         }
190
191         if (manip == NF_NAT_MANIP_SRC)
192                 statusbit = IPS_SRC_NAT;
193         else
194                 statusbit = IPS_DST_NAT;
195
196         /* Invert if this is reply direction */
197         if (dir == IP_CT_DIR_REPLY)
198                 statusbit ^= IPS_NAT_MASK;
199
200         if (!(ct->status & statusbit))
201                 return 1;
202
203         if (!nf_nat_ipv4_manip_pkt(skb, hdrlen + sizeof(inside->icmp),
204                                    &ct->tuplehash[!dir].tuple, !manip))
205                 return 0;
206
207         if (skb->ip_summed != CHECKSUM_PARTIAL) {
208                 /* Reloading "inside" here since manip_pkt may reallocate */
209                 inside = (void *)skb->data + hdrlen;
210                 inside->icmp.checksum = 0;
211                 inside->icmp.checksum =
212                         csum_fold(skb_checksum(skb, hdrlen,
213                                                skb->len - hdrlen, 0));
214         }
215
216         /* Change outer to look like the reply to an incoming packet */
217         nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
218         if (!nf_nat_ipv4_manip_pkt(skb, 0, &target, manip))
219                 return 0;
220
221         return 1;
222 }
223 EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
224
225 static unsigned int
226 nf_nat_ipv4_fn(void *priv, struct sk_buff *skb,
227                const struct nf_hook_state *state)
228 {
229         struct nf_conn *ct;
230         enum ip_conntrack_info ctinfo;
231
232         ct = nf_ct_get(skb, &ctinfo);
233         if (!ct)
234                 return NF_ACCEPT;
235
236         if (ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY) {
237                 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
238                         if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo,
239                                                            state->hook))
240                                 return NF_DROP;
241                         else
242                                 return NF_ACCEPT;
243                 }
244         }
245
246         return nf_nat_inet_fn(priv, skb, state);
247 }
248
249 static unsigned int
250 nf_nat_ipv4_in(void *priv, struct sk_buff *skb,
251                const struct nf_hook_state *state)
252 {
253         unsigned int ret;
254         __be32 daddr = ip_hdr(skb)->daddr;
255
256         ret = nf_nat_ipv4_fn(priv, skb, state);
257         if (ret != NF_DROP && ret != NF_STOLEN &&
258             daddr != ip_hdr(skb)->daddr)
259                 skb_dst_drop(skb);
260
261         return ret;
262 }
263
264 static unsigned int
265 nf_nat_ipv4_out(void *priv, struct sk_buff *skb,
266                 const struct nf_hook_state *state)
267 {
268 #ifdef CONFIG_XFRM
269         const struct nf_conn *ct;
270         enum ip_conntrack_info ctinfo;
271         int err;
272 #endif
273         unsigned int ret;
274
275         ret = nf_nat_ipv4_fn(priv, skb, state);
276 #ifdef CONFIG_XFRM
277         if (ret != NF_DROP && ret != NF_STOLEN &&
278             !(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
279             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
280                 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
281
282                 if ((ct->tuplehash[dir].tuple.src.u3.ip !=
283                      ct->tuplehash[!dir].tuple.dst.u3.ip) ||
284                     (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
285                      ct->tuplehash[dir].tuple.src.u.all !=
286                      ct->tuplehash[!dir].tuple.dst.u.all)) {
287                         err = nf_xfrm_me_harder(state->net, skb, AF_INET);
288                         if (err < 0)
289                                 ret = NF_DROP_ERR(err);
290                 }
291         }
292 #endif
293         return ret;
294 }
295
296 static unsigned int
297 nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb,
298                      const struct nf_hook_state *state)
299 {
300         const struct nf_conn *ct;
301         enum ip_conntrack_info ctinfo;
302         unsigned int ret;
303         int err;
304
305         ret = nf_nat_ipv4_fn(priv, skb, state);
306         if (ret != NF_DROP && ret != NF_STOLEN &&
307             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
308                 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
309
310                 if (ct->tuplehash[dir].tuple.dst.u3.ip !=
311                     ct->tuplehash[!dir].tuple.src.u3.ip) {
312                         err = ip_route_me_harder(state->net, skb, RTN_UNSPEC);
313                         if (err < 0)
314                                 ret = NF_DROP_ERR(err);
315                 }
316 #ifdef CONFIG_XFRM
317                 else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
318                          ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
319                          ct->tuplehash[dir].tuple.dst.u.all !=
320                          ct->tuplehash[!dir].tuple.src.u.all) {
321                         err = nf_xfrm_me_harder(state->net, skb, AF_INET);
322                         if (err < 0)
323                                 ret = NF_DROP_ERR(err);
324                 }
325 #endif
326         }
327         return ret;
328 }
329
330 static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
331         /* Before packet filtering, change destination */
332         {
333                 .hook           = nf_nat_ipv4_in,
334                 .pf             = NFPROTO_IPV4,
335                 .hooknum        = NF_INET_PRE_ROUTING,
336                 .priority       = NF_IP_PRI_NAT_DST,
337         },
338         /* After packet filtering, change source */
339         {
340                 .hook           = nf_nat_ipv4_out,
341                 .pf             = NFPROTO_IPV4,
342                 .hooknum        = NF_INET_POST_ROUTING,
343                 .priority       = NF_IP_PRI_NAT_SRC,
344         },
345         /* Before packet filtering, change destination */
346         {
347                 .hook           = nf_nat_ipv4_local_fn,
348                 .pf             = NFPROTO_IPV4,
349                 .hooknum        = NF_INET_LOCAL_OUT,
350                 .priority       = NF_IP_PRI_NAT_DST,
351         },
352         /* After packet filtering, change source */
353         {
354                 .hook           = nf_nat_ipv4_fn,
355                 .pf             = NFPROTO_IPV4,
356                 .hooknum        = NF_INET_LOCAL_IN,
357                 .priority       = NF_IP_PRI_NAT_SRC,
358         },
359 };
360
361 int nf_nat_l3proto_ipv4_register_fn(struct net *net, const struct nf_hook_ops *ops)
362 {
363         return nf_nat_register_fn(net, ops, nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops));
364 }
365 EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv4_register_fn);
366
367 void nf_nat_l3proto_ipv4_unregister_fn(struct net *net, const struct nf_hook_ops *ops)
368 {
369         nf_nat_unregister_fn(net, ops, ARRAY_SIZE(nf_nat_ipv4_ops));
370 }
371 EXPORT_SYMBOL_GPL(nf_nat_l3proto_ipv4_unregister_fn);
372
373 static int __init nf_nat_l3proto_ipv4_init(void)
374 {
375         return nf_nat_l3proto_register(&nf_nat_l3proto_ipv4);
376 }
377
378 static void __exit nf_nat_l3proto_ipv4_exit(void)
379 {
380         nf_nat_l3proto_unregister(&nf_nat_l3proto_ipv4);
381 }
382
383 MODULE_LICENSE("GPL");
384 MODULE_ALIAS("nf-nat-" __stringify(AF_INET));
385
386 module_init(nf_nat_l3proto_ipv4_init);
387 module_exit(nf_nat_l3proto_ipv4_exit);