/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14* 3. Neither the name of the project nor the names of its contributors15* may be used to endorse or promote products derived from this software16* without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND19* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE20* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE22* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL23* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS24* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)25* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT26* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY27* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF28* SUCH DAMAGE.29*30* $KAME: ip6_forward.c,v 1.69 2001/05/17 03:48:30 itojun Exp $31*/3233#include "opt_inet.h"34#include "opt_inet6.h"35#include "opt_ipsec.h"36#include "opt_ipstealth.h"37#include "opt_sctp.h"3839#include <sys/param.h>40#include <sys/systm.h>41#include <sys/malloc.h>42#include <sys/mbuf.h>43#include <sys/domain.h>44#include <sys/protosw.h>45#include <sys/socket.h>46#include <sys/errno.h>47#include <sys/time.h>48#include <sys/kernel.h>49#include <sys/syslog.h>5051#include <net/if.h>52#include <net/if_var.h>53#include <net/if_private.h>54#include <net/netisr.h>55#include <net/route.h>56#include <net/route/nhop.h>57#include <net/pfil.h>5859#include <netinet/in.h>60#include <netinet/in_var.h>61#include <netinet/in_systm.h>62#include <netinet/ip.h>63#include <netinet/ip_var.h>64#include <netinet6/in6_var.h>65#include <netinet/ip6.h>66#include <netinet6/in6_fib.h>67#include <netinet6/ip6_var.h>68#include <netinet6/scope6_var.h>69#include <netinet/icmp6.h>70#include <netinet6/nd6.h>7172#include <netinet/in_pcb.h>7374#include <netipsec/ipsec_support.h>7576#if defined(SCTP) || defined(SCTP_SUPPORT)77#include <netinet/sctp_crc32.h>78#endif7980/*81* Forward a packet. If some error occurs return the sender82* an icmp packet. Note we can't always generate a meaningful83* icmp message because icmp doesn't have a large enough repertoire84* of codes and types.85*86* If not forwarding, just drop the packet. This could be confusing87* if ipforwarding was zero but some routing protocol was advancing88* us as a gateway to somewhere. However, we must let the routing89* protocol deal with that.90*91*/92void93ip6_forward(struct mbuf *m, int srcrt)94{95struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);96struct sockaddr_in6 dst;97struct nhop_object *nh = NULL;98int error, type = 0, code = 0;99struct mbuf *mcopy = NULL;100struct ifnet *origifp; /* maybe unnecessary */101u_int32_t inzone, outzone;102struct in6_addr odst;103struct m_tag *fwd_tag;104char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];105106/*107* Do not forward packets to multicast destination (should be handled108* by ip6_mforward().109* Do not forward packets with unspecified source. It was discussed110* in July 2000, on the ipngwg mailing list.111*/112if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||113IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||114IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) ||115IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) {116IP6STAT_INC(ip6s_cantforward);117/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */118if (V_ip6_log_cannot_forward && ip6_log_ratelimit()) {119log(LOG_DEBUG,120"cannot forward "121"from %s to %s nxt %d received on %s\n",122ip6_sprintf(ip6bufs, &ip6->ip6_src),123ip6_sprintf(ip6bufd, &ip6->ip6_dst),124ip6->ip6_nxt,125if_name(m->m_pkthdr.rcvif));126}127m_freem(m);128return;129}130131if (132#ifdef IPSTEALTH133V_ip6stealth == 0 &&134#endif135ip6->ip6_hlim <= IPV6_HLIMDEC) {136/* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */137icmp6_error(m, ICMP6_TIME_EXCEEDED,138ICMP6_TIME_EXCEED_TRANSIT, 0);139return;140}141142/*143* Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -144* size of IPv6 + ICMPv6 headers) bytes of the packet in case145* we need to generate an ICMP6 message to the src.146* Thanks to M_EXT, in most cases copy will not occur.147*148* It is important to save it before IPsec processing as IPsec149* processing may modify the mbuf.150*/151mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),152M_NOWAIT);153#ifdef IPSTEALTH154if (V_ip6stealth == 0)155#endif156ip6->ip6_hlim -= IPV6_HLIMDEC;157158#if defined(IPSEC) || defined(IPSEC_SUPPORT)159if (IPSEC_ENABLED(ipv6)) {160if ((error = IPSEC_FORWARD(ipv6, m)) != 0) {161/* mbuf consumed by IPsec */162m_freem(mcopy);163if (error != EINPROGRESS)164IP6STAT_INC(ip6s_cantforward);165return;166}167/* No IPsec processing required */168}169#endif170/*171* ip6_forward() operates with IPv6 addresses with deembedded scope.172*173* There are 3 sources of IPv6 destination address:174*175* 1) ip6_input(), where ip6_dst contains deembedded address.176* In order to deal with forwarding of link-local packets,177* calculate the scope based on input interface (RFC 4007, clause 9).178* 2) packet filters changing ip6_dst directly. It would embed scope179* for LL addresses, so in6_localip() performs properly.180* 3) packet filters attaching PACKET_TAG_IPFORWARD would embed181* scope for the nexthop.182*/183bzero(&dst, sizeof(struct sockaddr_in6));184dst.sin6_family = AF_INET6;185dst.sin6_addr = ip6->ip6_dst;186dst.sin6_scope_id = in6_get_unicast_scopeid(&ip6->ip6_dst, m->m_pkthdr.rcvif);187again:188nh = fib6_lookup(M_GETFIB(m), &dst.sin6_addr, dst.sin6_scope_id,189NHR_REF, m->m_pkthdr.flowid);190if (nh == NULL) {191IP6STAT_INC(ip6s_noroute);192in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);193if (mcopy) {194icmp6_error(mcopy, ICMP6_DST_UNREACH,195ICMP6_DST_UNREACH_NOROUTE, 0);196}197goto bad;198}199200if (nh->nh_flags & (NHF_BLACKHOLE | NHF_REJECT)) {201IP6STAT_INC(ip6s_cantforward);202if (mcopy != NULL) {203if (nh->nh_flags & NHF_REJECT) {204icmp6_error(mcopy, ICMP6_DST_UNREACH,205ICMP6_DST_UNREACH_REJECT, 0);206} else207m_freem(mcopy);208}209goto bad;210}211212/*213* Source scope check: if a packet can't be delivered to its214* destination for the reason that the destination is beyond the scope215* of the source address, discard the packet and return an icmp6216* destination unreachable error with Code 2 (beyond scope of source217* address).218* [draft-ietf-ipngwg-icmp-v3-04.txt, Section 3.1]219*/220outzone = in6_get_unicast_scopeid(&ip6->ip6_src, nh->nh_ifp);221inzone = in6_get_unicast_scopeid(&ip6->ip6_src, m->m_pkthdr.rcvif);222if (inzone != outzone) {223IP6STAT_INC(ip6s_cantforward);224IP6STAT_INC(ip6s_badscope);225in6_ifstat_inc(nh->nh_ifp, ifs6_in_discard);226227if (V_ip6_log_cannot_forward && ip6_log_ratelimit()) {228log(LOG_DEBUG,229"cannot forward "230"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",231ip6_sprintf(ip6bufs, &ip6->ip6_src),232ip6_sprintf(ip6bufd, &ip6->ip6_dst),233ip6->ip6_nxt,234if_name(m->m_pkthdr.rcvif), if_name(nh->nh_ifp));235}236if (mcopy)237icmp6_error(mcopy, ICMP6_DST_UNREACH,238ICMP6_DST_UNREACH_BEYONDSCOPE, 0);239goto bad;240}241242/*243* Destination scope check: if a packet is going to break the scope244* zone of packet's destination address, discard it. This case should245* usually be prevented by appropriately-configured routing table, but246* we need an explicit check because we may mistakenly forward the247* packet to a different zone by (e.g.) a default route.248*/249inzone = in6_get_unicast_scopeid(&ip6->ip6_dst, m->m_pkthdr.rcvif);250outzone = in6_get_unicast_scopeid(&ip6->ip6_dst, nh->nh_ifp);251252if (inzone != outzone) {253IP6STAT_INC(ip6s_cantforward);254IP6STAT_INC(ip6s_badscope);255goto bad;256}257258if (nh->nh_flags & NHF_GATEWAY) {259/* Store gateway address in deembedded form */260dst.sin6_addr = nh->gw6_sa.sin6_addr;261dst.sin6_scope_id = ntohs(in6_getscope(&dst.sin6_addr));262in6_clearscope(&dst.sin6_addr);263}264265/*266* If we are to forward the packet using the same interface267* as one we got the packet from, perhaps we should send a redirect268* to sender to shortcut a hop.269* Only send redirect if source is sending directly to us,270* and if packet was not source routed (or has any options).271* Also, don't send redirect if forwarding using a route272* modified by a redirect.273*/274if (V_ip6_sendredirects && nh->nh_ifp == m->m_pkthdr.rcvif && !srcrt &&275(nh->nh_flags & NHF_REDIRECT) == 0)276type = ND_REDIRECT;277278/*279* Fake scoped addresses. Note that even link-local source or280* destinaion can appear, if the originating node just sends the281* packet to us (without address resolution for the destination).282* Since both icmp6_error and icmp6_redirect_output fill the embedded283* link identifiers, we can do this stuff after making a copy for284* returning an error.285*/286if ((nh->nh_ifp->if_flags & IFF_LOOPBACK) != 0) {287/*288* See corresponding comments in ip6_output.289* XXX: but is it possible that ip6_forward() sends a packet290* to a loopback interface? I don't think so, and thus291* I bark here. ([email protected])292* XXX: it is common to route invalid packets to loopback.293* also, the codepath will be visited on use of ::1 in294* rthdr. (itojun)295*/296#if 1297if (0)298#else299if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)300#endif301{302printf("ip6_forward: outgoing interface is loopback. "303"src %s, dst %s, nxt %d, rcvif %s, outif %s\n",304ip6_sprintf(ip6bufs, &ip6->ip6_src),305ip6_sprintf(ip6bufd, &ip6->ip6_dst),306ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),307if_name(nh->nh_ifp));308}309310/* we can just use rcvif in forwarding. */311origifp = m->m_pkthdr.rcvif;312}313else314origifp = nh->nh_ifp;315/*316* clear embedded scope identifiers if necessary.317* in6_clearscope will touch the addresses only when necessary.318*/319in6_clearscope(&ip6->ip6_src);320in6_clearscope(&ip6->ip6_dst);321322/* Jump over all PFIL processing if hooks are not active. */323if (!PFIL_HOOKED_OUT(V_inet6_pfil_head))324goto pass;325326odst = ip6->ip6_dst;327/* Run through list of hooks for forwarded packets. */328if (pfil_mbuf_fwd(V_inet6_pfil_head, &m, nh->nh_ifp,329NULL) != PFIL_PASS)330goto freecopy;331ip6 = mtod(m, struct ip6_hdr *);332333/* See if destination IP address was changed by packet filter. */334if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) {335m->m_flags |= M_SKIP_FIREWALL;336/* If destination is now ourself drop to ip6_input(). */337if (in6_localip(&ip6->ip6_dst))338m->m_flags |= M_FASTFWD_OURS;339else {340NH_FREE(nh);341342/* Update address and scopeid. Assume scope is embedded */343dst.sin6_scope_id = ntohs(in6_getscope(&ip6->ip6_dst));344dst.sin6_addr = ip6->ip6_dst;345in6_clearscope(&dst.sin6_addr);346goto again; /* Redo the routing table lookup. */347}348}349350/* See if local, if yes, send it to netisr. */351if (m->m_flags & M_FASTFWD_OURS) {352if (m->m_pkthdr.rcvif == NULL)353m->m_pkthdr.rcvif = V_loif;354if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {355m->m_pkthdr.csum_flags |=356CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR;357m->m_pkthdr.csum_data = 0xffff;358}359#if defined(SCTP) || defined(SCTP_SUPPORT)360if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6)361m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID;362#endif363error = netisr_queue(NETISR_IPV6, m);364goto out;365}366/* Or forward to some other address? */367if ((m->m_flags & M_IP6_NEXTHOP) &&368(fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) {369struct sockaddr_in6 *gw6 = (struct sockaddr_in6 *)(fwd_tag + 1);370371/* Update address and scopeid. Assume scope is embedded */372dst.sin6_scope_id = ntohs(in6_getscope(&gw6->sin6_addr));373dst.sin6_addr = gw6->sin6_addr;374in6_clearscope(&dst.sin6_addr);375376m->m_flags |= M_SKIP_FIREWALL;377m->m_flags &= ~M_IP6_NEXTHOP;378m_tag_delete(m, fwd_tag);379NH_FREE(nh);380goto again;381}382383pass:384/* See if the size was changed by the packet filter. */385/* TODO: change to nh->nh_mtu */386if (m->m_pkthdr.len > in6_ifmtu(nh->nh_ifp)) {387in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig);388if (mcopy)389icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,390in6_ifmtu(nh->nh_ifp));391goto bad;392}393394/*395* If TCP/UDP header still needs a valid checksum and interface will not396* calculate it for us, do it here.397*/398if (__predict_false(m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6 &399~nh->nh_ifp->if_hwassist)) {400int offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, NULL);401402if (offset < sizeof(struct ip6_hdr) || offset > m->m_pkthdr.len)403goto bad;404in6_delayed_cksum(m, m->m_pkthdr.len - offset, offset);405m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;406}407#if defined(SCTP) || defined(SCTP_SUPPORT)408if (__predict_false(m->m_pkthdr.csum_flags & CSUM_IP6_SCTP &409~nh->nh_ifp->if_hwassist)) {410int offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, NULL);411412sctp_delayed_cksum(m, offset);413m->m_pkthdr.csum_flags &= ~CSUM_IP6_SCTP;414}415#endif416417/* Currently LLE layer stores embedded IPv6 addresses */418if (IN6_IS_SCOPE_LINKLOCAL(&dst.sin6_addr)) {419in6_set_unicast_scopeid(&dst.sin6_addr, dst.sin6_scope_id);420dst.sin6_scope_id = 0;421}422error = nd6_output_ifp(nh->nh_ifp, origifp, m, &dst, NULL);423if (error) {424in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard);425IP6STAT_INC(ip6s_cantforward);426} else {427IP6STAT_INC(ip6s_forward);428in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward);429if (type)430IP6STAT_INC(ip6s_redirectsent);431else {432if (mcopy)433goto freecopy;434}435}436437if (mcopy == NULL)438goto out;439switch (error) {440case 0:441if (type == ND_REDIRECT) {442icmp6_redirect_output(mcopy, nh);443goto out;444}445goto freecopy;446447case EMSGSIZE:448/* xxx MTU is constant in PPP? */449goto freecopy;450451case ENOBUFS:452/* Tell source to slow down like source quench in IP? */453goto freecopy;454455case ENETUNREACH: /* shouldn't happen, checked above */456case EHOSTUNREACH:457case ENETDOWN:458case EHOSTDOWN:459default:460type = ICMP6_DST_UNREACH;461code = ICMP6_DST_UNREACH_ADDR;462break;463}464icmp6_error(mcopy, type, code, 0);465goto out;466467freecopy:468m_freem(mcopy);469goto out;470bad:471m_freem(m);472out:473if (nh != NULL)474NH_FREE(nh);475}476477478