Subject: kern/5559: ip_fil fails to send ICMP error when DF set and frag needed (breaks MTU discovery)
To: None <gnats-bugs@gnats.netbsd.org>
From: Bill Sommerfeld <sommerfeld@orchard.arlington.ma.us>
List: netbsd-bugs
Date: 06/09/1998 23:26:17
>Number: 5559
>Category: kern
>Synopsis: ip_fil fails to send ICMP error when DF set and frag needed (breaks MTU discovery)
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jun 9 16:35:01 1998
>Last-Modified:
>Originator: Bill Sommerfeld
>Organization:
>Release: 19980609
>Environment:
System: NetBSD orchard.arlington.ma.us 1.3F NetBSD 1.3F (ORCHARDII) #19: Tue Jun 9 15:48:49 EDT 1998 sommerfeld@orchard.arlington.ma.us:/d3/NetBSD-current/src/sys/arch/i386/compile/ORCHARDII i386
>Description:
If you're using the `fastroute' feature of ipfil, and the
forwarded-to interface has a smaller MTU than the packet being
forwarded, the packet in question gets bitbucketed without
error.
>How-To-Repeat:
run with ipf rules including one resembling:
pass out on ep0 to ppp0 from 128.224.138.0/24 to any group 350
with ppp0 having an mtu of <1500, turn on path MTU discovery
on a client, and watch TCP wedge up when sending max sized packets.
Note that since the `dup' feature also uses ipfr_fastroute,
this means that ICMP errors also get generated for the `dup'ed
interface. I'm not sure whether this is a bug or a feature..
(but then again, if the dup'ed I/F has a smaller MTU than the real
outbound I/F, packets with DF will be dropped rather than
fragmented going out the dup'ed IF..)
>Fix:
Index: ip_fil.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_fil.c,v
retrieving revision 1.27
diff -u -r1.27 ip_fil.c
--- ip_fil.c 1998/05/17 17:07:25 1.27
+++ ip_fil.c 1998/06/09 20:11:36
@@ -993,6 +993,12 @@
* Must be able to put at least 8 bytes per fragment.
*/
if (ip->ip_off & IP_DF) {
+ /* Send ICMP error here */
+ struct mbuf *mcopy;
+ mcopy = m_copy(m, 0, imin((int)ip->ip_len, 68));
+ if (mcopy)
+ icmp_error(mcopy, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
+ ip->ip_dst.s_addr, ifp);
error = EMSGSIZE;
goto bad;
}
>Audit-Trail:
>Unformatted: