setsockopt IP_ADD_MEMBERSHIP not honored

William A.Carrel william.a at carrel.org
Tue Oct 21 14:02:42 PDT 2003


On Tuesday, October 21, 2003, at 12:59PM, Joshua Graessley wrote:

> On Oct 21, 2003, at 12:28 PM, William A.Carrel wrote:
>
>> I have two such sockets set up, one on each of the interfaces I'm 
>> interested in.  The problem is that a packet that comes in on one 
>> interface winds up in the receive queue for both sockets.  Both the 
>> queue for the socket that has the membership on the interface I care 
>> about, and the receive queue for the socket that has the membership 
>> on the other interface.
>>
>> My reading of UNP vol. 1 (pg. 496) and the ip(4) man page would imply 
>> that this is not the correct behavior for a multicast membership that 
>> was tied to a specific interface.  This means that new processes that 
>> add membership to the multicast address on a new interface can cause 
>> older processes to receive packets on that interface that they did 
>> not intend to read.

> This is "by design". When you perform IP_ADD_MEMBERSHIP, it assures 
> you that the interface you've selected will receive packets destined 
> for the multicast address you specify. It will deal with any IGMP 
> traffic necessary for joining the group.
>
> When a packet is received on any interface, the packet is matched up 
> to any number of sockets. This matching is based on the address and 
> port the socket is bound to. This chunk of the code that matches a 
> packet up to an interface does not check to see if that socket joined 
> the multicast group on that specific interface.

Right.  This is exactly the issue I'm pointing out, and it is certainly 
my impression from the documentation of IP_ADD_MEMBERSHIP on this 
subject that the existing behavior needs fixing, as I'll elucidate in a 
little bit more detail below.

> Some applications may rely on this behavior, so it might be unwise to 
> change it. If you're going to make this change, you should probably 
> make it some sort of socket option that applications can opt in to on 
> a per socket basis.

Relying on this behavior doesn't seem to make sense.  It would be 
relying on the kernel to let other programs to make you receive 
unintended multicast packets.  It would also be relying on behavior 
contrary to the documentation.

The only change in behavior would be if the program presumes someone 
else is holding memberships on all the interfaces (on its behalf) so it 
only has to open one.  For example, in the case of multicast DNS, if 
the program is really wanting to listen for mDNS traffic on all 
interfaces, it needs to be adding membership on all interfaces.  It 
would be broken behavior on the part of the application to add 
membership to the multicast address on one interface and trust that 
someone else has memberships to that multicast address on all the other 
interfaces, so it can get the multicast traffic for all interfaces.  
The example code from Apple in mDNSResponder-58/mDNSPosix/mDNSPosix.c 
(SetupSocket() at line 464) also seems to acknowledge that the 
multicast socket is only handling multicast for a specific interface.

If a program really wants to get the multicast traffic on all 
interfaces, then it needs to add membership for all the interfaces.  
And if it holds membership on all the interfaces, my suggested fix will 
not keep it from receiving the packets that it wants destined for it.   
As such, I don't see the potential for a POLA violation in the 
suggested fix.

 From the manpage:
      A host must become a member of a multicast group before it can 
receive
      datagrams sent to the group.  To join a multicast group, use the
      IP_ADD_MEMBERSHIP option:

      struct ip_mreq mreq;
      setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));

      where mreq is the following structure:

      struct ip_mreq {
          struct in_addr imr_multiaddr; /* multicast group to join */
          struct in_addr imr_interface; /* interface to join on */
      }

      imr_interface should be INADDR_ANY to choose the default multicast 
inter-
      face, or the IP address of a particular multicast-capable 
interface if
      the host is multihomed.  Membership is associated with a single 
inter-
      face; programs running on multihomed hosts may need to join the 
same
      group on more than one interface.  Up to IP_MAX_MEMBERSHIPS 
(currently
      20) memberships may be added on a single socket.

The assertion that "membership is associated with a single interface" 
is false under the current implementation.  Membership is, at the 
moment, associated with the interface you specified to join on, and any 
other interfaces that any other processes on the entire system 
(possibly even processes in jails) have joined the same multicast 
address on.

W. Richard Stevens wrote similarly on page 496 of UNP Vol. 1 (2nd ed.). 
  "Join a multicast group on a specified local interface. ... If the 
local interface is specified as the wildcard address (INADDR_ANY for 
IPv4)..., then the local interface is chosen by the kernel. ... More 
than one join is allowed on a given socket...  This can be used on a 
multihomed host where, for example, one socket is created and then for 
each interface a join is performed for a given multicast address."

It seems odd that someone would join on a specified local interface and 
then start receiving packets on from an interface other than the one 
they had specified.  The descriptions given both by Stevens, by Apple's 
mDNS example code and in the ip(4) man page run counter to the current 
behavior, hence the code I presented a moment ago to bring the behavior 
in line with the documentation.



More information about the freebsd-net mailing list