[BACK]Return to ip6_forward.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / netinet6

Annotation of src/sys/netinet6/ip6_forward.c, Revision 1.65.12.1

1.65.12.1! sborrill    1: /*     $NetBSD: ip6_forward.c,v 1.65 2008/04/23 06:09:05 thorpej Exp $ */
1.32      itojun      2: /*     $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $   */
1.3       thorpej     3:
1.2       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
1.10      itojun      7:  *
1.2       itojun      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.
1.10      itojun     19:  *
1.2       itojun     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:  */
1.26      lukem      32:
                     33: #include <sys/cdefs.h>
1.65.12.1! sborrill   34: __KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.65 2008/04/23 06:09:05 thorpej Exp $");
1.2       itojun     35:
1.15      itojun     36: #include "opt_ipsec.h"
1.20      itojun     37: #include "opt_pfil_hooks.h"
1.15      itojun     38:
1.2       itojun     39: #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>
                     50:
                     51: #include <net/if.h>
                     52: #include <net/route.h>
                     53:
                     54: #include <netinet/in.h>
                     55: #include <netinet/in_var.h>
1.7       itojun     56: #include <netinet/ip_var.h>
1.8       itojun     57: #include <netinet/ip6.h>
1.2       itojun     58: #include <netinet6/ip6_var.h>
1.64      thorpej    59: #include <netinet6/ip6_private.h>
1.47      rpaulo     60: #include <netinet6/scope6_var.h>
1.8       itojun     61: #include <netinet/icmp6.h>
1.5       itojun     62: #include <netinet6/nd6.h>
                     63:
1.15      itojun     64: #ifdef IPSEC
1.5       itojun     65: #include <netinet6/ipsec.h>
1.65      thorpej    66: #include <netinet6/ipsec_private.h>
1.5       itojun     67: #include <netkey/key.h>
1.15      itojun     68: #endif /* IPSEC */
1.5       itojun     69:
1.54      degroote   70: #ifdef FAST_IPSEC
                     71: #include <netipsec/ipsec.h>
                     72: #include <netipsec/ipsec6.h>
                     73: #include <netipsec/key.h>
                     74: #include <netipsec/xform.h>
                     75: #endif /* FAST_IPSEC */
                     76:
1.20      itojun     77: #ifdef PFIL_HOOKS
                     78: #include <net/pfil.h>
                     79: #endif
                     80:
1.5       itojun     81: #include <net/net_osdep.h>
1.2       itojun     82:
1.57      dyoung     83: struct route ip6_forward_rt;
1.2       itojun     84:
1.20      itojun     85: #ifdef PFIL_HOOKS
                     86: extern struct pfil_head inet6_pfil_hook;       /* XXX */
                     87: #endif
                     88:
1.2       itojun     89: /*
                     90:  * Forward a packet.  If some error occurs return the sender
                     91:  * an icmp packet.  Note we can't always generate a meaningful
                     92:  * icmp message because icmp doesn't have a large enough repertoire
                     93:  * of codes and types.
                     94:  *
                     95:  * If not forwarding, just drop the packet.  This could be confusing
                     96:  * if ipforwarding was zero but some routing protocol was advancing
                     97:  * us as a gateway to somewhere.  However, we must let the routing
                     98:  * protocol deal with that.
                     99:  *
                    100:  */
                    101:
                    102: void
