ND for ipv6 in nftables

George Shuklin
OpsOps
Published in
2 min readMar 7, 2024

I just spend few days debugging absolutely simple problem.

My servers wasn’t able to communicate after applying nftables rules with policy deny.

The rule was very simple:

iifname eth0 ip6 saddr @good ip6 daddr @good accept

with @good been list of good IPs.

The symptoms was maddening. I can see it working, but as soon as I deploy those rules, it breaks apart. I fiddle around, get back to this config and it works.

I knew about conntrack issue (e.g. if your firewall letted some traffic to pass, denying it won’t kill existing sessions if you have ct establshied accept ), but resetting conntrack didn’t change a thing.

Sometimes it worked with one protocol (e.g. icmp) and didn’t worked with other (https). I suspected million problems and tried them (I won’t list them, but believe me, there were a lot).

Until together with a colleague we started to explore some theory and tried to ping gateway, and it didn’t replied, I decided to see routes, and saw that neighbors are failing.

That was it.

I wasn’t able to resolve gateway mac, which is now an ICMP traffic on the multicast address in IPv6, instead of ARP for IPv4. It’s called ND (Neighbor Discovery). As long as mac table was ‘in’, traffic was passing. As soon as it expired on any of two servers (they had identical config), stop, no more traffic.

It was double maddening, because of two firewalls acting in unison (until I applied rule on one of it).

The solution is simple:

icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect } accept

But it had cost me two days of endless debugging.

ARP is Dead, Long Live <s>ARP</s> ND.

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.