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

1.58    ! ozaki-r     1: /*     $NetBSD: ipsec_output.c,v 1.57 2017/07/27 06:59:28 ozaki-r Exp $        */
1.9       thorpej     2:
                      3: /*-
                      4:  * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  *
                     28:  * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $
                     29:  */
1.1       jonathan   30:
                     31: #include <sys/cdefs.h>
1.58    ! ozaki-r    32: __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.57 2017/07/27 06:59:28 ozaki-r Exp $");
1.1       jonathan   33:
                     34: /*
                     35:  * IPsec output processing.
                     36:  */
1.42      ozaki-r    37: #if defined(_KERNEL_OPT)
1.1       jonathan   38: #include "opt_inet.h"
1.57      ozaki-r    39: #include "opt_net_mpsafe.h"
1.42      ozaki-r    40: #endif
1.1       jonathan   41:
                     42: #include <sys/param.h>
                     43: #include <sys/systm.h>
                     44: #include <sys/mbuf.h>
                     45: #include <sys/domain.h>
                     46: #include <sys/protosw.h>
                     47: #include <sys/socket.h>
                     48: #include <sys/errno.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_systm.h>
                     56: #include <netinet/ip.h>
                     57: #include <netinet/ip_var.h>
                     58: #include <netinet/in_var.h>
                     59: #include <netinet/ip_ecn.h>
                     60:
                     61: #include <netinet/ip6.h>
                     62: #ifdef INET6
                     63: #include <netinet6/ip6_var.h>
                     64: #endif
                     65: #include <netinet/in_pcb.h>
                     66: #ifdef INET6
                     67: #include <netinet/icmp6.h>
                     68: #endif
1.22      degroote   69: #include <netinet/udp.h>
1.1       jonathan   70:
                     71: #include <netipsec/ipsec.h>
1.13      jonathan   72: #include <netipsec/ipsec_var.h>
1.27      thorpej    73: #include <netipsec/ipsec_private.h>
1.1       jonathan   74: #ifdef INET6
                     75: #include <netipsec/ipsec6.h>
                     76: #endif
                     77: #include <netipsec/ah_var.h>
                     78: #include <netipsec/esp_var.h>
                     79: #include <netipsec/ipcomp_var.h>
                     80:
                     81: #include <netipsec/xform.h>
                     82:
1.7       tls        83: #include <netipsec/key.h>
                     84: #include <netipsec/keydb.h>
                     85: #include <netipsec/key_debug.h>
1.1       jonathan   86:
1.10      jonathan   87: #include <net/net_osdep.h>             /* ovbcopy() in ipsec6_encapsulate() */
                     88:
1.25      degroote   89:
                     90: /*
                     91:  * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing
                     92:  * It will be used by ip{,6}_output to check if we have already or not
                     93:  * processed this packet.
                     94:  */
                     95: static int
                     96: ipsec_register_done(struct mbuf *m, int * error)
                     97: {
                     98:        struct m_tag *mtag;
                     99:
                    100:        mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT);
                    101:        if (mtag == NULL) {
1.48      ozaki-r   102:                IPSECLOG(LOG_DEBUG, "could not get packet tag\n");
1.25      degroote  103:                *error = ENOMEM;
                    104:                return -1;
                    105:        }
                    106:
                    107:        m_tag_prepend(m, mtag);
                    108:        return 0;
                    109: }
                    110:
1.26      degroote  111: static int
                    112: ipsec_reinject_ipstack(struct mbuf *m, int af)
                    113: {
1.30      drochner  114: #if defined(INET) || defined(INET6)
                    115:        int rv;
                    116: #endif
1.26      degroote  117:
                    118:        switch (af) {
                    119: #ifdef INET
                    120:        case AF_INET:
1.57      ozaki-r   121: #ifndef NET_MPSAFE
1.30      drochner  122:                KERNEL_LOCK(1, NULL);
1.57      ozaki-r   123: #endif
1.31      drochner  124:                rv = ip_output(m, NULL, NULL, IP_RAWOUTPUT|IP_NOIPNEWID,
1.37      plunky    125:                    NULL, NULL);
1.57      ozaki-r   126: #ifndef NET_MPSAFE
1.30      drochner  127:                KERNEL_UNLOCK_ONE(NULL);
1.57      ozaki-r   128: #endif
1.30      drochner  129:                return rv;
1.26      degroote  130:
                    131: #endif /* INET */
                    132: #ifdef INET6
                    133:        case AF_INET6:
                    134:                /*
                    135:                 * We don't need massage, IPv6 header fields are always in
                    136:                 * net endian.
                    137:                 */
1.57      ozaki-r   138: #ifndef NET_MPSAFE
1.30      drochner  139:                KERNEL_LOCK(1, NULL);
1.57      ozaki-r   140: #endif
1.30      drochner  141:                rv = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1.57      ozaki-r   142: #ifndef NET_MPSAFE
1.30      drochner  143:                KERNEL_UNLOCK_ONE(NULL);
1.57      ozaki-r   144: #endif
1.30      drochner  145:                return rv;
1.26      degroote  146: #endif /* INET6 */
                    147:        }
                    148:
                    149:        panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af);
                    150:        return -1; /* NOTREACHED */
                    151: }
                    152:
