NFTABLE issue: IPv6 does not behave like IPv4 with mirror config

I have an issue with IPv6 on my server. I have nginx configured to listen on port 443 from IPv4 and IPv6. And it works great: my webiste is available form Internet with TLS enabled.

Things get complicated when I activate nftables: when I am accessing my website from IPv4 it works, but when I access it from IPv6 connections time out :(

Output of sudo nft list ruleset:

table inet filter {
        chain INPUT {
                type filter hook input priority filter; policy drop;
                meta nftrace set 1
                ct state established,related accept comment "allow established connections"
                iif "lo" accept comment "allow all from localhost"
                iif != "lo" ip daddr 127.0.0.0/8 counter packets 0 bytes 0 drop comment "drop connections to loopback not coming from loopback"
                iif != "lo" ip6 daddr ::1 counter packets 0 bytes 0 drop comment "drop connections to loopback not coming from loopback"
                iifname "tunnel0" accept comment "allow all from VPN"
                udp dport 12345 accept comment "allow VPN on port 12345"
                tcp dport { 22, 80, 443 } accept comment "allow HTTP, HTTPS and SSH on classic ports"
        }

        chain OUTPUT {
                type filter hook output priority filter; policy accept;
        }

        chain FORWARD {
                type filter hook forward priority filter; policy drop;
        }
}

Output of sudo nft monitor trace | grep 443:

trace id 76d7cb1a inet filter INPUT packet: iif "eth0" ether saddr AA:AA:AA:AA:AA:AA ether daddr BB:BB:BB:BB:BB:BB ip6 saddr 2a01:cb09:804b:cd61:CCCC:CCCC:CCCC:CCCC ip6 daddr 2001:CCCC:CCCC:CCCC::CCCC ip6 dscp cs0 ip6 ecn not-ect ip6 hoplimit 45 ip6 flowlabel 0 ip6 nexthdr tcp ip6 length 40 tcp sport 53184 tcp dport 443 tcp flags == syn tcp window 22240

Note I do not have this issue with ssh on port 22. I am running nftables v0.9.8 (E.D.S.) on Debian 11.

I almost spent a day looking for the solution. Any help is welcome! Thank


Solution 1:

ICMPv6, which is a protocol over IPv6, implements the link layer resolution using multicast and unicast. Dropping ICMPv6 means there is no resolution available anymore: nodes can't find other nodes in the same LAN. This includes the upstream IPv6 router which can't communicate with the Linux system using IPv6 if ICMPv6 is dropped.

By contrast IPv4 relies on a different protocol: ARP (using broadcast and unicast), which is not over IPv4. So one can drop all of ICMP and suffer no LAN connectivity issue since ARP is unaffected (but one can still suffer from PMTU blackhole and other similar issues when dropping all of ICMP, especially when using tunnels).

So start by enabling all of ICMPv6 then, in a second time once you validate that IPv6 is working again, if you don't want to enable all of it check what to selectively accept in the Neighbor Discovery Protocol (for a non-routing node I would say at least types 134, 135, 136 and 137):

nft add rule inet filter INPUT 'icmpv6 type { 134, 135, 136, 137 } accept'