From b6a06c1a215f867f7eee4a3f2f40ec14028fe186 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 31 Aug 2018 12:29:57 +0200 Subject: xtables: Align return codes with legacy iptables 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 Signed-off-by: Florian Westphal --- iptables/nft.c | 15 +++++++++ iptables/nft.h | 1 + .../shell/testcases/ip6tables/0004-return-codes_0 | 38 ++++++++++++++++++++++ .../shell/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 b2165069..7123060b 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 eb14e908..7419ec21 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 00000000..f023b791 --- /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 00000000..34dffeee --- /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 72f65962..313b985b 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, -- cgit v1.2.3