]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
xtables-compat: check if nft ruleset is compatible
authorPablo M. Bermudo Garay <pablombg@gmail.com>
Fri, 26 Aug 2016 16:58:43 +0000 (18:58 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 26 Aug 2016 17:35:33 +0000 (19:35 +0200)
This patch adds a verification of the compatibility between the nft
ruleset and iptables. Nft tables, chains and rules are checked to be
compatible with iptables. If something is not compatible, the execution
stops and an error message is displayed to the user.

This checking is triggered by xtables-compat -L and xtables-compat-save
commands.

Signed-off-by: Pablo M. Bermudo Garay <pablombg@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
iptables/nft.c
iptables/nft.h
iptables/xtables-save.c
iptables/xtables.c

index 247a60aa1dd87967983b7e91a3b18814ff262e04..f1f0d9d6767b3a6fdcf3f2b82c086743b8d09543 100644 (file)
@@ -2698,3 +2698,197 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag)
 
        return NFT_CMP_EQ;
 }
+
+#define NFT_COMPAT_EXPR_MAX     8
+
+static const char *supported_exprs[NFT_COMPAT_EXPR_MAX] = {
+       "match",
+       "target",
+       "payload",
+       "meta",
+       "cmp",
+       "bitwise",
+       "counter",
+       "immediate"
+};
+
+
+static int nft_is_expr_compatible(const char *name)
+{
+       int i;
+
+       for (i = 0; i < NFT_COMPAT_EXPR_MAX; i++) {
+               if (strcmp(supported_exprs[i], name) == 0)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int nft_is_rule_compatible(struct nftnl_rule *rule)
+{
+       struct nftnl_expr_iter *iter;
+       struct nftnl_expr *expr;
+       int ret = 0;
+
+       iter = nftnl_expr_iter_create(rule);
+       if (iter == NULL)
+               return -1;
+
+       expr = nftnl_expr_iter_next(iter);
+       while (expr != NULL) {
+               const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
+
+               if (nft_is_expr_compatible(name) == 0) {
+                       expr = nftnl_expr_iter_next(iter);
+                       continue;
+               }
+
+               ret = 1;
+               break;
+       }
+
+       nftnl_expr_iter_destroy(iter);
+       return ret;
+}
+
+static int nft_is_chain_compatible(const char *table, const char *chain)
+{
+       const char *cur_table;
+       struct builtin_chain *chains;
+       int i, j;
+
+       for (i = 0; i < TABLES_MAX; i++) {
+               cur_table = xtables_ipv4[i].name;
+               chains = xtables_ipv4[i].chains;
+
+               if (strcmp(table, cur_table) != 0)
+                       continue;
+
+               for (j = 0; j < NF_INET_NUMHOOKS && chains[j].name; j++) {
+                       if (strcmp(chain, chains[j].name) == 0)
+                               return 0;
+               }
+       }
+
+       return 1;
+}
+
+static int nft_are_chains_compatible(struct nft_handle *h)
+{
+       struct nftnl_chain_list *list;
+       struct nftnl_chain_list_iter *iter;
+       struct nftnl_chain *chain;
+       int ret = 0;
+
+       list = nftnl_chain_list_get(h);
+       if (list == NULL)
+               return -1;
+
+       iter = nftnl_chain_list_iter_create(list);
+       if (iter == NULL)
+               return -1;
+
+       chain = nftnl_chain_list_iter_next(iter);
+       while (chain != NULL) {
+               if (!nft_chain_builtin(chain))
+                       goto next;
+
+               const char *table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE);
+               const char *name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME);
+
+               if (nft_is_chain_compatible(table, name) == 1) {
+                       ret = 1;
+                       break;
+               }
+
+next:
+               chain = nftnl_chain_list_iter_next(iter);
+       }
+
+       nftnl_chain_list_iter_destroy(iter);
+       nftnl_chain_list_free(list);
+       return ret;
+}
+
+static int nft_is_table_compatible(const char *name)
+{
+       int i;
+
+       for (i = 0; i < TABLES_MAX; i++) {
+               if (strcmp(xtables_ipv4[i].name, name) == 0)
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int nft_are_tables_compatible(struct nft_handle *h)
+{
+       struct nftnl_table_list *list;
+       struct nftnl_table_list_iter *iter;
+       struct nftnl_table *table;
+       int ret = 0;
+
+       list = nftnl_table_list_get(h);
+       if (list == NULL)
+               return -1;
+
+       iter = nftnl_table_list_iter_create(list);
+       if (iter == NULL)
+               return -1;
+
+       table = nftnl_table_list_iter_next(iter);
+       while (table != NULL) {
+               const char *name = nftnl_table_get(table, NFTNL_TABLE_NAME);
+
+               if (nft_is_table_compatible(name) == 0) {
+                       table = nftnl_table_list_iter_next(iter);
+                       continue;
+               }
+
+               ret = 1;
+               break;
+       }
+
+       nftnl_table_list_iter_destroy(iter);
+       nftnl_table_list_free(list);
+       return ret;
+}
+
+int nft_is_ruleset_compatible(struct nft_handle *h)
+{
+
+       struct nftnl_rule_list *list;
+       struct nftnl_rule_list_iter *iter;
+       struct nftnl_rule *rule;
+       int ret = 0;
+
+       ret = nft_are_tables_compatible(h);
+       if (ret != 0)
+               return ret;
+
+       ret = nft_are_chains_compatible(h);
+       if (ret != 0)
+               return ret;
+
+       list = nft_rule_list_get(h);
+       if (list == NULL)
+               return -1;
+
+       iter = nftnl_rule_list_iter_create(list);
+       if (iter == NULL)
+               return -1;
+
+       rule = nftnl_rule_list_iter_next(iter);
+       while (rule != NULL) {
+               ret = nft_is_rule_compatible(rule);
+               if (ret != 0)
+                       break;
+
+               rule = nftnl_rule_list_iter_next(iter);
+       }
+
+       nftnl_rule_list_iter_destroy(iter);
+       return ret;
+}
index bcabf42bf2f85b95cadbd32edd0efb0a1d32fb12..f5449db46a8d44c59eabb77a0741b2332d02a0b7 100644 (file)
@@ -181,4 +181,6 @@ int nft_arp_rule_insert(struct nft_handle *h, const char *chain,
 
 void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw);
 
+int nft_is_ruleset_compatible(struct nft_handle *h);
+
 #endif
index 50b5b5ae064c5c72891b5fad44e1a45dc134a096..f30867cf62bbb6b3f0037adab8547ef3d26551fc 100644 (file)
@@ -138,6 +138,11 @@ xtables_save_main(int family, const char *progname, int argc, char *argv[])
                exit(1);
        }
 
+       if (nft_is_ruleset_compatible(&h) == 1) {
+               printf("ERROR: You're using nft features that cannot be mapped to iptables, please keep using nft.\n");
+               exit(EXIT_FAILURE);
+       }
+
        if (dump) {
                do_output(&h, tablename, show_counters);
                exit(0);
index 48b9c51cabf3168d715614542d562e2ba3be3875..d222ae991dc8536f57d81fc6df4bb41ead84a787 100644 (file)
@@ -1253,6 +1253,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
        case CMD_LIST:
        case CMD_LIST|CMD_ZERO:
        case CMD_LIST|CMD_ZERO_NUM:
+               if (nft_is_ruleset_compatible(h) == 1) {
+                       printf("ERROR: You're using nft features that cannot be mapped to iptables, please keep using nft.\n");
+                       exit(EXIT_FAILURE);
+               }
+
                ret = list_entries(h, p.chain, p.table, p.rulenum,
                                   cs.options & OPT_VERBOSE,
                                   cs.options & OPT_NUMERIC,