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

1.27    ! thorpej     1: /*     $NetBSD: ipsec_output.c,v 1.26 2007/12/29 16:43:17 degroote 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.27    ! thorpej    32: __KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.26 2007/12/29 16:43:17 degroote 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 */
                    126:
                    127:        switch (af) {
                    128: #ifdef INET
                    129:        case AF_INET:
                    130:                ip = mtod(m, struct ip *);
                    131: #ifdef __FreeBSD__
                    132:                /* FreeBSD ip_output() expects ip_len, ip_off in host endian */
                    133:                ip->ip_len = ntohs(ip->ip_len);
                    134:                ip->ip_off = ntohs(ip->ip_off);
                    135: #endif /* __FreeBSD_ */
                    136:                return ip_output(m, NULL, NULL, IP_RAWOUTPUT,
                    137:                    (struct ip_moptions *)NULL, (struct socket *)NULL);
                    138:
                    139: #endif /* INET */
                    140: #ifdef INET6
                    141:        case AF_INET6:
                    142:                /*
                    143:                 * We don't need massage, IPv6 header fields are always in
                    144:                 * net endian.
                    145:                 */
                    146:                return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
                    147: #endif /* INET6 */
                    148:        }
                    149:
                    150:        panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af);
                    151:        return -1; /* NOTREACHED */
                    152: }
                    153:
1.1       jonathan  154: int
                    155: ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
                    156: {
                    157:        struct secasvar *sav;
                    158:        struct secasindex *saidx;
                    159:        int error;
1.22      degroote  160: #ifdef INET
                    161:        struct ip * ip;
                    162: #endif /* INET */
                    163: #ifdef INET6
                    164:        struct ip6_hdr * ip6;
                    165: #endif /* INET6 */
                    166: #ifdef IPSEC_NAT_T
                    167:        struct mbuf * mo;
                    168:        struct udphdr *udp = NULL;
                    169:        uint64_t * data = NULL;
                    170:        int hlen, roff;
                    171: #endif /* IPSEC_NAT_T */
1.1       jonathan  172:
                    173:        IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
                    174:
                    175:        IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
                    176:        IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
                    177:        sav = isr->sav;
                    178:        IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
                    179:        IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
                    180:
                    181:        saidx = &sav->sah->saidx;
1.22      degroote  182:
                    183: #ifdef IPSEC_NAT_T
                    184:        if(sav->natt_type != 0) {
                    185:                ip = mtod(m, struct ip *);
                    186:
                    187:                hlen = sizeof(struct udphdr);
                    188:                if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
                    189:                        hlen += sizeof(uint64_t);
                    190:
                    191:                mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
                    192:                if (mo == NULL) {
                    193:                        DPRINTF(("ipsec_process_done : failed to inject"
                    194:                                 "%u byte UDP for SA %s/%08lx\n",
                    195:                                         hlen, ipsec_address(&saidx->dst),
                    196:                                         (u_long) ntohl(sav->spi)));
                    197:                        error = ENOBUFS;
                    198:                        goto bad;
                    199:                }
                    200:
                    201:                udp = (struct udphdr*) (mtod(mo, char*) + roff);
                    202:                data = (uint64_t*) (udp + 1);
                    203:
                    204:                if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
                    205:                        *data = 0; /* NON-IKE Marker */
                    206:
                    207:                if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
                    208:                        udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
                    209:                else
                    210:                        udp->uh_sport = key_portfromsaddr(&saidx->src);
                    211:
                    212:                udp->uh_dport = key_portfromsaddr(&saidx->dst);
                    213:                udp->uh_sum = 0;
1.24      degroote  214:                udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
1.22      degroote  215:        }
                    216: #endif /* IPSEC_NAT_T */
                    217:
1.1       jonathan  218:        switch (saidx->dst.sa.sa_family) {
                    219: #ifdef INET
                    220:        case AF_INET:
                    221:                /* Fix the header length, for AH processing. */
1.22      degroote  222:                ip = mtod(m, struct ip *);
                    223:                ip->ip_len = htons(m->m_pkthdr.len);
                    224: #ifdef IPSEC_NAT_T
                    225:                if (sav->natt_type != 0)
                    226:                        ip->ip_p = IPPROTO_UDP;
                    227: #endif /* IPSEC_NAT_T */
1.1       jonathan  228:                break;
                    229: #endif /* INET */
                    230: #ifdef INET6
                    231:        case AF_INET6:
                    232:                /* Fix the header length, for AH processing. */
                    233:                if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
                    234:                        error = ENXIO;
                    235:                        goto bad;
                    236:                }
                    237:                if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
                    238:                        /* No jumbogram support. */
                    239:                        error = ENXIO;  /*?*/
                    240:                        goto bad;
                    241:                }
