Skip to content

Commit

Permalink
netfilter: nf_tables: allow to specify stateful expression in set def…
Browse files Browse the repository at this point in the history
…inition

This patch allows users to specify the stateful expression for the
elements in this set via NFTA_SET_EXPR. This new feature allows you to
turn on counters for all of the elements in this set.

Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
ummakynes committed Mar 19, 2020
1 parent 0c2a85e commit 6503842
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 12 deletions.
2 changes: 2 additions & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ struct nft_set_type {
* @policy: set parameterization (see enum nft_set_policies)
* @udlen: user data length
* @udata: user data
* @expr: stateful expression
* @ops: set ops
* @flags: set flags
* @genmask: generation mask
Expand Down Expand Up @@ -444,6 +445,7 @@ struct nft_set {
u16 policy;
u16 udlen;
unsigned char *udata;
struct nft_expr *expr;
/* runtime data below here */
const struct nft_set_ops *ops ____cacheline_aligned;
u16 flags:14,
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ enum nft_set_field_attributes {
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
* @NFTA_SET_HANDLE: set handle (NLA_U64)
* @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
Expand All @@ -361,6 +362,7 @@ enum nft_set_attributes {
NFTA_SET_PAD,
NFTA_SET_OBJ_TYPE,
NFTA_SET_HANDLE,
NFTA_SET_EXPR,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
Expand Down
60 changes: 48 additions & 12 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3394,6 +3394,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
.len = NFT_USERDATA_MAXLEN },
[NFTA_SET_OBJ_TYPE] = { .type = NLA_U32 },
[NFTA_SET_HANDLE] = { .type = NLA_U64 },
[NFTA_SET_EXPR] = { .type = NLA_NESTED },
};

static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
Expand Down Expand Up @@ -3597,8 +3598,8 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
{
struct nfgenmsg *nfmsg;
struct nlmsghdr *nlh;
struct nlattr *desc;
u32 portid = ctx->portid;
struct nlattr *nest;
u32 seq = ctx->seq;

event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
Expand Down Expand Up @@ -3654,9 +3655,8 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
goto nla_put_failure;

desc = nla_nest_start_noflag(skb, NFTA_SET_DESC);

if (desc == NULL)
nest = nla_nest_start_noflag(skb, NFTA_SET_DESC);
if (!nest)
goto nla_put_failure;
if (set->size &&
nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size)))
Expand All @@ -3666,7 +3666,15 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
nf_tables_fill_set_concat(skb, set))
goto nla_put_failure;

nla_nest_end(skb, desc);
nla_nest_end(skb, nest);

if (set->expr) {
nest = nla_nest_start_noflag(skb, NFTA_SET_EXPR);
if (nf_tables_fill_expr_info(skb, set->expr) < 0)
goto nla_put_failure;

nla_nest_end(skb, nest);
}

nlmsg_end(skb, nlh);
return 0;
Expand Down Expand Up @@ -3913,6 +3921,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
u8 genmask = nft_genmask_next(net);
int family = nfmsg->nfgen_family;
const struct nft_set_ops *ops;
struct nft_expr *expr = NULL;
struct nft_table *table;
struct nft_set *set;
struct nft_ctx ctx;
Expand Down Expand Up @@ -4069,13 +4078,21 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
name = nla_strdup(nla[NFTA_SET_NAME], GFP_KERNEL);
if (!name) {
err = -ENOMEM;
goto err2;
goto err_set_name;
}

err = nf_tables_set_alloc_name(&ctx, set, name);
kfree(name);
if (err < 0)
goto err2;
goto err_set_alloc_name;

if (nla[NFTA_SET_EXPR]) {
expr = nft_set_elem_expr_alloc(&ctx, set, nla[NFTA_SET_EXPR]);
if (IS_ERR(expr)) {
err = PTR_ERR(expr);
goto err_set_alloc_name;
}
}

udata = NULL;
if (udlen) {
Expand All @@ -4092,6 +4109,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
set->dtype = dtype;
set->objtype = objtype;
set->dlen = desc.dlen;
set->expr = expr;
set->flags = flags;
set->size = desc.size;
set->policy = policy;
Expand All @@ -4107,21 +4125,24 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,

err = ops->init(set, &desc, nla);
if (err < 0)
goto err3;
goto err_set_init;

err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
if (err < 0)
goto err4;
goto err_set_trans;

list_add_tail_rcu(&set->list, &table->sets);
table->use++;
return 0;

err4:
err_set_trans:
ops->destroy(set);
err3:
err_set_init:
if (expr)
nft_expr_destroy(&ctx, expr);
err_set_alloc_name:
kfree(set->name);
err2:
err_set_name:
kvfree(set);
return err;
}
Expand All @@ -4131,6 +4152,9 @@ static void nft_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
if (WARN_ON(set->use > 0))
return;

if (set->expr)
nft_expr_destroy(ctx, set->expr);

set->ops->destroy(set);
kfree(set->name);
kvfree(set);
Expand Down Expand Up @@ -4982,6 +5006,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
nla[NFTA_SET_ELEM_EXPR]);
if (IS_ERR(expr))
return PTR_ERR(expr);

err = -EOPNOTSUPP;
if (set->expr && set->expr->ops != expr->ops)
goto err_set_elem_expr;
} else if (set->expr) {
expr = kzalloc(set->expr->ops->size, GFP_KERNEL);
if (!expr)
return -ENOMEM;

err = nft_expr_clone(expr, set->expr);
if (err < 0)
goto err_set_elem_expr;
}

err = nft_setelem_parse_key(ctx, set, &elem.key.val,
Expand Down

0 comments on commit 6503842

Please sign in to comment.