summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/ip6_forward.c
diff options
context:
space:
mode:
authoritojun <itojun@FreeBSD.org>2000-07-04 16:35:15 +0000
committeritojun <itojun@FreeBSD.org>2000-07-04 16:35:15 +0000
commit5f4e854de19331a53788d6100bbcd42845056bc1 (patch)
tree3ff8c876a5868b103fb8713055d83e29a3fa38d5 /sys/netinet6/ip6_forward.c
parentbdc16885232d771a99d7dfc247cd27a44cd061f9 (diff)
downloadFreeBSD-src-5f4e854de19331a53788d6100bbcd42845056bc1.zip
FreeBSD-src-5f4e854de19331a53788d6100bbcd42845056bc1.tar.gz
sync with kame tree as of july00. tons of bug fixes/improvements.
API changes: - additional IPv6 ioctls - IPsec PF_KEY API was changed, it is mandatory to upgrade setkey(8). (also syntax change)
Diffstat (limited to 'sys/netinet6/ip6_forward.c')
-rw-r--r--sys/netinet6/ip6_forward.c237
1 files changed, 200 insertions, 37 deletions
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 249d38c..ba9bdad 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -1,3 +1,6 @@
+/* $FreeBSD$ */
+/* $KAME: ip6_forward.c,v 1.39 2000/07/03 13:23:28 itojun Exp $ */
+
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
@@ -25,10 +28,11 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
+#include "opt_ip6fw.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_ipsec.h"
#include <sys/param.h>
@@ -46,20 +50,15 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <netinet6/ip6.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
-#include <netinet6/icmp6.h>
+#include <netinet/icmp6.h>
#include <netinet6/nd6.h>
#ifdef IPSEC_IPV6FWD
#include <netinet6/ipsec.h>
-#include <netinet6/ipsec6.h>
#include <netkey/key.h>
-#ifdef IPSEC_DEBUG
-#include <netkey/key_debug.h>
-#else
-#define KEYDEBUG(lev,arg)
-#endif
#endif /* IPSEC_IPV6FWD */
#ifdef IPV6FIREWALL
@@ -92,7 +91,8 @@ ip6_forward(m, srcrt)
register struct sockaddr_in6 *dst;
register struct rtentry *rt;
int error, type = 0, code = 0;
- struct mbuf *mcopy;
+ struct mbuf *mcopy = NULL;
+ struct ifnet *origifp; /* maybe unnecessary */
#ifdef IPSEC_IPV6FWD
struct secpolicy *sp = NULL;
#endif
@@ -112,19 +112,17 @@ ip6_forward(m, srcrt)
}
#endif /*IPSEC_IPV6FWD*/
- if (m->m_flags & (M_BCAST|M_MCAST) ||
- in6_canforward(&ip6->ip6_src, &ip6->ip6_dst) == 0) {
+ if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
+ IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
ip6stat.ip6s_cantforward++;
- ip6stat.ip6s_badscope++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
if (ip6_log_time + ip6_log_interval < time_second) {
- char addr[INET6_ADDRSTRLEN];
ip6_log_time = time_second;
- strncpy(addr, ip6_sprintf(&ip6->ip6_src), sizeof(addr));
log(LOG_DEBUG,
"cannot forward "
"from %s to %s nxt %d received on %s\n",
- addr, ip6_sprintf(&ip6->ip6_dst),
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
ip6->ip6_nxt,
if_name(m->m_pkthdr.rcvif));
}
@@ -140,13 +138,30 @@ ip6_forward(m, srcrt)
}
ip6->ip6_hlim -= IPV6_HLIMDEC;
+ /*
+ * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
+ * size of IPv6 + ICMPv6 headers) bytes of the packet in case
+ * we need to generate an ICMP6 message to the src.
+ * Thanks to M_EXT, in most cases copy will not occur.
+ *
+ * It is important to save it before IPsec processing as IPsec
+ * processing may modify the mbuf.
+ */
+ mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
+
#ifdef IPSEC_IPV6FWD
/* get a security policy for this packet */
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
if (sp == NULL) {
ipsec6stat.out_inval++;
ip6stat.ip6s_cantforward++;
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
}
@@ -162,7 +177,13 @@ ip6_forward(m, srcrt)
ipsec6stat.out_polvio++;
ip6stat.ip6s_cantforward++;
key_freesp(sp);
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
@@ -171,14 +192,20 @@ ip6_forward(m, srcrt)
/* no need to do IPsec. */
key_freesp(sp);
goto skip_ipsec;
-
+
case IPSEC_POLICY_IPSEC:
if (sp->req == NULL) {
/* XXX should be panic ? */
printf("ip6_forward: No IPsec request specified.\n");
ip6stat.ip6s_cantforward++;
key_freesp(sp);
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
}
@@ -212,7 +239,10 @@ ip6_forward(m, srcrt)
error = ipsec6_output_tunnel(&state, sp, 0);
m = state.m;
- /* XXX allocate a route (ro, dst) again later */
+#if 0 /* XXX allocate a route (ro, dst) again later */
+ ro = (struct route_in6 *)state.ro;
+ dst = (struct sockaddr_in6 *)state.dst;
+#endif
key_freesp(sp);
if (error) {
@@ -232,7 +262,13 @@ ip6_forward(m, srcrt)
break;
}
ip6stat.ip6s_cantforward++;
- /* XXX: any icmp ? */
+ if (mcopy) {
+#if 0
+ /* XXX: what icmp ? */
+#else
+ m_freem(mcopy);
+#endif
+ }
m_freem(m);
return;
}
@@ -255,12 +291,15 @@ ip6_forward(m, srcrt)
rtalloc_ign((struct route *)&ip6_forward_rt,
RTF_PRCLONING);
}
-
+
if (ip6_forward_rt.ro_rt == 0) {
ip6stat.ip6s_noroute++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
- icmp6_error(m, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
+ if (mcopy) {
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOROUTE, 0);
+ }
+ m_freem(m);
return;
}
} else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
@@ -278,26 +317,89 @@ ip6_forward(m, srcrt)
if (ip6_forward_rt.ro_rt == 0) {
ip6stat.ip6s_noroute++;
/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
- icmp6_error(m, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
+ if (mcopy) {
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOROUTE, 0);
+ }
+ m_freem(m);
return;
}
}
rt = ip6_forward_rt.ro_rt;
- if (m->m_pkthdr.len > rt->rt_ifp->if_mtu){
+
+ /*
+ * Scope check: if a packet can't be delivered to its destination
+ * for the reason that the destination is beyond the scope of the
+ * source address, discard the packet and return an icmp6 destination
+ * unreachable error with Code 2 (beyond scope of source address).
+ * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
+ */
+ if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
+ in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
+ ip6stat.ip6s_cantforward++;
+ ip6stat.ip6s_badscope++;
+ in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
+
+ if (ip6_log_time + ip6_log_interval < time_second) {
+ ip6_log_time = time_second;
+ log(LOG_DEBUG,
+ "cannot forward "
+ "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
+ ip6->ip6_nxt,
+ if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
+ }
+ if (mcopy)
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
+ m_freem(m);
+ return;
+ }
+
+ if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
- icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, rt->rt_ifp->if_mtu);
+ if (mcopy) {
+ u_long mtu;
+#ifdef IPSEC_IPV6FWD
+ struct secpolicy *sp;
+ int ipsecerror;
+ size_t ipsechdrsiz;
+#endif
+
+ mtu = rt->rt_ifp->if_mtu;
+#ifdef IPSEC_IPV6FWD
+ /*
+ * When we do IPsec tunnel ingress, we need to play
+ * with if_mtu value (decrement IPsec header size
+ * from mtu value). The code is much simpler than v4
+ * case, as we have the outgoing interface for
+ * encapsulated packet as "rt->rt_ifp".
+ */
+ sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
+ IP_FORWARDING, &ipsecerror);
+ if (sp) {
+ ipsechdrsiz = ipsec6_hdrsiz(mcopy,
+ IPSEC_DIR_OUTBOUND, NULL);
+ if (ipsechdrsiz < mtu)
+ mtu -= ipsechdrsiz;
+ }
+
+ /*
+ * if mtu becomes less than minimum MTU,
+ * tell minimum MTU (and I'll need to fragment it).
+ */
+ if (mtu < IPV6_MMTU)
+ mtu = IPV6_MMTU;
+#endif
+ icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
+ }
+ m_freem(m);
return;
}
if (rt->rt_flags & RTF_GATEWAY)
dst = (struct sockaddr_in6 *)rt->rt_gateway;
- /*
- * Save at most 528 bytes of the packet in case
- * we need to generate an ICMP6 message to the src.
- * Thanks to M_EXT, in most cases copy will not occur.
- */
- mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
/*
* If we are to forward the packet using the same interface
@@ -328,7 +430,66 @@ ip6_forward(m, srcrt)
}
#endif
- error = nd6_output(rt->rt_ifp, m, dst, rt);
+ /*
+ * Fake scoped addresses. Note that even link-local source or
+ * destinaion can appear, if the originating node just sends the
+ * packet to us (without address resolution for the destination).
+ * Since both icmp6_error and icmp6_redirect_output fill the embedded
+ * link identifiers, we can do this stuff after make a copy for
+ * returning error.
+ */
+ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
+ /*
+ * See corresponding comments in ip6_output.
+ * XXX: but is it possible that ip6_forward() sends a packet
+ * to a loopback interface? I don't think so, and thus
+ * I bark here. (jinmei@kame.net)
+ * XXX: it is common to route invalid packets to loopback.
+ * also, the codepath will be visited on use of ::1 in
+ * rthdr. (itojun)
+ */
+#if 1
+ if (0)
+#else
+ if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
+#endif
+ {
+ printf("ip6_forward: outgoing interface is loopback. "
+ "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
+ ip6_sprintf(&ip6->ip6_src),
+ ip6_sprintf(&ip6->ip6_dst),
+ ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
+ if_name(rt->rt_ifp));
+ }
+
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
+ origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
+ else if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
+ origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
+ else
+ origifp = rt->rt_ifp;
+ }
+ else
+ origifp = rt->rt_ifp;
+#ifndef FAKE_LOOPBACK_IF
+ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
+#else
+ if (1)
+#endif
+ {
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
+ ip6->ip6_src.s6_addr16[1] = 0;
+ if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
+ ip6->ip6_dst.s6_addr16[1] = 0;
+ }
+
+#ifdef OLDIP6OUTPUT
+ error = (*rt->rt_ifp->if_output)(rt->rt_ifp, m,
+ (struct sockaddr *)dst,
+ ip6_forward_rt.ro_rt);
+#else
+ error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
+#endif
if (error) {
in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
ip6stat.ip6s_cantforward++;
@@ -347,10 +508,12 @@ ip6_forward(m, srcrt)
switch (error) {
case 0:
+#if 1
if (type == ND_REDIRECT) {
icmp6_redirect_output(mcopy, rt);
return;
}
+#endif
goto freecopy;
case EMSGSIZE:
OpenPOWER on IntegriCloud