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