1.22      degroote  242:                ip6 = mtod(m, struct ip6_hdr *);
                    243:                ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
                    244: #ifdef IPSEC_NAT_T
                    245:                if (sav->natt_type != 0)
                    246:                        ip6->ip6_nxt = IPPROTO_UDP;
                    247: #endif /* IPSEC_NAT_T */
1.1       jonathan  248:                break;
                    249: #endif /* INET6 */
                    250:        default:
                    251:                DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
                    252:                    saidx->dst.sa.sa_family));
                    253:                error = ENXIO;
                    254:                goto bad;
                    255:        }
                    256:
                    257:        /*
                    258:         * If there's another (bundled) SA to apply, do so.
                    259:         * Note that this puts a burden on the kernel stack size.
                    260:         * If this is a problem we'll need to introduce a queue
                    261:         * to set the packet on so we can unwind the stack before
                    262:         * doing further processing.
                    263:         */
                    264:        if (isr->next) {
1.27    ! thorpej   265:                IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA);
1.21      degroote  266:         switch ( saidx->dst.sa.sa_family ) {
                    267: #ifdef INET
                    268:         case AF_INET:
                    269:                        return ipsec4_process_packet(m, isr->next, 0,0);
                    270: #endif /* INET */
                    271: #ifdef INET6
                    272:                case AF_INET6:
                    273:                return ipsec6_process_packet(m,isr->next);
                    274: #endif /* INET6 */
                    275:                default :
                    276:                        DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
                    277:                                saidx->dst.sa.sa_family));
                    278:                        error = ENXIO;
                    279:                        goto bad;
                    280:         }
1.1       jonathan  281:        }
                    282:
                    283:        /*
1.25      degroote  284:         * We're done with IPsec processing,
                    285:         * mark that we have already processed the packet
                    286:         * transmit it packet using the appropriate network protocol (IP or IPv6).
1.1       jonathan  287:         */
1.25      degroote  288:
                    289:        if (ipsec_register_done(m, &error) < 0)
                    290:                goto bad;
                    291:
1.26      degroote  292:        return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family);
1.1       jonathan  293: bad:
                    294:        m_freem(m);
                    295:        KEY_FREESAV(&sav);
                    296:        return (error);
                    297: }
                    298:
1.26      degroote  299: /*
                    300:  * ipsec_nextisr can return :
                    301:  * - isr == NULL and error != 0 => something is bad : the packet must be
                    302:  *   discarded
                    303:  * - isr == NULL and error == 0 => no more rules to apply, ipsec processing
                    304:  *   is done, reinject it in ip stack
                    305:  * - isr != NULL (error == 0) => we need to apply one rule to the packet
                    306:  */
