From owner-freebsd-net@FreeBSD.ORG Tue Oct 21 14:02:42 2003 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 40B3216A4B3 for ; Tue, 21 Oct 2003 14:02:42 -0700 (PDT) Received: from mx.carrel.org (adsl-64-91-104-251.gh.customer.centurytel.net [64.91.104.251]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4BA1943F3F for ; Tue, 21 Oct 2003 14:02:41 -0700 (PDT) (envelope-from william.a@carrel.org) Received: from carrel.org (unknown [172.16.4.3]) by mx.carrel.org (Postfix) with ESMTP id E929E25A; Tue, 21 Oct 2003 14:02:29 -0700 (PDT) In-Reply-To: <1F8C654D-0401-11D8-8EA7-000A95B9474C@apple.com> References: <1F8C654D-0401-11D8-8EA7-000A95B9474C@apple.com> Mime-Version: 1.0 (Apple Message framework v581) Content-Type: text/plain; charset=US-ASCII; format=flowed Message-Id: Content-Transfer-Encoding: 7bit From: William A.Carrel Date: Tue, 21 Oct 2003 14:02:39 -0700 To: Joshua Graessley X-Mailer: Apple Mail (2.581) cc: freebsd-net@freebsd.org Subject: Re: setsockopt IP_ADD_MEMBERSHIP not honored X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Oct 2003 21:02:42 -0000 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.