1.1       jonathan  153: int
1.54      ozaki-r   154: ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr,
                    155:     struct secasvar *sav)
1.1       jonathan  156: {
                    157:        struct secasindex *saidx;
                    158:        int error;
1.22      degroote  159: #ifdef INET
                    160:        struct ip * ip;
                    161: #endif /* INET */
                    162: #ifdef INET6
                    163:        struct ip6_hdr * ip6;
                    164: #endif /* INET6 */
                    165:        struct mbuf * mo;
                    166:        struct udphdr *udp = NULL;
                    167:        uint64_t * data = NULL;
                    168:        int hlen, roff;
1.1       jonathan  169:
                    170:        IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
                    171:
1.44      ozaki-r   172:        KASSERT(m != NULL);
                    173:        KASSERT(isr != NULL);
                    174:        KASSERT(sav != NULL);
1.1       jonathan  175:
                    176:        saidx = &sav->sah->saidx;
1.22      degroote  177:
                    178:        if(sav->natt_type != 0) {
                    179:                ip = mtod(m, struct ip *);
                    180:
                    181:                hlen = sizeof(struct udphdr);
                    182:                if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
                    183:                        hlen += sizeof(uint64_t);
                    184:
                    185:                mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
                    186:                if (mo == NULL) {
1.47      ryo       187:                        char buf[IPSEC_ADDRSTRLEN];
1.48      ozaki-r   188:                        IPSECLOG(LOG_DEBUG,
                    189:                            "failed to inject %u byte UDP for SA %s/%08lx\n",
1.47      ryo       190:                            hlen, ipsec_address(&saidx->dst, buf, sizeof(buf)),
1.48      ozaki-r   191:                            (u_long) ntohl(sav->spi));
1.22      degroote  192:                        error = ENOBUFS;
                    193:                        goto bad;
                    194:                }
                    195:
                    196:                udp = (struct udphdr*) (mtod(mo, char*) + roff);
                    197:                data = (uint64_t*) (udp + 1);
                    198:
                    199:                if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
                    200:                        *data = 0; /* NON-IKE Marker */
                    201:
                    202:                if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
                    203:                        udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
                    204:                else
                    205:                        udp->uh_sport = key_portfromsaddr(&saidx->src);
                    206:
                    207:                udp->uh_dport = key_portfromsaddr(&saidx->dst);
                    208:                udp->uh_sum = 0;
1.29      dyoung    209:                udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
1.22      degroote  210:        }
                    211:
1.1       jonathan  212:        switch (saidx->dst.sa.sa_family) {
                    213: #ifdef INET
                    214:        case AF_INET:
                    215:                /* Fix the header length, for AH processing. */
1.22      degroote  216:                ip = mtod(m, struct ip *);
                    217:                ip->ip_len = htons(m->m_pkthdr.len);
                    218:                if (sav->natt_type != 0)
                    219:                        ip->ip_p = IPPROTO_UDP;
1.1       jonathan  220:                break;
                    221: #endif /* INET */
                    222: #ifdef INET6
                    223:        case AF_INET6:
                    224:                /* Fix the header length, for AH processing. */
                    225:                if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
                    226:                        error = ENXIO;
                    227:                        goto bad;
                    228:                }
                    229:                if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
                    230:                        /* No jumbogram support. */
                    231:                        error = ENXIO;  /*?*/
                    232:                        goto bad;
                    233:                }
1.22      degroote  234:                ip6 = mtod(m, struct ip6_hdr *);
                    235:                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
                    236:                if (sav->natt_type != 0)
                    237:                        ip6->ip6_nxt = IPPROTO_UDP;