1.1       jonathan  307: static struct ipsecrequest *
                    308: ipsec_nextisr(
                    309:        struct mbuf *m,
                    310:        struct ipsecrequest *isr,
                    311:        int af,
                    312:        struct secasindex *saidx,
                    313:        int *error
                    314: )
                    315: {
1.27    ! thorpej   316: #define        IPSEC_OSTAT(x, y, z)                                            \
        !           317: do {                                                                   \
        !           318:        switch (isr->saidx.proto) {                                     \
        !           319:        case IPPROTO_ESP:                                               \
        !           320:                ESP_STATINC(x);                                         \
        !           321:                break;                                                  \
        !           322:        case IPPROTO_AH:                                                \
        !           323:                AH_STATINC(y);                                          \
        !           324:                break;                                                  \
        !           325:        default:                                                        \
        !           326:                IPCOMP_STATINC(z);                                      \
        !           327:                break;                                                  \
        !           328:        }                                                               \
        !           329: } while (/*CONSTCOND*/0)
        !           330:
1.1       jonathan  331:        struct secasvar *sav;
                    332:
                    333:        IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
                    334:        IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
                    335:                ("ipsec_nextisr: invalid address family %u", af));
                    336: again:
                    337:        /*
                    338:         * Craft SA index to search for proper SA.  Note that
                    339:         * we only fillin unspecified SA peers for transport
                    340:         * mode; for tunnel mode they must already be filled in.
                    341:         */
                    342:        *saidx = isr->saidx;
                    343:        if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
                    344:                /* Fillin unspecified SA peers only for transport mode */
                    345:                if (af == AF_INET) {
                    346:                        struct sockaddr_in *sin;
                    347:                        struct ip *ip = mtod(m, struct ip *);
                    348:
                    349:                        if (saidx->src.sa.sa_len == 0) {
                    350:                                sin = &saidx->src.sin;
                    351:                                sin->sin_len = sizeof(*sin);
                    352:                                sin->sin_family = AF_INET;
                    353:                                sin->sin_port = IPSEC_PORT_ANY;
                    354:                                sin->sin_addr = ip->ip_src;
                    355:                        }
                    356:                        if (saidx->dst.sa.sa_len == 0) {
                    357:                                sin = &saidx->dst.sin;
                    358:                                sin->sin_len = sizeof(*sin);
                    359:                                sin->sin_family = AF_INET;
                    360:                                sin->sin_port = IPSEC_PORT_ANY;
                    361:                                sin->sin_addr = ip->ip_dst;
                    362:                        }
                    363:                } else {
                    364:                        struct sockaddr_in6 *sin6;
                    365:                        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
                    366:
                    367:                        if (saidx->src.sin6.sin6_len == 0) {
                    368:                                sin6 = (struct sockaddr_in6 *)&saidx->src;
                    369:                                sin6->sin6_len = sizeof(*sin6);
                    370:                                sin6->sin6_family = AF_INET6;
                    371:                                sin6->sin6_port = IPSEC_PORT_ANY;
                    372:                                sin6->sin6_addr = ip6->ip6_src;
                    373:                                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
                    374:                                        /* fix scope id for comparing SPD */
                    375:                                        sin6->sin6_addr.s6_addr16[1] = 0;
                    376:                                        sin6->sin6_scope_id =
                    377:                                            ntohs(ip6->ip6_src.s6_addr16[1]);
                    378:                                }
                    379:                        }
                    380:                        if (saidx->dst.sin6.sin6_len == 0) {
                    381:                                sin6 = (struct sockaddr_in6 *)&saidx->dst;
                    382:                                sin6->sin6_len = sizeof(*sin6);
                    383:                                sin6->sin6_family = AF_INET6;
                    384:                                sin6->sin6_port = IPSEC_PORT_ANY;
                    385:                                sin6->sin6_addr = ip6->ip6_dst;
                    386:                                if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
                    387:                                        /* fix scope id for comparing SPD */
                    388:                                        sin6->sin6_addr.s6_addr16[1] = 0;
                    389:                                        sin6->sin6_scope_id =
                    390:                                            ntohs(ip6->ip6_dst.s6_addr16[1]);
                    391:                                }
                    392:                        }
                    393:                }
                    394:        }
                    395:
                    396:        /*
                    397:         * Lookup SA and validate it.
                    398:         */
                    399:        *error = key_checkrequest(isr, saidx);
                    400:        if (*error != 0) {
                    401:                /*
                    402:                 * IPsec processing is required, but no SA found.
                    403:                 * I assume that key_acquire() had been called
                    404:                 * to get/establish the SA. Here I discard
                    405:                 * this packet because it is responsibility for
                    406:                 * upper layer to retransmit the packet.
                    407:                 */
1.27    ! thorpej   408:                IPSEC_STATINC(IPSEC_STAT_OUT_NOSA);
1.1       jonathan  409:                goto bad;
                    410:        }
                    411:        sav = isr->sav;
