NetBSD Problem Report #23221

Received: (qmail 9225 invoked by uid 605); 22 Oct 2003 02:35:19 -0000
Message-Id: <20031022023517.EECBA11152@narn.netbsd.org>
Date: Wed, 22 Oct 2003 02:35:17 +0000 (UTC)
From: william.a@carrel.org
Sender: gnats-bugs-owner@NetBSD.org
Reply-To: william.a@carrel.org
To: gnats-bugs@gnats.NetBSD.org
Subject: Multicast packets sent to inappropriate sockets (patch)
X-Send-Pr-Version: www-1.0

>Number:         23221
>Category:       kern
>Synopsis:       Multicast packets sent to inappropriate sockets (patch)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Oct 22 02:36:00 +0000 2003
>Closed-Date:    
>Last-Modified:  Fri Oct 24 21:07:00 +0000 2003
>Originator:     William A. Carrel
>Release:        Any
>Organization:
>Environment:
n/a
>Description:
	udp_input() in src/sys/netinet/udp_usrreq.c does not properly check 
	inbound multicast packets to make sure they conform with memberships 
	on a given socket before sending packets along to that socket.  

	This can result in UDP multicast packets being erroneously delivered 
	to sockets that should not be seeing them. Programs wishing to 
	guarantee that a socket is only seeing packets on one interface must 
	read in information about the interface configuration to try and 
	determine whether the packet was legitimately delivered to it.

	This bug has been present since at least 4.4BSD-Lite and is present
	in all known BSD derivatives.  Problem reports are simultaneously 
	being filed to FreeBSD, NetBSD, Darwin, DragonflyBSD and OpenBSD.
	I'll follow up to this PR with cross-references.

	A brief discussion of this issue and more details about it can be 
	found in the freebsd-net mailing list under the subject 
	"setsockopt IP_ADD_MEMBERSHIP not honored" around the date of this
	problem report.

>How-To-Repeat:
	On a machine with two multicast interfaces, open two sockets and
	add them to the same multicast address but on different interfaces
	using setsockopt([sock], IP_ADD_MEMBERSHIP, sizeof(the_mreq), 
	&the_mreq);  Inbound multicast packets to the requested multicast
	address on either interface will appear in both sockets, not just
	the requested one.

	See mailing list discussion for more information.

>Fix:
	Programs must either use sysctl or ioctl to gather information about
	the interface they want to be exclusively receiving multicast packets
	from or the kernel must be patched.  Patches follow for 
	NetBSD-CURRENT.  (The new code may not be fully 
	style(9) compliant, my apologies in advance.)

	The docontinue goto present in the stable patch is consistent with 
	treatment for FreeBSD-CURRENT and reduces diffs to that code base.

--- udp_usrreq.c.orig	Tue Oct 21 19:18:49 2003
+++ udp_usrreq.c	Tue Oct 21 19:18:25 2003
@@ -629,8 +629,10 @@
 		 */
 		CIRCLEQ_FOREACH(inph, &udbtable.inpt_queue, inph_queue) {
 			inp = (struct inpcb *)inph;
-			if (inp->inp_af != AF_INET)
+			if (inp->inp_af != AF_INET) {
+		docontinue:
 				continue;
+			}

 			if (inp->inp_lport != *dport)
 				continue;
@@ -643,6 +645,22 @@
 				    inp->inp_fport != *sport)
 					continue;
 			}
+			/*
+			 * Check multicast packets to make sure they are only
+			 * sent to sockets with multicast memberships for the
+			 * packet's destination address and arrival interface
+			 */
+			if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+				int mshipno;
+
+				for (mshipno = 0; mshipno <= inp->inp_moptions->imo_num_memberships; ++mshipno) {
+					if (mshipno == inp->inp_moptions->imo_num_memberships)
+						goto docontinue;
+					if (ip->ip_dst.s_addr == inp->inp_moptions->imo_membership[mshipno]->inm_addr.s_addr && m->m_pkthdr.rcvif == inp->inp_moptions->imo_membership[mshipno]->inm_ifp)
+						break;
+				}
+			}
+

 			udp4_sendup(m, off, (struct sockaddr *)src,
 				inp->inp_socket);

>Release-Note:
>Audit-Trail:

