Merge branches 'arm/rockchip', 'arm/exynos', 'arm/smmu', 'arm/mediatek', 'arm/io...
[linux-2.6-block.git] / net / netfilter / nft_meta.c
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 <linux/in.h>
18 #include <linux/ip.h>
19 #include <linux/ipv6.h>
20 #include <linux/smp.h>
21 #include <linux/static_key.h>
22 #include <net/dst.h>
23 #include <net/sock.h>
24 #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
25 #include <net/netfilter/nf_tables.h>
26 #include <net/netfilter/nf_tables_core.h>
27 #include <net/netfilter/nft_meta.h>
28
29 #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
30
31 void nft_meta_get_eval(const struct nft_expr *expr,
32                        struct nft_regs *regs,
33                        const struct nft_pktinfo *pkt)
34 {
35         const struct nft_meta *priv = nft_expr_priv(expr);
36         const struct sk_buff *skb = pkt->skb;
37         const struct net_device *in = pkt->in, *out = pkt->out;
38         struct sock *sk;
39         u32 *dest = &regs->data[priv->dreg];
40
41         switch (priv->key) {
42         case NFT_META_LEN:
43                 *dest = skb->len;
44                 break;
45         case NFT_META_PROTOCOL:
46                 *dest = 0;
47                 *(__be16 *)dest = skb->protocol;
48                 break;
49         case NFT_META_NFPROTO:
50                 *dest = pkt->pf;
51                 break;
52         case NFT_META_L4PROTO:
53                 *dest = pkt->tprot;
54                 break;
55         case NFT_META_PRIORITY:
56                 *dest = skb->priority;
57                 break;
58         case NFT_META_MARK:
59                 *dest = skb->mark;
60                 break;
61         case NFT_META_IIF:
62                 if (in == NULL)
63                         goto err;
64                 *dest = in->ifindex;
65                 break;
66         case NFT_META_OIF:
67                 if (out == NULL)
68                         goto err;
69                 *dest = out->ifindex;
70                 break;
71         case NFT_META_IIFNAME:
72                 if (in == NULL)
73                         goto err;
74                 strncpy((char *)dest, in->name, IFNAMSIZ);
75                 break;
76         case NFT_META_OIFNAME:
77                 if (out == NULL)
78                         goto err;
79                 strncpy((char *)dest, out->name, IFNAMSIZ);
80                 break;
81         case NFT_META_IIFTYPE:
82                 if (in == NULL)
83                         goto err;
84                 *dest = 0;
85                 *(u16 *)dest = in->type;
86                 break;
87         case NFT_META_OIFTYPE:
88                 if (out == NULL)
89                         goto err;
90                 *dest = 0;
91                 *(u16 *)dest = out->type;
92                 break;
93         case NFT_META_SKUID:
94                 sk = skb_to_full_sk(skb);
95                 if (!sk || !sk_fullsock(sk))
96                         goto err;
97
98                 read_lock_bh(&sk->sk_callback_lock);
99                 if (sk->sk_socket == NULL ||
100                     sk->sk_socket->file == NULL) {
101                         read_unlock_bh(&sk->sk_callback_lock);
102                         goto err;
103                 }
104
105                 *dest = from_kuid_munged(&init_user_ns,
106                                 sk->sk_socket->file->f_cred->fsuid);
107                 read_unlock_bh(&sk->sk_callback_lock);
108                 break;
109         case NFT_META_SKGID:
110                 sk = skb_to_full_sk(skb);
111                 if (!sk || !sk_fullsock(sk))
112                         goto err;
113
114                 read_lock_bh(&sk->sk_callback_lock);
115                 if (sk->sk_socket == NULL ||
116                     sk->sk_socket->file == NULL) {
117                         read_unlock_bh(&sk->sk_callback_lock);
118                         goto err;
119                 }
120                 *dest = from_kgid_munged(&init_user_ns,
121                                  sk->sk_socket->file->f_cred->fsgid);
122                 read_unlock_bh(&sk->sk_callback_lock);
123                 break;
124 #ifdef CONFIG_IP_ROUTE_CLASSID
125         case NFT_META_RTCLASSID: {
126                 const struct dst_entry *dst = skb_dst(skb);
127
128                 if (dst == NULL)
129                         goto err;
130                 *dest = dst->tclassid;
131                 break;
132         }
133 #endif
134 #ifdef CONFIG_NETWORK_SECMARK
135         case NFT_META_SECMARK:
136                 *dest = skb->secmark;
137                 break;
138 #endif
139         case NFT_META_PKTTYPE:
140                 if (skb->pkt_type != PACKET_LOOPBACK) {
141                         *dest = skb->pkt_type;
142                         break;
143                 }
144
145                 switch (pkt->pf) {
146                 case NFPROTO_IPV4:
147                         if (ipv4_is_multicast(ip_hdr(skb)->daddr))
148                                 *dest = PACKET_MULTICAST;
149                         else
150                                 *dest = PACKET_BROADCAST;
151                         break;
152                 case NFPROTO_IPV6:
153                         if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
154                                 *dest = PACKET_MULTICAST;
155                         else
156                                 *dest = PACKET_BROADCAST;
157                         break;
158                 default:
159                         WARN_ON(1);
160                         goto err;
161                 }
162                 break;
163         case NFT_META_CPU:
164                 *dest = raw_smp_processor_id();
165                 break;
166         case NFT_META_IIFGROUP:
167                 if (in == NULL)
168                         goto err;
169                 *dest = in->group;
170                 break;
171         case NFT_META_OIFGROUP:
172                 if (out == NULL)
173                         goto err;
174                 *dest = out->group;
175                 break;
176 #ifdef CONFIG_CGROUP_NET_CLASSID
177         case NFT_META_CGROUP:
178                 sk = skb_to_full_sk(skb);
179                 if (!sk || !sk_fullsock(sk))
180                         goto err;
181                 *dest = sock_cgroup_classid(&sk->sk_cgrp_data);
182                 break;
183 #endif
184         default:
185                 WARN_ON(1);
186                 goto err;
187         }
188         return;
189
190 err:
191         regs->verdict.code = NFT_BREAK;
192 }
193 EXPORT_SYMBOL_GPL(nft_meta_get_eval);
194
195 /* don't change or set _LOOPBACK, _USER, etc. */
196 static bool pkt_type_ok(u32 p)
197 {
198         return p == PACKET_HOST || p == PACKET_BROADCAST ||
199                p == PACKET_MULTICAST || p == PACKET_OTHERHOST;
200 }
201
202 void nft_meta_set_eval(const struct nft_expr *expr,
203                        struct nft_regs *regs,
204                        const struct nft_pktinfo *pkt)
205 {
206         const struct nft_meta *meta = nft_expr_priv(expr);
207         struct sk_buff *skb = pkt->skb;
208         u32 value = regs->data[meta->sreg];
209
210         switch (meta->key) {
211         case NFT_META_MARK:
212                 skb->mark = value;
213                 break;
214         case NFT_META_PRIORITY:
215                 skb->priority = value;
216                 break;
217         case NFT_META_PKTTYPE:
218                 if (skb->pkt_type != value &&
219                     pkt_type_ok(value) && pkt_type_ok(skb->pkt_type))
220                         skb->pkt_type = value;
221                 break;
222         case NFT_META_NFTRACE:
223                 skb->nf_trace = 1;
224                 break;
225         default:
226                 WARN_ON(1);
227         }
228 }
229 EXPORT_SYMBOL_GPL(nft_meta_set_eval);
230
231 const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
232         [NFTA_META_DREG]        = { .type = NLA_U32 },
233         [NFTA_META_KEY]         = { .type = NLA_U32 },
234         [NFTA_META_SREG]        = { .type = NLA_U32 },
235 };
236 EXPORT_SYMBOL_GPL(nft_meta_policy);
237
238 int nft_meta_get_init(const struct nft_ctx *ctx,
239                       const struct nft_expr *expr,
240                       const struct nlattr * const tb[])
241 {
242         struct nft_meta *priv = nft_expr_priv(expr);
243         unsigned int len;
244
245         priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
246         switch (priv->key) {
247         case NFT_META_PROTOCOL:
248         case NFT_META_IIFTYPE:
249         case NFT_META_OIFTYPE:
250                 len = sizeof(u16);
251                 break;
252         case NFT_META_NFPROTO:
253         case NFT_META_L4PROTO:
254         case NFT_META_LEN:
255         case NFT_META_PRIORITY:
256         case NFT_META_MARK:
257         case NFT_META_IIF:
258         case NFT_META_OIF:
259         case NFT_META_SKUID:
260         case NFT_META_SKGID:
261 #ifdef CONFIG_IP_ROUTE_CLASSID
262         case NFT_META_RTCLASSID:
263 #endif
264 #ifdef CONFIG_NETWORK_SECMARK
265         case NFT_META_SECMARK:
266 #endif
267         case NFT_META_PKTTYPE:
268         case NFT_META_CPU:
269         case NFT_META_IIFGROUP:
270         case NFT_META_OIFGROUP:
271 #ifdef CONFIG_CGROUP_NET_CLASSID
272         case NFT_META_CGROUP:
273 #endif
274                 len = sizeof(u32);
275                 break;
276         case NFT_META_IIFNAME:
277         case NFT_META_OIFNAME:
278                 len = IFNAMSIZ;
279                 break;
280         default:
281                 return -EOPNOTSUPP;
282         }
283
284         priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
285         return nft_validate_register_store(ctx, priv->dreg, NULL,
286                                            NFT_DATA_VALUE, len);
287 }
288 EXPORT_SYMBOL_GPL(nft_meta_get_init);
289
290 static int nft_meta_set_init_pkttype(const struct nft_ctx *ctx)
291 {
292         unsigned int hooks;
293
294         switch (ctx->afi->family) {
295         case NFPROTO_BRIDGE:
296                 hooks = 1 << NF_BR_PRE_ROUTING;
297                 break;
298         case NFPROTO_NETDEV:
299                 hooks = 1 << NF_NETDEV_INGRESS;
300                 break;
301         default:
302                 return -EOPNOTSUPP;
303         }
304
305         return nft_chain_validate_hooks(ctx->chain, hooks);
306 }
307
308 int nft_meta_set_init(const struct nft_ctx *ctx,
309                       const struct nft_expr *expr,
310                       const struct nlattr * const tb[])
311 {
312         struct nft_meta *priv = nft_expr_priv(expr);
313         unsigned int len;
314         int err;
315
316         priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
317         switch (priv->key) {
318         case NFT_META_MARK:
319         case NFT_META_PRIORITY:
320                 len = sizeof(u32);
321                 break;
322         case NFT_META_NFTRACE:
323                 len = sizeof(u8);
324                 break;
325         case NFT_META_PKTTYPE:
326                 err = nft_meta_set_init_pkttype(ctx);
327                 if (err)
328                         return err;
329                 len = sizeof(u8);
330                 break;
331         default:
332                 return -EOPNOTSUPP;
333         }
334
335         priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
336         err = nft_validate_register_load(priv->sreg, len);
337         if (err < 0)
338                 return err;
339
340         if (priv->key == NFT_META_NFTRACE)
341                 static_branch_inc(&nft_trace_enabled);
342
343         return 0;
344 }
345 EXPORT_SYMBOL_GPL(nft_meta_set_init);
346
347 int nft_meta_get_dump(struct sk_buff *skb,
348                       const struct nft_expr *expr)
349 {
350         const struct nft_meta *priv = nft_expr_priv(expr);
351
352         if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
353                 goto nla_put_failure;
354         if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
355                 goto nla_put_failure;
356         return 0;
357
358 nla_put_failure:
359         return -1;
360 }
361 EXPORT_SYMBOL_GPL(nft_meta_get_dump);
362
363 int nft_meta_set_dump(struct sk_buff *skb,
364                       const struct nft_expr *expr)
365 {
366         const struct nft_meta *priv = nft_expr_priv(expr);
367
368         if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
369                 goto nla_put_failure;
370         if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
371                 goto nla_put_failure;
372
373         return 0;
374
375 nla_put_failure:
376         return -1;
377 }
378 EXPORT_SYMBOL_GPL(nft_meta_set_dump);
379
380 void nft_meta_set_destroy(const struct nft_ctx *ctx,
381                           const struct nft_expr *expr)
382 {
383         const struct nft_meta *priv = nft_expr_priv(expr);
384
385         if (priv->key == NFT_META_NFTRACE)
386                 static_branch_dec(&nft_trace_enabled);
387 }
388 EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
389
390 static struct nft_expr_type nft_meta_type;
391 static const struct nft_expr_ops nft_meta_get_ops = {
392         .type           = &nft_meta_type,
393         .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
394         .eval           = nft_meta_get_eval,
395         .init           = nft_meta_get_init,
396         .dump           = nft_meta_get_dump,
397 };
398
399 static const struct nft_expr_ops nft_meta_set_ops = {
400         .type           = &nft_meta_type,
401         .size           = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
402         .eval           = nft_meta_set_eval,
403         .init           = nft_meta_set_init,
404         .destroy        = nft_meta_set_destroy,
405         .dump           = nft_meta_set_dump,
406 };
407
408 static const struct nft_expr_ops *
409 nft_meta_select_ops(const struct nft_ctx *ctx,
410                     const struct nlattr * const tb[])
411 {
412         if (tb[NFTA_META_KEY] == NULL)
413                 return ERR_PTR(-EINVAL);
414
415         if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
416                 return ERR_PTR(-EINVAL);
417
418         if (tb[NFTA_META_DREG])
419                 return &nft_meta_get_ops;
420
421         if (tb[NFTA_META_SREG])
422                 return &nft_meta_set_ops;
423
424         return ERR_PTR(-EINVAL);
425 }
426
427 static struct nft_expr_type nft_meta_type __read_mostly = {
428         .name           = "meta",
429         .select_ops     = &nft_meta_select_ops,
430         .policy         = nft_meta_policy,
431         .maxattr        = NFTA_META_MAX,
432         .owner          = THIS_MODULE,
433 };
434
435 static int __init nft_meta_module_init(void)
436 {
437         return nft_register_expr(&nft_meta_type);
438 }
439
440 static void __exit nft_meta_module_exit(void)
441 {
442         nft_unregister_expr(&nft_meta_type);
443 }
444
445 module_init(nft_meta_module_init);
446 module_exit(nft_meta_module_exit);
447
448 MODULE_LICENSE("GPL");
449 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
450 MODULE_ALIAS_NFT_EXPR("meta");