1.26      degroote  412:        /* sav may be NULL here if we have an USE rule */
                    413:        if (sav == NULL) {
1.1       jonathan  414:                IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
                    415:                        ("ipsec_nextisr: no SA found, but required; level %u",
                    416:                        ipsec_get_reqlevel(isr)));
                    417:                isr = isr->next;
1.26      degroote  418:                /*
                    419:                 * No more rules to apply, return NULL isr and no error
                    420:                 * It can happen when the last rules are USE rules
                    421:                 * */
1.1       jonathan  422:                if (isr == NULL) {
1.26      degroote  423:                        *error = 0;
1.1       jonathan  424:                        return isr;
                    425:                }
                    426:                goto again;
                    427:        }
                    428:
                    429:        /*
                    430:         * Check system global policy controls.
                    431:         */
                    432:        if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
                    433:            (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
                    434:            (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
                    435:                DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
                    436:                        " to policy (check your sysctls)\n"));
1.27    ! thorpej   437:                IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS,
        !           438:                    IPCOMP_STAT_PDROPS);
1.1       jonathan  439:                *error = EHOSTUNREACH;
                    440:                goto bad;
                    441:        }
                    442:
                    443:        /*
                    444:         * Sanity check the SA contents for the caller
                    445:         * before they invoke the xform output method.
                    446:         */
                    447:        if (sav->tdb_xform == NULL) {
                    448:                DPRINTF(("ipsec_nextisr: no transform for SA\n"));
1.27    ! thorpej   449:                IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM,
        !           450:                    IPCOMP_STAT_NOXFORM);
1.1       jonathan  451:                *error = EHOSTUNREACH;
                    452:                goto bad;
                    453:        }
                    454:        return isr;
                    455: bad:
                    456:        IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
                    457:        return NULL;
                    458: #undef IPSEC_OSTAT
                    459: }
                    460:
                    461: #ifdef INET
                    462: /*
                    463:  * IPsec output logic for IPv4.
                    464:  */
                    465: int
                    466: ipsec4_process_packet(
1.15      christos  467:     struct mbuf *m,
                    468:     struct ipsecrequest *isr,
1.16      christos  469:     int flags,
1.15      christos  470:     int tunalready
                    471: )