1.58      christos  103: ip6_forward(struct mbuf *m, int srcrt)
1.2       itojun    104: {
1.5       itojun    105:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.57      dyoung    106:        const struct sockaddr_in6 *dst;
1.18      itojun    107:        struct rtentry *rt;
1.42      itojun    108:        int error = 0, type = 0, code = 0;
1.5       itojun    109:        struct mbuf *mcopy = NULL;
1.10      itojun    110:        struct ifnet *origifp;  /* maybe unnecessary */
1.47      rpaulo    111:        u_int32_t inzone, outzone;
                    112:        struct in6_addr src_in6, dst_in6;
1.15      itojun    113: #ifdef IPSEC
1.5       itojun    114:        struct secpolicy *sp = NULL;
1.37      itojun    115:        int ipsecrt = 0;
1.5       itojun    116: #endif
1.54      degroote  117: #ifdef FAST_IPSEC
                    118:     struct secpolicy *sp = NULL;
                    119:     int needipsec = 0;
                    120:     int s;
                    121: #endif
                    122:
1.65.12.1! sborrill  123:        /*
        !           124:         * Clear any in-bound checksum flags for this packet.
        !           125:         */
        !           126:        m->m_pkthdr.csum_flags = 0;
1.5       itojun    127:
1.15      itojun    128: #ifdef IPSEC
1.5       itojun    129:        /*
                    130:         * Check AH/ESP integrity.
                    131:         */
                    132:        /*
                    133:         * Don't increment ip6s_cantforward because this is the check
                    134:         * before forwarding packet actually.
                    135:         */
                    136:        if (ipsec6_in_reject(m, NULL)) {
1.65      thorpej   137:                IPSEC6_STATINC(IPSEC_STAT_IN_POLVIO);
1.5       itojun    138:                m_freem(m);
                    139:                return;
                    140:        }
1.25      itojun    141: #endif /* IPSEC */
1.2       itojun    142:
1.16      itojun    143:        /*
                    144:         * Do not forward packets to multicast destination (should be handled
                    145:         * by ip6_mforward().
                    146:         * Do not forward packets with unspecified source.  It was discussed
                    147:         * in July 2000, on ipngwg mailing list.
                    148:         */
1.9       itojun    149:        if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
1.16      itojun    150:            IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
                    151:            IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1.64      thorpej   152:                IP6_STATINC(IP6_STAT_CANTFORWARD);
1.5       itojun    153:                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
1.48      kardel    154:                if (ip6_log_time + ip6_log_interval < time_second) {
                    155:                        ip6_log_time = time_second;
1.2       itojun    156:                        log(LOG_DEBUG,
                    157:                            "cannot forward "
                    158:                            "from %s to %s nxt %d received on %s\n",
1.9       itojun    159:                            ip6_sprintf(&ip6->ip6_src),
                    160:                            ip6_sprintf(&ip6->ip6_dst),
1.2       itojun    161:                            ip6->ip6_nxt,
1.5       itojun    162:                            if_name(m->m_pkthdr.rcvif));
1.2       itojun    163:                }
                    164:                m_freem(m);
                    165:                return;
                    166:        }
                    167:
                    168:        if (ip6->ip6_hlim <= IPV6_HLIMDEC) {
1.5       itojun    169:                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */
1.2       itojun    170:                icmp6_error(m, ICMP6_TIME_EXCEEDED,
                    171:                                ICMP6_TIME_EXCEED_TRANSIT, 0);
                    172:                return;
                    173:        }
                    174:        ip6->ip6_hlim -= IPV6_HLIMDEC;
                    175:
1.5       itojun    176:        /*
                    177:         * Save at most ICMPV6_PLD_MAXLEN (= the min IPv6 MTU -
                    178:         * size of IPv6 + ICMPv6 headers) bytes of the packet in case
                    179:         * we need to generate an ICMP6 message to the src.
                    180:         * Thanks to M_EXT, in most cases copy will not occur.
                    181:         *
                    182:         * It is important to save it before IPsec processing as IPsec
                    183:         * processing may modify the mbuf.
                    184:         */
                    185:        mcopy = m_copy(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN));
                    186:
1.15      itojun    187: #ifdef IPSEC
1.5       itojun    188:        /* get a security policy for this packet */
1.35      itojun    189:        sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
                    190:            IP_FORWARDING, &error);
