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: