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);