1.5       itojun    191:        if (sp == NULL) {
1.65      thorpej   192:                IPSEC6_STATINC(IPSEC_STAT_OUT_INVAL);
1.64      thorpej   193:                IP6_STATINC(IP6_STAT_CANTFORWARD);
1.5       itojun    194:                if (mcopy) {
                    195: #if 0
                    196:                        /* XXX: what icmp ? */
                    197: #else
                    198:                        m_freem(mcopy);
                    199: #endif
                    200:                }
                    201:                m_freem(m);
                    202:                return;
                    203:        }
                    204:
                    205:        error = 0;
                    206:
                    207:        /* check policy */
                    208:        switch (sp->policy) {
                    209:        case IPSEC_POLICY_DISCARD:
                    210:                /*
                    211:                 * This packet is just discarded.
                    212:                 */
1.65      thorpej   213:                IPSEC6_STATINC(IPSEC_STAT_OUT_POLVIO);
1.64      thorpej   214:                IP6_STATINC(IP6_STAT_CANTFORWARD);
1.5       itojun    215:                key_freesp(sp);
                    216:                if (mcopy) {
                    217: #if 0
                    218:                        /* XXX: what icmp ? */
                    219: #else
                    220:                        m_freem(mcopy);
                    221: #endif
                    222:                }
                    223:                m_freem(m);
                    224:                return;
                    225:
                    226:        case IPSEC_POLICY_BYPASS:
                    227:        case IPSEC_POLICY_NONE:
                    228:                /* no need to do IPsec. */
                    229:                key_freesp(sp);
                    230:                goto skip_ipsec;
1.13      itojun    231:
1.5       itojun    232:        case IPSEC_POLICY_IPSEC:
                    233:                if (sp->req == NULL) {
                    234:                        /* XXX should be panic ? */
                    235:                        printf("ip6_forward: No IPsec request specified.\n");
1.64      thorpej   236:                        IP6_STATINC(IP6_STAT_CANTFORWARD);
1.5       itojun    237:                        key_freesp(sp);
                    238:                        if (mcopy) {
                    239: #if 0
                    240:                                /* XXX: what icmp ? */
                    241: #else
                    242:                                m_freem(mcopy);
                    243: #endif
                    244:                        }
                    245:                        m_freem(m);
                    246:                        return;
                    247:                }
                    248:                /* do IPsec */
                    249:                break;
                    250:
                    251:        case IPSEC_POLICY_ENTRUST:
                    252:        default:
                    253:                /* should be panic ?? */
                    254:                printf("ip6_forward: Invalid policy found. %d\n", sp->policy);
                    255:                key_freesp(sp);
                    256:                goto skip_ipsec;
                    257:        }
                    258:
                    259:     {
1.32      itojun    260:        struct ipsecrequest *isr = NULL;
1.5       itojun    261:        struct ipsec_output_state state;
                    262:
1.32      itojun    263:        /*
                    264:         * when the kernel forwards a packet, it is not proper to apply
                    265:         * IPsec transport mode to the packet is not proper.  this check
                    266:         * avoid from this.
                    267:         * at present, if there is even a transport mode SA request in the
                    268:         * security policy, the kernel does not apply IPsec to the packet.
                    269:         * this check is not enough because the following case is valid.
                    270:         *      ipsec esp/tunnel/xxx-xxx/require esp/transport//require;
                    271:         */
                    272:        for (isr = sp->req; isr; isr = isr->next) {
1.41      itojun    273:                if (isr->saidx.mode == IPSEC_MODE_ANY)
                    274:                        goto doipsectunnel;
                    275:                if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
                    276:                        goto doipsectunnel;
1.32      itojun    277:        }
1.41      itojun    278:
                    279:        /*
                    280:         * if there's no need for tunnel mode IPsec, skip.
                    281:         */
                    282:        if (!isr)
                    283:                goto skip_ipsec;
1.44      perry     284:
1.41      itojun    285:     doipsectunnel:
1.5       itojun    286:        /*
                    287:         * All the extension headers will become inaccessible
                    288:         * (since they can be encrypted).
                    289:         * Don't panic, we need no more updates to extension headers
                    290:         * on inner IPv6 packet (since they are now encapsulated).
                    291:         *
                    292:         * IPv6 [ESP|AH] IPv6 [extension headers] payload
                    293:         */
                    294:        bzero(&state, sizeof(state));
                    295:        state.m = m;
                    296:        state.ro = NULL;        /* update at ipsec6_output_tunnel() */
                    297:        state.dst = NULL;       /* update at ipsec6_output_tunnel() */
                    298:
                    299:        error = ipsec6_output_tunnel(&state, sp, 0);
                    300:
                    301:        m = state.m;
                    302:        key_freesp(sp);
                    303:
                    304:        if (error) {
                    305:                /* mbuf is already reclaimed in ipsec6_output_tunnel. */
                    306:                switch (error) {
                    307:                case EHOSTUNREACH:
                    308:                case ENETUNREACH:
                    309:                case EMSGSIZE:
                    310:                case ENOBUFS:
                    311:                case ENOMEM:
                    312:                        break;
                    313:                default:
1.49      liamjfoy  314:                        printf("ip6_forward (ipsec): error code %d\n", error);
1.30      itojun    315:                        /* FALLTHROUGH */
1.5       itojun    316:                case ENOENT:
                    317:                        /* don't show these error codes to the user */
                    318:                        break;
                    319:                }
1.64      thorpej   320:                IP6_STATINC(IP6_STAT_CANTFORWARD);
1.5       itojun    321:                if (mcopy) {
                    322: #if 0
                    323:                        /* XXX: what icmp ? */
                    324: #else
                    325:                        m_freem(mcopy);
                    326: #endif
                    327:                }
                    328:                m_freem(m);
                    329:                return;
                    330:        }
1.37      itojun    331:
1.41      itojun    332:        if (ip6 != mtod(m, struct ip6_hdr *)) {
                    333:                /*
                    334:                 * now tunnel mode headers are added.  we are originating
1.44      perry     335:                 * packet instead of forwarding the packet.
1.41      itojun    336:                 */
                    337:                ip6_output(m, NULL, NULL, IPV6_FORWARDING/*XXX*/, NULL, NULL,
                    338:                    NULL);
1.43      itojun    339:                goto freecopy;
1.41      itojun    340:        }
                    341:
1.37      itojun    342:        /* adjust pointer */
1.62      dyoung    343:        rt = state.ro ? rtcache_validate(state.ro) : NULL;
1.57      dyoung    344:        dst = (const struct sockaddr_in6 *)state.dst;
1.40      mycroft   345:        if (dst != NULL && rt != NULL) {
1.37      itojun    346:                ipsecrt = 1;
1.40      mycroft   347:                goto skip_routing;
                    348:        }
1.5       itojun    349:     }
                    350:     skip_ipsec:
