kern/123858: stf(4) not usable behind a NAT
Lapo Luchini
lapo at lapo.it
Wed May 21 12:40:03 UTC 2008
>Number: 123858
>Category: kern
>Synopsis: stf(4) not usable behind a NAT
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Wed May 21 12:40:02 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator: Lapo Luchini
>Release: FreeBSD 6.3-PRERELEASE amd64
>Organization:
>Environment:
System: FreeBSD deepie.home.lapo.it 7.0-STABLE FreeBSD 7.0-STABLE #7: Thu Apr 3 08:55:02 CEST 2008 root at deepie.home.lapo.it:/usr/obj/usr/src/sys/DEEPIE amd64
>Description:
The stf(4) interface does proper filtering on the incoming 6to4 packets,
but checking the destination address avoids it to work behind a NAT.
For those of us with a modem/router not capable enough to support IPv6
but capable to redirect protocol 41 traffic (or maybe just all of it) to
a NAT-ed FreeBSD box, this patch means easy and working access to IPv6
world; ok, I'm absent-minded, but I already compiled a kernel forgetting
to re-apply the patch three times in a row ;-)
>How-To-Repeat:
ping6(8) some IPv6 website, watch the ping packets go (and correctly
reach destination) and never see the answer.
>Fix:
This is ume's patch as in Message-ID: <ygeacqp2y0f.wl%ume at mahoroba.org>,
applied on latest 6-STABLE.
Has been working perfectly for me in the past year and some more
(tracking 6-STABLE on both i386 and amd64).
--- stf.no_addr4check.diff begins here ---
--- share/man/man4/stf.4.orig 2005-02-09 19:07:16.000000000 +0100
+++ share/man/man4/stf.4 2008-04-01 08:34:57.381344242 +0200
@@ -179,6 +179,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
--- sys/net/if_stf.c.orig 2007-09-23 19:50:17.000000000 +0200
+++ sys/net/if_stf.c 2008-04-01 08:34:57.667320642 +0200
@@ -88,6 +88,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>
@@ -181,6 +182,13 @@
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)
{
@@ -334,9 +342,17 @@
* 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
@@ -373,12 +389,14 @@
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;
}
@@ -493,8 +511,10 @@
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;
@@ -569,13 +589,6 @@
}
/*
- * 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);
@@ -627,7 +640,16 @@
*/
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);
}
@@ -678,6 +700,18 @@
#endif
/*
+ * Skip RFC1918 check against dest address to allowincoming
+ * 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.
* for source, perform ingress filter as well.
*/
--- stf.no_addr4check.diff ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list