ip6_forward.c revision 165118
10Sstevel@tonic-gate/*	$FreeBSD: head/sys/netinet6/ip6_forward.c 165118 2006-12-12 12:17:58Z bz $	*/
20Sstevel@tonic-gate/*	$KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $	*/
30Sstevel@tonic-gate
40Sstevel@tonic-gate/*-
50Sstevel@tonic-gate * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
60Sstevel@tonic-gate * All rights reserved.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
90Sstevel@tonic-gate * modification, are permitted provided that the following conditions
100Sstevel@tonic-gate * are met:
110Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
120Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer.
130Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
140Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer in the
150Sstevel@tonic-gate *    documentation and/or other materials provided with the distribution.
160Sstevel@tonic-gate * 3. Neither the name of the project nor the names of its contributors
170Sstevel@tonic-gate *    may be used to endorse or promote products derived from this software
180Sstevel@tonic-gate *    without specific prior written permission.
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
210Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
220Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
230Sstevel@tonic-gate * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
240Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
250Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
260Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
270Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
280Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
290Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
300Sstevel@tonic-gate * SUCH DAMAGE.
310Sstevel@tonic-gate */
320Sstevel@tonic-gate
330Sstevel@tonic-gate#include "opt_inet.h"
340Sstevel@tonic-gate#include "opt_inet6.h"
350Sstevel@tonic-gate#include "opt_ipsec.h"
360Sstevel@tonic-gate#include "opt_ipstealth.h"
370Sstevel@tonic-gate
380Sstevel@tonic-gate#include <sys/param.h>
390Sstevel@tonic-gate#include <sys/systm.h>
400Sstevel@tonic-gate#include <sys/malloc.h>
410Sstevel@tonic-gate#include <sys/mbuf.h>
420Sstevel@tonic-gate#include <sys/domain.h>
430Sstevel@tonic-gate#include <sys/protosw.h>
440Sstevel@tonic-gate#include <sys/socket.h>
450Sstevel@tonic-gate#include <sys/errno.h>
460Sstevel@tonic-gate#include <sys/time.h>
470Sstevel@tonic-gate#include <sys/kernel.h>
480Sstevel@tonic-gate#include <sys/syslog.h>
490Sstevel@tonic-gate
500Sstevel@tonic-gate#include <net/if.h>
510Sstevel@tonic-gate#include <net/route.h>
520Sstevel@tonic-gate#include <net/pfil.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate#include <netinet/in.h>
550Sstevel@tonic-gate#include <netinet/in_var.h>
560Sstevel@tonic-gate#include <netinet/in_systm.h>
570Sstevel@tonic-gate#include <netinet/ip.h>
580Sstevel@tonic-gate#include <netinet/ip_var.h>
590Sstevel@tonic-gate#include <netinet6/in6_var.h>
600Sstevel@tonic-gate#include <netinet/ip6.h>
610Sstevel@tonic-gate#include <netinet6/ip6_var.h>
620Sstevel@tonic-gate#include <netinet6/scope6_var.h>
630Sstevel@tonic-gate#include <netinet/icmp6.h>
640Sstevel@tonic-gate#include <netinet6/nd6.h>
650Sstevel@tonic-gate
660Sstevel@tonic-gate#include <netinet/in_pcb.h>
670Sstevel@tonic-gate
680Sstevel@tonic-gate#ifdef IPSEC
690Sstevel@tonic-gate#include <netinet6/ipsec.h>
700Sstevel@tonic-gate#ifdef INET6
710Sstevel@tonic-gate#include <netinet6/ipsec6.h>
720Sstevel@tonic-gate#endif
730Sstevel@tonic-gate#include <netkey/key.h>
740Sstevel@tonic-gate#endif /* IPSEC */
750Sstevel@tonic-gate
760Sstevel@tonic-gate#ifdef FAST_IPSEC
770Sstevel@tonic-gate#include <netipsec/ipsec.h>
780Sstevel@tonic-gate#include <netipsec/ipsec6.h>
790Sstevel@tonic-gate#include <netipsec/key.h>
800Sstevel@tonic-gate#define	IPSEC
810Sstevel@tonic-gate#endif /* FAST_IPSEC */
820Sstevel@tonic-gate
830Sstevel@tonic-gate#include <netinet6/ip6protosw.h>
840Sstevel@tonic-gate
850Sstevel@tonic-gatestruct	route_in6 ip6_forward_rt;
860Sstevel@tonic-gate
870Sstevel@tonic-gate/*
880Sstevel@tonic-gate * Forward a packet.  If some error occurs return the sender
890Sstevel@tonic-gate * an icmp packet.  Note we can't always generate a meaningful
900Sstevel@tonic-gate * icmp message because icmp doesn't have a large enough repertoire
910Sstevel@tonic-gate * of codes and types.
920Sstevel@tonic-gate *
930Sstevel@tonic-gate * If not forwarding, just drop the packet.  This could be confusing
940Sstevel@tonic-gate * if ipforwarding was zero but some routing protocol was advancing
950Sstevel@tonic-gate * us as a gateway to somewhere.  However, we must let the routing
960Sstevel@tonic-gate * protocol deal with that.
970Sstevel@tonic-gate *
980Sstevel@tonic-gate */
990Sstevel@tonic-gate
1000Sstevel@tonic-gatevoid
1010Sstevel@tonic-gateip6_forward(m, srcrt)
1020Sstevel@tonic-gate	struct mbuf *m;
1030Sstevel@tonic-gate	int srcrt;
1040Sstevel@tonic-gate{
1050Sstevel@tonic-gate	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1060Sstevel@tonic-gate	struct sockaddr_in6 *dst = NULL;
1070Sstevel@tonic-gate	struct rtentry *rt = NULL;
1080Sstevel@tonic-gate	int error, type = 0, code = 0;
1090Sstevel@tonic-gate	struct mbuf *mcopy = NULL;
1100Sstevel@tonic-gate	struct ifnet *origifp;	/* maybe unnecessary */
1110Sstevel@tonic-gate	u_int32_t inzone, outzone;
1120Sstevel@tonic-gate	struct in6_addr src_in6, dst_in6;
1130Sstevel@tonic-gate#ifdef IPSEC
1140Sstevel@tonic-gate	struct secpolicy *sp = NULL;
1150Sstevel@tonic-gate	int ipsecrt = 0;
1160Sstevel@tonic-gate#endif
1170Sstevel@tonic-gate	char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate	GIANT_REQUIRED; /* XXX bz: ip6_forward_rt */
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate#ifdef IPSEC
1220Sstevel@tonic-gate	/*
1230Sstevel@tonic-gate	 * Check AH/ESP integrity.
1240Sstevel@tonic-gate	 */
1250Sstevel@tonic-gate	/*
1260Sstevel@tonic-gate	 * Don't increment ip6s_cantforward because this is the check
1270Sstevel@tonic-gate	 * before forwarding packet actually.
1280Sstevel@tonic-gate	 */
1290Sstevel@tonic-gate	if (ipsec6_in_reject(m, NULL)) {
1300Sstevel@tonic-gate#if !defined(FAST_IPSEC)
1310Sstevel@tonic-gate		ipsec6stat.in_polvio++;
1320Sstevel@tonic-gate#endif
1330Sstevel@tonic-gate		m_freem(m);
1340Sstevel@tonic-gate		return;
1350Sstevel@tonic-gate	}
1360Sstevel@tonic-gate#endif /* IPSEC */
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate	/*
1390Sstevel@tonic-gate	 * Do not forward packets to multicast destination (should be handled
1400Sstevel@tonic-gate	 * by ip6_mforward().
1410Sstevel@tonic-gate	 * Do not forward packets with unspecified source.  It was discussed
1420Sstevel@tonic-gate	 * in July 2000, on the ipngwg mailing list.
1430Sstevel@tonic-gate	 */
1440Sstevel@tonic-gate	if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
1450Sstevel@tonic-gate	    IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
1460Sstevel@tonic-gate	    IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1470Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
1480Sstevel@tonic-gate		/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
1490Sstevel@tonic-gate		if (ip6_log_time + ip6_log_interval < time_second) {
1500Sstevel@tonic-gate			ip6_log_time = time_second;
1510Sstevel@tonic-gate			log(LOG_DEBUG,
1520Sstevel@tonic-gate			    "cannot forward "
1530Sstevel@tonic-gate			    "from %s to %s nxt %d received on %s\n",
1540Sstevel@tonic-gate			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
1550Sstevel@tonic-gate			    ip6_sprintf(ip6bufd, &ip6->ip6_dst),
1560Sstevel@tonic-gate			    ip6->ip6_nxt,
1570Sstevel@tonic-gate			    if_name(m->m_pkthdr.rcvif));
1580Sstevel@tonic-gate		}
1590Sstevel@tonic-gate		m_freem(m);
1600Sstevel@tonic-gate		return;
1610Sstevel@tonic-gate	}
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate#ifdef IPSTEALTH
1640Sstevel@tonic-gate	if (!ip6stealth) {
1650Sstevel@tonic-gate#endif
1660Sstevel@tonic-gate	if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
1670Sstevel@tonic-gate		/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
1680Sstevel@tonic-gate		icmp6_error(m, ICMP6_TIME_EXCEEDED,
1690Sstevel@tonic-gate				ICMP6_TIME_EXCEED_TRANSIT, 0);
1700Sstevel@tonic-gate		return;
1710Sstevel@tonic-gate	}
1720Sstevel@tonic-gate	ip6->ip6_hlim -= IPV6_HLIMDEC;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate#ifdef IPSTEALTH
1750Sstevel@tonic-gate	}
1760Sstevel@tonic-gate#endif
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate	/*
1790Sstevel@tonic-gate	 * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
1800Sstevel@tonic-gate	 * size of IPv6 + ICMPv6 headers) bytes of the packet in case
1810Sstevel@tonic-gate	 * we need to generate an ICMP6 message to the src.
1820Sstevel@tonic-gate	 * Thanks to M_EXT, in most cases copy will not occur.
1830Sstevel@tonic-gate	 *
1840Sstevel@tonic-gate	 * It is important to save it before IPsec processing as IPsec
1850Sstevel@tonic-gate	 * processing may modify the mbuf.
1860Sstevel@tonic-gate	 */
1870Sstevel@tonic-gate	mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate#ifdef IPSEC
1900Sstevel@tonic-gate	/* get a security policy for this packet */
1910Sstevel@tonic-gate	sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
1920Sstevel@tonic-gate	    IP_FORWARDING, &error);
1930Sstevel@tonic-gate	if (sp == NULL) {
1940Sstevel@tonic-gate		ipsec6stat.out_inval++;
1950Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
1960Sstevel@tonic-gate		if (mcopy) {
1970Sstevel@tonic-gate#if 0
1980Sstevel@tonic-gate			/* XXX: what icmp ? */
1990Sstevel@tonic-gate#else
2000Sstevel@tonic-gate			m_freem(mcopy);
2010Sstevel@tonic-gate#endif
2020Sstevel@tonic-gate		}
2030Sstevel@tonic-gate		m_freem(m);
2040Sstevel@tonic-gate		return;
2050Sstevel@tonic-gate	}
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate	error = 0;
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate	/* check policy */
2100Sstevel@tonic-gate	switch (sp->policy) {
2110Sstevel@tonic-gate	case IPSEC_POLICY_DISCARD:
2120Sstevel@tonic-gate		/*
2130Sstevel@tonic-gate		 * This packet is just discarded.
2140Sstevel@tonic-gate		 */
2150Sstevel@tonic-gate		ipsec6stat.out_polvio++;
2160Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
2170Sstevel@tonic-gate		key_freesp(sp);
2180Sstevel@tonic-gate		if (mcopy) {
2190Sstevel@tonic-gate#if 0
2200Sstevel@tonic-gate			/* XXX: what icmp ? */
2210Sstevel@tonic-gate#else
2220Sstevel@tonic-gate			m_freem(mcopy);
2230Sstevel@tonic-gate#endif
2240Sstevel@tonic-gate		}
2250Sstevel@tonic-gate		m_freem(m);
2260Sstevel@tonic-gate		return;
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate	case IPSEC_POLICY_BYPASS:
2290Sstevel@tonic-gate	case IPSEC_POLICY_NONE:
2300Sstevel@tonic-gate		/* no need to do IPsec. */
2310Sstevel@tonic-gate		key_freesp(sp);
2320Sstevel@tonic-gate		goto skip_ipsec;
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate	case IPSEC_POLICY_IPSEC:
2350Sstevel@tonic-gate		if (sp->req == NULL) {
2360Sstevel@tonic-gate			/* XXX should be panic ? */
2370Sstevel@tonic-gate			printf("ip6_forward: No IPsec request specified.\n");
2380Sstevel@tonic-gate			ip6stat.ip6s_cantforward++;
2390Sstevel@tonic-gate			key_freesp(sp);
2400Sstevel@tonic-gate			if (mcopy) {
2410Sstevel@tonic-gate#if 0
2420Sstevel@tonic-gate				/* XXX: what icmp ? */
2430Sstevel@tonic-gate#else
2440Sstevel@tonic-gate				m_freem(mcopy);
2450Sstevel@tonic-gate#endif
2460Sstevel@tonic-gate			}
2470Sstevel@tonic-gate			m_freem(m);
2480Sstevel@tonic-gate			return;
2490Sstevel@tonic-gate		}
2500Sstevel@tonic-gate		/* do IPsec */
2510Sstevel@tonic-gate		break;
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate	case IPSEC_POLICY_ENTRUST:
2540Sstevel@tonic-gate	default:
2550Sstevel@tonic-gate		/* should be panic ?? */
2560Sstevel@tonic-gate		printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
2570Sstevel@tonic-gate		key_freesp(sp);
2580Sstevel@tonic-gate		goto skip_ipsec;
2590Sstevel@tonic-gate	}
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate    {
2620Sstevel@tonic-gate	struct ipsecrequest *isr = NULL;
2630Sstevel@tonic-gate	struct ipsec_output_state state;
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate	/*
2660Sstevel@tonic-gate	 * when the kernel forwards a packet, it is not proper to apply
2670Sstevel@tonic-gate	 * IPsec transport mode to the packet is not proper.  this check
2680Sstevel@tonic-gate	 * avoid from this.
2690Sstevel@tonic-gate	 * at present, if there is even a transport mode SA request in the
2700Sstevel@tonic-gate	 * security policy, the kernel does not apply IPsec to the packet.
2710Sstevel@tonic-gate	 * this check is not enough because the following case is valid.
2720Sstevel@tonic-gate	 *      ipsec esp/tunnel/xxx-xxx/require esp/transport//require;
2730Sstevel@tonic-gate	 */
2740Sstevel@tonic-gate	for (isr = sp->req; isr; isr = isr->next) {
2750Sstevel@tonic-gate		if (isr->saidx.mode == IPSEC_MODE_ANY)
2760Sstevel@tonic-gate			goto doipsectunnel;
2770Sstevel@tonic-gate		if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
2780Sstevel@tonic-gate			goto doipsectunnel;
2790Sstevel@tonic-gate	}
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate	/*
2820Sstevel@tonic-gate	 * if there's no need for tunnel mode IPsec, skip.
2830Sstevel@tonic-gate	 */
2840Sstevel@tonic-gate	if (!isr)
2850Sstevel@tonic-gate		goto skip_ipsec;
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate    doipsectunnel:
2880Sstevel@tonic-gate	/*
2890Sstevel@tonic-gate	 * All the extension headers will become inaccessible
2900Sstevel@tonic-gate	 * (since they can be encrypted).
2910Sstevel@tonic-gate	 * Don't panic, we need no more updates to extension headers
2920Sstevel@tonic-gate	 * on inner IPv6 packet (since they are now encapsulated).
2930Sstevel@tonic-gate	 *
2940Sstevel@tonic-gate	 * IPv6 [ESP|AH] IPv6 [extension headers] payload
2950Sstevel@tonic-gate	 */
2960Sstevel@tonic-gate	bzero(&state, sizeof(state));
2970Sstevel@tonic-gate	state.m = m;
2980Sstevel@tonic-gate	state.ro = NULL;	/* update at ipsec6_output_tunnel() */
2990Sstevel@tonic-gate	state.dst = NULL;	/* update at ipsec6_output_tunnel() */
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate	error = ipsec6_output_tunnel(&state, sp, 0);
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate	m = state.m;
3040Sstevel@tonic-gate	key_freesp(sp);
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate	if (error) {
3070Sstevel@tonic-gate		/* mbuf is already reclaimed in ipsec6_output_tunnel. */
3080Sstevel@tonic-gate		switch (error) {
3090Sstevel@tonic-gate		case EHOSTUNREACH:
3100Sstevel@tonic-gate		case ENETUNREACH:
3110Sstevel@tonic-gate		case EMSGSIZE:
3120Sstevel@tonic-gate		case ENOBUFS:
3130Sstevel@tonic-gate		case ENOMEM:
3140Sstevel@tonic-gate			break;
3150Sstevel@tonic-gate		default:
3160Sstevel@tonic-gate			printf("ip6_output (ipsec): error code %d\n", error);
3170Sstevel@tonic-gate			/* FALLTHROUGH */
3180Sstevel@tonic-gate		case ENOENT:
3190Sstevel@tonic-gate			/* don't show these error codes to the user */
3200Sstevel@tonic-gate			break;
3210Sstevel@tonic-gate		}
3220Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
3230Sstevel@tonic-gate		if (mcopy) {
3240Sstevel@tonic-gate#if 0
3250Sstevel@tonic-gate			/* XXX: what icmp ? */
3260Sstevel@tonic-gate#else
3270Sstevel@tonic-gate			m_freem(mcopy);
3280Sstevel@tonic-gate#endif
3290Sstevel@tonic-gate		}
3300Sstevel@tonic-gate		m_freem(m);
3310Sstevel@tonic-gate		return;
3320Sstevel@tonic-gate	}
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate	if (ip6 != mtod(m, struct ip6_hdr *)) {
3350Sstevel@tonic-gate		/*
3360Sstevel@tonic-gate		 * now tunnel mode headers are added.  we are originating
3370Sstevel@tonic-gate		 * packet instead of forwarding the packet.
3380Sstevel@tonic-gate		 */
3390Sstevel@tonic-gate		ip6_output(m, NULL, NULL, IPV6_FORWARDING/*XXX*/, NULL, NULL,
3400Sstevel@tonic-gate		    NULL);
3410Sstevel@tonic-gate		goto freecopy;
3420Sstevel@tonic-gate	}
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate	/* adjust pointer */
3450Sstevel@tonic-gate	dst = (struct sockaddr_in6 *)state.dst;
3460Sstevel@tonic-gate	rt = state.ro ? state.ro->ro_rt : NULL;
3470Sstevel@tonic-gate	if (dst != NULL && rt != NULL)
3480Sstevel@tonic-gate		ipsecrt = 1;
3490Sstevel@tonic-gate    }
3500Sstevel@tonic-gate    skip_ipsec:
3510Sstevel@tonic-gate#endif /* IPSEC */
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate#ifdef IPSEC
3540Sstevel@tonic-gate	if (ipsecrt)
3550Sstevel@tonic-gate		goto skip_routing;
3560Sstevel@tonic-gate#endif
3570Sstevel@tonic-gate
3580Sstevel@tonic-gate	dst = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;
3590Sstevel@tonic-gate	if (!srcrt) {
3600Sstevel@tonic-gate		/* ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst */
3610Sstevel@tonic-gate		if (ip6_forward_rt.ro_rt == 0 ||
3620Sstevel@tonic-gate		    (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
3630Sstevel@tonic-gate			if (ip6_forward_rt.ro_rt) {
3640Sstevel@tonic-gate				RTFREE(ip6_forward_rt.ro_rt);
3650Sstevel@tonic-gate				ip6_forward_rt.ro_rt = 0;
3660Sstevel@tonic-gate			}
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate			/* this probably fails but give it a try again */
3690Sstevel@tonic-gate			rtalloc((struct route *)&ip6_forward_rt);
3700Sstevel@tonic-gate		}
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate		if (ip6_forward_rt.ro_rt == 0) {
3730Sstevel@tonic-gate			ip6stat.ip6s_noroute++;
3740Sstevel@tonic-gate			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
3750Sstevel@tonic-gate			if (mcopy) {
3760Sstevel@tonic-gate				icmp6_error(mcopy, ICMP6_DST_UNREACH,
3770Sstevel@tonic-gate					    ICMP6_DST_UNREACH_NOROUTE, 0);
3780Sstevel@tonic-gate			}
3790Sstevel@tonic-gate			m_freem(m);
3800Sstevel@tonic-gate			return;
3810Sstevel@tonic-gate		}
3820Sstevel@tonic-gate	} else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
3830Sstevel@tonic-gate		   !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
3840Sstevel@tonic-gate		if (ip6_forward_rt.ro_rt) {
3850Sstevel@tonic-gate			RTFREE(ip6_forward_rt.ro_rt);
3860Sstevel@tonic-gate			ip6_forward_rt.ro_rt = 0;
3870Sstevel@tonic-gate		}
3880Sstevel@tonic-gate		bzero(dst, sizeof(*dst));
3890Sstevel@tonic-gate		dst->sin6_len = sizeof(struct sockaddr_in6);
3900Sstevel@tonic-gate		dst->sin6_family = AF_INET6;
3910Sstevel@tonic-gate		dst->sin6_addr = ip6->ip6_dst;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate  		rtalloc((struct route *)&ip6_forward_rt);
3940Sstevel@tonic-gate		if (ip6_forward_rt.ro_rt == 0) {
3950Sstevel@tonic-gate			ip6stat.ip6s_noroute++;
3960Sstevel@tonic-gate			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
3970Sstevel@tonic-gate			if (mcopy) {
3980Sstevel@tonic-gate				icmp6_error(mcopy, ICMP6_DST_UNREACH,
3990Sstevel@tonic-gate					    ICMP6_DST_UNREACH_NOROUTE, 0);
4000Sstevel@tonic-gate			}
4010Sstevel@tonic-gate			m_freem(m);
4020Sstevel@tonic-gate			return;
4030Sstevel@tonic-gate		}
4040Sstevel@tonic-gate	}
4050Sstevel@tonic-gate	rt = ip6_forward_rt.ro_rt;
4060Sstevel@tonic-gate#ifdef IPSEC
4070Sstevel@tonic-gate    skip_routing:;
4080Sstevel@tonic-gate#endif
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate	/*
4110Sstevel@tonic-gate	 * Source scope check: if a packet can't be delivered to its
4120Sstevel@tonic-gate	 * destination for the reason that the destination is beyond the scope
4130Sstevel@tonic-gate	 * of the source address, discard the packet and return an icmp6
4140Sstevel@tonic-gate	 * destination unreachable error with Code 2 (beyond scope of source
4150Sstevel@tonic-gate	 * address).  We use a local copy of ip6_src, since in6_setscope()
4160Sstevel@tonic-gate	 * will possibly modify its first argument.
4170Sstevel@tonic-gate	 * [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1]
4180Sstevel@tonic-gate	 */
4190Sstevel@tonic-gate	src_in6 = ip6->ip6_src;
4200Sstevel@tonic-gate	if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
4210Sstevel@tonic-gate		/* XXX: this should not happen */
4220Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
4230Sstevel@tonic-gate		ip6stat.ip6s_badscope++;
4240Sstevel@tonic-gate		m_freem(m);
4250Sstevel@tonic-gate		return;
4260Sstevel@tonic-gate	}
4270Sstevel@tonic-gate	if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
4280Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
4290Sstevel@tonic-gate		ip6stat.ip6s_badscope++;
4300Sstevel@tonic-gate		m_freem(m);
4310Sstevel@tonic-gate		return;
4320Sstevel@tonic-gate	}
4330Sstevel@tonic-gate	if (inzone != outzone
4340Sstevel@tonic-gate#ifdef IPSEC
4350Sstevel@tonic-gate	    && !ipsecrt
4360Sstevel@tonic-gate#endif
4370Sstevel@tonic-gate	    ) {
4380Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
4390Sstevel@tonic-gate		ip6stat.ip6s_badscope++;
4400Sstevel@tonic-gate		in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate		if (ip6_log_time + ip6_log_interval < time_second) {
4430Sstevel@tonic-gate			ip6_log_time = time_second;
4440Sstevel@tonic-gate			log(LOG_DEBUG,
4450Sstevel@tonic-gate			    "cannot forward "
4460Sstevel@tonic-gate			    "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
4470Sstevel@tonic-gate			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
4480Sstevel@tonic-gate			    ip6_sprintf(ip6bufd, &ip6->ip6_dst),
4490Sstevel@tonic-gate			    ip6->ip6_nxt,
4500Sstevel@tonic-gate			    if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
4510Sstevel@tonic-gate		}
4520Sstevel@tonic-gate		if (mcopy)
4530Sstevel@tonic-gate			icmp6_error(mcopy, ICMP6_DST_UNREACH,
4540Sstevel@tonic-gate				    ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
4550Sstevel@tonic-gate		m_freem(m);
4560Sstevel@tonic-gate		return;
4570Sstevel@tonic-gate	}
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate	/*
4600Sstevel@tonic-gate	 * Destination scope check: if a packet is going to break the scope
4610Sstevel@tonic-gate	 * zone of packet's destination address, discard it.  This case should
4620Sstevel@tonic-gate	 * usually be prevented by appropriately-configured routing table, but
4630Sstevel@tonic-gate	 * we need an explicit check because we may mistakenly forward the
4640Sstevel@tonic-gate	 * packet to a different zone by (e.g.) a default route.
4650Sstevel@tonic-gate	 */
4660Sstevel@tonic-gate	dst_in6 = ip6->ip6_dst;
4670Sstevel@tonic-gate	if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
4680Sstevel@tonic-gate	    in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
4690Sstevel@tonic-gate	    inzone != outzone) {
4700Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
4710Sstevel@tonic-gate		ip6stat.ip6s_badscope++;
4720Sstevel@tonic-gate		m_freem(m);
4730Sstevel@tonic-gate		return;
4740Sstevel@tonic-gate	}
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate	if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
4770Sstevel@tonic-gate		in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
4780Sstevel@tonic-gate		if (mcopy) {
4790Sstevel@tonic-gate			u_long mtu;
4800Sstevel@tonic-gate#ifdef IPSEC
4810Sstevel@tonic-gate			struct secpolicy *sp;
4820Sstevel@tonic-gate			int ipsecerror;
4830Sstevel@tonic-gate			size_t ipsechdrsiz;
4840Sstevel@tonic-gate#endif
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate			mtu = IN6_LINKMTU(rt->rt_ifp);
4870Sstevel@tonic-gate#ifdef IPSEC
4880Sstevel@tonic-gate			/*
4890Sstevel@tonic-gate			 * When we do IPsec tunnel ingress, we need to play
4900Sstevel@tonic-gate			 * with the link value (decrement IPsec header size
4910Sstevel@tonic-gate			 * from mtu value).  The code is much simpler than v4
4920Sstevel@tonic-gate			 * case, as we have the outgoing interface for
4930Sstevel@tonic-gate			 * encapsulated packet as "rt->rt_ifp".
4940Sstevel@tonic-gate			 */
4950Sstevel@tonic-gate			sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
4960Sstevel@tonic-gate				IP_FORWARDING, &ipsecerror);
4970Sstevel@tonic-gate			if (sp) {
4980Sstevel@tonic-gate				ipsechdrsiz = ipsec6_hdrsiz(mcopy,
4990Sstevel@tonic-gate					IPSEC_DIR_OUTBOUND, NULL);
5000Sstevel@tonic-gate				if (ipsechdrsiz < mtu)
5010Sstevel@tonic-gate					mtu -= ipsechdrsiz;
5020Sstevel@tonic-gate			}
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate			/*
5050Sstevel@tonic-gate			 * if mtu becomes less than minimum MTU,
5060Sstevel@tonic-gate			 * tell minimum MTU (and I'll need to fragment it).
5070Sstevel@tonic-gate			 */
5080Sstevel@tonic-gate			if (mtu < IPV6_MMTU)
5090Sstevel@tonic-gate				mtu = IPV6_MMTU;
5100Sstevel@tonic-gate#endif
5110Sstevel@tonic-gate			icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
5120Sstevel@tonic-gate		}
5130Sstevel@tonic-gate		m_freem(m);
5140Sstevel@tonic-gate		return;
5150Sstevel@tonic-gate	}
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate	if (rt->rt_flags & RTF_GATEWAY)
5180Sstevel@tonic-gate		dst = (struct sockaddr_in6 *)rt->rt_gateway;
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate	/*
5210Sstevel@tonic-gate	 * If we are to forward the packet using the same interface
5220Sstevel@tonic-gate	 * as one we got the packet from, perhaps we should send a redirect
5230Sstevel@tonic-gate	 * to sender to shortcut a hop.
5240Sstevel@tonic-gate	 * Only send redirect if source is sending directly to us,
5250Sstevel@tonic-gate	 * and if packet was not source routed (or has any options).
5260Sstevel@tonic-gate	 * Also, don't send redirect if forwarding using a route
5270Sstevel@tonic-gate	 * modified by a redirect.
5280Sstevel@tonic-gate	 */
5290Sstevel@tonic-gate	if (ip6_sendredirects && rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
5300Sstevel@tonic-gate#ifdef IPSEC
5310Sstevel@tonic-gate	    !ipsecrt &&
5320Sstevel@tonic-gate#endif
5330Sstevel@tonic-gate	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
5340Sstevel@tonic-gate		if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) {
5350Sstevel@tonic-gate			/*
5360Sstevel@tonic-gate			 * If the incoming interface is equal to the outgoing
5370Sstevel@tonic-gate			 * one, and the link attached to the interface is
5380Sstevel@tonic-gate			 * point-to-point, then it will be highly probable
5390Sstevel@tonic-gate			 * that a routing loop occurs. Thus, we immediately
5400Sstevel@tonic-gate			 * drop the packet and send an ICMPv6 error message.
5410Sstevel@tonic-gate			 *
5420Sstevel@tonic-gate			 * type/code is based on suggestion by Rich Draves.
5430Sstevel@tonic-gate			 * not sure if it is the best pick.
5440Sstevel@tonic-gate			 */
5450Sstevel@tonic-gate			icmp6_error(mcopy, ICMP6_DST_UNREACH,
5460Sstevel@tonic-gate				    ICMP6_DST_UNREACH_ADDR, 0);
5470Sstevel@tonic-gate			m_freem(m);
5480Sstevel@tonic-gate			return;
5490Sstevel@tonic-gate		}
5500Sstevel@tonic-gate		type = ND_REDIRECT;
5510Sstevel@tonic-gate	}
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate	/*
5540Sstevel@tonic-gate	 * Fake scoped addresses. Note that even link-local source or
5550Sstevel@tonic-gate	 * destinaion can appear, if the originating node just sends the
5560Sstevel@tonic-gate	 * packet to us (without address resolution for the destination).
5570Sstevel@tonic-gate	 * Since both icmp6_error and icmp6_redirect_output fill the embedded
5580Sstevel@tonic-gate	 * link identifiers, we can do this stuff after making a copy for
5590Sstevel@tonic-gate	 * returning an error.
5600Sstevel@tonic-gate	 */
5610Sstevel@tonic-gate	if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
5620Sstevel@tonic-gate		/*
5630Sstevel@tonic-gate		 * See corresponding comments in ip6_output.
5640Sstevel@tonic-gate		 * XXX: but is it possible that ip6_forward() sends a packet
5650Sstevel@tonic-gate		 *      to a loopback interface? I don't think so, and thus
5660Sstevel@tonic-gate		 *      I bark here. (jinmei@kame.net)
5670Sstevel@tonic-gate		 * XXX: it is common to route invalid packets to loopback.
5680Sstevel@tonic-gate		 *	also, the codepath will be visited on use of ::1 in
5690Sstevel@tonic-gate		 *	rthdr. (itojun)
5700Sstevel@tonic-gate		 */
5710Sstevel@tonic-gate#if 1
5720Sstevel@tonic-gate		if (0)
5730Sstevel@tonic-gate#else
5740Sstevel@tonic-gate		if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
5750Sstevel@tonic-gate#endif
5760Sstevel@tonic-gate		{
5770Sstevel@tonic-gate			printf("ip6_forward: outgoing interface is loopback. "
5780Sstevel@tonic-gate			       "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
5790Sstevel@tonic-gate			       ip6_sprintf(ip6bufs, &ip6->ip6_src),
5800Sstevel@tonic-gate			       ip6_sprintf(ip6bufd, &ip6->ip6_dst),
5810Sstevel@tonic-gate			       ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
5820Sstevel@tonic-gate			       if_name(rt->rt_ifp));
5830Sstevel@tonic-gate		}
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate		/* we can just use rcvif in forwarding. */
5860Sstevel@tonic-gate		origifp = m->m_pkthdr.rcvif;
5870Sstevel@tonic-gate	}
5880Sstevel@tonic-gate	else
5890Sstevel@tonic-gate		origifp = rt->rt_ifp;
5900Sstevel@tonic-gate	/*
5910Sstevel@tonic-gate	 * clear embedded scope identifiers if necessary.
5920Sstevel@tonic-gate	 * in6_clearscope will touch the addresses only when necessary.
5930Sstevel@tonic-gate	 */
5940Sstevel@tonic-gate	in6_clearscope(&ip6->ip6_src);
5950Sstevel@tonic-gate	in6_clearscope(&ip6->ip6_dst);
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate	/* Jump over all PFIL processing if hooks are not active. */
5980Sstevel@tonic-gate	if (!PFIL_HOOKED(&inet6_pfil_hook))
5990Sstevel@tonic-gate		goto pass;
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate	/* Run through list of hooks for output packets. */
6020Sstevel@tonic-gate	error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL);
6030Sstevel@tonic-gate	if (error != 0)
6040Sstevel@tonic-gate		goto senderr;
6050Sstevel@tonic-gate	if (m == NULL)
6060Sstevel@tonic-gate		goto freecopy;
6070Sstevel@tonic-gate	ip6 = mtod(m, struct ip6_hdr *);
6080Sstevel@tonic-gate
6090Sstevel@tonic-gatepass:
6100Sstevel@tonic-gate	error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
6110Sstevel@tonic-gate	if (error) {
6120Sstevel@tonic-gate		in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
6130Sstevel@tonic-gate		ip6stat.ip6s_cantforward++;
6140Sstevel@tonic-gate	} else {
6150Sstevel@tonic-gate		ip6stat.ip6s_forward++;
6160Sstevel@tonic-gate		in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
6170Sstevel@tonic-gate		if (type)
6180Sstevel@tonic-gate			ip6stat.ip6s_redirectsent++;
6190Sstevel@tonic-gate		else {
6200Sstevel@tonic-gate			if (mcopy)
6210Sstevel@tonic-gate				goto freecopy;
6220Sstevel@tonic-gate		}
6230Sstevel@tonic-gate	}
6240Sstevel@tonic-gate
6250Sstevel@tonic-gatesenderr:
6260Sstevel@tonic-gate	if (mcopy == NULL)
6270Sstevel@tonic-gate		return;
6280Sstevel@tonic-gate	switch (error) {
6290Sstevel@tonic-gate	case 0:
6300Sstevel@tonic-gate		if (type == ND_REDIRECT) {
6310Sstevel@tonic-gate			icmp6_redirect_output(mcopy, rt);
6320Sstevel@tonic-gate			return;
6330Sstevel@tonic-gate		}
6340Sstevel@tonic-gate		goto freecopy;
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate	case EMSGSIZE:
6370Sstevel@tonic-gate		/* xxx MTU is constant in PPP? */
6380Sstevel@tonic-gate		goto freecopy;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate	case ENOBUFS:
6410Sstevel@tonic-gate		/* Tell source to slow down like source quench in IP? */
6420Sstevel@tonic-gate		goto freecopy;
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate	case ENETUNREACH:	/* shouldn't happen, checked above */
6450Sstevel@tonic-gate	case EHOSTUNREACH:
6460Sstevel@tonic-gate	case ENETDOWN:
6470Sstevel@tonic-gate	case EHOSTDOWN:
6480Sstevel@tonic-gate	default:
6490Sstevel@tonic-gate		type = ICMP6_DST_UNREACH;
6500Sstevel@tonic-gate		code = ICMP6_DST_UNREACH_ADDR;
6510Sstevel@tonic-gate		break;
6520Sstevel@tonic-gate	}
6530Sstevel@tonic-gate	icmp6_error(mcopy, type, code, 0);
6540Sstevel@tonic-gate	return;
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate freecopy:
6570Sstevel@tonic-gate	m_freem(mcopy);
6580Sstevel@tonic-gate	return;
6590Sstevel@tonic-gate}
6600Sstevel@tonic-gate