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