Date: Tue, 29 Mar 2011 14:01:03 -0400 From: John Baldwin <jhb@freebsd.org> To: Randall Stewart <rrs@freebsd.org> Cc: svn-src-head@freebsd.org, deischen@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org Subject: Re: svn commit: r217592 - head/sys/netinet Message-ID: <201103291401.03565.jhb@freebsd.org> In-Reply-To: <201101191907.p0JJ7GMp086060@svn.freebsd.org> References: <201101191907.p0JJ7GMp086060@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Wednesday, January 19, 2011 2:07:16 pm Randall Stewart wrote: > Author: rrs > Date: Wed Jan 19 19:07:16 2011 > New Revision: 217592 > URL: http://svn.freebsd.org/changeset/base/217592 > > Log: > Fix a bug where Multicast packets sent from a > udp endpoint may end up echoing back to the sender > even with OUT joining the multi-cast group. > > Reviewed by: gnn, bms, bz? > Obtained from: deischen (with help from) > > Modified: > head/sys/netinet/udp_usrreq.c > > Modified: head/sys/netinet/udp_usrreq.c > ============================================================================== > --- head/sys/netinet/udp_usrreq.c Wed Jan 19 18:20:11 2011 (r217591) > +++ head/sys/netinet/udp_usrreq.c Wed Jan 19 19:07:16 2011 (r217592) > @@ -479,11 +479,13 @@ udp_input(struct mbuf *m, int off) > * and source-specific multicast. [RFC3678] > */ > imo = inp->inp_moptions; > - if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && > - imo != NULL) { > + if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { > struct sockaddr_in group; > int blocked; > - > + if(imo == NULL) { > + INP_RUNLOCK(inp); > + continue; > + } > bzero(&group, sizeof(struct sockaddr_in)); > group.sin_len = sizeof(struct sockaddr_in); > group.sin_family = AF_INET; So it turns out that this is a feature, not a bug, and is how multicast has always worked. Specifically, if you bind a UDP socket with a wildcard address, it should receive all traffic for the bound port, unicast or multicast. When you join a group, you have switched the socket into a mode where it now has a whitelist of acceptable multicast groups, but if a socket has no joined groups, it should receive all multicast traffic, not none. This change breaks that. I did not find this behavior intuitive at first, but it does seem to be required. Note the description of IP_ADD_MEMBERSHIP from RFC 3678 for example: 3. Overview of APIs There are a number of different APIs described in this document that are appropriate for a number of different application types and IP versions. Before providing detailed descriptions, this section provides a "taxonomy" with a brief description of each. There are two categories of source-filter APIs, both of which are designed to allow multicast receiver applications to designate the unicast address(es) of sender(s) along with the multicast group (destination address) to receive. o Basic (Delta-based): Some applications desire the simplicity of a delta-based API in which each function call specifies a single source address which should be added to or removed from the existing filter for a given multicast group address on which to listen. Such applications typically fall into either of two categories: + Any-Source Multicast: By default, all sources are accepted. Individual sources may be turned off and back on as needed over time. This is also known as "exclude" mode, since the source filter contains a list of excluded sources. + Source-Specific Multicast: Only sources in a given list are allowed. The list may change over time. This is also known as "include" mode, since the source filter contains a list of included sources. This API would be used, for example, by "single-source" applications such as audio/video broadcasting. It would also be used for logical multi-source sessions where each source independently allocates its own Source-Specific Multicast group address. ..... 4.1.1. IPv4 Any-Source Multicast API The following socket options are defined in <netinet/in.h> for applications in the Any-Source Multicast category: Socket option Argument type IP_ADD_MEMBERSHIP struct ip_mreq IP_BLOCK_SOURCE struct ip_mreq_source IP_UNBLOCK_SOURCE struct ip_mreq_source IP_DROP_MEMBERSHIP struct ip_mreq IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP are already implemented on most operating systems, and are used to join and leave an any-source group. IP_BLOCK_SOURCE can be used to block data from a given source to a given group (e.g., if the user "mutes" that source), and IP_UNBLOCK_SOURCE can be used to undo this (e.g., if the user then "unmutes" the source). As to why the packets loop back to the receiver, I believe that is a separate issue on the output side, not the receive side. -- John Baldwin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103291401.03565.jhb>