]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
Support 'add/insert rule index <IDX>'
authorPhil Sutter <phil@nwl.cc>
Wed, 9 May 2018 14:03:42 +0000 (16:03 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 9 May 2018 16:29:21 +0000 (18:29 +0200)
Allow to specify an absolute rule position in add/insert commands like
with iptables. The translation to rule handle takes place in userspace,
so no kernel support for this is needed. Possible undesired effects are
pointed out in man page to make users aware that this way of specifying
a rule location might not be ideal.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
doc/nft.xml
include/rule.h
src/evaluate.c
src/parser_bison.y
src/rule.c
src/scanner.l

index b80c8c439e2c76ea09f3e0bf1ed3570810638172..ab94bff447326cb040fea4b908482ce13f165635 100644 (file)
@@ -875,13 +875,19 @@ add table inet mytable
                                <arg choice="opt"><replaceable>family</replaceable></arg>
                                <replaceable>table</replaceable>
                                <replaceable>chain</replaceable>
-                               <arg choice="opt">
-                                       <group choice="req">
-                                               <arg>handle</arg>
-                                               <arg>position</arg>
-                                       </group>
-                                       <replaceable>handle</replaceable>
-                               </arg>
+                               <group choice="opt">
+                                       <arg>
+                                               <group choice="req">
+                                                       <arg>handle</arg>
+                                                       <arg>position</arg>
+                                               </group>
+                                               <replaceable>handle</replaceable>
+                                       </arg>
+                                       <arg>
+                                               <literal>index</literal>
+                                               <replaceable>index</replaceable>
+                                       </arg>
+                               </group>
                                <replaceable>statement</replaceable>...
                        </cmdsynopsis>
                        <cmdsynopsis>
@@ -909,6 +915,17 @@ add table inet mytable
                        Rules are constructed from two kinds of components according to a set
                        of grammatical rules: expressions and statements.
                </para>
+               <para>
+                       The <literal>add</literal> and <literal>insert</literal> commands support an optional
+                       location specifier, which is either a <replaceable>handle</replaceable> of an existing
+                       rule or an absolute <replaceable>index</replaceable> (starting at zero).  Internally,
+                       rule locations are always identified by <replaceable>handle</replaceable> and the
+                       translation from <replaceable>index</replaceable> happens in userspace. This has two
+                       potential implications in case a concurrent ruleset change happens after the translation
+                       was done: The effective rule index might change if a rule was inserted or deleted before
+                       the referred one.  If the referred rule was deleted, the command is rejected by the
+                       kernel just as if an invalid <replaceable>handle</replaceable> was given.
+               </para>
 
                <variablelist>
                        <varlistentry>
index b265690d3c964ed97f8efe860eaab34d752a735e..a3764bda74ce2dc8c5eb25ed09eddf94dcc25875 100644 (file)
@@ -69,6 +69,7 @@ struct handle {
        const char              *flowtable;
        struct handle_spec      handle;
        struct position_spec    position;
+       struct position_spec    index;
        uint32_t                set_id;
 };
 
index 46c97606ea8af9970acbc8bab31e1f346c6f8985..cb27f7c2690496605a6065d04ac7d969b862b1d1 100644 (file)
@@ -2851,6 +2851,47 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
        return 0;
 }
 