From: Robert Elz <kre@munnari.OZ.AU>
To: "William A.Carrel" <william.a@carrel.org>
Cc: tech-net@NetBSD.org, gnats-bugs@NetBSD.org
Subject: Re: kern/23221: setsockopt IP_ADD_MEMBERSHIP arguments not honored 
Date: Fri, 24 Oct 2003 17:39:32 +0700

     Date:        Thu, 23 Oct 2003 22:37:04 -0700
     From:        "William A.Carrel" <william.a@carrel.org>
     Message-ID:  <19A1094E-05E4-11D8-B2E9-003065D5E9A4@carrel.org>

   | The behavior is contrary to the documentation for setsockopt

 I can believe that's possible.

   | and also  contrary to common sense.

 But I have a harder time following this.

   | Contrary to common sense in that, adding 
   | memberships to other sockets (in other processes) should not to be able 
   | to cause a multicast socket to receive packets it didn't ask to 
   | receive.

 That's fine.

 However, you're making an assumption that the process didn't ask to
 receive the packets.   Unless you're talking about link scope multicast
 addresses (or similar) - which I don't think were what your PR used as
 an example, and certainly weren't in your proposed patch, shouldn't a
 packet transmitted to a particular multicast address go everywhere?
 What difference does it make which interface happens to have been used
 (other than to the source address when the application transmits packets,
 and hence the forwarding path).

 My assumption when I bind to a particular (non limited scope) multicast
 address, is that I am going to receive *every* packet sent to (the
 correct port) using that multicast address, not some subset of them.

 If the issue is just that the "same" packets get delivered on multiple
 interfaces, and hence the application gets multiple copies (which I don't
 think is really what you're concerned about, but just in case) then I
 believe that's simply a fact of multicast life - packets can be
 delivered more than once.

 What process or application is actually depending upon different
 applications running on the same address and port, but binding to
 different interfaces, actually receiving different sets of packets,
 on something that isn't a limited scope address?

 kre


From: William A.Carrel <william.a@carrel.org>
To: Robert Elz <kre@munnari.OZ.AU>
Cc: tech-net@NetBSD.org, gnats-bugs@NetBSD.org
Subject: Re: kern/23221: setsockopt IP_ADD_MEMBERSHIP arguments not honored 
Date: Fri, 24 Oct 2003 10:24:20 -0700

 On Friday, October 24, 2003, at 3:39AM, Robert Elz wrote:

 > However, you're making an assumption that the process didn't ask to
 > receive the packets.   Unless you're talking about link scope multicast
 > addresses (or similar) - which I don't think were what your PR used as
 > an example, and certainly weren't in your proposed patch, shouldn't a
 > packet transmitted to a particular multicast address go everywhere?
 > What difference does it make which interface happens to have been used
 > (other than to the source address when the application transmits 
 > packets,
 > and hence the forwarding path).
 >
 > My assumption when I bind to a particular (non limited scope) multicast
 > address, is that I am going to receive *every* packet sent to (the
 > correct port) using that multicast address, not some subset of them.
 >
 > If the issue is just that the "same" packets get delivered on multiple
 > interfaces, and hence the application gets multiple copies (which I 
 > don't
 > think is really what you're concerned about, but just in case) then I
 > believe that's simply a fact of multicast life - packets can be
 > delivered more than once.
 >
 > What process or application is actually depending upon different
 > applications running on the same address and port, but binding to
 > different interfaces, actually receiving different sets of packets,
 > on something that isn't a limited scope address?

 I handle multicast DNS on a machine that sits on a network border.  
 Multicast DNS is link-local multicast at 224.0.0.251:5353.  I open a 
 separate socket for each of the networks.  Each socket has membership 
 on one interface and only one interface so I can intelligently direct 
 responses to queries.  With this bug, incoming packets on either 
 interface wind up in the queue for both sockets.  I don't know where to 
 respond to with out broadcasting across both networks, which is 
 wasteful in a crowded network environment.  Worse yet, if I want to 
 echo certain queries across the network border I could wind up causing 
 duplicate traffic by resending a query back to the interface it 
 originally came from.  With two hosts doing this, I wind up with a 
 multicast storm saturating my network.

 Potentially, I could go ask for the complete network configuration for 
 the machine and try to use the source address on the packet to help me 
 determine where the packet came from so I can intelligently send the 
 response.  This won't work as soon as I stop talking about link-local 
 multicast though, as the addresses may not provide me with an adequate 
 clue as to where the packets came from.  Plus caring a whole lot about 
 the source address on the packet seems somewhat antithetical to how to 
 play and win a multicast environment.  This mucking about would not be 
 required if the kernel was behaving as the documentation says it 
 should.

 A socket with multicast memberships should only receive packets 
 intended for its memberships.  Multicast memberships include both a 
 specific multicast address and a specific interface.  Q.E.D.

 In the existing implementation your multicast socket, despite having 
 only asked for membership on a specific interface, could wind up 
 receiving traffic from any possible subset of available interfaces that 
 include the one you requested.  For applications whose behavior hinges 
 on which interface a multicast packet arrived on this is a disaster.

 As I mentioned in the last email, the patch should not cause any change 
 in behavior in existing programs, and has the potential to reduce the 
 heavy lifting that the program needs to do in order to handle the 
 packets in an efficient manner.  Apple's example multicast DNS 
 responder code contains a large block devoted to working around this 
 bug to try and determine what interface a packet came in on.  This same 
 hack can be avoided in other such projects with this small patch to 
 bring about the correct behavior in multicast DNS handling.

 Thanks for reading.


From: William A.Carrel <william.a@carrel.org>
To: gnats-bugs@NetBSD.org
Cc: tech-net@NetBSD.org
Subject: Re: kern/23221: setsockopt IP_ADD_MEMBERSHIP arguments not honored 
Date: Fri, 24 Oct 2003 13:07:03 -0700

 Updated patch.  The previous patch contained an error where in some 
 situations inp->inp_moptions could be dereferenced while null.  This 
 patch also has the effect of blocking multicast packets from reaching 
 non-multicast programs.  Thanks to Bruce Fenner for pointing these two 
 things out to me.  I've also paid homage to Dijkstra by removing the 
 goto, which didn't really need to be there except on FreeBSD-CURRENT 
 for consistencies sake.

 Under the existing implementation, packets bound for "multicast 
 address":2049 will be received by any process listening to udp4 *:2049 
 if any other process on the host is subscribed to the multicast 
 address.  The patch besides its other effect makes sure that processes 
 really want to receive multicast traffic before it starts coming to 
 them.

 --- netbsd_udp_usrreq.c.orig	Fri Oct 24 12:35:01 2003
 +++ netbsd_udp_usrreq.c	Fri Oct 24 12:48:04 2003
 @@ -643,6 +643,26 @@
   				    inp->inp_fport != *sport)
   					continue;
   			}
 +			/*
 +			 * Check multicast packets to make sure they are only
 +			 * sent to sockets with multicast memberships for the
 +			 * packet's destination address and arrival interface
 +			 */
 +			if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) &&
 +			    inp->inp_moptions != NULL) {
 +				int mshipno;
 +				
 +				for (mshipno = 0;
 +				     mshipno <=
 +				        inp->inp_moptions->imo_num_memberships;
 +				     ++mshipno) {
 +					if (ip->ip_dst.s_addr == 
 inp->inp_moptions->imo_membership[mshipno]->inm_addr.s_addr && 
 m->m_pkthdr.rcvif == 
 inp->inp_moptions->imo_membership[mshipno]->inm_ifp)
 +						break;
 +				}
 +				if (mshipno ==
 +				    inp->inp_moptions->imo_num_memberships)
 +					continue;
 +			}

   			udp4_sendup(m, off, (struct sockaddr *)src,
   				inp->inp_socket);


