netfilter: nf_tables: allow to filter out rules by table and chain
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 19 Jul 2016 10:20:45 +0000 (12:20 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 21 Jul 2016 00:32:35 +0000 (02:32 +0200)
If the table and/or chain attributes are set in a rule dump request,
we filter out the rules based on this selection.

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

index 0211eaec90608841990e40be68607b0bd5e5c902..13d50e7cfe2fe48d89096af578041e7351e04fb5 100644 (file)
@@ -1857,10 +1857,16 @@ err:
        return err;
 }
 
+struct nft_rule_dump_ctx {
+       char table[NFT_TABLE_MAXNAMELEN];
+       char chain[NFT_CHAIN_MAXNAMELEN];
+};
+
 static int nf_tables_dump_rules(struct sk_buff *skb,
                                struct netlink_callback *cb)
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
+       const struct nft_rule_dump_ctx *ctx = cb->data;
        const struct nft_af_info *afi;
        const struct nft_table *table;
        const struct nft_chain *chain;
@@ -1877,7 +1883,15 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
                        continue;
 
                list_for_each_entry_rcu(table, &afi->tables, list) {
+                       if (ctx && ctx->table[0] &&
+                           strcmp(ctx->table, table->name) != 0)
+                               continue;
+
                        list_for_each_entry_rcu(chain, &table->chains, list) {
+                               if (ctx && ctx->chain[0] &&
+                                   strcmp(ctx->chain, chain->name) != 0)
+                                       continue;
+
                                list_for_each_entry_rcu(rule, &chain->rules, list) {
                                        if (!nft_is_active(net, rule))
                                                goto cont;
@@ -1907,6 +1921,12 @@ done:
        return skb->len;
 }
 
+static int nf_tables_dump_rules_done(struct netlink_callback *cb)
+{
+       kfree(cb->data);
+       return 0;
+}
+
 static int nf_tables_getrule(struct net *net, struct sock *nlsk,
                             struct sk_buff *skb, const struct nlmsghdr *nlh,
                             const struct nlattr * const nla[])
@@ -1924,7 +1944,25 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = nf_tables_dump_rules,
+                       .done = nf_tables_dump_rules_done,
                };
+
+               if (nla[NFTA_RULE_TABLE] || nla[NFTA_RULE_CHAIN]) {
+                       struct nft_rule_dump_ctx *ctx;
+
+                       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+                       if (!ctx)
+                               return -ENOMEM;
+
+                       if (nla[NFTA_RULE_TABLE])
+                               nla_strlcpy(ctx->table, nla[NFTA_RULE_TABLE],
+                                           sizeof(ctx->table));
+                       if (nla[NFTA_RULE_CHAIN])
+                               nla_strlcpy(ctx->chain, nla[NFTA_RULE_CHAIN],
+                                           sizeof(ctx->chain));
+                       c.data = ctx;
+               }
+
                return netlink_dump_start(nlsk, skb, nlh, &c);
        }