NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/41005: kernel failed to select correct outgoing address for Multicast packets
>Number: 41005
>Category: kern
>Synopsis: kernel failed to select correct outgoing address for Multicast
>packets
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Mar 13 13:50:00 +0000 2009
>Originator: Wolfgang Stukenbrock
>Release: NetBSD 4.0
>Organization:
Dr. Nagler & Company GmbH
>Environment:
System: NetBSD s012 4.0 NetBSD 4.0 (NSW-S012) #9: Fri Mar 13 12:31:52 CET 2009
wgstuken@s012:/usr/src/sys/arch/amd64/compile/NSW-S012 amd64
Architecture: x86_64
Machine: amd64
>Description:
If alias addresses are defined on an interface, the kernel does not use
the
information passed to it by IP_MULTICAST_IF option. Instead it always
uses
the primary address of the interface.
This will break e.g. gated on such interfaces.
The problem is, that the information passed by IP_MULTICAST_IF is only
used
to select the interface itself in the call and to pass it back to user
level
on a call got getoption IP_MULTICAST_IF under some circumstances.
But is is ignored when sending packets with .e.g. sendto().
By the way, the current code when selecting the interface by pasing the
interface
index to the kernel (RFC1724) looks broken, because if the index 0 gets
selected,
the information is not stored and returned as expected. (recognized by
source
codde inspection) This patch will also solve this.
>How-To-Repeat:
Setup an interface with an alias address (with a different subnet mask)
on some machines
and try to gated on it.
remark: the different subnet mask will only lead to syslog output by
gated that can be
found in the log-file.
You can also use tcpdump. You will see that all packets come from the
primary addess, but
gated will try to send half of then from the other address.
You can also write a short test program: open a socket(RAW_IP), assign
it to a the alias
address to the multicast group, select that one as outgooing interface
and send some
data to that group. The wrong source address is in the packet on the
wire.
>Fix:
The best way to solve this problem seems to use the imo_multicas_addr
information in any
case - not only if the interface was selected via interface index.
If there is still no address selected on outgooing multicast packets,
then this information
should be used, if it is still a valid address of the interface.
If not, the old semantic by selecting the first one found is preserved.
This may only be done if the outgooing interface for multicast packets
is selected by
an address specification. Therefore we need to check for RFC1724 setup
here too.
remark: the second parameter for the interface index in
ip_multicast_if() is no longer
used in any call after applying this patch. I haven't removed it,
because it may be usefull
to reuse it in the future again. Feel free to eleminate it ...
*** ip_output.c 2009/02/16 10:09:16 1.11
--- ip_output.c 2009/03/13 13:17:29
***************
*** 394,400 ****
--- 394,420 ----
if (in_nullhost(ip->ip_src)) {
struct in_ifaddr *xia;
+ if ( IN_MULTICAST(ip->ip_dst.s_addr)
+ && imo != NULL
+ && ntohl(imo->imo_multicast_addr.s_addr) >> 24 != 0) /*
RFC1724 section 3.3 */
+ { /* use the stored multicast address from
IP_MULTICAST_IF to locate the in_ifaddr structure */
+ struct ifaddr *ifa;
+
+ xia = NULL;
+ IFADDR_FOREACH(ifa, ifp) { /* XXX special version of
the IFP_TO_IA() macro ...*/
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ if (imo->imo_multicast_addr.s_addr ==
ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
+ xia = ifatoia(ifa);
+ break;
+ }
+ if (xia == NULL) xia = ifatoia(ifa); /* default
to previous behaviour if no match - use first addres */
+ }
+ }
+ }
+ else
+ {
IFP_TO_IA(ifp, xia);
+ }
if (!xia) {
error = EADDRNOTAVAIL;
goto bad;
***************
*** 1683,1689 ****
struct ip_moptions *imo = *imop;
struct route ro;
struct sockaddr_in *dst;
- int ifindex;
if (imo == NULL) {
/*
--- 1703,1708 ----
***************
*** 1728,1743 ****
* IP address. Find the interface and confirm that
* it supports multicasting.
*/
! ifp = ip_multicast_if(&addr, &ifindex);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
error = EADDRNOTAVAIL;
break;
}
imo->imo_multicast_ifp = ifp;
! if (ifindex)
! imo->imo_multicast_addr = addr;
! else
! imo->imo_multicast_addr.s_addr = INADDR_ANY;
break;
case IP_MULTICAST_TTL:
--- 1747,1759 ----
* IP address. Find the interface and confirm that
* it supports multicasting.
*/
! ifp = ip_multicast_if(&addr, NULL);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
error = EADDRNOTAVAIL;
break;
}
imo->imo_multicast_ifp = ifp;
! imo->imo_multicast_addr = addr;
break;
case IP_MULTICAST_TTL:
***************
*** 1925,1930 ****
--- 1941,1947 ----
/* return the value user has set */
*addr = imo->imo_multicast_addr;
} else {
+ /* should never come here anymore - but kept for security reasons ... */
IFP_TO_IA(imo->imo_multicast_ifp, ia);
*addr = ia ? ia->ia_addr.sin_addr : zeroin_addr;
}
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index