]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables: add -I chain rulenum
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 19 Jul 2013 16:42:30 +0000 (18:42 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 30 Dec 2013 22:50:39 +0000 (23:50 +0100)
This patch adds the nft_rule_insert function, which allows
us to insert rules at a given position.

The function nft_rule_add has been renamed to nft_rule_append.

This is possible thanks to Eric Leblond's (netfilter: nf_tables:
add insert operation) kernel patch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
iptables/nft.c
iptables/nft.h
iptables/xtables.c

index d98b45386b4b0b59330b6065a9869ffaecfbf010..c22e6c5b81e8ffcc78cc9cee761440ef35d83c45 100644 (file)
@@ -689,30 +689,17 @@ void add_compat(struct nft_rule *r, uint32_t proto, bool inv)
                              inv ? NFT_RULE_COMPAT_F_INV : 0);
 }
 
-int
-nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
-            struct iptables_command_state *cs,
-            bool append, uint64_t handle, bool verbose)
+static struct nft_rule *
+nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
+            struct iptables_command_state *cs)
 {
-       char buf[MNL_SOCKET_BUFFER_SIZE];
-       struct nlmsghdr *nlh;
-       struct xtables_rule_match *matchp;
        struct nft_rule *r;
-       int ret = 1;
-       int flags = append ? NLM_F_APPEND : 0;
-       int ip_flags = 0;
-
-       /* If built-in chains don't exist for this table, create them */
-       if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
-               nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
-
-       nft_fn = nft_rule_add;
+       int ret = 0, ip_flags = 0;
+       struct xtables_rule_match *matchp;
 
        r = nft_rule_alloc();
-       if (r == NULL) {
-               ret = 0;
-               goto err;
-       }
+       if (r == NULL)
+               return NULL;
 
        nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FAMILY, h->family);
        nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, (char *)table);
@@ -721,19 +708,15 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
        ip_flags = h->ops->add(r, cs);
 
        for (matchp = cs->matches; matchp; matchp = matchp->next) {
-               if (add_match(r, matchp->match->m) < 0) {
-                       ret = 0;
+               if (add_match(r, matchp->match->m) < 0)
                        goto err;
-               }
        }
 
        /* Counters need to me added before the target, otherwise they are
         * increased for each rule because of the way nf_tables works.
         */
-       if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0) {
-               ret = 0;
+       if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
                goto err;
-       }
 
        /* If no target at all, add nothing (default to continue) */
        if (cs->target != NULL) {
@@ -754,25 +737,50 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
                        ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
        }
 
-       if (ret < 0) {
+       if (ret < 0)
+               goto err;
+
+       return r;
+err:
+       nft_rule_free(r);
+       return NULL;
+}
+
+int
+nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
+               struct iptables_command_state *cs, uint64_t handle,
+               bool verbose)
+{
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       struct nft_rule *r;
+       uint16_t flags = NLM_F_ACK|NLM_F_CREATE;
+       int ret = 1;
+
+       /* If built-in chains don't exist for this table, create them */
+       if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
+               nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
+
+       nft_fn = nft_rule_append;
+
+       r = nft_rule_new(h, chain, table, cs);
+       if (r == NULL) {
                ret = 0;
                goto err;
        }
 
-       /* NLM_F_CREATE autoloads the built-in table if it does not exists */
-       flags |= NLM_F_ACK|NLM_F_CREATE;
-
        if (handle > 0) {
                nft_rule_attr_set(r, NFT_RULE_ATTR_HANDLE, &handle);
                flags |= NLM_F_REPLACE;
-       }
+       } else
+               flags |= NLM_F_APPEND;
 
        if (h->commit) {
                nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
                                      NFT_RULE_F_COMMIT);
        }
-       nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE,
-                                      h->family, flags, h->seq);
+       nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, h->family,
+                                      flags, h->seq);
 
        nft_rule_nlmsg_build_payload(nlh, r);
 
@@ -782,7 +790,7 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
 
        ret = mnl_talk(h, nlh, NULL, NULL);
        if (ret < 0)
-               perror("mnl_talk:nft_rule_add");
+               perror("mnl_talk:nft_rule_append");
 
 err:
        /* the core expects 1 for success and 0 for error */
@@ -2139,6 +2147,82 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
        return ret;
 }
 
+static int
+nft_rule_add(struct nft_handle *h, const char *chain,
+            const char *table, struct iptables_command_state *cs,
+            uint64_t handle, bool verbose)
+{
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       struct nlmsghdr *nlh;
+       struct nft_rule *r;
+       int ret = 1;
+
+       r = nft_rule_new(h, chain, table, cs);
+       if (r == NULL) {
+               ret = 0;
+               goto err;
+       }
+       nft_rule_attr_set_u64(r, NFT_RULE_ATTR_POSITION, handle);
+
+       if (h->commit) {
+               nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                     NFT_RULE_F_COMMIT);
+       }
+       nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, h->family,
+                                      NLM_F_ACK|NLM_F_CREATE, h->seq);
+       nft_rule_nlmsg_build_payload(nlh, r);
+       nft_rule_print_debug(r, nlh);
+       nft_rule_free(r);
+
+       ret = mnl_talk(h, nlh, NULL, NULL);
+       if (ret < 0)
+               perror("mnl_talk:nft_rule_add_num");
+
+err:
+       /* the core expects 1 for success and 0 for error */
+       return ret == 0 ? 1 : 0;
+}
+
+int nft_rule_insert(struct nft_handle *h, const char *chain,
+                   const char *table, struct iptables_command_state *cs,
+                   int rulenum, bool verbose)
+{
+       struct nft_rule_list *list;
+       struct nft_rule *r;
+       uint64_t handle;
+
+       /* If built-in chains don't exist for this table, create them */
+       if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
+               nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
+
+       nft_fn = nft_rule_insert;
+
+       list = nft_rule_list_create(h);
+       if (list == NULL)
+               goto err;
+
+       r = nft_rule_find(list, chain, table, cs, rulenum);
+       if (r == NULL) {
+               errno = ENOENT;
+               goto err;
+       }
+
+       handle = nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE);
+       DEBUGP("adding after rule handle %"PRIu64"\n", handle);
+
+       if (h->commit) {
+               nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
+                                     NFT_RULE_F_COMMIT);
+       }
+
+       nft_rule_list_destroy(list);
+
+       return nft_rule_add(h, chain, table, cs, handle, verbose);
+err:
+       nft_rule_list_destroy(list);
+       return 0;
+}
+
 int nft_rule_delete_num(struct nft_handle *h, const char *chain,
                        const char *table, int rulenum, bool verbose)
 {
@@ -2194,9 +2278,9 @@ int nft_rule_replace(struct nft_handle *h, const char *chain,
                        nft_rule_attr_set_u32(r, NFT_RULE_ATTR_FLAGS,
                                                 NFT_RULE_F_COMMIT);
                }
-               ret = nft_rule_add(h, chain, table, cs, true,
-                                  nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE),
-                                  verbose);
+               ret = nft_rule_append(h, chain, table, cs,
+                                     nft_rule_attr_get_u64(r, NFT_RULE_ATTR_HANDLE),
+                                     verbose);
        } else
                errno = ENOENT;
 
index a64767142fbbda54f5dd57068b9e378d61b40697..7a6351b7a1626a5895bff0ab39324b1fd7977168 100644 (file)
@@ -49,7 +49,8 @@ int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const char
  */
 struct nft_rule;
 
-int nft_rule_add(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, bool append, uint64_t handle, bool verbose);
+int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, uint64_t handle, bool verbose);
+int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, int rulenum, bool verbose);
 int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, bool verbose);
 int nft_rule_delete(struct nft_handle *h, const char *chain, const char *table, struct iptables_command_state *cmd, bool verbose);
 int nft_rule_delete_num(struct nft_handle *h, const char *chain, const char *table, int rulenum, bool verbose);
index a5a83c24bf6aa3134938bf116534975e907fa3bc..41a7f7165bda52d72baa7ac106f04c8bbbccb659 100644 (file)
@@ -404,7 +404,7 @@ static int
 add_entry(const char *chain,
          const char *table,
          struct iptables_command_state *cs,
-         int family,
+         int rulenum, int family,
          const struct addr_mask s,
          const struct addr_mask d,
          bool verbose, struct nft_handle *h, bool append)
@@ -420,8 +420,15 @@ add_entry(const char *chain,
                                cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
                                cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
 
-                               ret = nft_rule_add(h, chain, table,
-                                                  cs, append, 0, verbose);
+                               if (append) {
+                                       ret = nft_rule_append(h, chain, table,
+                                                             cs, 0,
+                                                             verbose);
+                               } else {
+                                       ret = nft_rule_insert(h, chain, table,
+                                                             cs, rulenum,
+                                                             verbose);
+                               }
                        }
                } else if (family == AF_INET6) {
                        memcpy(&cs->fw6.ipv6.src,
@@ -433,8 +440,15 @@ add_entry(const char *chain,
                                       &d.addr.v6[j], sizeof(struct in6_addr));
                                memcpy(&cs->fw6.ipv6.dmsk,
                                       &d.mask.v6[j], sizeof(struct in6_addr));
-                               ret = nft_rule_add(h, chain, table,
-                                                  cs, append, 0, verbose);
+                               if (append) {
+                                       ret = nft_rule_append(h, chain, table,
+                                                             cs, append,
+                                                             verbose);
+                               } else {
+                                       ret = nft_rule_insert(h, chain, table,
+                                                             cs, rulenum,
+                                                             verbose);
+                               }
                        }
                }
        }
@@ -1148,7 +1162,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
 
        switch (command) {
        case CMD_APPEND:
-               ret = add_entry(chain, *table, &cs, h->family,
+               ret = add_entry(chain, *table, &cs, 0, h->family,
                                args.s, args.d, cs.options&OPT_VERBOSE,
                                h, true);
                break;
@@ -1170,8 +1184,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
                                    cs.options&OPT_VERBOSE, h);
                break;
        case CMD_INSERT:
-               /* FIXME insert at rulenum */
-               ret = add_entry(chain, *table, &cs, h->family,
+               ret = add_entry(chain, *table, &cs, rulenum - 1, h->family,
                                args.s, args.d, cs.options&OPT_VERBOSE, h,
                                false);
                break;