0001
0002
0003
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, ®s->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");