netfilter: nf_tables: Support RULE_ID reference in new rule
authorPhil Sutter <phil@nwl.cc>
Mon, 14 Jan 2019 17:41:35 +0000 (18:41 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 18 Jan 2019 14:02:33 +0000 (15:02 +0100)
To allow for a batch to contain rules in arbitrary ordering, introduce
NFTA_RULE_POSITION_ID attribute which works just like NFTA_RULE_POSITION
but contains the ID of another rule within the same batch. This helps
iptables-nft-restore handling dumps with mixed insert/append commands
correctly.

Note that NFTA_RULE_POSITION takes precedence over
NFTA_RULE_POSITION_ID, so if the former is present, the latter is
ignored.

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

index 7de4f1b..99ca95b 100644 (file)
@@ -219,6 +219,7 @@ enum nft_chain_attributes {
  * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
  * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  * @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
+ * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
  */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
@@ -231,6 +232,7 @@ enum nft_rule_attributes {
        NFTA_RULE_USERDATA,
        NFTA_RULE_PAD,
        NFTA_RULE_ID,
+       NFTA_RULE_POSITION_ID,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
index 621ff83..d88c86c 100644 (file)
@@ -2610,6 +2610,9 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
        return 0;
 }
 
+static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
+                                            const struct nlattr *nla);
+
 #define NFT_RULE_MAXEXPRS      128
 
 static int nf_tables_newrule(struct net *net, struct sock *nlsk,
@@ -2679,6 +2682,12 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
                                NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_POSITION]);
                                return PTR_ERR(old_rule);
                        }
+               } else if (nla[NFTA_RULE_POSITION_ID]) {
+                       old_rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_POSITION_ID]);
+                       if (IS_ERR(old_rule)) {
+                               NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_POSITION_ID]);
+                               return PTR_ERR(old_rule);
+                       }
                }
        }