Blame view

net/netfilter/nft_objref.c 6.3 KB
75a6faf61   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
2
3
  /*
   * Copyright (c) 2012-2016 Pablo Neira Ayuso <pablo@netfilter.org>
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/netlink.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter/nf_tables.h>
  #include <net/netfilter/nf_tables.h>
  
  #define nft_objref_priv(expr)	*((struct nft_object **)nft_expr_priv(expr))
  
  static void nft_objref_eval(const struct nft_expr *expr,
  			    struct nft_regs *regs,
  			    const struct nft_pktinfo *pkt)
  {
  	struct nft_object *obj = nft_objref_priv(expr);
dfc46034b   Pablo M. Bermudo Garay   netfilter: nf_tab...
21
  	obj->ops->eval(obj, regs, pkt);
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  }
  
  static int nft_objref_init(const struct nft_ctx *ctx,
  			   const struct nft_expr *expr,
  			   const struct nlattr * const tb[])
  {
  	struct nft_object *obj = nft_objref_priv(expr);
  	u8 genmask = nft_genmask_next(ctx->net);
  	u32 objtype;
  
  	if (!tb[NFTA_OBJREF_IMM_NAME] ||
  	    !tb[NFTA_OBJREF_IMM_TYPE])
  		return -EINVAL;
  
  	objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
4d44175aa   Florian Westphal   netfilter: nf_tab...
37
38
  	obj = nft_obj_lookup(ctx->net, ctx->table,
  			     tb[NFTA_OBJREF_IMM_NAME], objtype,
cac20fcdf   Pablo Neira Ayuso   netfilter: nf_tab...
39
  			     genmask);
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
40
41
42
43
44
45
46
47
48
49
50
51
  	if (IS_ERR(obj))
  		return -ENOENT;
  
  	nft_objref_priv(expr) = obj;
  	obj->use++;
  
  	return 0;
  }
  
  static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
  {
  	const struct nft_object *obj = nft_objref_priv(expr);
d152159b8   Florian Westphal   netfilter: nf_tab...
52
  	if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
dfc46034b   Pablo M. Bermudo Garay   netfilter: nf_tab...
53
54
  	    nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
  			 htonl(obj->ops->type->type)))
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
55
56
57
58
59
60
61
  		goto nla_put_failure;
  
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
8ffcd32f6   Pablo Neira Ayuso   netfilter: nf_tab...
62
63
64
  static void nft_objref_deactivate(const struct nft_ctx *ctx,
  				  const struct nft_expr *expr,
  				  enum nft_trans_phase phase)
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
65
66
  {
  	struct nft_object *obj = nft_objref_priv(expr);
8ffcd32f6   Pablo Neira Ayuso   netfilter: nf_tab...
67
68
  	if (phase == NFT_TRANS_COMMIT)
  		return;
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
69
70
  	obj->use--;
  }
8ffcd32f6   Pablo Neira Ayuso   netfilter: nf_tab...
71
72
73
74
75
76
77
  static void nft_objref_activate(const struct nft_ctx *ctx,
  				const struct nft_expr *expr)
  {
  	struct nft_object *obj = nft_objref_priv(expr);
  
  	obj->use++;
  }
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
78
79
80
81
82
83
  static struct nft_expr_type nft_objref_type;
  static const struct nft_expr_ops nft_objref_ops = {
  	.type		= &nft_objref_type,
  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_object *)),
  	.eval		= nft_objref_eval,
  	.init		= nft_objref_init,
8ffcd32f6   Pablo Neira Ayuso   netfilter: nf_tab...
84
85
  	.activate	= nft_objref_activate,
  	.deactivate	= nft_objref_deactivate,
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
86
87
  	.dump		= nft_objref_dump,
  };
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  struct nft_objref_map {
  	struct nft_set		*set;
  	enum nft_registers	sreg:8;
  	struct nft_set_binding	binding;
  };
  
  static void nft_objref_map_eval(const struct nft_expr *expr,
  				struct nft_regs *regs,
  				const struct nft_pktinfo *pkt)
  {
  	struct nft_objref_map *priv = nft_expr_priv(expr);
  	const struct nft_set *set = priv->set;
  	const struct nft_set_ext *ext;
  	struct nft_object *obj;
  	bool found;
  
  	found = set->ops->lookup(nft_net(pkt), set, &regs->data[priv->sreg],
  				 &ext);
  	if (!found) {
  		regs->verdict.code = NFT_BREAK;
  		return;
  	}
  	obj = *nft_set_ext_obj(ext);
dfc46034b   Pablo M. Bermudo Garay   netfilter: nf_tab...
111
  	obj->ops->eval(obj, regs, pkt);
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
112
113
114
115
116
117
118
119
120
121
  }
  
  static int nft_objref_map_init(const struct nft_ctx *ctx,
  			       const struct nft_expr *expr,
  			       const struct nlattr * const tb[])
  {
  	struct nft_objref_map *priv = nft_expr_priv(expr);
  	u8 genmask = nft_genmask_next(ctx->net);
  	struct nft_set *set;
  	int err;
10659cbab   Pablo Neira Ayuso   netfilter: nf_tab...
122
123
124
  	set = nft_set_lookup_global(ctx->net, ctx->table,
  				    tb[NFTA_OBJREF_SET_NAME],
  				    tb[NFTA_OBJREF_SET_ID], genmask);
c7a72e3fd   Pablo Neira Ayuso   netfilter: nf_tab...
125
126
  	if (IS_ERR(set))
  		return PTR_ERR(set);
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  
  	if (!(set->flags & NFT_SET_OBJECT))
  		return -EINVAL;
  
  	priv->sreg = nft_parse_register(tb[NFTA_OBJREF_SET_SREG]);
  	err = nft_validate_register_load(priv->sreg, set->klen);
  	if (err < 0)
  		return err;
  
  	priv->binding.flags = set->flags & NFT_SET_OBJECT;
  
  	err = nf_tables_bind_set(ctx, set, &priv->binding);
  	if (err < 0)
  		return err;
  
  	priv->set = set;
  	return 0;
  }
  
  static int nft_objref_map_dump(struct sk_buff *skb, const struct nft_expr *expr)
  {
  	const struct nft_objref_map *priv = nft_expr_priv(expr);
  
  	if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) ||
  	    nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name))
  		goto nla_put_failure;
  
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
cd5125d8f   Florian Westphal   netfilter: nf_tab...
159
  static void nft_objref_map_deactivate(const struct nft_ctx *ctx,
f6ac85858   Pablo Neira Ayuso   netfilter: nf_tab...
160
161
  				      const struct nft_expr *expr,
  				      enum nft_trans_phase phase)
cd5125d8f   Florian Westphal   netfilter: nf_tab...
162
163
  {
  	struct nft_objref_map *priv = nft_expr_priv(expr);
273fe3f10   Pablo Neira Ayuso   netfilter: nf_tab...
164
165
166
167
168
169
170
  	nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
  }
  
  static void nft_objref_map_activate(const struct nft_ctx *ctx,
  				    const struct nft_expr *expr)
  {
  	struct nft_objref_map *priv = nft_expr_priv(expr);
f6ac85858   Pablo Neira Ayuso   netfilter: nf_tab...
171

273fe3f10   Pablo Neira Ayuso   netfilter: nf_tab...
172
  	priv->set->use++;
cd5125d8f   Florian Westphal   netfilter: nf_tab...
173
  }
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
174
175
176
177
  static void nft_objref_map_destroy(const struct nft_ctx *ctx,
  				   const struct nft_expr *expr)
  {
  	struct nft_objref_map *priv = nft_expr_priv(expr);
cd5125d8f   Florian Westphal   netfilter: nf_tab...
178
  	nf_tables_destroy_set(ctx, priv->set);
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
179
180
181
182
183
184
185
186
  }
  
  static struct nft_expr_type nft_objref_type;
  static const struct nft_expr_ops nft_objref_map_ops = {
  	.type		= &nft_objref_type,
  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
  	.eval		= nft_objref_map_eval,
  	.init		= nft_objref_map_init,
273fe3f10   Pablo Neira Ayuso   netfilter: nf_tab...
187
  	.activate	= nft_objref_map_activate,
cd5125d8f   Florian Westphal   netfilter: nf_tab...
188
  	.deactivate	= nft_objref_map_deactivate,
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	.destroy	= nft_objref_map_destroy,
  	.dump		= nft_objref_map_dump,
  };
  
  static const struct nft_expr_ops *
  nft_objref_select_ops(const struct nft_ctx *ctx,
                        const struct nlattr * const tb[])
  {
  	if (tb[NFTA_OBJREF_SET_SREG] &&
  	    (tb[NFTA_OBJREF_SET_NAME] ||
  	     tb[NFTA_OBJREF_SET_ID]))
  		return &nft_objref_map_ops;
  	else if (tb[NFTA_OBJREF_IMM_NAME] &&
  		 tb[NFTA_OBJREF_IMM_TYPE])
  		return &nft_objref_ops;
  
  	return ERR_PTR(-EOPNOTSUPP);
  }
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
207
  static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
b2fbd0449   Liping Zhang   netfilter: nf_tab...
208
209
  	[NFTA_OBJREF_IMM_NAME]	= { .type = NLA_STRING,
  				    .len = NFT_OBJ_MAXNAMELEN - 1 },
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
210
  	[NFTA_OBJREF_IMM_TYPE]	= { .type = NLA_U32 },
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
211
  	[NFTA_OBJREF_SET_SREG]	= { .type = NLA_U32 },
b2fbd0449   Liping Zhang   netfilter: nf_tab...
212
213
  	[NFTA_OBJREF_SET_NAME]	= { .type = NLA_STRING,
  				    .len = NFT_SET_MAXNAMELEN - 1 },
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
214
  	[NFTA_OBJREF_SET_ID]	= { .type = NLA_U32 },
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
215
216
217
218
  };
  
  static struct nft_expr_type nft_objref_type __read_mostly = {
  	.name		= "objref",
63aea2906   Pablo Neira Ayuso   netfilter: nft_ob...
219
  	.select_ops	= nft_objref_select_ops,
c97d22e68   Pablo Neira Ayuso   netfilter: nf_tab...
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  	.policy		= nft_objref_policy,
  	.maxattr	= NFTA_OBJREF_MAX,
  	.owner		= THIS_MODULE,
  };
  
  static int __init nft_objref_module_init(void)
  {
  	return nft_register_expr(&nft_objref_type);
  }
  
  static void __exit nft_objref_module_exit(void)
  {
  	nft_unregister_expr(&nft_objref_type);
  }
  
  module_init(nft_objref_module_init);
  module_exit(nft_objref_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  MODULE_ALIAS_NFT_EXPR("objref");