nft_objref.c (6632B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2012-2016 Pablo Neira Ayuso <pablo@netfilter.org> 4 */ 5 6#include <linux/init.h> 7#include <linux/module.h> 8#include <linux/skbuff.h> 9#include <linux/netlink.h> 10#include <linux/netfilter.h> 11#include <linux/netfilter/nf_tables.h> 12#include <net/netfilter/nf_tables_core.h> 13 14#define nft_objref_priv(expr) *((struct nft_object **)nft_expr_priv(expr)) 15 16static void nft_objref_eval(const struct nft_expr *expr, 17 struct nft_regs *regs, 18 const struct nft_pktinfo *pkt) 19{ 20 struct nft_object *obj = nft_objref_priv(expr); 21 22 obj->ops->eval(obj, regs, pkt); 23} 24 25static int nft_objref_init(const struct nft_ctx *ctx, 26 const struct nft_expr *expr, 27 const struct nlattr * const tb[]) 28{ 29 struct nft_object *obj = nft_objref_priv(expr); 30 u8 genmask = nft_genmask_next(ctx->net); 31 u32 objtype; 32 33 if (!tb[NFTA_OBJREF_IMM_NAME] || 34 !tb[NFTA_OBJREF_IMM_TYPE]) 35 return -EINVAL; 36 37 objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE])); 38 obj = nft_obj_lookup(ctx->net, ctx->table, 39 tb[NFTA_OBJREF_IMM_NAME], objtype, 40 genmask); 41 if (IS_ERR(obj)) 42 return -ENOENT; 43 44 nft_objref_priv(expr) = obj; 45 obj->use++; 46 47 return 0; 48} 49 50static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr) 51{ 52 const struct nft_object *obj = nft_objref_priv(expr); 53 54 if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) || 55 nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE, 56 htonl(obj->ops->type->type))) 57 goto nla_put_failure; 58 59 return 0; 60 61nla_put_failure: 62 return -1; 63} 64 65static void nft_objref_deactivate(const struct nft_ctx *ctx, 66 const struct nft_expr *expr, 67 enum nft_trans_phase phase) 68{ 69 struct nft_object *obj = nft_objref_priv(expr); 70 71 if (phase == NFT_TRANS_COMMIT) 72 return; 73 74 obj->use--; 75} 76 77static void nft_objref_activate(const struct nft_ctx *ctx, 78 const struct nft_expr *expr) 79{ 80 struct nft_object *obj = nft_objref_priv(expr); 81 82 obj->use++; 83} 84 85static struct nft_expr_type nft_objref_type; 86static const struct nft_expr_ops nft_objref_ops = { 87 .type = &nft_objref_type, 88 .size = NFT_EXPR_SIZE(sizeof(struct nft_object *)), 89 .eval = nft_objref_eval, 90 .init = nft_objref_init, 91 .activate = nft_objref_activate, 92 .deactivate = nft_objref_deactivate, 93 .dump = nft_objref_dump, 94 .reduce = NFT_REDUCE_READONLY, 95}; 96 97struct nft_objref_map { 98 struct nft_set *set; 99 u8 sreg; 100 struct nft_set_binding binding; 101}; 102 103static void nft_objref_map_eval(const struct nft_expr *expr, 104 struct nft_regs *regs, 105 const struct nft_pktinfo *pkt) 106{ 107 struct nft_objref_map *priv = nft_expr_priv(expr); 108 const struct nft_set *set = priv->set; 109 struct net *net = nft_net(pkt); 110 const struct nft_set_ext *ext; 111 struct nft_object *obj; 112 bool found; 113 114 found = nft_set_do_lookup(net, set, ®s->data[priv->sreg], &ext); 115 if (!found) { 116 ext = nft_set_catchall_lookup(net, set); 117 if (!ext) { 118 regs->verdict.code = NFT_BREAK; 119 return; 120 } 121 } 122 obj = *nft_set_ext_obj(ext); 123 obj->ops->eval(obj, regs, pkt); 124} 125 126static int nft_objref_map_init(const struct nft_ctx *ctx, 127 const struct nft_expr *expr, 128 const struct nlattr * const tb[]) 129{ 130 struct nft_objref_map *priv = nft_expr_priv(expr); 131 u8 genmask = nft_genmask_next(ctx->net); 132 struct nft_set *set; 133 int err; 134 135 set = nft_set_lookup_global(ctx->net, ctx->table, 136 tb[NFTA_OBJREF_SET_NAME], 137 tb[NFTA_OBJREF_SET_ID], genmask); 138 if (IS_ERR(set)) 139 return PTR_ERR(set); 140 141 if (!(set->flags & NFT_SET_OBJECT)) 142 return -EINVAL; 143 144 err = nft_parse_register_load(tb[NFTA_OBJREF_SET_SREG], &priv->sreg, 145 set->klen); 146 if (err < 0) 147 return err; 148 149 priv->binding.flags = set->flags & NFT_SET_OBJECT; 150 151 err = nf_tables_bind_set(ctx, set, &priv->binding); 152 if (err < 0) 153 return err; 154 155 priv->set = set; 156 return 0; 157} 158 159static int nft_objref_map_dump(struct sk_buff *skb, const struct nft_expr *expr) 160{ 161 const struct nft_objref_map *priv = nft_expr_priv(expr); 162 163 if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) || 164 nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name)) 165 goto nla_put_failure; 166 167 return 0; 168 169nla_put_failure: 170 return -1; 171} 172 173static void nft_objref_map_deactivate(const struct nft_ctx *ctx, 174 const struct nft_expr *expr, 175 enum nft_trans_phase phase) 176{ 177 struct nft_objref_map *priv = nft_expr_priv(expr); 178 179 nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase); 180} 181 182static void nft_objref_map_activate(const struct nft_ctx *ctx, 183 const struct nft_expr *expr) 184{ 185 struct nft_objref_map *priv = nft_expr_priv(expr); 186 187 priv->set->use++; 188} 189 190static void nft_objref_map_destroy(const struct nft_ctx *ctx, 191 const struct nft_expr *expr) 192{ 193 struct nft_objref_map *priv = nft_expr_priv(expr); 194 195 nf_tables_destroy_set(ctx, priv->set); 196} 197 198static struct nft_expr_type nft_objref_type; 199static const struct nft_expr_ops nft_objref_map_ops = { 200 .type = &nft_objref_type, 201 .size = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)), 202 .eval = nft_objref_map_eval, 203 .init = nft_objref_map_init, 204 .activate = nft_objref_map_activate, 205 .deactivate = nft_objref_map_deactivate, 206 .destroy = nft_objref_map_destroy, 207 .dump = nft_objref_map_dump, 208 .reduce = NFT_REDUCE_READONLY, 209}; 210 211static const struct nft_expr_ops * 212nft_objref_select_ops(const struct nft_ctx *ctx, 213 const struct nlattr * const tb[]) 214{ 215 if (tb[NFTA_OBJREF_SET_SREG] && 216 (tb[NFTA_OBJREF_SET_NAME] || 217 tb[NFTA_OBJREF_SET_ID])) 218 return &nft_objref_map_ops; 219 else if (tb[NFTA_OBJREF_IMM_NAME] && 220 tb[NFTA_OBJREF_IMM_TYPE]) 221 return &nft_objref_ops; 222 223 return ERR_PTR(-EOPNOTSUPP); 224} 225 226static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = { 227 [NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING, 228 .len = NFT_OBJ_MAXNAMELEN - 1 }, 229 [NFTA_OBJREF_IMM_TYPE] = { .type = NLA_U32 }, 230 [NFTA_OBJREF_SET_SREG] = { .type = NLA_U32 }, 231 [NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING, 232 .len = NFT_SET_MAXNAMELEN - 1 }, 233 [NFTA_OBJREF_SET_ID] = { .type = NLA_U32 }, 234}; 235 236static struct nft_expr_type nft_objref_type __read_mostly = { 237 .name = "objref", 238 .select_ops = nft_objref_select_ops, 239 .policy = nft_objref_policy, 240 .maxattr = NFTA_OBJREF_MAX, 241 .owner = THIS_MODULE, 242}; 243 244static int __init nft_objref_module_init(void) 245{ 246 return nft_register_expr(&nft_objref_type); 247} 248 249static void __exit nft_objref_module_exit(void) 250{ 251 nft_unregister_expr(&nft_objref_type); 252} 253 254module_init(nft_objref_module_init); 255module_exit(nft_objref_module_exit); 256 257MODULE_LICENSE("GPL"); 258MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); 259MODULE_ALIAS_NFT_EXPR("objref"); 260MODULE_DESCRIPTION("nftables stateful object reference module");