1.1       jonathan  238:                break;
                    239: #endif /* INET6 */
                    240:        default:
1.48      ozaki-r   241:                IPSECLOG(LOG_DEBUG, "unknown protocol family %u\n",
                    242:                    saidx->dst.sa.sa_family);
1.1       jonathan  243:                error = ENXIO;
                    244:                goto bad;
                    245:        }
                    246:
1.32      drochner  247:        key_sa_recordxfer(sav, m);
                    248:
1.1       jonathan  249:        /*
                    250:         * If there's another (bundled) SA to apply, do so.
                    251:         * Note that this puts a burden on the kernel stack size.
                    252:         * If this is a problem we'll need to introduce a queue
                    253:         * to set the packet on so we can unwind the stack before
                    254:         * doing further processing.
                    255:         */
                    256:        if (isr->next) {
1.27      thorpej   257:                IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA);
1.29      dyoung    258:                switch ( saidx->dst.sa.sa_family ) {
1.21      degroote  259: #ifdef INET
1.29      dyoung    260:                case AF_INET:
1.56      ozaki-r   261:                        return ipsec4_process_packet(m, isr->next, NULL);
1.21      degroote  262: #endif /* INET */
                    263: #ifdef INET6
                    264:                case AF_INET6:
1.29      dyoung    265:                        return ipsec6_process_packet(m,isr->next);
1.21      degroote  266: #endif /* INET6 */
                    267:                default :
1.48      ozaki-r   268:                        IPSECLOG(LOG_DEBUG, "unknown protocol family %u\n",
                    269:                            saidx->dst.sa.sa_family);
1.21      degroote  270:                        error = ENXIO;
                    271:                        goto bad;
1.29      dyoung    272:                }
1.1       jonathan  273:        }
                    274:
                    275:        /*
1.25      degroote  276:         * We're done with IPsec processing,
                    277:         * mark that we have already processed the packet
                    278:         * transmit it packet using the appropriate network protocol (IP or IPv6).
1.1       jonathan  279:         */
1.25      degroote  280:
                    281:        if (ipsec_register_done(m, &error) < 0)
                    282:                goto bad;
                    283:
1.26      degroote  284:        return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family);
1.1       jonathan  285: bad:
                    286:        m_freem(m);
                    287:        return (error);
                    288: }
                    289:
1.26      degroote  290: /*
                    291:  * ipsec_nextisr can return :
                    292:  * - isr == NULL and error != 0 => something is bad : the packet must be
                    293:  *   discarded
                    294:  * - isr == NULL and error == 0 => no more rules to apply, ipsec processing
                    295:  *   is done, reinject it in ip stack
                    296:  * - isr != NULL (error == 0) => we need to apply one rule to the packet
                    297:  */
