if_stf and rfc1918

Hajimu UMEMOTO ume at freebsd.org
Mon Jan 31 11:34:54 PST 2005


Hi,

>>>>> On Mon, 31 Jan 2005 00:53:57 +0100
>>>>> Lukasz Stelmach <Lukasz.Stelmach at telmark.waw.pl> said:

Lukasz> Once I've discussed this matter with Hajimu UMEMOTO and he posted a patch
Lukasz> that made it possible to run 6to4 router behind a nat (FreeBSD 4.x). Soon
Lukasz> I will probably be upgrading my old system to 5.x release so I checked
Lukasz> if newer stf code allows such operation and to my disapointment I've
Lukasz> found out that it doesn't (or at least it seems so). The comment in the
Lukasz> code says that it is a requirement of RFC3056. I've check it and in fact
Lukasz> it says that RFC1918 addresses MUST NOT be used as NLAs in 6to4 addresses.
Lukasz> But IMHO it does not mean that I can't run my 6to4 router behind a NAT
Lukasz> at all. In such a situation the IPv6 address contains valid public IPv4
Lukasz> address and the private one in the IPv4 header is substitutet by NAT. So
Lukasz> after the packets leave my site they are completly valid 6to4 packets.
Lukasz> Also when 6to4 packets come to me they are handeled properly.

Lukasz> My question now is why FreeBSD is so restrictive about it.

Oops, I completely forget this issue.  If there is no objection, I'll
commit following patch into HEAD then MFC to RELENG_5.

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	Sat Jan  4 14:15:26 2003
+++ share/man/man4/stf.4	Tue Feb  1 02:05:05 2005
@@ -178,6 +178,17 @@
 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.  In this case, make sure to use a
+6to4 address which is worked out from an IPv4 global address 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	Thu Jan 13 00:47:31 2005
+++ sys/net/if_stf.c	Tue Feb  1 04:00:34 2005
@@ -89,6 +89,7 @@
 #include <sys/module.h>
 #include <sys/protosw.h>
 #include <sys/queue.h>
+#include <sys/sysctl.h>
 #include <machine/cpu.h>
 
 #include <sys/malloc.h>
@@ -183,6 +184,13 @@ static int stf_clone_destroy(struct if_c
 struct if_clone stf_cloner = IFC_CLONE_INITIALIZER(STFNAME, NULL, 0,
     NULL, stf_clone_match, stf_clone_create, stf_clone_destroy);
 
+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 checking outer IPv4 address");
+
 static int
 stf_clone_match(struct if_clone *ifc, const char *name)
 {
@@ -357,9 +365,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
@@ -401,12 +417,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;
 	}
@@ -511,8 +529,10 @@ 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;
@@ -587,13 +607,6 @@ stf_checkaddr4(sc, in, inifp)
 	}
 
 	/*
-	 * reject packets with private address range.
-	 * (requirement from RFC3056 section 2 1st paragraph)
-	 */
-	if (isrfc1918addr(in))
-		return -1;
-
-	/*
 	 * reject packets with broadcast
 	 */
 	for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
@@ -645,7 +658,16 @@ stf_checkaddr6(sc, 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);
 	}
 
@@ -694,6 +716,18 @@ in_stf_input(m, off)
 #ifdef MAC
 	mac_create_mbuf_from_ifnet(ifp, m);
 #endif
+
+	/*
+	 * 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;
+	}
 
 	/*
 	 * perform sanity check against outer src/dst.


Sincerely,

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


More information about the freebsd-net mailing list