xref: /openbmc/linux/net/netfilter/xt_CT.c (revision 1ac0bf99)
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_helper.h>
18 #include <net/netfilter/nf_conntrack_ecache.h>
19 #include <net/netfilter/nf_conntrack_l4proto.h>
20 #include <net/netfilter/nf_conntrack_timeout.h>
21 #include <net/netfilter/nf_conntrack_zones.h>
22 
23 static unsigned int xt_ct_target_v0(struct sk_buff *skb,
24 				    const struct xt_action_param *par)
25 {
26 	const struct xt_ct_target_info *info = par->targinfo;
27 	struct nf_conn *ct = info->ct;
28 
29 	/* Previously seen (loopback)? Ignore. */
30 	if (skb->nfct != NULL)
31 		return XT_CONTINUE;
32 
33 	atomic_inc(&ct->ct_general.use);
34 	skb->nfct = &ct->ct_general;
35 	skb->nfctinfo = IP_CT_NEW;
36 
37 	return XT_CONTINUE;
38 }
39 
40 static unsigned int xt_ct_target_v1(struct sk_buff *skb,
41 				    const struct xt_action_param *par)
42 {
43 	const struct xt_ct_target_info_v1 *info = par->targinfo;
44 	struct nf_conn *ct = info->ct;
45 
46 	/* Previously seen (loopback)? Ignore. */
47 	if (skb->nfct != NULL)
48 		return XT_CONTINUE;
49 
50 	atomic_inc(&ct->ct_general.use);
51 	skb->nfct = &ct->ct_general;
52 	skb->nfctinfo = IP_CT_NEW;
53 
54 	return XT_CONTINUE;
55 }
56 
57 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
58 {
59 	if (par->family == NFPROTO_IPV4) {
60 		const struct ipt_entry *e = par->entryinfo;
61 
62 		if (e->ip.invflags & IPT_INV_PROTO)
63 			return 0;
64 		return e->ip.proto;
65 	} else if (par->family == NFPROTO_IPV6) {
66 		const struct ip6t_entry *e = par->entryinfo;
67 
68 		if (e->ipv6.invflags & IP6T_INV_PROTO)
69 			return 0;
70 		return e->ipv6.proto;
71 	} else
72 		return 0;
73 }
74 
75 static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
76 {
77 	struct xt_ct_target_info *info = par->targinfo;
78 	struct nf_conntrack_tuple t;
79 	struct nf_conn_help *help;
80 	struct nf_conn *ct;
81 	int ret = 0;
82 	u8 proto;
83 
84 	if (info->flags & ~XT_CT_NOTRACK)
85 		return -EINVAL;
86 
87 	if (info->flags & XT_CT_NOTRACK) {
88 		ct = nf_ct_untracked_get();
89 		atomic_inc(&ct->ct_general.use);
90 		goto out;
91 	}
92 
93 #ifndef CONFIG_NF_CONNTRACK_ZONES
94 	if (info->zone)
95 		goto err1;
96 #endif
97 
98 	ret = nf_ct_l3proto_try_module_get(par->family);
99 	if (ret < 0)
100 		goto err1;
101 
102 	memset(&t, 0, sizeof(t));
103 	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
104 	ret = PTR_ERR(ct);
105 	if (IS_ERR(ct))
106 		goto err2;
107 
108 	ret = 0;
109 	if ((info->ct_events || info->exp_events) &&
110 	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
111 				  GFP_KERNEL))
112 		goto err3;
113 
114 	if (info->helper[0]) {
115 		ret = -ENOENT;
116 		proto = xt_ct_find_proto(par);
117 		if (!proto) {
118 			pr_info("You must specify a L4 protocol, "
119 				"and not use inversions on it.\n");
120 			goto err3;
121 		}
122 
123 		ret = -ENOMEM;
124 		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
125 		if (help == NULL)
126 			goto err3;
127 
128 		ret = -ENOENT;
129 		help->helper = nf_conntrack_helper_try_module_get(info->helper,
130 								  par->family,
131 								  proto);
132 		if (help->helper == NULL) {
133 			pr_info("No such helper \"%s\"\n", info->helper);
134 			goto err3;
135 		}
136 	}
137 
138 	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
139 	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
140 out:
141 	info->ct = ct;
142 	return 0;
143 
144 err3:
145 	nf_conntrack_free(ct);
146 err2:
147 	nf_ct_l3proto_module_put(par->family);
148 err1:
149 	return ret;
150 }
151 
152 static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
153 {
154 	struct xt_ct_target_info_v1 *info = par->targinfo;
155 	struct nf_conntrack_tuple t;
156 	struct nf_conn_help *help;
157 	struct nf_conn *ct;
158 	int ret = 0;
159 	u8 proto;
160 
161 	if (info->flags & ~XT_CT_NOTRACK)
162 		return -EINVAL;
163 
164 	if (info->flags & XT_CT_NOTRACK) {
165 		ct = nf_ct_untracked_get();
166 		atomic_inc(&ct->ct_general.use);
167 		goto out;
168 	}
169 
170 #ifndef CONFIG_NF_CONNTRACK_ZONES
171 	if (info->zone)
172 		goto err1;
173 #endif
174 
175 	ret = nf_ct_l3proto_try_module_get(par->family);
176 	if (ret < 0)
177 		goto err1;
178 
179 	memset(&t, 0, sizeof(t));
180 	ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
181 	ret = PTR_ERR(ct);
182 	if (IS_ERR(ct))
183 		goto err2;
184 
185 	ret = 0;
186 	if ((info->ct_events || info->exp_events) &&
187 	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
188 				  GFP_KERNEL))
189 		goto err3;
190 
191 	if (info->helper[0]) {
192 		ret = -ENOENT;
193 		proto = xt_ct_find_proto(par);
194 		if (!proto) {
195 			pr_info("You must specify a L4 protocol, "
196 				"and not use inversions on it.\n");
197 			goto err3;
198 		}
199 
200 		ret = -ENOMEM;
201 		help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
202 		if (help == NULL)
203 			goto err3;
204 
205 		ret = -ENOENT;
206 		help->helper = nf_conntrack_helper_try_module_get(info->helper,
207 								  par->family,
208 								  proto);
209 		if (help->helper == NULL) {
210 			pr_info("No such helper \"%s\"\n", info->helper);
211 			goto err3;
212 		}
213 	}
214 
215 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
216 	if (info->timeout) {
217 		typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
218 		struct ctnl_timeout *timeout;
219 		struct nf_conn_timeout *timeout_ext;
220 
221 		rcu_read_lock();
222 		timeout_find_get =
223 			rcu_dereference(nf_ct_timeout_find_get_hook);
224 
225 		if (timeout_find_get) {
226 			const struct ipt_entry *e = par->entryinfo;
227 
228 			if (e->ip.invflags & IPT_INV_PROTO) {
229 				ret = -EINVAL;
230 				pr_info("You cannot use inversion on "
231 					 "L4 protocol\n");
232 				goto err4;
233 			}
234 			timeout = timeout_find_get(info->timeout);
235 			if (timeout == NULL) {
236 				ret = -ENOENT;
237 				pr_info("No such timeout policy \"%s\"\n",
238 					info->timeout);
239 				goto err4;
240 			}
241 			if (timeout->l3num != par->family) {
242 				ret = -EINVAL;
243 				pr_info("Timeout policy `%s' can only be "
244 					"used by L3 protocol number %d\n",
245 					info->timeout, timeout->l3num);
246 				goto err4;
247 			}
248 			if (timeout->l4proto->l4proto != e->ip.proto) {
249 				ret = -EINVAL;
250 				pr_info("Timeout policy `%s' can only be "
251 					"used by L4 protocol number %d\n",
252 					info->timeout,
253 					timeout->l4proto->l4proto);
254 				goto err4;
255 			}
256 			timeout_ext = nf_ct_timeout_ext_add(ct, timeout,
257 							    GFP_KERNEL);
258 			if (timeout_ext == NULL) {
259 				ret = -ENOMEM;
260 				goto err4;
261 			}
262 		} else {
263 			ret = -ENOENT;
264 			pr_info("Timeout policy base is empty\n");
265 			goto err4;
266 		}
267 		rcu_read_unlock();
268 	}
269 #endif
270 
271 	__set_bit(IPS_TEMPLATE_BIT, &ct->status);
272 	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
273 out:
274 	info->ct = ct;
275 	return 0;
276 
277 err4:
278 	rcu_read_unlock();
279 err3:
280 	nf_conntrack_free(ct);
281 err2:
282 	nf_ct_l3proto_module_put(par->family);
283 err1:
284 	return ret;
285 }
286 
287 static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
288 {
289 	struct xt_ct_target_info *info = par->targinfo;
290 	struct nf_conn *ct = info->ct;
291 	struct nf_conn_help *help;
292 
293 	if (!nf_ct_is_untracked(ct)) {
294 		help = nfct_help(ct);
295 		if (help)
296 			module_put(help->helper->me);
297 
298 		nf_ct_l3proto_module_put(par->family);
299 	}
300 	nf_ct_put(info->ct);
301 }
302 
303 static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
304 {
305 	struct xt_ct_target_info_v1 *info = par->targinfo;
306 	struct nf_conn *ct = info->ct;
307 	struct nf_conn_help *help;
308 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
309 	struct nf_conn_timeout *timeout_ext;
310 	typeof(nf_ct_timeout_put_hook) timeout_put;
311 #endif
312 	if (!nf_ct_is_untracked(ct)) {
313 		help = nfct_help(ct);
314 		if (help)
315 			module_put(help->helper->me);
316 
317 		nf_ct_l3proto_module_put(par->family);
318 
319 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
320 		rcu_read_lock();
321 		timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
322 
323 		if (timeout_put) {
324 			timeout_ext = nf_ct_timeout_find(ct);
325 			if (timeout_ext)
326 				timeout_put(timeout_ext->timeout);
327 		}
328 		rcu_read_unlock();
329 #endif
330 	}
331 	nf_ct_put(info->ct);
332 }
333 
334 static struct xt_target xt_ct_tg_reg[] __read_mostly = {
335 	{
336 		.name		= "CT",
337 		.family		= NFPROTO_UNSPEC,
338 		.targetsize	= sizeof(struct xt_ct_target_info),
339 		.checkentry	= xt_ct_tg_check_v0,
340 		.destroy	= xt_ct_tg_destroy_v0,
341 		.target		= xt_ct_target_v0,
342 		.table		= "raw",
343 		.me		= THIS_MODULE,
344 	},
345 	{
346 		.name		= "CT",
347 		.family		= NFPROTO_UNSPEC,
348 		.revision	= 1,
349 		.targetsize	= sizeof(struct xt_ct_target_info_v1),
350 		.checkentry	= xt_ct_tg_check_v1,
351 		.destroy	= xt_ct_tg_destroy_v1,
352 		.target		= xt_ct_target_v1,
353 		.table		= "raw",
354 		.me		= THIS_MODULE,
355 	},
356 };
357 
358 static int __init xt_ct_tg_init(void)
359 {
360 	return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
361 }
362 
363 static void __exit xt_ct_tg_exit(void)
364 {
365 	xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
366 }
367 
368 module_init(xt_ct_tg_init);
369 module_exit(xt_ct_tg_exit);
370 
371 MODULE_LICENSE("GPL");
372 MODULE_DESCRIPTION("Xtables: connection tracking target");
373 MODULE_ALIAS("ipt_CT");
374 MODULE_ALIAS("ip6t_CT");
375