1.1       jonathan  472: {
                    473:        struct secasindex saidx;
                    474:        struct secasvar *sav;
                    475:        struct ip *ip;
                    476:        int s, error, i, off;
                    477:
                    478:        IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
                    479:        IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
                    480:
                    481:        s = splsoftnet();                       /* insure SA contents don't change */
                    482:
                    483:        isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
1.26      degroote  484:        if (isr == NULL) {
                    485:                if (error != 0) {
                    486:                        goto bad;
                    487:                } else {
                    488:                        if (ipsec_register_done(m, &error) < 0)
                    489:                                goto bad;
                    490:
                    491:                        splx(s);
                    492:                        return ipsec_reinject_ipstack(m, AF_INET);
                    493:                }
                    494:        }
1.1       jonathan  495:
                    496:        sav = isr->sav;
                    497:        if (!tunalready) {
                    498:                union sockaddr_union *dst = &sav->sah->saidx.dst;
                    499:                int setdf;
                    500:
                    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;
                    508:                                goto bad;
                    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 */
1.3       jonathan  518:                                setdf = ip->ip_off;
                    519: #ifndef __FreeBSD__
                    520:                /* On FreeBSD, ip_off and ip_len assumed in host endian. */
                    521:                                setdf = ntohs(setdf);
                    522: #endif
                    523:                                setdf = htons(setdf & IP_DF);
1.1       jonathan  524:                                break;
                    525:                        }
                    526:                } else {
                    527:                        ip = NULL;              /* keep compiler happy */
                    528:                        setdf = 0;
                    529:                }
                    530:                /* Do the appropriate encapsulation, if necessary */
                    531:                if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
                    532:                    dst->sa.sa_family != AF_INET ||         /* PF mismatch */
                    533: #if 0
                    534:                    (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
                    535:                    sav->tdb_xform->xf_type == XF_IP4 ||    /* ditto */
                    536: #endif
                    537:                    (dst->sa.sa_family == AF_INET &&        /* Proxy */
                    538:                     dst->sin.sin_addr.s_addr != INADDR_ANY &&
                    539:                     dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
                    540:                        struct mbuf *mp;
                    541:
                    542:                        /* Fix IPv4 header checksum and length */
                    543:                        if (m->m_len < sizeof (struct ip) &&
                    544:                            (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    545:                                error = ENOBUFS;
                    546:                                goto bad;
                    547:                        }
                    548:                        ip = mtod(m, struct ip *);
                    549:                        ip->ip_len = htons(m->m_pkthdr.len);
                    550:                        ip->ip_sum = 0;
                    551:                        ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
                    552:
                    553:                        /* Encapsulate the packet */
                    554:                        error = ipip_output(m, isr, &mp, 0, 0);
                    555:                        if (mp == NULL && !error) {
                    556:                                /* Should never happen. */
                    557:                                DPRINTF(("ipsec4_process_packet: ipip_output "
                    558:                                        "returns no mbuf and no error!"));
                    559:                                error = EFAULT;
                    560:                        }
                    561:                        if (error) {
1.8       scw       562:                                if (mp) {
                    563:                                        /* XXX: Should never happen! */
1.1       jonathan  564:                                        m_freem(mp);
1.8       scw       565:                                }
                    566:                                m = NULL; /* ipip_output() already freed it */
1.1       jonathan  567:                                goto bad;
                    568:                        }
                    569:                        m = mp, mp = NULL;
                    570:                        /*
                    571:                         * ipip_output clears IP_DF in the new header.  If
                    572:                         * we need to propagate IP_DF from the outer header,
                    573:                         * then we have to do it here.
                    574:                         *
                    575:                         * XXX shouldn't assume what ipip_output does.
                    576:                         */
                    577:                        if (dst->sa.sa_family == AF_INET && setdf) {
                    578:                                if (m->m_len < sizeof (struct ip) &&
                    579:                                    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
                    580:                                        error = ENOBUFS;
                    581:                                        goto bad;
                    582:                                }
                    583:                                ip = mtod(m, struct ip *);
1.23      adrianp   584:                                ip->ip_off |= IP_OFF_CONVERT(IP_DF);
1.1       jonathan  585:                        }
                    586:                }
                    587:        }
                    588:
                    589:        /*
                    590:         * Dispatch to the appropriate IPsec transform logic.  The
                    591:         * packet will be returned for transmission after crypto
                    592:         * processing, etc. are completed.  For encapsulation we
                    593:         * bypass this call because of the explicit call done above
                    594:         * (necessary to deal with IP_DF handling for IPv4).
                    595:         *
                    596:         * NB: m & sav are ``passed to caller'' who's reponsible for
                    597:         *     for reclaiming their resources.
                    598:         */
                    599:        if (sav->tdb_xform->xf_type != XF_IP4) {
                    600:                ip = mtod(m, struct ip *);
                    601:                i = ip->ip_hl << 2;
                    602:                off = offsetof(struct ip, ip_p);
                    603:                error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
                    604:        } else {
                    605:                error = ipsec_process_done(m, isr);
                    606:        }
                    607:        splx(s);
                    608:        return error;
                    609: bad:
                    610:        splx(s);
                    611:        if (m)
                    612:                m_freem(m);
                    613:        return error;
                    614: }
                    615: #endif
                    616:
                    617: #ifdef INET6
                    618: int
