The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet6/ip6_forward.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: ip6_forward.c,v 1.108 2022/08/09 21:10:02 kn Exp $    */
    2 /*      $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $    */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include "pf.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/mbuf.h>
   38 #include <sys/socket.h>
   39 #include <sys/errno.h>
   40 #include <sys/time.h>
   41 #include <sys/kernel.h>
   42 #include <sys/syslog.h>
   43 
   44 #include <net/if.h>
   45 #include <net/if_var.h>
   46 #include <net/if_enc.h>
   47 #include <net/route.h>
   48 
   49 #include <netinet/in.h>
   50 #include <netinet/ip_var.h>
   51 #include <netinet6/in6_var.h>
   52 #include <netinet/ip6.h>
   53 #include <netinet6/ip6_var.h>
   54 #include <netinet/icmp6.h>
   55 #include <netinet6/nd6.h>
   56 
   57 #if NPF > 0
   58 #include <net/pfvar.h>
   59 #endif
   60 
   61 #ifdef IPSEC
   62 #include <netinet/ip_ipsp.h>
   63 #include <netinet/ip_ah.h>
   64 #include <netinet/ip_esp.h>
   65 #include <netinet/udp.h>
   66 #include <netinet/tcp.h>
   67 #endif
   68 
   69 /*
   70  * Forward a packet.  If some error occurs return the sender
   71  * an icmp packet.  Note we can't always generate a meaningful
   72  * icmp message because icmp doesn't have a large enough repertoire
   73  * of codes and types.
   74  *
   75  * If not forwarding, just drop the packet.  This could be confusing
   76  * if ipforwarding was zero but some routing protocol was advancing
   77  * us as a gateway to somewhere.  However, we must let the routing
   78  * protocol deal with that.
   79  *
   80  */
   81 
   82 void
   83 ip6_forward(struct mbuf *m, struct rtentry *rt, int srcrt)
   84 {
   85         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
   86         struct sockaddr_in6 *sin6;
   87         struct route_in6 ro;
   88         struct ifnet *ifp = NULL;
   89         int error = 0, type = 0, code = 0, destmtu = 0;
   90         struct mbuf *mcopy = NULL;
   91 #ifdef IPSEC
   92         struct tdb *tdb = NULL;
   93 #endif /* IPSEC */
   94         char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN];
   95 
   96         /*
   97          * Do not forward packets to multicast destination (should be handled
   98          * by ip6_mforward().
   99          * Do not forward packets with unspecified source.  It was discussed
  100          * in July 2000, on ipngwg mailing list.
  101          */
  102         if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
  103             IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
  104             IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
  105                 ip6stat_inc(ip6s_cantforward);
  106                 if (ip6_log_time + ip6_log_interval < getuptime()) {
  107                         ip6_log_time = getuptime();
  108                         inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6));
  109                         inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6));
  110                         log(LOG_DEBUG,
  111                             "cannot forward "
  112                             "from %s to %s nxt %d received on interface %u\n",
  113                             src6, dst6,
  114                             ip6->ip6_nxt,
  115                             m->m_pkthdr.ph_ifidx);
  116                 }
  117                 m_freem(m);
  118                 goto out;
  119         }
  120 
  121         if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
  122                 icmp6_error(m, ICMP6_TIME_EXCEEDED,
  123                                 ICMP6_TIME_EXCEED_TRANSIT, 0);
  124                 goto out;
  125         }
  126         ip6->ip6_hlim -= IPV6_HLIMDEC;
  127 
  128         /*
  129          * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
  130          * size of IPv6 + ICMPv6 headers) bytes of the packet in case
  131          * we need to generate an ICMP6 message to the src.
  132          * Thanks to M_EXT, in most cases copy will not occur.
  133          *
  134          * It is important to save it before IPsec processing as IPsec
  135          * processing may modify the mbuf.
  136          */
  137         mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
  138             M_NOWAIT);
  139 
  140 #if NPF > 0
  141 reroute:
  142 #endif
  143 
  144 #ifdef IPSEC
  145         if (ipsec_in_use) {
  146                 error = ip6_output_ipsec_lookup(m, NULL, &tdb);
  147                 if (error) {
  148                         /*
  149                          * -EINVAL is used to indicate that the packet should
  150                          * be silently dropped, typically because we've asked
  151                          * key management for an SA.
  152                          */
  153                         if (error == -EINVAL) /* Should silently drop packet */
  154                                 error = 0;
  155 
  156                         m_freem(m);
  157                         goto freecopy;
  158                 }
  159         }
  160 #endif /* IPSEC */
  161 
  162         memset(&ro, 0, sizeof(ro));
  163         sin6 = &ro.ro_dst;
  164         sin6->sin6_family = AF_INET6;
  165         sin6->sin6_len = sizeof(*sin6);
  166         sin6->sin6_addr = ip6->ip6_dst;
  167 
  168         if (!rtisvalid(rt)) {
  169                 rtfree(rt);
  170                 rt = rtalloc_mpath(sin6tosa(sin6), &ip6->ip6_src.s6_addr32[0],
  171                     m->m_pkthdr.ph_rtableid);
  172                 if (rt == NULL) {
  173                         ip6stat_inc(ip6s_noroute);
  174                         if (mcopy) {
  175                                 icmp6_error(mcopy, ICMP6_DST_UNREACH,
  176                                             ICMP6_DST_UNREACH_NOROUTE, 0);
  177                         }
  178                         m_freem(m);
  179                         goto out;
  180                 }
  181         }
  182 
  183         /*
  184          * Scope check: if a packet can't be delivered to its destination
  185          * for the reason that the destination is beyond the scope of the
  186          * source address, discard the packet and return an icmp6 destination
  187          * unreachable error with Code 2 (beyond scope of source address).
  188          * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
  189          */
  190         if (in6_addr2scopeid(m->m_pkthdr.ph_ifidx, &ip6->ip6_src) !=
  191             in6_addr2scopeid(rt->rt_ifidx, &ip6->ip6_src)) {
  192                 ip6stat_inc(ip6s_cantforward);
  193                 ip6stat_inc(ip6s_badscope);
  194 
  195                 if (ip6_log_time + ip6_log_interval < getuptime()) {
  196                         ip6_log_time = getuptime();
  197                         inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6));
  198                         inet_ntop(AF_INET6, &ip6->ip6_dst, dst6, sizeof(dst6));
  199                         log(LOG_DEBUG,
  200                             "cannot forward "
  201                             "src %s, dst %s, nxt %d, rcvif %u, outif %u\n",
  202                             src6, dst6,
  203                             ip6->ip6_nxt,
  204                             m->m_pkthdr.ph_ifidx, rt->rt_ifidx);
  205                 }
  206                 if (mcopy)
  207                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  208                                     ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
  209                 m_freem(m);
  210                 goto out;
  211         }
  212 
  213 #ifdef IPSEC
  214         /*
  215          * Check if the packet needs encapsulation.
  216          * ipsp_process_packet will never come back to here.
  217          */
  218         if (tdb != NULL) {
  219                 /* Callee frees mbuf */
  220                 ro.ro_rt = rt;
  221                 ro.ro_tableid = m->m_pkthdr.ph_rtableid;
  222                 error = ip6_output_ipsec_send(tdb, m, &ro, 0, 1);
  223                 rt = ro.ro_rt;
  224                 if (error)
  225                         goto senderr;
  226                 goto freecopy;
  227         }
  228 #endif /* IPSEC */
  229 
  230         if (rt->rt_flags & RTF_GATEWAY)
  231                 sin6 = satosin6(rt->rt_gateway);
  232 
  233         /*
  234          * If we are to forward the packet using the same interface
  235          * as one we got the packet from, perhaps we should send a redirect
  236          * to sender to shortcut a hop.
  237          * Only send redirect if source is sending directly to us,
  238          * and if packet was not source routed (or has any options).
  239          * Also, don't send redirect if forwarding using a route
  240          * modified by a redirect.
  241          */
  242         ifp = if_get(rt->rt_ifidx);
  243         if (ifp == NULL) {
  244                 m_freem(m);
  245                 goto freecopy;
  246         }
  247         if (rt->rt_ifidx == m->m_pkthdr.ph_ifidx && !srcrt &&
  248             ip6_sendredirects &&
  249             (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
  250                 if ((ifp->if_flags & IFF_POINTOPOINT) &&
  251                     nd6_is_addr_neighbor(&ro.ro_dst, ifp)) {
  252                         /*
  253                          * If the incoming interface is equal to the outgoing
  254                          * one, the link attached to the interface is
  255                          * point-to-point, and the IPv6 destination is
  256                          * regarded as on-link on the link, then it will be
  257                          * highly probable that the destination address does
  258                          * not exist on the link and that the packet is going
  259                          * to loop.  Thus, we immediately drop the packet and
  260                          * send an ICMPv6 error message.
  261                          * For other routing loops, we dare to let the packet
  262                          * go to the loop, so that a remote diagnosing host
  263                          * can detect the loop by traceroute.
  264                          * type/code is based on suggestion by Rich Draves.
  265                          * not sure if it is the best pick.
  266                          */
  267                         if (mcopy)
  268                                 icmp6_error(mcopy, ICMP6_DST_UNREACH,
  269                                     ICMP6_DST_UNREACH_ADDR, 0);
  270                         m_freem(m);
  271                         goto out;
  272                 }
  273                 type = ND_REDIRECT;
  274         }
  275 
  276         /*
  277          * Fake scoped addresses. Note that even link-local source or
  278          * destination can appear, if the originating node just sends the
  279          * packet to us (without address resolution for the destination).
  280          * Since both icmp6_error and icmp6_redirect_output fill the embedded
  281          * link identifiers, we can do this stuff after making a copy for
  282          * returning an error.
  283          */
  284         if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
  285                 ip6->ip6_src.s6_addr16[1] = 0;
  286         if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
  287                 ip6->ip6_dst.s6_addr16[1] = 0;
  288 
  289 #if NPF > 0
  290         if (pf_test(AF_INET6, PF_FWD, ifp, &m) != PF_PASS) {
  291                 m_freem(m);
  292                 goto senderr;
  293         }
  294         if (m == NULL)
  295                 goto senderr;
  296         ip6 = mtod(m, struct ip6_hdr *);
  297         if ((m->m_pkthdr.pf.flags & (PF_TAG_REROUTE | PF_TAG_GENERATED)) ==
  298             (PF_TAG_REROUTE | PF_TAG_GENERATED)) {
  299                 /* already rerun the route lookup, go on */
  300                 m->m_pkthdr.pf.flags &= ~(PF_TAG_GENERATED | PF_TAG_REROUTE);
  301         } else if (m->m_pkthdr.pf.flags & PF_TAG_REROUTE) {
  302                 /* tag as generated to skip over pf_test on rerun */
  303                 m->m_pkthdr.pf.flags |= PF_TAG_GENERATED;
  304                 srcrt = 1;
  305                 rtfree(rt);
  306                 rt = NULL;
  307                 if_put(ifp);
  308                 ifp = NULL;
  309                 goto reroute;
  310         }
  311 #endif
  312         in6_proto_cksum_out(m, ifp);
  313 
  314         /* Check the size after pf_test to give pf a chance to refragment. */
  315         if (m->m_pkthdr.len > ifp->if_mtu) {
  316                 if (mcopy)
  317                         icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,
  318                             ifp->if_mtu);
  319                 m_freem(m);
  320                 goto out;
  321         }
  322 
  323         error = ifp->if_output(ifp, m, sin6tosa(sin6), rt);
  324         if (error) {
  325                 ip6stat_inc(ip6s_cantforward);
  326         } else {
  327                 ip6stat_inc(ip6s_forward);
  328                 if (type)
  329                         ip6stat_inc(ip6s_redirectsent);
  330                 else {
  331                         if (mcopy)
  332                                 goto freecopy;
  333                 }
  334         }
  335 
  336 #if NPF > 0 || defined(IPSEC)
  337 senderr:
  338 #endif
  339         if (mcopy == NULL)
  340                 goto out;
  341 
  342         switch (error) {
  343         case 0:
  344                 if (type == ND_REDIRECT) {
  345                         icmp6_redirect_output(mcopy, rt);
  346                         goto out;
  347                 }
  348                 goto freecopy;
  349 
  350         case EMSGSIZE:
  351                 type = ICMP6_PACKET_TOO_BIG;
  352                 code = 0;
  353                 if (rt != NULL) {
  354                         if (rt->rt_mtu) {
  355                                 destmtu = rt->rt_mtu;
  356                         } else {
  357                                 struct ifnet *destifp;
  358 
  359                                 destifp = if_get(rt->rt_ifidx);
  360                                 if (destifp != NULL)
  361                                         destmtu = destifp->if_mtu;
  362                                 if_put(destifp);
  363                         }
  364                 }
  365                 ip6stat_inc(ip6s_cantfrag);
  366                 if (destmtu == 0)
  367                         goto freecopy;
  368                 break;
  369 
  370         case EACCES:
  371                 /*
  372                  * pf(4) blocked the packet. There is no need to send an ICMP
  373                  * packet back since pf(4) takes care of it.
  374                  */
  375                 goto freecopy;
  376 
  377         case ENOBUFS:
  378                 /* Tell source to slow down like source quench in IP? */
  379                 goto freecopy;
  380 
  381         case ENETUNREACH:       /* shouldn't happen, checked above */
  382         case EHOSTUNREACH:
  383         case ENETDOWN:
  384         case EHOSTDOWN:
  385         default:
  386                 type = ICMP6_DST_UNREACH;
  387                 code = ICMP6_DST_UNREACH_ADDR;
  388                 break;
  389         }
  390         icmp6_error(mcopy, type, code, destmtu);
  391         goto out;
  392 
  393 freecopy:
  394         m_freem(mcopy);
  395 out:
  396         rtfree(rt);
  397         if_put(ifp);
  398 #ifdef IPSEC
  399         tdb_unref(tdb);
  400 #endif /* IPSEC */
  401 }

Cache object: 1b7a5f1a6d4ddaf0581bc927d38d4d8b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.