File Index
Files and directories
Sign in
FILE

nft_objref.c

File preview with syntax highlighting.

linux-6.19.14/net/netfilter/nft_objref.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2012-2016 Pablo Neira Ayuso <pablo@netfilter.org>
  4 */
  5
  6#include <linux/init.h>
  7#include <linux/module.h>
  8#include <linux/skbuff.h>
  9#include <linux/netlink.h>
 10#include <linux/netfilter.h>
 11#include <linux/netfilter/nf_tables.h>
 12#include <net/netfilter/nf_tables_core.h>
 13
 14#define nft_objref_priv(expr)	*((struct nft_object **)nft_expr_priv(expr))
 15
 16void nft_objref_eval(const struct nft_expr *expr,
 17		     struct nft_regs *regs,
 18		     const struct nft_pktinfo *pkt)
 19{
 20	struct nft_object *obj = nft_objref_priv(expr);
 21
 22	obj->ops->eval(obj, regs, pkt);
 23}
 24
 25static int nft_objref_validate_obj_type(const struct nft_ctx *ctx, u32 type)
 26{
 27	unsigned int hooks;
 28
 29	switch (type) {
 30	case NFT_OBJECT_SYNPROXY:
 31		if (ctx->family != NFPROTO_IPV4 &&
 32		    ctx->family != NFPROTO_IPV6 &&
 33		    ctx->family != NFPROTO_INET)
 34			return -EOPNOTSUPP;
 35
 36		hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD);
 37
 38		return nft_chain_validate_hooks(ctx->chain, hooks);
 39	default:
 40		break;
 41	}
 42
 43	return 0;
 44}
 45
 46static int nft_objref_validate(const struct nft_ctx *ctx,
 47			       const struct nft_expr *expr)
 48{
 49	struct nft_object *obj = nft_objref_priv(expr);
 50
 51	return nft_objref_validate_obj_type(ctx, obj->ops->type->type);
 52}
 53
 54static int nft_objref_init(const struct nft_ctx *ctx,
 55			   const struct nft_expr *expr,
 56			   const struct nlattr * const tb[])
 57{
 58	struct nft_object *obj = nft_objref_priv(expr);
 59	u8 genmask = nft_genmask_next(ctx->net);
 60	u32 objtype;
 61
 62	if (!tb[NFTA_OBJREF_IMM_NAME] ||
 63	    !tb[NFTA_OBJREF_IMM_TYPE])
 64		return -EINVAL;
 65
 66	objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
 67	obj = nft_obj_lookup(ctx->net, ctx->table,
 68			     tb[NFTA_OBJREF_IMM_NAME], objtype,
 69			     genmask);
 70	if (IS_ERR(obj))
 71		return -ENOENT;
 72
 73	if (!nft_use_inc(&obj->use))
 74		return -EMFILE;
 75
 76	nft_objref_priv(expr) = obj;
 77
 78	return 0;
 79}
 80
 81static int nft_objref_dump(struct sk_buff *skb,
 82			   const struct nft_expr *expr, bool reset)
 83{
 84	const struct nft_object *obj = nft_objref_priv(expr);
 85
 86	if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
 87	    nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
 88			 htonl(obj->ops->type->type)))
 89		goto nla_put_failure;
 90
 91	return 0;
 92
 93nla_put_failure:
 94	return -1;
 95}
 96
 97static void nft_objref_deactivate(const struct nft_ctx *ctx,
 98				  const struct nft_expr *expr,
 99				  enum nft_trans_phase phase)