1.1       jonathan  298: static struct ipsecrequest *
                    299: ipsec_nextisr(
                    300:        struct mbuf *m,
                    301:        struct ipsecrequest *isr,
                    302:        int af,
1.54      ozaki-r   303:        int *error,
                    304:        struct secasvar **ret
1.1       jonathan  305: )
                    306: {
1.49      ozaki-r   307: #define        IPSEC_OSTAT(type)                                               \
1.27      thorpej   308: do {                                                                   \
                    309:        switch (isr->saidx.proto) {                                     \
                    310:        case IPPROTO_ESP:                                               \
1.49      ozaki-r   311:                ESP_STATINC(ESP_STAT_ ## type);                         \
1.27      thorpej   312:                break;                                                  \
                    313:        case IPPROTO_AH:                                                \
1.49      ozaki-r   314:                AH_STATINC(AH_STAT_ ## type);                           \
1.27      thorpej   315:                break;                                                  \
                    316:        default:                                                        \
1.49      ozaki-r   317:                IPCOMP_STATINC(IPCOMP_STAT_ ## type);                   \
1.27      thorpej   318:                break;                                                  \
                    319:        }                                                               \
                    320: } while (/*CONSTCOND*/0)
                    321:
1.54      ozaki-r   322:        struct secasvar *sav = NULL;
1.52      ozaki-r   323:        struct secasindex *saidx;
1.1       jonathan  324:
                    325:        IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
1.44      ozaki-r   326:        KASSERTMSG(af == AF_INET || af == AF_INET6,
                    327:            "invalid address family %u", af);
1.1       jonathan  328: again:
                    329:        /*
                    330:         * Craft SA index to search for proper SA.  Note that
                    331:         * we only fillin unspecified SA peers for transport
                    332:         * mode; for tunnel mode they must already be filled in.
                    333:         */
1.52      ozaki-r   334:        saidx = &isr->saidx;
1.1       jonathan  335:        if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
                    336:                /* Fillin unspecified SA peers only for transport mode */
                    337:                if (af == AF_INET) {
                    338:                        struct sockaddr_in *sin;
                    339:                        struct ip *ip = mtod(m, struct ip *);
                    340:
                    341:                        if (saidx->src.sa.sa_len == 0) {
                    342:                                sin = &saidx->src.sin;
                    343:                                sin->sin_len = sizeof(*sin);
                    344:                                sin->sin_family = AF_INET;
                    345:                                sin->sin_port = IPSEC_PORT_ANY;
                    346:                                sin->sin_addr = ip->ip_src;
                    347:                        }
                    348:                        if (saidx->dst.sa.sa_len == 0) {
                    349:                                sin = &saidx->dst.sin;
                    350:                                sin->sin_len = sizeof(*sin);
                    351:                                sin->sin_family = AF_INET;
                    352:                                sin->sin_port = IPSEC_PORT_ANY;
                    353:                                sin->sin_addr = ip->ip_dst;
                    354:                        }
                    355:                } else {
                    356:                        struct sockaddr_in6 *sin6;
                    357:                        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
                    358:
                    359:                        if (saidx->src.sin6.sin6_len == 0) {
                    360:                                sin6 = (struct sockaddr_in6 *)&saidx->src;
                    361:                                sin6->sin6_len = sizeof(*sin6);
                    362:                                sin6->sin6_family = AF_INET6;
                    363:                                sin6->sin6_port = IPSEC_PORT_ANY;
                    364:                                sin6->sin6_addr = ip6->ip6_src;
                    365:                                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
                    366:                                        /* fix scope id for comparing SPD */
                    367:                                        sin6->sin6_addr.s6_addr16[1] = 0;
                    368:                                        sin6->sin6_scope_id =
                    369:                                            ntohs(ip6->ip6_src.s6_addr16[1]);
                    370:                                }
                    371:                        }
                    372:                        if (saidx->dst.sin6.sin6_len == 0) {
                    373:                                sin6 = (struct sockaddr_in6 *)&saidx->dst;
                    374:                                sin6->sin6_len = sizeof(*sin6);
                    375:                                sin6->sin6_family = AF_INET6;
                    376:                                sin6->sin6_port = IPSEC_PORT_ANY;
                    377:                                sin6->sin6_addr = ip6->ip6_dst;
                    378:                                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
                    379:                                        /* fix scope id for comparing SPD */
                    380:                                        sin6->sin6_addr.s6_addr16[1] = 0;
                    381:                                        sin6->sin6_scope_id =
                    382:                                            ntohs(ip6->ip6_dst.s6_addr16[1]);
                    383:                                }
                    384:                        }
                    385:                }
                    386:        }
                    387:
                    388:        /*
                    389:         * Lookup SA and validate it.
                    390:         */
1.54      ozaki-r   391:        *error = key_checkrequest(isr, &sav);
1.1       jonathan  392:        if (*error != 0) {
                    393:                /*
                    394:                 * IPsec processing is required, but no SA found.
                    395:                 * I assume that key_acquire() had been called
                    396:                 * to get/establish the SA. Here I discard
                    397:                 * this packet because it is responsibility for
                    398:                 * upper layer to retransmit the packet.
                    399:                 */
1.27      thorpej   400:                IPSEC_STATINC(IPSEC_STAT_OUT_NOSA);
1.1       jonathan  401:                goto bad;
                    402:        }
1.26      degroote  403:        /* sav may be NULL here if we have an USE rule */
                    404:        if (sav == NULL) {
1.44      ozaki-r   405:                KASSERTMSG(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
                    406:                    "no SA found, but required; level %u",
                    407:                    ipsec_get_reqlevel(isr));
1.1       jonathan  408:                isr = isr->next;
1.26      degroote  409:                /*
                    410:                 * No more rules to apply, return NULL isr and no error
                    411:                 * It can happen when the last rules are USE rules
                    412:                 * */
1.1       jonathan  413:                if (isr == NULL) {
1.54      ozaki-r   414:                        *ret = NULL;
1.26      degroote  415:                        *error = 0;
1.1       jonathan  416:                        return isr;
                    417:                }
                    418:                goto again;
                    419:        }
                    420:
                    421:        /*
                    422:         * Check system global policy controls.
                    423:         */
                    424:        if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
                    425:            (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
                    426:            (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
1.48      ozaki-r   427:                IPSECLOG(LOG_DEBUG, "IPsec outbound packet dropped due"
                    428:                    " to policy (check your sysctls)\n");
1.49      ozaki-r   429:                IPSEC_OSTAT(PDROPS);
1.1       jonathan  430:                *error = EHOSTUNREACH;
1.58    ! ozaki-r   431:                KEY_SA_UNREF(&sav);
1.1       jonathan  432:                goto bad;
                    433:        }
                    434:
                    435:        /*
                    436:         * Sanity check the SA contents for the caller
                    437:         * before they invoke the xform output method.
                    438:         */
1.50      ozaki-r   439:        KASSERT(sav->tdb_xform != NULL);
1.54      ozaki-r   440:        *ret = sav;
1.1       jonathan  441:        return isr;
                    442: bad:
1.44      ozaki-r   443:        KASSERTMSG(*error != 0, "error return w/ no error code");
1.1       jonathan  444:        return NULL;
                    445: #undef IPSEC_OSTAT
                    446: }
                    447:
                    448: #ifdef INET
                    449: /*
                    450:  * IPsec output logic for IPv4.
                    451:  */
                    452: int
1.56      ozaki-r   453: ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr,
                    454:     u_long *mtu)