1.21      degroote  619: ipsec6_process_packet(
                    620:        struct mbuf *m,
                    621:        struct ipsecrequest *isr
                    622:     )
1.1       jonathan  623: {
                    624:        struct secasindex saidx;
1.21      degroote  625:        struct secasvar *sav;
                    626:        struct ip6_hdr *ip6;
                    627:        int s, error, i, off;
1.1       jonathan  628:
1.21      degroote  629:        IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf"));
                    630:        IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr"));
1.1       jonathan  631:
1.21      degroote  632:        s = splsoftnet();   /* insure SA contents don't change */
1.1       jonathan  633:        isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
                    634:        if (isr == NULL) {
1.26      degroote  635:                if (error != 0) {
                    636:                        // XXX Should we send a notification ?
                    637:                        goto bad;
                    638:                } else {
                    639:                        if (ipsec_register_done(m, &error) < 0)
                    640:                                goto bad;
                    641:
                    642:                        splx(s);
                    643:                        return ipsec_reinject_ipstack(m, AF_INET);
                    644:                }
1.1       jonathan  645:        }
                    646:
1.21      degroote  647:        sav = isr->sav;
                    648:        if (sav->tdb_xform->xf_type != XF_IP4) {
                    649:                i = sizeof(struct ip6_hdr);
                    650:                off = offsetof(struct ip6_hdr, ip6_nxt);
                    651:                error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
                    652:        } else {
                    653:                union sockaddr_union *dst = &sav->sah->saidx.dst;
1.1       jonathan  654:
1.21      degroote  655:         ip6 = mtod(m, struct ip6_hdr *);
1.1       jonathan  656:
1.21      degroote  657:                /* Do the appropriate encapsulation, if necessary */
                    658:                if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
                    659:                dst->sa.sa_family != AF_INET6 ||        /* PF mismatch */
                    660:             ((dst->sa.sa_family == AF_INET6) &&
                    661:                 (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
                    662:                 (!IN6_ARE_ADDR_EQUAL(&dst->sin6.sin6_addr,
                    663:                 &ip6->ip6_dst)))
                    664:             )
                    665:                {
                    666:                        struct mbuf *mp;
                    667:             /* Fix IPv6 header payload length. */
                    668:             if (m->m_len < sizeof(struct ip6_hdr))
                    669:                 if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL)
                    670:                    return ENOBUFS;
                    671:
                    672:             if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
                    673:                 /* No jumbogram support. */
                    674:                 m_freem(m);
                    675:                 return ENXIO;   /*XXX*/
                    676:             }
                    677:             ip6 = mtod(m, struct ip6_hdr *);
                    678:             ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
1.1       jonathan  679:
1.21      degroote  680:                        /* Encapsulate the packet */
                    681:                        error = ipip_output(m, isr, &mp, 0, 0);
                    682:                        if (mp == NULL && !error) {
                    683:                                /* Should never happen. */
                    684:                                DPRINTF(("ipsec6_process_packet: ipip_output "
                    685:                                                 "returns no mbuf and no error!"));
                    686:                                 error = EFAULT;
                    687:                        }
1.1       jonathan  688:
1.21      degroote  689:                        if (error) {
                    690:                                if (mp) {
                    691:                                        /* XXX: Should never happen! */
                    692:                                        m_freem(mp);
                    693:                                }
                    694:                                m = NULL; /* ipip_output() already freed it */
1.19      joerg     695:                                goto bad;
                    696:                        }
1.21      degroote  697:
                    698:                        m = mp;
                    699:                        mp = NULL;
1.1       jonathan  700:                }
1.21      degroote  701:
                    702:                error = ipsec_process_done(m,isr);
1.1       jonathan  703:                }
1.21      degroote  704:                splx(s);
                    705:                return error;
1.1       jonathan  706: bad:
1.21      degroote  707:        splx(s);
1.1       jonathan  708:        if (m)
                    709:                m_freem(m);
                    710:        return error;
                    711: }
                    712: #endif /*INET6*/

CVSweb <webmaster@jp.NetBSD.org>