On Sat, Dec 9, 2017 at 8:01 AM, Andrew Lunn <and...@lunn.ch> wrote: > The choice of IP address for IGMP in Linux is 'interesting'. Try with > multiple IP addresses on the interfaces, addresses with different > scopes, etc. I've seen it reply to the querier using an address from > a different subnet to the incoming request, etc. > > Part of it is an implementation problem. When the application did a > join, it passed an IP address to identify the interface to perform the > join on. That IP address would be an idle choice for IGMP for that > group. However, the information gets discard once the interface has > been determined.
Right, and even if an address is specified in struct ip_mreqn for an IP_DROP_MEMBERSHIP call, that address is ignored (at least in my testing). > With a single IP address on a single interface, Linux IGMP probably > works. Outside of that, expect oddness. > > In your particular case, it is a global scope address. You are allowed > to use it on any interface. So it should not really trigger suspicious > activity. However, the RFC about multicast suggests IGMP with an > unexpected source address should be dropped. However, it is only a > should, not a must, if i remember correctly. Hmm, RFC3376 says: 4.2.13. IP Source Addresses for Reports An IGMP report is sent with a valid IP source address for the destination subnet. The 0.0.0.0 source address may be used by a system that has not yet acquired an IP address. Note that the 0.0.0.0 source address may simultaneously be used by multiple systems on a LAN. Routers MUST accept a report with a source address of 0.0.0.0. Would it make sense to add a special case that says "zero out pip->saddr if the interface doesn't have any IPv4 addresses"? e.g. diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d1f8f30..db02779 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -332,6 +332,10 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) int hlen = LL_RESERVED_SPACE(dev); int tlen = dev->needed_tailroom; unsigned int size = mtu; + struct in_device *in_dev = __in_dev_get_rcu(dev); + + if (!in_dev) + return NULL; while (1) { skb = alloc_skb(size + hlen + tlen, @@ -368,7 +372,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 = in_dev->ifa_list ? fl4.saddr : INADDR_ANY; pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(net, skb, NULL);