1.1       jonathan  455: {
1.54      ozaki-r   456:        struct secasvar *sav = NULL;
1.1       jonathan  457:        struct ip *ip;
                    458:        int s, error, i, off;
1.46      ozaki-r   459:        union sockaddr_union *dst;
                    460:        int setdf;
1.1       jonathan  461:
1.44      ozaki-r   462:        KASSERT(m != NULL);
                    463:        KASSERT(isr != NULL);
1.1       jonathan  464:
                    465:        s = splsoftnet();                       /* insure SA contents don't change */
                    466:
1.54      ozaki-r   467:        isr = ipsec_nextisr(m, isr, AF_INET, &error, &sav);
1.26      degroote  468:        if (isr == NULL) {
                    469:                if (error != 0) {
                    470:                        goto bad;
                    471:                } else {
                    472:                        if (ipsec_register_done(m, &error) < 0)
                    473:                                goto bad;
                    474:
                    475:                        splx(s);
                    476:                        return ipsec_reinject_ipstack(m, AF_INET);
                    477:                }
                    478:        }
1.1       jonathan  479:
1.54      ozaki-r   480:        KASSERT(sav != NULL);
1.56      ozaki-r   481:        /*
                    482:         * Check if we need to handle NAT-T fragmentation.
                    483:         */
                    484:        if (isr == isr->sp->req) { /* Check only if called from ipsec4_output */
                    485:                KASSERT(mtu != NULL);
                    486:                ip = mtod(m, struct ip *);
                    487:                if (!(sav->natt_type &
                    488:                    (UDP_ENCAP_ESPINUDP|UDP_ENCAP_ESPINUDP_NON_IKE))) {
                    489:                        goto noneed;
                    490:                }
                    491:                if (ntohs(ip->ip_len) <= sav->esp_frag)
                    492:                        goto noneed;
                    493:                *mtu = sav->esp_frag;
1.58    ! ozaki-r   494:                KEY_SA_UNREF(&sav);
1.56      ozaki-r   495:                splx(s);
                    496:                return 0;
                    497:        }
                    498: noneed:
1.46      ozaki-r   499:        dst = &sav->sah->saidx.dst;
1.1       jonathan  500:
1.46      ozaki-r   501:        /*
                    502:         * Collect IP_DF state from the outer header.
                    503:         */
                    504:        if (dst->sa.sa_family == AF_INET) {
                    505:                if (m->m_len < sizeof (struct ip) &&
                    506:                    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    507:                        error = ENOBUFS;
1.54      ozaki-r   508:                        goto unrefsav;
1.46      ozaki-r   509:                }
                    510:                ip = mtod(m, struct ip *);
                    511:                /* Honor system-wide control of how to handle IP_DF */
                    512:                switch (ip4_ipsec_dfbit) {
                    513:                case 0:                 /* clear in outer header */
                    514:                case 1:                 /* set in outer header */
                    515:                        setdf = ip4_ipsec_dfbit;
                    516:                        break;
                    517:                default:                /* propagate to outer header */
                    518:                        setdf = ip->ip_off;
                    519:                        setdf = ntohs(setdf);
                    520:                        setdf = htons(setdf & IP_DF);
                    521:                        break;
1.1       jonathan  522:                }
1.46      ozaki-r   523:        } else {
                    524:                ip = NULL;              /* keep compiler happy */
                    525:                setdf = 0;
                    526:        }
                    527:        /* Do the appropriate encapsulation, if necessary */
                    528:        if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
                    529:            dst->sa.sa_family != AF_INET ||         /* PF mismatch */
1.1       jonathan  530: #if 0
1.46      ozaki-r   531:            (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
                    532:            sav->tdb_xform->xf_type == XF_IP4 ||    /* ditto */
1.1       jonathan  533: #endif
1.46      ozaki-r   534:            (dst->sa.sa_family == AF_INET &&        /* Proxy */
                    535:             dst->sin.sin_addr.s_addr != INADDR_ANY &&
                    536:             dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
                    537:                struct mbuf *mp;
                    538:
                    539:                /* Fix IPv4 header checksum and length */
                    540:                if (m->m_len < sizeof (struct ip) &&
                    541:                    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    542:                        error = ENOBUFS;
1.54      ozaki-r   543:                        goto unrefsav;
1.46      ozaki-r   544:                }
                    545:                ip = mtod(m, struct ip *);
                    546:                ip->ip_len = htons(m->m_pkthdr.len);
                    547:                ip->ip_sum = 0;
                    548:                ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
1.1       jonathan  549:
1.46      ozaki-r   550:                /* Encapsulate the packet */
1.54      ozaki-r   551:                error = ipip_output(m, isr, sav, &mp, 0, 0);
1.46      ozaki-r   552:                if (mp == NULL && !error) {
                    553:                        /* Should never happen. */
1.48      ozaki-r   554:                        IPSECLOG(LOG_DEBUG,
                    555:                            "ipip_output returns no mbuf and no error!");
1.46      ozaki-r   556:                        error = EFAULT;
                    557:                }
                    558:                if (error) {
                    559:                        if (mp) {
                    560:                                /* XXX: Should never happen! */
                    561:                                m_freem(mp);
                    562:                        }
                    563:                        m = NULL; /* ipip_output() already freed it */
1.54      ozaki-r   564:                        goto unrefsav;
1.46      ozaki-r   565:                }
                    566:                m = mp, mp = NULL;
                    567:                /*
                    568:                 * ipip_output clears IP_DF in the new header.  If
                    569:                 * we need to propagate IP_DF from the outer header,
                    570:                 * then we have to do it here.
                    571:                 *
                    572:                 * XXX shouldn't assume what ipip_output does.
                    573:                 */
                    574:                if (dst->sa.sa_family == AF_INET && setdf) {
1.1       jonathan  575:                        if (m->m_len < sizeof (struct ip) &&
                    576:                            (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    577:                                error = ENOBUFS;
1.54      ozaki-r   578:                                goto unrefsav;
1.1       jonathan  579:                        }
                    580:                        ip = mtod(m, struct ip *);
1.46      ozaki-r   581:                        ip->ip_off |= htons(IP_DF);
1.1       jonathan  582:                }
                    583:        }
                    584:
                    585:        /*
                    586:         * Dispatch to the appropriate IPsec transform logic.  The
                    587:         * packet will be returned for transmission after crypto
                    588:         * processing, etc. are completed.  For encapsulation we
                    589:         * bypass this call because of the explicit call done above
                    590:         * (necessary to deal with IP_DF handling for IPv4).
                    591:         *
                    592:         * NB: m & sav are ``passed to caller'' who's reponsible for
                    593:         *     for reclaiming their resources.
                    594:         */
                    595:        if (sav->tdb_xform->xf_type != XF_IP4) {
1.33      drochner  596:                if (dst->sa.sa_family == AF_INET) {
                    597:                        ip = mtod(m, struct ip *);
                    598:                        i = ip->ip_hl << 2;
                    599:                        off = offsetof(struct ip, ip_p);
                    600:                } else {
                    601:                        i = sizeof(struct ip6_hdr);
                    602:                        off = offsetof(struct ip6_hdr, ip6_nxt);
                    603:                }
1.54      ozaki-r   604:                error = (*sav->tdb_xform->xf_output)(m, isr, sav, NULL, i, off);
1.1       jonathan  605:        } else {
1.54      ozaki-r   606:                error = ipsec_process_done(m, isr, sav);
1.1       jonathan  607:        }
1.58    ! ozaki-r   608:        KEY_SA_UNREF(&sav);
1.1       jonathan  609:        splx(s);
                    610:        return error;
1.54      ozaki-r   611: unrefsav:
1.58    ! ozaki-r   612:        KEY_SA_UNREF(&sav);
1.1       jonathan  613: bad:
                    614:        splx(s);
                    615:        if (m)
                    616:                m_freem(m);
                    617:        return error;
                    618: }
                    619: #endif
                    620:
                    621: #ifdef INET6
1.38      drochner  622: static void
                    623: compute_ipsec_pos(struct mbuf *m, int *i, int *off)
                    624: {
                    625:        int nxt;
                    626:        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr*);
                    627:        struct ip6_ext ip6e;
                    628:        int dstopt = 0;
                    629:
                    630:        *i = sizeof(struct ip6_hdr);
                    631:        *off = offsetof(struct ip6_hdr, ip6_nxt);
                    632:        nxt = ip6->ip6_nxt;
                    633:
                    634:        /*
                    635:         * chase mbuf chain to find the appropriate place to
                    636:         * put AH/ESP/IPcomp header.
                    637:         *  IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
                    638:         */
                    639:        do {
                    640:                switch (nxt) {
                    641:                case IPPROTO_AH:
                    642:                case IPPROTO_ESP:
                    643:                case IPPROTO_IPCOMP:
                    644:                /*
                    645:                 * we should not skip security header added
                    646:                 * beforehand.
                    647:                 */
                    648:                        return;
                    649:
                    650:                case IPPROTO_HOPOPTS:
                    651:                case IPPROTO_DSTOPTS:
                    652:                case IPPROTO_ROUTING:
                    653:                /*
                    654:                 * if we see 2nd destination option header,
                    655:                 * we should stop there.
                    656:                 */
                    657:                        if (nxt == IPPROTO_DSTOPTS && dstopt)
                    658:                                return;
                    659:
                    660:                        if (nxt == IPPROTO_DSTOPTS) {
                    661:                                /*
                    662:                                 * seen 1st or 2nd destination option.
                    663:                                 * next time we see one, it must be 2nd.
                    664:                                 */
                    665:                                dstopt = 1;
                    666:                        } else if (nxt == IPPROTO_ROUTING) {
                    667:                                /*
                    668:                                 * if we see destionation option next
                    669:                                 * time, it must be dest2.
                    670:                                 */
                    671:                                dstopt = 2;
                    672:                        }
                    673:
                    674:                        /* skip this header */
                    675:                        m_copydata(m, *i, sizeof(ip6e), &ip6e);
                    676:                        nxt = ip6e.ip6e_nxt;
                    677:                        *off = *i + offsetof(struct ip6_ext, ip6e_nxt);
                    678:                        /*
                    679:                         * we will never see nxt == IPPROTO_AH
                    680:                         * so it is safe to omit AH case.
                    681:                         */
                    682:                        *i += (ip6e.ip6e_len + 1) << 3;
                    683:                        break;
                    684:                default:
                    685:                        return;
                    686:                }
                    687:        } while (*i < m->m_pkthdr.len);
                    688: }
                    689:
1.36      drochner  690: static int
                    691: in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia)
                    692: {
                    693:        struct in6_addr ia2;
                    694:
                    695:        memcpy(&ia2, &sa->sin6_addr, sizeof(ia2));
                    696:        if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr))
                    697:                ia2.s6_addr16[1] = htons(sa->sin6_scope_id);
                    698:
                    699:        return IN6_ARE_ADDR_EQUAL(ia, &ia2);
                    700: }
                    701:
1.1       jonathan  702: int
1.21      degroote  703: ipsec6_process_packet(
                    704:        struct mbuf *m,
                    705:        struct ipsecrequest *isr
                    706:     )
1.1       jonathan  707: {
1.54      ozaki-r   708:        struct secasvar *sav = NULL;
1.21      degroote  709:        struct ip6_hdr *ip6;
1.35      drochner  710:        int s, error, i, off;
                    711:        union sockaddr_union *dst;
1.1       jonathan  712:
1.44      ozaki-r   713:        KASSERT(m != NULL);
                    714:        KASSERT(isr != NULL);
1.1       jonathan  715:
1.21      degroote  716:        s = splsoftnet();   /* insure SA contents don't change */
1.34      drochner  717:
1.54      ozaki-r   718:        isr = ipsec_nextisr(m, isr, AF_INET6, &error, &sav);
1.1       jonathan  719:        if (isr == NULL) {
1.26      degroote  720:                if (error != 0) {
1.34      drochner  721:                        /* XXX Should we send a notification ? */
1.26      degroote  722:                        goto bad;
                    723:                } else {
                    724:                        if (ipsec_register_done(m, &error) < 0)
                    725:                                goto bad;
                    726:
                    727:                        splx(s);
1.28      degroote  728:                        return ipsec_reinject_ipstack(m, AF_INET6);
1.26      degroote  729:                }
1.1       jonathan  730:        }
                    731:
1.54      ozaki-r   732:        KASSERT(sav != NULL);
1.35      drochner  733:        dst = &sav->sah->saidx.dst;
1.1       jonathan  734:
1.35      drochner  735:        ip6 = mtod(m, struct ip6_hdr *); /* XXX */
1.1       jonathan  736:
1.35      drochner  737:        /* Do the appropriate encapsulation, if necessary */
                    738:        if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
                    739:            dst->sa.sa_family != AF_INET6 ||        /* PF mismatch */
                    740:            ((dst->sa.sa_family == AF_INET6) &&
                    741:             (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
1.36      drochner  742:             (!in6_sa_equal_addrwithscope(&dst->sin6,
1.35      drochner  743:                                  &ip6->ip6_dst)))) {
                    744:                struct mbuf *mp;
                    745:
                    746:                /* Fix IPv6 header payload length. */
1.53      ozaki-r   747:                if (m->m_len < sizeof(struct ip6_hdr)) {
                    748:                        if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) {
                    749:                                error = ENOBUFS;
1.54      ozaki-r   750:                                goto unrefsav;
1.53      ozaki-r   751:                        }
                    752:                }
1.34      drochner  753:
1.35      drochner  754:                if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
                    755:                        /* No jumbogram support. */
1.53      ozaki-r   756:                        error = ENXIO;   /*XXX*/
1.54      ozaki-r   757:                        goto unrefsav;
1.35      drochner  758:                }
1.34      drochner  759:
1.35      drochner  760:                ip6 = mtod(m, struct ip6_hdr *);
                    761:                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
