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: 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 90 switch (priv->result) { 91 case NFT_FIB_RESULT_OIF: 92 if (priv->flags & NFTA_FIB_F_OIF) 93 return -EINVAL; 94 len = sizeof(int); 95 break; 96 case NFT_FIB_RESULT_OIFNAME: 97 if (priv->flags & NFTA_FIB_F_OIF) 98 return -EINVAL; 99 len = IFNAMSIZ; 100 break; 101 case NFT_FIB_RESULT_ADDRTYPE: 102 len = sizeof(u32); 103 break; 104 default: 105 return -EINVAL; 106 } 107 108 err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg, 109 NULL, NFT_DATA_VALUE, len); 110 if (err < 0) 111 return err; 112 113 return 0; 114 } 115 EXPORT_SYMBOL_GPL(nft_fib_init); 116 117 int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr) 118 { 119 const struct nft_fib *priv = nft_expr_priv(expr); 120 121 if (nft_dump_register(skb, NFTA_FIB_DREG, priv->dreg)) 122 return -1; 123 124 if (nla_put_be32(skb, NFTA_FIB_RESULT, htonl(priv->result))) 125 return -1; 126 127 if (nla_put_be32(skb, NFTA_FIB_FLAGS, htonl(priv->flags))) 128 return -1; 129 130 return 0; 131 } 132 EXPORT_SYMBOL_GPL(nft_fib_dump); 133 134 void nft_fib_store_result(void *reg, const struct nft_fib *priv, 135 const struct net_device *dev) 136 { 137 u32 *dreg = reg; 138 int index; 139 140 switch (priv->result) { 141 case NFT_FIB_RESULT_OIF: 142 index = dev ? dev->ifindex : 0; 143 *dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index; 144 break; 145 case NFT_FIB_RESULT_OIFNAME: 146 if (priv->flags & NFTA_FIB_F_PRESENT) 147 *dreg = !!dev; 148 else 149 strncpy(reg, dev ? dev->name : "", IFNAMSIZ); 150 break; 151 default: 152 WARN_ON_ONCE(1); 153 *dreg = 0; 154 break; 155 } 156 } 157 EXPORT_SYMBOL_GPL(nft_fib_store_result); 158 159 MODULE_LICENSE("GPL"); 160 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); 161