Phil Sutter <phil@xxxxxx> wrote: > > after "ebtables -P FOOBAR RETURN". > > Reverting this hunk shows "RETURN" as expected. > > Oh. I missed that case. Of course that's not a real solution, otherwise > user-defined chain policies will always show up as RETURN. I'll find a > real fix. Disregard that, I was low on caffeeine. Attached patch makes things work much better for me (no need to take this, consider it a bit more verbose bug report). Not perfect, and one major issue remains. When someone munges the chain using native nft, ebtables-nft shows: Bridge chain: FOOBAR, entries: 1, policy: DROP -d 01:02:03:04:05:06 -j CONTINUE What it should show instead: Bridge chain: FOOBAR, entries: 1, policy: RETURN -j DROP -d 01:02:03:04:05:06 -j CONTINUE (because thats whats the actual state -- the last rule is unreachable). Not a huge deal if we're only interested in "ebtables-nft only". diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -358,7 +358,7 @@ static void nft_bridge_print_header(unsigned int format, const char *chain, bool basechain, uint32_t refs, uint32_t entries) { printf("Bridge chain: %s, entries: %u, policy: %s\n", - chain, entries, pol); + chain, entries, pol ? pol : "RETURN"); } static void print_matches_and_watchers(const struct iptables_command_state *cs, diff --git a/iptables/nft.c b/iptables/nft.c --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1324,6 +1324,11 @@ retry: #define EBT_POLICY_COMMENT "XTABLES_EB_INTERNAL_POLICY_RULE" +struct nftnl_rule_list_cb_data { + struct nft_handle *handle; + struct nftnl_chain *chain; +}; + static bool nft_rule_is_policy_rule(struct nftnl_rule *r) { const void *data; @@ -1341,47 +1346,56 @@ static bool nft_rule_is_policy_rule(struct nftnl_rule *r) return true; } -struct nftnl_rule_list_cb_data { - struct nft_handle *handle; - struct nftnl_chain *chain; -}; - -static int nft_convert_policy_rule(struct nft_handle *h, - struct nftnl_chain *c, struct nftnl_rule *r) +static void nft_bridge_chain_rule_add_tail(struct nft_handle *h, + struct nftnl_rule *r, struct nftnl_chain *c) { struct nftnl_expr_iter *iter; int verdict = NFT_RETURN; struct nftnl_expr *expr; + if (!nft_rule_is_policy_rule(r)) + goto out_add; + iter = nftnl_expr_iter_create(r); if (iter == NULL) - return 0; + goto out_add; expr = nftnl_expr_iter_next(iter); - while (expr != NULL) { - if (strcmp("immediate", - nftnl_expr_get_str(expr, NFTNL_EXPR_NAME))) { - expr = nftnl_expr_iter_next(iter); - continue; - } - verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT); - break; - } + if (!expr) + goto out_iter; + + if (strcmp("counter", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME))) + goto out_iter; + + expr = nftnl_expr_iter_next(iter); + if (strcmp("immediate", nftnl_expr_get_str(expr, NFTNL_EXPR_NAME))) + goto out_iter; + nftnl_expr_iter_destroy(iter); + /* rule must only consist of verdict (else its not unconditional) */ + if (!nftnl_expr_is_set(expr, NFTNL_EXPR_IMM_VERDICT)) + goto out_iter; + + verdict = nftnl_expr_get_u32(expr, NFTNL_EXPR_IMM_VERDICT); + switch (verdict) { case NF_ACCEPT: case NF_DROP: nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, verdict); break; + default: + goto out_add; } - if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r) < 0) { + if (batch_rule_add(h, NFT_COMPAT_RULE_DELETE, r) < 0) printf("%s: failed to delete old policy rule\n", __func__); - return -1; - } - return 0; + return; +out_iter: + nftnl_expr_iter_destroy(iter); +out_add: + nftnl_chain_rule_add_tail(r, c); } static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) @@ -1400,9 +1414,8 @@ static int nftnl_rule_list_cb(const struct nlmsghdr *nlh, void *data) return MNL_CB_OK; } - if (h->family == NFPROTO_BRIDGE && - nft_rule_is_policy_rule(r)) - nft_convert_policy_rule(h, c, r); + if (h->family == NFPROTO_BRIDGE) + nft_bridge_chain_rule_add_tail(h, r, c); else nftnl_chain_rule_add_tail(r, c); @@ -2758,7 +2771,9 @@ static int nft_action(struct nft_handle *h, int action) static int ebt_add_policy_rule(struct nftnl_chain *c, void *data) { uint32_t policy = nftnl_chain_get_u32(c, NFTNL_CHAIN_POLICY); - struct iptables_command_state cs = {}; + struct iptables_command_state cs = { + .eb.bitmask = 0x2, + }; struct nftnl_udata_buf *udata; struct nft_handle *h = data; struct nftnl_rule *r;