Rate limiting ICMP flood with nftables

I'm trying to figure out how to allow ICMP pings to a server with nftables without being subject to flood attacks.

Here's my initial config:

table inet firewall {
    chain incoming {
        type filter hook input priority 0; policy drop;

        # established/related connections
        ct state { established, related } accept

        # ICMP
        ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
        ip protocol icmp icmp type { destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept

        # ICMP ping dealt with separately to rate limit
        ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 1/second accept
        ip protocol icmp icmp type echo-request limit rate 1/second accept
    }
}

However, flooding with ping -f [IP_ADDRESS] shows most packets getting through. Certainly more than one per second.

If I remove the ct state { established, related } accept rule I get 99% packet loss when trying to flood.

So it seems like the first request establishes a connection and subsequent pings ride in on that rule and it doesn't seem to matter if I put the ct rule after the icmp rule.

Any way to allow established connections but still rate limit pings?


Solution 1:

Try this solution:

table inet firewall {
    chain incoming {
        type filter hook input priority 0; policy drop;

        # ICMP ping dealt with separately to rate limit
        ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 1/second accept
        ip6 nexthdr icmpv6 icmpv6 type echo-request counter drop
        ip protocol icmp icmp type echo-request limit rate 1/second accept
        ip protocol icmp icmp type echo-request counter drop

        # established/related connections
        ct state { established, related } accept

        # ICMP
        ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-reply, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
        ip protocol icmp icmp type { destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept

    }
}

You should explicitly drop the packets, those exceeded ratelimit, to prevent accept they by rules below.