+/* Convert rule's handle.index into handle.position. */
+static int rule_translate_index(struct eval_ctx *ctx, struct rule *rule)
+{
+       struct table *table;
+       struct chain *chain;
+       uint64_t index = 0;
+       struct rule *r;
+       int ret;
+
+       /* update cache with CMD_LIST so that rules are fetched, too */
+       ret = cache_update(ctx->nf_sock, ctx->cache, CMD_LIST,
+                       ctx->msgs, ctx->debug_mask, ctx->octx);
+       if (ret < 0)
+               return ret;
+
+       table = table_lookup(&rule->handle, ctx->cache);
+       if (!table)
+               return cmd_error(ctx, &rule->handle.table.location,
+                               "Could not process rule: %s",
+                               strerror(ENOENT));
+
+       chain = chain_lookup(table, &rule->handle);
+       if (!chain)
+               return cmd_error(ctx, &rule->handle.chain.location,
+                               "Could not process rule: %s",
+                               strerror(ENOENT));
+
+       list_for_each_entry(r, &chain->rules, list) {
+               if (++index < rule->handle.index.id)
+                       continue;
+               rule->handle.position.id = r->handle.handle.id;
+               rule->handle.position.location = rule->handle.index.location;
+               break;
+       }
+       if (!rule->handle.position.id)
+               return cmd_error(ctx, &rule->handle.index.location,
+                               "Could not process rule: %s",
+                               strerror(EINVAL));
+       return 0;
+}
+
 static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule)
 {
        struct stmt *stmt, *tstmt = NULL;
@@ -2879,6 +2920,10 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule)
                return -1;
        }
 
+       if (rule->handle.index.id &&
+           rule_translate_index(ctx, rule))
+               return -1;
+
        return 0;
 }
 
index 174150aa3cd4190f2b2298825d77dd1882bb62c3..0e3ee84f3c400cbe80a966c947bae27c1d452fe3 100644 (file)
@@ -485,6 +485,7 @@ int nft_lex(void *, void *, void *);
 %token SEED                    "seed"
 
 %token POSITION                        "position"
+%token INDEX                   "index"
 %token COMMENT                 "comment"
 
 %token XML                     "xml"
@@ -512,8 +513,8 @@ int nft_lex(void *, void *, void *);
 %type <cmd>                    base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
 %destructor { cmd_free($$); }  base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
 
-%type <handle>                 table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%destructor { handle_free(&$$); } table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
+%type <handle>                 table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
+%destructor { handle_free(&$$); } table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
 %type <handle>                 set_spec setid_spec set_identifier flowtable_identifier obj_spec objid_spec obj_identifier
 %destructor { handle_free(&$$); } set_spec setid_spec set_identifier obj_spec objid_spec obj_identifier
 %type <val>                    family_spec family_spec_explicit chain_policy prio_spec
@@ -1961,6 +1962,14 @@ position_spec            :       POSITION        NUM
                        }
                        ;
 
+index_spec             :       INDEX           NUM
+                       {
+                               memset(&$$, 0, sizeof($$));
+                               $$.index.location       = @$;
+                               $$.index.id             = $2 + 1;
+                       }
+                       ;
+
 rule_position          :       chain_spec
                        {
                                $$ = $1;
@@ -1978,6 +1987,11 @@ rule_position            :       chain_spec
                                handle_merge(&$1, &$2);
                                $$ = $1;
                        }
+                       |       chain_spec      index_spec
+                       {
+                               handle_merge(&$1, &$2);
+                               $$ = $1;
+                       }
                        ;
 
 ruleid_spec            :       chain_spec      handle_spec
index a365876d07ea8c967e802e61f401a1f429c7a01f..279b741b133e4f80aab02cabea4f414bd129e8e5 100644 (file)
@@ -60,6 +60,8 @@ void handle_merge(struct handle *dst, const struct handle *src)
                dst->handle = src->handle;
        if (dst->position.id == 0)
                dst->position = src->position;
+       if (dst->index.id == 0)
+               dst->index = src->index;
 }
 
 static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
index bd641345f605cf1580b5c04952ece9dc8267b5c7..6a861cf255dcaffbed9794728c974a01ecb27790 100644 (file)
@@ -285,6 +285,7 @@ addrstring  ({macaddr}|{ip4addr}|{ip6addr})
 "monitor"              { return MONITOR; }
 
 "position"             { return POSITION; }
+"index"                        { return INDEX; }
 "comment"              { return COMMENT; }
 
 "constant"             { return CONSTANT; }