OSDN Git Service

netfilter: nf_tables: allow to filter stateful object dumps by type
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 27 Nov 2016 23:06:11 +0000 (00:06 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 7 Dec 2016 12:22:49 +0000 (13:22 +0100)
This patch adds the netlink code to filter out dump of stateful objects,
through the NFTA_OBJ_TYPE netlink attribute.

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

index b4db5bf..b04d4ee 100644 (file)
@@ -4183,12 +4183,18 @@ nla_put_failure:
        return -1;
 }
 
+struct nft_obj_filter {
+       char            table[NFT_OBJ_MAXNAMELEN];
+       u32             type;
+};
+
 static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        const struct nft_af_info *afi;
        const struct nft_table *table;
        unsigned int idx = 0, s_idx = cb->args[0];
+       struct nft_obj_filter *filter = cb->data;
        struct net *net = sock_net(skb->sk);
        int family = nfmsg->nfgen_family;
        struct nft_object *obj;
@@ -4213,6 +4219,13 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
                                if (idx > s_idx)
                                        memset(&cb->args[1], 0,
                                               sizeof(cb->args) - sizeof(cb->args[0]));
+                               if (filter->table[0] &&
+                                   strcmp(filter->table, table->name))
+                                       goto cont;
+                               if (filter->type != NFT_OBJECT_UNSPEC &&
+                                   obj->type->type != filter->type)
+                                       goto cont;
+
                                if (nf_tables_fill_obj_info(skb, net, NETLINK_CB(cb->skb).portid,
                                                            cb->nlh->nlmsg_seq,
                                                            NFT_MSG_NEWOBJ,
@@ -4233,6 +4246,31 @@ done:
        return skb->len;
 }
 
+static int nf_tables_dump_obj_done(struct netlink_callback *cb)
+{
+       kfree(cb->data);
+
+       return 0;
+}
+
+static struct nft_obj_filter *
+nft_obj_filter_alloc(const struct nlattr * const nla[])
+{
+       struct nft_obj_filter *filter;
+
+       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+       if (!filter)
+               return ERR_PTR(-ENOMEM);
+
+       if (nla[NFTA_OBJ_TABLE])
+               nla_strlcpy(filter->table, nla[NFTA_OBJ_TABLE],
+                           NFT_TABLE_MAXNAMELEN);
+       if (nla[NFTA_OBJ_TYPE])
+               filter->type = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
+
+       return filter;
+}
+
 static int nf_tables_getobj(struct net *net, struct sock *nlsk,
                            struct sk_buff *skb, const struct nlmsghdr *nlh,
                            const struct nlattr * const nla[])
@@ -4251,7 +4289,19 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = nf_tables_dump_obj,
+                       .done = nf_tables_dump_obj_done,
                };
+
+               if (nla[NFTA_OBJ_TABLE] ||
+                   nla[NFTA_OBJ_TYPE]) {
+                       struct nft_obj_filter *filter;
+
+                       filter = nft_obj_filter_alloc(nla);
+                       if (IS_ERR(filter))
+                               return -ENOMEM;
+
+                       c.data = filter;
+               }
                return netlink_dump_start(nlsk, skb, nlh, &c);
        }