0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/init.h>
0010 #include <linux/list.h>
0011 #include <linux/rbtree.h>
0012 #include <linux/netlink.h>
0013 #include <linux/netfilter.h>
0014 #include <linux/netfilter/nf_tables.h>
0015 #include <net/netfilter/nf_tables.h>
0016 #include <net/netfilter/nf_tables_core.h>
0017
0018 struct nft_lookup {
0019 struct nft_set *set;
0020 u8 sreg;
0021 u8 dreg;
0022 bool invert;
0023 struct nft_set_binding binding;
0024 };
0025
0026 #ifdef CONFIG_RETPOLINE
0027 bool nft_set_do_lookup(const struct net *net, const struct nft_set *set,
0028 const u32 *key, const struct nft_set_ext **ext)
0029 {
0030 if (set->ops == &nft_set_hash_fast_type.ops)
0031 return nft_hash_lookup_fast(net, set, key, ext);
0032 if (set->ops == &nft_set_hash_type.ops)
0033 return nft_hash_lookup(net, set, key, ext);
0034
0035 if (set->ops == &nft_set_rhash_type.ops)
0036 return nft_rhash_lookup(net, set, key, ext);
0037
0038 if (set->ops == &nft_set_bitmap_type.ops)
0039 return nft_bitmap_lookup(net, set, key, ext);
0040
0041 if (set->ops == &nft_set_pipapo_type.ops)
0042 return nft_pipapo_lookup(net, set, key, ext);
0043 #if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
0044 if (set->ops == &nft_set_pipapo_avx2_type.ops)
0045 return nft_pipapo_avx2_lookup(net, set, key, ext);
0046 #endif
0047
0048 if (set->ops == &nft_set_rbtree_type.ops)
0049 return nft_rbtree_lookup(net, set, key, ext);
0050
0051 WARN_ON_ONCE(1);
0052 return set->ops->lookup(net, set, key, ext);
0053 }
0054 EXPORT_SYMBOL_GPL(nft_set_do_lookup);
0055 #endif
0056
0057 void nft_lookup_eval(const struct nft_expr *expr,
0058 struct nft_regs *regs,
0059 const struct nft_pktinfo *pkt)
0060 {
0061 const struct nft_lookup *priv = nft_expr_priv(expr);
0062 const struct nft_set *set = priv->set;
0063 const struct nft_set_ext *ext = NULL;
0064 const struct net *net = nft_net(pkt);
0065 bool found;
0066
0067 found = nft_set_do_lookup(net, set, ®s->data[priv->sreg], &ext) ^
0068 priv->invert;
0069 if (!found) {
0070 ext = nft_set_catchall_lookup(net, set);
0071 if (!ext) {
0072 regs->verdict.code = NFT_BREAK;
0073 return;
0074 }
0075 }
0076
0077 if (ext) {
0078 if (set->flags & NFT_SET_MAP)
0079 nft_data_copy(®s->data[priv->dreg],
0080 nft_set_ext_data(ext), set->dlen);
0081
0082 nft_set_elem_update_expr(ext, regs, pkt);
0083 }
0084 }
0085
0086 static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
0087 [NFTA_LOOKUP_SET] = { .type = NLA_STRING,
0088 .len = NFT_SET_MAXNAMELEN - 1 },
0089 [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 },
0090 [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
0091 [NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
0092 [NFTA_LOOKUP_FLAGS] = { .type = NLA_U32 },
0093 };
0094
0095 static int nft_lookup_init(const struct nft_ctx *ctx,
0096 const struct nft_expr *expr,
0097 const struct nlattr * const tb[])
0098 {
0099 struct nft_lookup *priv = nft_expr_priv(expr);
0100 u8 genmask = nft_genmask_next(ctx->net);
0101 struct nft_set *set;
0102 u32 flags;
0103 int err;
0104
0105 if (tb[NFTA_LOOKUP_SET] == NULL ||
0106 tb[NFTA_LOOKUP_SREG] == NULL)
0107 return -EINVAL;
0108
0109 set = nft_set_lookup_global(ctx->net, ctx->table, tb[NFTA_LOOKUP_SET],
0110 tb[NFTA_LOOKUP_SET_ID], genmask);
0111 if (IS_ERR(set))
0112 return PTR_ERR(set);
0113
0114 err = nft_parse_register_load(tb[NFTA_LOOKUP_SREG], &priv->sreg,
0115 set->klen);
0116 if (err < 0)
0117 return err;
0118
0119 if (tb[NFTA_LOOKUP_FLAGS]) {
0120 flags = ntohl(nla_get_be32(tb[NFTA_LOOKUP_FLAGS]));
0121
0122 if (flags & ~NFT_LOOKUP_F_INV)
0123 return -EINVAL;
0124
0125 if (flags & NFT_LOOKUP_F_INV) {
0126 if (set->flags & NFT_SET_MAP)
0127 return -EINVAL;
0128 priv->invert = true;
0129 }
0130 }
0131
0132 if (tb[NFTA_LOOKUP_DREG] != NULL) {
0133 if (priv->invert)
0134 return -EINVAL;
0135 if (!(set->flags & NFT_SET_MAP))
0136 return -EINVAL;
0137
0138 err = nft_parse_register_store(ctx, tb[NFTA_LOOKUP_DREG],
0139 &priv->dreg, NULL, set->dtype,
0140 set->dlen);
0141 if (err < 0)
0142 return err;
0143 } else if (set->flags & NFT_SET_MAP)
0144 return -EINVAL;
0145
0146 priv->binding.flags = set->flags & NFT_SET_MAP;
0147
0148 err = nf_tables_bind_set(ctx, set, &priv->binding);
0149 if (err < 0)
0150 return err;
0151
0152 priv->set = set;
0153 return 0;
0154 }
0155
0156 static void nft_lookup_deactivate(const struct nft_ctx *ctx,
0157 const struct nft_expr *expr,
0158 enum nft_trans_phase phase)
0159 {
0160 struct nft_lookup *priv = nft_expr_priv(expr);
0161
0162 nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
0163 }
0164
0165 static void nft_lookup_activate(const struct nft_ctx *ctx,
0166 const struct nft_expr *expr)
0167 {
0168 struct nft_lookup *priv = nft_expr_priv(expr);
0169
0170 priv->set->use++;
0171 }
0172
0173 static void nft_lookup_destroy(const struct nft_ctx *ctx,
0174 const struct nft_expr *expr)
0175 {
0176 struct nft_lookup *priv = nft_expr_priv(expr);
0177
0178 nf_tables_destroy_set(ctx, priv->set);
0179 }
0180
0181 static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
0182 {
0183 const struct nft_lookup *priv = nft_expr_priv(expr);
0184 u32 flags = priv->invert ? NFT_LOOKUP_F_INV : 0;
0185
0186 if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
0187 goto nla_put_failure;
0188 if (nft_dump_register(skb, NFTA_LOOKUP_SREG, priv->sreg))
0189 goto nla_put_failure;
0190 if (priv->set->flags & NFT_SET_MAP)
0191 if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg))
0192 goto nla_put_failure;
0193 if (nla_put_be32(skb, NFTA_LOOKUP_FLAGS, htonl(flags)))
0194 goto nla_put_failure;
0195 return 0;
0196
0197 nla_put_failure:
0198 return -1;
0199 }
0200
0201 static int nft_lookup_validate_setelem(const struct nft_ctx *ctx,
0202 struct nft_set *set,
0203 const struct nft_set_iter *iter,
0204 struct nft_set_elem *elem)
0205 {
0206 const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
0207 struct nft_ctx *pctx = (struct nft_ctx *)ctx;
0208 const struct nft_data *data;
0209 int err;
0210
0211 if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
0212 *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
0213 return 0;
0214
0215 data = nft_set_ext_data(ext);
0216 switch (data->verdict.code) {
0217 case NFT_JUMP:
0218 case NFT_GOTO:
0219 pctx->level++;
0220 err = nft_chain_validate(ctx, data->verdict.chain);
0221 if (err < 0)
0222 return err;
0223 pctx->level--;
0224 break;
0225 default:
0226 break;
0227 }
0228
0229 return 0;
0230 }
0231
0232 static int nft_lookup_validate(const struct nft_ctx *ctx,
0233 const struct nft_expr *expr,
0234 const struct nft_data **d)
0235 {
0236 const struct nft_lookup *priv = nft_expr_priv(expr);
0237 struct nft_set_iter iter;
0238
0239 if (!(priv->set->flags & NFT_SET_MAP) ||
0240 priv->set->dtype != NFT_DATA_VERDICT)
0241 return 0;
0242
0243 iter.genmask = nft_genmask_next(ctx->net);
0244 iter.skip = 0;
0245 iter.count = 0;
0246 iter.err = 0;
0247 iter.fn = nft_lookup_validate_setelem;
0248
0249 priv->set->ops->walk(ctx, priv->set, &iter);
0250 if (iter.err < 0)
0251 return iter.err;
0252
0253 return 0;
0254 }
0255
0256 static bool nft_lookup_reduce(struct nft_regs_track *track,
0257 const struct nft_expr *expr)
0258 {
0259 const struct nft_lookup *priv = nft_expr_priv(expr);
0260
0261 if (priv->set->flags & NFT_SET_MAP)
0262 nft_reg_track_cancel(track, priv->dreg, priv->set->dlen);
0263
0264 return false;
0265 }
0266
0267 static const struct nft_expr_ops nft_lookup_ops = {
0268 .type = &nft_lookup_type,
0269 .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
0270 .eval = nft_lookup_eval,
0271 .init = nft_lookup_init,
0272 .activate = nft_lookup_activate,
0273 .deactivate = nft_lookup_deactivate,
0274 .destroy = nft_lookup_destroy,
0275 .dump = nft_lookup_dump,
0276 .validate = nft_lookup_validate,
0277 .reduce = nft_lookup_reduce,
0278 };
0279
0280 struct nft_expr_type nft_lookup_type __read_mostly = {
0281 .name = "lookup",
0282 .ops = &nft_lookup_ops,
0283 .policy = nft_lookup_policy,
0284 .maxattr = NFTA_LOOKUP_MAX,
0285 .owner = THIS_MODULE,
0286 };