Subject: ipf patch: -current silently drops small fragments
To: None <tech-net@NetBSD.org>
From: Stephen Degler <stephen@degler.net>
List: tech-net
Date: 07/09/2005 02:32:14
------=_20050709023214_72016
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

This patch fixes a problem I see with ipf on -current'ish kernels.  Ipf
will silently drop small ipv4 fragments under the following conditions.

1) The fragment is part of a icmp, esp, or gre packet.
2) The fragment offset is non zero.
3) The data size is less than the size of the (icmp,esp,gre) header.

This happens because pullup is called for the size of the upper layer
header, regardless of the current offset of the fragment.

Please take a look at this and let me know if it is ok.  Also, I'm not
clear on how the patch should be handled.  If accepted, does it go into
the next rev of ipf and get imported, or is it ok to commit to the NetBSD
tree?

thanks,
skd





------=_20050709023214_72016
Content-Type: text/x-patch; name="fil.c.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="fil.c.patch"

Index: fil.c
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/fil.c,v
retrieving revision 1.16
diff -u -r1.16 fil.c
--- fil.c	11 Jun 2005 12:31:40 -0000	1.16
+++ fil.c	9 Jul 2005 06:15:38 -0000
@@ -886,7 +886,7 @@
 	int minicmpsz = sizeof(struct icmp);
 	icmphdr_t *icmp;
 
-	if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+	if (fin->fin_off == 0 && frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
 		return;
 
 	fr_checkv4sum(fin);
@@ -1171,7 +1171,7 @@
 static INLINE void frpr_esp(fin)
 fr_info_t *fin;
 {
-	if (frpr_pullup(fin, 8) == -1)
+	if (fin->fin_off == 0 && frpr_pullup(fin, 8) == -1)
 		return;
 
 	if (fin->fin_v == 4)
@@ -1195,7 +1195,7 @@
 {
 	grehdr_t *gre;
 
-	if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
+	if (fin->fin_off == 0 && frpr_pullup(fin, sizeof(grehdr_t)) == -1)
 		return;
 
 	if (fin->fin_v == 4)
@@ -1204,9 +1204,11 @@
 	else if (fin->fin_v == 6)
 		frpr_short6(fin, sizeof(grehdr_t));
 #endif
-	gre = fin->fin_dp;
-	if (GRE_REV(gre->gr_flags) == 1)
-		fin->fin_data[0] = gre->gr_call;
+	if (fin->fin_off == 0 ) {
+		gre = fin->fin_dp;
+		if (GRE_REV(gre->gr_flags) == 1)
+			fin->fin_data[0] = gre->gr_call;
+        }
 }
 
 
@@ -2150,7 +2152,7 @@
 /*              User space:                                                 */
 /*                    -1 == packet blocked                                  */
 /*                     1 == packet not matched                              */
-/*                    -2 == requires authantication                         */
+/*                    -2 == requires authentication                         */
 /*              Kernel:                                                     */
 /*                   > 0 == filter error # for packet                       */
 /* Parameters: ip(I)   - pointer to start of IPv4/6 packet                  */
------=_20050709023214_72016--