diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index 8daa101fe4..94170c0bb2 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -260,7 +260,8 @@ is in a vrf, enter the interface command with the vrf keyword at the end. .. clicmd:: ipv6 mld require-router-alert - Only accept MLD reports with the router-alert IPv6 hop option. + Only accept MLD reports with the router-alert IPv6 hop option. MLDv1 reports + without this option are always dropped and not controlled by this command. .. clicmd:: ipv6 mld join X:X::X:X [Y:Y::Y:Y] diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index 616efe16af..5e4f18af8a 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -57,6 +57,8 @@ static void gm_sg_timer_start(struct gm_if *gm_ifp, struct gm_sg *sg, #define log_pkt_src(msg) \ "[MLD %s:%s %pI6] " msg, gm_ifp->ifp->vrf->name, gm_ifp->ifp->name, \ &pkt_src->sin6_addr +#define log_pkt_dst(msg) \ + "[MLD %s:%s %pI6] " msg, gm_ifp->ifp->vrf->name, gm_ifp->ifp->name, pkt_dst #define log_sg(sg, msg) \ "[MLD %s:%s %pSG] " msg, sg->iface->ifp->vrf->name, \ sg->iface->ifp->name, &sg->sgaddr @@ -1040,9 +1042,8 @@ static void gm_handle_v2_report(struct gm_if *gm_ifp, gm_packet_free(pkt); } -static void gm_handle_v1_report(struct gm_if *gm_ifp, - const struct sockaddr_in6 *pkt_src, char *data, - size_t len) +static void gm_handle_v1_report(struct gm_if *gm_ifp, const struct sockaddr_in6 *pkt_src, + pim_addr *pkt_dst, char *data, size_t len) { struct mld_v1_pkt *hdr; struct gm_packet_state *pkt; @@ -1061,6 +1062,14 @@ static void gm_handle_v1_report(struct gm_if *gm_ifp, gm_ifp->stats.rx_old_report++; hdr = (struct mld_v1_pkt *)data; + if (pim_addr_cmp(hdr->grp, *pkt_dst)) { + if (PIM_DEBUG_GM_PACKETS) + zlog_debug(log_pkt_dst( + "malformed MLDv1 report (destination address should be %pI6)"), + &hdr->grp); + gm_ifp->stats.rx_drop_malformed++; + return; + } if (gm_sg_filter_match(gm_ifp, PIMADDR_ANY, hdr->grp)) return; @@ -1709,7 +1718,7 @@ static void gm_rx_process(struct gm_if *gm_ifp, gm_handle_query(gm_ifp, pkt_src, pkt_dst, data, pktlen); break; case ICMP6_MLD_V1_REPORT: - gm_handle_v1_report(gm_ifp, pkt_src, data, pktlen); + gm_handle_v1_report(gm_ifp, pkt_src, pkt_dst, data, pktlen); break; case ICMP6_MLD_V1_DONE: gm_handle_v1_leave(gm_ifp, pkt_src, data, pktlen); diff --git a/tests/topotests/multicast_features/test_multicast_features.py b/tests/topotests/multicast_features/test_multicast_features.py index 30a340e0c8..f0f47a9d1c 100644 --- a/tests/topotests/multicast_features/test_multicast_features.py +++ b/tests/topotests/multicast_features/test_multicast_features.py @@ -658,7 +658,7 @@ def test_igmp_router_alert(): def host_send_mldv1_packet(host, source, group, router_alert=True): "Sends packet using specified script from host." command = f"python3 {CWD}/../lib/packet/mld/mld_v1.py" - command += f" --src_ip={source} --gaddr={group}" + command += f" --src_ip={source} --dst_ip={group} --gaddr={group}" command += f" --iface={host}-eth0" if router_alert: command += f" --enable_router_alert" @@ -714,13 +714,10 @@ def test_mld_router_alert(): # # Test that without require-router-alert we learn MLD groups # - group = "ff05::100" - host_send_mldv1_packet("h1", source, group, router_alert=False) - test_func = partial(expect_mld_group, "r1", "r1-eth2", group) - logger.info(f"Waiting for r1 to learn {group} in interface r1-eth2") - rv, _ = topotest.run_and_expect(test_func, True, count=10, wait=2) - assert rv, "failed to learn group using MLDv1 without router alert" - + # MLDv1 reports without router-alert are always dropped, they are not + # controlled by require-router-alert command. So skip the check of + # MLDv1 reports without router-alert. + # group = "ff05::101" host_send_mldv2_packet("h1", source, group, router_alert=False) test_func = partial(expect_mld_group, "r1", "r1-eth2", group)