Subject: kern/36484: PIM Register in-kernel encapsulation IP_DF setting is incorrect
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <pavlin@icir.org>
List: netbsd-bugs
Date: 06/13/2007 19:55:00
>Number:         36484
>Category:       kern
>Synopsis:       PIM Register in-kernel encapsulation IP_DF setting is incorrect
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jun 13 19:55:00 +0000 2007
>Originator:     Pavlin Radoslavov
>Release:        NetBSD-3.1
>Organization:
ICSI
>Environment:
System: NetBSD-3.1
Architecture: i386


>Description:
If the system is running PIM-SM and if it tries to encapsulate in-kernel
multicast data packet (with the IP_DF flag set) and send it as PIM Register
to the RP, the IP_DF flag in the outer IP header is incorrect on little endian
architectures (e.g., i386).

For the record, the bug was found first (and fixed) in OpenBSD:
see OpenBSD's PR 5116.
The credit for the bug discovery and fix goes to Hideki ONO <ono AT ono.org>

Also, for the record the fix is not required for FreeBSD and DragonFlyBSD.
The reason for that is because ip_output() on those systems does htons()
for the ip_off field in the IP packet.



>How-To-Repeat:
1. Start PIM-SM on NetBSD box by using an implementation that uses in-kernel PIM Register
     encapsulation (e.g., XORP http://www.xorp.org/).
     Configure it such that the RP is some remote system. Also, configure it such that
     it is the DR (Designated Router) on the interface with the directly connected sender.

2. Start a sender that transmits UDP multicast packets with the DF flag set.
    E.g., a Linux box probably will set the IP_DF flag by default.

3. Watch the PIM Register packets that should be unicast by the NetBSD box to the RP.

4. If the native multicast packet has the IP_DF flag set, then the outer IP header should
    also has the IP_DF flag set. However, on little endian architectures (e.g., i386), the
    IP_DF flag is set incorrectly.
>Fix:
Apply the following trivial patch to /usr/src/sys/netinet/ip_mroute.c
Note that the patch is for NetBSD-3.1. The same fix is needed for NetBSD-current
as well.

--- ip_mroute.c.org     2005-02-26 14:45:12.000000000 -0800
+++ ip_mroute.c 2007-06-12 19:04:25.000000000 -0700
@@ -3300,7 +3300,7 @@
      */
     ip_outer->ip_tos = ip->ip_tos;
     if (ntohs(ip->ip_off) & IP_DF)
-       ip_outer->ip_off |= IP_DF;
+       ip_outer->ip_off |= htons(IP_DF);
     pimhdr = (struct pim_encap_pimhdr *)((caddr_t)ip_outer
                                         + sizeof(pim_encap_iphdr));
     *pimhdr = pim_encap_pimhdr;