xref: /openbmc/linux/net/netfilter/nft_ct.c (revision a8fe58ce)
1 /*
2  * Copyright (c) 2008-2009 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  * Development of this code funded by Astaro AG (http://www.astaro.com/)
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/netlink.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter/nf_tables.h>
17 #include <net/netfilter/nf_tables.h>
18 #include <net/netfilter/nf_conntrack.h>
19 #include <net/netfilter/nf_conntrack_acct.h>
20 #include <net/netfilter/nf_conntrack_tuple.h>
21 #include <net/netfilter/nf_conntrack_helper.h>
22 #include <net/netfilter/nf_conntrack_ecache.h>
23 #include <net/netfilter/nf_conntrack_labels.h>
24 
25 struct nft_ct {
26 	enum nft_ct_keys	key:8;
27 	enum ip_conntrack_dir	dir:8;
28 	union {
29 		enum nft_registers	dreg:8;
30 		enum nft_registers	sreg:8;
31 	};
32 };
33 
34 static u64 nft_ct_get_eval_counter(const struct nf_conn_counter *c,
35 				   enum nft_ct_keys k,
36 				   enum ip_conntrack_dir d)
37 {
38 	if (d < IP_CT_DIR_MAX)
39 		return k == NFT_CT_BYTES ? atomic64_read(&c[d].bytes) :
40 					   atomic64_read(&c[d].packets);
41 
42 	return nft_ct_get_eval_counter(c, k, IP_CT_DIR_ORIGINAL) +
43 	       nft_ct_get_eval_counter(c, k, IP_CT_DIR_REPLY);
44 }
45 
46 static void nft_ct_get_eval(const struct nft_expr *expr,
47 			    struct nft_regs *regs,
48 			    const struct nft_pktinfo *pkt)
49 {
50 	const struct nft_ct *priv = nft_expr_priv(expr);
51 	u32 *dest = &regs->data[priv->dreg];
52 	enum ip_conntrack_info ctinfo;
53 	const struct nf_conn *ct;
54 	const struct nf_conn_help *help;
55 	const struct nf_conntrack_tuple *tuple;
56 	const struct nf_conntrack_helper *helper;
57 	long diff;
58 	unsigned int state;
59 
60 	ct = nf_ct_get(pkt->skb, &ctinfo);
61 
62 	switch (priv->key) {
63 	case NFT_CT_STATE:
64 		if (ct == NULL)
65 			state = NF_CT_STATE_INVALID_BIT;
66 		else if (nf_ct_is_untracked(ct))
67 			state = NF_CT_STATE_UNTRACKED_BIT;
68 		else
69 			state = NF_CT_STATE_BIT(ctinfo);
70 		*dest = state;
71 		return;
72 	default:
73 		break;
74 	}
75 
76 	if (ct == NULL)
77 		goto err;
78 
79 	switch (priv->key) {
80 	case NFT_CT_DIRECTION:
81 		*dest = CTINFO2DIR(ctinfo);
82 		return;
83 	case NFT_CT_STATUS:
84 		*dest = ct->status;
85 		return;
86 #ifdef CONFIG_NF_CONNTRACK_MARK
87 	case NFT_CT_MARK:
88 		*dest = ct->mark;
89 		return;
90 #endif
91 #ifdef CONFIG_NF_CONNTRACK_SECMARK
92 	case NFT_CT_SECMARK:
93 		*dest = ct->secmark;
94 		return;
95 #endif
96 	case NFT_CT_EXPIRATION:
97 		diff = (long)jiffies - (long)ct->timeout.expires;
98 		if (diff < 0)
99 			diff = 0;
100 		*dest = jiffies_to_msecs(diff);
101 		return;
102 	case NFT_CT_HELPER:
103 		if (ct->master == NULL)
104 			goto err;
105 		help = nfct_help(ct->master);
106 		if (help == NULL)
107 			goto err;
108 		helper = rcu_dereference(help->helper);
109 		if (helper == NULL)
110 			goto err;
111 		strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
112 		return;
113 #ifdef CONFIG_NF_CONNTRACK_LABELS
114 	case NFT_CT_LABELS: {
115 		struct nf_conn_labels *labels = nf_ct_labels_find(ct);
116 		unsigned int size;
117 
118 		if (!labels) {
119 			memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
120 			return;
121 		}
122 
123 		size = labels->words * sizeof(long);
124 		memcpy(dest, labels->bits, size);
125 		if (size < NF_CT_LABELS_MAX_SIZE)
126 			memset(((char *) dest) + size, 0,
127 			       NF_CT_LABELS_MAX_SIZE - size);
128 		return;
129 	}
130 #endif
131 	case NFT_CT_BYTES: /* fallthrough */
132 	case NFT_CT_PKTS: {
133 		const struct nf_conn_acct *acct = nf_conn_acct_find(ct);
134 		u64 count = 0;
135 
136 		if (acct)
137 			count = nft_ct_get_eval_counter(acct->counter,
138 							priv->key, priv->dir);
139 		memcpy(dest, &count, sizeof(count));
140 		return;
141 	}
142 	default:
143 		break;
144 	}
145 
146 	tuple = &ct->tuplehash[priv->dir].tuple;
147 	switch (priv->key) {
148 	case NFT_CT_L3PROTOCOL:
149 		*dest = nf_ct_l3num(ct);
150 		return;
151 	case NFT_CT_SRC:
152 		memcpy(dest, tuple->src.u3.all,
153 		       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
154 		return;
155 	case NFT_CT_DST:
156 		memcpy(dest, tuple->dst.u3.all,
157 		       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
158 		return;
159 	case NFT_CT_PROTOCOL:
160 		*dest = nf_ct_protonum(ct);
161 		return;
162 	case NFT_CT_PROTO_SRC:
163 		*dest = (__force __u16)tuple->src.u.all;
164 		return;
165 	case NFT_CT_PROTO_DST:
166 		*dest = (__force __u16)tuple->dst.u.all;
167 		return;
168 	default:
169 		break;
170 	}
171 	return;
172 err:
173 	regs->verdict.code = NFT_BREAK;
174 }
175 
176 static void nft_ct_set_eval(const struct nft_expr *expr,
177 			    struct nft_regs *regs,
178 			    const struct nft_pktinfo *pkt)
179 {
180 	const struct nft_ct *priv = nft_expr_priv(expr);
181 	struct sk_buff *skb = pkt->skb;
182 #ifdef CONFIG_NF_CONNTRACK_MARK
183 	u32 value = regs->data[priv->sreg];
184 #endif
185 	enum ip_conntrack_info ctinfo;
186 	struct nf_conn *ct;
187 
188 	ct = nf_ct_get(skb, &ctinfo);
189 	if (ct == NULL)
190 		return;
191 
192 	switch (priv->key) {
193 #ifdef CONFIG_NF_CONNTRACK_MARK
194 	case NFT_CT_MARK:
195 		if (ct->mark != value) {
196 			ct->mark = value;
197 			nf_conntrack_event_cache(IPCT_MARK, ct);
198 		}
199 		break;
200 #endif
201 	default:
202 		break;
203 	}
204 }
205 
206 static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
207 	[NFTA_CT_DREG]		= { .type = NLA_U32 },
208 	[NFTA_CT_KEY]		= { .type = NLA_U32 },
209 	[NFTA_CT_DIRECTION]	= { .type = NLA_U8 },
210 	[NFTA_CT_SREG]		= { .type = NLA_U32 },
211 };
212 
213 static int nft_ct_l3proto_try_module_get(uint8_t family)
214 {
215 	int err;
216 
217 	if (family == NFPROTO_INET) {
218 		err = nf_ct_l3proto_try_module_get(NFPROTO_IPV4);
219 		if (err < 0)
220 			goto err1;
221 		err = nf_ct_l3proto_try_module_get(NFPROTO_IPV6);
222 		if (err < 0)
223 			goto err2;
224 	} else {
225 		err = nf_ct_l3proto_try_module_get(family);
226 		if (err < 0)
227 			goto err1;
228 	}
229 	return 0;
230 
231 err2:
232 	nf_ct_l3proto_module_put(NFPROTO_IPV4);
233 err1:
234 	return err;
235 }
236 
237 static void nft_ct_l3proto_module_put(uint8_t family)
238 {
239 	if (family == NFPROTO_INET) {
240 		nf_ct_l3proto_module_put(NFPROTO_IPV4);
241 		nf_ct_l3proto_module_put(NFPROTO_IPV6);
242 	} else
243 		nf_ct_l3proto_module_put(family);
244 }
245 
246 static int nft_ct_get_init(const struct nft_ctx *ctx,
247 			   const struct nft_expr *expr,
248 			   const struct nlattr * const tb[])
249 {
250 	struct nft_ct *priv = nft_expr_priv(expr);
251 	unsigned int len;
252 	int err;
253 
254 	priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
255 	switch (priv->key) {
256 	case NFT_CT_DIRECTION:
257 		if (tb[NFTA_CT_DIRECTION] != NULL)
258 			return -EINVAL;
259 		len = sizeof(u8);
260 		break;
261 	case NFT_CT_STATE:
262 	case NFT_CT_STATUS:
263 #ifdef CONFIG_NF_CONNTRACK_MARK
264 	case NFT_CT_MARK:
265 #endif
266 #ifdef CONFIG_NF_CONNTRACK_SECMARK
267 	case NFT_CT_SECMARK:
268 #endif
269 	case NFT_CT_EXPIRATION:
270 		if (tb[NFTA_CT_DIRECTION] != NULL)
271 			return -EINVAL;
272 		len = sizeof(u32);
273 		break;
274 #ifdef CONFIG_NF_CONNTRACK_LABELS
275 	case NFT_CT_LABELS:
276 		if (tb[NFTA_CT_DIRECTION] != NULL)
277 			return -EINVAL;
278 		len = NF_CT_LABELS_MAX_SIZE;
279 		break;
280 #endif
281 	case NFT_CT_HELPER:
282 		if (tb[NFTA_CT_DIRECTION] != NULL)
283 			return -EINVAL;
284 		len = NF_CT_HELPER_NAME_LEN;
285 		break;
286 
287 	case NFT_CT_L3PROTOCOL:
288 	case NFT_CT_PROTOCOL:
289 		if (tb[NFTA_CT_DIRECTION] == NULL)
290 			return -EINVAL;
291 		len = sizeof(u8);
292 		break;
293 	case NFT_CT_SRC:
294 	case NFT_CT_DST:
295 		if (tb[NFTA_CT_DIRECTION] == NULL)
296 			return -EINVAL;
297 
298 		switch (ctx->afi->family) {
299 		case NFPROTO_IPV4:
300 			len = FIELD_SIZEOF(struct nf_conntrack_tuple,
301 					   src.u3.ip);
302 			break;
303 		case NFPROTO_IPV6:
304 		case NFPROTO_INET:
305 			len = FIELD_SIZEOF(struct nf_conntrack_tuple,
306 					   src.u3.ip6);
307 			break;
308 		default:
309 			return -EAFNOSUPPORT;
310 		}
311 		break;
312 	case NFT_CT_PROTO_SRC:
313 	case NFT_CT_PROTO_DST:
314 		if (tb[NFTA_CT_DIRECTION] == NULL)
315 			return -EINVAL;
316 		len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
317 		break;
318 	case NFT_CT_BYTES:
319 	case NFT_CT_PKTS:
320 		/* no direction? return sum of original + reply */
321 		if (tb[NFTA_CT_DIRECTION] == NULL)
322 			priv->dir = IP_CT_DIR_MAX;
323 		len = sizeof(u64);
324 		break;
325 	default:
326 		return -EOPNOTSUPP;
327 	}
328 
329 	if (tb[NFTA_CT_DIRECTION] != NULL) {
330 		priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
331 		switch (priv->dir) {
332 		case IP_CT_DIR_ORIGINAL:
333 		case IP_CT_DIR_REPLY:
334 			break;
335 		default:
336 			return -EINVAL;
337 		}
338 	}
339 
340 	priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
341 	err = nft_validate_register_store(ctx, priv->dreg, NULL,
342 					  NFT_DATA_VALUE, len);
343 	if (err < 0)
344 		return err;
345 
346 	err = nft_ct_l3proto_try_module_get(ctx->afi->family);
347 	if (err < 0)
348 		return err;
349 
350 	return 0;
351 }
352 
353 static int nft_ct_set_init(const struct nft_ctx *ctx,
354 			   const struct nft_expr *expr,
355 			   const struct nlattr * const tb[])
356 {
357 	struct nft_ct *priv = nft_expr_priv(expr);
358 	unsigned int len;
359 	int err;
360 
361 	priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
362 	switch (priv->key) {
363 #ifdef CONFIG_NF_CONNTRACK_MARK
364 	case NFT_CT_MARK:
365 		len = FIELD_SIZEOF(struct nf_conn, mark);
366 		break;
367 #endif
368 	default:
369 		return -EOPNOTSUPP;
370 	}
371 
372 	priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
373 	err = nft_validate_register_load(priv->sreg, len);
374 	if (err < 0)
375 		return err;
376 
377 	err = nft_ct_l3proto_try_module_get(ctx->afi->family);
378 	if (err < 0)
379 		return err;
380 
381 	return 0;
382 }
383 
384 static void nft_ct_destroy(const struct nft_ctx *ctx,
385 			   const struct nft_expr *expr)
386 {
387 	nft_ct_l3proto_module_put(ctx->afi->family);
388 }
389 
390 static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
391 {
392 	const struct nft_ct *priv = nft_expr_priv(expr);
393 
394 	if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
395 		goto nla_put_failure;
396 	if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
397 		goto nla_put_failure;
398 
399 	switch (priv->key) {
400 	case NFT_CT_L3PROTOCOL:
401 	case NFT_CT_PROTOCOL:
402 	case NFT_CT_SRC:
403 	case NFT_CT_DST:
404 	case NFT_CT_PROTO_SRC:
405 	case NFT_CT_PROTO_DST:
406 		if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
407 			goto nla_put_failure;
408 		break;
409 	case NFT_CT_BYTES:
410 	case NFT_CT_PKTS:
411 		if (priv->dir < IP_CT_DIR_MAX &&
412 		    nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
413 			goto nla_put_failure;
414 		break;
415 	default:
416 		break;
417 	}
418 
419 	return 0;
420 
421 nla_put_failure:
422 	return -1;
423 }
424 
425 static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
426 {
427 	const struct nft_ct *priv = nft_expr_priv(expr);
428 
429 	if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
430 		goto nla_put_failure;
431 	if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
432 		goto nla_put_failure;
433 	return 0;
434 
435 nla_put_failure:
436 	return -1;
437 }
438 
439 static struct nft_expr_type nft_ct_type;
440 static const struct nft_expr_ops nft_ct_get_ops = {
441 	.type		= &nft_ct_type,
442 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_ct)),
443 	.eval		= nft_ct_get_eval,
444 	.init		= nft_ct_get_init,
445 	.destroy	= nft_ct_destroy,
446 	.dump		= nft_ct_get_dump,
447 };
448 
449 static const struct nft_expr_ops nft_ct_set_ops = {
450 	.type		= &nft_ct_type,
451 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_ct)),
452 	.eval		= nft_ct_set_eval,
453 	.init		= nft_ct_set_init,
454 	.destroy	= nft_ct_destroy,
455 	.dump		= nft_ct_set_dump,
456 };
457 
458 static const struct nft_expr_ops *
459 nft_ct_select_ops(const struct nft_ctx *ctx,
460 		    const struct nlattr * const tb[])
461 {
462 	if (tb[NFTA_CT_KEY] == NULL)
463 		return ERR_PTR(-EINVAL);
464 
465 	if (tb[NFTA_CT_DREG] && tb[NFTA_CT_SREG])
466 		return ERR_PTR(-EINVAL);
467 
468 	if (tb[NFTA_CT_DREG])
469 		return &nft_ct_get_ops;
470 
471 	if (tb[NFTA_CT_SREG])
472 		return &nft_ct_set_ops;
473 
474 	return ERR_PTR(-EINVAL);
475 }
476 
477 static struct nft_expr_type nft_ct_type __read_mostly = {
478 	.name		= "ct",
479 	.select_ops	= &nft_ct_select_ops,
480 	.policy		= nft_ct_policy,
481 	.maxattr	= NFTA_CT_MAX,
482 	.owner		= THIS_MODULE,
483 };
484 
485 static int __init nft_ct_module_init(void)
486 {
487 	return nft_register_expr(&nft_ct_type);
488 }
489 
490 static void __exit nft_ct_module_exit(void)
491 {
492 	nft_unregister_expr(&nft_ct_type);
493 }
494 
495 module_init(nft_ct_module_init);
496 module_exit(nft_ct_module_exit);
497 
498 MODULE_LICENSE("GPL");
499 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
500 MODULE_ALIAS_NFT_EXPR("ct");
501