|
|
029dc7 |
From bbbebb7449605e62a0901b8d81ea2ed45044088b Mon Sep 17 00:00:00 2001
|
|
|
029dc7 |
From: Phil Sutter <phil@nwl.cc>
|
|
|
029dc7 |
Date: Thu, 7 Feb 2019 22:08:55 +0100
|
|
|
029dc7 |
Subject: [PATCH] ebtables-nft: Support user-defined chain policies
|
|
|
029dc7 |
|
|
|
029dc7 |
Legacy ebtables supports policies for user-defined chains - and what's
|
|
|
029dc7 |
worse, they default to ACCEPT unlike anywhere else. So lack of support
|
|
|
029dc7 |
for this braindead feature in ebtables-nft is actually a change of
|
|
|
029dc7 |
behaviour which very likely affects all ebtables users out there.
|
|
|
029dc7 |
|
|
|
029dc7 |
The solution implemented here uses an implicit (and transparent) last
|
|
|
029dc7 |
rule in all user-defined ebtables-nft chains with policy other than
|
|
|
029dc7 |
RETURN. This rule is identified by an nft comment
|
|
|
029dc7 |
"XTABLES_EB_INTERNAL_POLICY_RULE" (since commit ccf154d7420c0 ("xtables:
|
|
|
029dc7 |
Don't use native nftables comments") nft comments are not used
|
|
|
029dc7 |
otherwise).
|
|
|
029dc7 |
|
|
|
029dc7 |
To minimize interference with existing code, this policy rule is removed
|
|
|
029dc7 |
from chains during cache population and the policy is saved in
|
|
|
029dc7 |
NFTNL_CHAIN_POLICY attribute. When committing changes to the kernel,
|
|
|
029dc7 |
nft_commit() traverses through the list of chains and (re-)creates
|
|
|
029dc7 |
policy rules if required.
|
|
|
029dc7 |
|
|
|
029dc7 |
In ebtables-nft-restore, table flushes are problematic. To avoid weird
|
|
|
029dc7 |
kernel error responses, introduce a custom 'table_flush' callback which
|
|
|
029dc7 |
removes any pending policy rule add/remove jobs prior to creating the
|
|
|
029dc7 |
NFT_COMPAT_TABLE_FLUSH one.
|
|
|
029dc7 |
|
|
|
029dc7 |
I've hidden all this mess behind checks for h->family, so hopefully
|
|
|
029dc7 |
impact on {ip,ip6,arp}tables-nft should be negligible.
|
|
|
029dc7 |
|
|
|
029dc7 |
Signed-off-by: Phil Sutter <phil@nwl.cc>
|
|
|
029dc7 |
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
|
029dc7 |
Signed-off-by: Florian Westphal <fw@strlen.de>
|
|
|
029dc7 |
(cherry picked from commit aff1162b3e4b7ef805425a40306044c7d7dddc67)
|
|
|
029dc7 |
Signed-off-by: Phil Sutter <psutter@redhat.com>
|
|
|
029dc7 |
---
|
|
|
029dc7 |
iptables/nft-bridge.c | 2 +-
|
|
|
029dc7 |
iptables/nft.c | 228 +++++++++++++++++-
|
|
|
029dc7 |
iptables/nft.h | 4 +
|
|
|
029dc7 |
.../ebtables/0002-ebtables-save-restore_0 | 7 +
|
|
|
029dc7 |
iptables/xtables-eb.c | 20 +-
|
|
|
029dc7 |
iptables/xtables-restore.c | 23 +-
|
|
|
029dc7 |
6 files changed, 265 insertions(+), 19 deletions(-)
|
|
|
029dc7 |
|
|
|
029dc7 |
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
|
|
|
029dc7 |
index 2b79ca951cd92..a51792ef03ae1 100644
|
|
|
029dc7 |
--- a/iptables/nft-bridge.c
|
|
|
029dc7 |
+++ b/iptables/nft-bridge.c
|
|
|
029dc7 |
@@ -358,7 +358,7 @@ static void nft_bridge_print_header(unsigned int format, const char *chain,
|
|
|
029dc7 |
bool basechain, uint32_t refs, uint32_t entries)
|
|
|
029dc7 |
{
|
|
|
029dc7 |
printf("Bridge chain: %s, entries: %u, policy: %s\n",
|
|
|
029dc7 |
- chain, entries, basechain ? pol : "RETURN");
|
|
|
029dc7 |
+ chain, entries, pol ?: "RETURN");
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
static void print_matches_and_watchers(const struct iptables_command_state *cs,
|
|
|
029dc7 |
diff --git a/iptables/nft.c b/iptables/nft.c
|
|
|
029dc7 |
index 6129afdbad281..4fdc789d99928 100644
|
|
|
029dc7 |
--- a/iptables/nft.c
|
|
|
029dc7 |
+++ b/iptables/nft.c
|
|
|
029dc7 |
@@ -55,6 +55,7 @@
|
|
|
029dc7 |
#include "nft.h"
|
|
|
029dc7 |
#include "xshared.h" /* proto_to_name */
|
|
|
029dc7 |
#include "nft-shared.h"
|
|
|
029dc7 |
+#include "nft-bridge.h" /* EBT_NOPROTO */
|
|
|
029dc7 |
#include "xtables-config-parser.h"
|
|
|
029dc7 |
|
|
|
029dc7 |
static void *nft_fn;
|
|
|
029dc7 |
@@ -1325,6 +1326,87 @@ retry:
|
|
|
029dc7 |
return ret;
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
+static bool nft_rule_is_policy_rule(struct nftnl_rule *r)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
|
|
|
029dc7 |
+ const void *data;
|
|
|
029dc7 |
+ uint32_t len;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!nftnl_rule_is_set(r, NFTNL_RULE_USERDATA))
|
|
|
029dc7 |
+ return false;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len;;
|
|
|
029dc7 |
+ if (nftnl_udata_parse(data, len, parse_udata_cb, tb) < 0)
|
|
|
029dc7 |
+ return NULL;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!tb[UDATA_TYPE_EBTABLES_POLICY] ||
|
|
|
029dc7 |
+ nftnl_udata_get_u32(tb[UDATA_TYPE_EBTABLES_POLICY]) != 1)
|
|
|
029dc7 |
+ return false;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ return true;
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+static struct nftnl_rule *nft_chain_last_rule(struct nftnl_chain *c)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ struct nftnl_rule *r = NULL, *last;
|
|
|
029dc7 |
+ struct nftnl_rule_iter *iter;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ iter = nftnl_rule_iter_create(c);
|
|
|
029dc7 |
+ if (!iter)
|
|
|
029dc7 |
+ return NULL;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ do {
|
|
|
029dc7 |
+ last = r;
|
|
|
029dc7 |
+ r = nftnl_rule_iter_next(iter);
|
|
|
029dc7 |
+ } while (r);
|
|
|
029dc7 |
+ nftnl_rule_iter_destroy(iter);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ return last;
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+static void nft_bridge_chain_postprocess(struct nft_handle *h,
|
|
|
029dc7 |
+ struct nftnl_chain *c)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ struct nftnl_rule *last = nft_chain_last_rule(c);
|
|
|
029dc7 |
+ struct nftnl_expr_iter *iter;
|
|
|
029dc7 |
+ struct nftnl_expr *expr;
|
|
|
029dc7 |
+ int verdict;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!last || !nft_rule_is_policy_rule(last))
|
|
|
029dc7 |
+ return;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ iter = nftnl_expr_iter_create(last);
|
|
|
029dc7 |
+ if (!iter)
|
|
|
029dc7 |
+ return;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ expr = nftnl_expr_iter_next(iter);
|
|
|
029dc7 |
+ if (!expr ||
|
|
|
029dc7 |
+ strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)))
|
|
|
029dc7 |
+ goto out_iter;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ expr = nftnl_expr_iter_next(iter);
|
|
|
029dc7 |
+ if (!expr ||
|
|
|
029dc7 |
+ strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME)) ||
|
|
|
029dc7 |
+ !nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT))
|
|
|
029dc7 |
+ goto out_iter;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT);
|
|
|
029dc7 |
+ switch (verdict) {
|
|
|
029dc7 |
+ case NF_ACCEPT:
|
|
|
029dc7 |
+ case NF_DROP:
|
|
|
029dc7 |
+ break;
|
|
|
029dc7 |
+ default:
|
|
|
029dc7 |
+ goto out_iter;
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict);
|
|
|
029dc7 |
+ if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, last) < 0)
|
|
|
029dc7 |
+ fprintf(stderr, "Failed to delete old policy rule\n");
|
|
|
029dc7 |
+ nftnl_chain_rule_del(last);
|
|
|
029dc7 |
+out_iter:
|
|
|
029dc7 |
+ nftnl_expr_iter_destroy(iter);
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data)
|
|
|
029dc7 |
{
|
|
|
029dc7 |
struct nftnl_chain *c = data;
|
|
|
029dc7 |
@@ -1378,6 +1460,10 @@ retry:
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
nftnl_rule_free(rule);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (h->family == NFPROTO_BRIDGE)
|
|
|
029dc7 |
+ nft_bridge_chain_postprocess(h, c);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
return 0;
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
@@ -1443,6 +1529,15 @@ int nft_chain_save(struct nft_handle *h, struct nftnl_chain_list *list)
|
|
|
029dc7 |
if (nftnl_chain_get(c, NFTNL_CHAIN_POLICY))
|
|
|
029dc7 |
pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
|
|
|
029dc7 |
policy = policy_name[pol];
|
|
|
029dc7 |
+ } else if (h->family == NFPROTO_BRIDGE) {
|
|
|
029dc7 |
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY)) {
|
|
|
029dc7 |
+ uint32_t pol;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ pol = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
|
|
|
029dc7 |
+ policy = policy_name[pol];
|
|
|
029dc7 |
+ } else {
|
|
|
029dc7 |
+ policy = "RETURN";
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
if (ops->save_chain)
|
|
|
029dc7 |
@@ -1637,6 +1732,8 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
|
|
|
029dc7 |
|
|
|
029dc7 |
nftnl_chain_set(c, NFTNL_CHAIN_TABLE, (char *)table);
|
|
|
029dc7 |
nftnl_chain_set(c, NFTNL_CHAIN_NAME, (char *)chain);
|
|
|
029dc7 |
+ if (h->family == NFPROTO_BRIDGE)
|
|
|
029dc7 |
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
|
|
|
029dc7 |
|
|
|
029dc7 |
ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
|
|
|
029dc7 |
|
|
|
029dc7 |
@@ -2278,7 +2375,6 @@ static void __nft_print_header(struct nft_handle *h,
|
|
|
029dc7 |
struct nftnl_chain *c, unsigned int format)
|
|
|
029dc7 |
{
|
|
|
029dc7 |
const char *chain_name = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
|
|
|
029dc7 |
- uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
|
|
|
029dc7 |
bool basechain = !!nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM);
|
|
|
029dc7 |
uint32_t refs = nftnl_chain_get_u32(c, NFTNL_CHAIN_USE);
|
|
|
029dc7 |
uint32_t entries = nft_rule_count(h, c);
|
|
|
029dc7 |
@@ -2286,8 +2382,12 @@ static void __nft_print_header(struct nft_handle *h,
|
|
|
029dc7 |
.pcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_PACKETS),
|
|
|
029dc7 |
.bcnt = nftnl_chain_get_u64(c, NFTNL_CHAIN_BYTES),
|
|
|
029dc7 |
};
|
|
|
029dc7 |
+ const char *pname = NULL;
|
|
|
029dc7 |
|
|
|
029dc7 |
- ops->print_header(format, chain_name, policy_name[policy],
|
|
|
029dc7 |
+ if (nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
|
|
|
029dc7 |
+ pname = policy_name[nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY)];
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ ops->print_header(format, chain_name, pname,
|
|
|
029dc7 |
&ctrs, basechain, refs - entries, entries);
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
@@ -2671,8 +2771,111 @@ static int nft_action(struct nft_handle *h, int action)
|
|
|
029dc7 |
return ret == 0 ? 1 : 0;
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
+static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY);
|
|
|
029dc7 |
+ struct iptables_command_state cs = {
|
|
|
029dc7 |
+ .eb.bitmask = EBT_NOPROTO,
|
|
|
029dc7 |
+ };
|
|
|
029dc7 |
+ struct nftnl_udata_buf *udata;
|
|
|
029dc7 |
+ struct nft_handle *h = data;
|
|
|
029dc7 |
+ struct nftnl_rule *r;
|
|
|
029dc7 |
+ const char *pname;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (nftnl_chain_get(c, NFTNL_CHAIN_HOOKNUM))
|
|
|
029dc7 |
+ return 0; /* ignore base chains */
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!nftnl_chain_is_set(c, NFTNL_CHAIN_POLICY))
|
|
|
029dc7 |
+ return 0;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ nftnl_chain_unset(c, NFTNL_CHAIN_POLICY);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ switch (policy) {
|
|
|
029dc7 |
+ case NFT_RETURN:
|
|
|
029dc7 |
+ return 0; /* return policy is default for nft chains */
|
|
|
029dc7 |
+ case NF_ACCEPT:
|
|
|
029dc7 |
+ pname = "ACCEPT";
|
|
|
029dc7 |
+ break;
|
|
|
029dc7 |
+ case NF_DROP:
|
|
|
029dc7 |
+ pname = "DROP";
|
|
|
029dc7 |
+ break;
|
|
|
029dc7 |
+ default:
|
|
|
029dc7 |
+ return -1;
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ command_jump(&cs, pname);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
|
|
|
029dc7 |
+ nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
|
|
|
029dc7 |
+ if (!r)
|
|
|
029dc7 |
+ return -1;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
|
|
|
029dc7 |
+ if (!udata)
|
|
|
029dc7 |
+ return -1;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!nftnl_udata_put_u32(udata, UDATA_TYPE_EBTABLES_POLICY, 1))
|
|
|
029dc7 |
+ return -1;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
|
|
|
029dc7 |
+ nftnl_udata_buf_data(udata),
|
|
|
029dc7 |
+ nftnl_udata_buf_len(udata));
|
|
|
029dc7 |
+ nftnl_udata_buf_free(udata);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (batch_rule_add(h, NFT_COMPAT_RULE_APPEND, r) < 0) {
|
|
|
029dc7 |
+ nftnl_rule_free(r);
|
|
|
029dc7 |
+ return -1;
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ return 0;
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
|
|
|
029dc7 |
+ const char *chain, const char *policy)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ struct nftnl_chain *c = nft_chain_find(h, table, chain);
|
|
|
029dc7 |
+ int pval;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!c)
|
|
|
029dc7 |
+ return 0;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!strcmp(policy, "DROP"))
|
|
|
029dc7 |
+ pval = NF_DROP;
|
|
|
029dc7 |
+ else if (!strcmp(policy, "ACCEPT"))
|
|
|
029dc7 |
+ pval = NF_ACCEPT;
|
|
|
029dc7 |
+ else if (!strcmp(policy, "RETURN"))
|
|
|
029dc7 |
+ pval = NFT_RETURN;
|
|
|
029dc7 |
+ else
|
|
|
029dc7 |
+ return 0;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, pval);
|
|
|
029dc7 |
+ return 1;
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+static void nft_bridge_commit_prepare(struct nft_handle *h)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ const struct builtin_table *t;
|
|
|
029dc7 |
+ struct nftnl_chain_list *list;
|
|
|
029dc7 |
+ int i;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ for (i = 0; i < NFT_TABLE_MAX; i++) {
|
|
|
029dc7 |
+ t = &h->tables[i];
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!t->name)
|
|
|
029dc7 |
+ continue;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ list = h->table[t->type].chain_cache;
|
|
|
029dc7 |
+ if (!list)
|
|
|
029dc7 |
+ continue;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ nftnl_chain_list_foreach(list, ebt_add_policy_rule, h);
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
int nft_commit(struct nft_handle *h)
|
|
|
029dc7 |
{
|
|
|
029dc7 |
+ if (h->family == NFPROTO_BRIDGE)
|
|
|
029dc7 |
+ nft_bridge_commit_prepare(h);
|
|
|
029dc7 |
return nft_action(h, NFT_COMPAT_COMMIT);
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
@@ -2681,6 +2884,27 @@ int nft_abort(struct nft_handle *h)
|
|
|
029dc7 |
return nft_action(h, NFT_COMPAT_ABORT);
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
+int nft_abort_policy_rule(struct nft_handle *h, const char *table)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ struct obj_update *n, *tmp;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
|
|
|
029dc7 |
+ if (n->type != NFT_COMPAT_RULE_APPEND &&
|
|
|
029dc7 |
+ n->type != NFT_COMPAT_RULE_DELETE)
|
|
|
029dc7 |
+ continue;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (strcmp(table,
|
|
|
029dc7 |
+ nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE)))
|
|
|
029dc7 |
+ continue;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ if (!nft_rule_is_policy_rule(n->rule))
|
|
|
029dc7 |
+ continue;
|
|
|
029dc7 |
+
|
|
|
029dc7 |
+ batch_obj_del(h, n);
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
+ return 0;
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
int nft_compatible_revision(const char *name, uint8_t rev, int opt)
|
|
|
029dc7 |
{
|
|
|
029dc7 |
struct mnl_socket *nl;
|
|
|
029dc7 |
diff --git a/iptables/nft.h b/iptables/nft.h
|
|
|
029dc7 |
index 0726923a63dd4..56dc207608855 100644
|
|
|
029dc7 |
--- a/iptables/nft.h
|
|
|
029dc7 |
+++ b/iptables/nft.h
|
|
|
029dc7 |
@@ -137,6 +137,7 @@ uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag);
|
|
|
029dc7 |
*/
|
|
|
029dc7 |
int nft_commit(struct nft_handle *h);
|
|
|
029dc7 |
int nft_abort(struct nft_handle *h);
|
|
|
029dc7 |
+int nft_abort_policy_rule(struct nft_handle *h, const char *table);
|
|
|
029dc7 |
|
|
|
029dc7 |
/*
|
|
|
029dc7 |
* revision compatibility.
|
|
|
029dc7 |
@@ -203,4 +204,7 @@ void nft_rule_to_arpt_entry(struct nftnl_rule *r, struct arpt_entry *fw);
|
|
|
029dc7 |
|
|
|
029dc7 |
bool nft_is_table_compatible(struct nft_handle *h, const char *name);
|
|
|
029dc7 |
|
|
|
029dc7 |
+int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
|
|
|
029dc7 |
+ const char *chain, const char *policy);
|
|
|
029dc7 |
+
|
|
|
029dc7 |
#endif
|
|
|
029dc7 |
diff --git a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
|
|
|
029dc7 |
index b23c1ee18c8ae..080ba49a4974d 100755
|
|
|
029dc7 |
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
|
|
|
029dc7 |
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
|
|
|
029dc7 |
@@ -50,6 +50,9 @@ $XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT
|
|
|
029dc7 |
|
|
|
029dc7 |
$XT_MULTI ebtables -A FORWARD -j foo
|
|
|
029dc7 |
|
|
|
029dc7 |
+$XT_MULTI ebtables -N bar
|
|
|
029dc7 |
+$XT_MULTI ebtables -P bar RETURN
|
|
|
029dc7 |
+
|
|
|
029dc7 |
$XT_MULTI ebtables -t nat -A PREROUTING --redirect-target ACCEPT
|
|
|
029dc7 |
#$XT_MULTI ebtables -t nat -A PREROUTING --to-src fe:ed:ba:be:00:01
|
|
|
029dc7 |
|
|
|
029dc7 |
@@ -59,6 +62,8 @@ $XT_MULTI ebtables -t nat -P OUTPUT DROP
|
|
|
029dc7 |
$XT_MULTI ebtables -t nat -A POSTROUTING -j ACCEPT
|
|
|
029dc7 |
#$XT_MULTI ebtables -t nat -A POSTROUTING --to-dst fe:ed:ba:be:00:01 --dnat-target ACCEPT
|
|
|
029dc7 |
|
|
|
029dc7 |
+$XT_MULTI ebtables -t nat -N nat_foo -P DROP
|
|
|
029dc7 |
+
|
|
|
029dc7 |
# compare against stored ebtables dump
|
|
|
029dc7 |
|
|
|
029dc7 |
DUMP='*filter
|
|
|
029dc7 |
@@ -66,6 +71,7 @@ DUMP='*filter
|
|
|
029dc7 |
:FORWARD DROP
|
|
|
029dc7 |
:OUTPUT ACCEPT
|
|
|
029dc7 |
:foo ACCEPT
|
|
|
029dc7 |
+:bar RETURN
|
|
|
029dc7 |
-A INPUT -p IPv4 -i lo -j ACCEPT
|
|
|
029dc7 |
-A FORWARD -j foo
|
|
|
029dc7 |
-A OUTPUT -s Broadcast -j DROP
|
|
|
029dc7 |
@@ -98,6 +104,7 @@ DUMP='*filter
|
|
|
029dc7 |
:PREROUTING ACCEPT
|
|
|
029dc7 |
:OUTPUT DROP
|
|
|
029dc7 |
:POSTROUTING ACCEPT
|
|
|
029dc7 |
+:nat_foo DROP
|
|
|
029dc7 |
-A PREROUTING -j redirect
|
|
|
029dc7 |
-A OUTPUT -j ACCEPT
|
|
|
029dc7 |
-A POSTROUTING -j ACCEPT
|
|
|
029dc7 |
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
|
|
|
029dc7 |
index 21344843a365a..d0f0026e9c538 100644
|
|
|
029dc7 |
--- a/iptables/xtables-eb.c
|
|
|
029dc7 |
+++ b/iptables/xtables-eb.c
|
|
|
029dc7 |
@@ -811,7 +811,6 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
|
|
|
029dc7 |
case 'E': /* Rename chain */
|
|
|
029dc7 |
case 'X': /* Delete chain */
|
|
|
029dc7 |
/* We allow -N chainname -P policy */
|
|
|
029dc7 |
- /* XXX: Not in ebtables-compat */
|
|
|
029dc7 |
if (command == 'N' && c == 'P') {
|
|
|
029dc7 |
command = c;
|
|
|
029dc7 |
optind--; /* No table specified */
|
|
|
029dc7 |
@@ -1236,17 +1235,16 @@ print_zero:
|
|
|
029dc7 |
|
|
|
029dc7 |
if (command == 'P') {
|
|
|
029dc7 |
if (selected_chain < 0) {
|
|
|
029dc7 |
- xtables_error(PARAMETER_PROBLEM,
|
|
|
029dc7 |
- "Policy %s not allowed for user defined chains",
|
|
|
029dc7 |
- policy);
|
|
|
029dc7 |
- }
|
|
|
029dc7 |
- if (strcmp(policy, "RETURN") == 0) {
|
|
|
029dc7 |
- xtables_error(PARAMETER_PROBLEM,
|
|
|
029dc7 |
- "Policy RETURN only allowed for user defined chains");
|
|
|
029dc7 |
+ ret = ebt_set_user_chain_policy(h, *table, chain, policy);
|
|
|
029dc7 |
+ } else {
|
|
|
029dc7 |
+ if (strcmp(policy, "RETURN") == 0) {
|
|
|
029dc7 |
+ xtables_error(PARAMETER_PROBLEM,
|
|
|
029dc7 |
+ "Policy RETURN only allowed for user defined chains");
|
|
|
029dc7 |
+ }
|
|
|
029dc7 |
+ ret = nft_chain_set(h, *table, chain, policy, NULL);
|
|
|
029dc7 |
+ if (ret < 0)
|
|
|
029dc7 |
+ xtables_error(PARAMETER_PROBLEM, "Wrong policy");
|
|
|
029dc7 |
}
|
|
|
029dc7 |
- ret = nft_chain_set(h, *table, chain, policy, NULL);
|
|
|
029dc7 |
- if (ret < 0)
|
|
|
029dc7 |
- xtables_error(PARAMETER_PROBLEM, "Wrong policy");
|
|
|
029dc7 |
} else if (command == 'L') {
|
|
|
029dc7 |
ret = list_rules(h, chain, *table, rule_nr,
|
|
|
029dc7 |
0,
|
|
|
029dc7 |
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
|
|
|
029dc7 |
index 4e00ed86be06d..6e6daffc9a1df 100644
|
|
|
029dc7 |
--- a/iptables/xtables-restore.c
|
|
|
029dc7 |
+++ b/iptables/xtables-restore.c
|
|
|
029dc7 |
@@ -226,14 +226,20 @@ void xtables_restore_parse(struct nft_handle *h,
|
|
|
029dc7 |
curtable->name, chain);
|
|
|
029dc7 |
} else if (cb->chain_user_add &&
|
|
|
029dc7 |
cb->chain_user_add(h, chain,
|
|
|
029dc7 |
- curtable->name) < 0) {
|
|
|
029dc7 |
- if (errno == EEXIST)
|
|
|
029dc7 |
- continue;
|
|
|
029dc7 |
-
|
|
|
029dc7 |
+ curtable->name) < 0 &&
|
|
|
029dc7 |
+ errno != EEXIST) {
|
|
|
029dc7 |
xtables_error(PARAMETER_PROBLEM,
|
|
|
029dc7 |
"cannot create chain "
|
|
|
029dc7 |
"'%s' (%s)\n", chain,
|
|
|
029dc7 |
strerror(errno));
|
|
|
029dc7 |
+ } else if (h->family == NFPROTO_BRIDGE &&
|
|
|
029dc7 |
+ !ebt_set_user_chain_policy(h, curtable->name,
|
|
|
029dc7 |
+ chain, policy)) {
|
|
|
029dc7 |
+ xtables_error(OTHER_PROBLEM,
|
|
|
029dc7 |
+ "Can't set policy `%s'"
|
|
|
029dc7 |
+ " on `%s' line %u: %s\n",
|
|
|
029dc7 |
+ policy, chain, line,
|
|
|
029dc7 |
+ ops->strerror(errno));
|
|
|
029dc7 |
}
|
|
|
029dc7 |
ret = 1;
|
|
|
029dc7 |
} else if (in_table) {
|
|
|
029dc7 |
@@ -462,11 +468,18 @@ int xtables_ip6_restore_main(int argc, char *argv[])
|
|
|
029dc7 |
argc, argv);
|
|
|
029dc7 |
}
|
|
|
029dc7 |
|
|
|
029dc7 |
+static int ebt_table_flush(struct nft_handle *h, const char *table)
|
|
|
029dc7 |
+{
|
|
|
029dc7 |
+ /* drop any pending policy rule add/removal jobs */
|
|
|
029dc7 |
+ nft_abort_policy_rule(h, table);
|
|
|
029dc7 |
+ return nft_table_flush(h, table);
|
|
|
029dc7 |
+}
|
|
|
029dc7 |
+
|
|
|
029dc7 |
struct nft_xt_restore_cb ebt_restore_cb = {
|
|
|
029dc7 |
.chain_list = get_chain_list,
|
|
|
029dc7 |
.commit = nft_commit,
|
|
|
029dc7 |
.table_new = nft_table_new,
|
|
|
029dc7 |
- .table_flush = nft_table_flush,
|
|
|
029dc7 |
+ .table_flush = ebt_table_flush,
|
|
|
029dc7 |
.chain_user_flush = nft_chain_user_flush,
|
|
|
029dc7 |
.do_command = do_commandeb,
|
|
|
029dc7 |
.chain_set = nft_chain_set,
|
|
|
029dc7 |
--
|
|
|
029dc7 |
2.21.0
|
|
|
029dc7 |
|