netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 30 Jun 2020 17:21:16 +0000 (19:21 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 3 Jul 2020 23:18:41 +0000 (01:18 +0200)
This new netlink attribute allows you to add rules to chains by the
chain ID.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/uapi/linux/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c

index 477779595b78f72ef059db8ee9bda96d56f1cf01..2304d1b7ba5ebfab426a34a86092e11c3b112292 100644 (file)
@@ -240,6 +240,7 @@ enum nft_rule_attributes {
        NFTA_RULE_PAD,
        NFTA_RULE_ID,
        NFTA_RULE_POSITION_ID,
+       NFTA_RULE_CHAIN_ID,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
index 650ef0dd0773e2f366490fd72d3c02754730eb32..fbe8f92098135b9bc0d7e4dec0b0774435ec2870 100644 (file)
@@ -2153,6 +2153,22 @@ err:
        return err;
 }
 
+static struct nft_chain *nft_chain_lookup_byid(const struct net *net,
+                                              const struct nlattr *nla)
+{
+       u32 id = ntohl(nla_get_be32(nla));
+       struct nft_trans *trans;
+
+       list_for_each_entry(trans, &net->nft.commit_list, list) {
+               struct nft_chain *chain = trans->ctx.chain;
+
+               if (trans->msg_type == NFT_MSG_NEWCHAIN &&
+                   id == nft_trans_chain_id(trans))
+                       return chain;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 static int nf_tables_newchain(struct net *net, struct sock *nlsk,
                              struct sk_buff *skb, const struct nlmsghdr *nlh,
                              const struct nlattr * const nla[],
@@ -2633,6 +2649,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
                                    .len = NFT_USERDATA_MAXLEN },
        [NFTA_RULE_ID]          = { .type = NLA_U32 },
        [NFTA_RULE_POSITION_ID] = { .type = NLA_U32 },
+       [NFTA_RULE_CHAIN_ID]    = { .type = NLA_U32 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
@@ -3039,10 +3056,21 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
                return PTR_ERR(table);
        }
 
-       chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN], genmask);
-       if (IS_ERR(chain)) {
-               NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
-               return PTR_ERR(chain);
+       if (nla[NFTA_RULE_CHAIN]) {
+               chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
+                                        genmask);
+               if (IS_ERR(chain)) {
+                       NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
+                       return PTR_ERR(chain);
+               }
+       } else if (nla[NFTA_RULE_CHAIN_ID]) {
+               chain = nft_chain_lookup_byid(net, nla[NFTA_RULE_CHAIN_ID]);
+               if (IS_ERR(chain)) {
+                       NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN_ID]);
+                       return PTR_ERR(chain);
+               }
+       } else {
+               return -EINVAL;
        }
 
        if (nla[NFTA_RULE_HANDLE]) {