1.15      itojun    351: #endif /* IPSEC */
1.54      degroote  352: #ifdef FAST_IPSEC
                    353:        /* Check the security policy (SP) for the packet */
                    354:
                    355:        sp = ipsec6_check_policy(m,NULL,0,&needipsec,&error);
                    356:        if (error != 0) {
                    357:                /*
                    358:                 * Hack: -EINVAL is used to signal that a packet
                    359:                 * should be silently discarded.  This is typically
                    360:                 * because we asked key management for an SA and
                    361:                 * it was delayed (e.g. kicked up to IKE).
                    362:                 */
                    363:        if (error == -EINVAL)
                    364:                error = 0;
                    365:        goto freecopy;
                    366:        }
                    367: #endif /* FAST_IPSEC */
                    368:
1.61      dyoung    369:        if (srcrt) {
1.57      dyoung    370:                union {
                    371:                        struct sockaddr         dst;
                    372:                        struct sockaddr_in6     dst6;
                    373:                } u;
                    374:
                    375:                sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0);
1.62      dyoung    376:                if ((rt = rtcache_lookup(&ip6_forward_rt, &u.dst)) == NULL) {
1.64      thorpej   377:                        IP6_STATINC(IP6_STAT_NOROUTE);
1.5       itojun    378:                        /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
                    379:                        if (mcopy) {
                    380:                                icmp6_error(mcopy, ICMP6_DST_UNREACH,
                    381:                                            ICMP6_DST_UNREACH_NOROUTE, 0);
                    382:                        }
                    383:                        m_freem(m);
1.2       itojun    384:                        return;
                    385:                }
1.62      dyoung    386:        } else if ((rt = rtcache_validate(&ip6_forward_rt)) == NULL &&
                    387:                   (rt = rtcache_update(&ip6_forward_rt, 1)) == NULL) {
1.61      dyoung    388:                /*
                    389:                 * rtcache_getdst(ip6_forward_rt)->sin6_addr was equal to
                    390:                 * ip6->ip6_dst
                    391:                 */
1.64      thorpej   392:                IP6_STATINC(IP6_STAT_NOROUTE);
1.61      dyoung    393:                /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_noroute) */
                    394:                if (mcopy) {
                    395:                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
                    396:                            ICMP6_DST_UNREACH_NOROUTE, 0);
                    397:                }
                    398:                m_freem(m);
                    399:                return;
1.2       itojun    400:        }
1.57      dyoung    401:        dst = satocsin6(rtcache_getdst(&ip6_forward_rt));
1.37      itojun    402: #ifdef IPSEC
                    403:     skip_routing:;
                    404: #endif /* IPSEC */
1.9       itojun    405:
                    406:        /*
1.47      rpaulo    407:         * Source scope check: if a packet can't be delivered to its
                    408:         * destination for the reason that the destination is beyond the scope
                    409:         * of the source address, discard the packet and return an icmp6
                    410:         * destination unreachable error with Code 2 (beyond scope of source
                    411:         * address).  We use a local copy of ip6_src, since in6_setscope()
                    412:         * will possibly modify its first argument.
                    413:         * [draft-ietf-ipngwg-icmp-v3-07, Section 3.1]
                    414:         */
                    415:        src_in6 = ip6->ip6_src;
                    416:        if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) {
                    417:                /* XXX: this should not happen */
1.64      thorpej   418:                uint64_t *ip6s = IP6_STAT_GETREF();
                    419:                ip6s[IP6_STAT_CANTFORWARD]++;
                    420:                ip6s[IP6_STAT_BADSCOPE]++;
                    421:                IP6_STAT_PUTREF();
1.47      rpaulo    422:                m_freem(m);
                    423:                return;
                    424:        }
                    425:        if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
1.64      thorpej   426:                uint64_t *ip6s = IP6_STAT_GETREF();
                    427:                ip6s[IP6_STAT_CANTFORWARD]++;
                    428:                ip6s[IP6_STAT_BADSCOPE]++;
                    429:                IP6_STAT_PUTREF();
1.47      rpaulo    430:                m_freem(m);
                    431:                return;
                    432:        }
                    433:        if (inzone != outzone
1.39      itojun    434: #ifdef IPSEC
                    435:            && !ipsecrt
                    436: #endif
                    437:            ) {
1.64      thorpej   438:                uint64_t *ip6s = IP6_STAT_GETREF();
                    439:                ip6s[IP6_STAT_CANTFORWARD]++;
                    440:                ip6s[IP6_STAT_BADSCOPE]++;
                    441:                IP6_STAT_PUTREF();
1.9       itojun    442:                in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
                    443:
1.48      kardel    444:                if (ip6_log_time + ip6_log_interval < time_second) {
                    445:                        ip6_log_time = time_second;
1.9       itojun    446:                        log(LOG_DEBUG,
                    447:                            "cannot forward "
                    448:                            "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
                    449:                            ip6_sprintf(&ip6->ip6_src),
                    450:                            ip6_sprintf(&ip6->ip6_dst),
                    451:                            ip6->ip6_nxt,
                    452:                            if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp));
                    453:                }
                    454:                if (mcopy)
                    455:                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
                    456:                                    ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
                    457:                m_freem(m);
                    458:                return;
                    459:        }
