cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nf_conntrack_proto.c (17557B)


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