Subject: kern/10813: ipnat drops ICMP packets
To: None <gnats-bugs@gnats.netbsd.org>
From: IWAMOTO Toshihiro <iwamoto@sat.t.u-tokyo.ac.jp>
List: netbsd-bugs
Date: 08/10/2000 23:04:21
>Number:         10813
>Category:       kern
>Synopsis:       ipnat drops ICMP packets
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Aug 10 23:05:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     IWAMOTO Toshihiro
>Release:        yesterday's -current
>Organization:
	
>Environment:
	
System: NetBSD kiku.my.domain 1.5E NetBSD 1.5E (KIKU) #68: Fri Aug 11 14:48:21 JST 2000 toshii@kiku.my.domain:/usr/src/syssrc/sys/arch/i386/compile/KIKU i386


>Description:
	rev 1.35 of ip_nat.c checks if packets are too short.
	For ICMP packets, this packet length checking double counts
	the length of an IP header contained in ICMP messages.
	So, unless ICMP packets are long enough (such as echo-reply),
	packets are mistakingly considered too short and are dropped.

>How-To-Repeat:
	Configure the machine as a NAT router and run traceroute(1)
	from another machine.

>Fix:
	Apply the following patch.
Index: ip_nat.c
===================================================================
RCS file: /export/kiku/NetBSD/NetBSD-CVS/syssrc/sys/netinet/ip_nat.c,v
retrieving revision 1.35
diff -u -r1.35 ip_nat.c
--- ip_nat.c	2000/08/09 21:00:43	1.35
+++ ip_nat.c	2000/08/11 05:47:53
@@ -1492,8 +1492,10 @@
 
 	oip = (ip_t *)((char *)fin->fin_dp + 8);
 	minlen = (oip->ip_hl << 2);
-	if (ip->ip_len < ICMPERR_MINPKTLEN + minlen)
+	if (minlen < sizeof(ip_t))
 		return NULL;
+	if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
+		return NULL;
 	/*
 	 * Is the buffer big enough for all of it ?  It's the size of the IP
 	 * header claimed in the encapsulated part which is of concern.  It
@@ -1526,7 +1528,7 @@
 		flags = IPN_UDP;
 	if (flags & IPN_TCPUDP) {
 		minlen += 8;		/* + 64bits of data to get ports */
-		if (ip->ip_len < ICMPERR_MINPKTLEN + minlen)
+		if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
 			return NULL;
 		tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
 		if (dir == NAT_INBOUND)
>Release-Note:
>Audit-Trail:
>Unformatted: