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

Annotation of src/sys/netipsec/ipsec_output.c, Revision 1.5

1.5     ! itojun      1: /*     $NetBSD: ipsec_output.c,v 1.4 2003/08/20 22:33:40 jonathan Exp $        */
1.1       jonathan    2: /*     $FreeBSD: src/sys/netipsec/ipsec_output.c,v 1.3.2.1 2003/01/24 05:11:35 sam Exp $       */
                      3: /*     $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
                      4:
                      5: #include <sys/cdefs.h>
1.5     ! itojun      6: __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.4 2003/08/20 22:33:40 jonathan Exp $");
1.1       jonathan    7:
                      8: /*
                      9:  * IPsec output processing.
                     10:  */
                     11: #include "opt_inet.h"
1.4       jonathan   12: #ifdef __FreeBSD__
1.1       jonathan   13: #include "opt_inet6.h"
1.4       jonathan   14: #endif
1.1       jonathan   15: #include "opt_ipsec.h"
                     16:
                     17: #include <sys/param.h>
                     18: #include <sys/systm.h>
                     19: #include <sys/mbuf.h>
                     20: #include <sys/domain.h>
                     21: #include <sys/protosw.h>
                     22: #include <sys/socket.h>
                     23: #include <sys/errno.h>
                     24: #include <sys/syslog.h>
                     25:
                     26: #include <net/if.h>
                     27: #include <net/route.h>
                     28:
                     29: #include <netinet/in.h>
                     30: #include <netinet/in_systm.h>
                     31: #include <netinet/ip.h>
                     32: #include <netinet/ip_var.h>
                     33: #include <netinet/in_var.h>
                     34: #include <netinet/ip_ecn.h>
                     35: #ifdef INET6
                     36: #include <netinet6/ip6_ecn.h>
                     37: #endif
                     38:
                     39: #include <netinet/ip6.h>
                     40: #ifdef INET6
                     41: #include <netinet6/ip6_var.h>
                     42: #endif
                     43: #include <netinet/in_pcb.h>
                     44: #ifdef INET6
                     45: #include <netinet/icmp6.h>
                     46: #endif
                     47:
                     48: #include <netipsec/ipsec.h>
                     49: #ifdef INET6
                     50: #include <netipsec/ipsec6.h>
                     51: #endif
                     52: #include <netipsec/ah_var.h>
                     53: #include <netipsec/esp_var.h>
                     54: #include <netipsec/ipcomp_var.h>
                     55:
                     56: #include <netipsec/xform.h>
                     57:
                     58: #include <netipsec/key.h>
                     59: #include <netipsec/keydb.h>
                     60: #include <netipsec/key_debug.h>
                     61: #include <netipsec/ipsec_osdep.h>
                     62:
                     63: int
                     64: ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
                     65: {
                     66:        struct tdb_ident *tdbi;
                     67:        struct m_tag *mtag;
                     68:        struct secasvar *sav;
                     69:        struct secasindex *saidx;
                     70:        int error;
                     71:
                     72:        IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
                     73:
                     74:        IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
                     75:        IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
                     76:        sav = isr->sav;
                     77:        IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
                     78:        IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
                     79:
                     80:        saidx = &sav->sah->saidx;
                     81:        switch (saidx->dst.sa.sa_family) {
                     82: #ifdef INET
                     83:        case AF_INET:
                     84:                /* Fix the header length, for AH processing. */
                     85:                mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
                     86:                break;
                     87: #endif /* INET */
                     88: #ifdef INET6
                     89:        case AF_INET6:
                     90:                /* Fix the header length, for AH processing. */
                     91:                if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
                     92:                        error = ENXIO;
                     93:                        goto bad;
                     94:                }
                     95:                if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
                     96:                        /* No jumbogram support. */
                     97:                        error = ENXIO;  /*?*/
                     98:                        goto bad;
                     99:                }
                    100:                mtod(m, struct ip6_hdr *)->ip6_plen =
                    101:                        htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
                    102:                break;
                    103: #endif /* INET6 */
                    104:        default:
                    105:                DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
                    106:                    saidx->dst.sa.sa_family));
                    107:                error = ENXIO;
                    108:                goto bad;
                    109:        }
                    110:
                    111:        /*
                    112:         * Add a record of what we've done or what needs to be done to the
                    113:         * packet.
                    114:         */
                    115:        mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
                    116:                        sizeof(struct tdb_ident), M_NOWAIT);
                    117:        if (mtag == NULL) {
                    118:                DPRINTF(("ipsec_process_done: could not get packet tag\n"));
                    119:                error = ENOMEM;
                    120:                goto bad;
                    121:        }
                    122:
                    123:        tdbi = (struct tdb_ident *)(mtag + 1);
                    124:        tdbi->dst = saidx->dst;
                    125:        tdbi->proto = saidx->proto;
                    126:        tdbi->spi = sav->spi;
                    127:        m_tag_prepend(m, mtag);
                    128:
                    129:        /*
                    130:         * If there's another (bundled) SA to apply, do so.
                    131:         * Note that this puts a burden on the kernel stack size.
                    132:         * If this is a problem we'll need to introduce a queue
                    133:         * to set the packet on so we can unwind the stack before
                    134:         * doing further processing.
                    135:         */
                    136:        if (isr->next) {
                    137:                newipsecstat.ips_out_bundlesa++;
                    138:                return ipsec4_process_packet(m, isr->next, 0, 0);
                    139:        }
                    140:
                    141:        /*
                    142:         * We're done with IPsec processing, transmit the packet using the
                    143:         * appropriate network protocol (IP or IPv6). SPD lookup will be
                    144:         * performed again there.
                    145:         */
                    146:        switch (saidx->dst.sa.sa_family) {
                    147: #ifdef INET
                    148:        struct ip *ip;
                    149:        case AF_INET:
                    150:                ip = mtod(m, struct ip *);
                    151: #ifdef __FreeBSD__
                    152:                /* FreeBSD ip_output() expects ip_len, ip_off in host endian */
                    153:                ip->ip_len = ntohs(ip->ip_len);
                    154:                ip->ip_off = ntohs(ip->ip_off);
                    155: #endif /* __FreeBSD_ */
1.2       jonathan  156:                return ip_output(m, NULL, NULL, IP_RAWOUTPUT,
1.5     ! itojun    157:                    (struct ip_moptions *)NULL, (struct socket *)NULL);
1.2       jonathan  158:
1.1       jonathan  159: #endif /* INET */
                    160: #ifdef INET6
                    161:        case AF_INET6:
                    162:                /*
                    163:                 * We don't need massage, IPv6 header fields are always in
                    164:                 * net endian.
                    165:                 */
                    166:                return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
                    167: #endif /* INET6 */
                    168:        }
                    169:        panic("ipsec_process_done");
                    170: bad:
                    171:        m_freem(m);
                    172:        KEY_FREESAV(&sav);
                    173:        return (error);
                    174: }
                    175:
                    176: static struct ipsecrequest *
                    177: ipsec_nextisr(
                    178:        struct mbuf *m,
                    179:        struct ipsecrequest *isr,
                    180:        int af,
                    181:        struct secasindex *saidx,
                    182:        int *error
                    183: )
                    184: {
                    185: #define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \
                    186:                            isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++)
                    187:        struct secasvar *sav;
                    188:
                    189:        IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
                    190:        IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
                    191:                ("ipsec_nextisr: invalid address family %u", af));
                    192: again:
                    193:        /*
                    194:         * Craft SA index to search for proper SA.  Note that
                    195:         * we only fillin unspecified SA peers for transport
                    196:         * mode; for tunnel mode they must already be filled in.
                    197:         */
                    198:        *saidx = isr->saidx;
                    199:        if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
                    200:                /* Fillin unspecified SA peers only for transport mode */
                    201:                if (af == AF_INET) {
                    202:                        struct sockaddr_in *sin;
                    203:                        struct ip *ip = mtod(m, struct ip *);
                    204:
                    205:                        if (saidx->src.sa.sa_len == 0) {
                    206:                                sin = &saidx->src.sin;
                    207:                                sin->sin_len = sizeof(*sin);
                    208:                                sin->sin_family = AF_INET;
                    209:                                sin->sin_port = IPSEC_PORT_ANY;
                    210:                                sin->sin_addr = ip->ip_src;
                    211:                        }
                    212:                        if (saidx->dst.sa.sa_len == 0) {
                    213:                                sin = &saidx->dst.sin;
                    214:                                sin->sin_len = sizeof(*sin);
                    215:                                sin->sin_family = AF_INET;
                    216:                                sin->sin_port = IPSEC_PORT_ANY;
                    217:                                sin->sin_addr = ip->ip_dst;
                    218:                        }
                    219:                } else {
                    220:                        struct sockaddr_in6 *sin6;
                    221:                        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
                    222:
                    223:                        if (saidx->src.sin6.sin6_len == 0) {
                    224:                                sin6 = (struct sockaddr_in6 *)&saidx->src;
                    225:                                sin6->sin6_len = sizeof(*sin6);
                    226:                                sin6->sin6_family = AF_INET6;
                    227:                                sin6->sin6_port = IPSEC_PORT_ANY;
                    228:                                sin6->sin6_addr = ip6->ip6_src;
                    229:                                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
                    230:                                        /* fix scope id for comparing SPD */
                    231:                                        sin6->sin6_addr.s6_addr16[1] = 0;
                    232:                                        sin6->sin6_scope_id =
                    233:                                            ntohs(ip6->ip6_src.s6_addr16[1]);
                    234:                                }
                    235:                        }
                    236:                        if (saidx->dst.sin6.sin6_len == 0) {
                    237:                                sin6 = (struct sockaddr_in6 *)&saidx->dst;
                    238:                                sin6->sin6_len = sizeof(*sin6);
                    239:                                sin6->sin6_family = AF_INET6;
                    240:                                sin6->sin6_port = IPSEC_PORT_ANY;
                    241:                                sin6->sin6_addr = ip6->ip6_dst;
                    242:                                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
                    243:                                        /* fix scope id for comparing SPD */
                    244:                                        sin6->sin6_addr.s6_addr16[1] = 0;
                    245:                                        sin6->sin6_scope_id =
                    246:                                            ntohs(ip6->ip6_dst.s6_addr16[1]);
                    247:                                }
                    248:                        }
                    249:                }
                    250:        }
                    251:
                    252:        /*
                    253:         * Lookup SA and validate it.
                    254:         */
                    255:        *error = key_checkrequest(isr, saidx);
                    256:        if (*error != 0) {
                    257:                /*
                    258:                 * IPsec processing is required, but no SA found.
                    259:                 * I assume that key_acquire() had been called
                    260:                 * to get/establish the SA. Here I discard
                    261:                 * this packet because it is responsibility for
                    262:                 * upper layer to retransmit the packet.
                    263:                 */
                    264:                newipsecstat.ips_out_nosa++;
                    265:                goto bad;
                    266:        }
                    267:        sav = isr->sav;
                    268:        if (sav == NULL) {              /* XXX valid return */
                    269:                IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
                    270:                        ("ipsec_nextisr: no SA found, but required; level %u",
                    271:                        ipsec_get_reqlevel(isr)));
                    272:                isr = isr->next;
                    273:                if (isr == NULL) {
                    274:                        /*XXXstatistic??*/
                    275:                        *error = EINVAL;                /*XXX*/
                    276:                        return isr;
                    277:                }
                    278:                goto again;
                    279:        }
                    280:
                    281:        /*
                    282:         * Check system global policy controls.
                    283:         */
                    284:        if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
                    285:            (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
                    286:            (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
                    287:                DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
                    288:                        " to policy (check your sysctls)\n"));
                    289:                IPSEC_OSTAT(espstat.esps_pdrops, ahstat.ahs_pdrops,
                    290:                    ipcompstat.ipcomps_pdrops);
                    291:                *error = EHOSTUNREACH;
                    292:                goto bad;
                    293:        }
                    294:
                    295:        /*
                    296:         * Sanity check the SA contents for the caller
                    297:         * before they invoke the xform output method.
                    298:         */
                    299:        if (sav->tdb_xform == NULL) {
                    300:                DPRINTF(("ipsec_nextisr: no transform for SA\n"));
                    301:                IPSEC_OSTAT(espstat.esps_noxform, ahstat.ahs_noxform,
                    302:                    ipcompstat.ipcomps_noxform);
                    303:                *error = EHOSTUNREACH;
                    304:                goto bad;
                    305:        }
                    306:        return isr;
                    307: bad:
                    308:        IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
                    309:        return NULL;
                    310: #undef IPSEC_OSTAT
                    311: }
                    312:
                    313: #ifdef INET
                    314: /*
                    315:  * IPsec output logic for IPv4.
                    316:  */
                    317: int
                    318: ipsec4_process_packet(
                    319:        struct mbuf *m,
                    320:        struct ipsecrequest *isr,
                    321:        int flags,
                    322:        int tunalready)
                    323: {
                    324:        struct secasindex saidx;
                    325:        struct secasvar *sav;
                    326:        struct ip *ip;
                    327:        int s, error, i, off;
                    328:
                    329:        IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
                    330:        IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
                    331:
                    332:        s = splsoftnet();                       /* insure SA contents don't change */
                    333:
                    334:        isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
                    335:        if (isr == NULL)
                    336:                goto bad;
                    337:
                    338:        sav = isr->sav;
                    339:        if (!tunalready) {
                    340:                union sockaddr_union *dst = &sav->sah->saidx.dst;
                    341:                int setdf;
                    342:
                    343:                /*
                    344:                 * Collect IP_DF state from the outer header.
                    345:                 */
                    346:                if (dst->sa.sa_family == AF_INET) {
                    347:                        if (m->m_len < sizeof (struct ip) &&
                    348:                            (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    349:                                error = ENOBUFS;
                    350:                                goto bad;
                    351:                        }
                    352:                        ip = mtod(m, struct ip *);
                    353:                        /* Honor system-wide control of how to handle IP_DF */
                    354:                        switch (ip4_ipsec_dfbit) {
                    355:                        case 0:                 /* clear in outer header */
                    356:                        case 1:                 /* set in outer header */
                    357:                                setdf = ip4_ipsec_dfbit;
                    358:                                break;
                    359:                        default:                /* propagate to outer header */
1.3       jonathan  360:                                setdf = ip->ip_off;
                    361: #ifndef __FreeBSD__
                    362:                /* On FreeBSD, ip_off and ip_len assumed in host endian. */
                    363:                                setdf = ntohs(setdf);
                    364: #endif
                    365:                                setdf = htons(setdf & IP_DF);
1.1       jonathan  366:                                break;
                    367:                        }
                    368:                } else {
                    369:                        ip = NULL;              /* keep compiler happy */
                    370:                        setdf = 0;
                    371:                }
                    372:                /* Do the appropriate encapsulation, if necessary */
                    373:                if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
                    374:                    dst->sa.sa_family != AF_INET ||         /* PF mismatch */
                    375: #if 0
                    376:                    (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
                    377:                    sav->tdb_xform->xf_type == XF_IP4 ||    /* ditto */
                    378: #endif
                    379:                    (dst->sa.sa_family == AF_INET &&        /* Proxy */
                    380:                     dst->sin.sin_addr.s_addr != INADDR_ANY &&
                    381:                     dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
                    382:                        struct mbuf *mp;
                    383:
                    384:                        /* Fix IPv4 header checksum and length */
                    385:                        if (m->m_len < sizeof (struct ip) &&
                    386:                            (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    387:                                error = ENOBUFS;
                    388:                                goto bad;
                    389:                        }
                    390:                        ip = mtod(m, struct ip *);
                    391:                        ip->ip_len = htons(m->m_pkthdr.len);
                    392:                        ip->ip_sum = 0;
                    393: #ifdef _IP_VHL
                    394:                        if (ip->ip_vhl == IP_VHL_BORING)
                    395:                                ip->ip_sum = in_cksum_hdr(ip);
                    396:                        else
                    397:                                ip->ip_sum = in_cksum(m,
                    398:                                        _IP_VHL_HL(ip->ip_vhl) << 2);
                    399: #else
                    400:                        ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
                    401: #endif
                    402:
                    403:                        /* Encapsulate the packet */
                    404:                        error = ipip_output(m, isr, &mp, 0, 0);
                    405:                        if (mp == NULL && !error) {
                    406:                                /* Should never happen. */
                    407:                                DPRINTF(("ipsec4_process_packet: ipip_output "
                    408:                                        "returns no mbuf and no error!"));
                    409:                                error = EFAULT;
                    410:                        }
                    411:                        if (error) {
                    412:                                if (mp)
                    413:                                        m_freem(mp);
                    414:                                goto bad;
                    415:                        }
                    416:                        m = mp, mp = NULL;
                    417:                        /*
                    418:                         * ipip_output clears IP_DF in the new header.  If
                    419:                         * we need to propagate IP_DF from the outer header,
                    420:                         * then we have to do it here.
                    421:                         *
                    422:                         * XXX shouldn't assume what ipip_output does.
                    423:                         */
                    424:                        if (dst->sa.sa_family == AF_INET && setdf) {
                    425:                                if (m->m_len < sizeof (struct ip) &&
                    426:                                    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    427:                                        error = ENOBUFS;
                    428:                                        goto bad;
                    429:                                }
                    430:                                ip = mtod(m, struct ip *);
                    431:                                ip->ip_off = ntohs(ip->ip_off);
                    432:                                ip->ip_off |= IP_DF;
                    433:                                ip->ip_off = htons(ip->ip_off);
                    434:                        }
                    435:                }
                    436:        }
                    437:
                    438:        /*
                    439:         * Dispatch to the appropriate IPsec transform logic.  The
                    440:         * packet will be returned for transmission after crypto
                    441:         * processing, etc. are completed.  For encapsulation we
                    442:         * bypass this call because of the explicit call done above
                    443:         * (necessary to deal with IP_DF handling for IPv4).
                    444:         *
                    445:         * NB: m & sav are ``passed to caller'' who's reponsible for
                    446:         *     for reclaiming their resources.
                    447:         */
                    448:        if (sav->tdb_xform->xf_type != XF_IP4) {
                    449:                ip = mtod(m, struct ip *);
                    450:                i = ip->ip_hl << 2;
                    451:                off = offsetof(struct ip, ip_p);
                    452:                error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
                    453:        } else {
                    454:                error = ipsec_process_done(m, isr);
                    455:        }
                    456:        splx(s);
                    457:        return error;
                    458: bad:
                    459:        splx(s);
                    460:        if (m)
                    461:                m_freem(m);
                    462:        return error;
                    463: }
                    464: #endif
                    465:
                    466: #ifdef INET6
                    467: /*
                    468:  * Chop IP6 header from the payload.
                    469:  */
                    470: static struct mbuf *
                    471: ipsec6_splithdr(struct mbuf *m)
                    472: {
                    473:        struct mbuf *mh;
                    474:        struct ip6_hdr *ip6;
                    475:        int hlen;
                    476:
                    477:        IPSEC_ASSERT(m->m_len >= sizeof (struct ip6_hdr),
                    478:                ("ipsec6_splithdr: first mbuf too short, len %u", m->m_len));
                    479:        ip6 = mtod(m, struct ip6_hdr *);
                    480:        hlen = sizeof(struct ip6_hdr);
                    481:        if (m->m_len > hlen) {
                    482:                MGETHDR(mh, M_DONTWAIT, MT_HEADER);
                    483:                if (!mh) {
                    484:                        m_freem(m);
                    485:                        return NULL;
                    486:                }
                    487:                M_MOVE_PKTHDR(mh, m);
                    488:                MH_ALIGN(mh, hlen);
                    489:                m->m_len -= hlen;
                    490:                m->m_data += hlen;
                    491:                mh->m_next = m;
                    492:                m = mh;
                    493:                m->m_len = hlen;
                    494:                bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen);
                    495:        } else if (m->m_len < hlen) {
                    496:                m = m_pullup(m, hlen);
                    497:                if (!m)
                    498:                        return NULL;
                    499:        }
                    500:        return m;
                    501: }
                    502:
                    503: /*
                    504:  * IPsec output logic for IPv6, transport mode.
                    505:  */
                    506: int
                    507: ipsec6_output_trans(
                    508:        struct ipsec_output_state *state,
                    509:        u_char *nexthdrp,
                    510:        struct mbuf *mprev,
                    511:        struct secpolicy *sp,
                    512:        int flags,
                    513:        int *tun)
                    514: {
                    515:        struct ipsecrequest *isr;
                    516:        struct secasindex saidx;
                    517:        int error = 0;
                    518:        struct mbuf *m;
                    519:
                    520:        IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state"));
                    521:        IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m"));
                    522:        IPSEC_ASSERT(nexthdrp != NULL, ("ipsec6_output: null nexthdrp"));
                    523:        IPSEC_ASSERT(mprev != NULL, ("ipsec6_output: null mprev"));
                    524:        IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp"));
                    525:        IPSEC_ASSERT(tun != NULL, ("ipsec6_output: null tun"));
                    526:
                    527:        KEYDEBUG(KEYDEBUG_IPSEC_DATA,
                    528:                printf("ipsec6_output_trans: applyed SP\n");
                    529:                kdebug_secpolicy(sp));
                    530:
                    531:        isr = sp->req;
                    532:        if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
                    533:                /* the rest will be handled by ipsec6_output_tunnel() */
                    534:                *tun = 1;               /* need tunnel-mode processing */
                    535:                return 0;
                    536:        }
                    537:
                    538:        *tun = 0;
                    539:        m = state->m;
                    540:
                    541:        isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
                    542:        if (isr == NULL) {
                    543: #ifdef notdef
                    544:                /* XXX should notification be done for all errors ? */
                    545:                /*
                    546:                 * Notify the fact that the packet is discarded
                    547:                 * to ourselves. I believe this is better than
                    548:                 * just silently discarding. (jinmei@kame.net)
                    549:                 * XXX: should we restrict the error to TCP packets?
                    550:                 * XXX: should we directly notify sockets via
                    551:                 *      pfctlinputs?
                    552:                 */
                    553:                icmp6_error(m, ICMP6_DST_UNREACH,
                    554:                            ICMP6_DST_UNREACH_ADMIN, 0);
                    555:                m = NULL;       /* NB: icmp6_error frees mbuf */
                    556: #endif
                    557:                goto bad;
                    558:        }
                    559:
                    560:        return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
                    561:                sizeof (struct ip6_hdr),
                    562:                offsetof(struct ip6_hdr, ip6_nxt));
                    563: bad:
                    564:        if (m)
                    565:                m_freem(m);
                    566:        state->m = NULL;
                    567:        return error;
                    568: }
                    569:
                    570: static int
                    571: ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav)
                    572: {
                    573:        struct ip6_hdr *oip6;
                    574:        struct ip6_hdr *ip6;
                    575:        size_t plen;
                    576:
                    577:        /* can't tunnel between different AFs */
                    578:        if (sav->sah->saidx.src.sa.sa_family != AF_INET6 ||
                    579:            sav->sah->saidx.dst.sa.sa_family != AF_INET6) {
                    580:                m_freem(m);
                    581:                return EINVAL;
                    582:        }
                    583:        IPSEC_ASSERT(m->m_len != sizeof (struct ip6_hdr),
                    584:                ("ipsec6_encapsulate: mbuf wrong size; len %u", m->m_len));
                    585:
                    586:
                    587:        /*
                    588:         * grow the mbuf to accomodate the new IPv6 header.
                    589:         */
                    590:        plen = m->m_pkthdr.len;
                    591:        if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) {
                    592:                struct mbuf *n;
                    593:                MGET(n, M_DONTWAIT, MT_DATA);
                    594:                if (!n) {
                    595:                        m_freem(m);
                    596:                        return ENOBUFS;
                    597:                }
                    598:                n->m_len = sizeof(struct ip6_hdr);
                    599:                n->m_next = m->m_next;
                    600:                m->m_next = n;
                    601:                m->m_pkthdr.len += sizeof(struct ip6_hdr);
                    602:                oip6 = mtod(n, struct ip6_hdr *);
                    603:        } else {
                    604:                m->m_next->m_len += sizeof(struct ip6_hdr);
                    605:                m->m_next->m_data -= sizeof(struct ip6_hdr);
                    606:                m->m_pkthdr.len += sizeof(struct ip6_hdr);
                    607:                oip6 = mtod(m->m_next, struct ip6_hdr *);
                    608:        }
                    609:        ip6 = mtod(m, struct ip6_hdr *);
                    610:        ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr));
                    611:
                    612:        /* Fake link-local scope-class addresses */
                    613:        if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
                    614:                oip6->ip6_src.s6_addr16[1] = 0;
                    615:        if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
                    616:                oip6->ip6_dst.s6_addr16[1] = 0;
                    617:
                    618:        /* construct new IPv6 header. see RFC 2401 5.1.2.2 */
                    619:        /* ECN consideration. */
                    620:        ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow);
                    621:        if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr))
                    622:                ip6->ip6_plen = htons(plen);
                    623:        else {
                    624:                /* ip6->ip6_plen will be updated in ip6_output() */
                    625:        }
                    626:        ip6->ip6_nxt = IPPROTO_IPV6;
                    627:        sav->sah->saidx.src.sin6.sin6_addr = ip6->ip6_src;
                    628:        sav->sah->saidx.dst.sin6.sin6_addr = ip6->ip6_dst;
                    629:        ip6->ip6_hlim = IPV6_DEFHLIM;
                    630:
                    631:        /* XXX Should ip6_src be updated later ? */
                    632:
                    633:        return 0;
                    634: }
                    635:
                    636: /*
                    637:  * IPsec output logic for IPv6, tunnel mode.
                    638:  */
                    639: int
                    640: ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int flags)
                    641: {
                    642:        struct ip6_hdr *ip6;
                    643:        struct ipsecrequest *isr;
                    644:        struct secasindex saidx;
                    645:        int error;
                    646:        struct sockaddr_in6* dst6;
                    647:        struct mbuf *m;
                    648:
                    649:        IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state"));
                    650:        IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m"));
                    651:        IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp"));
                    652:
                    653:        KEYDEBUG(KEYDEBUG_IPSEC_DATA,
                    654:                printf("ipsec6_output_tunnel: applyed SP\n");
                    655:                kdebug_secpolicy(sp));
                    656:
                    657:        m = state->m;
                    658:        /*
                    659:         * transport mode ipsec (before the 1st tunnel mode) is already
                    660:         * processed by ipsec6_output_trans().
                    661:         */
                    662:        for (isr = sp->req; isr; isr = isr->next) {
                    663:                if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
                    664:                        break;
                    665:        }
                    666:        isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
                    667:        if (isr == NULL)
                    668:                goto bad;
                    669:
                    670:        /*
                    671:         * There may be the case that SA status will be changed when
                    672:         * we are refering to one. So calling splsoftnet().
                    673:         */
                    674:        if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
                    675:                /*
                    676:                 * build IPsec tunnel.
                    677:                 */
                    678:                /* XXX should be processed with other familiy */
                    679:                if (isr->sav->sah->saidx.src.sa.sa_family != AF_INET6) {
                    680:                        ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
                    681:                            "family mismatched between inner and outer, spi=%lu\n",
                    682:                            ntohl(isr->sav->spi)));
                    683:                        newipsecstat.ips_out_inval++;
                    684:                        error = EAFNOSUPPORT;
                    685:                        goto bad;
                    686:                }
                    687:
                    688:                m = ipsec6_splithdr(m);
                    689:                if (!m) {
                    690:                        newipsecstat.ips_out_nomem++;
                    691:                        error = ENOMEM;
                    692:                        goto bad;
                    693:                }
                    694:                error = ipsec6_encapsulate(m, isr->sav);
                    695:                if (error) {
                    696:                        m = NULL;
                    697:                        goto bad;
                    698:                }
                    699:                ip6 = mtod(m, struct ip6_hdr *);
                    700:
                    701:                state->ro = &isr->sav->sah->sa_route;
                    702:                state->dst = (struct sockaddr *)&state->ro->ro_dst;
                    703:                dst6 = (struct sockaddr_in6 *)state->dst;
                    704:                if (state->ro->ro_rt
                    705:                 && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0
                    706:                  || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) {
                    707:                        RTFREE(state->ro->ro_rt);
                    708:                        state->ro->ro_rt = NULL;
                    709:                }
                    710:                if (state->ro->ro_rt == 0) {
                    711:                        bzero(dst6, sizeof(*dst6));
                    712:                        dst6->sin6_family = AF_INET6;
                    713:                        dst6->sin6_len = sizeof(*dst6);
                    714:                        dst6->sin6_addr = ip6->ip6_dst;
                    715:                        rtalloc(state->ro);
                    716:                }
                    717:                if (state->ro->ro_rt == 0) {
                    718:                        ip6stat.ip6s_noroute++;
                    719:                        newipsecstat.ips_out_noroute++;
                    720:                        error = EHOSTUNREACH;
                    721:                        goto bad;
                    722:                }
                    723:
                    724:                /* adjust state->dst if tunnel endpoint is offlink */
                    725:                if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
                    726:                        state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
                    727:                        dst6 = (struct sockaddr_in6 *)state->dst;
                    728:                }
                    729:        }
                    730:
                    731:        m = ipsec6_splithdr(m);
                    732:        if (!m) {
                    733:                newipsecstat.ips_out_nomem++;
                    734:                error = ENOMEM;
                    735:                goto bad;
                    736:        }
                    737:        ip6 = mtod(m, struct ip6_hdr *);
                    738:        return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
                    739:                sizeof (struct ip6_hdr),
                    740:                offsetof(struct ip6_hdr, ip6_nxt));
                    741: bad:
                    742:        if (m)
                    743:                m_freem(m);
                    744:        state->m = NULL;
                    745:        return error;
                    746: }
                    747: #endif /*INET6*/

CVSweb <webmaster@jp.NetBSD.org>