1.54      degroote  460: #ifdef FAST_IPSEC
                    461:     /*
                    462:      * If we need to encapsulate the packet, do it here
                    463:      * ipsec6_proces_packet will send the packet using ip6_output
                    464:      */
                    465:        if (needipsec) {
                    466:                s = splsoftnet();
                    467:                error = ipsec6_process_packet(m,sp->req);
                    468:                splx(s);
                    469:                if (mcopy)
                    470:                        goto freecopy;
                    471:     }
                    472: #endif
                    473:
                    474:
1.9       itojun    475:
1.47      rpaulo    476:        /*
                    477:         * Destination scope check: if a packet is going to break the scope
                    478:         * zone of packet's destination address, discard it.  This case should
                    479:         * usually be prevented by appropriately-configured routing table, but
                    480:         * we need an explicit check because we may mistakenly forward the
                    481:         * packet to a different zone by (e.g.) a default route.
                    482:         */
                    483:        dst_in6 = ip6->ip6_dst;
                    484:        if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 ||
                    485:            in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 ||
                    486:            inzone != outzone) {
1.64      thorpej   487:                uint64_t *ip6s = IP6_STAT_GETREF();
                    488:                ip6s[IP6_STAT_CANTFORWARD]++;
                    489:                ip6s[IP6_STAT_BADSCOPE]++;
                    490:                IP6_STAT_PUTREF();
1.47      rpaulo    491:                m_freem(m);
                    492:                return;
                    493:        }
                    494:
1.28      itojun    495:        if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
1.5       itojun    496:                in6_ifstat_inc(rt->rt_ifp, ifs6_in_toobig);
                    497:                if (mcopy) {
                    498:                        u_long mtu;
1.15      itojun    499: #ifdef IPSEC
1.45      christos  500:                        struct secpolicy *xsp;
1.7       itojun    501:                        int ipsecerror;
                    502:                        size_t ipsechdrsiz;
                    503: #endif
1.5       itojun    504:
1.28      itojun    505:                        mtu = IN6_LINKMTU(rt->rt_ifp);
1.15      itojun    506: #ifdef IPSEC
1.7       itojun    507:                        /*
                    508:                         * When we do IPsec tunnel ingress, we need to play
1.28      itojun    509:                         * with the link value (decrement IPsec header size
1.7       itojun    510:                         * from mtu value).  The code is much simpler than v4
                    511:                         * case, as we have the outgoing interface for
                    512:                         * encapsulated packet as "rt->rt_ifp".
                    513:                         */
1.45      christos  514:                        xsp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND,
1.7       itojun    515:                                IP_FORWARDING, &ipsecerror);
1.45      christos  516:                        if (xsp) {
1.7       itojun    517:                                ipsechdrsiz = ipsec6_hdrsiz(mcopy,
                    518:                                        IPSEC_DIR_OUTBOUND, NULL);
                    519:                                if (ipsechdrsiz < mtu)
                    520:                                        mtu -= ipsechdrsiz;
                    521:                        }
                    522:
                    523:                        /*
1.10      itojun    524:                         * if mtu becomes less than minimum MTU,
1.7       itojun    525:                         * tell minimum MTU (and I'll need to fragment it).
                    526:                         */
                    527:                        if (mtu < IPV6_MMTU)
                    528:                                mtu = IPV6_MMTU;
                    529: #endif
1.5       itojun    530:                        icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
                    531:                }
                    532:                m_freem(m);
