aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorArturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>2013-12-26 10:38:01 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2013-12-28 08:02:12 -0500
commite035b77ac7be430a5fef8c9c23f60b6b50ec81c5 (patch)
tree39b4b80d82ab6a19d394c6ac529f1765230c463b /net/netfilter
parentd8bcc768c80e73cf4e948cb327949174b4b5b9e7 (diff)
netfilter: nf_tables: nft_meta module get/set ops
This patch adds kernel support for the meta expression in get/set flavour. The set operation indicates that a given packet has to be set with a property, currently one of mark, priority, nftrace. The get op is what was currently working: evaluate the given packet property. In the nftrace case, the value is always 1. Such behaviour is copied from net/netfilter/xt_TRACE.c The NFTA_META_DREG and NFTA_META_SREG attributes are mutually exclusives. Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nft_meta.c146
1 files changed, 123 insertions, 23 deletions
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 8c28220a90b3..1ceaaa6dfe72 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -21,12 +21,15 @@
21 21
22struct nft_meta { 22struct nft_meta {
23 enum nft_meta_keys key:8; 23 enum nft_meta_keys key:8;
24 enum nft_registers dreg:8; 24 union {
25 enum nft_registers dreg:8;
26 enum nft_registers sreg:8;
27 };
25}; 28};
26 29
27static void nft_meta_eval(const struct nft_expr *expr, 30static void nft_meta_get_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1], 31 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt) 32 const struct nft_pktinfo *pkt)
30{ 33{
31 const struct nft_meta *priv = nft_expr_priv(expr); 34 const struct nft_meta *priv = nft_expr_priv(expr);
32 const struct sk_buff *skb = pkt->skb; 35 const struct sk_buff *skb = pkt->skb;
@@ -132,23 +135,50 @@ err:
132 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 135 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
133} 136}
134 137
138static void nft_meta_set_eval(const struct nft_expr *expr,
139 struct nft_data data[NFT_REG_MAX + 1],
140 const struct nft_pktinfo *pkt)
141{
142 const struct nft_meta *meta = nft_expr_priv(expr);
143 struct sk_buff *skb = pkt->skb;
144 u32 value = data[meta->sreg].data[0];
145
146 switch (meta->key) {
147 case NFT_META_MARK:
148 skb->mark = value;
149 break;
150 case NFT_META_PRIORITY:
151 skb->priority = value;
152 break;
153 case NFT_META_NFTRACE:
154 skb->nf_trace = 1;
155 break;
156 default:
157 WARN_ON(1);
158 }
159}
160
135static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { 161static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
136 [NFTA_META_DREG] = { .type = NLA_U32 }, 162 [NFTA_META_DREG] = { .type = NLA_U32 },
137 [NFTA_META_KEY] = { .type = NLA_U32 }, 163 [NFTA_META_KEY] = { .type = NLA_U32 },
164 [NFTA_META_SREG] = { .type = NLA_U32 },
138}; 165};
139 166
140static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 167static int nft_meta_init_validate_set(uint32_t key)
141 const struct nlattr * const tb[])
142{ 168{
143 struct nft_meta *priv = nft_expr_priv(expr); 169 switch (key) {
144 int err; 170 case NFT_META_MARK:
145 171 case NFT_META_PRIORITY:
146 if (tb[NFTA_META_DREG] == NULL || 172 case NFT_META_NFTRACE:
147 tb[NFTA_META_KEY] == NULL) 173 return 0;
148 return -EINVAL; 174 default:
175 return -EOPNOTSUPP;
176 }
177}
149 178
150 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 179static int nft_meta_init_validate_get(uint32_t key)
151 switch (priv->key) { 180{
181 switch (key) {
152 case NFT_META_LEN: 182 case NFT_META_LEN:
153 case NFT_META_PROTOCOL: 183 case NFT_META_PROTOCOL:
154 case NFT_META_PRIORITY: 184 case NFT_META_PRIORITY:
@@ -167,26 +197,69 @@ static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
167#ifdef CONFIG_NETWORK_SECMARK 197#ifdef CONFIG_NETWORK_SECMARK
168 case NFT_META_SECMARK: 198 case NFT_META_SECMARK:
169#endif 199#endif
170 break; 200 return 0;
171 default: 201 default:
172 return -EOPNOTSUPP; 202 return -EOPNOTSUPP;
173 } 203 }
174 204
175 priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); 205}
176 err = nft_validate_output_register(priv->dreg); 206
207static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
208 const struct nlattr * const tb[])
209{
210 struct nft_meta *priv = nft_expr_priv(expr);
211 int err;
212
213 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
214
215 if (tb[NFTA_META_DREG]) {
216 err = nft_meta_init_validate_get(priv->key);
217 if (err < 0)
218 return err;
219
220 priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG]));
221 err = nft_validate_output_register(priv->dreg);
222 if (err < 0)
223 return err;
224
225 return nft_validate_data_load(ctx, priv->dreg, NULL,
226 NFT_DATA_VALUE);
227 }
228
229 err = nft_meta_init_validate_set(priv->key);
177 if (err < 0) 230 if (err < 0)
178 return err; 231 return err;
179 return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); 232
233 priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG]));
234
235 return 0;
180} 236}
181 237
182static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) 238static int nft_meta_get_dump(struct sk_buff *skb,
239 const struct nft_expr *expr)
183{ 240{
184 const struct nft_meta *priv = nft_expr_priv(expr); 241 const struct nft_meta *priv = nft_expr_priv(expr);
185 242
243 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
244 goto nla_put_failure;
186 if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg))) 245 if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg)))
187 goto nla_put_failure; 246 goto nla_put_failure;
247 return 0;
248
249nla_put_failure:
250 return -1;
251}
252
253static int nft_meta_set_dump(struct sk_buff *skb,
254 const struct nft_expr *expr)
255{
256 const struct nft_meta *priv = nft_expr_priv(expr);
257
188 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) 258 if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
189 goto nla_put_failure; 259 goto nla_put_failure;
260 if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg)))
261 goto nla_put_failure;
262
190 return 0; 263 return 0;
191 264
192nla_put_failure: 265nla_put_failure:
@@ -194,17 +267,44 @@ nla_put_failure:
194} 267}
195 268
196static struct nft_expr_type nft_meta_type; 269static struct nft_expr_type nft_meta_type;
197static const struct nft_expr_ops nft_meta_ops = { 270static const struct nft_expr_ops nft_meta_get_ops = {
198 .type = &nft_meta_type, 271 .type = &nft_meta_type,
199 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 272 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
200 .eval = nft_meta_eval, 273 .eval = nft_meta_get_eval,
201 .init = nft_meta_init, 274 .init = nft_meta_init,
202 .dump = nft_meta_dump, 275 .dump = nft_meta_get_dump,
203}; 276};
204 277
278static const struct nft_expr_ops nft_meta_set_ops = {
279 .type = &nft_meta_type,
280 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
281 .eval = nft_meta_set_eval,
282 .init = nft_meta_init,
283 .dump = nft_meta_set_dump,
284};
285
286static const struct nft_expr_ops *
287nft_meta_select_ops(const struct nft_ctx *ctx,
288 const struct nlattr * const tb[])
289{
290 if (tb[NFTA_META_KEY] == NULL)
291 return ERR_PTR(-EINVAL);
292
293 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
294 return ERR_PTR(-EINVAL);
295
296 if (tb[NFTA_META_DREG])
297 return &nft_meta_get_ops;
298
299 if (tb[NFTA_META_SREG])
300 return &nft_meta_set_ops;
301
302 return ERR_PTR(-EINVAL);
303}
304
205static struct nft_expr_type nft_meta_type __read_mostly = { 305static struct nft_expr_type nft_meta_type __read_mostly = {
206 .name = "meta", 306 .name = "meta",
207 .ops = &nft_meta_ops, 307 .select_ops = &nft_meta_select_ops,
208 .policy = nft_meta_policy, 308 .policy = nft_meta_policy,
209 .maxattr = NFTA_META_MAX, 309 .maxattr = NFTA_META_MAX,
210 .owner = THIS_MODULE, 310 .owner = THIS_MODULE,