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 17 const 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 }; 22 EXPORT_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 28 int 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 } 62 EXPORT_SYMBOL_GPL(nft_fib_validate); 63 64 int 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 } 116 EXPORT_SYMBOL_GPL(nft_fib_init); 117 118 int 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 } 133 EXPORT_SYMBOL_GPL(nft_fib_dump); 134 135 void 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 } 158 EXPORT_SYMBOL_GPL(nft_fib_store_result); 159 160 MODULE_LICENSE("GPL"); 161 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); 162