1.2       itojun    533:                return;
1.31      itojun    534:        }
1.2       itojun    535:
                    536:        if (rt->rt_flags & RTF_GATEWAY)
                    537:                dst = (struct sockaddr_in6 *)rt->rt_gateway;
                    538:
                    539:        /*
                    540:         * If we are to forward the packet using the same interface
                    541:         * as one we got the packet from, perhaps we should send a redirect
                    542:         * to sender to shortcut a hop.
                    543:         * Only send redirect if source is sending directly to us,
                    544:         * and if packet was not source routed (or has any options).
                    545:         * Also, don't send redirect if forwarding using a route
                    546:         * modified by a redirect.
                    547:         */
1.36      itojun    548:        if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt && ip6_sendredirects &&
1.37      itojun    549: #ifdef IPSEC
                    550:            !ipsecrt &&
                    551: #endif
1.22      itojun    552:            (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
1.23      itojun    553:                if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) &&
1.55      dyoung    554:                    nd6_is_addr_neighbor(
1.57      dyoung    555:                        satocsin6(rtcache_getdst(&ip6_forward_rt)),
1.55      dyoung    556:                        rt->rt_ifp)) {
1.22      itojun    557:                        /*
                    558:                         * If the incoming interface is equal to the outgoing
1.23      itojun    559:                         * one, the link attached to the interface is
                    560:                         * point-to-point, and the IPv6 destination is
                    561:                         * regarded as on-link on the link, then it will be
                    562:                         * highly probable that the destination address does
                    563:                         * not exist on the link and that the packet is going
                    564:                         * to loop.  Thus, we immediately drop the packet and
                    565:                         * send an ICMPv6 error message.
                    566:                         * For other routing loops, we dare to let the packet
                    567:                         * go to the loop, so that a remote diagnosing host
                    568:                         * can detect the loop by traceroute.
1.22      itojun    569:                         * type/code is based on suggestion by Rich Draves.
                    570:                         * not sure if it is the best pick.
                    571:                         */
                    572:                        icmp6_error(mcopy, ICMP6_DST_UNREACH,
                    573:                                    ICMP6_DST_UNREACH_ADDR, 0);
                    574:                        m_freem(m);
                    575:                        return;
                    576:                }
1.2       itojun    577:                type = ND_REDIRECT;
1.22      itojun    578:        }
1.2       itojun    579:
1.10      itojun    580:        /*
                    581:         * Fake scoped addresses. Note that even link-local source or
                    582:         * destinaion can appear, if the originating node just sends the
                    583:         * packet to us (without address resolution for the destination).
                    584:         * Since both icmp6_error and icmp6_redirect_output fill the embedded
1.18      itojun    585:         * link identifiers, we can do this stuff after making a copy for
                    586:         * returning an error.
1.10      itojun    587:         */
                    588:        if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
                    589:                /*
                    590:                 * See corresponding comments in ip6_output.
                    591:                 * XXX: but is it possible that ip6_forward() sends a packet
                    592:                 *      to a loopback interface? I don't think so, and thus
                    593:                 *      I bark here. (jinmei@kame.net)
1.12      itojun    594:                 * XXX: it is common to route invalid packets to loopback.
1.13      itojun    595:                 *      also, the codepath will be visited on use of ::1 in
                    596:                 *      rthdr. (itojun)
1.10      itojun    597:                 */
1.13      itojun    598: #if 1
                    599:                if (0)
                    600: #else
                    601:                if ((rt->rt_flags & (RTF_BLACKHOLE|RTF_REJECT)) == 0)
                    602: #endif
                    603:                {
1.12      itojun    604:                        printf("ip6_forward: outgoing interface is loopback. "
                    605:                               "src %s, dst %s, nxt %d, rcvif %s, outif %s\n",
                    606:                               ip6_sprintf(&ip6->ip6_src),
                    607:                               ip6_sprintf(&ip6->ip6_dst),
                    608:                               ip6->ip6_nxt, if_name(m->m_pkthdr.rcvif),
                    609:                               if_name(rt->rt_ifp));
                    610:                }
