Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / netfilter / nf_conntrack_l3proto_ipv6.c
1 /*
2  * Copyright (C)2004 USAGI/WIDE Project
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  * Author:
9  *      Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
10  */
11
12 #include <linux/types.h>
13 #include <linux/ipv6.h>
14 #include <linux/in6.h>
15 #include <linux/netfilter.h>
16 #include <linux/module.h>
17 #include <linux/skbuff.h>
18 #include <linux/icmp.h>
19 #include <net/ipv6.h>
20 #include <net/inet_frag.h>
21
22 #include <linux/netfilter_bridge.h>
23 #include <linux/netfilter_ipv6.h>
24 #include <linux/netfilter_ipv6/ip6_tables.h>
25 #include <net/netfilter/nf_conntrack.h>
26 #include <net/netfilter/nf_conntrack_helper.h>
27 #include <net/netfilter/nf_conntrack_l4proto.h>
28 #include <net/netfilter/nf_conntrack_l3proto.h>
29 #include <net/netfilter/nf_conntrack_core.h>
30 #include <net/netfilter/nf_conntrack_zones.h>
31 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
32 #include <net/netfilter/nf_nat_helper.h>
33 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
34 #include <net/netfilter/nf_log.h>
35
36 static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
37                               struct nf_conntrack_tuple *tuple)
38 {
39         const u_int32_t *ap;
40         u_int32_t _addrs[8];
41
42         ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr),
43                                 sizeof(_addrs), _addrs);
44         if (ap == NULL)
45                 return false;
46
47         memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6));
48         memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6));
49
50         return true;
51 }
52
53 static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
54                               const struct nf_conntrack_tuple *orig)
55 {
56         memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6));
57         memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6));
58
59         return true;
60 }
61
62 static int ipv6_print_tuple(struct seq_file *s,
63                             const struct nf_conntrack_tuple *tuple)
64 {
65         return seq_printf(s, "src=%pI6 dst=%pI6 ",
66                           tuple->src.u3.ip6, tuple->dst.u3.ip6);
67 }
68
69 static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
70                             unsigned int *dataoff, u_int8_t *protonum)
71 {
72         unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
73         __be16 frag_off;
74         int protoff;
75         u8 nexthdr;
76
77         if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
78                           &nexthdr, sizeof(nexthdr)) != 0) {
79                 pr_debug("ip6_conntrack_core: can't get nexthdr\n");
80                 return -NF_ACCEPT;
81         }
82         protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
83         /*
84          * (protoff == skb->len) means the packet has not data, just
85          * IPv6 and possibly extensions headers, but it is tracked anyway
86          */
87         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
88                 pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
89                 return -NF_ACCEPT;
90         }
91
92         *dataoff = protoff;
93         *protonum = nexthdr;
94         return NF_ACCEPT;
95 }
96
97 static unsigned int ipv6_helper(unsigned int hooknum,
98                                 struct sk_buff *skb,
99                                 const struct net_device *in,
100                                 const struct net_device *out,
101                                 int (*okfn)(struct sk_buff *))
102 {
103         struct nf_conn *ct;
104         const struct nf_conn_help *help;
105         const struct nf_conntrack_helper *helper;
106         enum ip_conntrack_info ctinfo;
107         __be16 frag_off;
108         int protoff;
109         u8 nexthdr;
110
111         /* This is where we call the helper: as the packet goes out. */
112         ct = nf_ct_get(skb, &ctinfo);
113         if (!ct || ctinfo == IP_CT_RELATED_REPLY)
114                 return NF_ACCEPT;
115
116         help = nfct_help(ct);
117         if (!help)
118                 return NF_ACCEPT;
119         /* rcu_read_lock()ed by nf_hook_slow */
120         helper = rcu_dereference(help->helper);
121         if (!helper)
122                 return NF_ACCEPT;
123
124         nexthdr = ipv6_hdr(skb)->nexthdr;
125         protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
126                                    &frag_off);
127         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
128                 pr_debug("proto header not found\n");
129                 return NF_ACCEPT;
130         }
131
132         return helper->help(skb, protoff, ct, ctinfo);
133 }
134
135 static unsigned int ipv6_confirm(unsigned int hooknum,
136                                  struct sk_buff *skb,
137                                  const struct net_device *in,
138                                  const struct net_device *out,
139                                  int (*okfn)(struct sk_buff *))
140 {
141         struct nf_conn *ct;
142         enum ip_conntrack_info ctinfo;
143         unsigned char pnum = ipv6_hdr(skb)->nexthdr;
144         int protoff;
145         __be16 frag_off;
146
147         ct = nf_ct_get(skb, &ctinfo);
148         if (!ct || ctinfo == IP_CT_RELATED_REPLY)
149                 goto out;
150
151         protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
152                                    &frag_off);
153         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
154                 pr_debug("proto header not found\n");
155                 goto out;
156         }
157
158         /* adjust seqs for loopback traffic only in outgoing direction */
159         if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
160             !nf_is_loopback_packet(skb)) {
161                 typeof(nf_nat_seq_adjust_hook) seq_adjust;
162
163                 seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
164                 if (!seq_adjust ||
165                     !seq_adjust(skb, ct, ctinfo, protoff)) {
166                         NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
167                         return NF_DROP;
168                 }
169         }
170 out:
171         /* We've seen it coming out the other side: confirm it */
172         return nf_conntrack_confirm(skb);
173 }
174
175 static unsigned int __ipv6_conntrack_in(struct net *net,
176                                         unsigned int hooknum,
177                                         struct sk_buff *skb,
178                                         const struct net_device *in,
179                                         const struct net_device *out,
180                                         int (*okfn)(struct sk_buff *))
181 {
182         struct sk_buff *reasm = skb->nfct_reasm;
183         const struct nf_conn_help *help;
184         struct nf_conn *ct;
185         enum ip_conntrack_info ctinfo;
186
187         /* This packet is fragmented and has reassembled packet. */
188         if (reasm) {
189                 /* Reassembled packet isn't parsed yet ? */
190                 if (!reasm->nfct) {
191                         unsigned int ret;
192
193                         ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm);
194                         if (ret != NF_ACCEPT)
195                                 return ret;
196                 }
197
198                 /* Conntrack helpers need the entire reassembled packet in the
199                  * POST_ROUTING hook. In case of unconfirmed connections NAT
200                  * might reassign a helper, so the entire packet is also
201                  * required.
202                  */
203                 ct = nf_ct_get(reasm, &ctinfo);
204                 if (ct != NULL && !nf_ct_is_untracked(ct)) {
205                         help = nfct_help(ct);
206                         if ((help && help->helper) || !nf_ct_is_confirmed(ct)) {
207                                 nf_conntrack_get_reasm(skb);
208                                 NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
209                                                (struct net_device *)in,
210                                                (struct net_device *)out,
211                                                okfn, NF_IP6_PRI_CONNTRACK + 1);
212                                 return NF_DROP_ERR(-ECANCELED);
213                         }
214                 }
215
216                 nf_conntrack_get(reasm->nfct);
217                 skb->nfct = reasm->nfct;
218                 skb->nfctinfo = reasm->nfctinfo;
219                 return NF_ACCEPT;
220         }
221
222         return nf_conntrack_in(net, PF_INET6, hooknum, skb);
223 }
224
225 static unsigned int ipv6_conntrack_in(unsigned int hooknum,
226                                       struct sk_buff *skb,
227                                       const struct net_device *in,
228                                       const struct net_device *out,
229                                       int (*okfn)(struct sk_buff *))
230 {
231         return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn);
232 }
233
234 static unsigned int ipv6_conntrack_local(unsigned int hooknum,
235                                          struct sk_buff *skb,
236                                          const struct net_device *in,
237                                          const struct net_device *out,
238                                          int (*okfn)(struct sk_buff *))
239 {
240         /* root is playing with raw sockets. */
241         if (skb->len < sizeof(struct ipv6hdr)) {
242                 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
243                 return NF_ACCEPT;
244         }
245         return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn);
246 }
247
248 static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
249         {
250                 .hook           = ipv6_conntrack_in,
251                 .owner          = THIS_MODULE,
252                 .pf             = NFPROTO_IPV6,
253                 .hooknum        = NF_INET_PRE_ROUTING,
254                 .priority       = NF_IP6_PRI_CONNTRACK,
255         },
256         {
257                 .hook           = ipv6_conntrack_local,
258                 .owner          = THIS_MODULE,
259                 .pf             = NFPROTO_IPV6,
260                 .hooknum        = NF_INET_LOCAL_OUT,
261                 .priority       = NF_IP6_PRI_CONNTRACK,
262         },
263         {
264                 .hook           = ipv6_helper,
265                 .owner          = THIS_MODULE,
266                 .pf             = NFPROTO_IPV6,
267                 .hooknum        = NF_INET_POST_ROUTING,
268                 .priority       = NF_IP6_PRI_CONNTRACK_HELPER,
269         },
270         {
271                 .hook           = ipv6_confirm,
272                 .owner          = THIS_MODULE,
273                 .pf             = NFPROTO_IPV6,
274                 .hooknum        = NF_INET_POST_ROUTING,
275                 .priority       = NF_IP6_PRI_LAST,
276         },
277         {
278                 .hook           = ipv6_helper,
279                 .owner          = THIS_MODULE,
280                 .pf             = NFPROTO_IPV6,
281                 .hooknum        = NF_INET_LOCAL_IN,
282                 .priority       = NF_IP6_PRI_CONNTRACK_HELPER,
283         },
284         {
285                 .hook           = ipv6_confirm,
286                 .owner          = THIS_MODULE,
287                 .pf             = NFPROTO_IPV6,
288                 .hooknum        = NF_INET_LOCAL_IN,
289                 .priority       = NF_IP6_PRI_LAST-1,
290         },
291 };
292
293 static int
294 ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
295 {
296         const struct inet_sock *inet = inet_sk(sk);
297         const struct ipv6_pinfo *inet6 = inet6_sk(sk);
298         const struct nf_conntrack_tuple_hash *h;
299         struct sockaddr_in6 sin6;
300         struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
301         struct nf_conn *ct;
302
303         tuple.src.u3.in6 = inet6->rcv_saddr;
304         tuple.src.u.tcp.port = inet->inet_sport;
305         tuple.dst.u3.in6 = inet6->daddr;
306         tuple.dst.u.tcp.port = inet->inet_dport;
307         tuple.dst.protonum = sk->sk_protocol;
308
309         if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
310                 return -ENOPROTOOPT;
311
312         if (*len < 0 || (unsigned int) *len < sizeof(sin6))
313                 return -EINVAL;
314
315         h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple);
316         if (!h) {
317                 pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
318                          &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port),
319                          &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port));
320                 return -ENOENT;
321         }
322
323         ct = nf_ct_tuplehash_to_ctrack(h);
324
325         sin6.sin6_family = AF_INET6;
326         sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
327         sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
328         memcpy(&sin6.sin6_addr,
329                 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
330                                         sizeof(sin6.sin6_addr));
331
332         nf_ct_put(ct);
333         sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
334                                                  sk->sk_bound_dev_if);
335         return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
336 }
337
338 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
339
340 #include <linux/netfilter/nfnetlink.h>
341 #include <linux/netfilter/nfnetlink_conntrack.h>
342
343 static int ipv6_tuple_to_nlattr(struct sk_buff *skb,
344                                 const struct nf_conntrack_tuple *tuple)
345 {
346         if (nla_put(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
347                     &tuple->src.u3.ip6) ||
348             nla_put(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
349                     &tuple->dst.u3.ip6))
350                 goto nla_put_failure;
351         return 0;
352
353 nla_put_failure:
354         return -1;
355 }
356
357 static const struct nla_policy ipv6_nla_policy[CTA_IP_MAX+1] = {
358         [CTA_IP_V6_SRC] = { .len = sizeof(u_int32_t)*4 },
359         [CTA_IP_V6_DST] = { .len = sizeof(u_int32_t)*4 },
360 };
361
362 static int ipv6_nlattr_to_tuple(struct nlattr *tb[],
363                                 struct nf_conntrack_tuple *t)
364 {
365         if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST])
366                 return -EINVAL;
367
368         memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]),
369                sizeof(u_int32_t) * 4);
370         memcpy(&t->dst.u3.ip6, nla_data(tb[CTA_IP_V6_DST]),
371                sizeof(u_int32_t) * 4);
372
373         return 0;
374 }
375
376 static int ipv6_nlattr_tuple_size(void)
377 {
378         return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1);
379 }
380 #endif
381
382 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
383         .l3proto                = PF_INET6,
384         .name                   = "ipv6",
385         .pkt_to_tuple           = ipv6_pkt_to_tuple,
386         .invert_tuple           = ipv6_invert_tuple,
387         .print_tuple            = ipv6_print_tuple,
388         .get_l4proto            = ipv6_get_l4proto,
389 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
390         .tuple_to_nlattr        = ipv6_tuple_to_nlattr,
391         .nlattr_tuple_size      = ipv6_nlattr_tuple_size,
392         .nlattr_to_tuple        = ipv6_nlattr_to_tuple,
393         .nla_policy             = ipv6_nla_policy,
394 #endif
395         .me                     = THIS_MODULE,
396 };
397
398 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
399 MODULE_LICENSE("GPL");
400 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
401
402 static struct nf_sockopt_ops so_getorigdst6 = {
403         .pf             = NFPROTO_IPV6,
404         .get_optmin     = IP6T_SO_ORIGINAL_DST,
405         .get_optmax     = IP6T_SO_ORIGINAL_DST + 1,
406         .get            = ipv6_getorigdst,
407         .owner          = THIS_MODULE,
408 };
409
410 static int ipv6_net_init(struct net *net)
411 {
412         int ret = 0;
413
414         ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6);
415         if (ret < 0) {
416                 pr_err("nf_conntrack_tcp6: pernet registration failed\n");
417                 goto out;
418         }
419         ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6);
420         if (ret < 0) {
421                 pr_err("nf_conntrack_udp6: pernet registration failed\n");
422                 goto cleanup_tcp6;
423         }
424         ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6);
425         if (ret < 0) {
426                 pr_err("nf_conntrack_icmp6: pernet registration failed\n");
427                 goto cleanup_udp6;
428         }
429         ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6);
430         if (ret < 0) {
431                 pr_err("nf_conntrack_ipv6: pernet registration failed.\n");
432                 goto cleanup_icmpv6;
433         }
434         return 0;
435  cleanup_icmpv6:
436         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
437  cleanup_udp6:
438         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
439  cleanup_tcp6:
440         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
441  out:
442         return ret;
443 }
444
445 static void ipv6_net_exit(struct net *net)
446 {
447         nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6);
448         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
449         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
450         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
451 }
452
453 static struct pernet_operations ipv6_net_ops = {
454         .init = ipv6_net_init,
455         .exit = ipv6_net_exit,
456 };
457
458 static int __init nf_conntrack_l3proto_ipv6_init(void)
459 {
460         int ret = 0;
461
462         need_conntrack();
463         nf_defrag_ipv6_enable();
464
465         ret = nf_register_sockopt(&so_getorigdst6);
466         if (ret < 0) {
467                 pr_err("Unable to register netfilter socket option\n");
468                 return ret;
469         }
470
471         ret = register_pernet_subsys(&ipv6_net_ops);
472         if (ret < 0)
473                 goto cleanup_sockopt;
474
475         ret = nf_register_hooks(ipv6_conntrack_ops,
476                                 ARRAY_SIZE(ipv6_conntrack_ops));
477         if (ret < 0) {
478                 pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
479                        "hook.\n");
480                 goto cleanup_pernet;
481         }
482
483         ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6);
484         if (ret < 0) {
485                 pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n");
486                 goto cleanup_hooks;
487         }
488
489         ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6);
490         if (ret < 0) {
491                 pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n");
492                 goto cleanup_tcp6;
493         }
494
495         ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6);
496         if (ret < 0) {
497                 pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n");
498                 goto cleanup_udp6;
499         }
500
501         ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6);
502         if (ret < 0) {
503                 pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n");
504                 goto cleanup_icmpv6;
505         }
506         return ret;
507
508  cleanup_icmpv6:
509         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
510  cleanup_udp6:
511         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
512  cleanup_tcp6:
513         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
514  cleanup_hooks:
515         nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
516  cleanup_pernet:
517         unregister_pernet_subsys(&ipv6_net_ops);
518  cleanup_sockopt:
519         nf_unregister_sockopt(&so_getorigdst6);
520         return ret;
521 }
522
523 static void __exit nf_conntrack_l3proto_ipv6_fini(void)
524 {
525         synchronize_net();
526         nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
527         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
528         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
529         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
530         nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
531         unregister_pernet_subsys(&ipv6_net_ops);
532         nf_unregister_sockopt(&so_getorigdst6);
533 }
534
535 module_init(nf_conntrack_l3proto_ipv6_init);
536 module_exit(nf_conntrack_l3proto_ipv6_fini);