netfilter: nf_tables: add elements with stateful expressions
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 11 Mar 2020 14:30:14 +0000 (15:30 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sun, 15 Mar 2020 14:27:49 +0000 (15:27 +0100)
Update nft_add_set_elem() to handle the NFTA_SET_ELEM_EXPR netlink
attribute. This patch allows users to to add elements with stateful
expressions.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_tables_api.c

index bc7a33f..f92fb60 100644 (file)
@@ -4891,6 +4891,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        struct nft_set_elem elem;
        struct nft_set_binding *binding;
        struct nft_object *obj = NULL;
+       struct nft_expr *expr = NULL;
        struct nft_userdata *udata;
        struct nft_data_desc desc;
        struct nft_data data;
@@ -4958,10 +4959,17 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        return err;
        }
 
+       if (nla[NFTA_SET_ELEM_EXPR] != NULL) {
+               expr = nft_set_elem_expr_alloc(ctx, set,
+                                              nla[NFTA_SET_ELEM_EXPR]);
+               if (IS_ERR(expr))
+                       return PTR_ERR(expr);
+       }
+
        err = nft_setelem_parse_key(ctx, set, &elem.key.val,
                                    nla[NFTA_SET_ELEM_KEY]);
        if (err < 0)
-               return err;
+               goto err_set_elem_expr;
 
        nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
 
@@ -4980,6 +4988,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
        }
 
+       if (expr)
+               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPR,
+                                      expr->ops->size);
+
        if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
                if (!(set->flags & NFT_SET_OBJECT)) {
                        err = -EINVAL;
@@ -5064,6 +5076,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                *nft_set_ext_obj(ext) = obj;
                obj->use++;
        }
+       if (expr) {
+               memcpy(nft_set_ext_expr(ext), expr, expr->ops->size);
+               kfree(expr);
+       }
 
        trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
        if (trans == NULL)
@@ -5119,6 +5135,9 @@ err_parse_key_end:
        nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
 err_parse_key:
        nft_data_release(&elem.key.val, NFT_DATA_VALUE);
+err_set_elem_expr:
+       if (expr != NULL)
+               nft_expr_destroy(ctx, expr);
 
        return err;
 }