From b022a38e133a00b3077a0b249a797b885e82defc Mon Sep 17 00:00:00 2001 From: David Stevens Date: Fri, 23 Jan 2004 17:59:08 -0800 Subject: [PATCH] [MULTICAST]: multicast loop with include filters fix When sending a multicast and using looping back a copy to the local machine, the interface filter checks can be done before the source address is specified. For an INCLUDE filter, this won't match the allowed sources and the packets won't be delivered locally, even when the ultimate source address chosen is in the allowed list. The patch below fixes the filter checks for both IGMPv3 and MLDv2 to only apply when a source address is available. Thanks to Steven Hessing for reporting the problem and providing a test case for reproducing it. --- net/ipv4/igmp.c | 23 +++++++++++++---------- net/ipv6/mcast.c | 32 ++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index b9840662ad5db..b1f9f7d62e386 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -2084,16 +2084,19 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) if (im && proto == IPPROTO_IGMP) { rv = 1; } else if (im) { - for (psf=im->sources; psf; psf=psf->sf_next) { - if (psf->sf_inaddr == src_addr) - break; - } - if (psf) - rv = psf->sf_count[MCAST_INCLUDE] || - psf->sf_count[MCAST_EXCLUDE] != - im->sfcount[MCAST_EXCLUDE]; - else - rv = im->sfcount[MCAST_EXCLUDE] != 0; + if (src_addr) { + for (psf=im->sources; psf; psf=psf->sf_next) { + if (psf->sf_inaddr == src_addr) + break; + } + if (psf) + rv = psf->sf_count[MCAST_INCLUDE] || + psf->sf_count[MCAST_EXCLUDE] != + im->sfcount[MCAST_EXCLUDE]; + else + rv = im->sfcount[MCAST_EXCLUDE] != 0; + } else + rv = 1; /* unspecified source; tentatively allow */ } read_unlock(&in_dev->lock); return rv; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 0e9dfa644e80c..8c8c2c9d7ad51 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -918,20 +918,24 @@ int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group, break; } if (mc) { - struct ip6_sf_list *psf; - - spin_lock_bh(&mc->mca_lock); - for (psf=mc->mca_sources; psf; psf=psf->sf_next) { - if (ipv6_addr_cmp(&psf->sf_addr, src_addr) == 0) - break; - } - if (psf) - rv = psf->sf_count[MCAST_INCLUDE] || - psf->sf_count[MCAST_EXCLUDE] != - mc->mca_sfcount[MCAST_EXCLUDE]; - else - rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0; - spin_unlock_bh(&mc->mca_lock); + if (!ipv6_addr_any(src_addr)) { + struct ip6_sf_list *psf; + + spin_lock_bh(&mc->mca_lock); + for (psf=mc->mca_sources;psf;psf=psf->sf_next) { + if (ipv6_addr_cmp(&psf->sf_addr, + src_addr) == 0) + break; + } + if (psf) + rv = psf->sf_count[MCAST_INCLUDE] || + psf->sf_count[MCAST_EXCLUDE] != + mc->mca_sfcount[MCAST_EXCLUDE]; + else + rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0; + spin_unlock_bh(&mc->mca_lock); + } else + rv = 1; /* don't filter unspecified source */ } read_unlock_bh(&idev->lock); in6_dev_put(idev); -- 2.53.0