Bug 1837129 - Direct rules with ACCEPT verdict not working with nftables backend
Summary: Direct rules with ACCEPT verdict not working with nftables backend
Keywords:
Status: CLOSED CANTFIX
Alias: None
Product: Fedora
Classification: Fedora
Component: firewalld
Version: 32
Hardware: Unspecified
OS: Linux
unspecified
unspecified
Target Milestone: ---
Assignee: Eric Garver
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2020-05-18 21:42 UTC by Oleg Girko
Modified: 2020-05-18 23:17 UTC (History)
2 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2020-05-18 23:17:56 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Oleg Girko 2020-05-18 21:42:30 UTC
Description of problem:
After upgrading to Fedora 32, firewalld uses nftables backend by default.
I've switched iptables command line utilities to use alternative provided by iptables-nft.
Unfortunately, firewalld doesn't support packet forwarding rules, so the only way to allow packet forwarding is using direct rules.
However, when I add a direct rule to FORWARD chain with ACCEPT verdict, it's not honoured.

Version-Release number of selected component (if applicable):
0.8.2

How reproducible:
Always.

Steps to Reproduce:
1. Configure firewalld with at least two zones (say, external and internal).
2. Add direct rule using FORWARD chain allowing connections to some host in internal zone:
firewall-cmd --direct --add-rule ipv6 filter FORWARD -200 -d XXXX:XXXX:XXXX:1::1 -p tcp -m tcp --dport 22 -j ACCEPT
(where XXXX:XXXX:XXXX:1::1 is IPv6 address of a host behind an interface in internal zone).
3. Try to connect to this IPv6 address from outside.

Actual results:
telnet: connect to address XXXX:XXXX:XXXX:1::1: Permission denied

Expected results:
Successful connection.

Additional info:
nft -y list ruleset
shows the following:

table ip6 filter {
        ...
        chain FORWARD {
                type filter hook forward priority 0; policy accept;
                meta l4proto tcp ip6 daddr XXXX:XXXX:XXXX:1::1 tcp dport 22 counter packets 4 bytes 320 accept
        }
        ...
}
...
table inet firewalld {
        ...
        chain filter_FORWARD {
                type filter hook forward priority 10; policy accept;
                ct state { established, related } accept
                ct status dnat accept
                iifname "lo" accept
                ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } log prefix "RFC3964_IPv4_REJECT: " reject with icmpv6 type addr-unreachable
                jump filter_FORWARD_IN_ZONES
                jump filter_FORWARD_OUT_ZONES
                ct state { invalid } log prefix "STATE_INVALID_DROP: "
                ct state { invalid } drop
                log prefix "FINAL_REJECT: "
                reject with icmpx type admin-prohibited
        }
        ...
}
...

This means that firewalld adds rules it generates to firewalld table, whereas direct rules are added to filter table.
And although FORWARD chain of filter table has higher priority than filter_FORWARD chain of firewalld table, accept statement finishes just FORWARD chain of filter table, not all chains.
This is documented behaviour.

From https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains :

> *NOTE:* if a packet gets accepted and there is another base chain in the same hook which is ordered with a later priority, the packet will be evaluated *again*. That is, packets will traverse chains in a given hook, until it is dropped or no more base chains exist. Drops take instant effect, no further rules or chains are evaluated.

In order to make direct rules with ACCEPT verdict work, they should be added to a chain inside firewalld table that is jumped to from filter_FORWARD chain, not to a separate base chain in a separate table.

Comment 1 Eric Garver 2020-05-18 23:17:56 UTC
This is known. See the Change [1]. It explains the behavior. See also the firewalld.direct(5) man page CAVEATS section [2]. firewalld upstream is working on full forward/output support [3]. But it's not ready yet.

Your workaround options are:

  1) revert to the iptables backend by setting FirewallBackend=iptables in /etc/firewalld/firewalld.conf
  2) Add the relevant interfaces/sources to the trusted zone and do all your filtering in the direct interface.

[1]: https://fedoraproject.org/wiki/Changes/firewalld_default_to_nftables#Upgrade.2Fcompatibility_impact
[2]: https://firewalld.org/documentation/man-pages/firewalld.direct.html
[3]: https://github.com/orgs/firewalld/projects/1#card-25963208


Note You need to log in before you can comment on or make changes to this bug.