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

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

CVSweb <webmaster@jp.NetBSD.org>