at master 7.1 kB view raw
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 16void 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_validate_obj_type(const struct nft_ctx *ctx, u32 type) 26{ 27 unsigned int hooks; 28 29 switch (type) { 30 case NFT_OBJECT_SYNPROXY: 31 if (ctx->family != NFPROTO_IPV4 && 32 ctx->family != NFPROTO_IPV6 && 33 ctx->family != NFPROTO_INET) 34 return -EOPNOTSUPP; 35 36 hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD); 37 38 return nft_chain_validate_hooks(ctx->chain, hooks); 39 default: 40 break; 41 } 42 43 return 0; 44} 45 46static int nft_objref_validate(const struct nft_ctx *ctx, 47 const struct nft_expr *expr) 48{ 49 struct nft_object *obj = nft_objref_priv(expr); 50 51 return nft_objref_validate_obj_type(ctx, obj->ops->type->type); 52} 53 54static int nft_objref_init(const struct nft_ctx *ctx, 55 const struct nft_expr *expr, 56 const struct nlattr * const tb[]) 57{ 58 struct nft_object *obj = nft_objref_priv(expr); 59 u8 genmask = nft_genmask_next(ctx->net); 60 u32 objtype; 61 62 if (!tb[NFTA_OBJREF_IMM_NAME] || 63 !tb[NFTA_OBJREF_IMM_TYPE]) 64 return -EINVAL; 65 66 objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE])); 67 obj = nft_obj_lookup(ctx->net, ctx->table, 68 tb[NFTA_OBJREF_IMM_NAME], objtype, 69 genmask); 70 if (IS_ERR(obj)) 71 return -ENOENT; 72 73 if (!nft_use_inc(&obj->use)) 74 return -EMFILE; 75 76 nft_objref_priv(expr) = obj; 77 78 return 0; 79} 80 81static int nft_objref_dump(struct sk_buff *skb, 82 const struct nft_expr *expr, bool reset) 83{ 84 const struct nft_object *obj = nft_objref_priv(expr); 85 86 if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->key.name) || 87 nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE, 88 htonl(obj->ops->type->type))) 89 goto nla_put_failure; 90 91 return 0; 92 93nla_put_failure: 94 return -1; 95} 96 97static void nft_objref_deactivate(const struct nft_ctx *ctx, 98 const struct nft_expr *expr, 99 enum nft_trans_phase phase) 100{ 101 struct nft_object *obj = nft_objref_priv(expr); 102 103 if (phase == NFT_TRANS_COMMIT) 104 return; 105 106 nft_use_dec(&obj->use); 107} 108 109static void nft_objref_activate(const struct nft_ctx *ctx, 110 const struct nft_expr *expr) 111{ 112 struct nft_object *obj = nft_objref_priv(expr); 113 114 nft_use_inc_restore(&obj->use); 115} 116 117static const struct nft_expr_ops nft_objref_ops = { 118 .type = &nft_objref_type, 119 .size = NFT_EXPR_SIZE(sizeof(struct nft_object *)), 120 .eval = nft_objref_eval, 121 .init = nft_objref_init, 122 .activate = nft_objref_activate, 123 .deactivate = nft_objref_deactivate, 124 .dump = nft_objref_dump, 125 .validate = nft_objref_validate, 126 .reduce = NFT_REDUCE_READONLY, 127}; 128 129struct nft_objref_map { 130 struct nft_set *set; 131 u8 sreg; 132 struct nft_set_binding binding; 133}; 134 135void nft_objref_map_eval(const struct nft_expr *expr, 136 struct nft_regs *regs, 137 const struct nft_pktinfo *pkt) 138{ 139 struct nft_objref_map *priv = nft_expr_priv(expr); 140 const struct nft_set *set = priv->set; 141 struct net *net = nft_net(pkt); 142 const struct nft_set_ext *ext; 143 struct nft_object *obj; 144 145 ext = nft_set_do_lookup(net, set, &regs->data[priv->sreg]); 146 if (!ext) { 147 ext = nft_set_catchall_lookup(net, set); 148 if (!ext) { 149 regs->verdict.code = NFT_BREAK; 150 return; 151 } 152 } 153 obj = *nft_set_ext_obj(ext); 154 obj->ops->eval(obj, regs, pkt); 155} 156 157static int nft_objref_map_init(const struct nft_ctx *ctx, 158 const struct nft_expr *expr, 159 const struct nlattr * const tb[]) 160{ 161 struct nft_objref_map *priv = nft_expr_priv(expr); 162 u8 genmask = nft_genmask_next(ctx->net); 163 struct nft_set *set; 164 int err; 165 166 set = nft_set_lookup_global(ctx->net, ctx->table, 167 tb[NFTA_OBJREF_SET_NAME], 168 tb[NFTA_OBJREF_SET_ID], genmask); 169 if (IS_ERR(set)) 170 return PTR_ERR(set); 171 172 if (!(set->flags & NFT_SET_OBJECT)) 173 return -EINVAL; 174 175 err = nft_parse_register_load(ctx, tb[NFTA_OBJREF_SET_SREG], &priv->sreg, 176 set->klen); 177 if (err < 0) 178 return err; 179 180 priv->binding.flags = set->flags & NFT_SET_OBJECT; 181 182 err = nf_tables_bind_set(ctx, set, &priv->binding); 183 if (err < 0) 184 return err; 185 186 priv->set = set; 187 return 0; 188} 189 190static int nft_objref_map_dump(struct sk_buff *skb, 191 const struct nft_expr *expr, bool reset) 192{ 193 const struct nft_objref_map *priv = nft_expr_priv(expr); 194 195 if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) || 196 nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name)) 197 goto nla_put_failure; 198 199 return 0; 200 201nla_put_failure: 202 return -1; 203} 204 205static void nft_objref_map_deactivate(const struct nft_ctx *ctx, 206 const struct nft_expr *expr, 207 enum nft_trans_phase phase) 208{ 209 struct nft_objref_map *priv = nft_expr_priv(expr); 210 211 nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase); 212} 213 214static void nft_objref_map_activate(const struct nft_ctx *ctx, 215 const struct nft_expr *expr) 216{ 217 struct nft_objref_map *priv = nft_expr_priv(expr); 218 219 nf_tables_activate_set(ctx, priv->set); 220} 221 222static void nft_objref_map_destroy(const struct nft_ctx *ctx, 223 const struct nft_expr *expr) 224{ 225 struct nft_objref_map *priv = nft_expr_priv(expr); 226 227 nf_tables_destroy_set(ctx, priv->set); 228} 229 230static int nft_objref_map_validate(const struct nft_ctx *ctx, 231 const struct nft_expr *expr) 232{ 233 const struct nft_objref_map *priv = nft_expr_priv(expr); 234 235 return nft_objref_validate_obj_type(ctx, priv->set->objtype); 236} 237 238static const struct nft_expr_ops nft_objref_map_ops = { 239 .type = &nft_objref_type, 240 .size = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)), 241 .eval = nft_objref_map_eval, 242 .init = nft_objref_map_init, 243 .activate = nft_objref_map_activate, 244 .deactivate = nft_objref_map_deactivate, 245 .destroy = nft_objref_map_destroy, 246 .dump = nft_objref_map_dump, 247 .validate = nft_objref_map_validate, 248 .reduce = NFT_REDUCE_READONLY, 249}; 250 251static const struct nft_expr_ops * 252nft_objref_select_ops(const struct nft_ctx *ctx, 253 const struct nlattr * const tb[]) 254{ 255 if (tb[NFTA_OBJREF_SET_SREG] && 256 (tb[NFTA_OBJREF_SET_NAME] || 257 tb[NFTA_OBJREF_SET_ID])) 258 return &nft_objref_map_ops; 259 else if (tb[NFTA_OBJREF_IMM_NAME] && 260 tb[NFTA_OBJREF_IMM_TYPE]) 261 return &nft_objref_ops; 262 263 return ERR_PTR(-EOPNOTSUPP); 264} 265 266static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = { 267 [NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING, 268 .len = NFT_OBJ_MAXNAMELEN - 1 }, 269 [NFTA_OBJREF_IMM_TYPE] = { .type = NLA_U32 }, 270 [NFTA_OBJREF_SET_SREG] = { .type = NLA_U32 }, 271 [NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING, 272 .len = NFT_SET_MAXNAMELEN - 1 }, 273 [NFTA_OBJREF_SET_ID] = { .type = NLA_U32 }, 274}; 275 276struct nft_expr_type nft_objref_type __read_mostly = { 277 .name = "objref", 278 .select_ops = nft_objref_select_ops, 279 .policy = nft_objref_policy, 280 .maxattr = NFTA_OBJREF_MAX, 281 .owner = THIS_MODULE, 282};