From: William A.Carrel <william.a@carrel.org>
To: gnats-bugs@NetBSD.org
Cc: tech-net@NetBSD.org
Subject: Re: kern/23221: setsockopt IP_ADD_MEMBERSHIP arguments not honored 
Date: Fri, 24 Oct 2003 13:42:31 -0700

 On Friday, October 24, 2003, at 1:07PM, William A. Carrel wrote:

 > Thanks to Bruce Fenner for pointing these two things out to me.

 That's Bill Fenner.  Sorry about the mistake.


From: Nick Amato <naamato@nexthop.com>
To: "William A.Carrel" <william.a@carrel.org>
Cc: Robert Elz <kre@munnari.oz.au>, tech-net@netbsd.org, gnats-bugs@netbsd.org
Subject: Re: kern/23221: setsockopt IP_ADD_MEMBERSHIP arguments not honored
Date: Fri, 24 Oct 2003 17:06:29 -0400

 William A.Carrel wrote:
 > On Friday, October 24, 2003, at 3:39AM, Robert Elz wrote:
  >
 > Potentially, I could go ask for the complete network configuration for 
 > the machine and try to use the source address on the packet to help me 
 > determine where the packet came from so I can intelligently send the 
 > response.  This won't work as soon as I stop talking about link-local 
 > multicast though, as the addresses may not provide me with an adequate 
 > clue as to where the packets came from.  Plus caring a whole lot about 
 > the source address on the packet seems somewhat antithetical to how to 
 > play and win a multicast environment.  This mucking about would not be 
 > required if the kernel was behaving as the documentation says it should.

 One way to handle this without depending on packet source 
 addresses is to use the IP_RECVIF socket option.  This gives 
 you the index of the packet's arrival interface.

 Using this with the hack that allows the IP_ADD_MEMBERSHIP 
 option to handle an interface index (by setting the first 
 octet to 0), you can quickly discard unwanted multicast 
 packets without ever caring about interface IP addresses.

 Nick

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.