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