1.13      itojun    611:
1.19      itojun    612:                /* we can just use rcvif in forwarding. */
                    613:                origifp = m->m_pkthdr.rcvif;
1.10      itojun    614:        }
                    615:        else
                    616:                origifp = rt->rt_ifp;
1.47      rpaulo    617:        /*
                    618:         * clear embedded scope identifiers if necessary.
                    619:         * in6_clearscope will touch the addresses only when necessary.
                    620:         */
                    621:        in6_clearscope(&ip6->ip6_src);
                    622:        in6_clearscope(&ip6->ip6_dst);
1.10      itojun    623:
1.20      itojun    624: #ifdef PFIL_HOOKS
                    625:        /*
                    626:         * Run through list of hooks for output packets.
                    627:         */
                    628:        if ((error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp,
1.34      itojun    629:            PFIL_OUT)) != 0)
1.20      itojun    630:                goto senderr;
                    631:        if (m == NULL)
                    632:                goto freecopy;
                    633:        ip6 = mtod(m, struct ip6_hdr *);
                    634: #endif /* PFIL_HOOKS */
                    635:
1.10      itojun    636:        error = nd6_output(rt->rt_ifp, origifp, m, dst, rt);
1.5       itojun    637:        if (error) {
                    638:                in6_ifstat_inc(rt->rt_ifp, ifs6_out_discard);
1.64      thorpej   639:                IP6_STATINC(IP6_STAT_CANTFORWARD);
1.5       itojun    640:        } else {
1.64      thorpej   641:                IP6_STATINC(IP6_STAT_FORWARD);
1.5       itojun    642:                in6_ifstat_inc(rt->rt_ifp, ifs6_out_forward);
1.2       itojun    643:                if (type)
1.64      thorpej   644:                        IP6_STATINC(IP6_STAT_REDIRECTSENT);
1.2       itojun    645:                else {
1.56      liamjfoy  646: #ifdef GATEWAY
                    647:                        if (m->m_flags & M_CANFASTFWD)
                    648:                                ip6flow_create(&ip6_forward_rt, m);
                    649: #endif
1.2       itojun    650:                        if (mcopy)
                    651:                                goto freecopy;
                    652:                }
                    653:        }
1.20      itojun    654:
1.21      matt      655: #ifdef PFIL_HOOKS
1.20      itojun    656:  senderr:
1.21      matt      657: #endif
1.2       itojun    658:        if (mcopy == NULL)
                    659:                return;
                    660:        switch (error) {
                    661:        case 0:
                    662:                if (type == ND_REDIRECT) {
                    663:                        icmp6_redirect_output(mcopy, rt);
                    664:                        return;
                    665:                }
                    666:                goto freecopy;
                    667:
                    668:        case EMSGSIZE:
                    669:                /* xxx MTU is constant in PPP? */
                    670:                goto freecopy;
                    671:
                    672:        case ENOBUFS:
                    673:                /* Tell source to slow down like source quench in IP? */
                    674:                goto freecopy;
                    675:
                    676:        case ENETUNREACH:       /* shouldn't happen, checked above */
                    677:        case EHOSTUNREACH:
                    678:        case ENETDOWN:
                    679:        case EHOSTDOWN:
                    680:        default:
                    681:                type = ICMP6_DST_UNREACH;
                    682:                code = ICMP6_DST_UNREACH_ADDR;
                    683:                break;
                    684:        }
                    685:        icmp6_error(mcopy, type, code, 0);
                    686:        return;
                    687:
                    688:  freecopy:
                    689:        m_freem(mcopy);
1.5       itojun    690:        return;
1.2       itojun    691: }

CVSweb <webmaster@jp.NetBSD.org>