xref: /openbmc/linux/net/netfilter/xt_CT.c (revision d6b00a53)
184f3bb9aSPatrick McHardy /*
284f3bb9aSPatrick McHardy  * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
384f3bb9aSPatrick McHardy  *
484f3bb9aSPatrick McHardy  * This program is free software; you can redistribute it and/or modify
584f3bb9aSPatrick McHardy  * it under the terms of the GNU General Public License version 2 as
684f3bb9aSPatrick McHardy  * published by the Free Software Foundation.
784f3bb9aSPatrick McHardy  */
884f3bb9aSPatrick McHardy 
984f3bb9aSPatrick McHardy #include <linux/module.h>
1084f3bb9aSPatrick McHardy #include <linux/skbuff.h>
1184f3bb9aSPatrick McHardy #include <linux/selinux.h>
1284f3bb9aSPatrick McHardy #include <linux/netfilter_ipv4/ip_tables.h>
1384f3bb9aSPatrick McHardy #include <linux/netfilter_ipv6/ip6_tables.h>
1484f3bb9aSPatrick McHardy #include <linux/netfilter/x_tables.h>
1584f3bb9aSPatrick McHardy #include <linux/netfilter/xt_CT.h>
1684f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack.h>
1784f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_helper.h>
1884f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_ecache.h>
195d0aa2ccSPatrick McHardy #include <net/netfilter/nf_conntrack_zones.h>
2084f3bb9aSPatrick McHardy 
2184f3bb9aSPatrick McHardy static unsigned int xt_ct_target(struct sk_buff *skb,
2284f3bb9aSPatrick McHardy 				 const struct xt_target_param *par)
2384f3bb9aSPatrick McHardy {
2484f3bb9aSPatrick McHardy 	const struct xt_ct_target_info *info = par->targinfo;
2584f3bb9aSPatrick McHardy 	struct nf_conn *ct = info->ct;
2684f3bb9aSPatrick McHardy 
2784f3bb9aSPatrick McHardy 	/* Previously seen (loopback)? Ignore. */
2884f3bb9aSPatrick McHardy 	if (skb->nfct != NULL)
2984f3bb9aSPatrick McHardy 		return XT_CONTINUE;
3084f3bb9aSPatrick McHardy 
3184f3bb9aSPatrick McHardy 	atomic_inc(&ct->ct_general.use);
3284f3bb9aSPatrick McHardy 	skb->nfct = &ct->ct_general;
3384f3bb9aSPatrick McHardy 	skb->nfctinfo = IP_CT_NEW;
3484f3bb9aSPatrick McHardy 
3584f3bb9aSPatrick McHardy 	return XT_CONTINUE;
3684f3bb9aSPatrick McHardy }
3784f3bb9aSPatrick McHardy 
3884f3bb9aSPatrick McHardy static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
3984f3bb9aSPatrick McHardy {
40076f7839SJan Engelhardt 	if (par->family == NFPROTO_IPV4) {
4184f3bb9aSPatrick McHardy 		const struct ipt_entry *e = par->entryinfo;
4284f3bb9aSPatrick McHardy 
4384f3bb9aSPatrick McHardy 		if (e->ip.invflags & IPT_INV_PROTO)
4484f3bb9aSPatrick McHardy 			return 0;
4584f3bb9aSPatrick McHardy 		return e->ip.proto;
46076f7839SJan Engelhardt 	} else if (par->family == NFPROTO_IPV6) {
4784f3bb9aSPatrick McHardy 		const struct ip6t_entry *e = par->entryinfo;
4884f3bb9aSPatrick McHardy 
4984f3bb9aSPatrick McHardy 		if (e->ipv6.invflags & IP6T_INV_PROTO)
5084f3bb9aSPatrick McHardy 			return 0;
5184f3bb9aSPatrick McHardy 		return e->ipv6.proto;
5284f3bb9aSPatrick McHardy 	} else
5384f3bb9aSPatrick McHardy 		return 0;
5484f3bb9aSPatrick McHardy }
5584f3bb9aSPatrick McHardy 
56135367b8SJan Engelhardt static int xt_ct_tg_check(const struct xt_tgchk_param *par)
5784f3bb9aSPatrick McHardy {
5884f3bb9aSPatrick McHardy 	struct xt_ct_target_info *info = par->targinfo;
5984f3bb9aSPatrick McHardy 	struct nf_conntrack_tuple t;
6084f3bb9aSPatrick McHardy 	struct nf_conn_help *help;
6184f3bb9aSPatrick McHardy 	struct nf_conn *ct;
6284f3bb9aSPatrick McHardy 	u8 proto;
6384f3bb9aSPatrick McHardy 
6484f3bb9aSPatrick McHardy 	if (info->flags & ~XT_CT_NOTRACK)
65d6b00a53SJan Engelhardt 		return -EINVAL;
6684f3bb9aSPatrick McHardy 
6784f3bb9aSPatrick McHardy 	if (info->flags & XT_CT_NOTRACK) {
6884f3bb9aSPatrick McHardy 		ct = &nf_conntrack_untracked;
6984f3bb9aSPatrick McHardy 		atomic_inc(&ct->ct_general.use);
7084f3bb9aSPatrick McHardy 		goto out;
7184f3bb9aSPatrick McHardy 	}
7284f3bb9aSPatrick McHardy 
735d0aa2ccSPatrick McHardy #ifndef CONFIG_NF_CONNTRACK_ZONES
745d0aa2ccSPatrick McHardy 	if (info->zone)
755d0aa2ccSPatrick McHardy 		goto err1;
765d0aa2ccSPatrick McHardy #endif
775d0aa2ccSPatrick McHardy 
7884f3bb9aSPatrick McHardy 	if (nf_ct_l3proto_try_module_get(par->family) < 0)
7984f3bb9aSPatrick McHardy 		goto err1;
8084f3bb9aSPatrick McHardy 
8184f3bb9aSPatrick McHardy 	memset(&t, 0, sizeof(t));
825d0aa2ccSPatrick McHardy 	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
8384f3bb9aSPatrick McHardy 	if (IS_ERR(ct))
8484f3bb9aSPatrick McHardy 		goto err2;
8584f3bb9aSPatrick McHardy 
8684f3bb9aSPatrick McHardy 	if ((info->ct_events || info->exp_events) &&
8784f3bb9aSPatrick McHardy 	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
8884f3bb9aSPatrick McHardy 				  GFP_KERNEL))
8984f3bb9aSPatrick McHardy 		goto err3;
9084f3bb9aSPatrick McHardy 
9184f3bb9aSPatrick McHardy 	if (info->helper[0]) {
9284f3bb9aSPatrick McHardy 		proto = xt_ct_find_proto(par);
9384f3bb9aSPatrick McHardy 		if (!proto)
9484f3bb9aSPatrick McHardy 			goto err3;
9584f3bb9aSPatrick McHardy 
9684f3bb9aSPatrick McHardy 		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
9784f3bb9aSPatrick McHardy 		if (help == NULL)
9884f3bb9aSPatrick McHardy 			goto err3;
9984f3bb9aSPatrick McHardy 
10084f3bb9aSPatrick McHardy 		help->helper = nf_conntrack_helper_try_module_get(info->helper,
10184f3bb9aSPatrick McHardy 								  par->family,
10284f3bb9aSPatrick McHardy 								  proto);
10384f3bb9aSPatrick McHardy 		if (help->helper == NULL)
10484f3bb9aSPatrick McHardy 			goto err3;
10584f3bb9aSPatrick McHardy 	}
10684f3bb9aSPatrick McHardy 
10784f3bb9aSPatrick McHardy 	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
10884f3bb9aSPatrick McHardy 	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
10984f3bb9aSPatrick McHardy out:
11084f3bb9aSPatrick McHardy 	info->ct = ct;
111d6b00a53SJan Engelhardt 	return 0;
11284f3bb9aSPatrick McHardy 
11384f3bb9aSPatrick McHardy err3:
11484f3bb9aSPatrick McHardy 	nf_conntrack_free(ct);
11584f3bb9aSPatrick McHardy err2:
11684f3bb9aSPatrick McHardy 	nf_ct_l3proto_module_put(par->family);
11784f3bb9aSPatrick McHardy err1:
118d6b00a53SJan Engelhardt 	return -EINVAL;
11984f3bb9aSPatrick McHardy }
12084f3bb9aSPatrick McHardy 
12184f3bb9aSPatrick McHardy static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
12284f3bb9aSPatrick McHardy {
12384f3bb9aSPatrick McHardy 	struct xt_ct_target_info *info = par->targinfo;
12484f3bb9aSPatrick McHardy 	struct nf_conn *ct = info->ct;
12584f3bb9aSPatrick McHardy 	struct nf_conn_help *help;
12684f3bb9aSPatrick McHardy 
12784f3bb9aSPatrick McHardy 	if (ct != &nf_conntrack_untracked) {
12884f3bb9aSPatrick McHardy 		help = nfct_help(ct);
12984f3bb9aSPatrick McHardy 		if (help)
13084f3bb9aSPatrick McHardy 			module_put(help->helper->me);
13184f3bb9aSPatrick McHardy 
13284f3bb9aSPatrick McHardy 		nf_ct_l3proto_module_put(par->family);
13384f3bb9aSPatrick McHardy 	}
13484f3bb9aSPatrick McHardy 	nf_ct_put(info->ct);
13584f3bb9aSPatrick McHardy }
13684f3bb9aSPatrick McHardy 
13784f3bb9aSPatrick McHardy static struct xt_target xt_ct_tg __read_mostly = {
13884f3bb9aSPatrick McHardy 	.name		= "CT",
13984f3bb9aSPatrick McHardy 	.family		= NFPROTO_UNSPEC,
1407d5f7ed8SJan Engelhardt 	.targetsize	= sizeof(struct xt_ct_target_info),
14184f3bb9aSPatrick McHardy 	.checkentry	= xt_ct_tg_check,
14284f3bb9aSPatrick McHardy 	.destroy	= xt_ct_tg_destroy,
14384f3bb9aSPatrick McHardy 	.target		= xt_ct_target,
14484f3bb9aSPatrick McHardy 	.table		= "raw",
14584f3bb9aSPatrick McHardy 	.me		= THIS_MODULE,
14684f3bb9aSPatrick McHardy };
14784f3bb9aSPatrick McHardy 
14884f3bb9aSPatrick McHardy static int __init xt_ct_tg_init(void)
14984f3bb9aSPatrick McHardy {
15084f3bb9aSPatrick McHardy 	return xt_register_target(&xt_ct_tg);
15184f3bb9aSPatrick McHardy }
15284f3bb9aSPatrick McHardy 
15384f3bb9aSPatrick McHardy static void __exit xt_ct_tg_exit(void)
15484f3bb9aSPatrick McHardy {
15584f3bb9aSPatrick McHardy 	xt_unregister_target(&xt_ct_tg);
15684f3bb9aSPatrick McHardy }
15784f3bb9aSPatrick McHardy 
15884f3bb9aSPatrick McHardy module_init(xt_ct_tg_init);
15984f3bb9aSPatrick McHardy module_exit(xt_ct_tg_exit);
16084f3bb9aSPatrick McHardy 
16184f3bb9aSPatrick McHardy MODULE_LICENSE("GPL");
16284f3bb9aSPatrick McHardy MODULE_DESCRIPTION("Xtables: connection tracking target");
16384f3bb9aSPatrick McHardy MODULE_ALIAS("ipt_CT");
16484f3bb9aSPatrick McHardy MODULE_ALIAS("ip6t_CT");
165