1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * Copyright (c) 2010 Patrick McHardy <kaber@trash.net>
4   */
5  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6  #include <linux/module.h>
7  #include <linux/gfp.h>
8  #include <linux/skbuff.h>
9  #include <linux/netfilter_ipv4/ip_tables.h>
10  #include <linux/netfilter_ipv6/ip6_tables.h>
11  #include <linux/netfilter/x_tables.h>
12  #include <linux/netfilter/xt_CT.h>
13  #include <net/netfilter/nf_conntrack.h>
14  #include <net/netfilter/nf_conntrack_l4proto.h>
15  #include <net/netfilter/nf_conntrack_helper.h>
16  #include <net/netfilter/nf_conntrack_ecache.h>
17  #include <net/netfilter/nf_conntrack_timeout.h>
18  #include <net/netfilter/nf_conntrack_zones.h>
19  
xt_ct_target(struct sk_buff * skb,struct nf_conn * ct)20  static inline int xt_ct_target(struct sk_buff *skb, struct nf_conn *ct)
21  {
22  	/* Previously seen (loopback)? Ignore. */
23  	if (skb->_nfct != 0)
24  		return XT_CONTINUE;
25  
26  	if (ct) {
27  		refcount_inc(&ct->ct_general.use);
28  		nf_ct_set(skb, ct, IP_CT_NEW);
29  	} else {
30  		nf_ct_set(skb, ct, IP_CT_UNTRACKED);
31  	}
32  
33  	return XT_CONTINUE;
34  }
35  
xt_ct_target_v0(struct sk_buff * skb,const struct xt_action_param * par)36  static 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  
xt_ct_target_v1(struct sk_buff * skb,const struct xt_action_param * par)45  static 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  
xt_ct_find_proto(const struct xt_tgchk_param * par)54  static 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  
72  static int
xt_ct_set_helper(struct nf_conn * ct,const char * helper_name,const struct xt_tgchk_param * par)73  xt_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_ratelimited("You must specify a L4 protocol and not use inversions on it\n");
83  		return -ENOENT;
84  	}
85  
86  	helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
87  						    proto);
88  	if (helper == NULL) {
89  		pr_info_ratelimited("No such helper \"%s\"\n", helper_name);
90  		return -ENOENT;
91  	}
92  
93  	help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
94  	if (help == NULL) {
95  		nf_conntrack_helper_put(helper);
96  		return -ENOMEM;
97  	}
98  
99  	rcu_assign_pointer(help->helper, helper);
100  	return 0;
101  }
102  
103  static int
xt_ct_set_timeout(struct nf_conn * ct,const struct xt_tgchk_param * par,const char * timeout_name)104  xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
105  		  const char *timeout_name)
106  {
107  #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
108  	const struct nf_conntrack_l4proto *l4proto;
109  	u8 proto;
110  
111  	proto = xt_ct_find_proto(par);
112  	if (!proto) {
113  		pr_info_ratelimited("You must specify a L4 protocol and not "
114  				    "use inversions on it");
115  		return -EINVAL;
116  	}
117  	l4proto = nf_ct_l4proto_find(proto);
118  	return nf_ct_set_timeout(par->net, ct, par->family, l4proto->l4proto,
119  				 timeout_name);
120  
121  #else
122  	return -EOPNOTSUPP;
123  #endif
124  }
125  
xt_ct_flags_to_dir(const struct xt_ct_target_info_v1 * info)126  static u16 xt_ct_flags_to_dir(const struct xt_ct_target_info_v1 *info)
127  {
128  	switch (info->flags & (XT_CT_ZONE_DIR_ORIG |
129  			       XT_CT_ZONE_DIR_REPL)) {
130  	case XT_CT_ZONE_DIR_ORIG:
131  		return NF_CT_ZONE_DIR_ORIG;
132  	case XT_CT_ZONE_DIR_REPL:
133  		return NF_CT_ZONE_DIR_REPL;
134  	default:
135  		return NF_CT_DEFAULT_ZONE_DIR;
136  	}
137  }
138  
xt_ct_put_helper(struct nf_conn_help * help)139  static void xt_ct_put_helper(struct nf_conn_help *help)
140  {
141  	struct nf_conntrack_helper *helper;
142  
143  	if (!help)
144  		return;
145  
146  	/* not yet exposed to other cpus, or ruleset
147  	 * already detached (post-replacement).
148  	 */
149  	helper = rcu_dereference_raw(help->helper);
150  	if (helper)
151  		nf_conntrack_helper_put(helper);
152  }
153  
xt_ct_tg_check(const struct xt_tgchk_param * par,struct xt_ct_target_info_v1 * info)154  static int xt_ct_tg_check(const struct xt_tgchk_param *par,
155  			  struct xt_ct_target_info_v1 *info)
156  {
157  	struct nf_conntrack_zone zone;
158  	struct nf_conn_help *help;
159  	struct nf_conn *ct;
160  	int ret = -EOPNOTSUPP;
161  
162  	if (info->flags & XT_CT_NOTRACK) {
163  		ct = NULL;
164  		goto out;
165  	}
166  
167  #ifndef CONFIG_NF_CONNTRACK_ZONES
168  	if (info->zone || info->flags & (XT_CT_ZONE_DIR_ORIG |
169  					 XT_CT_ZONE_DIR_REPL |
170  					 XT_CT_ZONE_MARK))
171  		goto err1;
172  #endif
173  
174  	ret = nf_ct_netns_get(par->net, par->family);
175  	if (ret < 0)
176  		goto err1;
177  
178  	memset(&zone, 0, sizeof(zone));
179  	zone.id = info->zone;
180  	zone.dir = xt_ct_flags_to_dir(info);
181  	if (info->flags & XT_CT_ZONE_MARK)
182  		zone.flags |= NF_CT_FLAG_MARK;
183  
184  	ct = nf_ct_tmpl_alloc(par->net, &zone, GFP_KERNEL);
185  	if (!ct) {
186  		ret = -ENOMEM;
187  		goto err2;
188  	}
189  
190  	if ((info->ct_events || info->exp_events) &&
191  	    !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
192  				  GFP_KERNEL)) {
193  		ret = -EINVAL;
194  		goto err3;
195  	}
196  
197  	if (info->helper[0]) {
198  		if (strnlen(info->helper, sizeof(info->helper)) == sizeof(info->helper)) {
199  			ret = -ENAMETOOLONG;
200  			goto err3;
201  		}
202  
203  		ret = xt_ct_set_helper(ct, info->helper, par);
204  		if (ret < 0)
205  			goto err3;
206  	}
207  
208  	if (info->timeout[0]) {
209  		if (strnlen(info->timeout, sizeof(info->timeout)) == sizeof(info->timeout)) {
210  			ret = -ENAMETOOLONG;
211  			goto err4;
212  		}
213  
214  		ret = xt_ct_set_timeout(ct, par, info->timeout);
215  		if (ret < 0)
216  			goto err4;
217  	}
218  	__set_bit(IPS_CONFIRMED_BIT, &ct->status);
219  out:
220  	info->ct = ct;
221  	return 0;
222  
223  err4:
224  	help = nfct_help(ct);
225  	xt_ct_put_helper(help);
226  err3:
227  	nf_ct_tmpl_free(ct);
228  err2:
229  	nf_ct_netns_put(par->net, par->family);
230  err1:
231  	return ret;
232  }
233  
xt_ct_tg_check_v0(const struct xt_tgchk_param * par)234  static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par)
235  {
236  	struct xt_ct_target_info *info = par->targinfo;
237  	struct xt_ct_target_info_v1 info_v1 = {
238  		.flags 		= info->flags,
239  		.zone		= info->zone,
240  		.ct_events	= info->ct_events,
241  		.exp_events	= info->exp_events,
242  	};
243  	int ret;
244  
245  	if (info->flags & ~XT_CT_NOTRACK)
246  		return -EINVAL;
247  
248  	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
249  
250  	ret = xt_ct_tg_check(par, &info_v1);
251  	if (ret < 0)
252  		return ret;
253  
254  	info->ct = info_v1.ct;
255  
256  	return ret;
257  }
258  
xt_ct_tg_check_v1(const struct xt_tgchk_param * par)259  static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par)
260  {
261  	struct xt_ct_target_info_v1 *info = par->targinfo;
262  
263  	if (info->flags & ~XT_CT_NOTRACK)
264  		return -EINVAL;
265  
266  	return xt_ct_tg_check(par, par->targinfo);
267  }
268  
xt_ct_tg_check_v2(const struct xt_tgchk_param * par)269  static int xt_ct_tg_check_v2(const struct xt_tgchk_param *par)
270  {
271  	struct xt_ct_target_info_v1 *info = par->targinfo;
272  
273  	if (info->flags & ~XT_CT_MASK)
274  		return -EINVAL;
275  
276  	return xt_ct_tg_check(par, par->targinfo);
277  }
278  
xt_ct_tg_destroy(const struct xt_tgdtor_param * par,struct xt_ct_target_info_v1 * info)279  static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par,
280  			     struct xt_ct_target_info_v1 *info)
281  {
282  	struct nf_conn *ct = info->ct;
283  	struct nf_conn_help *help;
284  
285  	if (ct) {
286  		help = nfct_help(ct);
287  		xt_ct_put_helper(help);
288  
289  		nf_ct_netns_put(par->net, par->family);
290  
291  		nf_ct_destroy_timeout(ct);
292  		nf_ct_put(info->ct);
293  	}
294  }
295  
xt_ct_tg_destroy_v0(const struct xt_tgdtor_param * par)296  static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par)
297  {
298  	struct xt_ct_target_info *info = par->targinfo;
299  	struct xt_ct_target_info_v1 info_v1 = {
300  		.flags 		= info->flags,
301  		.zone		= info->zone,
302  		.ct_events	= info->ct_events,
303  		.exp_events	= info->exp_events,
304  		.ct		= info->ct,
305  	};
306  	memcpy(info_v1.helper, info->helper, sizeof(info->helper));
307  
308  	xt_ct_tg_destroy(par, &info_v1);
309  }
310  
xt_ct_tg_destroy_v1(const struct xt_tgdtor_param * par)311  static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par)
312  {
313  	xt_ct_tg_destroy(par, par->targinfo);
314  }
315  
316  static unsigned int
notrack_tg(struct sk_buff * skb,const struct xt_action_param * par)317  notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
318  {
319  	/* Previously seen (loopback)? Ignore. */
320  	if (skb->_nfct != 0)
321  		return XT_CONTINUE;
322  
323  	nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
324  
325  	return XT_CONTINUE;
326  }
327  
328  static struct xt_target xt_ct_tg_reg[] __read_mostly = {
329  	{
330  		.name		= "NOTRACK",
331  		.revision	= 0,
332  		.family		= NFPROTO_IPV4,
333  		.target		= notrack_tg,
334  		.table		= "raw",
335  		.me		= THIS_MODULE,
336  	},
337  	{
338  		.name		= "CT",
339  		.family		= NFPROTO_IPV4,
340  		.targetsize	= sizeof(struct xt_ct_target_info),
341  		.usersize	= offsetof(struct xt_ct_target_info, ct),
342  		.checkentry	= xt_ct_tg_check_v0,
343  		.destroy	= xt_ct_tg_destroy_v0,
344  		.target		= xt_ct_target_v0,
345  		.table		= "raw",
346  		.me		= THIS_MODULE,
347  	},
348  	{
349  		.name		= "CT",
350  		.family		= NFPROTO_IPV4,
351  		.revision	= 1,
352  		.targetsize	= sizeof(struct xt_ct_target_info_v1),
353  		.usersize	= offsetof(struct xt_ct_target_info, ct),
354  		.checkentry	= xt_ct_tg_check_v1,
355  		.destroy	= xt_ct_tg_destroy_v1,
356  		.target		= xt_ct_target_v1,
357  		.table		= "raw",
358  		.me		= THIS_MODULE,
359  	},
360  	{
361  		.name		= "CT",
362  		.family		= NFPROTO_IPV4,
363  		.revision	= 2,
364  		.targetsize	= sizeof(struct xt_ct_target_info_v1),
365  		.usersize	= offsetof(struct xt_ct_target_info, ct),
366  		.checkentry	= xt_ct_tg_check_v2,
367  		.destroy	= xt_ct_tg_destroy_v1,
368  		.target		= xt_ct_target_v1,
369  		.table		= "raw",
370  		.me		= THIS_MODULE,
371  	},
372  #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
373  	{
374  		.name		= "NOTRACK",
375  		.revision	= 0,
376  		.family		= NFPROTO_IPV6,
377  		.target		= notrack_tg,
378  		.table		= "raw",
379  		.me		= THIS_MODULE,
380  	},
381  	{
382  		.name		= "CT",
383  		.family		= NFPROTO_IPV6,
384  		.targetsize	= sizeof(struct xt_ct_target_info),
385  		.usersize	= offsetof(struct xt_ct_target_info, ct),
386  		.checkentry	= xt_ct_tg_check_v0,
387  		.destroy	= xt_ct_tg_destroy_v0,
388  		.target		= xt_ct_target_v0,
389  		.table		= "raw",
390  		.me		= THIS_MODULE,
391  	},
392  	{
393  		.name		= "CT",
394  		.family		= NFPROTO_IPV6,
395  		.revision	= 1,
396  		.targetsize	= sizeof(struct xt_ct_target_info_v1),
397  		.usersize	= offsetof(struct xt_ct_target_info, ct),
398  		.checkentry	= xt_ct_tg_check_v1,
399  		.destroy	= xt_ct_tg_destroy_v1,
400  		.target		= xt_ct_target_v1,
401  		.table		= "raw",
402  		.me		= THIS_MODULE,
403  	},
404  	{
405  		.name		= "CT",
406  		.family		= NFPROTO_IPV6,
407  		.revision	= 2,
408  		.targetsize	= sizeof(struct xt_ct_target_info_v1),
409  		.usersize	= offsetof(struct xt_ct_target_info, ct),
410  		.checkentry	= xt_ct_tg_check_v2,
411  		.destroy	= xt_ct_tg_destroy_v1,
412  		.target		= xt_ct_target_v1,
413  		.table		= "raw",
414  		.me		= THIS_MODULE,
415  	},
416  #endif
417  };
418  
xt_ct_tg_init(void)419  static int __init xt_ct_tg_init(void)
420  {
421  	return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
422  }
423  
xt_ct_tg_exit(void)424  static void __exit xt_ct_tg_exit(void)
425  {
426  	xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg));
427  }
428  
429  module_init(xt_ct_tg_init);
430  module_exit(xt_ct_tg_exit);
431  
432  MODULE_LICENSE("GPL");
433  MODULE_DESCRIPTION("Xtables: connection tracking target");
434  MODULE_ALIAS("ipt_CT");
435  MODULE_ALIAS("ip6t_CT");
436  MODULE_ALIAS("ipt_NOTRACK");
437  MODULE_ALIAS("ip6t_NOTRACK");
438