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