root/netinet6/ip6_forward.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ip6_forward

    1 /*      $OpenBSD: ip6_forward.c,v 1.39 2007/06/01 00:52:38 henning 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/malloc.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/domain.h>
   40 #include <sys/protosw.h>
   41 #include <sys/socket.h>
   42 #include <sys/errno.h>
   43 #include <sys/time.h>
   44 #include <sys/kernel.h>
   45 #include <sys/syslog.h>
   46 
   47 #include <net/if.h>
   48 #include <net/route.h>
   49 
   50 #include <netinet/in.h>
   51 #include <netinet/in_var.h>
   52 #include <netinet/ip_var.h>
   53 #include <netinet/ip6.h>
   54 #include <netinet6/ip6_var.h>
   55 #include <netinet/icmp6.h>
   56 #include <netinet6/nd6.h>
   57 
   58 #if NPF > 0
   59 #include <net/pfvar.h>
   60 #endif
   61 
   62 #ifdef IPSEC
   63 #include <netinet/ip_ipsp.h>
   64 #include <netinet/ip_ah.h>
   65 #include <netinet/ip_esp.h>
   66 #include <netinet/udp.h>
   67 #include <netinet/tcp.h>
   68 #include <net/pfkeyv2.h>
   69 #endif
   70 
   71 struct  route_in6 ip6_forward_rt;
   72 int     ip6_forward_rtableid;
   73 
   74 /*
   75  * Forward a packet.  If some error occurs return the sender
   76  * an icmp packet.  Note we can't always generate a meaningful
   77  * icmp message because icmp doesn't have a large enough repertoire
   78  * of codes and types.
   79  *
   80  * If not forwarding, just drop the packet.  This could be confusing
   81  * if ipforwarding was zero but some routing protocol was advancing
   82  * us as a gateway to somewhere.  However, we must let the routing
   83  * protocol deal with that.
   84  *
   85  */
   86 
   87 void
   88 ip6_forward(m, srcrt)
   89         struct mbuf *m;
   90         int srcrt;
   91 {
   92         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
   93         struct sockaddr_in6 *dst;
   94         struct rtentry *rt;
   95         int error = 0, type = 0, code = 0;
   96         struct mbuf *mcopy = NULL;
   97         struct ifnet *origifp;  /* maybe unnecessary */
   98 #ifdef IPSEC
   99         u_int8_t sproto = 0;
  100         struct m_tag *mtag;
  101         union sockaddr_union sdst;
  102         struct tdb_ident *tdbi;
  103         u_int32_t sspi;
  104         struct tdb *tdb;
  105         int s;
  106 #endif /* IPSEC */
  107         int rtableid = 0;
  108 
  109         /*
  110          * Do not forward packets to multicast destination (should be handled
  111          * by ip6_mforward().
  112          * Do not forward packets with unspecified source.  It was discussed
  113          * in July 2000, on ipngwg mailing list.
  114          */
  115         if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
  116             IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
  117             IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
  118                 ip6stat.ip6s_cantforward++;
  119                 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
  120                 if (ip6_log_time + ip6_log_interval < time_second) {
  121                         ip6_log_time = time_second;
  122                         log(LOG_DEBUG,
  123                             "cannot forward "
  124                             "from %s to %s nxt %d received on %s\n",
  125                             ip6_sprintf(&ip6->ip6_src),
  126                             ip6_sprintf(&ip6->ip6_dst),
  127                             ip6->ip6_nxt,
  128                             m->m_pkthdr.rcvif->if_xname);
  129                 }
  130                 m_freem(m);
  131                 return;
  132         }
  133 
  134         if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
  135                 /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
  136                 icmp6_error(m, ICMP6_TIME_EXCEEDED,
  137                                 ICMP6_TIME_EXCEED_TRANSIT, 0);
  138                 return;
  139         }
  140         ip6->ip6_hlim -= IPV6_HLIMDEC;
  141 
  142 #ifdef IPSEC
  143         if (!ipsec_in_use)
  144                 goto done_spd;
  145 
  146         s = splnet();
  147 
  148         /*
  149          * Check if there was an outgoing SA bound to the flow
  150          * from a transport protocol.
  151          */
  152 
  153         /* Do we have any pending SAs to apply ? */
  154         mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
  155         if (mtag != NULL) {
  156 #ifdef DIAGNOSTIC
  157                 if (mtag->m_tag_len != sizeof (struct tdb_ident))
  158                         panic("ip6_forward: tag of length %d (should be %d",
  159                             mtag->m_tag_len, sizeof (struct tdb_ident));
  160 #endif
  161                 tdbi = (struct tdb_ident *)(mtag + 1);
  162                 tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
  163                 if (tdb == NULL)
  164                         error = -EINVAL;
  165                 m_tag_delete(m, mtag);
  166         } else
  167                 tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
  168                     &error, IPSP_DIRECTION_OUT, NULL, NULL);
  169 
  170         if (tdb == NULL) {
  171                 splx(s);
  172 
  173                 if (error == 0) {
  174                         /*
  175                          * No IPsec processing required, we'll just send the
  176                          * packet out.
  177                          */
  178                         sproto = 0;
  179 
  180                         /* Fall through to routing/multicast handling */
  181                 } else {
  182                         /*
  183                          * -EINVAL is used to indicate that the packet should
  184                          * be silently dropped, typically because we've asked
  185                          * key management for an SA.
  186                          */
  187                         if (error == -EINVAL) /* Should silently drop packet */
  188                                 error = 0;
  189 
  190                         goto freecopy;
  191                 }
  192         } else {
  193                 /* Loop detection */
  194                 for (mtag = m_tag_first(m); mtag != NULL;
  195                     mtag = m_tag_next(m, mtag)) {
  196                         if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
  197                             mtag->m_tag_id !=
  198                             PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
  199                                 continue;
  200                         tdbi = (struct tdb_ident *)(mtag + 1);
  201                         if (tdbi->spi == tdb->tdb_spi &&
  202                             tdbi->proto == tdb->tdb_sproto &&
  203                             !bcmp(&tdbi->dst, &tdb->tdb_dst,
  204                             sizeof(union sockaddr_union))) {
  205                                 splx(s);
  206                                 sproto = 0; /* mark as no-IPsec-needed */
  207                                 goto done_spd;
  208                         }
  209                 }
  210 
  211                 /* We need to do IPsec */
  212                 bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
  213                 sspi = tdb->tdb_spi;
  214                 sproto = tdb->tdb_sproto;
  215                 splx(s);
  216         }
  217 
  218         /* Fall through to the routing/multicast handling code */
  219  done_spd:
  220 #endif /* IPSEC */
  221 
  222 #if NPF > 0
  223         rtableid = m->m_pkthdr.pf.rtableid;
  224 #endif
  225 
  226         /*
  227          * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
  228          * size of IPv6 + ICMPv6 headers) bytes of the packet in case
  229          * we need to generate an ICMP6 message to the src.
  230          * Thanks to M_EXT, in most cases copy will not occur.
  231          *
  232          * It is important to save it before IPsec processing as IPsec
  233          * processing may modify the mbuf.
  234          */
  235         mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
  236 
  237         dst = &ip6_forward_rt.ro_dst;
  238         if (!srcrt) {
  239                 /*
  240                  * ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst
  241                  */
  242                 if (ip6_forward_rt.ro_rt == 0 ||
  243                     (ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0 ||
  244                     ip6_forward_rtableid != rtableid) {
  245                         if (ip6_forward_rt.ro_rt) {
  246                                 RTFREE(ip6_forward_rt.ro_rt);
  247                                 ip6_forward_rt.ro_rt = 0;
  248                         }
  249                         /* this probably fails but give it a try again */
  250                         rtalloc_mpath((struct route *)&ip6_forward_rt,
  251                             &ip6->ip6_src.s6_addr32[0], rtableid);
  252                         ip6_forward_rtableid = rtableid;
  253                 }
  254 
  255                 if (ip6_forward_rt.ro_rt == 0) {
  256                         ip6stat.ip6s_noroute++;
  257                         /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
  258                         if (mcopy) {
  259                                 icmp6_error(mcopy, ICMP6_DST_UNREACH,
  260                                             ICMP6_DST_UNREACH_NOROUTE, 0);
  261                         }
  262                         m_freem(m);
  263                         return;
  264                 }
  265         } else if ((rt = ip6_forward_rt.ro_rt) == 0 ||
  266                  !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
  267                 if (ip6_forward_rt.ro_rt) {
  268                         RTFREE(ip6_forward_rt.ro_rt);
  269                         ip6_forward_rt.ro_rt = 0;
  270                 }
  271                 bzero(dst, sizeof(*dst));
  272                 dst->sin6_len = sizeof(struct sockaddr_in6);
  273                 dst->sin6_family = AF_INET6;
  274                 dst->sin6_addr = ip6->ip6_dst;
  275 
  276                 rtalloc_mpath((struct route *)&ip6_forward_rt,
  277                     &ip6->ip6_src.s6_addr32[0], 0);
  278 
  279                 if (ip6_forward_rt.ro_rt == 0) {
  280                         ip6stat.ip6s_noroute++;
  281                         /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
  282                         if (mcopy) {
  283                                 icmp6_error(mcopy, ICMP6_DST_UNREACH,
  284                                             ICMP6_DST_UNREACH_NOROUTE, 0);
  285                         }
  286                         m_freem(m);
  287                         return;
  288                 }
  289         }
  290         rt = ip6_forward_rt.ro_rt;
  291 
  292         /*
  293          * Scope check: if a packet can't be delivered to its destination
  294          * for the reason that the destination is beyond the scope of the
  295          * source address, discard the packet and return an icmp6 destination
  296          * unreachable error with Code 2 (beyond scope of source address).
  297          * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1]
  298          */
  299         if (in6_addr2scopeid(m->m_pkthdr.rcvif, &ip6->ip6_src) !=
  300             in6_addr2scopeid(rt->rt_ifp, &ip6->ip6_src)) {
  301                 ip6stat.ip6s_cantforward++;
  302                 ip6stat.ip6s_badscope++;
  303                 in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
  304 
  305                 if (ip6_log_time + ip6_log_interval < time_second) {
  306                         ip6_log_time = time_second;
  307                         log(LOG_DEBUG,
  308                             "cannot forward "
  309                             "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
  310                             ip6_sprintf(&ip6->ip6_src),
  311                             ip6_sprintf(&ip6->ip6_dst),
  312                             ip6->ip6_nxt,
  313                             m->m_pkthdr.rcvif->if_xname, rt->rt_ifp->if_xname);
  314                 }
  315                 if (mcopy)
  316                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  317                                     ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
  318                 m_freem(m);
  319                 goto freert;
  320         }
  321 
  322 #ifdef IPSEC
  323         /*
  324          * Check if the packet needs encapsulation.
  325          * ipsp_process_packet will never come back to here.
  326          * XXX ipsp_process_packet() calls ip6_output(), and there'll be no
  327          * PMTU notification.  is it okay?
  328          */
  329         if (sproto != 0) {
  330                 s = splnet();
  331 
  332                 tdb = gettdb(sspi, &sdst, sproto);
  333                 if (tdb == NULL) {
  334                         splx(s);
  335                         error = EHOSTUNREACH;
  336                         m_freem(m);
  337                         goto senderr;   /*XXX*/
  338                 }
  339 
  340                 m->m_flags &= ~(M_BCAST | M_MCAST);     /* just in case */
  341 
  342                 /* Callee frees mbuf */
  343                 error = ipsp_process_packet(m, tdb, AF_INET6, 0);
  344                 splx(s);
  345                 m_freem(mcopy);
  346                 goto freert;
  347         }
  348 #endif /* IPSEC */
  349 
  350         if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
  351                 in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
  352                 if (mcopy) {
  353                         u_long mtu;
  354 
  355                         mtu = IN6_LINKMTU(rt->rt_ifp);
  356 
  357                         icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
  358                 }
  359                 m_freem(m);
  360                 goto freert;
  361         }
  362 
  363         if (rt->rt_flags & RTF_GATEWAY)
  364                 dst = (struct sockaddr_in6 *)rt->rt_gateway;
  365 
  366         /*
  367          * If we are to forward the packet using the same interface
  368          * as one we got the packet from, perhaps we should send a redirect
  369          * to sender to shortcut a hop.
  370          * Only send redirect if source is sending directly to us,
  371          * and if packet was not source routed (or has any options).
  372          * Also, don't send redirect if forwarding using a route
  373          * modified by a redirect.
  374          */
  375         if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects &&
  376             (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
  377                 if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
  378                     nd6_is_addr_neighbor((struct sockaddr_in6 *)&ip6_forward_rt.ro_dst, rt->rt_ifp)) {
  379                         /*
  380                          * If the incoming interface is equal to the outgoing
  381                          * one, the link attached to the interface is
  382                          * point-to-point, and the IPv6 destination is
  383                          * regarded as on-link on the link, then it will be
  384                          * highly probable that the destination address does
  385                          * not exist on the link and that the packet is going
  386                          * to loop.  Thus, we immediately drop the packet and
  387                          * send an ICMPv6 error message.
  388                          * For other routing loops, we dare to let the packet
  389                          * go to the loop, so that a remote diagnosing host
  390                          * can detect the loop by traceroute.
  391                          * type/code is based on suggestion by Rich Draves.
  392                          * not sure if it is the best pick.
  393                          */
  394                         icmp6_error(mcopy, ICMP6_DST_UNREACH,
  395                                     ICMP6_DST_UNREACH_ADDR, 0);
  396                         m_freem(m);
  397                         goto freert;
  398                 }
  399                 type = ND_REDIRECT;
  400         }
  401 
  402         /*
  403          * Fake scoped addresses. Note that even link-local source or
  404          * destinaion can appear, if the originating node just sends the
  405          * packet to us (without address resolution for the destination).
  406          * Since both icmp6_error and icmp6_redirect_output fill the embedded
  407          * link identifiers, we can do this stuff after making a copy for
  408          * returning an error.
  409          */
  410         if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
  411                 /*
  412                  * See corresponding comments in ip6_output.
  413                  * XXX: but is it possible that ip6_forward() sends a packet
  414                  *      to a loopback interface? I don't think so, and thus
  415                  *      I bark here. (jinmei@kame.net)
  416                  * XXX: it is common to route invalid packets to loopback.
  417                  *      also, the codepath will be visited on use of ::1 in
  418                  *      rthdr. (itojun)
  419                  */
  420 #if 1
  421                 if (0)
  422 #else
  423                 if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
  424 #endif
  425                 {
  426                         printf("ip6_forward: outgoing interface is loopback. "
  427                                "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
  428                                ip6_sprintf(&ip6->ip6_src),
  429                                ip6_sprintf(&ip6->ip6_dst),
  430                                ip6->ip6_nxt, m->m_pkthdr.rcvif->if_xname,
  431                                rt->rt_ifp->if_xname);
  432                 }
  433 
  434                 /* we can just use rcvif in forwarding. */
  435                 origifp = m->m_pkthdr.rcvif;
  436         }
  437         else
  438                 origifp = rt->rt_ifp;
  439         if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
  440                 ip6->ip6_src.s6_addr16[1] = 0;
  441         if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
  442                 ip6->ip6_dst.s6_addr16[1] = 0;
  443 
  444 #if NPF > 0 
  445         if (pf_test6(PF_OUT, rt->rt_ifp, &m, NULL) != PF_PASS) {
  446                 m_freem(m);
  447                 goto senderr;
  448         }
  449         if (m == NULL)
  450                 goto senderr;
  451 
  452         ip6 = mtod(m, struct ip6_hdr *);
  453 #endif 
  454 
  455         error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
  456         if (error) {
  457                 in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
  458                 ip6stat.ip6s_cantforward++;
  459         } else {
  460                 ip6stat.ip6s_forward++;
  461                 in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
  462                 if (type)
  463                         ip6stat.ip6s_redirectsent++;
  464                 else {
  465                         if (mcopy)
  466                                 goto freecopy;
  467                 }
  468         }
  469 
  470 #if NPF > 0 || defined(IPSEC)
  471 senderr:
  472 #endif
  473         if (mcopy == NULL)
  474                 goto freert;
  475         switch (error) {
  476         case 0:
  477                 if (type == ND_REDIRECT) {
  478                         icmp6_redirect_output(mcopy, rt);
  479                         goto freert;
  480                 }
  481                 goto freecopy;
  482 
  483         case EMSGSIZE:
  484                 /* xxx MTU is constant in PPP? */
  485                 goto freecopy;
  486 
  487         case ENOBUFS:
  488                 /* Tell source to slow down like source quench in IP? */
  489                 goto freecopy;
  490 
  491         case ENETUNREACH:       /* shouldn't happen, checked above */
  492         case EHOSTUNREACH:
  493         case ENETDOWN:
  494         case EHOSTDOWN:
  495         default:
  496                 type = ICMP6_DST_UNREACH;
  497                 code = ICMP6_DST_UNREACH_ADDR;
  498                 break;
  499         }
  500         icmp6_error(mcopy, type, code, 0);
  501         goto freert;
  502 
  503  freecopy:
  504         m_freem(mcopy);
  505  freert:
  506 #ifndef SMALL_KERNEL
  507         if (ip6_multipath && ip6_forward_rt.ro_rt &&
  508             (ip6_forward_rt.ro_rt->rt_flags & RTF_MPATH)) {
  509                 RTFREE(ip6_forward_rt.ro_rt);
  510                 ip6_forward_rt.ro_rt = 0;
  511         }
  512 #endif
  513         return;
  514 }

/* [<][>][^][v][top][bottom][index][help] */