1.1       jonathan  762:
1.35      drochner  763:                /* Encapsulate the packet */
1.54      ozaki-r   764:                error = ipip_output(m, isr, sav, &mp, 0, 0);
1.35      drochner  765:                if (mp == NULL && !error) {
                    766:                        /* Should never happen. */
1.48      ozaki-r   767:                        IPSECLOG(LOG_DEBUG,
                    768:                            "ipip_output returns no mbuf and no error!");
1.35      drochner  769:                        error = EFAULT;
                    770:                }
                    771:
                    772:                if (error) {
                    773:                        if (mp) {
                    774:                                /* XXX: Should never happen! */
                    775:                                m_freem(mp);
1.21      degroote  776:                        }
1.35      drochner  777:                        m = NULL; /* ipip_output() already freed it */
1.54      ozaki-r   778:                        goto unrefsav;
1.35      drochner  779:                }
                    780:
                    781:                m = mp;
                    782:                mp = NULL;
                    783:        }
1.1       jonathan  784:
1.35      drochner  785:        if (dst->sa.sa_family == AF_INET) {
                    786:                struct ip *ip;
                    787:                ip = mtod(m, struct ip *);
                    788:                i = ip->ip_hl << 2;
                    789:                off = offsetof(struct ip, ip_p);
                    790:        } else {
1.38      drochner  791:                compute_ipsec_pos(m, &i, &off);
1.34      drochner  792:        }
1.54      ozaki-r   793:        error = (*sav->tdb_xform->xf_output)(m, isr, sav, NULL, i, off);
1.58    ! ozaki-r   794:        KEY_SA_UNREF(&sav);
1.34      drochner  795:        splx(s);
                    796:        return error;
1.54      ozaki-r   797: unrefsav:
1.58    ! ozaki-r   798:        KEY_SA_UNREF(&sav);
1.1       jonathan  799: bad:
1.21      degroote  800:        splx(s);
1.1       jonathan  801:        if (m)
                    802:                m_freem(m);
                    803:        return error;
                    804: }
                    805: #endif /*INET6*/

CVSweb <webmaster@jp.NetBSD.org>