Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 12 May 2004 02:53:02 +0900
From:      Hajimu UMEMOTO <ume@FreeBSD.org>
To:        Lukasz Stelmach <Lukasz.Stelmach@k.telmark.waw.pl>
Cc:        SUZUKI Shinsuke <suz@crl.hitachi.co.jp>
Subject:   Re: if_stf bug/feature
Message-ID:  <ygept9aq29t.wl%ume@FreeBSD.org>
In-Reply-To: <20040511160734.GA66419@tygrys.k.telmark.waw.pl>
References:  <ygeisf3thbw.wl%ume@FreeBSD.org> <20040511160734.GA66419@tygrys.k.telmark.waw.pl>

next in thread | previous in thread | raw e-mail | index | archive | help
--Multipart_Wed_May_12_02:53:02_2004-1
Content-Type: text/plain; charset=US-ASCII

Hi,

>>>>> On Tue, 11 May 2004 18:07:34 +0200
>>>>> Lukasz Stelmach <Lukasz.Stelmach@telmark.waw.pl> said:

Lukasz> In one of my previous letters I have mentioned that i use 4.9-RCsomething
Lukasz> and unfortunately this is my only FreeBSD. I am also afraid :-( that
Lukasz> i don't have enough spare time neither. But please send the patch and
Lukasz> I will *try* to look at it if you don't mind.

I knew that you are using 4.X from your post to stable@.  I attach my
candidate patch for 4-STABLE into this mail.
Suzuki-san mentioned RFC3056.  However, though 5-CURRENT checks if an
address is not RFC1918 address, 4-STABLE version of if_stf doesn't
check RFC1918 address.  I included this check into my patch.  It makes
NAT thing more difficult, though.
A friend of mine tested this patch on his 4-STABLE box.

Sincerely,


--Multipart_Wed_May_12_02:53:02_2004-1
Content-Type: application/octet-stream; type=patch
Content-Disposition: attachment; filename="if_stf.c-nat-4s.diff"
Content-Transfer-Encoding: 7bit

Index: share/man/man4/stf.4
diff -u share/man/man4/stf.4.orig share/man/man4/stf.4
--- share/man/man4/stf.4.orig	Wed Sep 18 01:53:04 2002
+++ share/man/man4/stf.4	Wed May 12 00:39:09 2004
@@ -175,6 +175,16 @@
 Note, however, there are other security risks exist.
 If you wish to use the configuration,
 you must not advertise your 6to4 address to others.
+.Pp
+You can configure to use 6to4 from behind NAT by setting the
+.Xr sysctl 8
+variable
+.Va net.link.stf.no_addr4check
+to 1 with support of your NAT box.
+If you are directly connected to the Internet, you shouldn't
+chenge the value of
+.Va net.link.stf.no_addr4check .
+This is only hack to use 6to4 from within a NAT.
 .\"
 .Sh EXAMPLES
 Note that
Index: sys/net/if_stf.c
diff -u -p sys/net/if_stf.c.orig sys/net/if_stf.c
--- sys/net/if_stf.c.orig	Tue Feb  4 03:55:47 2003
+++ sys/net/if_stf.c	Wed May 12 02:43:17 2004
@@ -85,6 +85,7 @@
 #include <sys/errno.h>
 #include <sys/protosw.h>
 #include <sys/kernel.h>
+#include <sys/sysctl.h>
 #include <machine/cpu.h>
 
 #include <sys/malloc.h>
@@ -147,6 +148,7 @@ static int stf_encapcheck __P((const str
 static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *));
 static int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
 	struct rtentry *));
