File Index
Files and directories
Sign in
FILE

nf_conntrack_proto.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nf_conntrack_proto.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include <linux/types.h>
  4#include <linux/netfilter.h>
  5#include <linux/module.h>
  6#include <linux/slab.h>
  7#include <linux/mutex.h>
  8#include <linux/vmalloc.h>
  9#include <linux/stddef.h>
 10#include <linux/err.h>
 11#include <linux/percpu.h>
 12#include <linux/notifier.h>
 13#include <linux/kernel.h>
 14#include <linux/netdevice.h>
 15
 16#include <net/netfilter/nf_conntrack.h>
 17#include <net/netfilter/nf_conntrack_l4proto.h>
 18#include <net/netfilter/nf_conntrack_core.h>
 19#include <net/netfilter/nf_conntrack_bridge.h>
 20#include <net/netfilter/nf_log.h>
 21
 22#include <linux/ip.h>
 23#include <linux/icmp.h>
 24#include <linux/sysctl.h>
 25#include <net/route.h>
 26#include <net/ip.h>
 27
 28#include <linux/netfilter_ipv4.h>
 29#include <linux/netfilter_ipv6.h>
 30#include <linux/netfilter_ipv6/ip6_tables.h>
 31#include <net/netfilter/nf_conntrack_helper.h>
 32#include <net/netfilter/nf_conntrack_zones.h>
 33#include <net/netfilter/nf_conntrack_seqadj.h>
 34#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 35#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 36#include <net/netfilter/nf_nat_helper.h>
 37#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
 38#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
 39
 40#include <linux/ipv6.h>
 41#include <linux/in6.h>
 42#include <net/ipv6.h>
 43#include <net/inet_frag.h>
 44
 45static DEFINE_MUTEX(nf_ct_proto_mutex);
 46
 47#ifdef CONFIG_SYSCTL
 48__printf(4, 5)
 49void nf_l4proto_log_invalid(const struct sk_buff *skb,
 50			    const struct nf_hook_state *state,
 51			    u8 protonum,
 52			    const char *fmt, ...)
 53{
 54	struct net *net = state->net;
 55	struct va_format vaf;
 56	va_list args;
 57
 58	if (net->ct.sysctl_log_invalid != protonum &&
 59	    net->ct.sysctl_log_invalid != IPPROTO_RAW)
 60		return;
 61
 62	va_start(args, fmt);
 63	vaf.fmt = fmt;
 64	vaf.va = &args;
 65
 66	nf_log_packet(net, state->pf, 0, skb, state->in, state->out,
 67		      NULL, "nf_ct_proto_%d: %pV ", protonum, &vaf);
 68	va_end(args);
 69}
 70EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid);
 71
 72__printf(4, 5)
 73void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
 74			       const struct nf_conn *ct,
 75			       const struct nf_hook_state *state,
 76			       const char *fmt, ...)
 77{
 78	struct va_format vaf;
 79	struct net *net;
 80	va_list args;
 81
 82	net = nf_ct_net(ct);
 83	if (likely(net->ct.sysctl_log_invalid == 0))
 84		return;
 85
 86	va_start(args, fmt);
 87	vaf.fmt = fmt;
 88	vaf.va = &args;
 89
 90	nf_l4proto_log_invalid(skb, state,
 91			       nf_ct_protonum(ct), "%pV", &vaf);
 92	va_end(args);
 93}
 94EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid);
 95#endif
 96
 97const struct nf_conntrack_l4proto *nf_ct_l4proto_find(u8 l4proto)
 98{
 99	switch (l4proto) {
100	case IPPROTO_UDP: return &nf_conntrack_l4proto_udp;
101	case IPPROTO_TCP: return &nf_conntrack_l4proto_tcp;
102	case IPPROTO_ICMP: return &nf_conntrack_l4proto_icmp;
103#ifdef CONFIG_NF_CT_PROTO_SCTP
104	case IPPROTO_SCTP: return &nf_conntrack_l4proto_sctp;
105#endif
106#ifdef CONFIG_NF_CT_PROTO_UDPLITE
107	case IPPROTO_UDPLITE: return &nf_conntrack_l4proto_udplite;
108#endif
109#ifdef CONFIG_NF_CT_PROTO_GRE
110	case IPPROTO_GRE: return &nf_conntrack_l4proto_gre;
111#endif
112#if IS_ENABLED(CONFIG_IPV6)
113	case IPPROTO_ICMPV6: return &nf_conntrack_l4proto_icmpv6;
114#endif /* CONFIG_IPV6 */
115	}
116
117	return &nf_conntrack_l4proto_generic;
118};
119EXPORT_SYMBOL_GPL(nf_ct_l4proto_find);
120
121static bool in_vrf_postrouting(const struct nf_hook_state *state)
122{
123#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
124	if (state->hook == NF_INET_POST_ROUTING &&
125	    netif_is_l3_master(state->out))
126		return true;
127#endif
128	return false;
129}
130
131unsigned int nf_confirm(void *priv,
132			struct sk_buff *skb,
133			const struct nf_hook_state *state)
134{
135	const struct nf_conn_help *help;
136	enum ip_conntrack_info ctinfo;
137	unsigned int protoff;
138	struct nf_conn *ct;
139	bool seqadj_needed;
140	__be16 frag_off;
141	int start;
142	u8 pnum;
143
144	ct = nf_ct_get(skb, &ctinfo);
145	if (!ct || in_vrf_postrouting(state))
146		return NF_ACCEPT;
147
148	help = nfct_help(ct);
149
150	seqadj_needed = test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && !nf_is_loopback_packet(skb);
151	if (!help && !seqadj_needed)
152		return nf_conntrack_confirm(skb);
153
154	/* helper->help() do not expect ICMP packets */
155	if (ctinfo == IP_CT_RELATED_REPLY)
156		return nf_conntrack_confirm(skb);
157
158	switch (nf_ct_l3num(ct)) {
159	case NFPROTO_IPV4:
160		protoff = skb_network_offset(skb) + ip_hdrlen(skb);
161		break;
162	case NFPROTO_IPV6:
163		pnum = ipv6_hdr(skb)->nexthdr;
164		start = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, &frag_off);
165		if (start < 0 || (frag_off & htons(~0x7)) != 0)
166			return nf_conntrack_confirm(skb);
167
168		protoff = start;
169		break;
170	default:
171		return nf_conntrack_confirm(skb);
172	}
173
174	if (help) {
175		const struct nf_conntrack_helper *helper;
176		int ret;
177
178		/* rcu_read_lock()ed by nf_hook */
179		helper = rcu_dereference(help->helper);
180		if (helper) {
181			ret = helper->help(skb,
182					   protoff,
183					   ct, ctinfo);
184			if (ret != NF_ACCEPT)
185				return ret;
186		}
187	}
188
189	if (seqadj_needed &&
190	    !nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
191		NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
192		return NF_DROP;
193	}
194
195	/* We've seen it coming out the other side: confirm it */
196	return nf_conntrack_confirm(skb);
197}
198EXPORT_SYMBOL_GPL(nf_confirm);
199
200static unsigned int ipv4_conntrack_in(void *priv,
201				      struct sk_buff *skb,
202				      const struct nf_hook_state *state)
203{
204	return nf_conntrack_in(skb, state);
205}
206
207static unsigned int ipv4_conntrack_local(void *priv,
208					 struct sk_buff *skb,
209					 const struct nf_hook_state *state)
210{
211	if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
212		enum ip_conntrack_info ctinfo;
213		struct nf_conn *tmpl;
214
215		tmpl = nf_ct_get(skb, &ctinfo);
216		if (tmpl && nf_ct_is_template(tmpl)) {
217			/* when skipping ct, clear templates to avoid fooling
218			 * later targets/matches
219			 */
220			skb->_nfct = 0;
221			nf_ct_put(tmpl);
222		}
223		return NF_ACCEPT;
224	}
225
226	return nf_conntrack_in(skb, state);
227}
228
229/* Connection tracking may drop packets, but never alters them, so
230 * make it the first hook.
231 */
232static const struct nf_hook_ops ipv4_conntrack_ops[] = {
233	{
234		.hook		= ipv4_conntrack_in,
235		.pf		= NFPROTO_IPV4,
236		.hooknum	= NF_INET_PRE_ROUTING,
237		.priority	= NF_IP_PRI_CONNTRACK,
238	},
239	{
240		.hook		= ipv4_conntrack_local,
241		.pf		= NFPROTO_IPV4,
242		.hooknum	= NF_INET_LOCAL_OUT,
243		.priority	= NF_IP_PRI_CONNTRACK,
244	},
245	{
246		.hook		= nf_confirm,
247		.pf		= NFPROTO_IPV4,
248		.hooknum	= NF_INET_POST_ROUTING,
249		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
250	},
251	{
252		.hook		= nf_confirm,
253		.pf		= NFPROTO_IPV4,
254		.hooknum	= NF_INET_LOCAL_IN,
255		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
256	},
257};
258
259/* Fast function for those who don't want to parse /proc (and I don't
260 * blame them).
261 * Reversing the socket's dst/src point of view gives us the reply
262 * mapping.
263 */
264static int
265getorigdst(struct sock *sk, int optval, void __user *user, int *len)
266{
267	const struct inet_sock *inet = inet_sk(sk);
268	const struct nf_conntrack_tuple_hash *h;
269	struct nf_conntrack_tuple tuple;
270
271	memset(&tuple, 0, sizeof(tuple));
272
273	lock_sock(sk);
274	tuple.src.u3.ip = inet->inet_rcv_saddr;
275	tuple.src.u.tcp.port = inet->inet_sport;
276	tuple.dst.u3.ip = inet->inet_daddr;
277	tuple.dst.u.tcp.port = inet->inet_dport;
278	tuple.src.l3num = PF_INET;
279	tuple.dst.protonum = sk->sk_protocol;
280	release_sock(sk);
281
282	/* We only do TCP and SCTP at the moment: is there a better way? */
283	if (tuple.dst.protonum != IPPROTO_TCP &&
284	    tuple.dst.protonum != IPPROTO_SCTP)
285		return -ENOPROTOOPT;
286
287	if ((unsigned int)*len < sizeof(struct sockaddr_in))
288		return -EINVAL;
289
290	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
291	if (h) {
292		struct sockaddr_in sin;
293		struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
294
295		sin.sin_family = AF_INET;
296		sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
297			.tuple.dst.u.tcp.port;
298		sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
299			.tuple.dst.u3.ip;
300		memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
301
302		nf_ct_put(ct);
303		if (copy_to_user(user, &sin, sizeof(sin)) != 0)
304			return -EFAULT;
305		else
306			return 0;
307	}
308	return -ENOENT;
309}
310
311static struct nf_sockopt_ops so_getorigdst = {
312	.pf		= PF_INET,
313	.get_optmin	= SO_ORIGINAL_DST,
314	.get_optmax	= SO_ORIGINAL_DST + 1,
315	.get		= getorigdst,
316	.owner		= THIS_MODULE,
317};
318
319#if IS_ENABLED(CONFIG_IPV6)
320static int
321ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
322{
323	struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
324	const struct ipv6_pinfo *inet6 = inet6_sk(sk);
325	const struct inet_sock *inet = inet_sk(sk);
326	const struct nf_conntrack_tuple_hash *h;
327	struct sockaddr_in6 sin6;
328	struct nf_conn *ct;
329	__be32 flow_label;
330	int bound_dev_if;
331
332	lock_sock(sk);
333	tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
334	tuple.src.u.tcp.port = inet->inet_sport;
335	tuple.dst.u3.in6 = sk->sk_v6_daddr;
336	tuple.dst.u.tcp.port = inet->inet_dport;
337	tuple.dst.protonum = sk->sk_protocol;
338	bound_dev_if = sk->sk_bound_dev_if;
339	flow_label = inet6->flow_label;
340	release_sock(sk);
341
342	if (tuple.dst.protonum != IPPROTO_TCP &&
343	    tuple.dst.protonum != IPPROTO_SCTP)
344		return -ENOPROTOOPT;
345
346	if (*len < 0 || (unsigned int)*len < sizeof(sin6))
347		return -EINVAL;
348
349	h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
350	if (!h)
351		return -ENOENT;
352
353	ct = nf_ct_tuplehash_to_ctrack(h);
354
355	sin6.sin6_family = AF_INET6;
356	sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
357	sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
358	memcpy(&sin6.sin6_addr,
359	       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
360	       sizeof(sin6.sin6_addr));
361
362	nf_ct_put(ct);
363	sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
364	return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
365}
366
367static struct nf_sockopt_ops so_getorigdst6 = {
368	.pf		= NFPROTO_IPV6,
369	.get_optmin	= IP6T_SO_ORIGINAL_DST,
370	.get_optmax	= IP6T_SO_ORIGINAL_DST + 1,
371	.get		= ipv6_getorigdst,
372	.owner		= THIS_MODULE,
373};
374
375static unsigned int ipv6_conntrack_in(void *priv,
376				      struct sk_buff *skb,
377				      const struct nf_hook_state *state)
378{
379	return nf_conntrack_in(skb, state);
380}
381
382static unsigned int ipv6_conntrack_local(void *priv,
383					 struct sk_buff *skb,
384					 const struct nf_hook_state *state)
385{
386	return nf_conntrack_in(skb, state);
387}
388
389static const struct nf_hook_ops ipv6_conntrack_ops[] = {
390	{
391		.hook		= ipv6_conntrack_in,
392		.pf		= NFPROTO_IPV6,
393		.hooknum	= NF_INET_PRE_ROUTING,
394		.priority	= NF_IP6_PRI_CONNTRACK,
395	},
396	{
397		.hook		= ipv6_conntrack_local,
398		.pf		= NFPROTO_IPV6,
399		.hooknum	= NF_INET_LOCAL_OUT,
400		.priority	= NF_IP6_PRI_CONNTRACK,
401	},
402	{
403		.hook		= nf_confirm,
404		.pf		= NFPROTO_IPV6,
405		.hooknum	= NF_INET_POST_ROUTING,
406		.priority	= NF_IP6_PRI_LAST,
407	},
408	{
409		.hook		= nf_confirm,
410		.pf		= NFPROTO_IPV6,
411		.hooknum	= NF_INET_LOCAL_IN,
412		.priority	= NF_IP6_PRI_LAST - 1,
413	},
414};
415#endif
416
417static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto)
418{
419	u8 nfproto = (unsigned long)_nfproto;
420
421	if (nf_ct_l3num(ct) != nfproto)
422		return 0;
423
424	if (nf_ct_protonum(ct) == IPPROTO_TCP &&
425	    ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
426		ct->proto.tcp.seen[0].td_maxwin = 0;
427		ct->proto.tcp.seen[1].td_maxwin = 0;
428	}
429
430	return 0;
431}
432
433static struct nf_ct_bridge_info *nf_ct_bridge_info;
434
435static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
436{
437	struct nf_conntrack_net *cnet = nf_ct_pernet(net);
438	bool fixup_needed = false, retry = true;
439	int err = 0;
440retry:
441	mutex_lock(&nf_ct_proto_mutex);
442
443	switch (nfproto) {
444	case NFPROTO_IPV4:
445		cnet->users4++;
446		if (cnet->users4 > 1)
447			goto out_unlock;
448		err = nf_defrag_ipv4_enable(net);
449		if (err) {
450			cnet->users4 = 0;
451			goto out_unlock;
452		}
453
454		err = nf_register_net_hooks(net, ipv4_conntrack_ops,
455					    ARRAY_SIZE(ipv4_conntrack_ops));
456		if (err)
457			cnet->users4 = 0;
458		else
459			fixup_needed = true;
460		break;
461#if IS_ENABLED(CONFIG_IPV6)
462	case NFPROTO_IPV6:
463		cnet->users6++;
464		if (cnet->users6 > 1)
465			goto out_unlock;
466		err = nf_defrag_ipv6_enable(net);
467		if (err < 0) {
468			cnet->users6 = 0;
469			goto out_unlock;
470		}
471
472		err = nf_register_net_hooks(net, ipv6_conntrack_ops,
473					    ARRAY_SIZE(ipv6_conntrack_ops));
474		if (err)
475			cnet->users6 = 0;
476		else
477			fixup_needed = true;
478		break;
479#endif
480	case NFPROTO_BRIDGE:
481		if (!nf_ct_bridge_info) {
482			if (!retry) {
483				err = -EPROTO;
484				goto out_unlock;
485			}
486			mutex_unlock(&nf_ct_proto_mutex);
487			request_module("nf_conntrack_bridge");
488			retry = false;
489			goto retry;
490		}
491		if (!try_module_get(nf_ct_bridge_info->me)) {
492			err = -EPROTO;
493			goto out_unlock;
494		}
495		cnet->users_bridge++;
496		if (cnet->users_bridge > 1)
497			goto out_unlock;
498
499		err = nf_register_net_hooks(net, nf_ct_bridge_info->ops,
500					    nf_ct_bridge_info->ops_size);
501		if (err)
502			cnet->users_bridge = 0;
503		else
504			fixup_needed = true;
505		break;
506	default:
507		err = -EPROTO;
508		break;
509	}
510 out_unlock:
511	mutex_unlock(&nf_ct_proto_mutex);
512
513	if (fixup_needed) {
514		struct nf_ct_iter_data iter_data = {
515			.net	= net,
516			.data	= (void *)(unsigned long)nfproto,
517		};
518		nf_ct_iterate_cleanup_net(nf_ct_tcp_fixup, &iter_data);
519	}
520
521	return err;
522}
523
524static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
525{
526	struct nf_conntrack_net *cnet = nf_ct_pernet(net);
527
528	mutex_lock(&nf_ct_proto_mutex);
529	switch (nfproto) {
530	case NFPROTO_IPV4:
531		if (cnet->users4 && (--cnet->users4 == 0)) {
532			nf_unregister_net_hooks(net, ipv4_conntrack_ops,
533						ARRAY_SIZE(ipv4_conntrack_ops));
534			nf_defrag_ipv4_disable(net);
535		}
536		break;
537#if IS_ENABLED(CONFIG_IPV6)
538	case NFPROTO_IPV6:
539		if (cnet->users6 && (--cnet->users6 == 0)) {
540			nf_unregister_net_hooks(net, ipv6_conntrack_ops,
541						ARRAY_SIZE(ipv6_conntrack_ops));
542			nf_defrag_ipv6_disable(net);
543		}
544		break;
545#endif
546	case NFPROTO_BRIDGE:
547		if (!nf_ct_bridge_info)
548			break;
549		if (cnet->users_bridge && (--cnet->users_bridge == 0))
550			nf_unregister_net_hooks(net, nf_ct_bridge_info->ops,
551						nf_ct_bridge_info->ops_size);
552
553		module_put(nf_ct_bridge_info->me);
554		break;
555	}
556	mutex_unlock(&nf_ct_proto_mutex);
557}
558
559static int nf_ct_netns_inet_get(struct net *net)
560{
561	int err;
562
563	err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
564#if IS_ENABLED(CONFIG_IPV6)
565	if (err < 0)
566		goto err1;
567	err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
568	if (err < 0)
569		goto err2;
570
571	return err;
572err2:
573	nf_ct_netns_put(net, NFPROTO_IPV4);
574err1:
575#endif
576	return err;
577}
578
579int nf_ct_netns_get(struct net *net, u8 nfproto)
580{
581	int err;
582
583	switch (nfproto) {
584	case NFPROTO_INET:
585		err = nf_ct_netns_inet_get(net);
586		break;
587	case NFPROTO_BRIDGE:
588		err = nf_ct_netns_do_get(net, NFPROTO_BRIDGE);
589		if (err < 0)
590			return err;
591
592		err = nf_ct_netns_inet_get(net);
593		if (err < 0) {
594			nf_ct_netns_put(net, NFPROTO_BRIDGE);
595			return err;
596		}
597		break;
598	default:
599		err = nf_ct_netns_do_get(net, nfproto);
600		break;
601	}
602	return err;
603}
604EXPORT_SYMBOL_GPL(nf_ct_netns_get);
605
606void nf_ct_netns_put(struct net *net, uint8_t nfproto)
607{
608	switch (nfproto) {
609	case NFPROTO_BRIDGE:
610		nf_ct_netns_do_put(net, NFPROTO_BRIDGE);
611		fallthrough;
612	case NFPROTO_INET:
613		nf_ct_netns_do_put(net, NFPROTO_IPV4);
614		nf_ct_netns_do_put(net, NFPROTO_IPV6);
615		break;
616	default:
617		nf_ct_netns_do_put(net, nfproto);
618		break;
619	}
620}
621EXPORT_SYMBOL_GPL(nf_ct_netns_put);
622
623void nf_ct_bridge_register(struct nf_ct_bridge_info *info)
624{
625	WARN_ON(nf_ct_bridge_info);
626	mutex_lock(&nf_ct_proto_mutex);
627	nf_ct_bridge_info = info;
628	mutex_unlock(&nf_ct_proto_mutex);
629}
630EXPORT_SYMBOL_GPL(nf_ct_bridge_register);
631
632void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info)
633{
634	WARN_ON(!nf_ct_bridge_info);
635	mutex_lock(&nf_ct_proto_mutex);
636	nf_ct_bridge_info = NULL;
637	mutex_unlock(&nf_ct_proto_mutex);
638}
639EXPORT_SYMBOL_GPL(nf_ct_bridge_unregister);
640
641int nf_conntrack_proto_init(void)
642{
643	int ret;
644
645	ret = nf_register_sockopt(&so_getorigdst);
646	if (ret < 0)
647		return ret;
648
649#if IS_ENABLED(CONFIG_IPV6)
650	ret = nf_register_sockopt(&so_getorigdst6);
651	if (ret < 0)
652		goto cleanup_sockopt;
653#endif
654
655	return ret;
656
657#if IS_ENABLED(CONFIG_IPV6)
658cleanup_sockopt:
659	nf_unregister_sockopt(&so_getorigdst);
660#endif
661	return ret;
662}
663
664void nf_conntrack_proto_fini(void)
665{
666	nf_unregister_sockopt(&so_getorigdst);
667#if IS_ENABLED(CONFIG_IPV6)
668	nf_unregister_sockopt(&so_getorigdst6);
669#endif
670}
671
672void nf_conntrack_proto_pernet_init(struct net *net)
673{
674	nf_conntrack_generic_init_net(net);
675	nf_conntrack_udp_init_net(net);
676	nf_conntrack_tcp_init_net(net);
677	nf_conntrack_icmp_init_net(net);
678#if IS_ENABLED(CONFIG_IPV6)
679	nf_conntrack_icmpv6_init_net(net);
680#endif
681#ifdef CONFIG_NF_CT_PROTO_SCTP
682	nf_conntrack_sctp_init_net(net);
683#endif
684#ifdef CONFIG_NF_CT_PROTO_GRE
685	nf_conntrack_gre_init_net(net);
686#endif
687}
688
689module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
690		  &nf_conntrack_htable_size, 0600);
691
692MODULE_ALIAS("ip_conntrack");
693MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
694MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
695MODULE_LICENSE("GPL");
696MODULE_DESCRIPTION("IPv4 and IPv6 connection tracking");
~/ Read-only file preview.