summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/libipt_icmp.c5
-rw-r--r--extensions/libipt_icmp.txlate3
-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-shared.c2
-rw-r--r--iptables/nft.c382
-rw-r--r--iptables/nft.h3
-rwxr-xr-xiptables/tests/shell/testcases/ip6tables/0004-return-codes_039
-rwxr-xr-xiptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_053
-rwxr-xr-xiptables/tests/shell/testcases/iptables/0004-return-codes_0113
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0007-mid-restore-flush_023
-rwxr-xr-xiptables/tests/shell/testcases/nft-only/0008-basechain-policy_029
-rw-r--r--iptables/xtables-monitor.c2
-rw-r--r--iptables/xtables-standalone.c12
-rw-r--r--libiptc/libiptc.c2
-rw-r--r--libxtables/xtables.c213
17 files changed, 480 insertions, 491 deletions
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
index e76257c5..e5e23661 100644
--- a/extensions/libipt_icmp.c
+++ b/extensions/libipt_icmp.c
@@ -256,6 +256,11 @@ static int icmp_xlate(struct xt_xlate *xl,
if (!type_xlate_print(xl, info->type, info->code[0],
info->code[1]))
return 0;
+ } else {
+ /* '-m icmp --icmp-type any' is a noop by itself,
+ * but it eats a (mandatory) previous '-p icmp' so
+ * emit it here */
+ xt_xlate_add(xl, "ip protocol icmp");
}
return 1;
}
diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate
index 434f8cc4..a2aec8e2 100644
--- a/extensions/libipt_icmp.txlate
+++ b/extensions/libipt_icmp.txlate
@@ -6,3 +6,6 @@ nft add rule ip filter INPUT icmp type destination-unreachable counter accept
iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT
nft add rule ip filter INPUT icmp type != destination-unreachable counter accept
+
+iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT
+nft add rule ip filter INPUT ip protocol icmp counter accept
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-shared.c b/iptables/nft-shared.c
index c5a8f3fc..7741d23b 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -165,7 +165,7 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
void add_addr(struct nftnl_rule *r, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
- const char *m = mask;
+ const unsigned char *m = mask;
int i;
add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
diff --git a/iptables/nft.c b/iptables/nft.c
index 634d02fe..39882a44 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -265,7 +265,6 @@ struct obj_update {
struct list_head head;
enum obj_update_type type:8;
uint8_t skip:1;
- uint8_t implicit:1;
unsigned int seq;
union {
struct nftnl_table *table;
@@ -388,10 +387,11 @@ batch_set_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, s);
}
-static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
+static struct obj_update *
+batch_chain_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_chain *c)
{
- return batch_add(h, type, c) ? 0 : -1;
+ return batch_add(h, type, c);
}
static struct obj_update *
@@ -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();
@@ -684,7 +678,9 @@ nft_chain_builtin_alloc(const struct builtin_table *table,
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain->name);
nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, chain->hook);
nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, chain->prio);
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
+ if (policy >= 0)
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, policy);
+
nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, chain->type);
return c;
@@ -742,22 +738,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 +766,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 +774,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 +828,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;
@@ -921,7 +905,6 @@ int nft_chain_set(struct nft_handle *h, const char *table,
const struct xt_counters *counters)
{
struct nftnl_chain *c = NULL;
- int ret;
nft_fn = nft_chain_set;
@@ -929,16 +912,19 @@ int nft_chain_set(struct nft_handle *h, const char *table,
c = nft_chain_new(h, table, chain, NF_DROP, counters);
else if (strcmp(policy, "ACCEPT") == 0)
c = nft_chain_new(h, table, chain, NF_ACCEPT, counters);
+ else if (strcmp(policy, "-") == 0)
+ c = nft_chain_new(h, table, chain, -1, counters);
else
errno = EINVAL;
if (c == NULL)
return 0;
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c))
+ return 0;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
@@ -1401,9 +1387,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 +1562,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 +1579,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 +1589,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;
@@ -1645,7 +1622,7 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
static void
__nft_rule_flush(struct nft_handle *h, const char *table,
- const char *chain, bool verbose, bool implicit)
+ const char *chain, bool verbose, bool skip)
{
struct obj_update *obj;
struct nftnl_rule *r;
@@ -1667,13 +1644,34 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
return;
}
- obj->implicit = implicit;
+ obj->skip = skip;
+}
+
+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 +1704,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;
@@ -1731,7 +1714,6 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
{
struct nftnl_chain_list *list;
struct nftnl_chain *c;
- int ret;
nft_fn = nft_chain_user_add;
@@ -1751,33 +1733,28 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (h->family == NFPROTO_BRIDGE)
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
+ return 0;
list = nft_chain_list_get(h, table, chain);
if (list)
nftnl_chain_list_add(c, list);
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
{
struct nftnl_chain_list *list;
+ struct obj_update *obj;
struct nftnl_chain *c;
bool created = false;
- int ret;
nft_xt_builtin_init(h, table);
c = nft_chain_find(h, table, chain);
- if (c) {
- /* Apparently -n still flushes existing user defined
- * chains that are redefined.
- */
- if (h->noflush)
- __nft_rule_flush(h, table, chain, false, true);
- } else {
+ if (!c) {
c = nftnl_chain_alloc();
if (!c)
return 0;
@@ -1785,22 +1762,29 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
- }
- if (h->family == NFPROTO_BRIDGE)
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
+ list = nft_chain_list_get(h, table, chain);
+ if (list)
+ nftnl_chain_list_add(c, list);
+ } else {
+ /* If the chain should vanish meanwhile, kernel genid changes
+ * and the transaction is refreshed enabling the chain add
+ * object. With the handle still set, kernel interprets it as a
+ * chain replace job and errors since it is not found anymore.
+ */
+ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
+ }
- if (!created)
- return 1;
+ __nft_rule_flush(h, table, chain, false, created);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ obj = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ if (!obj)
+ return 0;
- list = nft_chain_list_get(h, table, chain);
- if (list)
- nftnl_chain_list_add(c, list);
+ obj->skip = !created;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
/* From linux/netlink.h */
@@ -1818,7 +1802,6 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
{
struct chain_user_del_data *d = data;
struct nft_handle *h = d->handle;
- int ret;
/* don't delete built-in chain */
if (nft_chain_builtin(c))
@@ -1830,8 +1813,7 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
/* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
- if (ret)
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
return -1;
nftnl_chain_list_del(c);
@@ -1906,7 +1888,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
{
struct nftnl_chain *c;
uint64_t handle;
- int ret;
nft_fn = nft_chain_user_rename;
@@ -1935,47 +1916,35 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c))
+ return 0;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
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 +1973,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 +1982,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 +2345,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 +2391,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 +2404,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 +2418,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 +2440,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 +2460,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,
@@ -2687,11 +2638,6 @@ static void nft_refresh_transaction(struct nft_handle *h)
h->error.lineno = 0;
list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
- if (n->implicit) {
- batch_obj_del(h, n);
- continue;
- }
-
switch (n->type) {
case NFT_COMPAT_TABLE_FLUSH:
tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME);
@@ -2717,14 +2663,22 @@ static void nft_refresh_transaction(struct nft_handle *h)
c = nft_chain_find(h, tablename, chainname);
if (c) {
- /* -restore -n flushes existing rules from redefined user-chain */
- __nft_rule_flush(h, tablename,
- chainname, false, true);
n->skip = 1;
} else if (!c) {
n->skip = 0;
}
break;
+ case NFT_COMPAT_RULE_FLUSH:
+ tablename = nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE);
+ if (!tablename)
+ continue;
+
+ chainname = nftnl_rule_get_str(n->rule, NFTNL_RULE_CHAIN);
+ if (!chainname)
+ continue;
+
+ n->skip = !nft_chain_find(h, tablename, chainname);
+ break;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
@@ -2736,7 +2690,6 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
- case NFT_COMPAT_RULE_FLUSH:
case NFT_COMPAT_SET_ADD:
case NFT_COMPAT_RULE_LIST:
case NFT_COMPAT_RULE_CHECK:
@@ -2767,9 +2720,10 @@ retry:
h->nft_genid++;
list_for_each_entry(n, &h->obj_list, head) {
-
- if (n->skip)
+ if (n->skip) {
+ n->seq = 0;
continue;
+ }
n->seq = seq++;
switch (n->type) {
@@ -3333,7 +3287,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
- if (batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
return -1;
}
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/ipt-restore/0016-concurrent-restores_0 b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
new file mode 100755
index 00000000..53ec12fa
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+set -e
+
+RS="*filter
+:INPUT ACCEPT [12024:3123388]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [12840:2144421]
+:FOO - [0:0]
+:BAR0 - [0:0]
+:BAR1 - [0:0]
+:BAR2 - [0:0]
+:BAR3 - [0:0]
+:BAR4 - [0:0]
+:BAR5 - [0:0]
+:BAR6 - [0:0]
+:BAR7 - [0:0]
+:BAR8 - [0:0]
+:BAR9 - [0:0]
+"
+
+RS1="$RS
+-X BAR3
+-X BAR6
+-X BAR9
+-A FOO -s 9.9.0.1/32 -j BAR1
+-A FOO -s 9.9.0.2/32 -j BAR2
+-A FOO -s 9.9.0.4/32 -j BAR4
+-A FOO -s 9.9.0.5/32 -j BAR5
+-A FOO -s 9.9.0.7/32 -j BAR7
+-A FOO -s 9.9.0.8/32 -j BAR8
+COMMIT
+"
+
+RS2="$RS
+-X BAR2
+-X BAR5
+-X BAR7
+-A FOO -s 9.9.0.1/32 -j BAR1
+-A FOO -s 9.9.0.3/32 -j BAR3
+-A FOO -s 9.9.0.4/32 -j BAR4
+-A FOO -s 9.9.0.6/32 -j BAR6
+-A FOO -s 9.9.0.8/32 -j BAR8
+-A FOO -s 9.9.0.9/32 -j BAR9
+COMMIT
+"
+
+for n in $(seq 1 10); do
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS1" &
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS2" &
+ wait -n
+ wait -n
+done
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/tests/shell/testcases/nft-only/0008-basechain-policy_0 b/iptables/tests/shell/testcases/nft-only/0008-basechain-policy_0
new file mode 100755
index 00000000..a81e9bad
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0008-basechain-policy_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+set -e
+
+$XT_MULTI iptables -t raw -P OUTPUT DROP
+
+# make sure iptables-nft-restore can correctly handle basechain policies when
+# they aren't set with --noflush
+#
+$XT_MULTI iptables-restore --noflush <<EOF
+*raw
+:OUTPUT - [0:0]
+:PREROUTING - [0:0]
+:neutron-linuxbri-OUTPUT - [0:0]
+:neutron-linuxbri-PREROUTING - [0:0]
+-I OUTPUT 1 -j neutron-linuxbri-OUTPUT
+-I PREROUTING 1 -j neutron-linuxbri-PREROUTING
+-I neutron-linuxbri-PREROUTING 1 -m physdev --physdev-in brq7425e328-56 -j CT --zone 4097
+-I neutron-linuxbri-PREROUTING 2 -i brq7425e328-56 -j CT --zone 4097
+-I neutron-linuxbri-PREROUTING 3 -m physdev --physdev-in tap7f101a28-1d -j CT --zone 4097
+
+COMMIT
+EOF
+
+$XT_MULTI iptables-save | grep -C2 raw | grep OUTPUT | grep DROP
+if [ $? -ne 0 ]; then
+ exit 1
+fi
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);
}
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index 58882015..ceeb017b 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -1169,7 +1169,7 @@ static int iptcc_compile_chain(struct xtc_handle *h, STRUCT_REPLACE *repl, struc
else
foot->target.verdict = RETURN;
/* set policy-counters */
- memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
+ foot->e.counters = c->counters;
return 0;
}
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 8907ba20..7152c657 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -203,8 +203,10 @@ struct xtables_match *xtables_matches;
struct xtables_target *xtables_targets;
/* Fully register a match/target which was previously partially registered. */
-static bool xtables_fully_register_pending_match(struct xtables_match *me);
-static bool xtables_fully_register_pending_target(struct xtables_target *me);
+static bool xtables_fully_register_pending_match(struct xtables_match *me,
+ struct xtables_match *prev);
+static bool xtables_fully_register_pending_target(struct xtables_target *me,
+ struct xtables_target *prev);
#ifndef NO_SHARED_LIBS
/* registry for loaded shared objects to close later */
@@ -662,6 +664,7 @@ struct xtables_match *
xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_rule_match **matches)
{
+ struct xtables_match *prev = NULL;
struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
@@ -683,8 +686,12 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_match(ptr))
+ if (xtables_fully_register_pending_match(ptr, prev)) {
+ prev = ptr;
continue;
+ } else if (prev) {
+ continue;
+ }
*dptr = ptr;
}
dptr = &((*dptr)->next);
@@ -778,6 +785,7 @@ xtables_find_match_revision(const char *name, enum xtables_tryload tryload,
struct xtables_target *
xtables_find_target(const char *name, enum xtables_tryload tryload)
{
+ struct xtables_target *prev = NULL;
struct xtables_target **dptr;
struct xtables_target *ptr;
@@ -794,8 +802,12 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_target(ptr))
+ if (xtables_fully_register_pending_target(ptr, prev)) {
+ prev = ptr;
continue;
+ } else if (prev) {
+ continue;
+ }
*dptr = ptr;
}
dptr = &((*dptr)->next);
@@ -948,8 +960,14 @@ static void xtables_check_options(const char *name, const struct option *opt)
}
}
+static int xtables_match_prefer(const struct xtables_match *a,
+ const struct xtables_match *b);
+
void xtables_register_match(struct xtables_match *me)
{
+ struct xtables_match **pos;
+ bool seen_myself = false;
+
if (me->next) {
fprintf(stderr, "%s: match \"%s\" already registered\n",
xt_params->program_name, me->name);
@@ -1001,10 +1019,34 @@ void xtables_register_match(struct xtables_match *me)
if (me->extra_opts != NULL)
xtables_check_options(me->name, me->extra_opts);
-
- /* place on linked list of matches pending full registration */
- me->next = xtables_pending_matches;
- xtables_pending_matches = me;
+ /* order into linked list of matches pending full registration */
+ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
+ /* group by name and family */
+ if (strcmp(me->name, (*pos)->name) ||
+ me->family != (*pos)->family) {
+ if (seen_myself)
+ break; /* end of own group, append to it */
+ continue;
+ }
+ /* found own group */
+ seen_myself = true;
+ if (xtables_match_prefer(me, *pos) >= 0)
+ break; /* put preferred items first in group */
+ }
+ /* if own group was not found, prepend item */
+ if (!*pos && !seen_myself)
+ pos = &xtables_pending_matches;
+
+ me->next = *pos;
+ *pos = me;
+#ifdef DEBUG
+ printf("%s: inserted match %s (family %d, revision %d):\n",
+ __func__, me->name, me->family, me->revision);
+ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
+ printf("%s:\tmatch %s (family %d, revision %d)\n", __func__,
+ (*pos)->name, (*pos)->family, (*pos)->revision);
+ }
+#endif
}
/**
@@ -1068,64 +1110,27 @@ static int xtables_target_prefer(const struct xtables_target *a,
b->revision, b->family);
}
-static bool xtables_fully_register_pending_match(struct xtables_match *me)
+static bool xtables_fully_register_pending_match(struct xtables_match *me,
+ struct xtables_match *prev)
{
- struct xtables_match **i, *old, *pos = NULL;
+ struct xtables_match **i;
const char *rn;
- int compare;
/* See if new match can be used. */
rn = (me->real_name != NULL) ? me->real_name : me->name;
if (!compatible_match_revision(rn, me->revision))
return false;
- old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
- while (old) {
- compare = xtables_match_prefer(old, me);
- if (compare == 0) {
- fprintf(stderr,
- "%s: match `%s' already registered.\n",
- xt_params->program_name, me->name);
- exit(1);
- }
-
- /* Now we have two (or more) options, check compatibility. */
- rn = (old->real_name != NULL) ? old->real_name : old->name;
- if (compare > 0) {
- /* Kernel tells old isn't compatible anymore??? */
- if (!compatible_match_revision(rn, old->revision)) {
- /* Delete old one. */
- for (i = &xtables_matches; *i != old;)
- i = &(*i)->next;
- *i = old->next;
- }
- pos = old;
- old = old->next;
- if (!old)
- break;
- if (!extension_cmp(me->name, old->name, old->family))
- break;
- continue;
- }
-
- /* Found right old */
- pos = old;
- break;
- }
-
- if (!pos) {
+ if (!prev) {
/* Append to list. */
for (i = &xtables_matches; *i; i = &(*i)->next);
- } else if (compare < 0) {
- /* Prepend it */
- for (i = &xtables_matches; *i != pos; i = &(*i)->next);
- } else if (compare > 0) {
+ } else {
/* Append it */
- i = &pos->next;
- pos = pos->next;
+ i = &prev->next;
+ prev = prev->next;
}
- me->next = pos;
+ me->next = prev;
*i = me;
me->m = NULL;
@@ -1136,13 +1141,17 @@ static bool xtables_fully_register_pending_match(struct xtables_match *me)
void xtables_register_matches(struct xtables_match *match, unsigned int n)
{
- do {
- xtables_register_match(&match[--n]);
- } while (n > 0);
+ int i;
+
+ for (i = 0; i < n; i++)
+ xtables_register_match(&match[i]);
}
void xtables_register_target(struct xtables_target *me)
{
+ struct xtables_target **pos;
+ bool seen_myself = false;
+
if (me->next) {
fprintf(stderr, "%s: target \"%s\" already registered\n",
xt_params->program_name, me->name);
@@ -1198,16 +1207,40 @@ void xtables_register_target(struct xtables_target *me)
if (me->family != afinfo->family && me->family != AF_UNSPEC)
return;
- /* place on linked list of targets pending full registration */
- me->next = xtables_pending_targets;
- xtables_pending_targets = me;
+ /* order into linked list of targets pending full registration */
+ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
+ /* group by name */
+ if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
+ if (seen_myself)
+ break; /* end of own group, append to it */
+ continue;
+ }
+ /* found own group */
+ seen_myself = true;
+ if (xtables_target_prefer(me, *pos) >= 0)
+ break; /* put preferred items first in group */
+ }
+ /* if own group was not found, prepend item */
+ if (!*pos && !seen_myself)
+ pos = &xtables_pending_targets;
+
+ me->next = *pos;
+ *pos = me;
+#ifdef DEBUG
+ printf("%s: inserted target %s (family %d, revision %d):\n",
+ __func__, me->name, me->family, me->revision);
+ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
+ printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
+ (*pos)->name, (*pos)->family, (*pos)->revision);
+ }
+#endif
}
-static bool xtables_fully_register_pending_target(struct xtables_target *me)
+static bool xtables_fully_register_pending_target(struct xtables_target *me,
+ struct xtables_target *prev)
{
- struct xtables_target **i, *old, *pos = NULL;
+ struct xtables_target **i;
const char *rn;
- int compare;
if (strcmp(me->name, "standard") != 0) {
/* See if new target can be used. */
@@ -1216,54 +1249,17 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me)
return false;
}
- old = xtables_find_target(me->name, XTF_DURING_LOAD);
- while (old) {
- compare = xtables_target_prefer(old, me);
- if (compare == 0) {
- fprintf(stderr,
- "%s: target `%s' already registered.\n",
- xt_params->program_name, me->name);
- exit(1);
- }
-
- /* Now we have two (or more) options, check compatibility. */
- rn = (old->real_name != NULL) ? old->real_name : old->name;
- if (compare > 0) {
- /* Kernel tells old isn't compatible anymore??? */
- if (!compatible_target_revision(rn, old->revision)) {
- /* Delete old one. */
- for (i = &xtables_targets; *i != old;)
- i = &(*i)->next;
- *i = old->next;
- }
- pos = old;
- old = old->next;
- if (!old)
- break;
- if (!extension_cmp(me->name, old->name, old->family))
- break;
- continue;
- }
-
- /* Found right old */
- pos = old;
- break;
- }
-
- if (!pos) {
+ if (!prev) {
/* Prepend to list. */
i = &xtables_targets;
- pos = xtables_targets;
- } else if (compare < 0) {
- /* Prepend it */
- for (i = &xtables_targets; *i != pos; i = &(*i)->next);
- } else if (compare > 0) {
+ prev = xtables_targets;
+ } else {
/* Append it */
- i = &pos->next;
- pos = pos->next;
+ i = &prev->next;
+ prev = prev->next;
}
- me->next = pos;
+ me->next = prev;
*i = me;
me->t = NULL;
@@ -1274,9 +1270,10 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me)
void xtables_register_targets(struct xtables_target *target, unsigned int n)
{
- do {
- xtables_register_target(&target[--n]);
- } while (n > 0);
+ int i;
+
+ for (i = 0; i < n; i++)
+ xtables_register_target(&target[i]);
}
/* receives a list of xtables_rule_match, release them */