Subject: kern/10857: ipf doesn't fill in nextmtu field of NEEDFRAG ICMP
To: None <gnats-bugs@gnats.netbsd.org>
From: None <marc@mit.edu, lxs@mit.edu>
List: netbsd-bugs
Date: 08/19/2000 16:34:16
>Number:         10857
>Category:       kern
>Synopsis:       ipf doesn't fill in nextmtu field of NEEDFRAG ICMP
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Aug 19 16:35:01 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     Marc Horowitz
>Release:        around July 13
>Organization:
TNF
>Environment:
System: NetBSD pearl-harbor 1.5_ALPHA NetBSD 1.5_ALPHA (PEARL-HARBOR) #0: Thu Jul 13 08:16:08 PDT 2000     lxs@pearl-harbor:/usr/athena/src/sys/arch/i386/compile/PEARL-HARBOR i386

>Description:

When ipfilter is being used to route packets out a specific interface,
but the MTU is too small (such as is likely with a tunnel, gif0 in
this case), it doesn't fill in the nextmtu field of the ICMP NEEDFRAG:

16:31:27.890790 24.147.233.208 > SALTINE.MIT.EDU: icmp: 24.147.233.208 unreachable - need to frag (ttl 62, id 45315)
                         4500 0038 b103 0000 3e01 b5e7 1893 e9d0
                         1265 0112 0304 2058 0000 0000 4500 dc05
                         b103 0040 3f06 0000 1265 0112 1893 e9d0
                         0050 ed6f 0027 c791

>How-To-Repeat:

Create a tunnel, then route packets through it with an ipf rule
something like

	pass out on ep0 to gif0 from 18.101.1.16/28 to any

Then send a packet through it which exceeds the tunnel mtu, and look
at the ICMP you get back.

>Fix:

I believe this fix is correct for the ipv4 case, but I'm not 100%
confident.  More code may be needed for the ipv6 case.

*** src/sys/netinet/ip_fil.c    Sat May 27 12:40:44 2000
--- /tmp/ip_fil.c       Sat Aug 19 18:56:16 2000
***************
*** 1185,1190 ****
--- 1185,1194 ----
        icmp->icmp_type = type;
        icmp->icmp_code = fin->fin_icode;
        icmp->icmp_cksum = 0;
+       if (type == ICMP_UNREACH &&
+               fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp)
+               icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu);
+ 
        if (avail) {
                bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail));
                avail -= MIN(ohlen, avail);


This patch includes an extra bonus kludge; since fin->fin_ifp is a
void *, I need to cast it.  It looks like it's a void * for solaris
portability, but it also looks like send_icmp_err() is bsd-specific,
so ifp could be declared to be a struct ifnet * and the cast in the
patch could be removed.  I'm not too sure about this, however, so I'm
going to leave the cast in, since I know the only time this code path
can be executed, fin->fin_ifp is a struct ifnet *.

>Release-Note:
>Audit-Trail:
>Unformatted: