nftables blocks ipv6-icmp multicast echos after upgrade

Hi!
I usually find my routers with a multicast ping like this:

ping -c 2 ff02::2%enp0s25

However, when I upgraded from tumbleweed 20221014-0 to 20221121-0, this stopped working. It appears as if I don’t get any replies any longer:

pony@katze:~> ping -c 2 ff02::2%enp0s25
PING ff02::2%enp0s25(ff02::2%enp0s25) 56 data bytes 

--- ff02::2%enp0s25 ping statistics --- 
2 packets transmitted, 0 received, 100% packet loss, time 1001ms

I found that the reason is that the nft chain filter_INPUT changed from


    chain filter_INPUT { # handle 165
        type filter hook input priority filter + 10; policy accept;
        ct state { established, related } accept # handle 169
        ct status dnat accept # handle 170
        iifname "lo" accept # handle 171
        jump filter_INPUT_ZONES # handle 175
        ct state invalid drop # handle 176
        reject with icmpx admin-prohibited # handle 177
    }

...]

    chain filter_INPUT_ZONES { # handle 173
        iifname "enp0s25" goto filter_IN_public # handle 502
        iifname "docker0" goto filter_IN_docker # handle 390
        goto filter_IN_public # handle 345
    }

...]

    chain filter_IN_public { # handle 274
        jump filter_INPUT_POLICIES_pre # handle 280
        jump filter_IN_public_pre # handle 281
        jump filter_IN_public_log # handle 282
        jump filter_IN_public_deny # handle 283
        jump filter_IN_public_allow # handle 284
        jump filter_IN_public_post # handle 285
        jump filter_INPUT_POLICIES_post # handle 286
        meta l4proto { icmp, ipv6-icmp } accept # handle 344
        reject with icmpx admin-prohibited # handle 287
    }

to


    chain filter_INPUT { # handle 22
        type filter hook input priority filter + 10; policy accept;
        ct state { established, related } accept # handle 26
        ct status dnat accept # handle 27
        ct state invalid log prefix "STATE_INVALID_DROP: " # handle 28
        ct state invalid drop # handle 29
        iifname "lo" accept # handle 30
        jump filter_INPUT_ZONES # handle 34
        log prefix "FINAL_REJECT: " # handle 35
        reject with icmpx admin-prohibited # handle 36
    }

What has changed is that

ct state invalid drop # handle 176

now comes before

meta l4proto { icmp, ipv6-icmp } accept

From the comments underneath this question: https://unix.stackexchange.com/questions/493831/multicast-icmpv6-comes-back-with-conntrack-state-invalid I get that it is normal that ct state ivalid matches.
Was the change of the order intentional? Meaning, is it a feature or is it a bug? I’m new with nftables and firewalls in general. I found out that I can fix it by adding a rule like this:

sudo nft add rule inet firewalld filter_INPUT handle 27 meta l4proto { icmp, ipv6-icmp } accept

But the rule disappears when I reboot. I couldn’t find a /etc/nftables.conf. How can I permanently add a rule?

Reading package changelog sometimes may be useful.

sudo nft add rule inet firewalld filter_INPUT handle 27 meta l4proto { icmp, ipv6-icmp } accept

Table firewalld is owned by - surprise - firewalld and should not be modified manually.

How can I permanently add a rule?

One way is to add firewalld direct rule that sets these packets as NOTRACK as suggested in commit e1d11e8691bf31d816ce556009a38bd7ebd40444. Otherwise create systemd service.

I have a hard time understanding how to add the correct direct rule.
First of all, the manual states that direct rules are depreciated and that I should use policies instead. But policies are applied after the

ct state invalid drop

rule. So I go for a direct rule anyways. The manual also says that with

FirewallBackend=nftables

direct rules were given a higher precedence than all other firewalld rules. Thats fine. Then I have to choose the right value for ipv, table, chain and priority. Because I want a nftables rule to be made, I would like ipv=“inet”, table=“firewalld”, chain=“filter_INPUT”. But the manual says I can only choose between ipv=“ipv4|ipv6|eb”. Additionally, I don’t know which priority I have to choose to get the rule in the right place. Then it wants me to define the rule in terms of arguments for iptables or ip6tables, which confuses me because I’m using nftables as backend. What should I write into the direct.xml file to fix my problem?

How can I get it to work with a systemd-service? That service would run ‘nft add …’ every time after firewalld reloads?

There are no nftables rules; all direct rules are iptables.

What should I write into the direct.xml file to fix my problem?

firewall-cmd --permanent --direct --add-rule ipv6 raw PREROUTING 0 -p icmpv6 -j CT --notrack

Add whatever additional arguments are needed. I actually tested that the above does allow replies to multicast ping.

That service would run ‘nft add …’ every time after firewalld reloads?

firewalld only manages firewalld table; if you add your rules to another table, it will be preserved across firewalld restart. So it is enough to run this service once on boot.

Thank you arvidjaar. That helped.

This article cleared my confusion about nftables and iptables: https://developers.redhat.com/blog/2020/08/18/iptables-the-two-variants-and-their-relationship-with-nftables#
I found the meaning of the target CT and the parameter --notrack in the manual for iptables-extensions.

Good, except it is entirely orthogonal to this discussion. There is no dependency on iptables-nft. Whether iptables-legacy or iptables-nft is used, it works exactly the same.