Date: 21 May 2008 12:35:53 -0000 From: Lapo Luchini <lapo@lapo.it> To: FreeBSD-gnats-submit@FreeBSD.org Cc: Lapo Luchini <lapo@lapo.it> Subject: kern/123858: stf(4) not usable behind a NAT Message-ID: <20080521123553.57266.qmail@mail.lapo.it> Resent-Message-ID: <200805211240.m4LCe33Z032518@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080521123553.57266.qmail>