Accept established not working for DHCPv6

Here are my IPv6 firewall rules:

/ipv6 firewall filter
add action=accept chain=input protocol=icmpv6
add action=accept chain=input in-interface=switch
add action=accept chain=input connection-state=established,related
add action=accept chain=forward connection-state=established,related
add action=accept chain=forward in-interface=switch out-interface=dsl
add action=accept chain=forward in-interface=vlan-guests out-interface=dsl
add action=accept chain=input comment="Workaround for DHCPv6" dst-port=546 protocol=udp
add action=drop chain=input
add action=drop chain=forward

I have a DHCPv6 client as well:

/ipv6 dhcp-client
add add-default-route=yes dhcp-options=option_req dhcp-options=option_req interface=dsl pool-name=dsl pool-prefix-length=60 request=prefix script=":log info (\$options->\"64\");" use-peer-dns=no

I have put a comment “Workaround for DHCPv6” on one rule. Without that rule the DHCPv6 client cannot get an IP address. But shouldn’t it? UDP is tracked just like TCP, otherwise NAT traversal wouldn’t be possible, right? Then why does the “established,related” rule not allow the DHCPv6 response through?

I can even see the connection in the Connections table:
2024-12-01-03-34-33-winbox3.png
It doesn’t have a state though, maybe that is the issue? If yes, then how can I match it with a rule?

The main thing, I would say, is that DHCPv6 starts by sending a “Solicit” packet to a multicast address (ff02::1:2) and the connection tracking module can’t be quite sure that the “Advertise” or “Reply” packet that comes back (depending on availability of Rapid Commit) can be classified as “related”. But there are even more nuances to this, of course.

Since RouterOS uses the Linux kernel underneath (and, thus, netfilter/iptables), we are able to find longer discussions on this issue. Here are some insightful examples:

https://unix.stackexchange.com/questions/593357/why-do-we-need-to-have-an-ip6tables-rule-for-dhcp6-to-work-by-contrast-ipv4-d/593359#593359

https://serverfault.com/questions/250797/stateful-matching-of-multicast-responses-in-iptables/250804#250804

That’s because the protocol use multicast. The ff02::1:2 address that you see in your screenshot is a multicast address.

https://datatracker.ietf.org/doc/html/rfc8415#section-5

A DHCP client sends most messages using a reserved, link-scoped
multicast destination address so that the client need not be
configured with the address or addresses of DHCP servers.

When the server responds, it will of course not be able to use ff02::1:2 as source address for its packets, but a fe80::/10 address, which means the packets will not be tracked as part of the previous outgoing connection.

BTW, the rule for DHCPv6 client in the MikroTik defconf firewall is:

/ipv6 firewall filter
add action=accept chain=input comment="defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=udp src-address=fe80::/10

And includes the restriction for src-address. You should use that too, to restrict the incoming packets to the local link layer.

Whenever possible, yes, restricting the source address to link-local is the way to go.

However, that’s not always the case, like with this ISP from the USA: Xfinity (Comcast) DHCPv6 configuration change!

So it is better to restrict it, but be prepared to loosen it in case it is needed.