+static int isrfc1918addr __P((struct in_addr *));
 static int stf_checkaddr4 __P((struct stf_softc *, struct in_addr *,
 	struct ifnet *));
 static int stf_checkaddr6 __P((struct stf_softc *, struct in6_addr *,
@@ -154,6 +156,13 @@ static int stf_checkaddr6 __P((struct st
 static void stf_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
 static int stf_ioctl __P((struct ifnet *, u_long, caddr_t));
 
+SYSCTL_DECL(_net_link);
+SYSCTL_NODE(_net_link, IFT_STF, stf, CTLFLAG_RW, 0, "6to4 Interface");
+
+static int no_addr4check = 0;
+SYSCTL_INT(_net_link_stf, OID_AUTO, no_addr4check, CTLFLAG_RW,
+    &no_addr4check, 0, "Skip outer IPv4 address");
+
 static int
 stfmodevent(mod, type, data)
 	module_t mod;
@@ -261,9 +270,17 @@ stf_encapcheck(m, off, proto, arg)
 	 * local 6to4 address.
 	 * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:...
 	 */
-	if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst,
-	    sizeof(ip.ip_dst)) != 0)
-		return 0;
+	if (no_addr4check) {
+		struct ifnet *tif;
+
+		INADDR_TO_IFP(ip.ip_dst, tif);
+		if (!tif)
+			return 0;
+	} else {
+		if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst,
+		    sizeof(ip.ip_dst)) != 0)
+			return 0;
+	}
 
 	/*
 	 * check if IPv4 src matches the IPv4 address derived from the
@@ -301,12 +318,14 @@ stf_getsrcifa6(ifp)
 		if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr))
 			continue;
 
-		bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in));
-		LIST_FOREACH(ia4, INADDR_HASH(in.s_addr), ia_hash)
-			if (ia4->ia_addr.sin_addr.s_addr == in.s_addr)
-				break;
-		if (ia4 == NULL)
-			continue;
+		if (!no_addr4check) {
+			bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in));
+			LIST_FOREACH(ia4, INADDR_HASH(in.s_addr), ia_hash)
+				if (ia4->ia_addr.sin_addr.s_addr == in.s_addr)
+					break;
+			if (ia4 == NULL)
+				continue;
+		}
 
 		return (struct in6_ifaddr *)ia;
 	}
@@ -404,8 +423,9 @@ stf_output(ifp, m, dst, rt)
 
 	bzero(ip, sizeof(*ip));
 
-	bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr),
-	    &ip->ip_src, sizeof(ip->ip_src));
+	if (!no_addr4check)
+		bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr),
+		    &ip->ip_src, sizeof(ip->ip_src));
 	bcopy(in4, &ip->ip_dst, sizeof(ip->ip_dst));
 	ip->ip_p = IPPROTO_IPV6;
 	ip->ip_ttl = ip_stf_ttl;
@@ -440,6 +460,22 @@ stf_output(ifp, m, dst, rt)
 }
 
 static int
+isrfc1918addr(in)
+	struct in_addr *in;
+{
+	/*
+	 * returns 1 if private address range:
+	 * 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
+	 */
+	if ((ntohl(in->s_addr) & 0xff000000) >> 24 == 10 ||
+	    (ntohl(in->s_addr) & 0xfff00000) >> 16 == 172 * 256 + 16 ||
+	    (ntohl(in->s_addr) & 0xffff0000) >> 16 == 192 * 256 + 168)
+		return 1;
+
+	return 0;
+}
+
+static int
 stf_checkaddr4(sc, in, inifp)
 	struct stf_softc *sc;
 	struct in_addr *in;
@@ -508,8 +544,20 @@ stf_checkaddr6(sc, in6, inifp)
 	/*
 	 * check 6to4 addresses
 	 */
-	if (IN6_IS_ADDR_6TO4(in6))
-		return stf_checkaddr4(sc, GET_V4(in6), inifp);
+	if (IN6_IS_ADDR_6TO4(in6)) {
+		struct in_addr in4;
+
+		bcopy(GET_V4(in6), &in4, sizeof(in4));
+
+		/*
+		 * reject packets with private address range.
+		 * (requirement from RFC3056 section 2 1st paragraph)
+		 */
+		if (isrfc1918addr(&in4))
+			return -1;
+
+		return stf_checkaddr4(sc, &in4, inifp);
+	}
 
 	/*
 	 * reject anything that look suspicious.  the test is implemented
@@ -572,6 +620,18 @@ in_stf_input(m, va_alist)
 		return;
 	}
 
+	/*
+	 * Skip RFC1918 check against dest address to allow incoming
+	 * packets with private address for dest.  Though it may
+	 * breasks the requirement from RFC3056 section 2 1st
+	 * paragraph, it helps for 6to4 over NAT.
+	 */
+	if ((!no_addr4check && isrfc1918addr(&ip->ip_dst)) ||
+	    isrfc1918addr(&ip->ip_src)) {
+		m_freem(m);
+		return;
+	}
+
 	otos = ip->ip_tos;
 	m_adj(m, off);
 
@@ -668,6 +728,7 @@ stf_ioctl(ifp, cmd, data)
 	struct ifaddr *ifa;
 	struct ifreq *ifr;
 	struct sockaddr_in6 *sin6;
+	struct in_addr addr;
 	int error;
 
 	error = 0;
@@ -679,11 +740,18 @@ stf_ioctl(ifp, cmd, data)
 			break;
 		}
 		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
-		if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) {
-			ifa->ifa_rtrequest = stf_rtrequest;
-			ifp->if_flags |= IFF_UP;
-		} else
+		if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) {
+			error = EINVAL;
+			break;
+		}
+		bcopy(GET_V4(&sin6->sin6_addr), &addr, sizeof(addr));
+		if (isrfc1918addr(&addr)) {
 			error = EINVAL;
+			break;
+		}
+
+		ifa->ifa_rtrequest = stf_rtrequest;
+		ifp->if_flags |= IFF_UP;
 		break;
 
 	case SIOCADDMULTI:

--Multipart_Wed_May_12_02:53:02_2004-1
Content-Type: text/plain; charset=US-ASCII

--
Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan
ume@mahoroba.org  ume@{,jp.}FreeBSD.org
http://www.imasy.org/~ume/

--Multipart_Wed_May_12_02:53:02_2004-1--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?ygept9aq29t.wl%ume>