Commit a46182b0 authored by Kevin Cernekee's avatar Kevin Cernekee Committed by David S. Miller

net: igmp: Use correct source address on IGMPv3 reports

Closing a multicast socket after the final IPv4 address is deleted
from an interface can generate a membership report that uses the
source IP from a different interface.  The following test script, run
from an isolated netns, reproduces the issue:


    ip link add dummy0 type dummy
    ip link add dummy1 type dummy
    ip link set dummy0 up
    ip link set dummy1 up
    ip addr add dev dummy0
    ip addr add dev dummy1

    tcpdump -U -i dummy0 &
    socat EXEC:"sleep 2" \
        UDP4-DATAGRAM:,ip-add-membership= &

    sleep 1
    ip addr del dev dummy0
    sleep 5
    kill %tcpdump

RFC 3376 specifies that the report must be sent with a valid IP source
address from the destination subnet, or from address  Add an
extra check to make sure this is the case.
Signed-off-by: default avatarKevin Cernekee <>
Reviewed-by: default avatarAndrew Lunn <>
Signed-off-by: default avatarDavid S. Miller <>
parent c545a945
......@@ -89,6 +89,7 @@
#include <linux/rtnetlink.h>
#include <linux/times.h>
#include <linux/pkt_sched.h>
#include <linux/byteorder/generic.h>
#include <net/net_namespace.h>
#include <net/arp.h>
......@@ -321,6 +322,23 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted)
return scount;
/* source address selection per RFC 3376 section 4.2.13 */
static __be32 igmpv3_get_srcaddr(struct net_device *dev,
const struct flowi4 *fl4)
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev)
return htonl(INADDR_ANY);
for_ifa(in_dev) {
if (inet_ifa_match(fl4->saddr, ifa))
return fl4->saddr;
} endfor_ifa(in_dev);
return htonl(INADDR_ANY);
static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
struct sk_buff *skb;
......@@ -368,7 +386,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
pip->frag_off = htons(IP_DF);
pip->ttl = 1;
pip->daddr = fl4.daddr;
pip->saddr = fl4.saddr;
pip->saddr = igmpv3_get_srcaddr(dev, &fl4);
pip->protocol = IPPROTO_IGMP;
pip->tot_len = 0; /* filled in later */
ip_select_ident(net, skb, NULL);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment