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:
(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.