100{
101	struct nft_object *obj = nft_objref_priv(expr);
102
103	if (phase == NFT_TRANS_COMMIT)
104		return;
105
106	nft_use_dec(&obj->use);
107}
108
109static void nft_objref_activate(const struct nft_ctx *ctx,
110				const struct nft_expr *expr)
111{
112	struct nft_object *obj = nft_objref_priv(expr);
113
114	nft_use_inc_restore(&obj->use);
115}
116
117static const struct nft_expr_ops nft_objref_ops = {
118	.type		= &nft_objref_type,
119	.size		= NFT_EXPR_SIZE(sizeof(struct nft_object *)),
120	.eval		= nft_objref_eval,
121	.init		= nft_objref_init,
122	.activate	= nft_objref_activate,
123	.deactivate	= nft_objref_deactivate,
124	.dump		= nft_objref_dump,
125	.validate	= nft_objref_validate,
126	.reduce		= NFT_REDUCE_READONLY,
127};
128
129struct nft_objref_map {
130	struct nft_set		*set;
131	u8			sreg;
132	struct nft_set_binding	binding;
133};
134
135void nft_objref_map_eval(const struct nft_expr *expr,
136			 struct nft_regs *regs,
137			 const struct nft_pktinfo *pkt)
138{
139	struct nft_objref_map *priv = nft_expr_priv(expr);
140	const struct nft_set *set = priv->set;
141	struct net *net = nft_net(pkt);
142	const struct nft_set_ext *ext;
143	struct nft_object *obj;
144
145	ext = nft_set_do_lookup(net, set, &regs->data[priv->sreg]);
146	if (!ext) {
147		ext = nft_set_catchall_lookup(net, set);
148		if (!ext) {
149			regs->verdict.code = NFT_BREAK;
150			return;
151		}
152	}
153	obj = *nft_set_ext_obj(ext);
154	obj->ops->eval(obj, regs, pkt);
155}
156
157static int nft_objref_map_init(const struct nft_ctx *ctx,
158			       const struct nft_expr *expr,
159			       const struct nlattr * const tb[])
160{
161	struct nft_objref_map *priv = nft_expr_priv(expr);
162	u8 genmask = nft_genmask_next(ctx->net);
163	struct nft_set *set;
164	int err;
165
166	set = nft_set_lookup_global(ctx->net, ctx->table,
167				    tb[NFTA_OBJREF_SET_NAME],
168				    tb[NFTA_OBJREF_SET_ID], genmask);
169	if (IS_ERR(set))
170		return PTR_ERR(set);
171
172	if (!(set->flags & NFT_SET_OBJECT))
173		return -EINVAL;
174
175	err = nft_parse_register_load(ctx, tb[NFTA_OBJREF_SET_SREG], &priv->sreg,
176				      set->klen);
177	if (err < 0)
178		return err;
179
180	priv->binding.flags = set->flags & NFT_SET_OBJECT;
181
182	err = nf_tables_bind_set(ctx, set, &priv->binding);
183	if (err < 0)
184		return err;
185
186	priv->set = set;
187	return 0;
188}
189
190static int nft_objref_map_dump(struct sk_buff *skb,
191			       const struct nft_expr *expr, bool reset)
192{
193	const struct nft_objref_map *priv = nft_expr_priv(expr);
194
195	if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) ||
196	    nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name))
197		goto nla_put_failure;
198
199	return 0;
200
201nla_put_failure:
202	return -1;
203}
204
205static void nft_objref_map_deactivate(const struct nft_ctx *ctx,
206				      const struct nft_expr *expr,
207				      enum nft_trans_phase phase)
208{
209	struct nft_objref_map *priv = nft_expr_priv(expr);
210
211	nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
212}
213
214static void nft_objref_map_activate(const struct nft_ctx *ctx,
215				    const struct nft_expr *expr)
216{
217	struct nft_objref_map *priv = nft_expr_priv(expr);
218
219	nf_tables_activate_set(ctx, priv->set);
220}
221
222static void nft_objref_map_destroy(const struct nft_ctx *ctx,
223				   const struct nft_expr *expr)
224{
225	struct nft_objref_map *priv = nft_expr_priv(expr);
226
227	nf_tables_destroy_set(ctx, priv->set);
228}
229
230static int nft_objref_map_validate(const struct nft_ctx *ctx,
231				   const struct nft_expr *expr)
232{
233	const struct nft_objref_map *priv = nft_expr_priv(expr);
234
235	return nft_objref_validate_obj_type(ctx, priv->set->objtype);
236}
237
238static const struct nft_expr_ops nft_objref_map_ops = {
239	.type		= &nft_objref_type,
240	.size		= NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
241	.eval		= nft_objref_map_eval,
242	.init		= nft_objref_map_init,
243	.activate	= nft_objref_map_activate,
244	.deactivate	= nft_objref_map_deactivate,
245	.destroy	= nft_objref_map_destroy,
246	.dump		= nft_objref_map_dump,
247	.validate	= nft_objref_map_validate,
248	.reduce		= NFT_REDUCE_READONLY,
249};
250
251static const struct nft_expr_ops *
252nft_objref_select_ops(const struct nft_ctx *ctx,
253                      const struct nlattr * const tb[])
254{
255	if (tb[NFTA_OBJREF_SET_SREG] &&
256	    (tb[NFTA_OBJREF_SET_NAME] ||
257	     tb[NFTA_OBJREF_SET_ID]))
258		return &nft_objref_map_ops;
259	else if (tb[NFTA_OBJREF_IMM_NAME] &&
260		 tb[NFTA_OBJREF_IMM_TYPE])
261		return &nft_objref_ops;
262
263	return ERR_PTR(-EOPNOTSUPP);
264}
265
266static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
267	[NFTA_OBJREF_IMM_NAME]	= { .type = NLA_STRING,
268				    .len = NFT_OBJ_MAXNAMELEN - 1 },
269	[NFTA_OBJREF_IMM_TYPE]	= { .type = NLA_U32 },
270	[NFTA_OBJREF_SET_SREG]	= { .type = NLA_U32 },
271	[NFTA_OBJREF_SET_NAME]	= { .type = NLA_STRING,
272				    .len = NFT_SET_MAXNAMELEN - 1 },
273	[NFTA_OBJREF_SET_ID]	= { .type = NLA_U32 },
274};
275
276struct nft_expr_type nft_objref_type __read_mostly = {
277	.name		= "objref",
278	.select_ops	= nft_objref_select_ops,
279	.policy		= nft_objref_policy,
280	.maxattr	= NFTA_OBJREF_MAX,
281	.owner		= THIS_MODULE,
282};
~/ Read-only file preview.