Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2012-2016 Pablo Neira Ayuso <pablo@netfilter.org>
0004  */
0005 
0006 #include <linux/init.h>
0007 #include <linux/module.h>
0008 #include <linux/skbuff.h>
0009 #include <linux/netlink.h>
0010 #include <linux/netfilter.h>
0011 #include <linux/netfilter/nf_tables.h>
0012 #include <net/netfilter/nf_tables_core.h>
0013 
0014 #define nft_objref_priv(expr)   *((struct nft_object **)nft_expr_priv(expr))
0015 
0016 static void nft_objref_eval(const struct nft_expr *expr,
0017                 struct nft_regs *regs,
0018                 const struct nft_pktinfo *pkt)
0019 {
0020     struct nft_object *obj = nft_objref_priv(expr);
0021 
0022     obj->ops->eval(obj, regs, pkt);
0023 }
0024 
0025 static int nft_objref_init(const struct nft_ctx *ctx,
0026                const struct nft_expr *expr,
0027                const struct nlattr * const tb[])
0028 {
0029     struct nft_object *obj = nft_objref_priv(expr);
0030     u8 genmask = nft_genmask_next(ctx->net);
0031     u32 objtype;
0032 
0033     if (!tb[NFTA_OBJREF_IMM_NAME] ||
0034         !tb[NFTA_OBJREF_IMM_TYPE])
0035         return -EINVAL;
0036 
0037     objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
0038     obj = nft_obj_lookup(ctx->net, ctx->table,
0039                  tb[NFTA_OBJREF_IMM_NAME], objtype,
0040                  genmask);
0041     if (IS_ERR(obj))
0042         return -ENOENT;
0043 
0044     nft_objref_priv(expr) = obj;
0045     obj->use++;
0046 
0047     return 0;
0048 }
0049 
0050 static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
0051 {
0052     const struct nft_object *obj = nft_objref_priv(expr);
0053 
0054     if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) ||
0055         nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
0056              htonl(obj->ops->type->type)))
0057         goto nla_put_failure;
0058 
0059     return 0;
0060 
0061 nla_put_failure:
0062     return -1;
0063 }
0064 
0065 static void nft_objref_deactivate(const struct nft_ctx *ctx,
0066                   const struct nft_expr *expr,
0067                   enum nft_trans_phase phase)
0068 {
0069     struct nft_object *obj = nft_objref_priv(expr);
0070 
0071     if (phase == NFT_TRANS_COMMIT)
0072         return;
0073 
0074     obj->use--;
0075 }
0076 
0077 static void nft_objref_activate(const struct nft_ctx *ctx,
0078                 const struct nft_expr *expr)
0079 {
0080     struct nft_object *obj = nft_objref_priv(expr);
0081 
0082     obj->use++;
0083 }
0084 
0085 static struct nft_expr_type nft_objref_type;
0086 static const struct nft_expr_ops nft_objref_ops = {
0087     .type       = &nft_objref_type,
0088     .size       = NFT_EXPR_SIZE(sizeof(struct nft_object *)),
0089     .eval       = nft_objref_eval,
0090     .init       = nft_objref_init,
0091     .activate   = nft_objref_activate,
0092     .deactivate = nft_objref_deactivate,
0093     .dump       = nft_objref_dump,
0094     .reduce     = NFT_REDUCE_READONLY,
0095 };
0096 
0097 struct nft_objref_map {
0098     struct nft_set      *set;
0099     u8          sreg;
0100     struct nft_set_binding  binding;
0101 };
0102 
0103 static void nft_objref_map_eval(const struct nft_expr *expr,
0104                 struct nft_regs *regs,
0105                 const struct nft_pktinfo *pkt)
0106 {
0107     struct nft_objref_map *priv = nft_expr_priv(expr);
0108     const struct nft_set *set = priv->set;
0109     struct net *net = nft_net(pkt);
0110     const struct nft_set_ext *ext;
0111     struct nft_object *obj;
0112     bool found;
0113 
0114     found = nft_set_do_lookup(net, set, &regs->data[priv->sreg], &ext);
0115     if (!found) {
0116         ext = nft_set_catchall_lookup(net, set);
0117         if (!ext) {
0118             regs->verdict.code = NFT_BREAK;
0119             return;
0120         }
0121     }
0122     obj = *nft_set_ext_obj(ext);
0123     obj->ops->eval(obj, regs, pkt);
0124 }
0125 
0126 static int nft_objref_map_init(const struct nft_ctx *ctx,
0127                    const struct nft_expr *expr,
0128                    const struct nlattr * const tb[])
0129 {
0130     struct nft_objref_map *priv = nft_expr_priv(expr);
0131     u8 genmask = nft_genmask_next(ctx->net);
0132     struct nft_set *set;
0133     int err;
0134 
0135     set = nft_set_lookup_global(ctx->net, ctx->table,
0136                     tb[NFTA_OBJREF_SET_NAME],
0137                     tb[NFTA_OBJREF_SET_ID], genmask);
0138     if (IS_ERR(set))
0139         return PTR_ERR(set);
0140 
0141     if (!(set->flags & NFT_SET_OBJECT))
0142         return -EINVAL;
0143 
0144     err = nft_parse_register_load(tb[NFTA_OBJREF_SET_SREG], &priv->sreg,
0145                       set->klen);
0146     if (err < 0)
0147         return err;
0148 
0149     priv->binding.flags = set->flags & NFT_SET_OBJECT;
0150 
0151     err = nf_tables_bind_set(ctx, set, &priv->binding);
0152     if (err < 0)
0153         return err;
0154 
0155     priv->set = set;
0156     return 0;
0157 }
0158 
0159 static int nft_objref_map_dump(struct sk_buff *skb, const struct nft_expr *expr)
0160 {
0161     const struct nft_objref_map *priv = nft_expr_priv(expr);
0162 
0163     if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) ||
0164         nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name))
0165         goto nla_put_failure;
0166 
0167     return 0;
0168 
0169 nla_put_failure:
0170     return -1;
0171 }
0172 
0173 static void nft_objref_map_deactivate(const struct nft_ctx *ctx,
0174                       const struct nft_expr *expr,
0175                       enum nft_trans_phase phase)
0176 {
0177     struct nft_objref_map *priv = nft_expr_priv(expr);
0178 
0179     nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
0180 }
0181 
0182 static void nft_objref_map_activate(const struct nft_ctx *ctx,
0183                     const struct nft_expr *expr)
0184 {
0185     struct nft_objref_map *priv = nft_expr_priv(expr);
0186 
0187     priv->set->use++;
0188 }
0189 
0190 static void nft_objref_map_destroy(const struct nft_ctx *ctx,
0191                    const struct nft_expr *expr)
0192 {
0193     struct nft_objref_map *priv = nft_expr_priv(expr);
0194 
0195     nf_tables_destroy_set(ctx, priv->set);
0196 }
0197 
0198 static struct nft_expr_type nft_objref_type;
0199 static const struct nft_expr_ops nft_objref_map_ops = {
0200     .type       = &nft_objref_type,
0201     .size       = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
0202     .eval       = nft_objref_map_eval,
0203     .init       = nft_objref_map_init,
0204     .activate   = nft_objref_map_activate,
0205     .deactivate = nft_objref_map_deactivate,
0206     .destroy    = nft_objref_map_destroy,
0207     .dump       = nft_objref_map_dump,
0208     .reduce     = NFT_REDUCE_READONLY,
0209 };
0210 
0211 static const struct nft_expr_ops *
0212 nft_objref_select_ops(const struct nft_ctx *ctx,
0213                       const struct nlattr * const tb[])
0214 {
0215     if (tb[NFTA_OBJREF_SET_SREG] &&
0216         (tb[NFTA_OBJREF_SET_NAME] ||
0217          tb[NFTA_OBJREF_SET_ID]))
0218         return &nft_objref_map_ops;
0219     else if (tb[NFTA_OBJREF_IMM_NAME] &&
0220          tb[NFTA_OBJREF_IMM_TYPE])
0221         return &nft_objref_ops;
0222 
0223     return ERR_PTR(-EOPNOTSUPP);
0224 }
0225 
0226 static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
0227     [NFTA_OBJREF_IMM_NAME]  = { .type = NLA_STRING,
0228                     .len = NFT_OBJ_MAXNAMELEN - 1 },
0229     [NFTA_OBJREF_IMM_TYPE]  = { .type = NLA_U32 },
0230     [NFTA_OBJREF_SET_SREG]  = { .type = NLA_U32 },
0231     [NFTA_OBJREF_SET_NAME]  = { .type = NLA_STRING,
0232                     .len = NFT_SET_MAXNAMELEN - 1 },
0233     [NFTA_OBJREF_SET_ID]    = { .type = NLA_U32 },
0234 };
0235 
0236 static struct nft_expr_type nft_objref_type __read_mostly = {
0237     .name       = "objref",
0238     .select_ops = nft_objref_select_ops,
0239     .policy     = nft_objref_policy,
0240     .maxattr    = NFTA_OBJREF_MAX,
0241     .owner      = THIS_MODULE,
0242 };
0243 
0244 static int __init nft_objref_module_init(void)
0245 {
0246     return nft_register_expr(&nft_objref_type);
0247 }
0248 
0249 static void __exit nft_objref_module_exit(void)
0250 {
0251     nft_unregister_expr(&nft_objref_type);
0252 }
0253 
0254 module_init(nft_objref_module_init);
0255 module_exit(nft_objref_module_exit);
0256 
0257 MODULE_LICENSE("GPL");
0258 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
0259 MODULE_ALIAS_NFT_EXPR("objref");
0260 MODULE_DESCRIPTION("nftables stateful object reference module");