diff options
author | Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> | 2013-12-26 10:38:01 -0500 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-12-28 08:02:12 -0500 |
commit | e035b77ac7be430a5fef8c9c23f60b6b50ec81c5 (patch) | |
tree | 39b4b80d82ab6a19d394c6ac529f1765230c463b /net/netfilter | |
parent | d8bcc768c80e73cf4e948cb327949174b4b5b9e7 (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.c | 146 |
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 | ||
22 | struct nft_meta { | 22 | struct 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 | ||
27 | static void nft_meta_eval(const struct nft_expr *expr, | 30 | static 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 | ||
138 | static 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 | |||
135 | static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = { | 161 | static 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 | ||
140 | static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | 167 | static 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])); | 179 | static 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 | |
207 | static 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 | ||
182 | static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr) | 238 | static 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 | |||
249 | nla_put_failure: | ||
250 | return -1; | ||
251 | } | ||
252 | |||
253 | static 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 | ||
192 | nla_put_failure: | 265 | nla_put_failure: |
@@ -194,17 +267,44 @@ nla_put_failure: | |||
194 | } | 267 | } |
195 | 268 | ||
196 | static struct nft_expr_type nft_meta_type; | 269 | static struct nft_expr_type nft_meta_type; |
197 | static const struct nft_expr_ops nft_meta_ops = { | 270 | static 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 | ||
278 | static 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 | |||
286 | static const struct nft_expr_ops * | ||
287 | nft_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 | |||
205 | static struct nft_expr_type nft_meta_type __read_mostly = { | 305 | static 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, |