linux/net/netfilter/nft_fib.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *
   4 * Generic part shared by ipv4 and ipv6 backends.
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/init.h>
   9#include <linux/module.h>
  10#include <linux/netlink.h>
  11#include <linux/netfilter.h>
  12#include <linux/netfilter/nf_tables.h>
  13#include <net/netfilter/nf_tables_core.h>
  14#include <net/netfilter/nf_tables.h>
  15#include <net/netfilter/nft_fib.h>
  16
  17const struct nla_policy nft_fib_policy[NFTA_FIB_MAX + 1] = {
  18        [NFTA_FIB_DREG]         = { .type = NLA_U32 },
  19        [NFTA_FIB_RESULT]       = { .type = NLA_U32 },
  20        [NFTA_FIB_FLAGS]        = { .type = NLA_U32 },
  21};
  22EXPORT_SYMBOL(nft_fib_policy);
  23
  24#define NFTA_FIB_F_ALL (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR | \
  25                        NFTA_FIB_F_MARK | NFTA_FIB_F_IIF | NFTA_FIB_F_OIF | \
  26                        NFTA_FIB_F_PRESENT)
  27
  28int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
  29                     const struct nft_data **data)
  30{
  31        const struct nft_fib *priv = nft_expr_priv(expr);
  32        unsigned int hooks;
  33
  34        switch (priv->result) {
  35        case NFT_FIB_RESULT_OIF: /* fallthrough */
  36        case NFT_FIB_RESULT_OIFNAME:
  37                hooks = (1 << NF_INET_PRE_ROUTING);
  38                break;
  39        case NFT_FIB_RESULT_ADDRTYPE:
  40                if (priv->flags & NFTA_FIB_F_IIF)
  41                        hooks = (1 << NF_INET_PRE_ROUTING) |
  42                                (1 << NF_INET_LOCAL_IN) |
  43                                (1 << NF_INET_FORWARD);
  44                else if (priv->flags & NFTA_FIB_F_OIF)
  45                        hooks = (1 << NF_INET_LOCAL_OUT) |
  46                                (1 << NF_INET_POST_ROUTING) |
  47                                (1 << NF_INET_FORWARD);
  48                else
  49                        hooks = (1 << NF_INET_LOCAL_IN) |
  50                                (1 << NF_INET_LOCAL_OUT) |
  51                                (1 << NF_INET_FORWARD) |
  52                                (1 << NF_INET_PRE_ROUTING) |
  53                                (1 << NF_INET_POST_ROUTING);
  54
  55                break;
  56        default:
  57                return -EINVAL;
  58        }
  59
  60        return nft_chain_validate_hooks(ctx->chain, hooks);
  61}
  62EXPORT_SYMBOL_GPL(nft_fib_validate);
  63
  64int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  65                 const struct nlattr * const tb[])
  66{
  67        struct nft_fib *priv = nft_expr_priv(expr);
  68        unsigned int len;
  69        int err;
  70
  71        if (!tb[NFTA_FIB_DREG] || !tb[NFTA_FIB_RESULT] || !tb[NFTA_FIB_FLAGS])
  72                return -EINVAL;
  73
  74        priv->flags = ntohl(nla_get_be32(tb[NFTA_FIB_FLAGS]));
  75
  76        if (priv->flags == 0 || (priv->flags & ~NFTA_FIB_F_ALL))
  77                return -EINVAL;
  78
  79        if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) ==
  80                           (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR))
  81                return -EINVAL;
  82        if ((priv->flags & (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF)) ==
  83                           (NFTA_FIB_F_IIF | NFTA_FIB_F_OIF))
  84                return -EINVAL;
  85        if ((priv->flags & (NFTA_FIB_F_SADDR | NFTA_FIB_F_DADDR)) == 0)
  86                return -EINVAL;
  87
  88        priv->result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));
  89        priv->dreg = nft_parse_register(tb[NFTA_FIB_DREG]);
  90
  91        switch (priv->result) {
  92        case NFT_FIB_RESULT_OIF:
  93                if (priv->flags & NFTA_FIB_F_OIF)
  94                        return -EINVAL;
  95                len = sizeof(int);
  96                break;
  97        case NFT_FIB_RESULT_OIFNAME:
  98                if (priv->flags & NFTA_FIB_F_OIF)
  99                        return -EINVAL;
 100                len = IFNAMSIZ;
 101                break;
 102        case NFT_FIB_RESULT_ADDRTYPE:
 103                len = sizeof(u32);
 104                break;
 105        default:
 106                return -EINVAL;
 107        }
 108
 109        err = nft_validate_register_store(ctx, priv->dreg, NULL,
 110                                          NFT_DATA_VALUE, len);
 111        if (err < 0)
 112                return err;
 113
 114        return 0;
 115}
 116EXPORT_SYMBOL_GPL(nft_fib_init);
 117
 118int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr)
 119{
 120        const struct nft_fib *priv = nft_expr_priv(expr);
 121
 122        if (nft_dump_register(skb, NFTA_FIB_DREG, priv->dreg))
 123                return -1;
 124
 125        if (nla_put_be32(skb, NFTA_FIB_RESULT, htonl(priv->result)))
 126                return -1;
 127
 128        if (nla_put_be32(skb, NFTA_FIB_FLAGS, htonl(priv->flags)))
 129                return -1;
 130
 131        return 0;
 132}
 133EXPORT_SYMBOL_GPL(nft_fib_dump);
 134
 135void nft_fib_store_result(void *reg, const struct nft_fib *priv,
 136                          const struct net_device *dev)
 137{
 138        u32 *dreg = reg;
 139        int index;
 140
 141        switch (priv->result) {
 142        case NFT_FIB_RESULT_OIF:
 143                index = dev ? dev->ifindex : 0;
 144                *dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index;
 145                break;
 146        case NFT_FIB_RESULT_OIFNAME:
 147                if (priv->flags & NFTA_FIB_F_PRESENT)
 148                        *dreg = !!dev;
 149                else
 150                        strncpy(reg, dev ? dev->name : "", IFNAMSIZ);
 151                break;
 152        default:
 153                WARN_ON_ONCE(1);
 154                *dreg = 0;
 155                break;
 156        }
 157}
 158EXPORT_SYMBOL_GPL(nft_fib_store_result);
 159
 160MODULE_LICENSE("GPL");
 161MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
 162