Linux 3.9-rc8
[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
334         if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
335                 sin6.sin6_scope_id = sk->sk_bound_dev_if;
336         else
337                 sin6.sin6_scope_id = 0;
338
339         return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
340 }
341
342 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
343
344 #include <linux/netfilter/nfnetlink.h>
345 #include <linux/netfilter/nfnetlink_conntrack.h>
346
347 static int ipv6_tuple_to_nlattr(struct sk_buff *skb,
348                                 const struct nf_conntrack_tuple *tuple)
349 {
350         if (nla_put(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
351                     &tuple->src.u3.ip6) ||
352             nla_put(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
353                     &tuple->dst.u3.ip6))
354                 goto nla_put_failure;
355         return 0;
356
357 nla_put_failure:
358         return -1;
359 }
360
361 static const struct nla_policy ipv6_nla_policy[CTA_IP_MAX+1] = {
362         [CTA_IP_V6_SRC] = { .len = sizeof(u_int32_t)*4 },
363         [CTA_IP_V6_DST] = { .len = sizeof(u_int32_t)*4 },
364 };
365
366 static int ipv6_nlattr_to_tuple(struct nlattr *tb[],
367                                 struct nf_conntrack_tuple *t)
368 {
369         if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST])
370                 return -EINVAL;
371
372         memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]),
373                sizeof(u_int32_t) * 4);
374         memcpy(&t->dst.u3.ip6, nla_data(tb[CTA_IP_V6_DST]),
375                sizeof(u_int32_t) * 4);
376
377         return 0;
378 }
379
380 static int ipv6_nlattr_tuple_size(void)
381 {
382         return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1);
383 }
384 #endif
385
386 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
387         .l3proto                = PF_INET6,
388         .name                   = "ipv6",
389         .pkt_to_tuple           = ipv6_pkt_to_tuple,
390         .invert_tuple           = ipv6_invert_tuple,
391         .print_tuple            = ipv6_print_tuple,
392         .get_l4proto            = ipv6_get_l4proto,
393 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
394         .tuple_to_nlattr        = ipv6_tuple_to_nlattr,
395         .nlattr_tuple_size      = ipv6_nlattr_tuple_size,
396         .nlattr_to_tuple        = ipv6_nlattr_to_tuple,
397         .nla_policy             = ipv6_nla_policy,
398 #endif
399         .me                     = THIS_MODULE,
400 };
401
402 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
403 MODULE_LICENSE("GPL");
404 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
405
406 static struct nf_sockopt_ops so_getorigdst6 = {
407         .pf             = NFPROTO_IPV6,
408         .get_optmin     = IP6T_SO_ORIGINAL_DST,
409         .get_optmax     = IP6T_SO_ORIGINAL_DST + 1,
410         .get            = ipv6_getorigdst,
411         .owner          = THIS_MODULE,
412 };
413
414 static int ipv6_net_init(struct net *net)
415 {
416         int ret = 0;
417
418         ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6);
419         if (ret < 0) {
420                 pr_err("nf_conntrack_tcp6: pernet registration failed\n");
421                 goto out;
422         }
423         ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6);
424         if (ret < 0) {
425                 pr_err("nf_conntrack_udp6: pernet registration failed\n");
426                 goto cleanup_tcp6;
427         }
428         ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6);
429         if (ret < 0) {
430                 pr_err("nf_conntrack_icmp6: pernet registration failed\n");
431                 goto cleanup_udp6;
432         }
433         ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6);
434         if (ret < 0) {
435                 pr_err("nf_conntrack_ipv6: pernet registration failed.\n");
436                 goto cleanup_icmpv6;
437         }
438         return 0;
439  cleanup_icmpv6:
440         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
441  cleanup_udp6:
442         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
443  cleanup_tcp6:
444         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
445  out:
446         return ret;
447 }
448
449 static void ipv6_net_exit(struct net *net)
450 {
451         nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6);
452         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6);
453         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6);
454         nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6);
455 }
456
457 static struct pernet_operations ipv6_net_ops = {
458         .init = ipv6_net_init,
459         .exit = ipv6_net_exit,
460 };
461
462 static int __init nf_conntrack_l3proto_ipv6_init(void)
463 {
464         int ret = 0;
465
466         need_conntrack();
467         nf_defrag_ipv6_enable();
468
469         ret = nf_register_sockopt(&so_getorigdst6);
470         if (ret < 0) {
471                 pr_err("Unable to register netfilter socket option\n");
472                 return ret;
473         }
474
475         ret = register_pernet_subsys(&ipv6_net_ops);
476         if (ret < 0)
477                 goto cleanup_sockopt;
478
479         ret = nf_register_hooks(ipv6_conntrack_ops,
480                                 ARRAY_SIZE(ipv6_conntrack_ops));
481         if (ret < 0) {
482                 pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
483                        "hook.\n");
484                 goto cleanup_pernet;
485         }
486
487         ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6);
488         if (ret < 0) {
489                 pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n");
490                 goto cleanup_hooks;
491         }
492
493         ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6);
494         if (ret < 0) {
495                 pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n");
496                 goto cleanup_tcp6;
497         }
498
499         ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6);
500         if (ret < 0) {
501                 pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n");
502                 goto cleanup_udp6;
503         }
504
505         ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6);
506         if (ret < 0) {
507                 pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n");
508                 goto cleanup_icmpv6;
509         }
510         return ret;
511
512  cleanup_icmpv6:
513         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
514  cleanup_udp6:
515         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
516  cleanup_tcp6:
517         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
518  cleanup_hooks:
519         nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
520  cleanup_pernet:
521         unregister_pernet_subsys(&ipv6_net_ops);
522  cleanup_sockopt:
523         nf_unregister_sockopt(&so_getorigdst6);
524         return ret;
525 }
526
527 static void __exit nf_conntrack_l3proto_ipv6_fini(void)
528 {
529         synchronize_net();
530         nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
531         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
532         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6);
533         nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
534         nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
535         unregister_pernet_subsys(&ipv6_net_ops);
536         nf_unregister_sockopt(&so_getorigdst6);
537 }
538
539 module_init(nf_conntrack_l3proto_ipv6_init);
540 module_exit(nf_conntrack_l3proto_ipv6_fini);