~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/nft_meta.c

Version: ~ [ linux-6.0-rc6 ] ~ [ linux-5.19.10 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.69 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.144 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.214 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.259 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.294 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.329 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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");
451 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp