diff options
author | Maciej Żenczykowski <maze@google.com> | 2021-04-03 00:01:23 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-04-03 00:01:23 +0000 |
commit | 1245fe8db4a632043e8e6e22bf6775b842f20229 (patch) | |
tree | 2cd21395992487f6f20217809c449090af29f882 | |
parent | 2ab7df4bf9409b88f892f3d83ffc0516619295f5 (diff) | |
parent | 5a7265ae38c0dff54021c1424fd199a3b6a8ac77 (diff) | |
download | iptables-1245fe8db4a632043e8e6e22bf6775b842f20229.tar.gz |
Merge tag 'v1.8.6' of git://git.netfilter.org/iptables am: de7a62aa82 am: 72f23c9bf9 am: af645f03f7 am: 5a7265ae38
Original change: https://android-review.googlesource.com/c/platform/external/iptables/+/1650934
Change-Id: Ic61b7339e608a105bab3116f66fd65fe634bbdb7
36 files changed, 769 insertions, 597 deletions
diff --git a/configure.ac b/configure.ac index 31a8bb26..357c5116 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT([iptables], [1.8.5]) +AC_INIT([iptables], [1.8.6]) # See libtool.info "Libtool's versioning system" libxtables_vcurrent=15 @@ -219,6 +219,7 @@ AC_SUBST([libxtables_vmajor]) AC_DEFINE_UNQUOTED([XT_LOCK_NAME], "${xt_lock_name}", [Location of the iptables lock file]) +AC_SUBST([XT_LOCK_NAME], "${xt_lock_name}") AC_CONFIG_FILES([Makefile extensions/GNUmakefile include/Makefile iptables/Makefile iptables/xtables.pc diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 0842a553..956ccb38 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -79,7 +79,7 @@ targets_install := .SECONDARY: -.PHONY: all install clean distclean FORCE +.PHONY: all install uninstall clean distclean FORCE all: ${targets} @@ -92,6 +92,19 @@ install: ${targets_install} ${symlinks_install} cp -P ${symlinks_install} "${DESTDIR}${xtlibdir}/"; \ fi; +uninstall: + dir=${DESTDIR}${xtlibdir}; { \ + test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ + } || { \ + test -z "${targets_install}" || ( \ + cd "$$dir" && rm -f ${targets_install} \ + ); \ + test -z "${symlinks_install}" || ( \ + cd "$$dir" && rm -f ${symlinks_install} \ + ); \ + rmdir -p --ignore-fail-on-non-empty "$$dir"; \ + } + clean: rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c initextb.c initexta.c; rm -f .*.d .*.dd; diff --git a/extensions/libip6t_REJECT.man b/extensions/libip6t_REJECT.man index 0030a51f..3c42768e 100644 --- a/extensions/libip6t_REJECT.man +++ b/extensions/libip6t_REJECT.man @@ -30,3 +30,23 @@ TCP RST packet to be sent back. This is mainly useful for blocking hosts (which won't accept your mail otherwise). \fBtcp\-reset\fP can only be used with kernel versions 2.6.14 or later. +.PP +\fIWarning:\fP You should not indiscriminately apply the REJECT target to +packets whose connection state is classified as INVALID; instead, you should +only DROP these. +.PP +Consider a source host transmitting a packet P, with P experiencing so much +delay along its path that the source host issues a retransmission, P_2, with +P_2 being successful in reaching its destination and advancing the connection +state normally. It is conceivable that the late-arriving P may be considered +not to be associated with any connection tracking entry. Generating a reject +response for a packet so classed would then terminate the healthy connection. +.PP +So, instead of: +.PP +-A INPUT ... -j REJECT +.PP +do consider using: +.PP +-A INPUT ... -m conntrack --ctstate INVALID -j DROP +-A INPUT ... -j REJECT diff --git a/extensions/libipt_REJECT.man b/extensions/libipt_REJECT.man index 8a360ce7..cc47aead 100644 --- a/extensions/libipt_REJECT.man +++ b/extensions/libipt_REJECT.man @@ -30,3 +30,23 @@ TCP RST packet to be sent back. This is mainly useful for blocking hosts (which won't accept your mail otherwise). .IP (*) Using icmp\-admin\-prohibited with kernels that do not support it will result in a plain DROP instead of REJECT +.PP +\fIWarning:\fP You should not indiscriminately apply the REJECT target to +packets whose connection state is classified as INVALID; instead, you should +only DROP these. +.PP +Consider a source host transmitting a packet P, with P experiencing so much +delay along its path that the source host issues a retransmission, P_2, with +P_2 being successful in reaching its destination and advancing the connection +state normally. It is conceivable that the late-arriving P may be considered +not to be associated with any connection tracking entry. Generating a reject +response for a packet so classed would then terminate the healthy connection. +.PP +So, instead of: +.PP +-A INPUT ... -j REJECT +.PP +do consider using: +.PP +-A INPUT ... -m conntrack --ctstate INVALID -j DROP +-A INPUT ... -j REJECT 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/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 6f350393..7734509c 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -1249,11 +1249,19 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl, } if (sinfo->match_flags & XT_CONNTRACK_STATE) { - xt_xlate_add(xl, "%sct state %s", space, - sinfo->invert_flags & XT_CONNTRACK_STATE ? - "!= " : ""); - state_xlate_print(xl, sinfo->state_mask); - space = " "; + if ((sinfo->state_mask & XT_CONNTRACK_STATE_SNAT) || + (sinfo->state_mask & XT_CONNTRACK_STATE_DNAT)) { + xt_xlate_add(xl, "%sct status %s%s", space, + sinfo->invert_flags & XT_CONNTRACK_STATUS ? "!=" : "", + sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat"); + space = " "; + } else { + xt_xlate_add(xl, "%sct state %s", space, + sinfo->invert_flags & XT_CONNTRACK_STATE ? + "!= " : ""); + state_xlate_print(xl, sinfo->state_mask); + space = " "; + } } if (sinfo->match_flags & XT_CONNTRACK_STATUS) { diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate index 8a3d0181..d374f8a0 100644 --- a/extensions/libxt_conntrack.txlate +++ b/extensions/libxt_conntrack.txlate @@ -42,3 +42,10 @@ nft add rule ip filter INPUT ct direction original counter accept iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctstate SNAT -j ACCEPT +nft add rule ip filter INPUT ct status snat counter accept + +iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT +nft add rule ip filter INPUT ct status dnat counter accept + diff --git a/include/Makefile.am b/include/Makefile.am index e6951209..ea34c2fe 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -10,3 +10,8 @@ endif nobase_include_HEADERS += \ libiptc/ipt_kernel_headers.h libiptc/libiptc.h \ libiptc/libip6tc.h libiptc/libxtc.h libiptc/xtcshared.h + +uninstall-hook: + dir=${includedir}/libiptc; { \ + test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ + } || rmdir -p --ignore-fail-on-non-empty "$$dir" diff --git a/iptables/Makefile.am b/iptables/Makefile.am index dc66b3cc..4bf5742c 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -56,7 +56,7 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \ ip6tables-save.8 iptables-extensions.8 \ iptables-apply.8 ip6tables-apply.8 -sbin_SCRIPT = iptables-apply +sbin_SCRIPTS = iptables-apply if ENABLE_NFTABLES man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \ @@ -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 @@ -111,3 +115,26 @@ install-exec-hook: for i in ${v6_sbin_links}; do ${LN_S} -f xtables-legacy-multi "${DESTDIR}${sbindir}/$$i"; done; for i in ${x_sbin_links}; do ${LN_S} -f xtables-nft-multi "${DESTDIR}${sbindir}/$$i"; done; ${LN_S} -f iptables-apply "${DESTDIR}${sbindir}/ip6tables-apply" + +uninstall-hook: + dir=${DESTDIR}${bindir}; { \ + test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ + } || { \ + test -z "${vx_bin_links}" || ( \ + cd "$$dir" && rm -f ${vx_bin_links} \ + ) \ + } + dir=${DESTDIR}${sbindir}; { \ + test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ + } || { \ + test -z "${v4_sbin_links}" || ( \ + cd "$$dir" && rm -f ${v4_sbin_links} \ + ); \ + test -z "${v6_sbin_links}" || ( \ + cd "$$dir" && rm -f ${v6_sbin_links} \ + ); \ + test -z "${x_sbin_links}" || ( \ + cd "$$dir" && rm -f ${x_sbin_links} \ + ); \ + ( cd "$$dir" && rm -f ip6tables-apply ); \ + } diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in index 054564b3..999cf339 100644 --- a/iptables/iptables.8.in +++ b/iptables/iptables.8.in @@ -397,6 +397,14 @@ corresponding to that rule's position in the chain. \fB\-\-modprobe=\fP\fIcommand\fP When adding or inserting rules into a chain, use \fIcommand\fP to load any necessary modules (targets, match extensions, etc). + +.SH LOCK FILE +iptables uses the \fI@XT_LOCK_NAME@\fP file to take an exclusive lock at +launch. + +The \fBXTABLES_LOCKFILE\fP environment variable can be used to override +the default setting. + .SH MATCH AND TARGET EXTENSIONS .PP iptables can use extended packet matching and target modules. diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c index 638b18bc..32cfd6cf 100644 --- a/iptables/nft-cache.c +++ b/iptables/nft-cache.c @@ -109,48 +109,44 @@ static void mnl_genid_get(struct nft_handle *h, uint32_t *genid) static int nftnl_table_list_cb(const struct nlmsghdr *nlh, void *data) { - struct nftnl_table *t; - struct nftnl_table_list *list = data; + struct nftnl_table *nftnl = nftnl_table_alloc(); + const struct builtin_table *t; + struct nft_handle *h = data; + const char *name; - t = nftnl_table_alloc(); - if (t == NULL) - goto err; + if (!nftnl) + return MNL_CB_OK; - if (nftnl_table_nlmsg_parse(nlh, t) < 0) + if (nftnl_table_nlmsg_parse(nlh, nftnl) < 0) goto out; - nftnl_table_list_add_tail(t, list); + name = nftnl_table_get_str(nftnl, NFTNL_TABLE_NAME); + if (!name) + goto out; - return MNL_CB_OK; + t = nft_table_builtin_find(h, name); + if (!t) + goto out; + + h->cache->table[t->type].exists = true; out: - nftnl_table_free(t); -err: + nftnl_table_free(nftnl); return MNL_CB_OK; } static int fetch_table_cache(struct nft_handle *h) { - char buf[16536]; struct nlmsghdr *nlh; - struct nftnl_table_list *list; + char buf[16536]; int i, ret; - if (h->cache->tables) - return 0; - - list = nftnl_table_list_alloc(); - if (list == NULL) - 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, list); + ret = mnl_talk(h, nlh, nftnl_table_list_cb, h); if (ret < 0 && errno == EINTR) assert(nft_restart(h) >= 0); - h->cache->tables = list; - for (i = 0; i < NFT_TABLE_MAX; i++) { enum nft_table_type type = h->tables[i].type; @@ -180,8 +176,8 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) const struct builtin_table *t = d->t; struct nftnl_chain_list *list; struct nft_handle *h = d->h; - const char *tname, *cname; struct nftnl_chain *c; + const char *tname; c = nftnl_chain_alloc(); if (c == NULL) @@ -201,11 +197,6 @@ static int nftnl_chain_list_cb(const struct nlmsghdr *nlh, void *data) } list = h->cache->table[t->type].chains; - cname = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME); - - if (nftnl_chain_list_lookup_byname(list, cname)) - goto out; - nftnl_chain_list_add_tail(c, list); return MNL_CB_OK; @@ -511,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); @@ -612,10 +603,8 @@ 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; } - } - if (c->tables) { - nftnl_table_list_free(c->tables); - c->tables = NULL; + + c->table[i].exists = false; } return 1; @@ -689,11 +678,6 @@ void nft_release_cache(struct nft_handle *h) } } -struct nftnl_table_list *nftnl_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 f4291180..76f9fbb6 100644 --- a/iptables/nft-cache.h +++ b/iptables/nft-cache.h @@ -17,6 +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 nftnl_table_list *nftnl_table_list_get(struct nft_handle *h); #endif /* _NFT_CACHE_H_ */ diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c index 9c0901e7..5d33f1f0 100644 --- a/iptables/nft-cmd.c +++ b/iptables/nft-cmd.c @@ -311,10 +311,15 @@ int nft_cmd_chain_set(struct nft_handle *h, const char *table, return 1; } -int nft_cmd_table_flush(struct nft_handle *h, const char *table) +int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose) { struct nft_cmd *cmd; + if (verbose) { + return nft_cmd_rule_flush(h, NULL, table, verbose) && + nft_cmd_chain_user_del(h, NULL, table, verbose); + } + cmd = nft_cmd_new(h, NFT_COMPAT_TABLE_FLUSH, table, NULL, NULL, -1, false); if (!cmd) @@ -388,8 +393,3 @@ int ebt_cmd_user_chain_policy(struct nft_handle *h, const char *table, return 1; } - -void nft_cmd_table_new(struct nft_handle *h, const char *table) -{ - nft_cmd_new(h, NFT_COMPAT_TABLE_NEW, table, NULL, NULL, -1, false); -} diff --git a/iptables/nft-cmd.h b/iptables/nft-cmd.h index 0e1776ce..ecf7655a 100644 --- a/iptables/nft-cmd.h +++ b/iptables/nft-cmd.h @@ -65,7 +65,7 @@ int nft_cmd_chain_user_rename(struct nft_handle *h,const char *chain, int nft_cmd_rule_replace(struct nft_handle *h, const char *chain, const char *table, void *data, int rulenum, bool verbose); -int nft_cmd_table_flush(struct nft_handle *h, const char *table); +int nft_cmd_table_flush(struct nft_handle *h, const char *table, bool verbose); int nft_cmd_chain_restore(struct nft_handle *h, const char *chain, const char *table); int nft_cmd_rule_zero_counters(struct nft_handle *h, const char *chain, 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-shared.h b/iptables/nft-shared.h index 94437ffe..4440fd17 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -225,7 +225,8 @@ struct nft_xt_restore_cb { int (*chain_restore)(struct nft_handle *h, const char *chain, const char *table); - int (*table_flush)(struct nft_handle *h, const char *table); + int (*table_flush)(struct nft_handle *h, const char *table, + bool verbose); int (*do_command)(struct nft_handle *h, int argc, char *argv[], char **table, bool restore); diff --git a/iptables/nft.c b/iptables/nft.c index 0c5a74fc..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; @@ -350,7 +349,6 @@ static int mnl_append_error(const struct nft_handle *h, case NFT_COMPAT_RULE_SAVE: case NFT_COMPAT_RULE_ZERO: case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: - case NFT_COMPAT_TABLE_NEW: assert(0); break; } @@ -389,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 * @@ -645,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(); @@ -685,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; @@ -743,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]); @@ -776,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; @@ -787,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; } @@ -892,7 +877,7 @@ static struct nftnl_chain *nft_chain_new(struct nft_handle *h, } /* if this built-in table does not exists, create it */ - nft_table_builtin_add(h, _t); + nft_xt_builtin_init(h, table); _c = nft_chain_builtin_find(_t, chain); if (_c != NULL) { @@ -920,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; @@ -928,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) @@ -1400,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) @@ -1559,51 +1543,33 @@ static const char *policy_name[NF_ACCEPT+1] = { [NF_ACCEPT] = "ACCEPT", }; -int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list) +int nft_chain_save(struct nftnl_chain *c, void *data) { - struct nft_family_ops *ops = h->ops; - struct nftnl_chain_list_iter *iter; - struct nftnl_chain *c; - - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) - return 0; - - c = nftnl_chain_list_iter_next(iter); - while (c != NULL) { - const char *policy = NULL; - - if (nft_chain_builtin(c)) { - uint32_t pol = NF_ACCEPT; - - if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY)) - pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - policy = policy_name[pol]; - } else if (h->family == NFPROTO_BRIDGE) { - if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) { - uint32_t pol; - - pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - policy = policy_name[pol]; - } else { - policy = "RETURN"; - } - } - - if (ops->save_chain) - ops->save_chain(c, policy); + struct nft_handle *h = data; + const char *policy = NULL; - c = nftnl_chain_list_iter_next(iter); + if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) { + policy = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)]; + } else if (nft_chain_builtin(c)) { + policy = "ACCEPT"; + } else if (h->family == NFPROTO_BRIDGE) { + policy = "RETURN"; } - nftnl_chain_list_iter_destroy(iter); + if (h->ops->save_chain) + h->ops->save_chain(c, policy); - return 1; + 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; @@ -1613,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); } @@ -1623,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; @@ -1667,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; @@ -1689,31 +1644,47 @@ __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; - nft_xt_builtin_init(h, table); - nft_fn = nft_rule_flush; - if (chain || verbose) { - list = nft_chain_list_get(h, table, chain); - if (list == NULL) { - ret = 1; - goto err; - } - } + if (chain || verbose) + nft_xt_builtin_init(h, table); + else if (!nft_table_find(h, table)) + return 1; if (chain) { - c = nftnl_chain_list_lookup_byname(list, chain); + c = nft_chain_find(h, table, chain); if (!c) { errno = ENOENT; return 0; @@ -1727,22 +1698,13 @@ int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table, return 1; } - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) { + list = nft_chain_list_get(h, table, chain); + if (list == 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; @@ -1752,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; @@ -1772,31 +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; @@ -1804,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 */ @@ -1837,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)) @@ -1849,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); @@ -1925,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; @@ -1934,8 +1896,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain, return 0; } - nft_xt_builtin_init(h, table); - /* Config load changed errno. Ensure genuine info for our callers. */ errno = 0; @@ -1956,73 +1916,37 @@ 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 nftnl_table_list_iter *iter; - struct nftnl_table_list *list; - struct nftnl_table *t; - bool ret = false; - - list = nftnl_table_list_get(h); - if (list == NULL) - goto err; - - iter = nftnl_table_list_iter_create(list); - if (iter == NULL) - goto err; - - t = nftnl_table_list_iter_next(iter); - while (t != NULL) { - const char *this_tablename = - nftnl_table_get(t, NFTNL_TABLE_NAME); - - if (strcmp(tablename, this_tablename) == 0) { - ret = true; - break; - } - - t = nftnl_table_list_iter_next(iter); - } - - nftnl_table_list_iter_destroy(iter); + const struct builtin_table *t; -err: - 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 nftnl_table_list *list; - struct nftnl_table_list_iter *iter; - struct nftnl_table *t; - - list = nftnl_table_list_get(h); - if (list == NULL) - return -1; - - iter = nftnl_table_list_iter_create(list); - if (iter == NULL) - return -1; + int i; - t = nftnl_table_list_iter_next(iter); - while (t != NULL) { - const char *tablename = - nftnl_table_get(t, NFTNL_TABLE_NAME); + for (i = 0; i < NFT_TABLE_MAX; i++) { + if (h->tables[i].name == NULL) + continue; - func(h, tablename, data); + if (!h->cache->table[h->tables[i].type].exists) + continue; - t = nftnl_table_list_iter_next(iter); + func(h, h->tables[i].name, data); } - nftnl_table_list_iter_destroy(iter); return 0; } @@ -2049,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); @@ -2058,52 +1982,21 @@ 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 nftnl_table_list_iter *iter; - struct nftnl_table_list *list; - struct nftnl_table *t; - bool exists = false; + const struct builtin_table *t; int ret = 0; nft_fn = nft_table_flush; - list = nftnl_table_list_get(h); - if (list == NULL) { - ret = -1; - goto err_out; - } - - iter = nftnl_table_list_iter_create(list); - if (iter == NULL) { - ret = -1; - goto err_table_list; - } - - t = nftnl_table_list_iter_next(iter); - while (t != NULL) { - const char *table_name = - nftnl_table_get_str(t, NFTNL_TABLE_NAME); - - if (strcmp(table_name, table) == 0) { - exists = true; - break; - } + t = nft_table_builtin_find(h, table); + if (!t) + return 0; - t = nftnl_table_list_iter_next(iter); - } + ret = __nft_table_flush(h, table, h->cache->table[t->type].exists); - ret = __nft_table_flush(h, table, exists); - nftnl_table_list_iter_destroy(iter); -err_table_list: -err_out: /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } -void nft_table_new(struct nft_handle *h, const char *table) -{ - nft_xt_builtin_init(h, table); -} - static int __nft_rule_del(struct nft_handle *h, struct nftnl_rule *r) { struct obj_update *obj; @@ -2452,55 +2345,69 @@ 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); - list = nft_chain_list_get(h, table, chain); - if (!list) - return 0; - if (chain) { - c = nftnl_chain_list_lookup_byname(list, chain); + c = nft_chain_find(h, table, chain); 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; } - iter = nftnl_chain_list_iter_create(list); - if (iter == NULL) + list = nft_chain_list_get(h, table, chain); + if (!list) 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; } @@ -2511,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); @@ -2533,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; @@ -2568,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, @@ -2735,7 +2620,6 @@ static void batch_obj_del(struct nft_handle *h, struct obj_update *o) case NFT_COMPAT_RULE_SAVE: case NFT_COMPAT_RULE_ZERO: case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: - case NFT_COMPAT_TABLE_NEW: assert(0); break; } @@ -2754,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); @@ -2784,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: @@ -2803,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: @@ -2811,7 +2697,6 @@ static void nft_refresh_transaction(struct nft_handle *h) case NFT_COMPAT_RULE_SAVE: case NFT_COMPAT_RULE_ZERO: case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: - case NFT_COMPAT_TABLE_NEW: break; } } @@ -2835,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) { @@ -2915,7 +2801,6 @@ retry: case NFT_COMPAT_RULE_SAVE: case NFT_COMPAT_RULE_ZERO: case NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE: - case NFT_COMPAT_TABLE_NEW: assert(0); } @@ -3178,10 +3063,6 @@ static int nft_prepare(struct nft_handle *h) ret = ebt_set_user_chain_policy(h, cmd->table, cmd->chain, cmd->policy); break; - case NFT_COMPAT_TABLE_NEW: - nft_xt_builtin_init(h, cmd->table); - ret = 1; - break; case NFT_COMPAT_SET_ADD: nft_xt_builtin_init(h, cmd->table); batch_set_add(h, NFT_COMPAT_SET_ADD, cmd->obj.set); @@ -3406,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 bd783231..128e09be 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -8,10 +8,10 @@ #include <libiptc/linux_list.h> enum nft_table_type { - NFT_TABLE_FILTER = 0, - NFT_TABLE_MANGLE, - NFT_TABLE_RAW, + NFT_TABLE_MANGLE = 0, NFT_TABLE_SECURITY, + NFT_TABLE_RAW, + NFT_TABLE_FILTER, NFT_TABLE_NAT, }; #define NFT_TABLE_MAX (NFT_TABLE_NAT + 1) @@ -38,11 +38,10 @@ enum nft_cache_level { }; struct nft_cache { - struct nftnl_table_list *tables; struct { struct nftnl_chain_list *chains; struct nftnl_set_list *sets; - bool initialized; + bool exists; } table[NFT_TABLE_MAX]; }; @@ -68,7 +67,6 @@ enum obj_update_type { NFT_COMPAT_RULE_SAVE, NFT_COMPAT_RULE_ZERO, NFT_COMPAT_BRIDGE_USER_CHAIN_UPDATE, - NFT_COMPAT_TABLE_NEW, }; struct cache_chain { @@ -135,7 +133,6 @@ int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, c bool nft_table_find(struct nft_handle *h, const char *tablename); int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nftnl_chain_list *list); int nft_table_flush(struct nft_handle *h, const char *table); -void nft_table_new(struct nft_handle *h, const char *table); const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const char *table); /* @@ -144,7 +141,7 @@ const struct builtin_table *nft_table_builtin_find(struct nft_handle *h, const c struct nftnl_chain; int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); -int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list); +int nft_chain_save(struct nftnl_chain *c, void *data); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table, bool verbose); int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table); diff --git a/iptables/tests/shell/run-tests.sh b/iptables/tests/shell/run-tests.sh index 2125e2cb..65c37adb 100755 --- a/iptables/tests/shell/run-tests.sh +++ b/iptables/tests/shell/run-tests.sh @@ -4,6 +4,21 @@ TESTDIR="./$(dirname $0)/" RETURNCODE_SEPARATOR="_" +usage() { + cat <<EOF +Usage: $(basename $0) [-v|--verbose] [-H|--host] [-V|--valgrind] + [[-l|--legacy]|[-n|--nft]] [testscript ...] + +-v | --verbose Enable verbose mode (do not drop testscript output). +-H | --host Run tests against installed binaries in \$PATH, + not those built in this source tree. +-V | --valgrind Enable leak checking via valgrind. +-l | --legacy Test legacy variant only. Conflicts with --nft. +-n | --nft Test nft variant only. Conflicts with --legacy. +testscript Run only specific test(s). Implies --verbose. +EOF +} + msg_error() { echo "E: $1 ..." >&2 exit 1 @@ -50,6 +65,10 @@ while [ -n "$1" ]; do VALGRIND=y shift ;; + -h|--help) + usage + exit 0 + ;; *${RETURNCODE_SEPARATOR}+([0-9])) SINGLE+=" $1" VERBOSE=y 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/0014-verbose-restore_0 b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 new file mode 100755 index 00000000..94bed0ec --- /dev/null +++ b/iptables/tests/shell/testcases/ipt-restore/0014-verbose-restore_0 @@ -0,0 +1,76 @@ +#!/bin/bash + +set -e + +DUMP="*filter +:foo - [0:0] +:bar - [0:0] +-A foo -j ACCEPT +COMMIT +*nat +:natfoo - [0:0] +:natbar - [0:0] +-A natfoo -j ACCEPT +COMMIT +*raw +:rawfoo - [0:0] +COMMIT +*mangle +:manglefoo - [0:0] +COMMIT +*security +:secfoo - [0:0] +COMMIT +" + +$XT_MULTI iptables-restore <<< "$DUMP" +$XT_MULTI ip6tables-restore <<< "$DUMP" + +EXPECT="Flushing chain \`INPUT' +Flushing chain \`FORWARD' +Flushing chain \`OUTPUT' +Flushing chain \`bar' +Flushing chain \`foo' +Deleting chain \`bar' +Deleting chain \`foo' +Flushing chain \`PREROUTING' +Flushing chain \`INPUT' +Flushing chain \`OUTPUT' +Flushing chain \`POSTROUTING' +Flushing chain \`natbar' +Flushing chain \`natfoo' +Deleting chain \`natbar' +Deleting chain \`natfoo' +Flushing chain \`PREROUTING' +Flushing chain \`OUTPUT' +Flushing chain \`rawfoo' +Deleting chain \`rawfoo' +Flushing chain \`PREROUTING' +Flushing chain \`INPUT' +Flushing chain \`FORWARD' +Flushing chain \`OUTPUT' +Flushing chain \`POSTROUTING' +Flushing chain \`manglefoo' +Deleting chain \`manglefoo' +Flushing chain \`INPUT' +Flushing chain \`FORWARD' +Flushing chain \`OUTPUT' +Flushing chain \`secfoo' +Deleting chain \`secfoo'" + +for ipt in iptables-restore ip6tables-restore; do + diff -u -Z <(sort <<< "$EXPECT") <($XT_MULTI $ipt -v <<< "$DUMP" | sort) +done + +DUMP="*filter +:baz - [0:0] +-F foo +-X bar +-A foo -j ACCEPT +COMMIT +" + +EXPECT="" +for ipt in iptables-restore ip6tables-restore; do + diff -u -Z <(echo -ne "$EXPECT") <($XT_MULTI $ipt -v --noflush <<< "$DUMP") +done 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..aa746ab4 --- /dev/null +++ b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0 @@ -0,0 +1,67 @@ +#!/bin/bash + +# test for iptables-restore --noflush skipping an explicitly requested chain +# flush because the chain did not exist when cache was fetched. In order to +# expect for that chain to appear when refreshing the transaction (due to a +# concurrent ruleset change), the chain flush job has to be present in batch +# job list (although disabled at first). +# The input line requesting chain flush is ':FOO - [0:0]'. RS1 and RS2 contents +# are crafted to cause EBUSY when deleting the BAR* chains if FOO is not +# flushed in the same transaction. + +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 +" + +NORS="*filter +COMMIT +" + +for n in $(seq 1 10); do + $XT_MULTI iptables-restore <<< "$NORS" + $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/xshared.c b/iptables/xshared.c index c1d1371a..7d97637f 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -249,15 +249,20 @@ void xs_init_match(struct xtables_match *match) static int xtables_lock(int wait, struct timeval *wait_interval) { struct timeval time_left, wait_time; + const char *lock_file; int fd, i = 0; time_left.tv_sec = wait; time_left.tv_usec = 0; - fd = open(XT_LOCK_NAME, O_CREAT, 0600); + lock_file = getenv("XTABLES_LOCKFILE"); + if (lock_file == NULL || lock_file[0] == '\0') + lock_file = XT_LOCK_NAME; + + fd = open(lock_file, O_CREAT, 0600); if (fd < 0) { fprintf(stderr, "Fatal: can't open lock file %s: %s\n", - XT_LOCK_NAME, strerror(errno)); + lock_file, strerror(errno)); return XT_LOCK_FAILED; } @@ -265,7 +270,7 @@ static int xtables_lock(int wait, struct timeval *wait_interval) if (flock(fd, LOCK_EX) == 0) return fd; - fprintf(stderr, "Can't lock %s: %s\n", XT_LOCK_NAME, + fprintf(stderr, "Can't lock %s: %s\n", lock_file, strerror(errno)); return XT_LOCK_BUSY; } diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 375a95d1..6641a21a 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -1155,7 +1155,7 @@ print_zero: /*case 7 :*/ /* atomic-init */ /*case 10:*/ /* atomic-save */ case 11: /* init-table */ - nft_cmd_table_flush(h, *table); + nft_cmd_table_flush(h, *table, false); return 1; /* replace->command = c; 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-restore.c b/iptables/xtables-restore.c index a3bb4f00..d2739497 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -61,7 +61,6 @@ static void print_usage(const char *name, const char *version) static const struct nft_xt_restore_cb restore_cb = { .commit = nft_commit, .abort = nft_abort, - .table_new = nft_cmd_table_new, .table_flush = nft_cmd_table_flush, .do_command = do_commandx, .chain_set = nft_cmd_chain_set, @@ -135,7 +134,7 @@ static void xtables_restore_parse_line(struct nft_handle *h, if (h->noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); if (cb->table_flush) - cb->table_flush(h, table); + cb->table_flush(h, table, verbose); } ret = 1; @@ -260,7 +259,7 @@ void xtables_restore_parse(struct nft_handle *h, struct nft_xt_restore_state state = {}; char buffer[10240] = {}; - if (!h->noflush) + if (!verbose && !h->noflush) nft_cache_level_set(h, NFT_CL_FAKE, NULL); line = 0; @@ -410,7 +409,6 @@ int xtables_ip6_restore_main(int argc, char *argv[]) static const struct nft_xt_restore_cb ebt_restore_cb = { .commit = nft_bridge_commit, - .table_new = nft_cmd_table_new, .table_flush = nft_cmd_table_flush, .do_command = do_commandeb, .chain_set = nft_cmd_chain_set, @@ -456,7 +454,6 @@ int xtables_eb_restore_main(int argc, char *argv[]) static const struct nft_xt_restore_cb arp_restore_cb = { .commit = nft_commit, - .table_new = nft_cmd_table_new, .table_flush = nft_cmd_table_flush, .do_command = do_commandarp, .chain_set = nft_cmd_chain_set, diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c index bb3d8cd3..92b0c911 100644 --- a/iptables/xtables-save.c +++ b/iptables/xtables-save.c @@ -92,7 +92,7 @@ __do_output(struct nft_handle *h, const char *tablename, void *data) printf("*%s\n", tablename); /* Dump out chain names first, * thereby preventing dependency conflicts */ - nft_chain_save(h, chain_list); + nftnl_chain_list_foreach(chain_list, nft_chain_save, h); nft_rule_save(h, tablename, d->format); if (d->commit) printf("COMMIT\n"); 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/iptables/xtables-translate.c b/iptables/xtables-translate.c index 5aa42496..575fb320 100644 --- a/iptables/xtables-translate.c +++ b/iptables/xtables-translate.c @@ -249,7 +249,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], cs.restore = restore; - if (!restore) + if (!restore && p.command != CMD_NONE) printf("nft "); switch (p.command) { @@ -310,13 +310,16 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[], break; case CMD_SET_POLICY: break; + case CMD_NONE: + ret = 1; + break; default: /* We should never reach this... */ printf("Unsupported command?\n"); exit(1); } - xtables_rule_matches_free(&cs.matches); + nft_clear_iptables_command_state(&cs); if (h->family == AF_INET) { free(args.s.addr.v4); 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 47da14bc..66b333b0 100644 --- a/libxtables/xtables.c +++ b/libxtables/xtables.c @@ -203,9 +203,12 @@ 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 */ struct dlreg { struct dlreg *next; @@ -237,6 +240,7 @@ static void dlreg_free(void) dlreg = next; } } +#endif void xtables_init(void) { @@ -267,7 +271,9 @@ void xtables_init(void) void xtables_fini(void) { +#ifndef NO_SHARED_LIBS dlreg_free(); +#endif } void xtables_set_nfproto(uint8_t nfproto) @@ -658,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"; @@ -679,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); @@ -774,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; @@ -790,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); @@ -946,8 +962,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); @@ -999,10 +1021,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 } /** @@ -1066,64 +1112,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; @@ -1134,13 +1143,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); @@ -1196,16 +1209,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. */ @@ -1214,54 +1251,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; @@ -1272,9 +1272,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 */ diff --git a/utils/Makefile.am b/utils/Makefile.am index d09a6974..42bd9737 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -14,6 +14,11 @@ sbin_PROGRAMS += nfnl_osf pkgdata_DATA += pf.os nfnl_osf_LDADD = ${libnfnetlink_LIBS} + +uninstall-hook: + dir=${DESTDIR}${pkgdatadir}; { \ + test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; \ + } || rmdir -p --ignore-fail-on-non-empty "$$dir" endif if ENABLE_BPFC |