hello,

bluhm@ has committed a fix [1] which makes pf to accept IGMP/MLD messages.
If I remember correct pf(4) was dropping those messages because
of Router Alert IP option being present. The IP option is mandatory
for IGMP/MLD according to RFCs.

For both protocol versions (IPv4, IPv6) standards say:

    TTL/hop-limit in IP header must be set to 1

    Router Alert option/extension header must be present

in case of IPv6 the MLD messages must be sent from link-local address.


diff below adds exactly those checks.

OK?

thanks and
regards
sashan


[1] https://marc.info/?l=openbsd-tech&m=165109904223362&w=2

[2] https://datatracker.ietf.org/doc/html/rfc2710
    https://datatracker.ietf.org/doc/html/rfc2236

--------8<---------------8<---------------8<------------------8<--------
diff --git a/sys/net/pf.c b/sys/net/pf.c
index f15e1ead8c0..9b107751d95 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -6456,8 +6456,21 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, 
u_short *reason)
        pd->off += hlen;
        pd->proto = h->ip_p;
        /* IGMP packets have router alert options, allow them */
-       if (pd->proto == IPPROTO_IGMP)
-               CLR(pd->badopts, PF_OPT_ROUTER_ALERT);
+       if (pd->proto == IPPROTO_IGMP) {
+               /*
+                * If router alert option is missing or ttl is not 1, then we
+                * deal invalid IGMP packet. According to RFC 1112 ttl must be
+                * set to 1. Also IP header must carry router alert option
+                * as specified in RFC 2236.
+                */
+               if (ISSET(pd->badopts, PF_OPT_ROUTER_ALERT) && (h->ip_ttl == 1))
+                       CLR(pd->badopts, PF_OPT_ROUTER_ALERT);
+               else {
+                       DPFPRINTF(LOG_NOTICE, "invalid IGMP");
+                       REASON_SET(reason, PFRES_IPOPTIONS);
+                       return (PF_DROP);
+               }
+       }
        /* stop walking over non initial fragments */
        if ((h->ip_off & htons(IP_OFFMASK)) != 0)
                return (PF_PASS);
@@ -6698,7 +6711,22 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, 
u_short *reason)
                        case MLD_LISTENER_REPORT:
                        case MLD_LISTENER_DONE:
                        case MLDV2_LISTENER_REPORT:
-                               CLR(pd->badopts, PF_OPT_ROUTER_ALERT);
+                               /*
+                                * According to RFC 2710 all MLD messages are
+                                * sent with with router alert header and hop
+                                * limit (ttl) set to 1, and link local source
+                                * address.  If either one is missing then MLD
+                                * message is invalid and should be discarded.
+                                */
+                               if (ISSET(pd->badopts, PF_OPT_ROUTER_ALERT) &&
+                                   (h->ip6_hlim == 1) &&
+                                   IN6_IS_ADDR_LINKLOCAL(&h->ip6_src))
+                                       CLR(pd->badopts, PF_OPT_ROUTER_ALERT);
+                               else {
+                                       DPFPRINTF(LOG_NOTICE, "invalid MLD");
+                                       REASON_SET(reason, PFRES_IPOPTIONS);
+                                       return (PF_DROP);
+                               }
                                break;
                        }
                        return (PF_PASS);

Reply via email to