Make sure return codes match legacy ones at least for a few selected
commands typically used to check ruleset state.

Signed-off-by: Phil Sutter <p...@nwl.cc>
---
 iptables/nft.c                                | 15 ++++++++
 iptables/nft.h                                |  1 +
 .../testcases/ip6tables/0004-return-codes_0   | 38 +++++++++++++++++++
 .../testcases/iptables/0004-return-codes_0    | 38 +++++++++++++++++++
 iptables/xtables.c                            | 20 +++++++---
 5 files changed, 107 insertions(+), 5 deletions(-)
 create mode 100755 iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
 create mode 100755 iptables/tests/shell/testcases/iptables/0004-return-codes_0

diff --git a/iptables/nft.c b/iptables/nft.c
index b2165069c6d89..7123060b34ef5 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1725,6 +1725,21 @@ nft_chain_find(struct nft_handle *h, const char *table, 
const char *chain)
        return nft_chain_list_find(list, table, chain);
 }
 
+bool nft_chain_exists(struct nft_handle *h,
+                     const char *table, const char *chain)
+{
+       struct builtin_table *t = nft_table_builtin_find(h, table);
+
+       /* xtables does not support custom tables */
+       if (!t)
+               return false;
+
+       if (nft_chain_builtin_find(t, chain))
+               return true;
+
+       return !!nft_chain_find(h, table, chain);
+}
+
 int nft_chain_user_rename(struct nft_handle *h,const char *chain,
                          const char *table, const char *newname)
 {
diff --git a/iptables/nft.h b/iptables/nft.h
index eb14e908ab924..7419ec21a63a8 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -86,6 +86,7 @@ int nft_chain_user_flush(struct nft_handle *h, struct 
nftnl_chain_list *list,
 int nft_chain_user_rename(struct nft_handle *h, const char *chain, const char 
*table, const char *newname);
 int nft_chain_zero_counters(struct nft_handle *h, const char *chain, const 
char *table, bool verbose);
 struct builtin_chain *nft_chain_builtin_find(struct builtin_table *t, const 
char *chain);
+bool nft_chain_exists(struct nft_handle *h, const char *table, const char 
*chain);
 
 /*
  * Operations with rule-set.
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 
b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
new file mode 100755
index 0000000000000..f023b7915498e
--- /dev/null
+++ b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# make sure error return codes are as expected useful cases
+# (e.g. commands to check ruleset state)
+
+global_rc=0
+
+cmd() { # (rc, cmd, [args ...])
+       rc_exp=$1; shift
+
+       $XT_MULTI "$@"
+       rc=$?
+
+       [ $rc -eq $rc_exp ] || {
+               echo "---> expected $rc_exp, got $rc for command '$@'"
+               global_rc=1
+       }
+}
+
+# test chain creation
+cmd 0 ip6tables -N foo
+cmd 1 ip6tables -N foo
+# iptables-nft allows this - bug or feature?
+#cmd 2 ip6tables -N "invalid name"
+
+# test rule adding
+cmd 0 ip6tables -A INPUT -j ACCEPT
+cmd 1 ip6tables -A noexist -j ACCEPT
+
+# test rule checking
+cmd 0 ip6tables -C INPUT -j ACCEPT
+cmd 1 ip6tables -C FORWARD -j ACCEPT
+cmd 1 ip6tables -C nonexist -j ACCEPT
+cmd 2 ip6tables -C INPUT -j foobar
+cmd 2 ip6tables -C INPUT -m foobar -j ACCEPT
+cmd 3 ip6tables -t foobar -C INPUT -j ACCEPT
+
+exit $global_rc
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 
b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
new file mode 100755
index 0000000000000..34dffeee4604a
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# make sure error return codes are as expected useful cases
+# (e.g. commands to check ruleset state)
+
+global_rc=0
+
+cmd() { # (rc, cmd, [args ...])
+       rc_exp=$1; shift
+
+       $XT_MULTI "$@"
+       rc=$?
+
+       [ $rc -eq $rc_exp ] || {
+               echo "---> expected $rc_exp, got $rc for command '$@'"
+               global_rc=1
+       }
+}
+
+# test chain creation
+cmd 0 iptables -N foo
+cmd 1 iptables -N foo
+# iptables-nft allows this - bug or feature?
+#cmd 2 iptables -N "invalid name"
+
+# test rule adding
+cmd 0 iptables -A INPUT -j ACCEPT
+cmd 1 iptables -A noexist -j ACCEPT
+
+# test rule checking
+cmd 0 iptables -C INPUT -j ACCEPT
+cmd 1 iptables -C FORWARD -j ACCEPT
+cmd 1 iptables -C nonexist -j ACCEPT
+cmd 2 iptables -C INPUT -j foobar
+cmd 2 iptables -C INPUT -m foobar -j ACCEPT
+cmd 3 iptables -t foobar -C INPUT -j ACCEPT
+
+exit $global_rc
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 72f6596251da0..313b985bbaa85 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -976,6 +976,10 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
                        if (cs->invert)
                                xtables_error(PARAMETER_PROBLEM,
                                           "unexpected ! flag before --table");
+                       if (!nft_table_builtin_find(h, optarg))
+                               xtables_error(VERSION_PROBLEM,
+                                             "table '%s' does not exist",
+                                             optarg);
                        p->table = optarg;
                        break;
 
@@ -1156,12 +1160,18 @@ void do_parse(struct nft_handle *h, int argc, char 
*argv[],
                                           p->chain);
                }
 
-               /*
-                * Contrary to what iptables does, we assume that any jumpto
-                * is a custom chain jumps (if no target is found). Later on,
-                * nf_table will spot the error if the chain does not exists.
-                */
+               if (p->chain && !nft_chain_exists(h, p->table, p->chain))
+                       xtables_error(OTHER_PROBLEM,
+                                     "Chain '%s' does not exist", cs->jumpto);
+
+               if (!cs->target && strlen(cs->jumpto) > 0 &&
+                   !nft_chain_exists(h, p->table, cs->jumpto))
+                       xtables_error(PARAMETER_PROBLEM,
+                                     "Chain '%s' does not exist", cs->jumpto);
        }
+       if (p->command == CMD_NEW_CHAIN &&
+           nft_chain_exists(h, p->table, p->chain))
+               xtables_error(OTHER_PROBLEM, "Chain already exists");
 }
 
 int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
-- 
2.18.0

Reply via email to