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 /*      $NetBSD: ip6_forward.c,v 1.102 2020/08/28 06:32:24 ozaki-r Exp $        */
    2 /*      $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane 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 <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.102 2020/08/28 06:32:24 ozaki-r Exp $");
   35 
   36 #ifdef _KERNEL_OPT
   37 #include "opt_gateway.h"
   38 #include "opt_ipsec.h"
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/errno.h>
   45 #include <sys/time.h>
   46 #include <sys/kernel.h>
   47 #include <sys/syslog.h>
   48 #include <sys/percpu.h>
   49 
   50 #include <net/if.h>
   51 #include <net/route.h>
   52 #include <net/pfil.h>
   53 
   54 #include <netinet/in.h>
   55 #include <netinet/in_var.h>
   56 #include <netinet/ip_var.h>
   57 #include <netinet/ip6.h>
   58 #include <netinet6/ip6_var.h>
   59 #include <netinet6/ip6_private.h>
   60 #include <netinet6/scope6_var.h>
   61 #include <netinet/icmp6.h>
   62 #include <netinet6/nd6.h>
   63 
   64 #ifdef IPSEC
   65 #include <netipsec/ipsec.h>
   66 #include <netipsec/ipsec6.h>
   67 #include <netipsec/key.h>
   68 #endif
   69 
   70 extern percpu_t *ip6_forward_rt_percpu;
   71 
   72 extern pfil_head_t *inet6_pfil_hook;    /* XXX */
   73 
   74 static void __printflike(4, 5)
   75 ip6_cantforward(const struct ip6_hdr *ip6, const struct ifnet *srcifp,
   76     const struct ifnet *dstifp, const char *fmt, ...)
   77 {
   78         char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN];
   79         char reason[256];
   80         va_list ap;
   81         uint64_t *ip6s;
   82 
   83         /* update statistics */
   84         ip6s = IP6_STAT_GETREF();
   85         ip6s[IP6_STAT_CANTFORWARD]++;
   86         if (dstifp)
   87                 ip6s[IP6_STAT_BADSCOPE]++;
   88         IP6_STAT_PUTREF();
   89 
   90         if (dstifp)
   91                 in6_ifstat_inc(dstifp, ifs6_in_discard);
   92 
   93         if (ip6_log_time + ip6_log_interval >= time_uptime)
   94                 return;
   95         ip6_log_time = time_uptime;
   96 
   97         va_start(ap, fmt);
   98         vsnprintf(reason, sizeof(reason), fmt, ap);
   99         va_end(ap);
  100 
  101         log(LOG_DEBUG, "Cannot forward from %s@%s to %s@%s nxt %d (%s)\n",
  102             IN6_PRINT(sbuf, &ip6->ip6_src), srcifp ? if_name(srcifp) : "?",
  103             IN6_PRINT(dbuf, &ip6->ip6_dst), dstifp ? if_name(dstifp) : "?",
  104             ip6->ip6_nxt, reason);
  105 }
  106 
  107 /*
  108  * Forward a packet.  If some error occurs return the sender
  109  * an icmp packet.  Note we can't always generate a meaningful
  110  * icmp message because icmp doesn't have a large enough repertoire
  111  * of codes and types.
  112  *
  113  * If not forwarding, just drop the packet.  This could be confusing
  114  * if ipforwarding was zero but some routing protocol was advancing
  115  * us as a gateway to somewhere.  However, we must let the routing
  116  * protocol deal with that.
  117  */
  118 void
  119 ip6_forward(struct mbuf *m, int srcrt, struct ifnet *rcvif)
  120 {
  121         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
  122         const struct sockaddr_in6 *dst;
  123         struct rtentry *rt = NULL;
  124         int error = 0, type = 0, code = 0;
  125         struct mbuf *mcopy = NULL;
  126         struct ifnet *origifp;  /* maybe unnecessary */
  127         uint32_t inzone, outzone;
  128         struct in6_addr src_in6, dst_in6;
  129         struct route *ro = NULL;
  130 #ifdef IPSEC
  131         int needipsec = 0;
  132         struct secpolicy *sp = NULL;
  133 #endif
  134 
  135         /*
  136          * Clear any in-bound checksum flags for this packet.
  137          */
  138         m->m_pkthdr.csum_flags = 0;
  139 
  140         /*
  141          * Do not forward packets to multicast destination (should be handled
  142          * by ip6_mforward()). Do not forward packets with unspecified source.
  143          * It was discussed in July 2000, on ipngwg mailing list.
  144          */
  145         if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
  146             IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
  147             IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
  148                 ip6_cantforward(ip6, rcvif, NULL,
  149                     ((m->m_flags & (M_BCAST|M_MCAST)) != 0) ? "bcast/mcast" :
  150                     IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ? "mcast/dst" :
  151                     "unspec/src");
  152                 goto drop;
  153         }
  154 
  155         if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
  156                 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
  157                 icmp6_error(m, ICMP6_TIME_EXCEEDED,
  158                                 ICMP6_TIME_EXCEED_TRANSIT, 0);
  159                 goto out;
  160         }
  161         ip6->ip6_hlim -= IPV6_HLIMDEC;
  162 
  163         /*
  164          * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
  165          * size of IPv6 + ICMPv6 headers) bytes of the packet in case
  166          * we need to generate an ICMP6 message to the src.
  167          * Thanks to M_EXT, in most cases copy will not occur.
  168          *
  169          * It is important to save it before IPsec processing as IPsec
  170          * processing may modify the mbuf.
  171          */
  172         mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN),
  173             M_DONTWAIT);
  174 
  175 #ifdef IPSEC
  176         if (ipsec_used) {
  177                 /* Check the security policy (SP) for the packet */
  178                 sp = ipsec6_check_policy(m, NULL, 0, &needipsec, &error);
  179                 if (error != 0) {
  180                         /*
  181                          * Hack: -EINVAL is used to signal that a packet
  182                          * should be silently discarded.  This is typically
  183                          * because we asked key management for an SA and
  184                          * it was delayed (e.g. kicked up to IKE).
  185                          */
  186                         if (error == -EINVAL)
  187                                 error = 0;
  188                         m_freem(m);
  189                         IP6_STATINC(IP6_STAT_IPSECDROP_OUT);
  190                         goto freecopy;
  191                 }
  192         }
  193 #endif
  194 
  195         ro = rtcache_percpu_getref(ip6_forward_rt_percpu);
  196         if (srcrt) {
  197                 union {
  198                         struct sockaddr         dst;
  199                         struct sockaddr_in6     dst6;
  200                 } u;
  201 
  202                 sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0);
  203                 rt = rtcache_lookup(ro, &u.dst);
  204                 if (rt == NULL) {
  205                         IP6_STATINC(IP6_STAT_NOROUTE);
  206                         /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
  207                         if (mcopy) {
  208                                 icmp6_error(mcopy, ICMP6_DST_UNREACH,
  209                                             ICMP6_DST_UNREACH_NOROUTE, 0);
  210                         }
  211                         goto drop;
  212                 }
  213         } else if ((rt = rtcache_validate(ro)) == NULL &&
  214                    (rt = rtcache_update(ro, 1)) == NULL) {
  215                 /*
  216                  * rtcache_getdst(ip6_forward_rt)->sin6_addr was equal to
  217                  * ip6->ip6_dst
  218                  */
  219                 IP6_STATINC(IP6_STAT_NOROUTE);
  220                 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
  221                 if (mcopy) {
  222                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  223                             ICMP6_DST_UNREACH_NOROUTE, 0);
  224                 }
  225                 goto drop;
  226         }
  227         dst = satocsin6(rtcache_getdst(ro));
  228 
  229         /*
  230          * Source scope check: if a packet can't be delivered to its
  231          * destination for the reason that the destination is beyond the scope
  232          * of the source address, discard the packet and return an icmp6
  233          * destination unreachable error with Code 2 (beyond scope of source
  234          * address).  We use a local copy of ip6_src, since in6_setscope()
  235          * will possibly modify its first argument.
  236          * [draft-ietf-ipngwg-icmp-v3-07, Section 3.1]
  237          */
  238         src_in6 = ip6->ip6_src;
  239         inzone = outzone = ~0;
  240         if (in6_setscope(&src_in6, rt->rt_ifp, &outzone) != 0 ||
  241             in6_setscope(&src_in6, rcvif, &inzone) != 0 ||
  242             inzone != outzone) {
  243                 ip6_cantforward(ip6, rcvif, rt->rt_ifp,
  244                     "src[%s] inzone %d outzone %d",
  245                     in6_getscopename(&ip6->ip6_src), inzone, outzone);
  246                 if (mcopy)
  247                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  248                                     ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
  249                 goto drop;
  250         }
  251 
  252 #ifdef IPSEC
  253         /*
  254          * If we need to encapsulate the packet, do it here.
  255          * ipsec6_process_packet will send the packet using ip6_output.
  256          */
  257         if (needipsec) {
  258                 int s = splsoftnet();
  259                 error = ipsec6_process_packet(m, sp->req, 0);
  260                 splx(s);
  261                 /* m is freed */
  262                 if (mcopy)
  263                         goto freecopy;
  264                 goto out;
  265         }
  266 #endif
  267 
  268         /*
  269          * Destination scope check: if a packet is going to break the scope
  270          * zone of packet's destination address, discard it.  This case should
  271          * usually be prevented by appropriately-configured routing table, but
  272          * we need an explicit check because we may mistakenly forward the
  273          * packet to a different zone by (e.g.) a default route.
  274          */
  275         dst_in6 = ip6->ip6_dst;
  276         inzone = outzone = ~0;
  277         if (in6_setscope(&dst_in6, rcvif, &inzone) != 0 ||
  278             in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
  279             inzone != outzone) {
  280                 ip6_cantforward(ip6, rcvif, rt->rt_ifp,
  281                     "dst[%s] inzone %d outzone %d",
  282                     in6_getscopename(&ip6->ip6_dst), inzone, outzone);
  283                 if (mcopy)
  284                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  285                                     ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
  286                 goto drop;
  287         }
  288 
  289         if (m->m_pkthdr.len > rt->rt_ifp->if_mtu) {
  290                 IP6_STATINC(IP6_STAT_TOOBIG);
  291                 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
  292                 if (mcopy)
  293                         icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0,
  294                             rt->rt_ifp->if_mtu);
  295                 goto drop;
  296         }
  297 
  298         if (rt->rt_flags & RTF_GATEWAY)
  299                 dst = (struct sockaddr_in6 *)rt->rt_gateway;
  300 
  301         /*
  302          * If we are to forward the packet using the same interface
  303          * as one we got the packet from, perhaps we should send a redirect
  304          * to sender to shortcut a hop.
  305          * Only send redirect if source is sending directly to us,
  306          * and if packet was not source routed (or has any options).
  307          * Also, don't send redirect if forwarding using a route
  308          * modified by a redirect.
  309          */
  310         if (rt->rt_ifp == rcvif && !srcrt && ip6_sendredirects &&
  311             (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
  312                 if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
  313                     nd6_is_addr_neighbor(satocsin6(rtcache_getdst(ro)),
  314                                          rt->rt_ifp)) {
  315                         /*
  316                          * If the incoming interface is equal to the outgoing
  317                          * one, the link attached to the interface is
  318                          * point-to-point, and the IPv6 destination is
  319                          * regarded as on-link on the link, then it will be
  320                          * highly probable that the destination address does
  321                          * not exist on the link and that the packet is going
  322                          * to loop.  Thus, we immediately drop the packet and
  323                          * send an ICMPv6 error message.
  324                          * For other routing loops, we dare to let the packet
  325                          * go to the loop, so that a remote diagnosing host
  326                          * can detect the loop by traceroute.
  327                          * type/code is based on suggestion by Rich Draves.
  328                          * not sure if it is the best pick.
  329                          */
  330                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  331                                     ICMP6_DST_UNREACH_ADDR, 0);
  332                         goto drop;
  333                 }
  334                 type = ND_REDIRECT;
  335         }
  336 
  337         /*
  338          * Fake scoped addresses. Note that even link-local source or
  339          * destination can appear, if the originating node just sends the
  340          * packet to us (without address resolution for the destination).
  341          * Since both icmp6_error and icmp6_redirect_output fill the embedded
  342          * link identifiers, we can do this stuff after making a copy for
  343          * returning an error.
  344          */
  345         if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
  346                 /*
  347                  * See corresponding comments in ip6_output.
  348                  * XXX: but is it possible that ip6_forward() sends a packet
  349                  *      to a loopback interface? I don't think so, and thus
  350                  *      I bark here. (jinmei@kame.net)
  351                  * XXX: it is common to route invalid packets to loopback.
  352                  *      also, the codepath will be visited on use of ::1 in
  353                  *      rthdr. (itojun)
  354                  */
  355 #if 1
  356                 if (0)
  357 #else
  358                 if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
  359 #endif
  360                 {
  361                         char ip6bufs[INET6_ADDRSTRLEN];
  362                         char ip6bufd[INET6_ADDRSTRLEN];
  363 
  364                         printf("ip6_forward: outgoing interface is loopback. "
  365                                "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
  366                                IN6_PRINT(ip6bufs, &ip6->ip6_src),
  367                                IN6_PRINT(ip6bufd, &ip6->ip6_dst),
  368                                ip6->ip6_nxt, if_name(rcvif),
  369                                if_name(rt->rt_ifp));
  370                 }
  371 
  372                 /* we can just use rcvif in forwarding. */
  373                 origifp = rcvif;
  374         } else {
  375                 origifp = rt->rt_ifp;
  376         }
  377 
  378         /*
  379          * clear embedded scope identifiers if necessary.
  380          * in6_clearscope will touch the addresses only when necessary.
  381          */
  382         in6_clearscope(&ip6->ip6_src);
  383         in6_clearscope(&ip6->ip6_dst);
  384 
  385         /*
  386          * Run through list of hooks for output packets.
  387          */
  388         if ((error = pfil_run_hooks(inet6_pfil_hook, &m, rt->rt_ifp,
  389             PFIL_OUT)) != 0) {
  390                 IP6_STATINC(IP6_STAT_PFILDROP_OUT);
  391                 goto senderr;
  392         }
  393         if (m == NULL) {
  394                 IP6_STATINC(IP6_STAT_PFILDROP_OUT);
  395                 goto freecopy;
  396         }
  397         ip6 = mtod(m, struct ip6_hdr *);
  398 
  399         error = ip6_if_output(rt->rt_ifp, origifp, m, dst, rt);
  400         if (error) {
  401                 in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
  402                 IP6_STATINC(IP6_STAT_CANTFORWARD);
  403         } else {
  404                 IP6_STATINC(IP6_STAT_FORWARD);
  405                 in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
  406                 if (type)
  407                         IP6_STATINC(IP6_STAT_REDIRECTSENT);
  408                 else {
  409 #ifdef GATEWAY
  410                         /* Need to release rt here */
  411                         rtcache_unref(rt, ro);
  412                         rt = NULL;
  413                         if (mcopy->m_flags & M_CANFASTFWD)
  414                                 ip6flow_create(ro, mcopy);
  415 #endif
  416                         if (mcopy)
  417                                 goto freecopy;
  418                 }
  419         }
  420 
  421 senderr:
  422         if (mcopy == NULL)
  423                 goto out;
  424         switch (error) {
  425         case 0:
  426                 if (type == ND_REDIRECT) {
  427                         icmp6_redirect_output(mcopy, rt);
  428                         goto out;
  429                 }
  430                 goto freecopy;
  431 
  432         case EMSGSIZE:
  433                 /* xxx MTU is constant in PPP? */
  434                 goto freecopy;
  435 
  436         case ENOBUFS:
  437                 /* Tell source to slow down like source quench in IP? */
  438                 goto freecopy;
  439 
  440         case ENETUNREACH:       /* shouldn't happen, checked above */
  441         case EHOSTUNREACH:
  442         case ENETDOWN:
  443         case EHOSTDOWN:
  444         default:
  445                 type = ICMP6_DST_UNREACH;
  446                 code = ICMP6_DST_UNREACH_ADDR;
  447                 break;
  448         }
  449         icmp6_error(mcopy, type, code, 0);
  450         goto out;
  451 
  452 freecopy:
  453         m_freem(mcopy);
  454         goto out;
  455 
  456 drop:
  457         m_freem(m);
  458 
  459 out:
  460 #ifdef IPSEC
  461         if (sp != NULL)
  462                 KEY_SP_UNREF(&sp);
  463 #endif
  464         rtcache_unref(rt, ro);
  465         if (ro != NULL)
  466                 rtcache_percpu_putref(ip6_forward_rt_percpu);
  467         return;
  468 }

Cache object: ff2f2e58a43e247050e0118de90c9704


[ 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.