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 
124827318feSFlorian Westphal static unsigned int nf_confirm(struct sk_buff *skb,
125827318feSFlorian Westphal 			       unsigned int protoff,
126827318feSFlorian Westphal 			       struct nf_conn *ct,
127827318feSFlorian Westphal 			       enum ip_conntrack_info ctinfo)
128a0ae2562SFlorian Westphal {
129a0ae2562SFlorian Westphal 	const struct nf_conn_help *help;
130a0ae2562SFlorian Westphal 
131a0ae2562SFlorian Westphal 	help = nfct_help(ct);
132827318feSFlorian Westphal 	if (help) {
133827318feSFlorian Westphal 		const struct nf_conntrack_helper *helper;
134827318feSFlorian Westphal 		int ret;
135a0ae2562SFlorian Westphal 
136a0ae2562SFlorian Westphal 		/* rcu_read_lock()ed by nf_hook_thresh */
137a0ae2562SFlorian Westphal 		helper = rcu_dereference(help->helper);
138827318feSFlorian Westphal 		if (helper) {
139827318feSFlorian Westphal 			ret = helper->help(skb,
140827318feSFlorian Westphal 					   protoff,
141a0ae2562SFlorian Westphal 					   ct, ctinfo);
142827318feSFlorian Westphal 			if (ret != NF_ACCEPT)
143827318feSFlorian Westphal 				return ret;
144827318feSFlorian Westphal 		}
145827318feSFlorian Westphal 	}
146827318feSFlorian Westphal 
147827318feSFlorian Westphal 	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
148827318feSFlorian Westphal 	    !nf_is_loopback_packet(skb)) {
149827318feSFlorian Westphal 		if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
150827318feSFlorian Westphal 			NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
151827318feSFlorian Westphal 			return NF_DROP;
152827318feSFlorian Westphal 		}
153827318feSFlorian Westphal 	}
154827318feSFlorian Westphal 
155827318feSFlorian Westphal 	/* We've seen it coming out the other side: confirm it */
156827318feSFlorian Westphal 	return nf_conntrack_confirm(skb);
157a0ae2562SFlorian Westphal }
158a0ae2562SFlorian Westphal 
159a0ae2562SFlorian Westphal static unsigned int ipv4_confirm(void *priv,
160a0ae2562SFlorian Westphal 				 struct sk_buff *skb,
161a0ae2562SFlorian Westphal 				 const struct nf_hook_state *state)
162a0ae2562SFlorian Westphal {
163a0ae2562SFlorian Westphal 	enum ip_conntrack_info ctinfo;
164827318feSFlorian Westphal 	struct nf_conn *ct;
165a0ae2562SFlorian Westphal 
166a0ae2562SFlorian Westphal 	ct = nf_ct_get(skb, &ctinfo);
167a0ae2562SFlorian Westphal 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
168a0ae2562SFlorian Westphal 		return nf_conntrack_confirm(skb);
169827318feSFlorian Westphal 
170827318feSFlorian Westphal 	return nf_confirm(skb,
171827318feSFlorian Westphal 			  skb_network_offset(skb) + ip_hdrlen(skb),
172827318feSFlorian Westphal 			  ct, ctinfo);
173a0ae2562SFlorian Westphal }
174a0ae2562SFlorian Westphal 
175a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv,
176a0ae2562SFlorian Westphal 				      struct sk_buff *skb,
177a0ae2562SFlorian Westphal 				      const struct nf_hook_state *state)
178a0ae2562SFlorian Westphal {
17993e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
180a0ae2562SFlorian Westphal }
181a0ae2562SFlorian Westphal 
182a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv,
183a0ae2562SFlorian Westphal 					 struct sk_buff *skb,
184a0ae2562SFlorian Westphal 					 const struct nf_hook_state *state)
185a0ae2562SFlorian Westphal {
186a0ae2562SFlorian Westphal 	if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
187a0ae2562SFlorian Westphal 		enum ip_conntrack_info ctinfo;
188a0ae2562SFlorian Westphal 		struct nf_conn *tmpl;
189a0ae2562SFlorian Westphal 
190a0ae2562SFlorian Westphal 		tmpl = nf_ct_get(skb, &ctinfo);
191a0ae2562SFlorian Westphal 		if (tmpl && nf_ct_is_template(tmpl)) {
192a0ae2562SFlorian Westphal 			/* when skipping ct, clear templates to avoid fooling
193a0ae2562SFlorian Westphal 			 * later targets/matches
194a0ae2562SFlorian Westphal 			 */
195a0ae2562SFlorian Westphal 			skb->_nfct = 0;
196a0ae2562SFlorian Westphal 			nf_ct_put(tmpl);
197a0ae2562SFlorian Westphal 		}
198a0ae2562SFlorian Westphal 		return NF_ACCEPT;
199a0ae2562SFlorian Westphal 	}
200a0ae2562SFlorian Westphal 
20193e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
202a0ae2562SFlorian Westphal }
203a0ae2562SFlorian Westphal 
204a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so
205a0ae2562SFlorian Westphal  * make it the first hook.
206a0ae2562SFlorian Westphal  */
207a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = {
208a0ae2562SFlorian Westphal 	{
209a0ae2562SFlorian Westphal 		.hook		= ipv4_conntrack_in,
210a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
211a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_PRE_ROUTING,
212a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK,
213a0ae2562SFlorian Westphal 	},
214a0ae2562SFlorian Westphal 	{
215a0ae2562SFlorian Westphal 		.hook		= ipv4_conntrack_local,
216a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
217a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_OUT,
218a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK,
219a0ae2562SFlorian Westphal 	},
220a0ae2562SFlorian Westphal 	{
221a0ae2562SFlorian Westphal 		.hook		= ipv4_confirm,
222a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
223a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_POST_ROUTING,
224a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
225a0ae2562SFlorian Westphal 	},
226a0ae2562SFlorian Westphal 	{
227a0ae2562SFlorian Westphal 		.hook		= ipv4_confirm,
228a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
229a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_IN,
230a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
231a0ae2562SFlorian Westphal 	},
232a0ae2562SFlorian Westphal };
233a0ae2562SFlorian Westphal 
234a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't
235a0ae2562SFlorian Westphal  * blame them).
236a0ae2562SFlorian Westphal  * Reversing the socket's dst/src point of view gives us the reply
237a0ae2562SFlorian Westphal  * mapping.
238a0ae2562SFlorian Westphal  */
239a0ae2562SFlorian Westphal static int
240a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len)
241a0ae2562SFlorian Westphal {
242a0ae2562SFlorian Westphal 	const struct inet_sock *inet = inet_sk(sk);
243a0ae2562SFlorian Westphal 	const struct nf_conntrack_tuple_hash *h;
244a0ae2562SFlorian Westphal 	struct nf_conntrack_tuple tuple;
245a0ae2562SFlorian Westphal 
246a0ae2562SFlorian Westphal 	memset(&tuple, 0, sizeof(tuple));
247a0ae2562SFlorian Westphal 
248a0ae2562SFlorian Westphal 	lock_sock(sk);
249a0ae2562SFlorian Westphal 	tuple.src.u3.ip = inet->inet_rcv_saddr;
250a0ae2562SFlorian Westphal 	tuple.src.u.tcp.port = inet->inet_sport;
251a0ae2562SFlorian Westphal 	tuple.dst.u3.ip = inet->inet_daddr;
252a0ae2562SFlorian Westphal 	tuple.dst.u.tcp.port = inet->inet_dport;
253a0ae2562SFlorian Westphal 	tuple.src.l3num = PF_INET;
254a0ae2562SFlorian Westphal 	tuple.dst.protonum = sk->sk_protocol;
255a0ae2562SFlorian Westphal 	release_sock(sk);
256a0ae2562SFlorian Westphal 
257a0ae2562SFlorian Westphal 	/* We only do TCP and SCTP at the moment: is there a better way? */
258a0ae2562SFlorian Westphal 	if (tuple.dst.protonum != IPPROTO_TCP &&
259a0ae2562SFlorian Westphal 	    tuple.dst.protonum != IPPROTO_SCTP) {
260a0ae2562SFlorian Westphal 		pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
261a0ae2562SFlorian Westphal 		return -ENOPROTOOPT;
262a0ae2562SFlorian Westphal 	}
263a0ae2562SFlorian Westphal 
264a0ae2562SFlorian Westphal 	if ((unsigned int)*len < sizeof(struct sockaddr_in)) {
265a0ae2562SFlorian Westphal 		pr_debug("SO_ORIGINAL_DST: len %d not %zu\n",
266a0ae2562SFlorian Westphal 			 *len, sizeof(struct sockaddr_in));
267a0ae2562SFlorian Westphal 		return -EINVAL;
268a0ae2562SFlorian Westphal 	}
269a0ae2562SFlorian Westphal 
270a0ae2562SFlorian Westphal 	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
271a0ae2562SFlorian Westphal 	if (h) {
272a0ae2562SFlorian Westphal 		struct sockaddr_in sin;
273a0ae2562SFlorian Westphal 		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
274a0ae2562SFlorian Westphal 
275a0ae2562SFlorian Westphal 		sin.sin_family = AF_INET;
276a0ae2562SFlorian Westphal 		sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
277a0ae2562SFlorian Westphal 			.tuple.dst.u.tcp.port;
278a0ae2562SFlorian Westphal 		sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
279a0ae2562SFlorian Westphal 			.tuple.dst.u3.ip;
280a0ae2562SFlorian Westphal 		memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
281a0ae2562SFlorian Westphal 
282a0ae2562SFlorian Westphal 		pr_debug("SO_ORIGINAL_DST: %pI4 %u\n",
283a0ae2562SFlorian Westphal 			 &sin.sin_addr.s_addr, ntohs(sin.sin_port));
284a0ae2562SFlorian Westphal 		nf_ct_put(ct);
285a0ae2562SFlorian Westphal 		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
286a0ae2562SFlorian Westphal 			return -EFAULT;
287a0ae2562SFlorian Westphal 		else
288a0ae2562SFlorian Westphal 			return 0;
289a0ae2562SFlorian Westphal 	}
290a0ae2562SFlorian Westphal 	pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n",
291a0ae2562SFlorian Westphal 		 &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port),
292a0ae2562SFlorian Westphal 		 &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port));
293a0ae2562SFlorian Westphal 	return -ENOENT;
294a0ae2562SFlorian Westphal }
295a0ae2562SFlorian Westphal 
296a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = {
297a0ae2562SFlorian Westphal 	.pf		= PF_INET,
298a0ae2562SFlorian Westphal 	.get_optmin	= SO_ORIGINAL_DST,
299a0ae2562SFlorian Westphal 	.get_optmax	= SO_ORIGINAL_DST + 1,
300a0ae2562SFlorian Westphal 	.get		= getorigdst,
301a0ae2562SFlorian Westphal 	.owner		= THIS_MODULE,
302a0ae2562SFlorian Westphal };
303a0ae2562SFlorian Westphal 
304a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
305a0ae2562SFlorian Westphal static int
306a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
307a0ae2562SFlorian Westphal {
308a0ae2562SFlorian Westphal 	struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
309a0ae2562SFlorian Westphal 	const struct ipv6_pinfo *inet6 = inet6_sk(sk);
310a0ae2562SFlorian Westphal 	const struct inet_sock *inet = inet_sk(sk);
311a0ae2562SFlorian Westphal 	const struct nf_conntrack_tuple_hash *h;
312a0ae2562SFlorian Westphal 	struct sockaddr_in6 sin6;
313a0ae2562SFlorian Westphal 	struct nf_conn *ct;
314a0ae2562SFlorian Westphal 	__be32 flow_label;
315a0ae2562SFlorian Westphal 	int bound_dev_if;
316a0ae2562SFlorian Westphal 
317a0ae2562SFlorian Westphal 	lock_sock(sk);
318a0ae2562SFlorian Westphal 	tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
319a0ae2562SFlorian Westphal 	tuple.src.u.tcp.port = inet->inet_sport;
320a0ae2562SFlorian Westphal 	tuple.dst.u3.in6 = sk->sk_v6_daddr;
321a0ae2562SFlorian Westphal 	tuple.dst.u.tcp.port = inet->inet_dport;
322a0ae2562SFlorian Westphal 	tuple.dst.protonum = sk->sk_protocol;
323a0ae2562SFlorian Westphal 	bound_dev_if = sk->sk_bound_dev_if;
324a0ae2562SFlorian Westphal 	flow_label = inet6->flow_label;
325a0ae2562SFlorian Westphal 	release_sock(sk);
326a0ae2562SFlorian Westphal 
327a0ae2562SFlorian Westphal 	if (tuple.dst.protonum != IPPROTO_TCP &&
328a0ae2562SFlorian Westphal 	    tuple.dst.protonum != IPPROTO_SCTP)
329a0ae2562SFlorian Westphal 		return -ENOPROTOOPT;
330a0ae2562SFlorian Westphal 
331a0ae2562SFlorian Westphal 	if (*len < 0 || (unsigned int)*len < sizeof(sin6))
332a0ae2562SFlorian Westphal 		return -EINVAL;
333a0ae2562SFlorian Westphal 
334a0ae2562SFlorian Westphal 	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
335a0ae2562SFlorian Westphal 	if (!h) {
336a0ae2562SFlorian Westphal 		pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
337a0ae2562SFlorian Westphal 			 &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port),
338a0ae2562SFlorian Westphal 			 &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port));
339a0ae2562SFlorian Westphal 		return -ENOENT;
340a0ae2562SFlorian Westphal 	}
341a0ae2562SFlorian Westphal 
342a0ae2562SFlorian Westphal 	ct = nf_ct_tuplehash_to_ctrack(h);
343a0ae2562SFlorian Westphal 
344a0ae2562SFlorian Westphal 	sin6.sin6_family = AF_INET6;
345a0ae2562SFlorian Westphal 	sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
346a0ae2562SFlorian Westphal 	sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
347a0ae2562SFlorian Westphal 	memcpy(&sin6.sin6_addr,
348a0ae2562SFlorian Westphal 	       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
349a0ae2562SFlorian Westphal 	       sizeof(sin6.sin6_addr));
350a0ae2562SFlorian Westphal 
351a0ae2562SFlorian Westphal 	nf_ct_put(ct);
352a0ae2562SFlorian Westphal 	sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
353a0ae2562SFlorian Westphal 	return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
354a0ae2562SFlorian Westphal }
355a0ae2562SFlorian Westphal 
356a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = {
357a0ae2562SFlorian Westphal 	.pf		= NFPROTO_IPV6,
358a0ae2562SFlorian Westphal 	.get_optmin	= IP6T_SO_ORIGINAL_DST,
359a0ae2562SFlorian Westphal 	.get_optmax	= IP6T_SO_ORIGINAL_DST + 1,
360a0ae2562SFlorian Westphal 	.get		= ipv6_getorigdst,
361a0ae2562SFlorian Westphal 	.owner		= THIS_MODULE,
362a0ae2562SFlorian Westphal };
363a0ae2562SFlorian Westphal 
364a0ae2562SFlorian Westphal static unsigned int ipv6_confirm(void *priv,
365a0ae2562SFlorian Westphal 				 struct sk_buff *skb,
366a0ae2562SFlorian Westphal 				 const struct nf_hook_state *state)
367a0ae2562SFlorian Westphal {
368a0ae2562SFlorian Westphal 	struct nf_conn *ct;
369a0ae2562SFlorian Westphal 	enum ip_conntrack_info ctinfo;
370a0ae2562SFlorian Westphal 	unsigned char pnum = ipv6_hdr(skb)->nexthdr;
371a0ae2562SFlorian Westphal 	__be16 frag_off;
372827318feSFlorian Westphal 	int protoff;
373a0ae2562SFlorian Westphal 
374a0ae2562SFlorian Westphal 	ct = nf_ct_get(skb, &ctinfo);
375a0ae2562SFlorian Westphal 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
376827318feSFlorian Westphal 		return nf_conntrack_confirm(skb);
377a0ae2562SFlorian Westphal 
378a0ae2562SFlorian Westphal 	protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
379a0ae2562SFlorian Westphal 				   &frag_off);
380a0ae2562SFlorian Westphal 	if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
381a0ae2562SFlorian Westphal 		pr_debug("proto header not found\n");
382827318feSFlorian Westphal 		return nf_conntrack_confirm(skb);
383a0ae2562SFlorian Westphal 	}
384a0ae2562SFlorian Westphal 
385827318feSFlorian Westphal 	return nf_confirm(skb, protoff, ct, ctinfo);
386a0ae2562SFlorian Westphal }
387a0ae2562SFlorian Westphal 
388a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv,
389a0ae2562SFlorian Westphal 				      struct sk_buff *skb,
390a0ae2562SFlorian Westphal 				      const struct nf_hook_state *state)
391a0ae2562SFlorian Westphal {
39293e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
393a0ae2562SFlorian Westphal }
394a0ae2562SFlorian Westphal 
395a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv,
396a0ae2562SFlorian Westphal 					 struct sk_buff *skb,
397a0ae2562SFlorian Westphal 					 const struct nf_hook_state *state)
398a0ae2562SFlorian Westphal {
39993e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
400a0ae2562SFlorian Westphal }
401a0ae2562SFlorian Westphal 
402a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = {
403a0ae2562SFlorian Westphal 	{
404a0ae2562SFlorian Westphal 		.hook		= ipv6_conntrack_in,
405a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
406a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_PRE_ROUTING,
407a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_CONNTRACK,
408a0ae2562SFlorian Westphal 	},
409a0ae2562SFlorian Westphal 	{
410a0ae2562SFlorian Westphal 		.hook		= ipv6_conntrack_local,
411a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
412a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_OUT,
413a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_CONNTRACK,
414a0ae2562SFlorian Westphal 	},
415a0ae2562SFlorian Westphal 	{
416a0ae2562SFlorian Westphal 		.hook		= ipv6_confirm,
417a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
418a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_POST_ROUTING,
419a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_LAST,
420a0ae2562SFlorian Westphal 	},
421a0ae2562SFlorian Westphal 	{
422a0ae2562SFlorian Westphal 		.hook		= ipv6_confirm,
423a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
424a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_IN,
425a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_LAST - 1,
426a0ae2562SFlorian Westphal 	},
427a0ae2562SFlorian Westphal };
428a0ae2562SFlorian Westphal #endif
429a0ae2562SFlorian Westphal 
430f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto)
431f94e6380SFlorian Westphal {
432f94e6380SFlorian Westphal 	u8 nfproto = (unsigned long)_nfproto;
433f94e6380SFlorian Westphal 
434f94e6380SFlorian Westphal 	if (nf_ct_l3num(ct) != nfproto)
435f94e6380SFlorian Westphal 		return 0;
436f94e6380SFlorian Westphal 
437f94e6380SFlorian Westphal 	if (nf_ct_protonum(ct) == IPPROTO_TCP &&
438f94e6380SFlorian Westphal 	    ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
439f94e6380SFlorian Westphal 		ct->proto.tcp.seen[0].td_maxwin = 0;
440f94e6380SFlorian Westphal 		ct->proto.tcp.seen[1].td_maxwin = 0;
441f94e6380SFlorian Westphal 	}
442f94e6380SFlorian Westphal 
443f94e6380SFlorian Westphal 	return 0;
444f94e6380SFlorian Westphal }
445f94e6380SFlorian Westphal 
446d035f19fSPablo Neira Ayuso static struct nf_ct_bridge_info *nf_ct_bridge_info;
447d035f19fSPablo Neira Ayuso 
448a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
449a0ae2562SFlorian Westphal {
450a0ae2562SFlorian Westphal 	struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
451d035f19fSPablo Neira Ayuso 	bool fixup_needed = false, retry = true;
452a0ae2562SFlorian Westphal 	int err = 0;
453d035f19fSPablo Neira Ayuso retry:
454a0ae2562SFlorian Westphal 	mutex_lock(&nf_ct_proto_mutex);
455a0ae2562SFlorian Westphal 
456a0ae2562SFlorian Westphal 	switch (nfproto) {
457a0ae2562SFlorian Westphal 	case NFPROTO_IPV4:
458a0ae2562SFlorian Westphal 		cnet->users4++;
459a0ae2562SFlorian Westphal 		if (cnet->users4 > 1)
460a0ae2562SFlorian Westphal 			goto out_unlock;
461a0ae2562SFlorian Westphal 		err = nf_defrag_ipv4_enable(net);
462a0ae2562SFlorian Westphal 		if (err) {
463a0ae2562SFlorian Westphal 			cnet->users4 = 0;
464a0ae2562SFlorian Westphal 			goto out_unlock;
465a0ae2562SFlorian Westphal 		}
466a0ae2562SFlorian Westphal 
467a0ae2562SFlorian Westphal 		err = nf_register_net_hooks(net, ipv4_conntrack_ops,
468a0ae2562SFlorian Westphal 					    ARRAY_SIZE(ipv4_conntrack_ops));
469a0ae2562SFlorian Westphal 		if (err)
470a0ae2562SFlorian Westphal 			cnet->users4 = 0;
471f94e6380SFlorian Westphal 		else
472f94e6380SFlorian Westphal 			fixup_needed = true;
473a0ae2562SFlorian Westphal 		break;
474a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
475a0ae2562SFlorian Westphal 	case NFPROTO_IPV6:
476a0ae2562SFlorian Westphal 		cnet->users6++;
477a0ae2562SFlorian Westphal 		if (cnet->users6 > 1)
478a0ae2562SFlorian Westphal 			goto out_unlock;
479a0ae2562SFlorian Westphal 		err = nf_defrag_ipv6_enable(net);
480a0ae2562SFlorian Westphal 		if (err < 0) {
481a0ae2562SFlorian Westphal 			cnet->users6 = 0;
482a0ae2562SFlorian Westphal 			goto out_unlock;
483a0ae2562SFlorian Westphal 		}
484a0ae2562SFlorian Westphal 
485a0ae2562SFlorian Westphal 		err = nf_register_net_hooks(net, ipv6_conntrack_ops,
486a0ae2562SFlorian Westphal 					    ARRAY_SIZE(ipv6_conntrack_ops));
487a0ae2562SFlorian Westphal 		if (err)
488a0ae2562SFlorian Westphal 			cnet->users6 = 0;
489f94e6380SFlorian Westphal 		else
490f94e6380SFlorian Westphal 			fixup_needed = true;
491a0ae2562SFlorian Westphal 		break;
492a0ae2562SFlorian Westphal #endif
493d035f19fSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
494d035f19fSPablo Neira Ayuso 		if (!nf_ct_bridge_info) {
495d035f19fSPablo Neira Ayuso 			if (!retry) {
496d035f19fSPablo Neira Ayuso 				err = -EPROTO;
497d035f19fSPablo Neira Ayuso 				goto out_unlock;
498d035f19fSPablo Neira Ayuso 			}
499d035f19fSPablo Neira Ayuso 			mutex_unlock(&nf_ct_proto_mutex);
500d035f19fSPablo Neira Ayuso 			request_module("nf_conntrack_bridge");
501d035f19fSPablo Neira Ayuso 			retry = false;
502d035f19fSPablo Neira Ayuso 			goto retry;
503d035f19fSPablo Neira Ayuso 		}
504d035f19fSPablo Neira Ayuso 		if (!try_module_get(nf_ct_bridge_info->me)) {
505d035f19fSPablo Neira Ayuso 			err = -EPROTO;
506d035f19fSPablo Neira Ayuso 			goto out_unlock;
507d035f19fSPablo Neira Ayuso 		}
508d035f19fSPablo Neira Ayuso 		cnet->users_bridge++;
509d035f19fSPablo Neira Ayuso 		if (cnet->users_bridge > 1)
510d035f19fSPablo Neira Ayuso 			goto out_unlock;
511d035f19fSPablo Neira Ayuso 
512d035f19fSPablo Neira Ayuso 		err = nf_register_net_hooks(net, nf_ct_bridge_info->ops,
513d035f19fSPablo Neira Ayuso 					    nf_ct_bridge_info->ops_size);
514d035f19fSPablo Neira Ayuso 		if (err)
515d035f19fSPablo Neira Ayuso 			cnet->users_bridge = 0;
516d035f19fSPablo Neira Ayuso 		else
517d035f19fSPablo Neira Ayuso 			fixup_needed = true;
518d035f19fSPablo Neira Ayuso 		break;
519a0ae2562SFlorian Westphal 	default:
520a0ae2562SFlorian Westphal 		err = -EPROTO;
521a0ae2562SFlorian Westphal 		break;
522a0ae2562SFlorian Westphal 	}
523a0ae2562SFlorian Westphal  out_unlock:
524a0ae2562SFlorian Westphal 	mutex_unlock(&nf_ct_proto_mutex);
525f94e6380SFlorian Westphal 
526f94e6380SFlorian Westphal 	if (fixup_needed)
527f94e6380SFlorian Westphal 		nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup,
528f94e6380SFlorian Westphal 					  (void *)(unsigned long)nfproto, 0, 0);
529f94e6380SFlorian Westphal 
530a0ae2562SFlorian Westphal 	return err;
531a0ae2562SFlorian Westphal }
532a0ae2562SFlorian Westphal 
533a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
534a0ae2562SFlorian Westphal {
535a0ae2562SFlorian Westphal 	struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
536a0ae2562SFlorian Westphal 
537a0ae2562SFlorian Westphal 	mutex_lock(&nf_ct_proto_mutex);
538a0ae2562SFlorian Westphal 	switch (nfproto) {
539a0ae2562SFlorian Westphal 	case NFPROTO_IPV4:
540a0ae2562SFlorian Westphal 		if (cnet->users4 && (--cnet->users4 == 0))
541a0ae2562SFlorian Westphal 			nf_unregister_net_hooks(net, ipv4_conntrack_ops,
542a0ae2562SFlorian Westphal 						ARRAY_SIZE(ipv4_conntrack_ops));
543a0ae2562SFlorian Westphal 		break;
544a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
545a0ae2562SFlorian Westphal 	case NFPROTO_IPV6:
546a0ae2562SFlorian Westphal 		if (cnet->users6 && (--cnet->users6 == 0))
547a0ae2562SFlorian Westphal 			nf_unregister_net_hooks(net, ipv6_conntrack_ops,
548a0ae2562SFlorian Westphal 						ARRAY_SIZE(ipv6_conntrack_ops));
549a0ae2562SFlorian Westphal 		break;
550a0ae2562SFlorian Westphal #endif
551d035f19fSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
552d035f19fSPablo Neira Ayuso 		if (!nf_ct_bridge_info)
553d035f19fSPablo Neira Ayuso 			break;
554d035f19fSPablo Neira Ayuso 		if (cnet->users_bridge && (--cnet->users_bridge == 0))
555d035f19fSPablo Neira Ayuso 			nf_unregister_net_hooks(net, nf_ct_bridge_info->ops,
556d035f19fSPablo Neira Ayuso 						nf_ct_bridge_info->ops_size);
557a0ae2562SFlorian Westphal 
558d035f19fSPablo Neira Ayuso 		module_put(nf_ct_bridge_info->me);
559d035f19fSPablo Neira Ayuso 		break;
560d035f19fSPablo Neira Ayuso 	}
561a0ae2562SFlorian Westphal 	mutex_unlock(&nf_ct_proto_mutex);
562a0ae2562SFlorian Westphal }
563a0ae2562SFlorian Westphal 
564a0ae2562SFlorian Westphal int nf_ct_netns_get(struct net *net, u8 nfproto)
565a0ae2562SFlorian Westphal {
566a0ae2562SFlorian Westphal 	int err;
567a0ae2562SFlorian Westphal 
568a0ae2562SFlorian Westphal 	if (nfproto == NFPROTO_INET) {
569a0ae2562SFlorian Westphal 		err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
570a0ae2562SFlorian Westphal 		if (err < 0)
571a0ae2562SFlorian Westphal 			goto err1;
572a0ae2562SFlorian Westphal 		err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
573a0ae2562SFlorian Westphal 		if (err < 0)
574a0ae2562SFlorian Westphal 			goto err2;
575a0ae2562SFlorian Westphal 	} else {
576a0ae2562SFlorian Westphal 		err = nf_ct_netns_do_get(net, nfproto);
577a0ae2562SFlorian Westphal 		if (err < 0)
578a0ae2562SFlorian Westphal 			goto err1;
579a0ae2562SFlorian Westphal 	}
580a0ae2562SFlorian Westphal 	return 0;
581a0ae2562SFlorian Westphal 
582a0ae2562SFlorian Westphal err2:
583a0ae2562SFlorian Westphal 	nf_ct_netns_put(net, NFPROTO_IPV4);
584a0ae2562SFlorian Westphal err1:
585a0ae2562SFlorian Westphal 	return err;
586a0ae2562SFlorian Westphal }
587a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get);
588a0ae2562SFlorian Westphal 
589a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto)
590a0ae2562SFlorian Westphal {
591a0ae2562SFlorian Westphal 	if (nfproto == NFPROTO_INET) {
592a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, NFPROTO_IPV4);
593a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, NFPROTO_IPV6);
594a0ae2562SFlorian Westphal 	} else {
595a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, nfproto);
596a0ae2562SFlorian Westphal 	}
597a0ae2562SFlorian Westphal }
598a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put);
599a0ae2562SFlorian Westphal 
600d035f19fSPablo Neira Ayuso void nf_ct_bridge_register(struct nf_ct_bridge_info *info)
601d035f19fSPablo Neira Ayuso {
602d035f19fSPablo Neira Ayuso 	WARN_ON(nf_ct_bridge_info);
603d035f19fSPablo Neira Ayuso 	mutex_lock(&nf_ct_proto_mutex);
604d035f19fSPablo Neira Ayuso 	nf_ct_bridge_info = info;
605d035f19fSPablo Neira Ayuso 	mutex_unlock(&nf_ct_proto_mutex);
606d035f19fSPablo Neira Ayuso }
607d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_register);
608d035f19fSPablo Neira Ayuso 
609d035f19fSPablo Neira Ayuso void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info)
610d035f19fSPablo Neira Ayuso {
611d035f19fSPablo Neira Ayuso 	WARN_ON(!nf_ct_bridge_info);
612d035f19fSPablo Neira Ayuso 	mutex_lock(&nf_ct_proto_mutex);
613d035f19fSPablo Neira Ayuso 	nf_ct_bridge_info = NULL;
614d035f19fSPablo Neira Ayuso 	mutex_unlock(&nf_ct_proto_mutex);
615d035f19fSPablo Neira Ayuso }
616d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_unregister);
617d035f19fSPablo Neira Ayuso 
618a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void)
619a0ae2562SFlorian Westphal {
6204a60dc74SFlorian Westphal 	int ret;
621a0ae2562SFlorian Westphal 
622a0ae2562SFlorian Westphal 	ret = nf_register_sockopt(&so_getorigdst);
623a0ae2562SFlorian Westphal 	if (ret < 0)
624a0ae2562SFlorian Westphal 		return ret;
625a0ae2562SFlorian Westphal 
626a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
627a0ae2562SFlorian Westphal 	ret = nf_register_sockopt(&so_getorigdst6);
628a0ae2562SFlorian Westphal 	if (ret < 0)
629a0ae2562SFlorian Westphal 		goto cleanup_sockopt;
630a0ae2562SFlorian Westphal #endif
631dd2934a9SFlorian Westphal 
632a0ae2562SFlorian Westphal 	return ret;
6334a60dc74SFlorian Westphal 
634a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
635a0ae2562SFlorian Westphal cleanup_sockopt:
636a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst6);
637a0ae2562SFlorian Westphal #endif
638a0ae2562SFlorian Westphal 	return ret;
639a0ae2562SFlorian Westphal }
640a0ae2562SFlorian Westphal 
641a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void)
642a0ae2562SFlorian Westphal {
643a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst);
644a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
645a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst6);
646a0ae2562SFlorian Westphal #endif
647a0ae2562SFlorian Westphal }
648a0ae2562SFlorian Westphal 
6494a60dc74SFlorian Westphal void nf_conntrack_proto_pernet_init(struct net *net)
650ac5357ebSPatrick McHardy {
6512a389de8SFlorian Westphal 	nf_conntrack_generic_init_net(net);
6522a389de8SFlorian Westphal 	nf_conntrack_udp_init_net(net);
6532a389de8SFlorian Westphal 	nf_conntrack_tcp_init_net(net);
6542a389de8SFlorian Westphal 	nf_conntrack_icmp_init_net(net);
65581e01647SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
6562a389de8SFlorian Westphal 	nf_conntrack_icmpv6_init_net(net);
65781e01647SFlorian Westphal #endif
6582a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP
6592a389de8SFlorian Westphal 	nf_conntrack_dccp_init_net(net);
6602a389de8SFlorian Westphal #endif
6612a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP
6622a389de8SFlorian Westphal 	nf_conntrack_sctp_init_net(net);
6632a389de8SFlorian Westphal #endif
6642a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
6652a389de8SFlorian Westphal 	nf_conntrack_gre_init_net(net);
6662a389de8SFlorian Westphal #endif
667ac5357ebSPatrick McHardy }
668ac5357ebSPatrick McHardy 
66904d87001SGao feng void nf_conntrack_proto_pernet_fini(struct net *net)
670ac5357ebSPatrick McHardy {
67122fc4c4cSFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
67222fc4c4cSFlorian Westphal 	nf_ct_gre_keymap_flush(net);
67322fc4c4cSFlorian Westphal #endif
67404d87001SGao feng }
67504d87001SGao feng 
676a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
677a0ae2562SFlorian Westphal 		  &nf_conntrack_htable_size, 0600);
678a0ae2562SFlorian Westphal 
679a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack");
680a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
681a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
682a0ae2562SFlorian Westphal MODULE_LICENSE("GPL");
683