Index | Thread | Search

From:
Kristof Provost <kp@FreeBSD.org>
Subject:
pf(4) is still overly strict in filtering MLD messages
To:
tech@openbsd.org
Date:
Thu, 03 Sep 2026 10:07:08 +0200

Download raw body.

Thread
Hi,

I’ve gotten a bug report from a FreeBSD user that pf filters valid MLD messages.
Specifically, messages with an unspecified source address.
RFC 3590 explains that this can happen when doing duplicate address detection, and should be allowed for MLD Report and Done messages.

Specifically paragraph 4 MLD Source Address Selection Guidelines:

> MLD Query messages MUST be sent with a valid link-local address as
> the IPv6 source address.  If a node (router or host) receives a query
> message with an IPv6 source address set to the unspecified address
> (::), it MUST silently discard the message and SHOULD log a warning.

> MLD Report and Done messages are sent with a link-local address as
> the IPv6 source address, if a valid address is available on the
> interface.  If a valid link-local address is not available (e.g., one
> has not been configured), the message is sent with the unspecified
> address (::) as the IPv6 source address.

I propose the following:

diff --git a/sys/net/pf.c b/sys/net/pf.c
index 130843a03a1..5daa5c14249 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -7974,9 +7974,17 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
                                 * local source address.  If either one is
                                 * missing then MLD message is invalid and
                                 * should be discarded.
+                                * RFC 3590 clarifies that during initial
+                                * duplicate address detection nodes may not
+                                * have an address, so are permitted to use
+                                * the unspecified address, but only for Report
+                                * and Done messages.
                                 */
                                if ((h->ip6_hlim != 1) ||
-                                   !IN6_IS_ADDR_LINKLOCAL(&h->ip6_src)) {
+                                   (!IN6_IS_ADDR_LINKLOCAL(&h->ip6_src) &&
+                                    icmp6.icmp6_type == MLD_LISTENER_QUERY) ||
+                                   (!IN6_IS_ADDR_LINKLOCAL(&h->ip6_src) &&
+                                   !IN6_IS_ADDR_UNSPECIFIED(&h->ip6_src))) {
                                        DPFPRINTF(LOG_NOTICE, "Invalid MLD");
                                        REASON_SET(reason, PFRES_IPOPTIONS);
                                        return (PF_DROP);

(Patch against OpenBSD, but I’ve only tested it on FreeBSD.)

—
Kristof