1a0ae2562SFlorian Westphal // SPDX-License-Identifier: GPL-2.0
28f03dea5SMartin Josefsson 
38f03dea5SMartin Josefsson #include <linux/types.h>
48f03dea5SMartin Josefsson #include <linux/netfilter.h>
58f03dea5SMartin Josefsson #include <linux/module.h>
65a0e3ad6STejun Heo #include <linux/slab.h>
7d62f9ed4SPatrick McHardy #include <linux/mutex.h>
88f03dea5SMartin Josefsson #include <linux/vmalloc.h>
98f03dea5SMartin Josefsson #include <linux/stddef.h>
108f03dea5SMartin Josefsson #include <linux/err.h>
118f03dea5SMartin Josefsson #include <linux/percpu.h>
128f03dea5SMartin Josefsson #include <linux/notifier.h>
138f03dea5SMartin Josefsson #include <linux/kernel.h>
148f03dea5SMartin Josefsson #include <linux/netdevice.h>
158f03dea5SMartin Josefsson 
168f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack.h>
17605dcad6SMartin Josefsson #include <net/netfilter/nf_conntrack_l4proto.h>
188f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack_core.h>
19d035f19fSPablo Neira Ayuso #include <net/netfilter/nf_conntrack_bridge.h>
20c4f3db15SFlorian Westphal #include <net/netfilter/nf_log.h>
218f03dea5SMartin Josefsson 
22a0ae2562SFlorian Westphal #include <linux/ip.h>
23a0ae2562SFlorian Westphal #include <linux/icmp.h>
24a0ae2562SFlorian Westphal #include <linux/sysctl.h>
25a0ae2562SFlorian Westphal #include <net/route.h>
26a0ae2562SFlorian Westphal #include <net/ip.h>
27a0ae2562SFlorian Westphal 
28a0ae2562SFlorian Westphal #include <linux/netfilter_ipv4.h>
29a0ae2562SFlorian Westphal #include <linux/netfilter_ipv6.h>
30a0ae2562SFlorian Westphal #include <linux/netfilter_ipv6/ip6_tables.h>
31a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_helper.h>
32a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_zones.h>
33a0ae2562SFlorian Westphal #include <net/netfilter/nf_conntrack_seqadj.h>
34a0ae2562SFlorian Westphal #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
35a0ae2562SFlorian Westphal #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
36a0ae2562SFlorian Westphal #include <net/netfilter/nf_nat_helper.h>
37a0ae2562SFlorian Westphal #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
38a0ae2562SFlorian Westphal #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
39a0ae2562SFlorian Westphal 
40a0ae2562SFlorian Westphal #include <linux/ipv6.h>
41a0ae2562SFlorian Westphal #include <linux/in6.h>
42a0ae2562SFlorian Westphal #include <net/ipv6.h>
43a0ae2562SFlorian Westphal #include <net/inet_frag.h>
44a0ae2562SFlorian Westphal 
45a0ae2562SFlorian Westphal extern unsigned int nf_conntrack_net_id;
46a0ae2562SFlorian Westphal 
47b19caa0cSPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_mutex);
48d62f9ed4SPatrick McHardy 
49b19caa0cSPatrick McHardy #ifdef CONFIG_SYSCTL
50c4f3db15SFlorian Westphal __printf(5, 6)
51c4f3db15SFlorian Westphal void nf_l4proto_log_invalid(const struct sk_buff *skb,
52c4f3db15SFlorian Westphal 			    struct net *net,
53c4f3db15SFlorian Westphal 			    u16 pf, u8 protonum,
54c4f3db15SFlorian Westphal 			    const char *fmt, ...)
55c4f3db15SFlorian Westphal {
56c4f3db15SFlorian Westphal 	struct va_format vaf;
57c4f3db15SFlorian Westphal 	va_list args;
58c4f3db15SFlorian Westphal 
59d4866805SAndrei Vagin 	if (net->ct.sysctl_log_invalid != protonum &&
60c4f3db15SFlorian Westphal 	    net->ct.sysctl_log_invalid != IPPROTO_RAW)
61c4f3db15SFlorian Westphal 		return;
62c4f3db15SFlorian Westphal 
63c4f3db15SFlorian Westphal 	va_start(args, fmt);
64c4f3db15SFlorian Westphal 	vaf.fmt = fmt;
65c4f3db15SFlorian Westphal 	vaf.va = &args;
66c4f3db15SFlorian Westphal 
67c4f3db15SFlorian Westphal 	nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
68c4f3db15SFlorian Westphal 		      "nf_ct_proto_%d: %pV ", protonum, &vaf);
69c4f3db15SFlorian Westphal 	va_end(args);
70c4f3db15SFlorian Westphal }
71c4f3db15SFlorian Westphal EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid);
723d0b527bSFlorian Westphal 
733d0b527bSFlorian Westphal __printf(3, 4)
743d0b527bSFlorian Westphal void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
753d0b527bSFlorian Westphal 			       const struct nf_conn *ct,
763d0b527bSFlorian Westphal 			       const char *fmt, ...)
773d0b527bSFlorian Westphal {
783d0b527bSFlorian Westphal 	struct va_format vaf;
793d0b527bSFlorian Westphal 	struct net *net;
803d0b527bSFlorian Westphal 	va_list args;
813d0b527bSFlorian Westphal 
823d0b527bSFlorian Westphal 	net = nf_ct_net(ct);
833d0b527bSFlorian Westphal 	if (likely(net->ct.sysctl_log_invalid == 0))
843d0b527bSFlorian Westphal 		return;
853d0b527bSFlorian Westphal 
863d0b527bSFlorian Westphal 	va_start(args, fmt);
873d0b527bSFlorian Westphal 	vaf.fmt = fmt;
883d0b527bSFlorian Westphal 	vaf.va = &args;
893d0b527bSFlorian Westphal 
903d0b527bSFlorian Westphal 	nf_l4proto_log_invalid(skb, net, nf_ct_l3num(ct),
913d0b527bSFlorian Westphal 			       nf_ct_protonum(ct), "%pV", &vaf);
923d0b527bSFlorian Westphal 	va_end(args);
933d0b527bSFlorian Westphal }
943d0b527bSFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid);
95d62f9ed4SPatrick McHardy #endif
96d62f9ed4SPatrick McHardy 
974a60dc74SFlorian Westphal const struct nf_conntrack_l4proto *nf_ct_l4proto_find(u8 l4proto)
988f03dea5SMartin Josefsson {
994a60dc74SFlorian Westphal 	switch (l4proto) {
1004a60dc74SFlorian Westphal 	case IPPROTO_UDP: return &nf_conntrack_l4proto_udp;
1014a60dc74SFlorian Westphal 	case IPPROTO_TCP: return &nf_conntrack_l4proto_tcp;
1024a60dc74SFlorian Westphal 	case IPPROTO_ICMP: return &nf_conntrack_l4proto_icmp;
1034a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP
1044a60dc74SFlorian Westphal 	case IPPROTO_DCCP: return &nf_conntrack_l4proto_dccp;
1054a60dc74SFlorian Westphal #endif
1064a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP
1074a60dc74SFlorian Westphal 	case IPPROTO_SCTP: return &nf_conntrack_l4proto_sctp;
1084a60dc74SFlorian Westphal #endif
1094a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_UDPLITE
1104a60dc74SFlorian Westphal 	case IPPROTO_UDPLITE: return &nf_conntrack_l4proto_udplite;
1114a60dc74SFlorian Westphal #endif
1124a60dc74SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
1134a60dc74SFlorian Westphal 	case IPPROTO_GRE: return &nf_conntrack_l4proto_gre;
1144a60dc74SFlorian Westphal #endif
1154a60dc74SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
1164a60dc74SFlorian Westphal 	case IPPROTO_ICMPV6: return &nf_conntrack_l4proto_icmpv6;
1174a60dc74SFlorian Westphal #endif /* CONFIG_IPV6 */
1184a60dc74SFlorian Westphal 	}
1194a60dc74SFlorian Westphal 
120605dcad6SMartin Josefsson 	return &nf_conntrack_l4proto_generic;
1214a60dc74SFlorian Westphal };
1224a60dc74SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_l4proto_find);
1230e54d217SDavide Caratti 
1243c171f49SPablo Neira Ayuso unsigned int nf_confirm(struct sk_buff *skb, unsigned int protoff,
1253c171f49SPablo Neira Ayuso 			struct nf_conn *ct, enum ip_conntrack_info ctinfo)
126a0ae2562SFlorian Westphal {
127a0ae2562SFlorian Westphal 	const struct nf_conn_help *help;
128a0ae2562SFlorian Westphal 
129a0ae2562SFlorian Westphal 	help = nfct_help(ct);
130827318feSFlorian Westphal 	if (help) {
131827318feSFlorian Westphal 		const struct nf_conntrack_helper *helper;
132827318feSFlorian Westphal 		int ret;
133a0ae2562SFlorian Westphal 
134a0ae2562SFlorian Westphal 		/* rcu_read_lock()ed by nf_hook_thresh */
135a0ae2562SFlorian Westphal 		helper = rcu_dereference(help->helper);
136827318feSFlorian Westphal 		if (helper) {
137827318feSFlorian Westphal 			ret = helper->help(skb,
138827318feSFlorian Westphal 					   protoff,
139a0ae2562SFlorian Westphal 					   ct, ctinfo);
140827318feSFlorian Westphal 			if (ret != NF_ACCEPT)
141827318feSFlorian Westphal 				return ret;
142827318feSFlorian Westphal 		}
143827318feSFlorian Westphal 	}
144827318feSFlorian Westphal 
145827318feSFlorian Westphal 	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
146827318feSFlorian Westphal 	    !nf_is_loopback_packet(skb)) {
147827318feSFlorian Westphal 		if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
148827318feSFlorian Westphal 			NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
149827318feSFlorian Westphal 			return NF_DROP;
150827318feSFlorian Westphal 		}
151827318feSFlorian Westphal 	}
152827318feSFlorian Westphal 
153827318feSFlorian Westphal 	/* We've seen it coming out the other side: confirm it */
154827318feSFlorian Westphal 	return nf_conntrack_confirm(skb);
155a0ae2562SFlorian Westphal }
1563c171f49SPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_confirm);
157a0ae2562SFlorian Westphal 
158a0ae2562SFlorian Westphal static unsigned int ipv4_confirm(void *priv,
159a0ae2562SFlorian Westphal 				 struct sk_buff *skb,
160a0ae2562SFlorian Westphal 				 const struct nf_hook_state *state)
161a0ae2562SFlorian Westphal {
162a0ae2562SFlorian Westphal 	enum ip_conntrack_info ctinfo;
163827318feSFlorian Westphal 	struct nf_conn *ct;
164a0ae2562SFlorian Westphal 
165a0ae2562SFlorian Westphal 	ct = nf_ct_get(skb, &ctinfo);
166a0ae2562SFlorian Westphal 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
167a0ae2562SFlorian Westphal 		return nf_conntrack_confirm(skb);
168827318feSFlorian Westphal 
169827318feSFlorian Westphal 	return nf_confirm(skb,
170827318feSFlorian Westphal 			  skb_network_offset(skb) + ip_hdrlen(skb),
171827318feSFlorian Westphal 			  ct, ctinfo);
172a0ae2562SFlorian Westphal }
173a0ae2562SFlorian Westphal 
174a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv,
175a0ae2562SFlorian Westphal 				      struct sk_buff *skb,
176a0ae2562SFlorian Westphal 				      const struct nf_hook_state *state)
177a0ae2562SFlorian Westphal {
17893e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
179a0ae2562SFlorian Westphal }
180a0ae2562SFlorian Westphal 
181a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv,
182a0ae2562SFlorian Westphal 					 struct sk_buff *skb,
183a0ae2562SFlorian Westphal 					 const struct nf_hook_state *state)
184a0ae2562SFlorian Westphal {
185a0ae2562SFlorian Westphal 	if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
186a0ae2562SFlorian Westphal 		enum ip_conntrack_info ctinfo;
187a0ae2562SFlorian Westphal 		struct nf_conn *tmpl;
188a0ae2562SFlorian Westphal 
189a0ae2562SFlorian Westphal 		tmpl = nf_ct_get(skb, &ctinfo);
190a0ae2562SFlorian Westphal 		if (tmpl && nf_ct_is_template(tmpl)) {
191a0ae2562SFlorian Westphal 			/* when skipping ct, clear templates to avoid fooling
192a0ae2562SFlorian Westphal 			 * later targets/matches
193a0ae2562SFlorian Westphal 			 */
194a0ae2562SFlorian Westphal 			skb->_nfct = 0;
195a0ae2562SFlorian Westphal 			nf_ct_put(tmpl);
196a0ae2562SFlorian Westphal 		}
197a0ae2562SFlorian Westphal 		return NF_ACCEPT;
198a0ae2562SFlorian Westphal 	}
199a0ae2562SFlorian Westphal 
20093e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
201a0ae2562SFlorian Westphal }
202a0ae2562SFlorian Westphal 
203a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so
204a0ae2562SFlorian Westphal  * make it the first hook.
205a0ae2562SFlorian Westphal  */
206a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = {
207a0ae2562SFlorian Westphal 	{
208a0ae2562SFlorian Westphal 		.hook		= ipv4_conntrack_in,
209a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
210a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_PRE_ROUTING,
211a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK,
212a0ae2562SFlorian Westphal 	},
213a0ae2562SFlorian Westphal 	{
214a0ae2562SFlorian Westphal 		.hook		= ipv4_conntrack_local,
215a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
216a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_OUT,
217a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK,
218a0ae2562SFlorian Westphal 	},
219a0ae2562SFlorian Westphal 	{
220a0ae2562SFlorian Westphal 		.hook		= ipv4_confirm,
221a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
222a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_POST_ROUTING,
223a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
224a0ae2562SFlorian Westphal 	},
225a0ae2562SFlorian Westphal 	{
226a0ae2562SFlorian Westphal 		.hook		= ipv4_confirm,
227a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
228a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_IN,
229a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
230a0ae2562SFlorian Westphal 	},
231a0ae2562SFlorian Westphal };
232a0ae2562SFlorian Westphal 
233a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't
234a0ae2562SFlorian Westphal  * blame them).
235a0ae2562SFlorian Westphal  * Reversing the socket's dst/src point of view gives us the reply
236a0ae2562SFlorian Westphal  * mapping.
237a0ae2562SFlorian Westphal  */
238a0ae2562SFlorian Westphal static int
239a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len)
240a0ae2562SFlorian Westphal {
241a0ae2562SFlorian Westphal 	const struct inet_sock *inet = inet_sk(sk);
242a0ae2562SFlorian Westphal 	const struct nf_conntrack_tuple_hash *h;
243a0ae2562SFlorian Westphal 	struct nf_conntrack_tuple tuple;
244a0ae2562SFlorian Westphal 
245a0ae2562SFlorian Westphal 	memset(&tuple, 0, sizeof(tuple));
246a0ae2562SFlorian Westphal 
247a0ae2562SFlorian Westphal 	lock_sock(sk);
248a0ae2562SFlorian Westphal 	tuple.src.u3.ip = inet->inet_rcv_saddr;
249a0ae2562SFlorian Westphal 	tuple.src.u.tcp.port = inet->inet_sport;
250a0ae2562SFlorian Westphal 	tuple.dst.u3.ip = inet->inet_daddr;
251a0ae2562SFlorian Westphal 	tuple.dst.u.tcp.port = inet->inet_dport;
252a0ae2562SFlorian Westphal 	tuple.src.l3num = PF_INET;
253a0ae2562SFlorian Westphal 	tuple.dst.protonum = sk->sk_protocol;
254a0ae2562SFlorian Westphal 	release_sock(sk);
255a0ae2562SFlorian Westphal 
256a0ae2562SFlorian Westphal 	/* We only do TCP and SCTP at the moment: is there a better way? */
257a0ae2562SFlorian Westphal 	if (tuple.dst.protonum != IPPROTO_TCP &&
258a0ae2562SFlorian Westphal 	    tuple.dst.protonum != IPPROTO_SCTP) {
259a0ae2562SFlorian Westphal 		pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
260a0ae2562SFlorian Westphal 		return -ENOPROTOOPT;
261a0ae2562SFlorian Westphal 	}
262a0ae2562SFlorian Westphal 
263a0ae2562SFlorian Westphal 	if ((unsigned int)*len < sizeof(struct sockaddr_in)) {
264a0ae2562SFlorian Westphal 		pr_debug("SO_ORIGINAL_DST: len %d not %zu\n",
265a0ae2562SFlorian Westphal 			 *len, sizeof(struct sockaddr_in));
266a0ae2562SFlorian Westphal 		return -EINVAL;
267a0ae2562SFlorian Westphal 	}
268a0ae2562SFlorian Westphal 
269a0ae2562SFlorian Westphal 	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
270a0ae2562SFlorian Westphal 	if (h) {
271a0ae2562SFlorian Westphal 		struct sockaddr_in sin;
272a0ae2562SFlorian Westphal 		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
273a0ae2562SFlorian Westphal 
274a0ae2562SFlorian Westphal 		sin.sin_family = AF_INET;
275a0ae2562SFlorian Westphal 		sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
276a0ae2562SFlorian Westphal 			.tuple.dst.u.tcp.port;
277a0ae2562SFlorian Westphal 		sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
278a0ae2562SFlorian Westphal 			.tuple.dst.u3.ip;
279a0ae2562SFlorian Westphal 		memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
280a0ae2562SFlorian Westphal 
281a0ae2562SFlorian Westphal 		pr_debug("SO_ORIGINAL_DST: %pI4 %u\n",
282a0ae2562SFlorian Westphal 			 &sin.sin_addr.s_addr, ntohs(sin.sin_port));
283a0ae2562SFlorian Westphal 		nf_ct_put(ct);
284a0ae2562SFlorian Westphal 		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
285a0ae2562SFlorian Westphal 			return -EFAULT;
286a0ae2562SFlorian Westphal 		else
287a0ae2562SFlorian Westphal 			return 0;
288a0ae2562SFlorian Westphal 	}
289a0ae2562SFlorian Westphal 	pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n",
290a0ae2562SFlorian Westphal 		 &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port),
291a0ae2562SFlorian Westphal 		 &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port));
292a0ae2562SFlorian Westphal 	return -ENOENT;
293a0ae2562SFlorian Westphal }
294a0ae2562SFlorian Westphal 
295a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = {
296a0ae2562SFlorian Westphal 	.pf		= PF_INET,
297a0ae2562SFlorian Westphal 	.get_optmin	= SO_ORIGINAL_DST,
298a0ae2562SFlorian Westphal 	.get_optmax	= SO_ORIGINAL_DST + 1,
299a0ae2562SFlorian Westphal 	.get		= getorigdst,
300a0ae2562SFlorian Westphal 	.owner		= THIS_MODULE,
301a0ae2562SFlorian Westphal };
302a0ae2562SFlorian Westphal 
303a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
304a0ae2562SFlorian Westphal static int
305a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
306a0ae2562SFlorian Westphal {
307a0ae2562SFlorian Westphal 	struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
308a0ae2562SFlorian Westphal 	const struct ipv6_pinfo *inet6 = inet6_sk(sk);
309a0ae2562SFlorian Westphal 	const struct inet_sock *inet = inet_sk(sk);
310a0ae2562SFlorian Westphal 	const struct nf_conntrack_tuple_hash *h;
311a0ae2562SFlorian Westphal 	struct sockaddr_in6 sin6;
312a0ae2562SFlorian Westphal 	struct nf_conn *ct;
313a0ae2562SFlorian Westphal 	__be32 flow_label;
314a0ae2562SFlorian Westphal 	int bound_dev_if;
315a0ae2562SFlorian Westphal 
316a0ae2562SFlorian Westphal 	lock_sock(sk);
317a0ae2562SFlorian Westphal 	tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
318a0ae2562SFlorian Westphal 	tuple.src.u.tcp.port = inet->inet_sport;
319a0ae2562SFlorian Westphal 	tuple.dst.u3.in6 = sk->sk_v6_daddr;
320a0ae2562SFlorian Westphal 	tuple.dst.u.tcp.port = inet->inet_dport;
321a0ae2562SFlorian Westphal 	tuple.dst.protonum = sk->sk_protocol;
322a0ae2562SFlorian Westphal 	bound_dev_if = sk->sk_bound_dev_if;
323a0ae2562SFlorian Westphal 	flow_label = inet6->flow_label;
324a0ae2562SFlorian Westphal 	release_sock(sk);
325a0ae2562SFlorian Westphal 
326a0ae2562SFlorian Westphal 	if (tuple.dst.protonum != IPPROTO_TCP &&
327a0ae2562SFlorian Westphal 	    tuple.dst.protonum != IPPROTO_SCTP)
328a0ae2562SFlorian Westphal 		return -ENOPROTOOPT;
329a0ae2562SFlorian Westphal 
330a0ae2562SFlorian Westphal 	if (*len < 0 || (unsigned int)*len < sizeof(sin6))
331a0ae2562SFlorian Westphal 		return -EINVAL;
332a0ae2562SFlorian Westphal 
333a0ae2562SFlorian Westphal 	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
334a0ae2562SFlorian Westphal 	if (!h) {
335a0ae2562SFlorian Westphal 		pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
336a0ae2562SFlorian Westphal 			 &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port),
337a0ae2562SFlorian Westphal 			 &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port));
338a0ae2562SFlorian Westphal 		return -ENOENT;
339a0ae2562SFlorian Westphal 	}
340a0ae2562SFlorian Westphal 
341a0ae2562SFlorian Westphal 	ct = nf_ct_tuplehash_to_ctrack(h);
342a0ae2562SFlorian Westphal 
343a0ae2562SFlorian Westphal 	sin6.sin6_family = AF_INET6;
344a0ae2562SFlorian Westphal 	sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
345a0ae2562SFlorian Westphal 	sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
346a0ae2562SFlorian Westphal 	memcpy(&sin6.sin6_addr,
347a0ae2562SFlorian Westphal 	       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
348a0ae2562SFlorian Westphal 	       sizeof(sin6.sin6_addr));
349a0ae2562SFlorian Westphal 
350a0ae2562SFlorian Westphal 	nf_ct_put(ct);
351a0ae2562SFlorian Westphal 	sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
352a0ae2562SFlorian Westphal 	return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
353a0ae2562SFlorian Westphal }
354a0ae2562SFlorian Westphal 
355a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = {
356a0ae2562SFlorian Westphal 	.pf		= NFPROTO_IPV6,
357a0ae2562SFlorian Westphal 	.get_optmin	= IP6T_SO_ORIGINAL_DST,
358a0ae2562SFlorian Westphal 	.get_optmax	= IP6T_SO_ORIGINAL_DST + 1,
359a0ae2562SFlorian Westphal 	.get		= ipv6_getorigdst,
360a0ae2562SFlorian Westphal 	.owner		= THIS_MODULE,
361a0ae2562SFlorian Westphal };
362a0ae2562SFlorian Westphal 
363a0ae2562SFlorian Westphal static unsigned int ipv6_confirm(void *priv,
364a0ae2562SFlorian Westphal 				 struct sk_buff *skb,
365a0ae2562SFlorian Westphal 				 const struct nf_hook_state *state)
366a0ae2562SFlorian Westphal {
367a0ae2562SFlorian Westphal 	struct nf_conn *ct;
368a0ae2562SFlorian Westphal 	enum ip_conntrack_info ctinfo;
369a0ae2562SFlorian Westphal 	unsigned char pnum = ipv6_hdr(skb)->nexthdr;
370a0ae2562SFlorian Westphal 	__be16 frag_off;
371827318feSFlorian Westphal 	int protoff;
372a0ae2562SFlorian Westphal 
373a0ae2562SFlorian Westphal 	ct = nf_ct_get(skb, &ctinfo);
374a0ae2562SFlorian Westphal 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
375827318feSFlorian Westphal 		return nf_conntrack_confirm(skb);
376a0ae2562SFlorian Westphal 
377a0ae2562SFlorian Westphal 	protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
378a0ae2562SFlorian Westphal 				   &frag_off);
379a0ae2562SFlorian Westphal 	if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
380a0ae2562SFlorian Westphal 		pr_debug("proto header not found\n");
381827318feSFlorian Westphal 		return nf_conntrack_confirm(skb);
382a0ae2562SFlorian Westphal 	}
383a0ae2562SFlorian Westphal 
384827318feSFlorian Westphal 	return nf_confirm(skb, protoff, ct, ctinfo);
385a0ae2562SFlorian Westphal }
386a0ae2562SFlorian Westphal 
387a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv,
388a0ae2562SFlorian Westphal 				      struct sk_buff *skb,
389a0ae2562SFlorian Westphal 				      const struct nf_hook_state *state)
390a0ae2562SFlorian Westphal {
39193e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
392a0ae2562SFlorian Westphal }
393a0ae2562SFlorian Westphal 
394a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv,
395a0ae2562SFlorian Westphal 					 struct sk_buff *skb,
396a0ae2562SFlorian Westphal 					 const struct nf_hook_state *state)
397a0ae2562SFlorian Westphal {
39893e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
399a0ae2562SFlorian Westphal }
400a0ae2562SFlorian Westphal 
401a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = {
402a0ae2562SFlorian Westphal 	{
403a0ae2562SFlorian Westphal 		.hook		= ipv6_conntrack_in,
404a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
405a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_PRE_ROUTING,
406a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_CONNTRACK,
407a0ae2562SFlorian Westphal 	},
408a0ae2562SFlorian Westphal 	{
409a0ae2562SFlorian Westphal 		.hook		= ipv6_conntrack_local,
410a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
411a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_OUT,
412a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_CONNTRACK,
413a0ae2562SFlorian Westphal 	},
414a0ae2562SFlorian Westphal 	{
415a0ae2562SFlorian Westphal 		.hook		= ipv6_confirm,
416a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
417a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_POST_ROUTING,
418a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_LAST,
419a0ae2562SFlorian Westphal 	},
420a0ae2562SFlorian Westphal 	{
421a0ae2562SFlorian Westphal 		.hook		= ipv6_confirm,
422a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
423a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_IN,
424a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_LAST - 1,
425a0ae2562SFlorian Westphal 	},
426a0ae2562SFlorian Westphal };
427a0ae2562SFlorian Westphal #endif
428a0ae2562SFlorian Westphal 
429f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto)
430f94e6380SFlorian Westphal {
431f94e6380SFlorian Westphal 	u8 nfproto = (unsigned long)_nfproto;
432f94e6380SFlorian Westphal 
433f94e6380SFlorian Westphal 	if (nf_ct_l3num(ct) != nfproto)
434f94e6380SFlorian Westphal 		return 0;
435f94e6380SFlorian Westphal 
436f94e6380SFlorian Westphal 	if (nf_ct_protonum(ct) == IPPROTO_TCP &&
437f94e6380SFlorian Westphal 	    ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
438f94e6380SFlorian Westphal 		ct->proto.tcp.seen[0].td_maxwin = 0;
439f94e6380SFlorian Westphal 		ct->proto.tcp.seen[1].td_maxwin = 0;
440f94e6380SFlorian Westphal 	}
441f94e6380SFlorian Westphal 
442f94e6380SFlorian Westphal 	return 0;
443f94e6380SFlorian Westphal }
444f94e6380SFlorian Westphal 
445d035f19fSPablo Neira Ayuso static struct nf_ct_bridge_info *nf_ct_bridge_info;
446d035f19fSPablo Neira Ayuso 
447a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
448a0ae2562SFlorian Westphal {
449a0ae2562SFlorian Westphal 	struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
450d035f19fSPablo Neira Ayuso 	bool fixup_needed = false, retry = true;
451a0ae2562SFlorian Westphal 	int err = 0;
452d035f19fSPablo Neira Ayuso retry:
453a0ae2562SFlorian Westphal 	mutex_lock(&nf_ct_proto_mutex);
454a0ae2562SFlorian Westphal 
455a0ae2562SFlorian Westphal 	switch (nfproto) {
456a0ae2562SFlorian Westphal 	case NFPROTO_IPV4:
457a0ae2562SFlorian Westphal 		cnet->users4++;
458a0ae2562SFlorian Westphal 		if (cnet->users4 > 1)
459a0ae2562SFlorian Westphal 			goto out_unlock;
460a0ae2562SFlorian Westphal 		err = nf_defrag_ipv4_enable(net);
461a0ae2562SFlorian Westphal 		if (err) {
462a0ae2562SFlorian Westphal 			cnet->users4 = 0;
463a0ae2562SFlorian Westphal 			goto out_unlock;
464a0ae2562SFlorian Westphal 		}
465a0ae2562SFlorian Westphal 
466a0ae2562SFlorian Westphal 		err = nf_register_net_hooks(net, ipv4_conntrack_ops,
467a0ae2562SFlorian Westphal 					    ARRAY_SIZE(ipv4_conntrack_ops));
468a0ae2562SFlorian Westphal 		if (err)
469a0ae2562SFlorian Westphal 			cnet->users4 = 0;
470f94e6380SFlorian Westphal 		else
471f94e6380SFlorian Westphal 			fixup_needed = true;
472a0ae2562SFlorian Westphal 		break;
473a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
474a0ae2562SFlorian Westphal 	case NFPROTO_IPV6:
475a0ae2562SFlorian Westphal 		cnet->users6++;
476a0ae2562SFlorian Westphal 		if (cnet->users6 > 1)
477a0ae2562SFlorian Westphal 			goto out_unlock;
478a0ae2562SFlorian Westphal 		err = nf_defrag_ipv6_enable(net);
479a0ae2562SFlorian Westphal 		if (err < 0) {
480a0ae2562SFlorian Westphal 			cnet->users6 = 0;
481a0ae2562SFlorian Westphal 			goto out_unlock;
482a0ae2562SFlorian Westphal 		}
483a0ae2562SFlorian Westphal 
484a0ae2562SFlorian Westphal 		err = nf_register_net_hooks(net, ipv6_conntrack_ops,
485a0ae2562SFlorian Westphal 					    ARRAY_SIZE(ipv6_conntrack_ops));
486a0ae2562SFlorian Westphal 		if (err)
487a0ae2562SFlorian Westphal 			cnet->users6 = 0;
488f94e6380SFlorian Westphal 		else
489f94e6380SFlorian Westphal 			fixup_needed = true;
490a0ae2562SFlorian Westphal 		break;
491a0ae2562SFlorian Westphal #endif
492d035f19fSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
493d035f19fSPablo Neira Ayuso 		if (!nf_ct_bridge_info) {
494d035f19fSPablo Neira Ayuso 			if (!retry) {
495d035f19fSPablo Neira Ayuso 				err = -EPROTO;
496d035f19fSPablo Neira Ayuso 				goto out_unlock;
497d035f19fSPablo Neira Ayuso 			}
498d035f19fSPablo Neira Ayuso 			mutex_unlock(&nf_ct_proto_mutex);
499d035f19fSPablo Neira Ayuso 			request_module("nf_conntrack_bridge");
500d035f19fSPablo Neira Ayuso 			retry = false;
501d035f19fSPablo Neira Ayuso 			goto retry;
502d035f19fSPablo Neira Ayuso 		}
503d035f19fSPablo Neira Ayuso 		if (!try_module_get(nf_ct_bridge_info->me)) {
504d035f19fSPablo Neira Ayuso 			err = -EPROTO;
505d035f19fSPablo Neira Ayuso 			goto out_unlock;
506d035f19fSPablo Neira Ayuso 		}
507d035f19fSPablo Neira Ayuso 		cnet->users_bridge++;
508d035f19fSPablo Neira Ayuso 		if (cnet->users_bridge > 1)
509d035f19fSPablo Neira Ayuso 			goto out_unlock;
510d035f19fSPablo Neira Ayuso 
511d035f19fSPablo Neira Ayuso 		err = nf_register_net_hooks(net, nf_ct_bridge_info->ops,
512d035f19fSPablo Neira Ayuso 					    nf_ct_bridge_info->ops_size);
513d035f19fSPablo Neira Ayuso 		if (err)
514d035f19fSPablo Neira Ayuso 			cnet->users_bridge = 0;
515d035f19fSPablo Neira Ayuso 		else
516d035f19fSPablo Neira Ayuso 			fixup_needed = true;
517d035f19fSPablo Neira Ayuso 		break;
518a0ae2562SFlorian Westphal 	default:
519a0ae2562SFlorian Westphal 		err = -EPROTO;
520a0ae2562SFlorian Westphal 		break;
521a0ae2562SFlorian Westphal 	}
522a0ae2562SFlorian Westphal  out_unlock:
523a0ae2562SFlorian Westphal 	mutex_unlock(&nf_ct_proto_mutex);
524f94e6380SFlorian Westphal 
525f94e6380SFlorian Westphal 	if (fixup_needed)
526f94e6380SFlorian Westphal 		nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup,
527f94e6380SFlorian Westphal 					  (void *)(unsigned long)nfproto, 0, 0);
528f94e6380SFlorian Westphal 
529a0ae2562SFlorian Westphal 	return err;
530a0ae2562SFlorian Westphal }
531a0ae2562SFlorian Westphal 
532a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
533a0ae2562SFlorian Westphal {
534a0ae2562SFlorian Westphal 	struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
535a0ae2562SFlorian Westphal 
536a0ae2562SFlorian Westphal 	mutex_lock(&nf_ct_proto_mutex);
537a0ae2562SFlorian Westphal 	switch (nfproto) {
538a0ae2562SFlorian Westphal 	case NFPROTO_IPV4:
539de8c1211SFlorian Westphal 		if (cnet->users4 && (--cnet->users4 == 0)) {
540a0ae2562SFlorian Westphal 			nf_unregister_net_hooks(net, ipv4_conntrack_ops,
541a0ae2562SFlorian Westphal 						ARRAY_SIZE(ipv4_conntrack_ops));
542de8c1211SFlorian Westphal 			nf_defrag_ipv4_disable(net);
543de8c1211SFlorian Westphal 		}
544a0ae2562SFlorian Westphal 		break;
545a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
546a0ae2562SFlorian Westphal 	case NFPROTO_IPV6:
547de8c1211SFlorian Westphal 		if (cnet->users6 && (--cnet->users6 == 0)) {
548a0ae2562SFlorian Westphal 			nf_unregister_net_hooks(net, ipv6_conntrack_ops,
549a0ae2562SFlorian Westphal 						ARRAY_SIZE(ipv6_conntrack_ops));
550de8c1211SFlorian Westphal 			nf_defrag_ipv6_disable(net);
551de8c1211SFlorian Westphal 		}
552a0ae2562SFlorian Westphal 		break;
553a0ae2562SFlorian Westphal #endif
554d035f19fSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
555d035f19fSPablo Neira Ayuso 		if (!nf_ct_bridge_info)
556d035f19fSPablo Neira Ayuso 			break;
557d035f19fSPablo Neira Ayuso 		if (cnet->users_bridge && (--cnet->users_bridge == 0))
558d035f19fSPablo Neira Ayuso 			nf_unregister_net_hooks(net, nf_ct_bridge_info->ops,
559d035f19fSPablo Neira Ayuso 						nf_ct_bridge_info->ops_size);
560a0ae2562SFlorian Westphal 
561d035f19fSPablo Neira Ayuso 		module_put(nf_ct_bridge_info->me);
562d035f19fSPablo Neira Ayuso 		break;
563d035f19fSPablo Neira Ayuso 	}
564a0ae2562SFlorian Westphal 	mutex_unlock(&nf_ct_proto_mutex);
565a0ae2562SFlorian Westphal }
566a0ae2562SFlorian Westphal 
567af9573beSPablo Neira Ayuso static int nf_ct_netns_inet_get(struct net *net)
568a0ae2562SFlorian Westphal {
569a0ae2562SFlorian Westphal 	int err;
570a0ae2562SFlorian Westphal 
571a0ae2562SFlorian Westphal 	err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
572526e81b9SEelco Chaudron #if IS_ENABLED(CONFIG_IPV6)
573a0ae2562SFlorian Westphal 	if (err < 0)
574a0ae2562SFlorian Westphal 		goto err1;
575a0ae2562SFlorian Westphal 	err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
576a0ae2562SFlorian Westphal 	if (err < 0)
577a0ae2562SFlorian Westphal 		goto err2;
578a0ae2562SFlorian Westphal 
579af9573beSPablo Neira Ayuso 	return err;
580a0ae2562SFlorian Westphal err2:
581a0ae2562SFlorian Westphal 	nf_ct_netns_put(net, NFPROTO_IPV4);
582a0ae2562SFlorian Westphal err1:
583526e81b9SEelco Chaudron #endif
584a0ae2562SFlorian Westphal 	return err;
585a0ae2562SFlorian Westphal }
586af9573beSPablo Neira Ayuso 
587af9573beSPablo Neira Ayuso int nf_ct_netns_get(struct net *net, u8 nfproto)
588af9573beSPablo Neira Ayuso {
589af9573beSPablo Neira Ayuso 	int err;
590af9573beSPablo Neira Ayuso 
591af9573beSPablo Neira Ayuso 	switch (nfproto) {
592af9573beSPablo Neira Ayuso 	case NFPROTO_INET:
593af9573beSPablo Neira Ayuso 		err = nf_ct_netns_inet_get(net);
594af9573beSPablo Neira Ayuso 		break;
595af9573beSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
596af9573beSPablo Neira Ayuso 		err = nf_ct_netns_do_get(net, NFPROTO_BRIDGE);
597af9573beSPablo Neira Ayuso 		if (err < 0)
598af9573beSPablo Neira Ayuso 			return err;
599af9573beSPablo Neira Ayuso 
600af9573beSPablo Neira Ayuso 		err = nf_ct_netns_inet_get(net);
601af9573beSPablo Neira Ayuso 		if (err < 0) {
602af9573beSPablo Neira Ayuso 			nf_ct_netns_put(net, NFPROTO_BRIDGE);
603af9573beSPablo Neira Ayuso 			return err;
604af9573beSPablo Neira Ayuso 		}
605af9573beSPablo Neira Ayuso 		break;
606af9573beSPablo Neira Ayuso 	default:
607af9573beSPablo Neira Ayuso 		err = nf_ct_netns_do_get(net, nfproto);
608af9573beSPablo Neira Ayuso 		break;
609af9573beSPablo Neira Ayuso 	}
610af9573beSPablo Neira Ayuso 	return err;
611af9573beSPablo Neira Ayuso }
612a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get);
613a0ae2562SFlorian Westphal 
614a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto)
615a0ae2562SFlorian Westphal {
616af9573beSPablo Neira Ayuso 	switch (nfproto) {
617af9573beSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
618af9573beSPablo Neira Ayuso 		nf_ct_netns_do_put(net, NFPROTO_BRIDGE);
619954d8297SGustavo A. R. Silva 		fallthrough;
620af9573beSPablo Neira Ayuso 	case NFPROTO_INET:
621a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, NFPROTO_IPV4);
622a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, NFPROTO_IPV6);
623af9573beSPablo Neira Ayuso 		break;
624af9573beSPablo Neira Ayuso 	default:
625a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, nfproto);
626af9573beSPablo Neira Ayuso 		break;
627a0ae2562SFlorian Westphal 	}
628a0ae2562SFlorian Westphal }
629a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put);
630a0ae2562SFlorian Westphal 
631d035f19fSPablo Neira Ayuso void nf_ct_bridge_register(struct nf_ct_bridge_info *info)
632d035f19fSPablo Neira Ayuso {
633d035f19fSPablo Neira Ayuso 	WARN_ON(nf_ct_bridge_info);
634d035f19fSPablo Neira Ayuso 	mutex_lock(&nf_ct_proto_mutex);
635d035f19fSPablo Neira Ayuso 	nf_ct_bridge_info = info;
636d035f19fSPablo Neira Ayuso 	mutex_unlock(&nf_ct_proto_mutex);
637d035f19fSPablo Neira Ayuso }
638d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_register);
639d035f19fSPablo Neira Ayuso 
640d035f19fSPablo Neira Ayuso void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info)
641d035f19fSPablo Neira Ayuso {
642d035f19fSPablo Neira Ayuso 	WARN_ON(!nf_ct_bridge_info);
643d035f19fSPablo Neira Ayuso 	mutex_lock(&nf_ct_proto_mutex);
644d035f19fSPablo Neira Ayuso 	nf_ct_bridge_info = NULL;
645d035f19fSPablo Neira Ayuso 	mutex_unlock(&nf_ct_proto_mutex);
646d035f19fSPablo Neira Ayuso }
647d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_unregister);
648d035f19fSPablo Neira Ayuso 
649a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void)
650a0ae2562SFlorian Westphal {
6514a60dc74SFlorian Westphal 	int ret;
652a0ae2562SFlorian Westphal 
653a0ae2562SFlorian Westphal 	ret = nf_register_sockopt(&so_getorigdst);
654a0ae2562SFlorian Westphal 	if (ret < 0)
655a0ae2562SFlorian Westphal 		return ret;
656a0ae2562SFlorian Westphal 
657a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
658a0ae2562SFlorian Westphal 	ret = nf_register_sockopt(&so_getorigdst6);
659a0ae2562SFlorian Westphal 	if (ret < 0)
660a0ae2562SFlorian Westphal 		goto cleanup_sockopt;
661a0ae2562SFlorian Westphal #endif
662dd2934a9SFlorian Westphal 
663a0ae2562SFlorian Westphal 	return ret;
6644a60dc74SFlorian Westphal 
665a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
666a0ae2562SFlorian Westphal cleanup_sockopt:
667*22cbdbcfSFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst);
668a0ae2562SFlorian Westphal #endif
669a0ae2562SFlorian Westphal 	return ret;
670a0ae2562SFlorian Westphal }
671a0ae2562SFlorian Westphal 
672a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void)
673a0ae2562SFlorian Westphal {
674a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst);
675a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
676a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst6);
677a0ae2562SFlorian Westphal #endif
678a0ae2562SFlorian Westphal }
679a0ae2562SFlorian Westphal 
6804a60dc74SFlorian Westphal void nf_conntrack_proto_pernet_init(struct net *net)
681ac5357ebSPatrick McHardy {
6822a389de8SFlorian Westphal 	nf_conntrack_generic_init_net(net);
6832a389de8SFlorian Westphal 	nf_conntrack_udp_init_net(net);
6842a389de8SFlorian Westphal 	nf_conntrack_tcp_init_net(net);
6852a389de8SFlorian Westphal 	nf_conntrack_icmp_init_net(net);
68681e01647SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
6872a389de8SFlorian Westphal 	nf_conntrack_icmpv6_init_net(net);
68881e01647SFlorian Westphal #endif
6892a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP
6902a389de8SFlorian Westphal 	nf_conntrack_dccp_init_net(net);
6912a389de8SFlorian Westphal #endif
6922a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP
6932a389de8SFlorian Westphal 	nf_conntrack_sctp_init_net(net);
6942a389de8SFlorian Westphal #endif
6952a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
6962a389de8SFlorian Westphal 	nf_conntrack_gre_init_net(net);
6972a389de8SFlorian Westphal #endif
698ac5357ebSPatrick McHardy }
699ac5357ebSPatrick McHardy 
70004d87001SGao feng void nf_conntrack_proto_pernet_fini(struct net *net)
701ac5357ebSPatrick McHardy {
70222fc4c4cSFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
70322fc4c4cSFlorian Westphal 	nf_ct_gre_keymap_flush(net);
70422fc4c4cSFlorian Westphal #endif
70504d87001SGao feng }
70604d87001SGao feng 
707a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
708a0ae2562SFlorian Westphal 		  &nf_conntrack_htable_size, 0600);
709a0ae2562SFlorian Westphal 
710a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack");
711a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
712a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
713a0ae2562SFlorian Westphal MODULE_LICENSE("GPL");
714