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 
45b19caa0cSPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_mutex);
46d62f9ed4SPatrick McHardy 
47b19caa0cSPatrick McHardy #ifdef CONFIG_SYSCTL
4862eec0d7SFlorian Westphal __printf(4, 5)
nf_l4proto_log_invalid(const struct sk_buff * skb,const struct nf_hook_state * state,u8 protonum,const char * fmt,...)49c4f3db15SFlorian Westphal void nf_l4proto_log_invalid(const struct sk_buff *skb,
5062eec0d7SFlorian Westphal 			    const struct nf_hook_state *state,
5162eec0d7SFlorian Westphal 			    u8 protonum,
52c4f3db15SFlorian Westphal 			    const char *fmt, ...)
53c4f3db15SFlorian Westphal {
5462eec0d7SFlorian Westphal 	struct net *net = state->net;
55c4f3db15SFlorian Westphal 	struct va_format vaf;
56c4f3db15SFlorian Westphal 	va_list args;
57c4f3db15SFlorian Westphal 
58d4866805SAndrei Vagin 	if (net->ct.sysctl_log_invalid != protonum &&
59c4f3db15SFlorian Westphal 	    net->ct.sysctl_log_invalid != IPPROTO_RAW)
60c4f3db15SFlorian Westphal 		return;
61c4f3db15SFlorian Westphal 
62c4f3db15SFlorian Westphal 	va_start(args, fmt);
63c4f3db15SFlorian Westphal 	vaf.fmt = fmt;
64c4f3db15SFlorian Westphal 	vaf.va = &args;
65c4f3db15SFlorian Westphal 
6662eec0d7SFlorian Westphal 	nf_log_packet(net, state->pf, 0, skb, state->in, state->out,
6762eec0d7SFlorian Westphal 		      NULL, "nf_ct_proto_%d: %pV ", protonum, &vaf);
68c4f3db15SFlorian Westphal 	va_end(args);
69c4f3db15SFlorian Westphal }
70c4f3db15SFlorian Westphal EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid);
713d0b527bSFlorian Westphal 
7262eec0d7SFlorian Westphal __printf(4, 5)
nf_ct_l4proto_log_invalid(const struct sk_buff * skb,const struct nf_conn * ct,const struct nf_hook_state * state,const char * fmt,...)733d0b527bSFlorian Westphal void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
743d0b527bSFlorian Westphal 			       const struct nf_conn *ct,
7562eec0d7SFlorian Westphal 			       const struct nf_hook_state *state,
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 
9062eec0d7SFlorian Westphal 	nf_l4proto_log_invalid(skb, state,
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 
nf_ct_l4proto_find(u8 l4proto)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 
in_vrf_postrouting(const struct nf_hook_state * state)1248e0538d8SFlorian Westphal static bool in_vrf_postrouting(const struct nf_hook_state *state)
1258e0538d8SFlorian Westphal {
1268e0538d8SFlorian Westphal #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
1278e0538d8SFlorian Westphal 	if (state->hook == NF_INET_POST_ROUTING &&
1288e0538d8SFlorian Westphal 	    netif_is_l3_master(state->out))
1298e0538d8SFlorian Westphal 		return true;
1308e0538d8SFlorian Westphal #endif
1318e0538d8SFlorian Westphal 	return false;
1328e0538d8SFlorian Westphal }
1338e0538d8SFlorian Westphal 
nf_confirm(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)134a70e4834SFlorian Westphal unsigned int nf_confirm(void *priv,
135a0ae2562SFlorian Westphal 			struct sk_buff *skb,
136a0ae2562SFlorian Westphal 			const struct nf_hook_state *state)
137a0ae2562SFlorian Westphal {
138a70e4834SFlorian Westphal 	const struct nf_conn_help *help;
139a0ae2562SFlorian Westphal 	enum ip_conntrack_info ctinfo;
140a70e4834SFlorian Westphal 	unsigned int protoff;
141827318feSFlorian Westphal 	struct nf_conn *ct;
142a70e4834SFlorian Westphal 	bool seqadj_needed;
143a70e4834SFlorian Westphal 	__be16 frag_off;
1445eb119daSFlorian Westphal 	int start;
145a70e4834SFlorian Westphal 	u8 pnum;
146a0ae2562SFlorian Westphal 
147a0ae2562SFlorian Westphal 	ct = nf_ct_get(skb, &ctinfo);
148a70e4834SFlorian Westphal 	if (!ct || in_vrf_postrouting(state))
1498e0538d8SFlorian Westphal 		return NF_ACCEPT;
1508e0538d8SFlorian Westphal 
151a70e4834SFlorian Westphal 	help = nfct_help(ct);
152a70e4834SFlorian Westphal 
153a70e4834SFlorian Westphal 	seqadj_needed = test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && !nf_is_loopback_packet(skb);
154a70e4834SFlorian Westphal 	if (!help && !seqadj_needed)
155a70e4834SFlorian Westphal 		return nf_conntrack_confirm(skb);
156a70e4834SFlorian Westphal 
157a70e4834SFlorian Westphal 	/* helper->help() do not expect ICMP packets */
158a70e4834SFlorian Westphal 	if (ctinfo == IP_CT_RELATED_REPLY)
159a70e4834SFlorian Westphal 		return nf_conntrack_confirm(skb);
160a70e4834SFlorian Westphal 
161a70e4834SFlorian Westphal 	switch (nf_ct_l3num(ct)) {
162a70e4834SFlorian Westphal 	case NFPROTO_IPV4:
163a70e4834SFlorian Westphal 		protoff = skb_network_offset(skb) + ip_hdrlen(skb);
164a70e4834SFlorian Westphal 		break;
165a70e4834SFlorian Westphal 	case NFPROTO_IPV6:
166a70e4834SFlorian Westphal 		pnum = ipv6_hdr(skb)->nexthdr;
1675eb119daSFlorian Westphal 		start = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, &frag_off);
1685eb119daSFlorian Westphal 		if (start < 0 || (frag_off & htons(~0x7)) != 0)
169a70e4834SFlorian Westphal 			return nf_conntrack_confirm(skb);
1705eb119daSFlorian Westphal 
1715eb119daSFlorian Westphal 		protoff = start;
172a70e4834SFlorian Westphal 		break;
173a70e4834SFlorian Westphal 	default:
174a70e4834SFlorian Westphal 		return nf_conntrack_confirm(skb);
175a0ae2562SFlorian Westphal 	}
176a0ae2562SFlorian Westphal 
177a70e4834SFlorian Westphal 	if (help) {
178a70e4834SFlorian Westphal 		const struct nf_conntrack_helper *helper;
179a70e4834SFlorian Westphal 		int ret;
180a70e4834SFlorian Westphal 
181a70e4834SFlorian Westphal 		/* rcu_read_lock()ed by nf_hook */
182a70e4834SFlorian Westphal 		helper = rcu_dereference(help->helper);
183a70e4834SFlorian Westphal 		if (helper) {
184a70e4834SFlorian Westphal 			ret = helper->help(skb,
185a70e4834SFlorian Westphal 					   protoff,
186a70e4834SFlorian Westphal 					   ct, ctinfo);
187a70e4834SFlorian Westphal 			if (ret != NF_ACCEPT)
188a70e4834SFlorian Westphal 				return ret;
189a70e4834SFlorian Westphal 		}
190a70e4834SFlorian Westphal 	}
191a70e4834SFlorian Westphal 
192a70e4834SFlorian Westphal 	if (seqadj_needed &&
193a70e4834SFlorian Westphal 	    !nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
194a70e4834SFlorian Westphal 		NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
195a70e4834SFlorian Westphal 		return NF_DROP;
196a70e4834SFlorian Westphal 	}
197a70e4834SFlorian Westphal 
198a70e4834SFlorian Westphal 	/* We've seen it coming out the other side: confirm it */
199a70e4834SFlorian Westphal 	return nf_conntrack_confirm(skb);
200a70e4834SFlorian Westphal }
201a70e4834SFlorian Westphal EXPORT_SYMBOL_GPL(nf_confirm);
202a70e4834SFlorian Westphal 
ipv4_conntrack_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)203a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_in(void *priv,
204a0ae2562SFlorian Westphal 				      struct sk_buff *skb,
205a0ae2562SFlorian Westphal 				      const struct nf_hook_state *state)
206a0ae2562SFlorian Westphal {
20793e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
208a0ae2562SFlorian Westphal }
209a0ae2562SFlorian Westphal 
ipv4_conntrack_local(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)210a0ae2562SFlorian Westphal static unsigned int ipv4_conntrack_local(void *priv,
211a0ae2562SFlorian Westphal 					 struct sk_buff *skb,
212a0ae2562SFlorian Westphal 					 const struct nf_hook_state *state)
213a0ae2562SFlorian Westphal {
214a0ae2562SFlorian Westphal 	if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
215a0ae2562SFlorian Westphal 		enum ip_conntrack_info ctinfo;
216a0ae2562SFlorian Westphal 		struct nf_conn *tmpl;
217a0ae2562SFlorian Westphal 
218a0ae2562SFlorian Westphal 		tmpl = nf_ct_get(skb, &ctinfo);
219a0ae2562SFlorian Westphal 		if (tmpl && nf_ct_is_template(tmpl)) {
220a0ae2562SFlorian Westphal 			/* when skipping ct, clear templates to avoid fooling
221a0ae2562SFlorian Westphal 			 * later targets/matches
222a0ae2562SFlorian Westphal 			 */
223a0ae2562SFlorian Westphal 			skb->_nfct = 0;
224a0ae2562SFlorian Westphal 			nf_ct_put(tmpl);
225a0ae2562SFlorian Westphal 		}
226a0ae2562SFlorian Westphal 		return NF_ACCEPT;
227a0ae2562SFlorian Westphal 	}
228a0ae2562SFlorian Westphal 
22993e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
230a0ae2562SFlorian Westphal }
231a0ae2562SFlorian Westphal 
232a0ae2562SFlorian Westphal /* Connection tracking may drop packets, but never alters them, so
233a0ae2562SFlorian Westphal  * make it the first hook.
234a0ae2562SFlorian Westphal  */
235a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv4_conntrack_ops[] = {
236a0ae2562SFlorian Westphal 	{
237a0ae2562SFlorian Westphal 		.hook		= ipv4_conntrack_in,
238a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
239a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_PRE_ROUTING,
240a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK,
241a0ae2562SFlorian Westphal 	},
242a0ae2562SFlorian Westphal 	{
243a0ae2562SFlorian Westphal 		.hook		= ipv4_conntrack_local,
244a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
245a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_OUT,
246a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK,
247a0ae2562SFlorian Westphal 	},
248a0ae2562SFlorian Westphal 	{
249a70e4834SFlorian Westphal 		.hook		= nf_confirm,
250a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
251a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_POST_ROUTING,
252a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
253a0ae2562SFlorian Westphal 	},
254a0ae2562SFlorian Westphal 	{
255a70e4834SFlorian Westphal 		.hook		= nf_confirm,
256a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV4,
257a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_IN,
258a0ae2562SFlorian Westphal 		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
259a0ae2562SFlorian Westphal 	},
260a0ae2562SFlorian Westphal };
261a0ae2562SFlorian Westphal 
262a0ae2562SFlorian Westphal /* Fast function for those who don't want to parse /proc (and I don't
263a0ae2562SFlorian Westphal  * blame them).
264a0ae2562SFlorian Westphal  * Reversing the socket's dst/src point of view gives us the reply
265a0ae2562SFlorian Westphal  * mapping.
266a0ae2562SFlorian Westphal  */
267a0ae2562SFlorian Westphal static int
getorigdst(struct sock * sk,int optval,void __user * user,int * len)268a0ae2562SFlorian Westphal getorigdst(struct sock *sk, int optval, void __user *user, int *len)
269a0ae2562SFlorian Westphal {
270a0ae2562SFlorian Westphal 	const struct inet_sock *inet = inet_sk(sk);
271a0ae2562SFlorian Westphal 	const struct nf_conntrack_tuple_hash *h;
272a0ae2562SFlorian Westphal 	struct nf_conntrack_tuple tuple;
273a0ae2562SFlorian Westphal 
274a0ae2562SFlorian Westphal 	memset(&tuple, 0, sizeof(tuple));
275a0ae2562SFlorian Westphal 
276a0ae2562SFlorian Westphal 	lock_sock(sk);
277a0ae2562SFlorian Westphal 	tuple.src.u3.ip = inet->inet_rcv_saddr;
278a0ae2562SFlorian Westphal 	tuple.src.u.tcp.port = inet->inet_sport;
279a0ae2562SFlorian Westphal 	tuple.dst.u3.ip = inet->inet_daddr;
280a0ae2562SFlorian Westphal 	tuple.dst.u.tcp.port = inet->inet_dport;
281a0ae2562SFlorian Westphal 	tuple.src.l3num = PF_INET;
282a0ae2562SFlorian Westphal 	tuple.dst.protonum = sk->sk_protocol;
283a0ae2562SFlorian Westphal 	release_sock(sk);
284a0ae2562SFlorian Westphal 
285a0ae2562SFlorian Westphal 	/* We only do TCP and SCTP at the moment: is there a better way? */
286a0ae2562SFlorian Westphal 	if (tuple.dst.protonum != IPPROTO_TCP &&
287*50bfbb89SFlorian Westphal 	    tuple.dst.protonum != IPPROTO_SCTP)
288a0ae2562SFlorian Westphal 		return -ENOPROTOOPT;
289a0ae2562SFlorian Westphal 
290*50bfbb89SFlorian Westphal 	if ((unsigned int)*len < sizeof(struct sockaddr_in))
291a0ae2562SFlorian Westphal 		return -EINVAL;
292a0ae2562SFlorian Westphal 
293a0ae2562SFlorian Westphal 	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
294a0ae2562SFlorian Westphal 	if (h) {
295a0ae2562SFlorian Westphal 		struct sockaddr_in sin;
296a0ae2562SFlorian Westphal 		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
297a0ae2562SFlorian Westphal 
298a0ae2562SFlorian Westphal 		sin.sin_family = AF_INET;
299a0ae2562SFlorian Westphal 		sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
300a0ae2562SFlorian Westphal 			.tuple.dst.u.tcp.port;
301a0ae2562SFlorian Westphal 		sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
302a0ae2562SFlorian Westphal 			.tuple.dst.u3.ip;
303a0ae2562SFlorian Westphal 		memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
304a0ae2562SFlorian Westphal 
305a0ae2562SFlorian Westphal 		nf_ct_put(ct);
306a0ae2562SFlorian Westphal 		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
307a0ae2562SFlorian Westphal 			return -EFAULT;
308a0ae2562SFlorian Westphal 		else
309a0ae2562SFlorian Westphal 			return 0;
310a0ae2562SFlorian Westphal 	}
311a0ae2562SFlorian Westphal 	return -ENOENT;
312a0ae2562SFlorian Westphal }
313a0ae2562SFlorian Westphal 
314a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst = {
315a0ae2562SFlorian Westphal 	.pf		= PF_INET,
316a0ae2562SFlorian Westphal 	.get_optmin	= SO_ORIGINAL_DST,
317a0ae2562SFlorian Westphal 	.get_optmax	= SO_ORIGINAL_DST + 1,
318a0ae2562SFlorian Westphal 	.get		= getorigdst,
319a0ae2562SFlorian Westphal 	.owner		= THIS_MODULE,
320a0ae2562SFlorian Westphal };
321a0ae2562SFlorian Westphal 
322a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
323a0ae2562SFlorian Westphal static int
ipv6_getorigdst(struct sock * sk,int optval,void __user * user,int * len)324a0ae2562SFlorian Westphal ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
325a0ae2562SFlorian Westphal {
326a0ae2562SFlorian Westphal 	struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
327a0ae2562SFlorian Westphal 	const struct ipv6_pinfo *inet6 = inet6_sk(sk);
328a0ae2562SFlorian Westphal 	const struct inet_sock *inet = inet_sk(sk);
329a0ae2562SFlorian Westphal 	const struct nf_conntrack_tuple_hash *h;
330a0ae2562SFlorian Westphal 	struct sockaddr_in6 sin6;
331a0ae2562SFlorian Westphal 	struct nf_conn *ct;
332a0ae2562SFlorian Westphal 	__be32 flow_label;
333a0ae2562SFlorian Westphal 	int bound_dev_if;
334a0ae2562SFlorian Westphal 
335a0ae2562SFlorian Westphal 	lock_sock(sk);
336a0ae2562SFlorian Westphal 	tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
337a0ae2562SFlorian Westphal 	tuple.src.u.tcp.port = inet->inet_sport;
338a0ae2562SFlorian Westphal 	tuple.dst.u3.in6 = sk->sk_v6_daddr;
339a0ae2562SFlorian Westphal 	tuple.dst.u.tcp.port = inet->inet_dport;
340a0ae2562SFlorian Westphal 	tuple.dst.protonum = sk->sk_protocol;
341a0ae2562SFlorian Westphal 	bound_dev_if = sk->sk_bound_dev_if;
342a0ae2562SFlorian Westphal 	flow_label = inet6->flow_label;
343a0ae2562SFlorian Westphal 	release_sock(sk);
344a0ae2562SFlorian Westphal 
345a0ae2562SFlorian Westphal 	if (tuple.dst.protonum != IPPROTO_TCP &&
346a0ae2562SFlorian Westphal 	    tuple.dst.protonum != IPPROTO_SCTP)
347a0ae2562SFlorian Westphal 		return -ENOPROTOOPT;
348a0ae2562SFlorian Westphal 
349a0ae2562SFlorian Westphal 	if (*len < 0 || (unsigned int)*len < sizeof(sin6))
350a0ae2562SFlorian Westphal 		return -EINVAL;
351a0ae2562SFlorian Westphal 
352a0ae2562SFlorian Westphal 	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
353*50bfbb89SFlorian Westphal 	if (!h)
354a0ae2562SFlorian Westphal 		return -ENOENT;
355a0ae2562SFlorian Westphal 
356a0ae2562SFlorian Westphal 	ct = nf_ct_tuplehash_to_ctrack(h);
357a0ae2562SFlorian Westphal 
358a0ae2562SFlorian Westphal 	sin6.sin6_family = AF_INET6;
359a0ae2562SFlorian Westphal 	sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
360a0ae2562SFlorian Westphal 	sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
361a0ae2562SFlorian Westphal 	memcpy(&sin6.sin6_addr,
362a0ae2562SFlorian Westphal 	       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
363a0ae2562SFlorian Westphal 	       sizeof(sin6.sin6_addr));
364a0ae2562SFlorian Westphal 
365a0ae2562SFlorian Westphal 	nf_ct_put(ct);
366a0ae2562SFlorian Westphal 	sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
367a0ae2562SFlorian Westphal 	return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
368a0ae2562SFlorian Westphal }
369a0ae2562SFlorian Westphal 
370a0ae2562SFlorian Westphal static struct nf_sockopt_ops so_getorigdst6 = {
371a0ae2562SFlorian Westphal 	.pf		= NFPROTO_IPV6,
372a0ae2562SFlorian Westphal 	.get_optmin	= IP6T_SO_ORIGINAL_DST,
373a0ae2562SFlorian Westphal 	.get_optmax	= IP6T_SO_ORIGINAL_DST + 1,
374a0ae2562SFlorian Westphal 	.get		= ipv6_getorigdst,
375a0ae2562SFlorian Westphal 	.owner		= THIS_MODULE,
376a0ae2562SFlorian Westphal };
377a0ae2562SFlorian Westphal 
ipv6_conntrack_in(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)378a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_in(void *priv,
379a0ae2562SFlorian Westphal 				      struct sk_buff *skb,
380a0ae2562SFlorian Westphal 				      const struct nf_hook_state *state)
381a0ae2562SFlorian Westphal {
38293e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
383a0ae2562SFlorian Westphal }
384a0ae2562SFlorian Westphal 
ipv6_conntrack_local(void * priv,struct sk_buff * skb,const struct nf_hook_state * state)385a0ae2562SFlorian Westphal static unsigned int ipv6_conntrack_local(void *priv,
386a0ae2562SFlorian Westphal 					 struct sk_buff *skb,
387a0ae2562SFlorian Westphal 					 const struct nf_hook_state *state)
388a0ae2562SFlorian Westphal {
38993e66024SFlorian Westphal 	return nf_conntrack_in(skb, state);
390a0ae2562SFlorian Westphal }
391a0ae2562SFlorian Westphal 
392a0ae2562SFlorian Westphal static const struct nf_hook_ops ipv6_conntrack_ops[] = {
393a0ae2562SFlorian Westphal 	{
394a0ae2562SFlorian Westphal 		.hook		= ipv6_conntrack_in,
395a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
396a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_PRE_ROUTING,
397a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_CONNTRACK,
398a0ae2562SFlorian Westphal 	},
399a0ae2562SFlorian Westphal 	{
400a0ae2562SFlorian Westphal 		.hook		= ipv6_conntrack_local,
401a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
402a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_OUT,
403a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_CONNTRACK,
404a0ae2562SFlorian Westphal 	},
405a0ae2562SFlorian Westphal 	{
406a70e4834SFlorian Westphal 		.hook		= nf_confirm,
407a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
408a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_POST_ROUTING,
409a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_LAST,
410a0ae2562SFlorian Westphal 	},
411a0ae2562SFlorian Westphal 	{
412a70e4834SFlorian Westphal 		.hook		= nf_confirm,
413a0ae2562SFlorian Westphal 		.pf		= NFPROTO_IPV6,
414a0ae2562SFlorian Westphal 		.hooknum	= NF_INET_LOCAL_IN,
415a0ae2562SFlorian Westphal 		.priority	= NF_IP6_PRI_LAST - 1,
416a0ae2562SFlorian Westphal 	},
417a0ae2562SFlorian Westphal };
418a0ae2562SFlorian Westphal #endif
419a0ae2562SFlorian Westphal 
nf_ct_tcp_fixup(struct nf_conn * ct,void * _nfproto)420f94e6380SFlorian Westphal static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto)
421f94e6380SFlorian Westphal {
422f94e6380SFlorian Westphal 	u8 nfproto = (unsigned long)_nfproto;
423f94e6380SFlorian Westphal 
424f94e6380SFlorian Westphal 	if (nf_ct_l3num(ct) != nfproto)
425f94e6380SFlorian Westphal 		return 0;
426f94e6380SFlorian Westphal 
427f94e6380SFlorian Westphal 	if (nf_ct_protonum(ct) == IPPROTO_TCP &&
428f94e6380SFlorian Westphal 	    ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
429f94e6380SFlorian Westphal 		ct->proto.tcp.seen[0].td_maxwin = 0;
430f94e6380SFlorian Westphal 		ct->proto.tcp.seen[1].td_maxwin = 0;
431f94e6380SFlorian Westphal 	}
432f94e6380SFlorian Westphal 
433f94e6380SFlorian Westphal 	return 0;
434f94e6380SFlorian Westphal }
435f94e6380SFlorian Westphal 
436d035f19fSPablo Neira Ayuso static struct nf_ct_bridge_info *nf_ct_bridge_info;
437d035f19fSPablo Neira Ayuso 
nf_ct_netns_do_get(struct net * net,u8 nfproto)438a0ae2562SFlorian Westphal static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
439a0ae2562SFlorian Westphal {
4400418b989SPablo Neira Ayuso 	struct nf_conntrack_net *cnet = nf_ct_pernet(net);
441d035f19fSPablo Neira Ayuso 	bool fixup_needed = false, retry = true;
442a0ae2562SFlorian Westphal 	int err = 0;
443d035f19fSPablo Neira Ayuso retry:
444a0ae2562SFlorian Westphal 	mutex_lock(&nf_ct_proto_mutex);
445a0ae2562SFlorian Westphal 
446a0ae2562SFlorian Westphal 	switch (nfproto) {
447a0ae2562SFlorian Westphal 	case NFPROTO_IPV4:
448a0ae2562SFlorian Westphal 		cnet->users4++;
449a0ae2562SFlorian Westphal 		if (cnet->users4 > 1)
450a0ae2562SFlorian Westphal 			goto out_unlock;
451a0ae2562SFlorian Westphal 		err = nf_defrag_ipv4_enable(net);
452a0ae2562SFlorian Westphal 		if (err) {
453a0ae2562SFlorian Westphal 			cnet->users4 = 0;
454a0ae2562SFlorian Westphal 			goto out_unlock;
455a0ae2562SFlorian Westphal 		}
456a0ae2562SFlorian Westphal 
457a0ae2562SFlorian Westphal 		err = nf_register_net_hooks(net, ipv4_conntrack_ops,
458a0ae2562SFlorian Westphal 					    ARRAY_SIZE(ipv4_conntrack_ops));
459a0ae2562SFlorian Westphal 		if (err)
460a0ae2562SFlorian Westphal 			cnet->users4 = 0;
461f94e6380SFlorian Westphal 		else
462f94e6380SFlorian Westphal 			fixup_needed = true;
463a0ae2562SFlorian Westphal 		break;
464a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
465a0ae2562SFlorian Westphal 	case NFPROTO_IPV6:
466a0ae2562SFlorian Westphal 		cnet->users6++;
467a0ae2562SFlorian Westphal 		if (cnet->users6 > 1)
468a0ae2562SFlorian Westphal 			goto out_unlock;
469a0ae2562SFlorian Westphal 		err = nf_defrag_ipv6_enable(net);
470a0ae2562SFlorian Westphal 		if (err < 0) {
471a0ae2562SFlorian Westphal 			cnet->users6 = 0;
472a0ae2562SFlorian Westphal 			goto out_unlock;
473a0ae2562SFlorian Westphal 		}
474a0ae2562SFlorian Westphal 
475a0ae2562SFlorian Westphal 		err = nf_register_net_hooks(net, ipv6_conntrack_ops,
476a0ae2562SFlorian Westphal 					    ARRAY_SIZE(ipv6_conntrack_ops));
477a0ae2562SFlorian Westphal 		if (err)
478a0ae2562SFlorian Westphal 			cnet->users6 = 0;
479f94e6380SFlorian Westphal 		else
480f94e6380SFlorian Westphal 			fixup_needed = true;
481a0ae2562SFlorian Westphal 		break;
482a0ae2562SFlorian Westphal #endif
483d035f19fSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
484d035f19fSPablo Neira Ayuso 		if (!nf_ct_bridge_info) {
485d035f19fSPablo Neira Ayuso 			if (!retry) {
486d035f19fSPablo Neira Ayuso 				err = -EPROTO;
487d035f19fSPablo Neira Ayuso 				goto out_unlock;
488d035f19fSPablo Neira Ayuso 			}
489d035f19fSPablo Neira Ayuso 			mutex_unlock(&nf_ct_proto_mutex);
490d035f19fSPablo Neira Ayuso 			request_module("nf_conntrack_bridge");
491d035f19fSPablo Neira Ayuso 			retry = false;
492d035f19fSPablo Neira Ayuso 			goto retry;
493d035f19fSPablo Neira Ayuso 		}
494d035f19fSPablo Neira Ayuso 		if (!try_module_get(nf_ct_bridge_info->me)) {
495d035f19fSPablo Neira Ayuso 			err = -EPROTO;
496d035f19fSPablo Neira Ayuso 			goto out_unlock;
497d035f19fSPablo Neira Ayuso 		}
498d035f19fSPablo Neira Ayuso 		cnet->users_bridge++;
499d035f19fSPablo Neira Ayuso 		if (cnet->users_bridge > 1)
500d035f19fSPablo Neira Ayuso 			goto out_unlock;
501d035f19fSPablo Neira Ayuso 
502d035f19fSPablo Neira Ayuso 		err = nf_register_net_hooks(net, nf_ct_bridge_info->ops,
503d035f19fSPablo Neira Ayuso 					    nf_ct_bridge_info->ops_size);
504d035f19fSPablo Neira Ayuso 		if (err)
505d035f19fSPablo Neira Ayuso 			cnet->users_bridge = 0;
506d035f19fSPablo Neira Ayuso 		else
507d035f19fSPablo Neira Ayuso 			fixup_needed = true;
508d035f19fSPablo Neira Ayuso 		break;
509a0ae2562SFlorian Westphal 	default:
510a0ae2562SFlorian Westphal 		err = -EPROTO;
511a0ae2562SFlorian Westphal 		break;
512a0ae2562SFlorian Westphal 	}
513a0ae2562SFlorian Westphal  out_unlock:
514a0ae2562SFlorian Westphal 	mutex_unlock(&nf_ct_proto_mutex);
515f94e6380SFlorian Westphal 
5168169ff58SPablo Neira Ayuso 	if (fixup_needed) {
5178169ff58SPablo Neira Ayuso 		struct nf_ct_iter_data iter_data = {
5188169ff58SPablo Neira Ayuso 			.net	= net,
5198169ff58SPablo Neira Ayuso 			.data	= (void *)(unsigned long)nfproto,
5208169ff58SPablo Neira Ayuso 		};
5218169ff58SPablo Neira Ayuso 		nf_ct_iterate_cleanup_net(nf_ct_tcp_fixup, &iter_data);
5228169ff58SPablo Neira Ayuso 	}
523f94e6380SFlorian Westphal 
524a0ae2562SFlorian Westphal 	return err;
525a0ae2562SFlorian Westphal }
526a0ae2562SFlorian Westphal 
nf_ct_netns_do_put(struct net * net,u8 nfproto)527a0ae2562SFlorian Westphal static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
528a0ae2562SFlorian Westphal {
5290418b989SPablo Neira Ayuso 	struct nf_conntrack_net *cnet = nf_ct_pernet(net);
530a0ae2562SFlorian Westphal 
531a0ae2562SFlorian Westphal 	mutex_lock(&nf_ct_proto_mutex);
532a0ae2562SFlorian Westphal 	switch (nfproto) {
533a0ae2562SFlorian Westphal 	case NFPROTO_IPV4:
534de8c1211SFlorian Westphal 		if (cnet->users4 && (--cnet->users4 == 0)) {
535a0ae2562SFlorian Westphal 			nf_unregister_net_hooks(net, ipv4_conntrack_ops,
536a0ae2562SFlorian Westphal 						ARRAY_SIZE(ipv4_conntrack_ops));
537de8c1211SFlorian Westphal 			nf_defrag_ipv4_disable(net);
538de8c1211SFlorian Westphal 		}
539a0ae2562SFlorian Westphal 		break;
540a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
541a0ae2562SFlorian Westphal 	case NFPROTO_IPV6:
542de8c1211SFlorian Westphal 		if (cnet->users6 && (--cnet->users6 == 0)) {
543a0ae2562SFlorian Westphal 			nf_unregister_net_hooks(net, ipv6_conntrack_ops,
544a0ae2562SFlorian Westphal 						ARRAY_SIZE(ipv6_conntrack_ops));
545de8c1211SFlorian Westphal 			nf_defrag_ipv6_disable(net);
546de8c1211SFlorian Westphal 		}
547a0ae2562SFlorian Westphal 		break;
548a0ae2562SFlorian Westphal #endif
549d035f19fSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
550d035f19fSPablo Neira Ayuso 		if (!nf_ct_bridge_info)
551d035f19fSPablo Neira Ayuso 			break;
552d035f19fSPablo Neira Ayuso 		if (cnet->users_bridge && (--cnet->users_bridge == 0))
553d035f19fSPablo Neira Ayuso 			nf_unregister_net_hooks(net, nf_ct_bridge_info->ops,
554d035f19fSPablo Neira Ayuso 						nf_ct_bridge_info->ops_size);
555a0ae2562SFlorian Westphal 
556d035f19fSPablo Neira Ayuso 		module_put(nf_ct_bridge_info->me);
557d035f19fSPablo Neira Ayuso 		break;
558d035f19fSPablo Neira Ayuso 	}
559a0ae2562SFlorian Westphal 	mutex_unlock(&nf_ct_proto_mutex);
560a0ae2562SFlorian Westphal }
561a0ae2562SFlorian Westphal 
nf_ct_netns_inet_get(struct net * net)562af9573beSPablo Neira Ayuso static int nf_ct_netns_inet_get(struct net *net)
563a0ae2562SFlorian Westphal {
564a0ae2562SFlorian Westphal 	int err;
565a0ae2562SFlorian Westphal 
566a0ae2562SFlorian Westphal 	err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
567526e81b9SEelco Chaudron #if IS_ENABLED(CONFIG_IPV6)
568a0ae2562SFlorian Westphal 	if (err < 0)
569a0ae2562SFlorian Westphal 		goto err1;
570a0ae2562SFlorian Westphal 	err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
571a0ae2562SFlorian Westphal 	if (err < 0)
572a0ae2562SFlorian Westphal 		goto err2;
573a0ae2562SFlorian Westphal 
574af9573beSPablo Neira Ayuso 	return err;
575a0ae2562SFlorian Westphal err2:
576a0ae2562SFlorian Westphal 	nf_ct_netns_put(net, NFPROTO_IPV4);
577a0ae2562SFlorian Westphal err1:
578526e81b9SEelco Chaudron #endif
579a0ae2562SFlorian Westphal 	return err;
580a0ae2562SFlorian Westphal }
581af9573beSPablo Neira Ayuso 
nf_ct_netns_get(struct net * net,u8 nfproto)582af9573beSPablo Neira Ayuso int nf_ct_netns_get(struct net *net, u8 nfproto)
583af9573beSPablo Neira Ayuso {
584af9573beSPablo Neira Ayuso 	int err;
585af9573beSPablo Neira Ayuso 
586af9573beSPablo Neira Ayuso 	switch (nfproto) {
587af9573beSPablo Neira Ayuso 	case NFPROTO_INET:
588af9573beSPablo Neira Ayuso 		err = nf_ct_netns_inet_get(net);
589af9573beSPablo Neira Ayuso 		break;
590af9573beSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
591af9573beSPablo Neira Ayuso 		err = nf_ct_netns_do_get(net, NFPROTO_BRIDGE);
592af9573beSPablo Neira Ayuso 		if (err < 0)
593af9573beSPablo Neira Ayuso 			return err;
594af9573beSPablo Neira Ayuso 
595af9573beSPablo Neira Ayuso 		err = nf_ct_netns_inet_get(net);
596af9573beSPablo Neira Ayuso 		if (err < 0) {
597af9573beSPablo Neira Ayuso 			nf_ct_netns_put(net, NFPROTO_BRIDGE);
598af9573beSPablo Neira Ayuso 			return err;
599af9573beSPablo Neira Ayuso 		}
600af9573beSPablo Neira Ayuso 		break;
601af9573beSPablo Neira Ayuso 	default:
602af9573beSPablo Neira Ayuso 		err = nf_ct_netns_do_get(net, nfproto);
603af9573beSPablo Neira Ayuso 		break;
604af9573beSPablo Neira Ayuso 	}
605af9573beSPablo Neira Ayuso 	return err;
606af9573beSPablo Neira Ayuso }
607a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_get);
608a0ae2562SFlorian Westphal 
nf_ct_netns_put(struct net * net,uint8_t nfproto)609a0ae2562SFlorian Westphal void nf_ct_netns_put(struct net *net, uint8_t nfproto)
610a0ae2562SFlorian Westphal {
611af9573beSPablo Neira Ayuso 	switch (nfproto) {
612af9573beSPablo Neira Ayuso 	case NFPROTO_BRIDGE:
613af9573beSPablo Neira Ayuso 		nf_ct_netns_do_put(net, NFPROTO_BRIDGE);
614954d8297SGustavo A. R. Silva 		fallthrough;
615af9573beSPablo Neira Ayuso 	case NFPROTO_INET:
616a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, NFPROTO_IPV4);
617a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, NFPROTO_IPV6);
618af9573beSPablo Neira Ayuso 		break;
619af9573beSPablo Neira Ayuso 	default:
620a0ae2562SFlorian Westphal 		nf_ct_netns_do_put(net, nfproto);
621af9573beSPablo Neira Ayuso 		break;
622a0ae2562SFlorian Westphal 	}
623a0ae2562SFlorian Westphal }
624a0ae2562SFlorian Westphal EXPORT_SYMBOL_GPL(nf_ct_netns_put);
625a0ae2562SFlorian Westphal 
nf_ct_bridge_register(struct nf_ct_bridge_info * info)626d035f19fSPablo Neira Ayuso void nf_ct_bridge_register(struct nf_ct_bridge_info *info)
627d035f19fSPablo Neira Ayuso {
628d035f19fSPablo Neira Ayuso 	WARN_ON(nf_ct_bridge_info);
629d035f19fSPablo Neira Ayuso 	mutex_lock(&nf_ct_proto_mutex);
630d035f19fSPablo Neira Ayuso 	nf_ct_bridge_info = info;
631d035f19fSPablo Neira Ayuso 	mutex_unlock(&nf_ct_proto_mutex);
632d035f19fSPablo Neira Ayuso }
633d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_register);
634d035f19fSPablo Neira Ayuso 
nf_ct_bridge_unregister(struct nf_ct_bridge_info * info)635d035f19fSPablo Neira Ayuso void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info)
636d035f19fSPablo Neira Ayuso {
637d035f19fSPablo Neira Ayuso 	WARN_ON(!nf_ct_bridge_info);
638d035f19fSPablo Neira Ayuso 	mutex_lock(&nf_ct_proto_mutex);
639d035f19fSPablo Neira Ayuso 	nf_ct_bridge_info = NULL;
640d035f19fSPablo Neira Ayuso 	mutex_unlock(&nf_ct_proto_mutex);
641d035f19fSPablo Neira Ayuso }
642d035f19fSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_bridge_unregister);
643d035f19fSPablo Neira Ayuso 
nf_conntrack_proto_init(void)644a0ae2562SFlorian Westphal int nf_conntrack_proto_init(void)
645a0ae2562SFlorian Westphal {
6464a60dc74SFlorian Westphal 	int ret;
647a0ae2562SFlorian Westphal 
648a0ae2562SFlorian Westphal 	ret = nf_register_sockopt(&so_getorigdst);
649a0ae2562SFlorian Westphal 	if (ret < 0)
650a0ae2562SFlorian Westphal 		return ret;
651a0ae2562SFlorian Westphal 
652a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
653a0ae2562SFlorian Westphal 	ret = nf_register_sockopt(&so_getorigdst6);
654a0ae2562SFlorian Westphal 	if (ret < 0)
655a0ae2562SFlorian Westphal 		goto cleanup_sockopt;
656a0ae2562SFlorian Westphal #endif
657dd2934a9SFlorian Westphal 
658a0ae2562SFlorian Westphal 	return ret;
6594a60dc74SFlorian Westphal 
660a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
661a0ae2562SFlorian Westphal cleanup_sockopt:
66222cbdbcfSFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst);
663a0ae2562SFlorian Westphal #endif
664a0ae2562SFlorian Westphal 	return ret;
665a0ae2562SFlorian Westphal }
666a0ae2562SFlorian Westphal 
nf_conntrack_proto_fini(void)667a0ae2562SFlorian Westphal void nf_conntrack_proto_fini(void)
668a0ae2562SFlorian Westphal {
669a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst);
670a0ae2562SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
671a0ae2562SFlorian Westphal 	nf_unregister_sockopt(&so_getorigdst6);
672a0ae2562SFlorian Westphal #endif
673a0ae2562SFlorian Westphal }
674a0ae2562SFlorian Westphal 
nf_conntrack_proto_pernet_init(struct net * net)6754a60dc74SFlorian Westphal void nf_conntrack_proto_pernet_init(struct net *net)
676ac5357ebSPatrick McHardy {
6772a389de8SFlorian Westphal 	nf_conntrack_generic_init_net(net);
6782a389de8SFlorian Westphal 	nf_conntrack_udp_init_net(net);
6792a389de8SFlorian Westphal 	nf_conntrack_tcp_init_net(net);
6802a389de8SFlorian Westphal 	nf_conntrack_icmp_init_net(net);
68181e01647SFlorian Westphal #if IS_ENABLED(CONFIG_IPV6)
6822a389de8SFlorian Westphal 	nf_conntrack_icmpv6_init_net(net);
68381e01647SFlorian Westphal #endif
6842a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_DCCP
6852a389de8SFlorian Westphal 	nf_conntrack_dccp_init_net(net);
6862a389de8SFlorian Westphal #endif
6872a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_SCTP
6882a389de8SFlorian Westphal 	nf_conntrack_sctp_init_net(net);
6892a389de8SFlorian Westphal #endif
6902a389de8SFlorian Westphal #ifdef CONFIG_NF_CT_PROTO_GRE
6912a389de8SFlorian Westphal 	nf_conntrack_gre_init_net(net);
6922a389de8SFlorian Westphal #endif
693ac5357ebSPatrick McHardy }
694ac5357ebSPatrick McHardy 
695a0ae2562SFlorian Westphal module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
696a0ae2562SFlorian Westphal 		  &nf_conntrack_htable_size, 0600);
697a0ae2562SFlorian Westphal 
698a0ae2562SFlorian Westphal MODULE_ALIAS("ip_conntrack");
699a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
700a0ae2562SFlorian Westphal MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
701a0ae2562SFlorian Westphal MODULE_LICENSE("GPL");
702