xref: /openbmc/linux/net/netfilter/xt_CT.c (revision 0838aa7f)
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  */
8a7fed762SJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
984f3bb9aSPatrick McHardy #include <linux/module.h>
105a0e3ad6STejun Heo #include <linux/gfp.h>
1184f3bb9aSPatrick McHardy #include <linux/skbuff.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>
17eeb4cb95SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_l4proto.h>
1884f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_helper.h>
1984f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_ecache.h>
2024de58f4SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_timeout.h>
215d0aa2ccSPatrick McHardy #include <net/netfilter/nf_conntrack_zones.h>
2284f3bb9aSPatrick McHardy 
23d52ed437SPablo Neira Ayuso static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
2484f3bb9aSPatrick McHardy {
2584f3bb9aSPatrick McHardy 	/* Previously seen (loopback)? Ignore. */
2684f3bb9aSPatrick McHardy 	if (skb->nfct != NULL)
2784f3bb9aSPatrick McHardy 		return XT_CONTINUE;
2884f3bb9aSPatrick McHardy 
2927e7190eSEric Dumazet 	/* special case the untracked ct : we want the percpu object */
3027e7190eSEric Dumazet 	if (!ct)
3127e7190eSEric Dumazet 		ct = nf_ct_untracked_get();
3284f3bb9aSPatrick McHardy 	atomic_inc(&ct->ct_general.use);
3384f3bb9aSPatrick McHardy 	skb->nfct = &ct->ct_general;
3484f3bb9aSPatrick McHardy 	skb->nfctinfo = IP_CT_NEW;
3584f3bb9aSPatrick McHardy 
3684f3bb9aSPatrick McHardy 	return XT_CONTINUE;
3784f3bb9aSPatrick McHardy }
3884f3bb9aSPatrick McHardy 
39d52ed437SPablo Neira Ayuso static unsigned int xt_ct_target_v0(struct sk_buff *skb,
40d52ed437SPablo Neira Ayuso 				    const struct xt_action_param *par)
41d52ed437SPablo Neira Ayuso {
42d52ed437SPablo Neira Ayuso 	const struct xt_ct_target_info *info = par->targinfo;
43d52ed437SPablo Neira Ayuso 	struct nf_conn *ct = info->ct;
44d52ed437SPablo Neira Ayuso 
45d52ed437SPablo Neira Ayuso 	return xt_ct_target(skb, ct);
46d52ed437SPablo Neira Ayuso }
47d52ed437SPablo Neira Ayuso 
4824de58f4SPablo Neira Ayuso static unsigned int xt_ct_target_v1(struct sk_buff *skb,
4924de58f4SPablo Neira Ayuso 				    const struct xt_action_param *par)
5024de58f4SPablo Neira Ayuso {
5124de58f4SPablo Neira Ayuso 	const struct xt_ct_target_info_v1 *info = par->targinfo;
5224de58f4SPablo Neira Ayuso 	struct nf_conn *ct = info->ct;
5324de58f4SPablo Neira Ayuso 
54d52ed437SPablo Neira Ayuso 	return xt_ct_target(skb, ct);
5524de58f4SPablo Neira Ayuso }
5624de58f4SPablo Neira Ayuso 
5784f3bb9aSPatrick McHardy static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
5884f3bb9aSPatrick McHardy {
59076f7839SJan Engelhardt 	if (par->family == NFPROTO_IPV4) {
6084f3bb9aSPatrick McHardy 		const struct ipt_entry *e = par->entryinfo;
6184f3bb9aSPatrick McHardy 
6284f3bb9aSPatrick McHardy 		if (e->ip.invflags & IPT_INV_PROTO)
6384f3bb9aSPatrick McHardy 			return 0;
6484f3bb9aSPatrick McHardy 		return e->ip.proto;
65076f7839SJan Engelhardt 	} else if (par->family == NFPROTO_IPV6) {
6684f3bb9aSPatrick McHardy 		const struct ip6t_entry *e = par->entryinfo;
6784f3bb9aSPatrick McHardy 
6884f3bb9aSPatrick McHardy 		if (e->ipv6.invflags & IP6T_INV_PROTO)
6984f3bb9aSPatrick McHardy 			return 0;
7084f3bb9aSPatrick McHardy 		return e->ipv6.proto;
7184f3bb9aSPatrick McHardy 	} else
7284f3bb9aSPatrick McHardy 		return 0;
7384f3bb9aSPatrick McHardy }
7484f3bb9aSPatrick McHardy 
75236df005SPablo Neira Ayuso static int
76236df005SPablo Neira Ayuso xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
77236df005SPablo Neira Ayuso 		 const struct xt_tgchk_param *par)
78236df005SPablo Neira Ayuso {
79236df005SPablo Neira Ayuso 	struct nf_conntrack_helper *helper;
80236df005SPablo Neira Ayuso 	struct nf_conn_help *help;
81236df005SPablo Neira Ayuso 	u8 proto;
82236df005SPablo Neira Ayuso 
83236df005SPablo Neira Ayuso 	proto = xt_ct_find_proto(par);
84236df005SPablo Neira Ayuso 	if (!proto) {
85236df005SPablo Neira Ayuso 		pr_info("You must specify a L4 protocol, and not use "
86236df005SPablo Neira Ayuso 			"inversions on it.\n");
87236df005SPablo Neira Ayuso 		return -ENOENT;
88236df005SPablo Neira Ayuso 	}
89236df005SPablo Neira Ayuso 
90236df005SPablo Neira Ayuso 	helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
91236df005SPablo Neira Ayuso 						    proto);
92236df005SPablo Neira Ayuso 	if (helper == NULL) {
93236df005SPablo Neira Ayuso 		pr_info("No such helper \"%s\"\n", helper_name);
94236df005SPablo Neira Ayuso 		return -ENOENT;
95236df005SPablo Neira Ayuso 	}
96236df005SPablo Neira Ayuso 
97236df005SPablo Neira Ayuso 	help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
98236df005SPablo Neira Ayuso 	if (help == NULL) {
99236df005SPablo Neira Ayuso 		module_put(helper->me);
100236df005SPablo Neira Ayuso 		return -ENOMEM;
101236df005SPablo Neira Ayuso 	}
102236df005SPablo Neira Ayuso 
103236df005SPablo Neira Ayuso 	help->helper = helper;
104236df005SPablo Neira Ayuso 	return 0;
105236df005SPablo Neira Ayuso }
106236df005SPablo Neira Ayuso 
107ee14186fSPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
108ee14186fSPablo Neira Ayuso static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
109ee14186fSPablo Neira Ayuso {
110ee14186fSPablo Neira Ayuso 	typeof(nf_ct_timeout_put_hook) timeout_put;
111ee14186fSPablo Neira Ayuso 
112ee14186fSPablo Neira Ayuso 	timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
113ee14186fSPablo Neira Ayuso 	if (timeout_put)
114ee14186fSPablo Neira Ayuso 		timeout_put(timeout);
115ee14186fSPablo Neira Ayuso }
116ee14186fSPablo Neira Ayuso #endif
117ee14186fSPablo Neira Ayuso 
118236df005SPablo Neira Ayuso static int
119236df005SPablo Neira Ayuso xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
120236df005SPablo Neira Ayuso 		  const char *timeout_name)
121236df005SPablo Neira Ayuso {
122236df005SPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
123236df005SPablo Neira Ayuso 	typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
124236df005SPablo Neira Ayuso 	struct ctnl_timeout *timeout;
125236df005SPablo Neira Ayuso 	struct nf_conn_timeout *timeout_ext;
126236df005SPablo Neira Ayuso 	struct nf_conntrack_l4proto *l4proto;
127236df005SPablo Neira Ayuso 	int ret = 0;
1280153d5a8SPablo Neira Ayuso 	u8 proto;
129236df005SPablo Neira Ayuso 
130236df005SPablo Neira Ayuso 	rcu_read_lock();
131236df005SPablo Neira Ayuso 	timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
132236df005SPablo Neira Ayuso 	if (timeout_find_get == NULL) {
133236df005SPablo Neira Ayuso 		ret = -ENOENT;
134236df005SPablo Neira Ayuso 		pr_info("Timeout policy base is empty\n");
135236df005SPablo Neira Ayuso 		goto out;
136236df005SPablo Neira Ayuso 	}
137236df005SPablo Neira Ayuso 
1380153d5a8SPablo Neira Ayuso 	proto = xt_ct_find_proto(par);
1390153d5a8SPablo Neira Ayuso 	if (!proto) {
140236df005SPablo Neira Ayuso 		ret = -EINVAL;
1410153d5a8SPablo Neira Ayuso 		pr_info("You must specify a L4 protocol, and not use "
1420153d5a8SPablo Neira Ayuso 			"inversions on it.\n");
143236df005SPablo Neira Ayuso 		goto out;
144236df005SPablo Neira Ayuso 	}
145236df005SPablo Neira Ayuso 
146236df005SPablo Neira Ayuso 	timeout = timeout_find_get(timeout_name);
147236df005SPablo Neira Ayuso 	if (timeout == NULL) {
148236df005SPablo Neira Ayuso 		ret = -ENOENT;
149236df005SPablo Neira Ayuso 		pr_info("No such timeout policy \"%s\"\n", timeout_name);
150236df005SPablo Neira Ayuso 		goto out;
151236df005SPablo Neira Ayuso 	}
152236df005SPablo Neira Ayuso 
153236df005SPablo Neira Ayuso 	if (timeout->l3num != par->family) {
154236df005SPablo Neira Ayuso 		ret = -EINVAL;
155236df005SPablo Neira Ayuso 		pr_info("Timeout policy `%s' can only be used by L3 protocol "
156236df005SPablo Neira Ayuso 			"number %d\n", timeout_name, timeout->l3num);
157236df005SPablo Neira Ayuso 		goto err_put_timeout;
158236df005SPablo Neira Ayuso 	}
159236df005SPablo Neira Ayuso 	/* Make sure the timeout policy matches any existing protocol tracker,
160236df005SPablo Neira Ayuso 	 * otherwise default to generic.
161236df005SPablo Neira Ayuso 	 */
1620153d5a8SPablo Neira Ayuso 	l4proto = __nf_ct_l4proto_find(par->family, proto);
163236df005SPablo Neira Ayuso 	if (timeout->l4proto->l4proto != l4proto->l4proto) {
164236df005SPablo Neira Ayuso 		ret = -EINVAL;
165236df005SPablo Neira Ayuso 		pr_info("Timeout policy `%s' can only be used by L4 protocol "
166236df005SPablo Neira Ayuso 			"number %d\n",
167236df005SPablo Neira Ayuso 			timeout_name, timeout->l4proto->l4proto);
168236df005SPablo Neira Ayuso 		goto err_put_timeout;
169236df005SPablo Neira Ayuso 	}
170236df005SPablo Neira Ayuso 	timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
171236df005SPablo Neira Ayuso 	if (timeout_ext == NULL)
172236df005SPablo Neira Ayuso 		ret = -ENOMEM;
173236df005SPablo Neira Ayuso 
174236df005SPablo Neira Ayuso err_put_timeout:
175236df005SPablo Neira Ayuso 	__xt_ct_tg_timeout_put(timeout);
176236df005SPablo Neira Ayuso out:
177236df005SPablo Neira Ayuso 	rcu_read_unlock();
178236df005SPablo Neira Ayuso 	return ret;
179236df005SPablo Neira Ayuso #else
180236df005SPablo Neira Ayuso 	return -EOPNOTSUPP;
181236df005SPablo Neira Ayuso #endif
182236df005SPablo Neira Ayuso }
183236df005SPablo Neira Ayuso 
184d52ed437SPablo Neira Ayuso static int xt_ct_tg_check(const struct xt_tgchk_param *par,
185d52ed437SPablo Neira Ayuso 			  struct xt_ct_target_info_v1 *info)
18624de58f4SPablo Neira Ayuso {
18724de58f4SPablo Neira Ayuso 	struct nf_conn *ct;
1884610476dSPablo Neira Ayuso 	int ret = -EOPNOTSUPP;
189236df005SPablo Neira Ayuso 
19024de58f4SPablo Neira Ayuso 	if (info->flags & XT_CT_NOTRACK) {
19127e7190eSEric Dumazet 		ct = NULL;
19224de58f4SPablo Neira Ayuso 		goto out;
19324de58f4SPablo Neira Ayuso 	}
19424de58f4SPablo Neira Ayuso 
19524de58f4SPablo Neira Ayuso #ifndef CONFIG_NF_CONNTRACK_ZONES
19624de58f4SPablo Neira Ayuso 	if (info->zone)
19724de58f4SPablo Neira Ayuso 		goto err1;
19824de58f4SPablo Neira Ayuso #endif
19924de58f4SPablo Neira Ayuso 
20024de58f4SPablo Neira Ayuso 	ret = nf_ct_l3proto_try_module_get(par->family);
20124de58f4SPablo Neira Ayuso 	if (ret < 0)
20224de58f4SPablo Neira Ayuso 		goto err1;
20324de58f4SPablo Neira Ayuso 
2040838aa7fSPablo Neira Ayuso 	ct = nf_ct_tmpl_alloc(par->net, info->zone, GFP_KERNEL);
20524de58f4SPablo Neira Ayuso 	ret = PTR_ERR(ct);
20624de58f4SPablo Neira Ayuso 	if (IS_ERR(ct))
20724de58f4SPablo Neira Ayuso 		goto err2;
20824de58f4SPablo Neira Ayuso 
20924de58f4SPablo Neira Ayuso 	ret = 0;
21024de58f4SPablo Neira Ayuso 	if ((info->ct_events || info->exp_events) &&
21124de58f4SPablo Neira Ayuso 	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
21214abfa16SEric Leblond 				  GFP_KERNEL)) {
21314abfa16SEric Leblond 		ret = -EINVAL;
21424de58f4SPablo Neira Ayuso 		goto err3;
21514abfa16SEric Leblond 	}
21624de58f4SPablo Neira Ayuso 
21724de58f4SPablo Neira Ayuso 	if (info->helper[0]) {
218236df005SPablo Neira Ayuso 		ret = xt_ct_set_helper(ct, info->helper, par);
219236df005SPablo Neira Ayuso 		if (ret < 0)
22024de58f4SPablo Neira Ayuso 			goto err3;
22124de58f4SPablo Neira Ayuso 	}
22224de58f4SPablo Neira Ayuso 
2236cf51852SPablo Neira Ayuso 	if (info->timeout[0]) {
224236df005SPablo Neira Ayuso 		ret = xt_ct_set_timeout(ct, par, info->timeout);
225236df005SPablo Neira Ayuso 		if (ret < 0)
226236df005SPablo Neira Ayuso 			goto err3;
22724de58f4SPablo Neira Ayuso 	}
2280838aa7fSPablo Neira Ayuso 	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
2290838aa7fSPablo Neira Ayuso 	nf_conntrack_get(&ct->ct_general);
23024de58f4SPablo Neira Ayuso out:
23124de58f4SPablo Neira Ayuso 	info->ct = ct;
23224de58f4SPablo Neira Ayuso 	return 0;
23324de58f4SPablo Neira Ayuso 
23424de58f4SPablo Neira Ayuso err3:
23524de58f4SPablo Neira Ayuso 	nf_conntrack_free(ct);
23624de58f4SPablo Neira Ayuso err2:
23724de58f4SPablo Neira Ayuso 	nf_ct_l3proto_module_put(par->family);
23824de58f4SPablo Neira Ayuso err1:
23924de58f4SPablo Neira Ayuso 	return ret;
24024de58f4SPablo Neira Ayuso }
24124de58f4SPablo Neira Ayuso 
242d52ed437SPablo Neira Ayuso static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
24384f3bb9aSPatrick McHardy {
24484f3bb9aSPatrick McHardy 	struct xt_ct_target_info *info = par->targinfo;
245d52ed437SPablo Neira Ayuso 	struct xt_ct_target_info_v1 info_v1 = {
246d52ed437SPablo Neira Ayuso 		.flags 		= info->flags,
247d52ed437SPablo Neira Ayuso 		.zone		= info->zone,
248d52ed437SPablo Neira Ayuso 		.ct_events	= info->ct_events,
249d52ed437SPablo Neira Ayuso 		.exp_events	= info->exp_events,
250d52ed437SPablo Neira Ayuso 	};
251d52ed437SPablo Neira Ayuso 	int ret;
25284f3bb9aSPatrick McHardy 
2535474f57fSPablo Neira Ayuso 	if (info->flags & ~XT_CT_NOTRACK)
2545474f57fSPablo Neira Ayuso 		return -EINVAL;
2555474f57fSPablo Neira Ayuso 
256d52ed437SPablo Neira Ayuso 	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
25784f3bb9aSPatrick McHardy 
258d52ed437SPablo Neira Ayuso 	ret = xt_ct_tg_check(par, &info_v1);
259d52ed437SPablo Neira Ayuso 	if (ret < 0)
260d52ed437SPablo Neira Ayuso 		return ret;
261d52ed437SPablo Neira Ayuso 
262d52ed437SPablo Neira Ayuso 	info->ct = info_v1.ct;
263d52ed437SPablo Neira Ayuso 
264d52ed437SPablo Neira Ayuso 	return ret;
26584f3bb9aSPatrick McHardy }
266d52ed437SPablo Neira Ayuso 
267d52ed437SPablo Neira Ayuso static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
268d52ed437SPablo Neira Ayuso {
2695474f57fSPablo Neira Ayuso 	struct xt_ct_target_info_v1 *info = par->targinfo;
2705474f57fSPablo Neira Ayuso 
2715474f57fSPablo Neira Ayuso 	if (info->flags & ~XT_CT_NOTRACK)
2725474f57fSPablo Neira Ayuso 		return -EINVAL;
2735474f57fSPablo Neira Ayuso 
2745474f57fSPablo Neira Ayuso 	return xt_ct_tg_check(par, par->targinfo);
2755474f57fSPablo Neira Ayuso }
2765474f57fSPablo Neira Ayuso 
2775474f57fSPablo Neira Ayuso static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
2785474f57fSPablo Neira Ayuso {
2795474f57fSPablo Neira Ayuso 	struct xt_ct_target_info_v1 *info = par->targinfo;
2805474f57fSPablo Neira Ayuso 
2815474f57fSPablo Neira Ayuso 	if (info->flags & ~XT_CT_MASK)
2825474f57fSPablo Neira Ayuso 		return -EINVAL;
2835474f57fSPablo Neira Ayuso 
284d52ed437SPablo Neira Ayuso 	return xt_ct_tg_check(par, par->targinfo);
28584f3bb9aSPatrick McHardy }
28684f3bb9aSPatrick McHardy 
287236df005SPablo Neira Ayuso static void xt_ct_destroy_timeout(struct nf_conn *ct)
28824de58f4SPablo Neira Ayuso {
28924de58f4SPablo Neira Ayuso #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
29024de58f4SPablo Neira Ayuso 	struct nf_conn_timeout *timeout_ext;
29124de58f4SPablo Neira Ayuso 	typeof(nf_ct_timeout_put_hook) timeout_put;
29224de58f4SPablo Neira Ayuso 
2931ac0bf99SPablo Neira Ayuso 	rcu_read_lock();
29424de58f4SPablo Neira Ayuso 	timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
29524de58f4SPablo Neira Ayuso 
29624de58f4SPablo Neira Ayuso 	if (timeout_put) {
29724de58f4SPablo Neira Ayuso 		timeout_ext = nf_ct_timeout_find(ct);
29824de58f4SPablo Neira Ayuso 		if (timeout_ext)
29924de58f4SPablo Neira Ayuso 			timeout_put(timeout_ext->timeout);
30024de58f4SPablo Neira Ayuso 	}
3011ac0bf99SPablo Neira Ayuso 	rcu_read_unlock();
30224de58f4SPablo Neira Ayuso #endif
30324de58f4SPablo Neira Ayuso }
304236df005SPablo Neira Ayuso 
305d52ed437SPablo Neira Ayuso static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
306d52ed437SPablo Neira Ayuso 			     struct xt_ct_target_info_v1 *info)
307236df005SPablo Neira Ayuso {
308236df005SPablo Neira Ayuso 	struct nf_conn *ct = info->ct;
309236df005SPablo Neira Ayuso 	struct nf_conn_help *help;
310236df005SPablo Neira Ayuso 
31127e7190eSEric Dumazet 	if (ct && !nf_ct_is_untracked(ct)) {
312236df005SPablo Neira Ayuso 		help = nfct_help(ct);
313236df005SPablo Neira Ayuso 		if (help)
314236df005SPablo Neira Ayuso 			module_put(help->helper->me);
315236df005SPablo Neira Ayuso 
316236df005SPablo Neira Ayuso 		nf_ct_l3proto_module_put(par->family);
317236df005SPablo Neira Ayuso 
318236df005SPablo Neira Ayuso 		xt_ct_destroy_timeout(ct);
31924de58f4SPablo Neira Ayuso 		nf_ct_put(info->ct);
32024de58f4SPablo Neira Ayuso 	}
32127e7190eSEric Dumazet }
32224de58f4SPablo Neira Ayuso 
323d52ed437SPablo Neira Ayuso static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
324d52ed437SPablo Neira Ayuso {
325d52ed437SPablo Neira Ayuso 	struct xt_ct_target_info *info = par->targinfo;
326d52ed437SPablo Neira Ayuso 	struct xt_ct_target_info_v1 info_v1 = {
327d52ed437SPablo Neira Ayuso 		.flags 		= info->flags,
328d52ed437SPablo Neira Ayuso 		.zone		= info->zone,
329d52ed437SPablo Neira Ayuso 		.ct_events	= info->ct_events,
330d52ed437SPablo Neira Ayuso 		.exp_events	= info->exp_events,
331d52ed437SPablo Neira Ayuso 		.ct		= info->ct,
332d52ed437SPablo Neira Ayuso 	};
333d52ed437SPablo Neira Ayuso 	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
334d52ed437SPablo Neira Ayuso 
335d52ed437SPablo Neira Ayuso 	xt_ct_tg_destroy(par, &info_v1);
336d52ed437SPablo Neira Ayuso }
337d52ed437SPablo Neira Ayuso 
338d52ed437SPablo Neira Ayuso static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
339d52ed437SPablo Neira Ayuso {
340d52ed437SPablo Neira Ayuso 	xt_ct_tg_destroy(par, par->targinfo);
341d52ed437SPablo Neira Ayuso }
342d52ed437SPablo Neira Ayuso 
34324de58f4SPablo Neira Ayuso static struct xt_target xt_ct_tg_reg[] __read_mostly = {
34424de58f4SPablo Neira Ayuso 	{
34584f3bb9aSPatrick McHardy 		.name		= "CT",
34684f3bb9aSPatrick McHardy 		.family		= NFPROTO_UNSPEC,
3477d5f7ed8SJan Engelhardt 		.targetsize	= sizeof(struct xt_ct_target_info),
34824de58f4SPablo Neira Ayuso 		.checkentry	= xt_ct_tg_check_v0,
34924de58f4SPablo Neira Ayuso 		.destroy	= xt_ct_tg_destroy_v0,
35024de58f4SPablo Neira Ayuso 		.target		= xt_ct_target_v0,
35184f3bb9aSPatrick McHardy 		.table		= "raw",
35284f3bb9aSPatrick McHardy 		.me		= THIS_MODULE,
35324de58f4SPablo Neira Ayuso 	},
35424de58f4SPablo Neira Ayuso 	{
35524de58f4SPablo Neira Ayuso 		.name		= "CT",
35624de58f4SPablo Neira Ayuso 		.family		= NFPROTO_UNSPEC,
35724de58f4SPablo Neira Ayuso 		.revision	= 1,
35824de58f4SPablo Neira Ayuso 		.targetsize	= sizeof(struct xt_ct_target_info_v1),
35924de58f4SPablo Neira Ayuso 		.checkentry	= xt_ct_tg_check_v1,
36024de58f4SPablo Neira Ayuso 		.destroy	= xt_ct_tg_destroy_v1,
36124de58f4SPablo Neira Ayuso 		.target		= xt_ct_target_v1,
36224de58f4SPablo Neira Ayuso 		.table		= "raw",
36324de58f4SPablo Neira Ayuso 		.me		= THIS_MODULE,
36424de58f4SPablo Neira Ayuso 	},
3655474f57fSPablo Neira Ayuso 	{
3665474f57fSPablo Neira Ayuso 		.name		= "CT",
3675474f57fSPablo Neira Ayuso 		.family		= NFPROTO_UNSPEC,
3685474f57fSPablo Neira Ayuso 		.revision	= 2,
3695474f57fSPablo Neira Ayuso 		.targetsize	= sizeof(struct xt_ct_target_info_v1),
3705474f57fSPablo Neira Ayuso 		.checkentry	= xt_ct_tg_check_v2,
3715474f57fSPablo Neira Ayuso 		.destroy	= xt_ct_tg_destroy_v1,
3725474f57fSPablo Neira Ayuso 		.target		= xt_ct_target_v1,
3735474f57fSPablo Neira Ayuso 		.table		= "raw",
3745474f57fSPablo Neira Ayuso 		.me		= THIS_MODULE,
3755474f57fSPablo Neira Ayuso 	},
37684f3bb9aSPatrick McHardy };
37784f3bb9aSPatrick McHardy 
37810db9069SPablo Neira Ayuso static unsigned int
37910db9069SPablo Neira Ayuso notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
38010db9069SPablo Neira Ayuso {
38110db9069SPablo Neira Ayuso 	/* Previously seen (loopback)? Ignore. */
38210db9069SPablo Neira Ayuso 	if (skb->nfct != NULL)
38310db9069SPablo Neira Ayuso 		return XT_CONTINUE;
38410db9069SPablo Neira Ayuso 
38510db9069SPablo Neira Ayuso 	skb->nfct = &nf_ct_untracked_get()->ct_general;
38610db9069SPablo Neira Ayuso 	skb->nfctinfo = IP_CT_NEW;
38710db9069SPablo Neira Ayuso 	nf_conntrack_get(skb->nfct);
38810db9069SPablo Neira Ayuso 
38910db9069SPablo Neira Ayuso 	return XT_CONTINUE;
39010db9069SPablo Neira Ayuso }
39110db9069SPablo Neira Ayuso 
39210db9069SPablo Neira Ayuso static int notrack_chk(const struct xt_tgchk_param *par)
39310db9069SPablo Neira Ayuso {
39410db9069SPablo Neira Ayuso 	if (!par->net->xt.notrack_deprecated_warning) {
39510db9069SPablo Neira Ayuso 		pr_info("netfilter: NOTRACK target is deprecated, "
39610db9069SPablo Neira Ayuso 			"use CT instead or upgrade iptables\n");
39710db9069SPablo Neira Ayuso 		par->net->xt.notrack_deprecated_warning = true;
39810db9069SPablo Neira Ayuso 	}
39910db9069SPablo Neira Ayuso 	return 0;
40010db9069SPablo Neira Ayuso }
40110db9069SPablo Neira Ayuso 
40210db9069SPablo Neira Ayuso static struct xt_target notrack_tg_reg __read_mostly = {
40310db9069SPablo Neira Ayuso 	.name		= "NOTRACK",
40410db9069SPablo Neira Ayuso 	.revision	= 0,
40510db9069SPablo Neira Ayuso 	.family		= NFPROTO_UNSPEC,
40610db9069SPablo Neira Ayuso 	.checkentry	= notrack_chk,
40710db9069SPablo Neira Ayuso 	.target		= notrack_tg,
40810db9069SPablo Neira Ayuso 	.table		= "raw",
40910db9069SPablo Neira Ayuso 	.me		= THIS_MODULE,
41010db9069SPablo Neira Ayuso };
41110db9069SPablo Neira Ayuso 
41284f3bb9aSPatrick McHardy static int __init xt_ct_tg_init(void)
41384f3bb9aSPatrick McHardy {
41410db9069SPablo Neira Ayuso 	int ret;
41510db9069SPablo Neira Ayuso 
41610db9069SPablo Neira Ayuso 	ret = xt_register_target(&notrack_tg_reg);
41710db9069SPablo Neira Ayuso 	if (ret < 0)
41810db9069SPablo Neira Ayuso 		return ret;
41910db9069SPablo Neira Ayuso 
42010db9069SPablo Neira Ayuso 	ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
42110db9069SPablo Neira Ayuso 	if (ret < 0) {
42210db9069SPablo Neira Ayuso 		xt_unregister_target(&notrack_tg_reg);
42310db9069SPablo Neira Ayuso 		return ret;
42410db9069SPablo Neira Ayuso 	}
42510db9069SPablo Neira Ayuso 	return 0;
42684f3bb9aSPatrick McHardy }
42784f3bb9aSPatrick McHardy 
42884f3bb9aSPatrick McHardy static void __exit xt_ct_tg_exit(void)
42984f3bb9aSPatrick McHardy {
43024de58f4SPablo Neira Ayuso 	xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
43110db9069SPablo Neira Ayuso 	xt_unregister_target(&notrack_tg_reg);
43284f3bb9aSPatrick McHardy }
43384f3bb9aSPatrick McHardy 
43484f3bb9aSPatrick McHardy module_init(xt_ct_tg_init);
43584f3bb9aSPatrick McHardy module_exit(xt_ct_tg_exit);
43684f3bb9aSPatrick McHardy 
43784f3bb9aSPatrick McHardy MODULE_LICENSE("GPL");
43884f3bb9aSPatrick McHardy MODULE_DESCRIPTION("Xtables: connection tracking target");
43984f3bb9aSPatrick McHardy MODULE_ALIAS("ipt_CT");
44084f3bb9aSPatrick McHardy MODULE_ALIAS("ip6t_CT");
44110db9069SPablo Neira Ayuso MODULE_ALIAS("ipt_NOTRACK");
44210db9069SPablo Neira Ayuso MODULE_ALIAS("ip6t_NOTRACK");
443