GNU Linux-libre 4.4.299-gnu1
[releases.git] / net / ipv6 / netfilter / nf_nat_l3proto_ipv6.c
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  * Development of IPv6 NAT funded by Astaro.
9  */
10 #include <linux/types.h>
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <linux/ipv6.h>
14 #include <linux/netfilter.h>
15 #include <linux/netfilter_ipv6.h>
16 #include <net/secure_seq.h>
17 #include <net/checksum.h>
18 #include <net/ip6_checksum.h>
19 #include <net/ip6_route.h>
20 #include <net/ipv6.h>
21
22 #include <net/netfilter/nf_conntrack_core.h>
23 #include <net/netfilter/nf_conntrack.h>
24 #include <net/netfilter/nf_nat_core.h>
25 #include <net/netfilter/nf_nat_l3proto.h>
26 #include <net/netfilter/nf_nat_l4proto.h>
27
28 static const struct nf_nat_l3proto nf_nat_l3proto_ipv6;
29
30 #ifdef CONFIG_XFRM
31 static void nf_nat_ipv6_decode_session(struct sk_buff *skb,
32                                        const struct nf_conn *ct,
33                                        enum ip_conntrack_dir dir,
34                                        unsigned long statusbit,
35                                        struct flowi *fl)
36 {
37         const struct nf_conntrack_tuple *t = &ct->tuplehash[dir].tuple;
38         struct flowi6 *fl6 = &fl->u.ip6;
39
40         if (ct->status & statusbit) {
41                 fl6->daddr = t->dst.u3.in6;
42                 if (t->dst.protonum == IPPROTO_TCP ||
43                     t->dst.protonum == IPPROTO_UDP ||
44                     t->dst.protonum == IPPROTO_UDPLITE ||
45                     t->dst.protonum == IPPROTO_DCCP ||
46                     t->dst.protonum == IPPROTO_SCTP)
47                         fl6->fl6_dport = t->dst.u.all;
48         }
49
50         statusbit ^= IPS_NAT_MASK;
51
52         if (ct->status & statusbit) {
53                 fl6->saddr = t->src.u3.in6;
54                 if (t->dst.protonum == IPPROTO_TCP ||
55                     t->dst.protonum == IPPROTO_UDP ||
56                     t->dst.protonum == IPPROTO_UDPLITE ||
57                     t->dst.protonum == IPPROTO_DCCP ||
58                     t->dst.protonum == IPPROTO_SCTP)
59                         fl6->fl6_sport = t->src.u.all;
60         }
61 }
62 #endif
63
64 static bool nf_nat_ipv6_in_range(const struct nf_conntrack_tuple *t,
65                                  const struct nf_nat_range *range)
66 {
67         return ipv6_addr_cmp(&t->src.u3.in6, &range->min_addr.in6) >= 0 &&
68                ipv6_addr_cmp(&t->src.u3.in6, &range->max_addr.in6) <= 0;
69 }
70
71 static u32 nf_nat_ipv6_secure_port(const struct nf_conntrack_tuple *t,
72                                    __be16 dport)
73 {
74         return secure_ipv6_port_ephemeral(t->src.u3.ip6, t->dst.u3.ip6, dport);
75 }
76
77 static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
78                                   unsigned int iphdroff,
79                                   const struct nf_nat_l4proto *l4proto,
80                                   const struct nf_conntrack_tuple *target,
81                                   enum nf_nat_manip_type maniptype)
82 {
83         struct ipv6hdr *ipv6h;
84         __be16 frag_off;
85         int hdroff;
86         u8 nexthdr;
87
88         if (!skb_make_writable(skb, iphdroff + sizeof(*ipv6h)))
89                 return false;
90
91         ipv6h = (void *)skb->data + iphdroff;
92         nexthdr = ipv6h->nexthdr;
93         hdroff = ipv6_skip_exthdr(skb, iphdroff + sizeof(*ipv6h),
94                                   &nexthdr, &frag_off);
95         if (hdroff < 0)
96                 goto manip_addr;
97
98         if ((frag_off & htons(~0x7)) == 0 &&
99             !l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff,
100                                 target, maniptype))
101                 return false;
102
103         /* must reload, offset might have changed */
104         ipv6h = (void *)skb->data + iphdroff;
105
106 manip_addr:
107         if (maniptype == NF_NAT_MANIP_SRC)
108                 ipv6h->saddr = target->src.u3.in6;
109         else
110                 ipv6h->daddr = target->dst.u3.in6;
111
112         return true;
113 }
114
115 static void nf_nat_ipv6_csum_update(struct sk_buff *skb,
116                                     unsigned int iphdroff, __sum16 *check,
117                                     const struct nf_conntrack_tuple *t,
118                                     enum nf_nat_manip_type maniptype)
119 {
120         const struct ipv6hdr *ipv6h = (struct ipv6hdr *)(skb->data + iphdroff);
121         const struct in6_addr *oldip, *newip;
122
123         if (maniptype == NF_NAT_MANIP_SRC) {
124                 oldip = &ipv6h->saddr;
125                 newip = &t->src.u3.in6;
126         } else {
127                 oldip = &ipv6h->daddr;
128                 newip = &t->dst.u3.in6;
129         }
130         inet_proto_csum_replace16(check, skb, oldip->s6_addr32,
131                                   newip->s6_addr32, true);
132 }
133
134 static void nf_nat_ipv6_csum_recalc(struct sk_buff *skb,
135                                     u8 proto, void *data, __sum16 *check,
136                                     int datalen, int oldlen)
137 {
138         const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
139         struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
140
141         if (skb->ip_summed != CHECKSUM_PARTIAL) {
142                 if (!(rt->rt6i_flags & RTF_LOCAL) &&
143                     (!skb->dev || skb->dev->features & NETIF_F_V6_CSUM)) {
144                         skb->ip_summed = CHECKSUM_PARTIAL;
145                         skb->csum_start = skb_headroom(skb) +
146                                           skb_network_offset(skb) +
147                                           (data - (void *)skb->data);
148                         skb->csum_offset = (void *)check - data;
149                         *check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
150                                                   datalen, proto, 0);
151                 } else {
152                         *check = 0;
153                         *check = csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
154                                                  datalen, proto,
155                                                  csum_partial(data, datalen,
156                                                               0));
157                         if (proto == IPPROTO_UDP && !*check)
158                                 *check = CSUM_MANGLED_0;
159                 }
160         } else
161                 inet_proto_csum_replace2(check, skb,
162                                          htons(oldlen), htons(datalen), true);
163 }
164
165 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
166 static int nf_nat_ipv6_nlattr_to_range(struct nlattr *tb[],
167                                        struct nf_nat_range *range)
168 {
169         if (tb[CTA_NAT_V6_MINIP]) {
170                 nla_memcpy(&range->min_addr.ip6, tb[CTA_NAT_V6_MINIP],
171                            sizeof(struct in6_addr));
172                 range->flags |= NF_NAT_RANGE_MAP_IPS;
173         }
174
175         if (tb[CTA_NAT_V6_MAXIP])
176                 nla_memcpy(&range->max_addr.ip6, tb[CTA_NAT_V6_MAXIP],
177                            sizeof(struct in6_addr));
178         else
179                 range->max_addr = range->min_addr;
180
181         return 0;
182 }
183 #endif
184
185 static const struct nf_nat_l3proto nf_nat_l3proto_ipv6 = {
186         .l3proto                = NFPROTO_IPV6,
187         .secure_port            = nf_nat_ipv6_secure_port,
188         .in_range               = nf_nat_ipv6_in_range,
189         .manip_pkt              = nf_nat_ipv6_manip_pkt,
190         .csum_update            = nf_nat_ipv6_csum_update,
191         .csum_recalc            = nf_nat_ipv6_csum_recalc,
192 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
193         .nlattr_to_range        = nf_nat_ipv6_nlattr_to_range,
194 #endif
195 #ifdef CONFIG_XFRM
196         .decode_session = nf_nat_ipv6_decode_session,
197 #endif
198 };
199
200 int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
201                                     struct nf_conn *ct,
202                                     enum ip_conntrack_info ctinfo,
203                                     unsigned int hooknum,
204                                     unsigned int hdrlen)
205 {
206         struct {
207                 struct icmp6hdr icmp6;
208                 struct ipv6hdr  ip6;
209         } *inside;
210         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
211         enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
212         const struct nf_nat_l4proto *l4proto;
213         struct nf_conntrack_tuple target;
214         unsigned long statusbit;
215
216         NF_CT_ASSERT(ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED_REPLY);
217
218         if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
219                 return 0;
220         if (nf_ip6_checksum(skb, hooknum, hdrlen, IPPROTO_ICMPV6))
221                 return 0;
222
223         inside = (void *)skb->data + hdrlen;
224         if (inside->icmp6.icmp6_type == NDISC_REDIRECT) {
225                 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
226                         return 0;
227                 if (ct->status & IPS_NAT_MASK)
228                         return 0;
229         }
230
231         if (manip == NF_NAT_MANIP_SRC)
232                 statusbit = IPS_SRC_NAT;
233         else
234                 statusbit = IPS_DST_NAT;
235
236         /* Invert if this is reply direction */
237         if (dir == IP_CT_DIR_REPLY)
238                 statusbit ^= IPS_NAT_MASK;
239
240         if (!(ct->status & statusbit))
241                 return 1;
242
243         l4proto = __nf_nat_l4proto_find(NFPROTO_IPV6, inside->ip6.nexthdr);
244         if (!nf_nat_ipv6_manip_pkt(skb, hdrlen + sizeof(inside->icmp6),
245                                    l4proto, &ct->tuplehash[!dir].tuple, !manip))
246                 return 0;
247
248         if (skb->ip_summed != CHECKSUM_PARTIAL) {
249                 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
250                 inside = (void *)skb->data + hdrlen;
251                 inside->icmp6.icmp6_cksum = 0;
252                 inside->icmp6.icmp6_cksum =
253                         csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
254                                         skb->len - hdrlen, IPPROTO_ICMPV6,
255                                         csum_partial(&inside->icmp6,
256                                                      skb->len - hdrlen, 0));
257         }
258
259         nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
260         l4proto = __nf_nat_l4proto_find(NFPROTO_IPV6, IPPROTO_ICMPV6);
261         if (!nf_nat_ipv6_manip_pkt(skb, 0, l4proto, &target, manip))
262                 return 0;
263
264         return 1;
265 }
266 EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation);
267
268 unsigned int
269 nf_nat_ipv6_fn(void *priv, struct sk_buff *skb,
270                const struct nf_hook_state *state,
271                unsigned int (*do_chain)(void *priv,
272                                         struct sk_buff *skb,
273                                         const struct nf_hook_state *state,
274                                         struct nf_conn *ct))
275 {
276         struct nf_conn *ct;
277         enum ip_conntrack_info ctinfo;
278         struct nf_conn_nat *nat;
279         enum nf_nat_manip_type maniptype = HOOK2MANIP(state->hook);
280         __be16 frag_off;
281         int hdrlen;
282         u8 nexthdr;
283
284         ct = nf_ct_get(skb, &ctinfo);
285         /* Can't track?  It's not due to stress, or conntrack would
286          * have dropped it.  Hence it's the user's responsibilty to
287          * packet filter it out, or implement conntrack/NAT for that
288          * protocol. 8) --RR
289          */
290         if (!ct)
291                 return NF_ACCEPT;
292
293         /* Don't try to NAT if this packet is not conntracked */
294         if (nf_ct_is_untracked(ct))
295                 return NF_ACCEPT;
296
297         nat = nf_ct_nat_ext_add(ct);
298         if (nat == NULL)
299                 return NF_ACCEPT;
300
301         switch (ctinfo) {
302         case IP_CT_RELATED:
303         case IP_CT_RELATED_REPLY:
304                 nexthdr = ipv6_hdr(skb)->nexthdr;
305                 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
306                                           &nexthdr, &frag_off);
307
308                 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
309                         if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
310                                                              state->hook,
311                                                              hdrlen))
312                                 return NF_DROP;
313                         else
314                                 return NF_ACCEPT;
315                 }
316                 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
317         case IP_CT_NEW:
318                 /* Seen it before?  This can happen for loopback, retrans,
319                  * or local packets.
320                  */
321                 if (!nf_nat_initialized(ct, maniptype)) {
322                         unsigned int ret;
323
324                         ret = do_chain(priv, skb, state, ct);
325                         if (ret != NF_ACCEPT)
326                                 return ret;
327
328                         if (nf_nat_initialized(ct, HOOK2MANIP(state->hook)))
329                                 break;
330
331                         ret = nf_nat_alloc_null_binding(ct, state->hook);
332                         if (ret != NF_ACCEPT)
333                                 return ret;
334                 } else {
335                         pr_debug("Already setup manip %s for ct %p\n",
336                                  maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST",
337                                  ct);
338                         if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out))
339                                 goto oif_changed;
340                 }
341                 break;
342
343         default:
344                 /* ESTABLISHED */
345                 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
346                              ctinfo == IP_CT_ESTABLISHED_REPLY);
347                 if (nf_nat_oif_changed(state->hook, ctinfo, nat, state->out))
348                         goto oif_changed;
349         }
350
351         return nf_nat_packet(ct, ctinfo, state->hook, skb);
352
353 oif_changed:
354         nf_ct_kill_acct(ct, ctinfo, skb);
355         return NF_DROP;
356 }
357 EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn);
358
359 unsigned int
360 nf_nat_ipv6_in(void *priv, struct sk_buff *skb,
361                const struct nf_hook_state *state,
362                unsigned int (*do_chain)(void *priv,
363                                         struct sk_buff *skb,
364                                         const struct nf_hook_state *state,
365                                         struct nf_conn *ct))
366 {
367         unsigned int ret;
368         struct in6_addr daddr = ipv6_hdr(skb)->daddr;
369
370         ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
371         if (ret != NF_DROP && ret != NF_STOLEN &&
372             ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
373                 skb_dst_drop(skb);
374
375         return ret;
376 }
377 EXPORT_SYMBOL_GPL(nf_nat_ipv6_in);
378
379 unsigned int
380 nf_nat_ipv6_out(void *priv, struct sk_buff *skb,
381                 const struct nf_hook_state *state,
382                 unsigned int (*do_chain)(void *priv,
383                                          struct sk_buff *skb,
384                                          const struct nf_hook_state *state,
385                                          struct nf_conn *ct))
386 {
387 #ifdef CONFIG_XFRM
388         const struct nf_conn *ct;
389         enum ip_conntrack_info ctinfo;
390         int err;
391 #endif
392         unsigned int ret;
393
394         /* root is playing with raw sockets. */
395         if (skb->len < sizeof(struct ipv6hdr))
396                 return NF_ACCEPT;
397
398         ret = nf_nat_ipv6_fn(priv, skb, state, do_chain);
399 #ifdef CONFIG_XFRM
400         if (ret != NF_DROP && ret != NF_STOLEN &&
401             !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
402             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
403                 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
404
405                 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
406                                       &ct->tuplehash[!dir].tuple.dst.u3) ||
407                     (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
408                      ct->tuplehash[dir].tuple.src.u.all !=
409                      ct->tuplehash[!dir].tuple.dst.u.all)) {
410                         err = nf_xfrm_me_harder(state->net, skb, AF_INET6);
411                         if (err < 0)
412                                 ret = NF_DROP_ERR(err);
413                 }
414         }
415 #endif
416         return ret;
417 }
418 EXPORT_SYMBOL_GPL(nf_nat_ipv6_out);
419
420 unsigned int
421 nf_nat_ipv6_local_fn(void *priv, struct sk_buff *skb,
422                      const struct nf_hook_state *state,
423                      unsigned int (*do_chain)(void *priv,
424                                               struct sk_buff *skb,
425                                               const struct nf_hook_state *state,
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(priv, skb, state, 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(state->net, 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(state->net, skb, AF_INET6);
454                         if (err < 0)
455                                 ret = NF_DROP_ERR(err);
456                 }
457 #endif
458         }
459         return ret;
460 }
461 EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn);
462
463 static int __init nf_nat_l3proto_ipv6_init(void)
464 {
465         int err;
466
467         err = nf_nat_l4proto_register(NFPROTO_IPV6, &nf_nat_l4proto_icmpv6);
468         if (err < 0)
469                 goto err1;
470         err = nf_nat_l3proto_register(&nf_nat_l3proto_ipv6);
471         if (err < 0)
472                 goto err2;
473         return err;
474
475 err2:
476         nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_icmpv6);
477 err1:
478         return err;
479 }
480
481 static void __exit nf_nat_l3proto_ipv6_exit(void)
482 {
483         nf_nat_l3proto_unregister(&nf_nat_l3proto_ipv6);
484         nf_nat_l4proto_unregister(NFPROTO_IPV6, &nf_nat_l4proto_icmpv6);
485 }
486
487 MODULE_LICENSE("GPL");
488 MODULE_ALIAS("nf-nat-" __stringify(AF_INET6));
489
490 module_init(nf_nat_l3proto_ipv6_init);
491 module_exit(nf_nat_l3proto_ipv6_exit);