summaryrefslogtreecommitdiffstats
path: root/iptables
diff options
context:
space:
mode:
Diffstat (limited to 'iptables')
-rw-r--r--iptables/Makefile.am4
-rw-r--r--iptables/nft-cache.c77
-rw-r--r--iptables/nft-cache.h9
-rw-r--r--iptables/nft.c280
-rw-r--r--iptables/nft.h3
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-return-codes_039
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_0113
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_023
-rw-r--r--iptables/xtables-monitor.c2
-rw-r--r--iptables/xtables-standalone.c12
10 files changed, 229 insertions, 333 deletions
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index bab094b7..4bf5742c 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -67,6 +67,10 @@ man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
ebtables-nft.8
endif
CLEANFILES = iptables.8 xtables-monitor.8 \
+ iptables-xml.1 iptables-apply.8 \
+ iptables-extensions.8 iptables-extensions.8.tmpl \
+ iptables-restore.8 iptables-save.8 \
+ iptables-restore-translate.8 ip6tables-restore-translate.8 \
iptables-translate.8 ip6tables-translate.8
vx_bin_links = iptables-xml
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index bf1fb346..32cfd6cf 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -107,59 +107,30 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid)
"Could not fetch rule set generation id: %s\n", nft_strerror(errno));
}
-static struct nft_table *nft_table_alloc(void)
-{
- struct nftnl_table *nftnl;
- struct nft_table *table;
-
- table = malloc(sizeof(struct nft_table));
- if (!table)
- return NULL;
-
- nftnl = nftnl_table_alloc();
- if (!nftnl) {
- free(table);
- return NULL;
- }
- table->nftnl = nftnl;
-
- return table;
-}
-
-static void nft_table_free(struct nft_table *table)
+static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
{
- nftnl_table_free(table->nftnl);
- free(table);
-}
+ struct nftnl_table *nftnl = nftnl_table_alloc();
+ const struct builtin_table *t;
+ struct nft_handle *h = data;
+ const char *name;
-static void nft_table_list_free(struct list_head *table_list)
-{
- struct nft_table *table, *next;
+ if (!nftnl)
+ return MNL_CB_OK;
- list_for_each_entry_safe(table, next, table_list, list) {
- list_del(&table->list);
- nft_table_free(table);
- }
-}
+ if (nftnl_table_nlmsg_parse(nlh, nftnl) < 0)
+ goto out;
-static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data)
-{
- struct list_head *list = data;
- struct nft_table *t;
+ name = nftnl_table_get_str(nftnl, NFTNL_TABLE_NAME);
+ if (!name)
+ goto out;
- t = nft_table_alloc();
+ t = nft_table_builtin_find(h, name);
if (!t)
- goto err;
-
- if (nftnl_table_nlmsg_parse(nlh, t->nftnl) < 0)
goto out;
- list_add_tail(&t->list, list);
-
- return MNL_CB_OK;
+ h->cache->table[t->type].exists = true;
out:
- nft_table_free(t);
-err:
+ nftnl_table_free(nftnl);
return MNL_CB_OK;
}
@@ -169,13 +140,10 @@ static int fetch_table_cache(struct nft_handle *h)
char buf[16536];
int i, ret;
- if (!list_empty(&h->cache->tables))
- return 0;
-
nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
NLM_F_DUMP, h->seq);
- ret = mnl_talk(h, nlh, nftnl_table_list_cb, &h->cache->tables);
+ ret = mnl_talk(h, nlh, nftnl_table_list_cb, h);
if (ret < 0 && errno == EINTR)
assert(nft_restart(h) >= 0);
@@ -534,14 +502,14 @@ retry:
if (req->level >= NFT_CL_TABLES)
fetch_table_cache(h);
if (req->level == NFT_CL_FAKE)
- return;
+ goto genid_check;
if (req->level >= NFT_CL_CHAINS)
fetch_chain_cache(h, t, chains);
if (req->level >= NFT_CL_SETS)
fetch_set_cache(h, t, NULL);
if (req->level >= NFT_CL_RULES)
fetch_rule_cache(h, t);
-
+genid_check:
mnl_genid_get(h, &genid_check);
if (h->nft_genid != genid_check) {
flush_cache(h, h->cache, NULL);
@@ -635,9 +603,9 @@ static int flush_cache(struct nft_handle *h, struct nft_cache *c,
nftnl_set_list_free(c->table[i].sets);
c->table[i].sets = NULL;
}
+
+ c->table[i].exists = false;
}
- if (!list_empty(&c->tables))
- nft_table_list_free(&c->tables);
return 1;
}
@@ -710,11 +678,6 @@ void nft_release_cache(struct nft_handle *h)
}
}
-struct list_head *nft_table_list_get(struct nft_handle *h)
-{
- return &h->cache->tables;
-}
-
struct nftnl_set_list *
nft_set_list_get(struct nft_handle *h, const char *table, const char *set)
{
diff --git a/iptables/nft-cache.h b/iptables/nft-cache.h
index aeab4bde..76f9fbb6 100644
--- a/iptables/nft-cache.h
+++ b/iptables/nft-cache.h
@@ -1,8 +1,6 @@
#ifndef _NFT_CACHE_H_
#define _NFT_CACHE_H_
-#include <libiptc/linux_list.h>
-
struct nft_handle;
struct nft_cmd;
@@ -19,12 +17,5 @@ struct nftnl_chain_list *
nft_chain_list_get(struct nft_handle *h, const char *table, const char *chain);
struct nftnl_set_list *
nft_set_list_get(struct nft_handle *h, const char *table, const char *set);
-struct list_head *nft_table_list_get(struct nft_handle *h);
-
-struct nft_table {
- struct list_head list;
- struct nftnl_table *nftnl;
-};
-
#endif /* _NFT_CACHE_H_ */
diff --git a/iptables/nft.c b/iptables/nft.c
index 634d02fe..27bb98d1 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -644,19 +644,13 @@ const struct builtin_table xtables_bridge[NFT_TABLE_MAX] = {
},
};
-static bool nft_table_initialized(const struct nft_handle *h,
- enum nft_table_type type)
-{
- return h->cache->table[type].initialized;
-}
-
static int nft_table_builtin_add(struct nft_handle *h,
const struct builtin_table *_t)
{
struct nftnl_table *t;
int ret;
- if (nft_table_initialized(h, _t->type))
+ if (h->cache->table[_t->type].exists)
return 0;
t = nftnl_table_alloc();
@@ -742,22 +736,17 @@ nft_chain_builtin_find(const struct builtin_table *t, const char *chain)
return found ? &t->chains[i] : NULL;
}
+static struct nftnl_chain *
+nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
+
static void nft_chain_builtin_init(struct nft_handle *h,
const struct builtin_table *table)
{
- struct nftnl_chain_list *list;
- struct nftnl_chain *c;
int i;
/* Initialize built-in chains if they don't exist yet */
for (i=0; i < NF_INET_NUMHOOKS && table->chains[i].name != NULL; i++) {
- list = nft_chain_list_get(h, table->name,
- table->chains[i].name);
- if (!list)
- continue;
-
- c = nftnl_chain_list_lookup_byname(list, table->chains[i].name);
- if (c != NULL)
+ if (nft_chain_find(h, table->name, table->chains[i].name))
continue;
nft_chain_builtin_add(h, table, &table->chains[i]);
@@ -775,9 +764,6 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
if (t == NULL)
return -1;
- if (nft_table_initialized(h, t->type))
- return 0;
-
if (nft_table_builtin_add(h, t) < 0)
return -1;
@@ -786,8 +772,6 @@ static int nft_xt_builtin_init(struct nft_handle *h, const char *table)
nft_chain_builtin_init(h, t);
- h->cache->table[t->type].initialized = true;
-
return 0;
}
@@ -842,8 +826,6 @@ int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
INIT_LIST_HEAD(&h->obj_list);
INIT_LIST_HEAD(&h->err_list);
INIT_LIST_HEAD(&h->cmd_list);
- INIT_LIST_HEAD(&h->__cache[0].tables);
- INIT_LIST_HEAD(&h->__cache[1].tables);
INIT_LIST_HEAD(&h->cache_req.chain_list);
return 0;
@@ -1401,9 +1383,6 @@ err:
return NULL;
}
-static struct nftnl_chain *
-nft_chain_find(struct nft_handle *h, const char *table, const char *chain);
-
int
nft_rule_append(struct nft_handle *h, const char *chain, const char *table,
struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose)
@@ -1579,9 +1558,14 @@ int nft_chain_save(struct nftnl_chain *c, void *data)
return 0;
}
-static int nft_chain_save_rules(struct nft_handle *h,
- struct nftnl_chain *c, unsigned int format)
+struct nft_rule_save_data {
+ struct nft_handle *h;
+ unsigned int format;
+};
+
+static int nft_rule_save_cb(struct nftnl_chain *c, void *data)
{
+ struct nft_rule_save_data *d = data;
struct nftnl_rule_iter *iter;
struct nftnl_rule *r;
@@ -1591,7 +1575,7 @@ static int nft_chain_save_rules(struct nft_handle *h,
r = nftnl_rule_iter_next(iter);
while (r != NULL) {
- nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
+ nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format);
r = nftnl_rule_iter_next(iter);
}
@@ -1601,29 +1585,18 @@ static int nft_chain_save_rules(struct nft_handle *h,
int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format)
{
- struct nftnl_chain_list_iter *iter;
+ struct nft_rule_save_data d = {
+ .h = h,
+ .format = format,
+ };
struct nftnl_chain_list *list;
- struct nftnl_chain *c;
- int ret = 0;
+ int ret;
list = nft_chain_list_get(h, table, NULL);
if (!list)
return 0;
- iter = nftnl_chain_list_iter_create(list);
- if (!iter)
- return 0;
-
- c = nftnl_chain_list_iter_next(iter);
- while (c) {
- ret = nft_chain_save_rules(h, c, format);
- if (ret != 0)
- break;
-
- c = nftnl_chain_list_iter_next(iter);
- }
-
- nftnl_chain_list_iter_destroy(iter);
+ ret = nftnl_chain_list_foreach(list, nft_rule_save_cb, &d);
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1670,10 +1643,31 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
obj->implicit = implicit;
}
+struct nft_rule_flush_data {
+ struct nft_handle *h;
+ const char *table;
+ bool verbose;
+};
+
+static int nft_rule_flush_cb(struct nftnl_chain *c, void *data)
+{
+ const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
+ struct nft_rule_flush_data *d = data;
+
+ batch_chain_flush(d->h, d->table, chain);
+ __nft_rule_flush(d->h, d->table, chain, d->verbose, false);
+ flush_rule_cache(d->h, d->table, c);
+ return 0;
+}
+
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
bool verbose)
{
- struct nftnl_chain_list_iter *iter;
+ struct nft_rule_flush_data d = {
+ .h = h,
+ .table = table,
+ .verbose = verbose,
+ };
struct nftnl_chain_list *list;
struct nftnl_chain *c = NULL;
int ret = 0;
@@ -1706,22 +1700,7 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
goto err;
}
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL) {
- ret = 1;
- goto err;
- }
-
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
-
- batch_chain_flush(h, table, chain);
- __nft_rule_flush(h, table, chain, verbose, false);
- flush_rule_cache(h, table, c);
- c = nftnl_chain_list_iter_next(iter);
- }
- nftnl_chain_list_iter_destroy(iter);
+ ret = nftnl_chain_list_foreach(list, nft_rule_flush_cb, &d);
err:
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -1943,39 +1922,26 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
bool nft_table_find(struct nft_handle *h, const char *tablename)
{
- struct list_head *list;
- struct nft_table *t;
- bool ret = false;
-
- list = nft_table_list_get(h);
-
- list_for_each_entry(t, list, list) {
- const char *this_tablename =
- nftnl_table_get(t->nftnl, NFTNL_TABLE_NAME);
-
- if (strcmp(tablename, this_tablename) == 0) {
- ret = true;
- break;
- }
- }
+ const struct builtin_table *t;
- return ret;
+ t = nft_table_builtin_find(h, tablename);
+ return t ? h->cache->table[t->type].exists : false;
}
int nft_for_each_table(struct nft_handle *h,
int (*func)(struct nft_handle *h, const char *tablename, void *data),
void *data)
{
- struct list_head *list;
- struct nft_table *t;
+ int i;
- list = nft_table_list_get(h);
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
+ if (h->tables[i].name == NULL)
+ continue;
- list_for_each_entry(t, list, list) {
- const char *tablename =
- nftnl_table_get(t->nftnl, NFTNL_TABLE_NAME);
+ if (!h->cache->table[h->tables[i].type].exists)
+ continue;
- func(h, tablename, data);
+ func(h, h->tables[i].name, data);
}
return 0;
@@ -2004,7 +1970,7 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
_t = nft_table_builtin_find(h, table);
assert(_t);
- h->cache->table[_t->type].initialized = false;
+ h->cache->table[_t->type].exists = false;
flush_chain_cache(h, table);
@@ -2013,26 +1979,16 @@ static int __nft_table_flush(struct nft_handle *h, const char *table, bool exist
int nft_table_flush(struct nft_handle *h, const char *table)
{
- struct list_head *list;
- struct nft_table *t;
- bool exists = false;
+ const struct builtin_table *t;
int ret = 0;
nft_fn = nft_table_flush;
- list = nft_table_list_get(h);
-
- list_for_each_entry(t, list, list) {
- const char *table_name =
- nftnl_table_get_str(t->nftnl, NFTNL_TABLE_NAME);
-
- if (strcmp(table_name, table) == 0) {
- exists = true;
- break;
- }
- }
+ t = nft_table_builtin_find(h, table);
+ if (!t)
+ return 0;
- ret = __nft_table_flush(h, table, exists);
+ ret = __nft_table_flush(h, table, h->cache->table[t->type].exists);
/* the core expects 1 for success and 0 for error */
return ret == 0 ? 1 : 0;
@@ -2386,14 +2342,43 @@ static void __nft_print_header(struct nft_handle *h,
&ctrs, basechain, refs - entries, entries);
}
+struct nft_rule_list_cb_data {
+ struct nft_handle *h;
+ unsigned int format;
+ int rulenum;
+ bool found;
+ bool save_fmt;
+ void (*cb)(struct nft_handle *h, struct nftnl_rule *r,
+ unsigned int num, unsigned int format);
+};
+
+static int nft_rule_list_cb(struct nftnl_chain *c, void *data)
+{
+ struct nft_rule_list_cb_data *d = data;
+
+ if (!d->save_fmt) {
+ if (d->found)
+ printf("\n");
+ d->found = true;
+
+ __nft_print_header(d->h, c, d->format);
+ }
+
+ return __nft_rule_list(d->h, c, d->rulenum, d->format, d->cb);
+}
+
int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
int rulenum, unsigned int format)
{
const struct nft_family_ops *ops = h->ops;
+ struct nft_rule_list_cb_data d = {
+ .h = h,
+ .format = format,
+ .rulenum = rulenum,
+ .cb = ops->print_rule,
+ };
struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
struct nftnl_chain *c;
- bool found = false;
nft_xt_builtin_init(h, table);
nft_assert_table_compatible(h, table, chain);
@@ -2403,12 +2388,12 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (!c)
return 0;
- if (!rulenum) {
- if (ops->print_table_header)
- ops->print_table_header(table);
- __nft_print_header(h, c, format);
- }
- __nft_rule_list(h, c, rulenum, format, ops->print_rule);
+ if (rulenum)
+ d.save_fmt = true; /* skip header printing */
+ else if (ops->print_table_header)
+ ops->print_table_header(table);
+
+ nft_rule_list_cb(c, &d);
return 1;
}
@@ -2416,25 +2401,10 @@ int nft_rule_list(struct nft_handle *h, const char *chain, const char *table,
if (!list)
return 0;
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- return 0;
-
if (ops->print_table_header)
ops->print_table_header(table);
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- if (found)
- printf("\n");
-
- __nft_print_header(h, c, format);
- __nft_rule_list(h, c, rulenum, format, ops->print_rule);
-
- found = true;
- c = nftnl_chain_list_iter_next(iter);
- }
- nftnl_chain_list_iter_destroy(iter);
+ nftnl_chain_list_foreach(list, nft_rule_list_cb, &d);
return 1;
}
@@ -2445,7 +2415,7 @@ list_save(struct nft_handle *h, struct nftnl_rule *r,
nft_rule_print_save(h, r, NFT_RULE_APPEND, format);
}
-static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
+static int nft_rule_list_chain_save(struct nftnl_chain *c, void *data)
{
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
@@ -2467,31 +2437,16 @@ static int __nftnl_rule_list_chain_save(struct nftnl_chain *c, void *data)
return 0;
}
-static int
-nftnl_rule_list_chain_save(struct nft_handle *h, const char *chain,
- struct nftnl_chain_list *list, int counters)
-{
- struct nftnl_chain *c;
-
- if (chain) {
- c = nftnl_chain_list_lookup_byname(list, chain);
- if (!c)
- return 0;
-
- __nftnl_rule_list_chain_save(c, &counters);
- return 1;
- }
-
- nftnl_chain_list_foreach(list, __nftnl_rule_list_chain_save, &counters);
- return 1;
-}
-
int nft_rule_list_save(struct nft_handle *h, const char *chain,
const char *table, int rulenum, int counters)
{
+ struct nft_rule_list_cb_data d = {
+ .h = h,
+ .rulenum = rulenum,
+ .save_fmt = true,
+ .cb = list_save,
+ };
struct nftnl_chain_list *list;
- struct nftnl_chain_list_iter *iter;
- unsigned int format = 0;
struct nftnl_chain *c;
int ret = 0;
@@ -2502,35 +2457,28 @@ int nft_rule_list_save(struct nft_handle *h, const char *chain,
if (!list)
return 0;
- /* Dump policies and custom chains first */
- if (!rulenum)
- nftnl_rule_list_chain_save(h, chain, list, counters);
-
if (counters < 0)
- format = FMT_C_COUNTS;
+ d.format = FMT_C_COUNTS;
else if (counters == 0)
- format = FMT_NOCOUNTS;
+ d.format = FMT_NOCOUNTS;
if (chain) {
c = nftnl_chain_list_lookup_byname(list, chain);
if (!c)
return 0;
- return __nft_rule_list(h, c, rulenum, format, list_save);
+ if (!rulenum)
+ nft_rule_list_chain_save(c, &counters);
+
+ return nft_rule_list_cb(c, &d);
}
- /* Now dump out rules in this table */
- iter = nftnl_chain_list_iter_create(list);
- if (iter == NULL)
- return 0;
+ /* Dump policies and custom chains first */
+ nftnl_chain_list_foreach(list, nft_rule_list_chain_save, &counters);
- c = nftnl_chain_list_iter_next(iter);
- while (c != NULL) {
- ret = __nft_rule_list(h, c, rulenum, format, list_save);
- c = nftnl_chain_list_iter_next(iter);
- }
- nftnl_chain_list_iter_destroy(iter);
- return ret;
+ /* Now dump out rules in this table */
+ ret = nftnl_chain_list_foreach(list, nft_rule_list_cb, &d);
+ return ret == 0 ? 1 : 0;
}
int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
diff --git a/iptables/nft.h b/iptables/nft.h
index b2175958..128e09be 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -38,11 +38,10 @@ enum nft_cache_level {
};
struct nft_cache {
- struct list_head tables;
struct {
struct nftnl_chain_list *chains;
struct nftnl_set_list *sets;
- bool initialized;
+ bool exists;
} table[NFT_TABLE_MAX];
};
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
deleted file mode 100755
index c583b0eb..00000000
--- a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/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
-cmd 2 ip6tables -I INPUT -j foobar
-
-# 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
index f730bede..dcd9dfd3 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -13,75 +13,84 @@ cmd() { # (rc, msg, cmd, [args ...])
msg_exp="$1"; shift
}
- msg="$($XT_MULTI "$@" 2>&1 >/dev/null)"
- rc=$?
+ for ipt in iptables ip6tables; do
+ msg="$($XT_MULTI $ipt "$@" 2>&1 >/dev/null)"
+ rc=$?
- [ $rc -eq $rc_exp ] || {
- echo "---> expected return code $rc_exp, got $rc for command '$@'"
- global_rc=1
- }
+ [ $rc -eq $rc_exp ] || {
+ echo "---> expected return code $rc_exp, got $rc for command '$ipt $@'"
+ global_rc=1
+ }
- [ -n "$msg_exp" ] || return
- grep -q "$msg_exp" <<< $msg || {
- echo "---> expected error message '$msg_exp', got '$msg' for command '$@'"
- global_rc=1
- }
+ [ -n "$msg_exp" ] || continue
+ msg_exp_full="${ipt}$msg_exp"
+ grep -q "$msg_exp_full" <<< $msg || {
+ echo "---> expected error message '$msg_exp_full', got '$msg' for command '$ipt $@'"
+ global_rc=1
+ }
+ done
}
-EEXIST_F="File exists."
-EEXIST="Chain already exists."
-ENOENT="No chain/target/match by that name."
-E2BIG_I="Index of insertion too big."
-E2BIG_D="Index of deletion too big."
-E2BIG_R="Index of replacement too big."
-EBADRULE="Bad rule (does a matching rule exist in that chain?)."
-ENOTGT="Couldn't load target \`foobar':No such file or directory"
-ENOMTH="Couldn't load match \`foobar':No such file or directory"
-ENOTBL="can't initialize iptables table \`foobar': Table does not exist"
+EEXIST_F=": File exists."
+EEXIST=": Chain already exists."
+ENOENT=": No chain/target/match by that name."
+E2BIG_I=": Index of insertion too big."
+E2BIG_D=": Index of deletion too big."
+E2BIG_R=": Index of replacement too big."
+EBADRULE=": Bad rule (does a matching rule exist in that chain?)."
+#ENOTGT=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory"
+ENOMTH=" v[0-9\.]* [^ ]*: Couldn't load match \`foobar':No such file or directory"
+ENOTBL=": can't initialize iptables table \`foobar': Table does not exist"
# test chain creation
-cmd 0 iptables -N foo
-cmd 1 "$EEXIST" iptables -N foo
+cmd 0 -N foo
+cmd 1 "$EEXIST" -N foo
# iptables-nft allows this - bug or feature?
-#cmd 2 iptables -N "invalid name"
+#cmd 2 -N "invalid name"
# test chain flushing/zeroing
-cmd 0 iptables -F foo
-cmd 0 iptables -Z foo
-cmd 1 "$ENOENT" iptables -F bar
-cmd 1 "$ENOENT" iptables -Z bar
+cmd 0 -F foo
+cmd 0 -Z foo
+cmd 1 "$ENOENT" -F bar
+cmd 1 "$ENOENT" -Z bar
# test chain rename
-cmd 0 iptables -E foo bar
-cmd 1 "$EEXIST_F" iptables -E foo bar
-cmd 1 "$ENOENT" iptables -E foo bar2
-cmd 0 iptables -N foo2
-cmd 1 "$EEXIST_F" iptables -E foo2 bar
+cmd 0 -E foo bar
+cmd 1 "$EEXIST_F" -E foo bar
+cmd 1 "$ENOENT" -E foo bar2
+cmd 0 -N foo2
+cmd 1 "$EEXIST_F" -E foo2 bar
# test rule adding
-cmd 0 iptables -A INPUT -j ACCEPT
-cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT
-cmd 2 "" iptables -I INPUT -j foobar
-cmd 2 "" iptables -R INPUT 1 -j foobar
-cmd 2 "" iptables -D INPUT -j foobar
+cmd 0 -A INPUT -j ACCEPT
+cmd 1 "$ENOENT" -A noexist -j ACCEPT
+# next three differ:
+# legacy: Couldn't load target `foobar':No such file or directory
+# nft: Chain 'foobar' does not exist
+cmd 2 "" -I INPUT -j foobar
+cmd 2 "" -R INPUT 1 -j foobar
+cmd 2 "" -D INPUT -j foobar
+cmd 1 "$EBADRULE" -D INPUT -p tcp --dport 22 -j ACCEPT
# test rulenum commands
-cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT
-cmd 1 "$E2BIG_D" iptables -D INPUT 23
-cmd 1 "$E2BIG_R" iptables -R INPUT 23 -j ACCEPT
-cmd 1 "$ENOENT" iptables -I nonexist 23 -j ACCEPT
-cmd 1 "$ENOENT" iptables -D nonexist 23
-cmd 1 "$ENOENT" iptables -R nonexist 23 -j ACCEPT
+cmd 1 "$E2BIG_I" -I INPUT 23 -j ACCEPT
+cmd 1 "$E2BIG_D" -D INPUT 23
+cmd 1 "$E2BIG_R" -R INPUT 23 -j ACCEPT
+cmd 1 "$ENOENT" -I nonexist 23 -j ACCEPT
+cmd 1 "$ENOENT" -D nonexist 23
+cmd 1 "$ENOENT" -R nonexist 23 -j ACCEPT
# test rule checking
-cmd 0 iptables -C INPUT -j ACCEPT
-cmd 1 "$EBADRULE" iptables -C FORWARD -j ACCEPT
-cmd 1 "$BADRULE" iptables -C nonexist -j ACCEPT
-cmd 2 "$ENOMTH" iptables -C INPUT -m foobar -j ACCEPT
+cmd 0 -C INPUT -j ACCEPT
+cmd 1 "$EBADRULE" -C FORWARD -j ACCEPT
+cmd 1 "$BADRULE" -C nonexist -j ACCEPT
+cmd 2 "$ENOMTH" -C INPUT -m foobar -j ACCEPT
# messages of those don't match, but iptables-nft ones are actually nicer.
-#cmd 2 "$ENOTGT" iptables -C INPUT -j foobar
-#cmd 3 "$ENOTBL" iptables -t foobar -C INPUT -j ACCEPT
-cmd 2 "" iptables -C INPUT -j foobar
-cmd 3 "" iptables -t foobar -C INPUT -j ACCEPT
+# legacy: Couldn't load target `foobar':No such file or directory
+# nft: Chain 'foobar' does not exist
+cmd 2 "" -C INPUT -j foobar
+# legacy: can't initialize ip6tables table `foobar': Table does not exist (do you need to insmod?)
+# nft: table 'foobar' does not exist
+cmd 3 "" -t foobar -C INPUT -j ACCEPT
exit $global_rc
diff --git a/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0 b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
new file mode 100755
index 00000000..43880ffb
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+nft -v >/dev/null || { echo "skip $XT_MULTI (no nft)"; exit 0; }
+
+coproc $XT_MULTI iptables-restore --noflush
+
+cat >&"${COPROC[1]}" <<EOF
+*filter
+:foo [0:0]
+COMMIT
+*filter
+:foo [0:0]
+EOF
+
+$XT_MULTI iptables-save | grep -q ':foo'
+nft flush ruleset
+
+echo "COMMIT" >&"${COPROC[1]}"
+sleep 1
+
+[[ -n $COPROC_PID ]] && kill $COPROC_PID
+wait
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 57def83e..4008cc00 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -93,6 +93,8 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
if (arg->nfproto && arg->nfproto != family)
goto err_free;
+ arg->h->ops = nft_family_ops_lookup(family);
+
if (arg->is_event)
printf(" EVENT: ");
switch (family) {
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index dd6fb791..7b71db62 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -75,14 +75,10 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
xtables_fini();
if (!ret) {
- if (errno == EINVAL) {
- fprintf(stderr, "iptables: %s. "
- "Run `dmesg' for more information.\n",
- nft_strerror(errno));
- } else {
- fprintf(stderr, "iptables: %s.\n",
- nft_strerror(errno));
- }
+ fprintf(stderr, "%s: %s.%s\n", progname, nft_strerror(errno),
+ (errno == EINVAL ?
+ " Run `dmesg' for more information." : ""));
+
if (errno == EAGAIN)
exit(RESOURCE_PROBLEM);
}