NetBSD Problem Report #38457
From ws@tools.de Fri Apr 18 15:21:40 2008
Return-Path: <ws@tools.de>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
by narn.NetBSD.org (Postfix) with ESMTP id E7F4E63B293
for <gnats-bugs@gnats.NetBSD.org>; Fri, 18 Apr 2008 15:21:40 +0000 (UTC)
Message-Id: <20080418152135.87B3E6BA9F@sdsl1.tools.de>
Date: Fri, 18 Apr 2008 17:21:35 +0200 (MEST)
From: ws@tools.de
Reply-To: ws@tools.de
To: gnats-bugs@gnats.NetBSD.org
Subject: ipf doesn't handle IPv6 fragments
X-Send-Pr-Version: 3.95
>Number: 38457
>Category: kern
>Synopsis: ipf doesn't handle IPv6 fragments
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Apr 18 15:25:00 +0000 2008
>Closed-Date: Mon May 30 00:01:44 +0000 2016
>Last-Modified: Mon May 30 00:01:44 +0000 2016
>Originator: Wolfgang Solfrank
>Release: NetBSD 4.99.58
>Organization:
Tools GmbH
>Environment:
System: NetBSD sdsl1.tools.de 4.99.58 NetBSD 4.99.58 (sdsl1) #0: Thu Apr 10 18:40:23 MEST 2008 ws@sdsl1.tools.de:/src/obj/sys/arch/i386/compile/sdsl1 i386
Architecture: i386
Machine: i386
>Description:
ipf doesn't handle IPv6 fragments. The first fragment is not handled correctly,
since the fragment header is skipped twice. The other fragments are not
handled at all.
>How-To-Repeat:
Arrange for some fragmented IPv6 packets to arrive at your box on a port
where you have configured a "keep frags" rule. Observe that the traffic
doesn't arrive at the destination.
>Fix:
Index: fil.c
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/fil.c,v
retrieving revision 1.42
diff -u -r1.42 fil.c
--- fil.c 17 Sep 2007 06:25:21 -0000 1.42
+++ fil.c 18 Apr 2008 14:52:56 -0000
@@ -694,12 +694,11 @@
}
fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
- fin->fin_off <<= 3;
if (fin->fin_off != 0)
fin->fin_flx |= FI_FRAGBODY;
- fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag);
- fin->fin_dlen -= sizeof(*frag);
+ if (frag->ip6f_offlg & IP6F_MORE_FRAG)
+ fin->fin_flx |= FI_MOREFRAG;
return frag->ip6f_nxt;
}
@@ -1455,6 +1454,8 @@
int morefrag = off & IP_MF;
fi->fi_flx |= FI_FRAG;
+ if (morefrag)
+ fi->fi_flx |= FI_MOREFRAG;
off &= IP_OFFMASK;
if (off != 0) {
fin->fin_flx |= FI_FRAGBODY;
Index: ip_fil.h
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_fil.h,v
retrieving revision 1.15
diff -u -r1.15 ip_fil.h
--- ip_fil.h 2 Oct 2007 06:15:11 -0000 1.15
+++ ip_fil.h 18 Apr 2008 14:52:56 -0000
@@ -271,6 +271,7 @@
#define FI_V6EXTHDR 0x10000
#define FI_COALESCE 0x20000
#define FI_NEWNAT 0x40000
+#define FI_MOREFRAG 0x80000
#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */
#define FI_DONTCACHE 0x40000000 /* don't cache the result */
#define FI_IGNORE 0x80000000
Index: ip_frag.c
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_frag.c,v
retrieving revision 1.8
diff -u -r1.8 ip_frag.c
--- ip_frag.c 2 Oct 2007 06:15:12 -0000 1.8
+++ ip_frag.c 18 Apr 2008 14:52:56 -0000
@@ -134,6 +134,7 @@
u_long fr_ticks = 0;
+static INLINE int ipfr_index __P((fr_info_t *, ipfr_t *));
static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
static void fr_fragdelete __P((ipfr_t *, ipfr_t ***));
@@ -218,6 +219,76 @@
/* ------------------------------------------------------------------------ */
+/* Function: ipfr_index */
+/* Returns: int - index in fragment table for given packet */
+/* Parameters: fin(I) - pointer to packet information */
+/* frag(O) - pointer to ipfr_t structure to fill */
+/* */
+/* Compute the index in the fragment table while filling the per packet */
+/* part of the fragment state. */
+/* ------------------------------------------------------------------------ */
+static INLINE int ipfr_index(fin, frag)
+fr_info_t *fin;
+ipfr_t *frag;
+{
+ u_int idx;
+
+ /*
+ * For fragments, we record protocol, packet id, TOS and both IP#'s
+ * (these should all be the same for all fragments of a packet).
+ *
+ * build up a hash value to index the table with.
+ */
+
+#ifdef USE_INET6
+ if (fin->fin_v == 6) {
+ ip6_t *ip6 = (ip6_t *)fin->fin_ip;
+
+ frag->ipfr_p = fin->fin_fi.fi_p;
+ frag->ipfr_id = fin->fin_id;
+ frag->ipfr_tos = ip6->ip6_flow & IPV6_FLOWINFO_MASK;
+ frag->ipfr_src.in6 = ip6->ip6_src;
+ frag->ipfr_dst.in6 = ip6->ip6_dst;
+ } else
+#endif
+ {
+ ip_t *ip = fin->fin_ip;
+
+ frag->ipfr_p = ip->ip_p;
+ frag->ipfr_id = ip->ip_id;
+ frag->ipfr_tos = ip->ip_tos;
+ frag->ipfr_src.in4.s_addr = ip->ip_src.s_addr;
+ frag->ipfr_src.i6[1] = 0;
+ frag->ipfr_src.i6[2] = 0;
+ frag->ipfr_src.i6[3] = 0;
+ frag->ipfr_dst.in4.s_addr = ip->ip_dst.s_addr;
+ frag->ipfr_dst.i6[1] = 0;
+ frag->ipfr_dst.i6[2] = 0;
+ frag->ipfr_dst.i6[3] = 0;
+ }
+ frag->ipfr_ifp = fin->fin_ifp;
+ frag->ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
+ frag->ipfr_secmsk = fin->fin_fi.fi_secmsk;
+ frag->ipfr_auth = fin->fin_fi.fi_auth;
+
+ idx = frag->ipfr_p;
+ idx += frag->ipfr_id;
+ idx += frag->ipfr_src.i6[0];
+ idx += frag->ipfr_src.i6[1];
+ idx += frag->ipfr_src.i6[2];
+ idx += frag->ipfr_src.i6[3];
+ idx += frag->ipfr_dst.i6[0];
+ idx += frag->ipfr_dst.i6[1];
+ idx += frag->ipfr_dst.i6[2];
+ idx += frag->ipfr_dst.i6[3];
+ idx *= 127;
+ idx %= IPFT_SIZE;
+
+ return idx;
+}
+
+
+/* ------------------------------------------------------------------------ */
/* Function: ipfr_newfrag */
/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
/* Parameters: fin(I) - pointer to packet information */
@@ -234,7 +305,6 @@
ipfr_t *fra, frag;
u_int idx, off;
frentry_t *fr;
- ip_t *ip;
if (ipfr_inuse >= IPFT_SIZE)
return NULL;
@@ -242,28 +312,11 @@
if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
return NULL;
- ip = fin->fin_ip;
-
if (pass & FR_FRSTRICT)
if (fin->fin_off != 0)
return NULL;
- frag.ipfr_p = ip->ip_p;
- idx = ip->ip_p;
- frag.ipfr_id = ip->ip_id;
- idx += ip->ip_id;
- frag.ipfr_tos = ip->ip_tos;
- frag.ipfr_src.s_addr = ip->ip_src.s_addr;
- idx += ip->ip_src.s_addr;
- frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
- idx += ip->ip_dst.s_addr;
- frag.ipfr_ifp = fin->fin_ifp;
- idx *= 127;
- idx %= IPFT_SIZE;
-
- frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
- frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
- frag.ipfr_auth = fin->fin_fi.fi_auth;
+ idx = ipfr_index(fin, &frag);
/*
* first, make sure it isn't already there...
@@ -309,7 +362,7 @@
/*
* Compute the offset of the expected start of the next packet.
*/
- off = ip->ip_off & IP_OFFMASK;
+ off = fin->fin_off >> 3;
if (off == 0)
fra->ipfr_seen0 = 1;
fra->ipfr_off = off + (fin->fin_dlen >> 3);
@@ -334,7 +387,7 @@
{
ipfr_t *fra;
- if ((fin->fin_v != 4) || (fr_frag_lock != 0))
+ if (fr_frag_lock != 0)
return -1;
WRITE_ENTER(&ipf_frag);
@@ -368,7 +421,7 @@
{
ipfr_t *fra;
- if ((fin->fin_v != 4) || (fr_frag_lock != 0))
+ if (fr_frag_lock != 0)
return 0;
WRITE_ENTER(&ipf_natfrag);
@@ -401,7 +454,7 @@
{
ipfr_t *fra;
- if ((fin->fin_v != 4) || (fr_frag_lock))
+ if (fr_frag_lock)
return 0;
WRITE_ENTER(&ipf_ipidfrag);
@@ -434,34 +487,11 @@
{
ipfr_t *f, frag;
u_int idx;
- ip_t *ip;
if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
return NULL;
- /*
- * For fragments, we record protocol, packet id, TOS and both IP#'s
- * (these should all be the same for all fragments of a packet).
- *
- * build up a hash value to index the table with.
- */
- ip = fin->fin_ip;
- frag.ipfr_p = ip->ip_p;
- idx = ip->ip_p;
- frag.ipfr_id = ip->ip_id;
- idx += ip->ip_id;
- frag.ipfr_tos = ip->ip_tos;
- frag.ipfr_src.s_addr = ip->ip_src.s_addr;
- idx += ip->ip_src.s_addr;
- frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
- idx += ip->ip_dst.s_addr;
- frag.ipfr_ifp = fin->fin_ifp;
- idx *= 127;
- idx %= IPFT_SIZE;
-
- frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
- frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
- frag.ipfr_auth = fin->fin_fi.fi_auth;
+ idx = ipfr_index(fin, &frag);
/*
* check the table, careful to only compare the right amount of data
@@ -492,7 +522,7 @@
* because a fragmented packet is never resent with
* the same IP ID# (or shouldn't).
*/
- off = ip->ip_off & IP_OFFMASK;
+ off = fin->fin_off >> 3;
if (f->ipfr_seen0) {
if (off == 0) {
ATOMIC_INCL(ipfr_stats.ifs_retrans0);
@@ -526,7 +556,7 @@
* last (in order), shrink expiration time.
*/
if (off == f->ipfr_off) {
- if (!(ip->ip_off & IP_MF))
+ if (!(fin->fin_flx & FI_MOREFRAG))
f->ipfr_ttl = fr_ticks + 1;
f->ipfr_off = (fin->fin_dlen >> 3) + off;
} else if (f->ipfr_pass & FR_FRSTRICT)
@@ -552,7 +582,7 @@
nat_t *nat;
ipfr_t *ipf;
- if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist)
+ if ((fr_frag_lock) || !ipfr_natlist)
return NULL;
READ_ENTER(&ipf_natfrag);
ipf = fr_fraglookup(fin, ipfr_nattab);
@@ -586,7 +616,7 @@
ipfr_t *ipf;
u_32_t id;
- if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist)
+ if ((fr_frag_lock) || !ipfr_ipidlist)
return 0xffffffff;
READ_ENTER(&ipf_ipidfrag);
@@ -619,7 +649,7 @@
ipfr_t *fra;
u_32_t pass;
- if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL))
+ if ((fr_frag_lock) || (ipfr_list == NULL))
return NULL;
READ_ENTER(&ipf_frag);
Index: ip_frag.h
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_frag.h,v
retrieving revision 1.4
diff -u -r1.4 ip_frag.h
--- ip_frag.h 14 Apr 2007 20:34:36 -0000 1.4
+++ ip_frag.h 18 Apr 2008 14:52:56 -0000
@@ -29,14 +29,14 @@
* therefore important for this set to remain together.
*/
void *ipfr_ifp;
- struct in_addr ipfr_src;
- struct in_addr ipfr_dst;
+ i6addr_t ipfr_src;
+ i6addr_t ipfr_dst;
u_32_t ipfr_optmsk;
u_short ipfr_secmsk;
u_short ipfr_auth;
- u_short ipfr_id;
- u_char ipfr_p;
- u_char ipfr_tos;
+ u_32_t ipfr_id;
+ u_32_t ipfr_p;
+ u_32_t ipfr_tos;
u_32_t ipfr_pass;
} ipfr_t;
>Release-Note:
>Audit-Trail:
From: darrenr@NetBSD.org (Darren Reed)
To: ws@tools.de
Cc: gnats-bugs@NetBSD.org
Subject: Re: kern/38457
Date: Tue, 4 Nov 2008 01:38:53 +0000 (UTC)
IPFilter version 4 doesn't handle ipv6 fragments - this is a known
issue, hence the "if fin_v != 4" parts of the code.
State-Changed-From-To: open->feedback
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Thu, 15 Jan 2015 22:41:55 +0000
State-Changed-Why:
Is this still true with current ipf? Christos says it isn't.
State-Changed-From-To: feedback->closed
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Mon, 30 May 2016 00:01:44 +0000
State-Changed-Why:
Feedback timeout.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.