1/*
2 * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9#include <linux/module.h>
10#include <linux/gfp.h>
11#include <linux/skbuff.h>
12#include <linux/netfilter_ipv4/ip_tables.h>
13#include <linux/netfilter_ipv6/ip6_tables.h>
14#include <linux/netfilter/x_tables.h>
15#include <linux/netfilter/xt_CT.h>
16#include <net/netfilter/nf_conntrack.h>
17#include <net/netfilter/nf_conntrack_l4proto.h>
18#include <net/netfilter/nf_conntrack_helper.h>
19#include <net/netfilter/nf_conntrack_ecache.h>
20#include <net/netfilter/nf_conntrack_timeout.h>
21#include <net/netfilter/nf_conntrack_zones.h>
22
23static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
24{
25	/* Previously seen (loopback)? Ignore. */
26	if (skb->nfct != NULL)
27		return XT_CONTINUE;
28
29	atomic_inc(&ct->ct_general.use);
30	skb->nfct = &ct->ct_general;
31	skb->nfctinfo = IP_CT_NEW;
32
33	return XT_CONTINUE;
34}
35
36static unsigned int xt_ct_target_v0(struct sk_buff *skb,
37				    const struct xt_action_param *par)
38{
39	const struct xt_ct_target_info *info = par->targinfo;
40	struct nf_conn *ct = info->ct;
41
42	return xt_ct_target(skb, ct);
43}
44
45static unsigned int xt_ct_target_v1(struct sk_buff *skb,
46				    const struct xt_action_param *par)
47{
48	const struct xt_ct_target_info_v1 *info = par->targinfo;
49	struct nf_conn *ct = info->ct;
50
51	return xt_ct_target(skb, ct);
52}
53
54static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
55{
56	if (par->family == NFPROTO_IPV4) {
57		const struct ipt_entry *e = par->entryinfo;
58
59		if (e->ip.invflags & IPT_INV_PROTO)
60			return 0;
61		return e->ip.proto;
62	} else if (par->family == NFPROTO_IPV6) {
63		const struct ip6t_entry *e = par->entryinfo;
64
65		if (e->ipv6.invflags & IP6T_INV_PROTO)
66			return 0;
67		return e->ipv6.proto;
68	} else
69		return 0;
70}
71
72static int
73xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
74		 const struct xt_tgchk_param *par)
75{
76	struct nf_conntrack_helper *helper;
77	struct nf_conn_help *help;
78	u8 proto;
79
80	proto = xt_ct_find_proto(par);
81	if (!proto) {
82		pr_info("You must specify a L4 protocol, and not use "
83			"inversions on it.\n");
84		return -ENOENT;
85	}
86
87	helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
88						    proto);
89	if (helper == NULL) {
90		pr_info("No such helper \"%s\"\n", helper_name);
91		return -ENOENT;
92	}
93
94	help = nf_ct_helper_ext_add(ct, helper, GFP_KERNEL);
95	if (help == NULL) {
96		module_put(helper->me);
97		return -ENOMEM;
98	}
99
100	help->helper = helper;
101	return 0;
102}
103
104#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
105static void __xt_ct_tg_timeout_put(struct ctnl_timeout *timeout)
106{
107	typeof(nf_ct_timeout_put_hook) timeout_put;
108
109	timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
110	if (timeout_put)
111		timeout_put(timeout);
112}
113#endif
114
115static int
116xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
117		  const char *timeout_name)
118{
119#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
120	typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
121	struct ctnl_timeout *timeout;
122	struct nf_conn_timeout *timeout_ext;
123	struct nf_conntrack_l4proto *l4proto;
124	int ret = 0;
125	u8 proto;
126
127	rcu_read_lock();
128	timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
129	if (timeout_find_get == NULL) {
130		ret = -ENOENT;
131		pr_info("Timeout policy base is empty\n");
132		goto out;
133	}
134
135	proto = xt_ct_find_proto(par);
136	if (!proto) {
137		ret = -EINVAL;
138		pr_info("You must specify a L4 protocol, and not use "
139			"inversions on it.\n");
140		goto out;
141	}
142
143	timeout = timeout_find_get(timeout_name);
144	if (timeout == NULL) {
145		ret = -ENOENT;
146		pr_info("No such timeout policy \"%s\"\n", timeout_name);
147		goto out;
148	}
149
150	if (timeout->l3num != par->family) {
151		ret = -EINVAL;
152		pr_info("Timeout policy `%s' can only be used by L3 protocol "
153			"number %d\n", timeout_name, timeout->l3num);
154		goto err_put_timeout;
155	}
156	/* Make sure the timeout policy matches any existing protocol tracker,
157	 * otherwise default to generic.
158	 */
159	l4proto = __nf_ct_l4proto_find(par->family, proto);
160	if (timeout->l4proto->l4proto != l4proto->l4proto) {
161		ret = -EINVAL;
162		pr_info("Timeout policy `%s' can only be used by L4 protocol "
163			"number %d\n",
164			timeout_name, timeout->l4proto->l4proto);
165		goto err_put_timeout;
166	}
167	timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
168	if (timeout_ext == NULL)
169		ret = -ENOMEM;
170
171err_put_timeout:
172	__xt_ct_tg_timeout_put(timeout);
173out:
174	rcu_read_unlock();
175	return ret;
176#else
177	return -EOPNOTSUPP;
178#endif
179}
180
181static int xt_ct_tg_check(const struct xt_tgchk_param *par,
182			  struct xt_ct_target_info_v1 *info)
183{
184	struct nf_conntrack_tuple t;
185	struct nf_conn *ct;
186	int ret = -EOPNOTSUPP;
187
188	if (info->flags & XT_CT_NOTRACK) {
189		ct = nf_ct_untracked_get();
190		atomic_inc(&ct->ct_general.use);
191		goto out;
192	}
193
194#ifndef CONFIG_NF_CONNTRACK_ZONES
195	if (info->zone)
196		goto err1;
197#endif
198
199	ret = nf_ct_l3proto_try_module_get(par->family);
200	if (ret < 0)
201		goto err1;
202
203	memset(&t, 0, sizeof(t));
204	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
205	ret = PTR_ERR(ct);
206	if (IS_ERR(ct))
207		goto err2;
208
209	ret = 0;
210	if ((info->ct_events || info->exp_events) &&
211	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
212				  GFP_KERNEL))
213		goto err3;
214
215	if (info->helper[0]) {
216		ret = xt_ct_set_helper(ct, info->helper, par);
217		if (ret < 0)
218			goto err3;
219	}
220
221	if (info->timeout[0]) {
222		ret = xt_ct_set_timeout(ct, par, info->timeout);
223		if (ret < 0)
224			goto err3;
225	}
226
227	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
228	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
229
230	/* Overload tuple linked list to put us in template list. */
231	hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
232				 &par->net->ct.tmpl);
233out:
234	info->ct = ct;
235	return 0;
236
237err3:
238	nf_conntrack_free(ct);
239err2:
240	nf_ct_l3proto_module_put(par->family);
241err1:
242	return ret;
243}
244
245static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
246{
247	struct xt_ct_target_info *info = par->targinfo;
248	struct xt_ct_target_info_v1 info_v1 = {
249		.flags 		= info->flags,
250		.zone		= info->zone,
251		.ct_events	= info->ct_events,
252		.exp_events	= info->exp_events,
253	};
254	int ret;
255
256	if (info->flags & ~XT_CT_NOTRACK)
257		return -EINVAL;
258
259	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
260
261	ret = xt_ct_tg_check(par, &info_v1);
262	if (ret < 0)
263		return ret;
264
265	info->ct = info_v1.ct;
266
267	return ret;
268}
269
270static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
271{
272	struct xt_ct_target_info_v1 *info = par->targinfo;
273
274	if (info->flags & ~XT_CT_NOTRACK)
275		return -EINVAL;
276
277	return xt_ct_tg_check(par, par->targinfo);
278}
279
280static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
281{
282	struct xt_ct_target_info_v1 *info = par->targinfo;
283
284	if (info->flags & ~XT_CT_MASK)
285		return -EINVAL;
286
287	return xt_ct_tg_check(par, par->targinfo);
288}
289
290static void xt_ct_destroy_timeout(struct nf_conn *ct)
291{
292#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
293	struct nf_conn_timeout *timeout_ext;
294	typeof(nf_ct_timeout_put_hook) timeout_put;
295
296	rcu_read_lock();
297	timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
298
299	if (timeout_put) {
300		timeout_ext = nf_ct_timeout_find(ct);
301		if (timeout_ext)
302			timeout_put(timeout_ext->timeout);
303	}
304	rcu_read_unlock();
305#endif
306}
307
308static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
309			     struct xt_ct_target_info_v1 *info)
310{
311	struct nf_conn *ct = info->ct;
312	struct nf_conn_help *help;
313
314	if (!nf_ct_is_untracked(ct)) {
315		help = nfct_help(ct);
316		if (help)
317			module_put(help->helper->me);
318
319		nf_ct_l3proto_module_put(par->family);
320
321		xt_ct_destroy_timeout(ct);
322	}
323	nf_ct_put(info->ct);
324}
325
326static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
327{
328	struct xt_ct_target_info *info = par->targinfo;
329	struct xt_ct_target_info_v1 info_v1 = {
330		.flags 		= info->flags,
331		.zone		= info->zone,
332		.ct_events	= info->ct_events,
333		.exp_events	= info->exp_events,
334		.ct		= info->ct,
335	};
336	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
337
338	xt_ct_tg_destroy(par, &info_v1);
339}
340
341static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
342{
343	xt_ct_tg_destroy(par, par->targinfo);
344}
345
346static struct xt_target xt_ct_tg_reg[] __read_mostly = {
347	{
348		.name		= "CT",
349		.family		= NFPROTO_UNSPEC,
350		.targetsize	= sizeof(struct xt_ct_target_info),
351		.checkentry	= xt_ct_tg_check_v0,
352		.destroy	= xt_ct_tg_destroy_v0,
353		.target		= xt_ct_target_v0,
354		.table		= "raw",
355		.me		= THIS_MODULE,
356	},
357	{
358		.name		= "CT",
359		.family		= NFPROTO_UNSPEC,
360		.revision	= 1,
361		.targetsize	= sizeof(struct xt_ct_target_info_v1),
362		.checkentry	= xt_ct_tg_check_v1,
363		.destroy	= xt_ct_tg_destroy_v1,
364		.target		= xt_ct_target_v1,
365		.table		= "raw",
366		.me		= THIS_MODULE,
367	},
368	{
369		.name		= "CT",
370		.family		= NFPROTO_UNSPEC,
371		.revision	= 2,
372		.targetsize	= sizeof(struct xt_ct_target_info_v1),
373		.checkentry	= xt_ct_tg_check_v2,
374		.destroy	= xt_ct_tg_destroy_v1,
375		.target		= xt_ct_target_v1,
376		.table		= "raw",
377		.me		= THIS_MODULE,
378	},
379};
380
381static unsigned int
382notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
383{
384	/* Previously seen (loopback)? Ignore. */
385	if (skb->nfct != NULL)
386		return XT_CONTINUE;
387
388	skb->nfct = &nf_ct_untracked_get()->ct_general;
389	skb->nfctinfo = IP_CT_NEW;
390	nf_conntrack_get(skb->nfct);
391
392	return XT_CONTINUE;
393}
394
395static int notrack_chk(const struct xt_tgchk_param *par)
396{
397	if (!par->net->xt.notrack_deprecated_warning) {
398		pr_info("netfilter: NOTRACK target is deprecated, "
399			"use CT instead or upgrade iptables\n");
400		par->net->xt.notrack_deprecated_warning = true;
401	}
402	return 0;
403}
404
405static struct xt_target notrack_tg_reg __read_mostly = {
406	.name		= "NOTRACK",
407	.revision	= 0,
408	.family		= NFPROTO_UNSPEC,
409	.checkentry	= notrack_chk,
410	.target		= notrack_tg,
411	.table		= "raw",
412	.me		= THIS_MODULE,
413};
414
415static int __init xt_ct_tg_init(void)
416{
417	int ret;
418
419	ret = xt_register_target(&notrack_tg_reg);
420	if (ret < 0)
421		return ret;
422
423	ret = xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
424	if (ret < 0) {
425		xt_unregister_target(&notrack_tg_reg);
426		return ret;
427	}
428	return 0;
429}
430
431static void __exit xt_ct_tg_exit(void)
432{
433	xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
434	xt_unregister_target(&notrack_tg_reg);
435}
436
437module_init(xt_ct_tg_init);
438module_exit(xt_ct_tg_exit);
439
440MODULE_LICENSE("GPL");
441MODULE_DESCRIPTION("Xtables: connection tracking target");
442MODULE_ALIAS("ipt_CT");
443MODULE_ALIAS("ip6t_CT");
444MODULE_ALIAS("ipt_NOTRACK");
445MODULE_ALIAS("ip6t_NOTRACK");
446