[BACK]Return to ip_spd.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/ip_spd.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: ip_spd.c,v 1.53 2007/02/14 00:53:48 jsg Exp $ */
        !             2: /*
        !             3:  * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
        !             4:  *
        !             5:  * Copyright (c) 2000-2001 Angelos D. Keromytis.
        !             6:  *
        !             7:  * Permission to use, copy, and modify this software with or without fee
        !             8:  * is hereby granted, provided that this entire notice is included in
        !             9:  * all copies of any software which is or includes a copy or
        !            10:  * modification of this software.
        !            11:  * You may use this code under the GNU public license if you so wish. Please
        !            12:  * contribute changes back to the authors under this freer than GPL license
        !            13:  * so that we may further the use of strong encryption without limitations to
        !            14:  * all.
        !            15:  *
        !            16:  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
        !            18:  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
        !            19:  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
        !            20:  * PURPOSE.
        !            21:  */
        !            22:
        !            23: #include <sys/param.h>
        !            24: #include <sys/systm.h>
        !            25: #include <sys/mbuf.h>
        !            26: #include <sys/socket.h>
        !            27: #include <sys/kernel.h>
        !            28: #include <sys/socketvar.h>
        !            29: #include <sys/protosw.h>
        !            30:
        !            31: #include <net/if.h>
        !            32: #include <net/route.h>
        !            33: #include <net/netisr.h>
        !            34:
        !            35: #ifdef INET
        !            36: #include <netinet/in.h>
        !            37: #include <netinet/in_systm.h>
        !            38: #include <netinet/ip.h>
        !            39: #include <netinet/in_pcb.h>
        !            40: #include <netinet/in_var.h>
        !            41: #endif /* INET */
        !            42:
        !            43: #ifdef INET6
        !            44: #ifndef INET
        !            45: #include <netinet/in.h>
        !            46: #endif
        !            47: #include <netinet6/in6_var.h>
        !            48: #endif /* INET6 */
        !            49:
        !            50: #include <netinet/ip_ipsp.h>
        !            51: #include <net/pfkeyv2.h>
        !            52:
        !            53: #ifdef ENCDEBUG
        !            54: #define        DPRINTF(x)      if (encdebug) printf x
        !            55: #else
        !            56: #define        DPRINTF(x)
        !            57: #endif
        !            58:
        !            59: struct pool ipsec_policy_pool;
        !            60: struct pool ipsec_acquire_pool;
        !            61: int ipsec_policy_pool_initialized = 0;
        !            62: int ipsec_acquire_pool_initialized = 0;
        !            63:
        !            64: /*
        !            65:  * Lookup at the SPD based on the headers contained on the mbuf. The second
        !            66:  * argument indicates what protocol family the header at the beginning of
        !            67:  * the mbuf is. hlen is the offset of the transport protocol header
        !            68:  * in the mbuf.
        !            69:  *
        !            70:  * Return combinations (of return value and in *error):
        !            71:  * - NULL/0 -> no IPsec required on packet
        !            72:  * - NULL/-EINVAL -> silently drop the packet
        !            73:  * - NULL/errno -> drop packet and return error
        !            74:  * or a pointer to a TDB (and 0 in *error).
        !            75:  *
        !            76:  * In the case of incoming flows, only the first three combinations are
        !            77:  * returned.
        !            78:  */
        !            79: struct tdb *
        !            80: ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
        !            81:     struct tdb *tdbp, struct inpcb *inp)
        !            82: {
        !            83:        struct route_enc re0, *re = &re0;
        !            84:        union sockaddr_union sdst, ssrc;
        !            85:        struct sockaddr_encap *ddst;
        !            86:        struct ipsec_policy *ipo;
        !            87:        int signore = 0, dignore = 0;
        !            88:
        !            89:        /*
        !            90:         * If there are no flows in place, there's no point
        !            91:         * continuing with the SPD lookup.
        !            92:         */
        !            93:        if (!ipsec_in_use && inp == NULL) {
        !            94:                *error = 0;
        !            95:                return NULL;
        !            96:        }
        !            97:
        !            98:        /*
        !            99:         * If an input packet is destined to a BYPASS socket, just accept it.
        !           100:         */
        !           101:        if ((inp != NULL) && (direction == IPSP_DIRECTION_IN) &&
        !           102:            (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) &&
        !           103:            (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS) &&
        !           104:            (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) {
        !           105:                *error = 0;
        !           106:                return NULL;
        !           107:        }
        !           108:
        !           109:        bzero((caddr_t) re, sizeof(struct route_enc));
        !           110:        bzero((caddr_t) &sdst, sizeof(union sockaddr_union));
        !           111:        bzero((caddr_t) &ssrc, sizeof(union sockaddr_union));
        !           112:        ddst = (struct sockaddr_encap *) &re->re_dst;
        !           113:        ddst->sen_family = PF_KEY;
        !           114:        ddst->sen_len = SENT_LEN;
        !           115:
        !           116:        switch (af) {
        !           117: #ifdef INET
        !           118:        case AF_INET:
        !           119:                if (hlen < sizeof (struct ip) || m->m_pkthdr.len < hlen) {
        !           120:                        *error = EINVAL;
        !           121:                        return NULL;
        !           122:                }
        !           123:                ddst->sen_direction = direction;
        !           124:                ddst->sen_type = SENT_IP4;
        !           125:
        !           126:                m_copydata(m, offsetof(struct ip, ip_src),
        !           127:                    sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_src));
        !           128:                m_copydata(m, offsetof(struct ip, ip_dst),
        !           129:                    sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_dst));
        !           130:                m_copydata(m, offsetof(struct ip, ip_p), sizeof(u_int8_t),
        !           131:                    (caddr_t) &(ddst->sen_proto));
        !           132:
        !           133:                sdst.sin.sin_family = ssrc.sin.sin_family = AF_INET;
        !           134:                sdst.sin.sin_len = ssrc.sin.sin_len =
        !           135:                    sizeof(struct sockaddr_in);
        !           136:                ssrc.sin.sin_addr = ddst->sen_ip_src;
        !           137:                sdst.sin.sin_addr = ddst->sen_ip_dst;
        !           138:
        !           139:                /*
        !           140:                 * If TCP/UDP, extract the port numbers to use in the lookup.
        !           141:                 */
        !           142:                switch (ddst->sen_proto) {
        !           143:                case IPPROTO_UDP:
        !           144:                case IPPROTO_TCP:
        !           145:                        /* Make sure there's enough data in the packet. */
        !           146:                        if (m->m_pkthdr.len < hlen + 2 * sizeof(u_int16_t)) {
        !           147:                                *error = EINVAL;
        !           148:                                return NULL;
        !           149:                        }
        !           150:
        !           151:                        /*
        !           152:                         * Luckily, the offset of the src/dst ports in
        !           153:                         * both the UDP and TCP headers is the same (first
        !           154:                         * two 16-bit values in the respective headers),
        !           155:                         * so we can just copy them.
        !           156:                         */
        !           157:                        m_copydata(m, hlen, sizeof(u_int16_t),
        !           158:                            (caddr_t) &(ddst->sen_sport));
        !           159:                        m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t),
        !           160:                            (caddr_t) &(ddst->sen_dport));
        !           161:                        break;
        !           162:
        !           163:                default:
        !           164:                        ddst->sen_sport = 0;
        !           165:                        ddst->sen_dport = 0;
        !           166:                }
        !           167:
        !           168:                break;
        !           169: #endif /* INET */
        !           170:
        !           171: #ifdef INET6
        !           172:        case AF_INET6:
        !           173:                if (hlen < sizeof (struct ip6_hdr) || m->m_pkthdr.len < hlen) {
        !           174:                        *error = EINVAL;
        !           175:                        return NULL;
        !           176:                }
        !           177:                ddst->sen_type = SENT_IP6;
        !           178:                ddst->sen_ip6_direction = direction;
        !           179:
        !           180:                m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
        !           181:                    sizeof(struct in6_addr),
        !           182:                    (caddr_t) &(ddst->sen_ip6_src));
        !           183:                m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
        !           184:                    sizeof(struct in6_addr),
        !           185:                    (caddr_t) &(ddst->sen_ip6_dst));
        !           186:                m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt),
        !           187:                    sizeof(u_int8_t),
        !           188:                    (caddr_t) &(ddst->sen_ip6_proto));
        !           189:
        !           190:                sdst.sin6.sin6_family = ssrc.sin6.sin6_family = AF_INET6;
        !           191:                sdst.sin6.sin6_len = ssrc.sin6.sin6_family =
        !           192:                    sizeof(struct sockaddr_in6);
        !           193:                in6_recoverscope(&ssrc.sin6, &ddst->sen_ip6_src, NULL);
        !           194:                in6_recoverscope(&sdst.sin6, &ddst->sen_ip6_dst, NULL);
        !           195:
        !           196:                /*
        !           197:                 * If TCP/UDP, extract the port numbers to use in the lookup.
        !           198:                 */
        !           199:                switch (ddst->sen_ip6_proto) {
        !           200:                case IPPROTO_UDP:
        !           201:                case IPPROTO_TCP:
        !           202:                        /* Make sure there's enough data in the packet. */
        !           203:                        if (m->m_pkthdr.len < hlen + 2 * sizeof(u_int16_t)) {
        !           204:                                *error = EINVAL;
        !           205:                                return NULL;
        !           206:                        }
        !           207:
        !           208:                        /*
        !           209:                         * Luckily, the offset of the src/dst ports in
        !           210:                         * both the UDP and TCP headers is the same
        !           211:                         * (first two 16-bit values in the respective
        !           212:                         * headers), so we can just copy them.
        !           213:                         */
        !           214:                        m_copydata(m, hlen, sizeof(u_int16_t),
        !           215:                            (caddr_t) &(ddst->sen_ip6_sport));
        !           216:                        m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t),
        !           217:                            (caddr_t) &(ddst->sen_ip6_dport));
        !           218:                        break;
        !           219:
        !           220:                default:
        !           221:                        ddst->sen_ip6_sport = 0;
        !           222:                        ddst->sen_ip6_dport = 0;
        !           223:                }
        !           224:
        !           225:                break;
        !           226: #endif /* INET6 */
        !           227:
        !           228:        default:
        !           229:                *error = EAFNOSUPPORT;
        !           230:                return NULL;
        !           231:        }
        !           232:
        !           233:        /* Actual SPD lookup. */
        !           234:        rtalloc((struct route *) re);
        !           235:        if (re->re_rt == NULL) {
        !           236:                /*
        !           237:                 * Return whatever the socket requirements are, there are no
        !           238:                 * system-wide policies.
        !           239:                 */
        !           240:                *error = 0;
        !           241:                return ipsp_spd_inp(m, af, hlen, error, direction,
        !           242:                    tdbp, inp, NULL);
        !           243:        }
        !           244:
        !           245:        /* Sanity check. */
        !           246:        if ((re->re_rt->rt_gateway == NULL) ||
        !           247:            (((struct sockaddr_encap *) re->re_rt->rt_gateway)->sen_type !=
        !           248:                SENT_IPSP)) {
        !           249:                RTFREE(re->re_rt);
        !           250:                *error = EHOSTUNREACH;
        !           251:                DPRINTF(("ip_spd_lookup: no gateway in SPD entry!"));
        !           252:                return NULL;
        !           253:        }
        !           254:
        !           255:        ipo = ((struct sockaddr_encap *) (re->re_rt->rt_gateway))->sen_ipsp;
        !           256:        RTFREE(re->re_rt);
        !           257:        if (ipo == NULL) {
        !           258:                *error = EHOSTUNREACH;
        !           259:                DPRINTF(("ip_spd_lookup: no policy attached to SPD entry!"));
        !           260:                return NULL;
        !           261:        }
        !           262:
        !           263:        switch (ipo->ipo_type) {
        !           264:        case IPSP_PERMIT:
        !           265:                *error = 0;
        !           266:                return ipsp_spd_inp(m, af, hlen, error, direction, tdbp,
        !           267:                    inp, ipo);
        !           268:
        !           269:        case IPSP_DENY:
        !           270:                *error = EHOSTUNREACH;
        !           271:                return NULL;
        !           272:
        !           273:        case IPSP_IPSEC_USE:
        !           274:        case IPSP_IPSEC_ACQUIRE:
        !           275:        case IPSP_IPSEC_REQUIRE:
        !           276:        case IPSP_IPSEC_DONTACQ:
        !           277:                /* Nothing more needed here. */
        !           278:                break;
        !           279:
        !           280:        default:
        !           281:                *error = EINVAL;
        !           282:                return NULL;
        !           283:        }
        !           284:
        !           285:        /* Check for non-specific destination in the policy. */
        !           286:        switch (ipo->ipo_dst.sa.sa_family) {
        !           287: #ifdef INET
        !           288:        case AF_INET:
        !           289:                if ((ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_ANY) ||
        !           290:                    (ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_BROADCAST))
        !           291:                        dignore = 1;
        !           292:                break;
        !           293: #endif /* INET */
        !           294:
        !           295: #ifdef INET6
        !           296:        case AF_INET6:
        !           297:                if ((IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_dst.sin6.sin6_addr)) ||
        !           298:                    (bcmp(&ipo->ipo_dst.sin6.sin6_addr, &in6mask128,
        !           299:                        sizeof(in6mask128)) == 0))
        !           300:                        dignore = 1;
        !           301:                break;
        !           302: #endif /* INET6 */
        !           303:        }
        !           304:
        !           305:        /* Likewise for source. */
        !           306:        switch (ipo->ipo_src.sa.sa_family) {
        !           307: #ifdef INET
        !           308:        case AF_INET:
        !           309:                if (ipo->ipo_src.sin.sin_addr.s_addr == INADDR_ANY)
        !           310:                        signore = 1;
        !           311:                break;
        !           312: #endif /* INET */
        !           313:
        !           314: #ifdef INET6
        !           315:        case AF_INET6:
        !           316:                if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_src.sin6.sin6_addr))
        !           317:                        signore = 1;
        !           318:                break;
        !           319: #endif /* INET6 */
        !           320:        }
        !           321:
        !           322:        /* Do we have a cached entry ? If so, check if it's still valid. */
        !           323:        if ((ipo->ipo_tdb) && (ipo->ipo_tdb->tdb_flags & TDBF_INVALID)) {
        !           324:                TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
        !           325:                    ipo_tdb_next);
        !           326:                ipo->ipo_tdb = NULL;
        !           327:        }
        !           328:
        !           329:        /* Outgoing packet policy check. */
        !           330:        if (direction == IPSP_DIRECTION_OUT) {
        !           331:                /*
        !           332:                 * If the packet is destined for the policy-specified
        !           333:                 * gateway/endhost, and the socket has the BYPASS
        !           334:                 * option set, skip IPsec processing.
        !           335:                 */
        !           336:                if ((inp != NULL) &&
        !           337:                    (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) &&
        !           338:                    (inp->inp_seclevel[SL_ESP_NETWORK] ==
        !           339:                        IPSEC_LEVEL_BYPASS) &&
        !           340:                    (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS)) {
        !           341:                        /* Direct match. */
        !           342:                        if (dignore ||
        !           343:                            !bcmp(&sdst, &ipo->ipo_dst, sdst.sa.sa_len)) {
        !           344:                                *error = 0;
        !           345:                                return NULL;
        !           346:                        }
        !           347:                }
        !           348:
        !           349:                /* Check that the cached TDB (if present), is appropriate. */
        !           350:                if (ipo->ipo_tdb) {
        !           351:                        if ((ipo->ipo_last_searched <= ipsec_last_added) ||
        !           352:                            (ipo->ipo_sproto != ipo->ipo_tdb->tdb_sproto) ||
        !           353:                            bcmp(dignore ? &sdst : &ipo->ipo_dst,
        !           354:                                &ipo->ipo_tdb->tdb_dst,
        !           355:                                ipo->ipo_tdb->tdb_dst.sa.sa_len))
        !           356:                                goto nomatchout;
        !           357:
        !           358:                        if (!ipsp_aux_match(ipo->ipo_tdb,
        !           359:                            ipo->ipo_srcid, ipo->ipo_dstid,
        !           360:                            ipo->ipo_local_cred, NULL,
        !           361:                            &ipo->ipo_addr, &ipo->ipo_mask))
        !           362:                                goto nomatchout;
        !           363:
        !           364:                        /* Cached entry is good. */
        !           365:                        *error = 0;
        !           366:                        return ipsp_spd_inp(m, af, hlen, error, direction,
        !           367:                            tdbp, inp, ipo);
        !           368:
        !           369:   nomatchout:
        !           370:                        /* Cached TDB was not good. */
        !           371:                        TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
        !           372:                            ipo_tdb_next);
        !           373:                        ipo->ipo_tdb = NULL;
        !           374:                        ipo->ipo_last_searched = 0;
        !           375:                }
        !           376:
        !           377:                /*
        !           378:                 * If no SA has been added since the last time we did a
        !           379:                 * lookup, there's no point searching for one. However, if the
        !           380:                 * destination gateway is left unspecified (or is all-1's),
        !           381:                 * always lookup since this is a generic-match rule
        !           382:                 * (otherwise, we can have situations where SAs to some
        !           383:                 * destinations exist but are not used, possibly leading to an
        !           384:                 * explosion in the number of acquired SAs).
        !           385:                 */
        !           386:                if (ipo->ipo_last_searched <= ipsec_last_added) {
        !           387:                        /* "Touch" the entry. */
        !           388:                        if (dignore == 0)
        !           389:                                ipo->ipo_last_searched = time_second;
        !           390:
        !           391:                        /* Find an appropriate SA from the existing ones. */
        !           392:                        ipo->ipo_tdb =
        !           393:                            gettdbbyaddr(dignore ? &sdst : &ipo->ipo_dst,
        !           394:                                ipo->ipo_sproto, ipo->ipo_srcid,
        !           395:                                ipo->ipo_dstid, ipo->ipo_local_cred, m, af,
        !           396:                                &ipo->ipo_addr, &ipo->ipo_mask);
        !           397:                        if (ipo->ipo_tdb) {
        !           398:                                TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head,
        !           399:                                    ipo, ipo_tdb_next);
        !           400:                                *error = 0;
        !           401:                                return ipsp_spd_inp(m, af, hlen, error,
        !           402:                                    direction, tdbp, inp, ipo);
        !           403:                        }
        !           404:                }
        !           405:
        !           406:                /* So, we don't have an SA -- just a policy. */
        !           407:                switch (ipo->ipo_type) {
        !           408:                case IPSP_IPSEC_REQUIRE:
        !           409:                        /* Acquire SA through key management. */
        !           410:                        if (ipsp_acquire_sa(ipo,
        !           411:                            dignore ? &sdst : &ipo->ipo_dst,
        !           412:                            signore ? NULL : &ipo->ipo_src, ddst, m) != 0) {
        !           413:                                *error = EACCES;
        !           414:                                return NULL;
        !           415:                        }
        !           416:
        !           417:                        /* FALLTHROUGH */
        !           418:                case IPSP_IPSEC_DONTACQ:
        !           419:                        *error = -EINVAL; /* Silently drop packet. */
        !           420:                        return NULL;
        !           421:
        !           422:                case IPSP_IPSEC_ACQUIRE:
        !           423:                        /* Acquire SA through key management. */
        !           424:                        ipsp_acquire_sa(ipo, dignore ? &sdst : &ipo->ipo_dst,
        !           425:                            signore ? NULL : &ipo->ipo_src, ddst, NULL);
        !           426:
        !           427:                        /* FALLTHROUGH */
        !           428:                case IPSP_IPSEC_USE:
        !           429:                        *error = 0;
        !           430:                        return ipsp_spd_inp(m, af, hlen, error, direction,
        !           431:                            tdbp, inp, ipo);
        !           432:                }
        !           433:        } else { /* IPSP_DIRECTION_IN */
        !           434:                if (tdbp != NULL) {
        !           435:                        /* Direct match in the cache. */
        !           436:                        if (ipo->ipo_tdb == tdbp) {
        !           437:                                *error = 0;
        !           438:                                return ipsp_spd_inp(m, af, hlen, error,
        !           439:                                    direction, tdbp, inp, ipo);
        !           440:                        }
        !           441:
        !           442:                        if (bcmp(dignore ? &ssrc : &ipo->ipo_dst,
        !           443:                            &tdbp->tdb_src, tdbp->tdb_src.sa.sa_len) ||
        !           444:                            (ipo->ipo_sproto != tdbp->tdb_sproto))
        !           445:                                goto nomatchin;
        !           446:
        !           447:                        /* Match source ID. */
        !           448:                        if (ipo->ipo_srcid) {
        !           449:                                if (tdbp->tdb_dstid == NULL ||
        !           450:                                    !ipsp_ref_match(ipo->ipo_srcid,
        !           451:                                        tdbp->tdb_dstid))
        !           452:                                        goto nomatchin;
        !           453:                        }
        !           454:
        !           455:                        /* Match destination ID. */
        !           456:                        if (ipo->ipo_dstid) {
        !           457:                                if (tdbp->tdb_srcid == NULL ||
        !           458:                                    !ipsp_ref_match(ipo->ipo_dstid,
        !           459:                                        tdbp->tdb_srcid))
        !           460:                                        goto nomatchin;
        !           461:                        }
        !           462:
        !           463:                        /* Add it to the cache. */
        !           464:                        if (ipo->ipo_tdb)
        !           465:                                TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head,
        !           466:                                    ipo, ipo_tdb_next);
        !           467:                        ipo->ipo_tdb = tdbp;
        !           468:                        TAILQ_INSERT_TAIL(&tdbp->tdb_policy_head, ipo,
        !           469:                            ipo_tdb_next);
        !           470:                        *error = 0;
        !           471:                        return ipsp_spd_inp(m, af, hlen, error, direction,
        !           472:                            tdbp, inp, ipo);
        !           473:
        !           474:   nomatchin: /* Nothing needed here, falling through */
        !           475:        ;
        !           476:                }
        !           477:
        !           478:                /* Check whether cached entry applies. */
        !           479:                if (ipo->ipo_tdb) {
        !           480:                        /*
        !           481:                         * We only need to check that the correct
        !           482:                         * security protocol and security gateway are
        !           483:                         * set; credentials/IDs will be the same,
        !           484:                         * since the cached entry is linked on this
        !           485:                         * policy.
        !           486:                         */
        !           487:                        if (ipo->ipo_sproto == ipo->ipo_tdb->tdb_sproto &&
        !           488:                            !bcmp(&ipo->ipo_tdb->tdb_src,
        !           489:                                dignore ? &ssrc : &ipo->ipo_dst,
        !           490:                                ipo->ipo_tdb->tdb_src.sa.sa_len))
        !           491:                                goto skipinputsearch;
        !           492:
        !           493:                        /* Not applicable, unlink. */
        !           494:                        TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
        !           495:                            ipo_tdb_next);
        !           496:                        ipo->ipo_last_searched = 0;
        !           497:                        ipo->ipo_tdb = NULL;
        !           498:                }
        !           499:
        !           500:                /* Find whether there exists an appropriate SA. */
        !           501:                if (ipo->ipo_last_searched <= ipsec_last_added) {
        !           502:                        if (dignore == 0)
        !           503:                                ipo->ipo_last_searched = time_second;
        !           504:
        !           505:                        ipo->ipo_tdb =
        !           506:                            gettdbbysrc(dignore ? &ssrc : &ipo->ipo_dst,
        !           507:                                ipo->ipo_sproto, ipo->ipo_srcid,
        !           508:                                ipo->ipo_dstid, m, af, &ipo->ipo_addr,
        !           509:                                &ipo->ipo_mask);
        !           510:                        if (ipo->ipo_tdb)
        !           511:                                TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head,
        !           512:                                    ipo, ipo_tdb_next);
        !           513:                }
        !           514:   skipinputsearch:
        !           515:
        !           516:                switch (ipo->ipo_type) {
        !           517:                case IPSP_IPSEC_REQUIRE:
        !           518:                        /* If appropriate SA exists, don't acquire another. */
        !           519:                        if (ipo->ipo_tdb) {
        !           520:                                *error = -EINVAL;
        !           521:                                return NULL;
        !           522:                        }
        !           523:
        !           524:                        /* Acquire SA through key management. */
        !           525:                        if ((*error = ipsp_acquire_sa(ipo,
        !           526:                            dignore ? &ssrc : &ipo->ipo_dst,
        !           527:                            signore ? NULL : &ipo->ipo_src, ddst, m)) != 0)
        !           528:                                return NULL;
        !           529:
        !           530:                        /* FALLTHROUGH */
        !           531:                case IPSP_IPSEC_DONTACQ:
        !           532:                        /* Drop packet. */
        !           533:                        *error = -EINVAL;
        !           534:                        return NULL;
        !           535:
        !           536:                case IPSP_IPSEC_ACQUIRE:
        !           537:                        /* If appropriate SA exists, don't acquire another. */
        !           538:                        if (ipo->ipo_tdb) {
        !           539:                                *error = 0;
        !           540:                                return ipsp_spd_inp(m, af, hlen, error,
        !           541:                                    direction, tdbp, inp, ipo);
        !           542:                        }
        !           543:
        !           544:                        /* Acquire SA through key management. */
        !           545:                        ipsp_acquire_sa(ipo, dignore ? &ssrc : &ipo->ipo_dst,
        !           546:                            signore ? NULL : &ipo->ipo_src, ddst, NULL);
        !           547:
        !           548:                        /* FALLTHROUGH */
        !           549:                case IPSP_IPSEC_USE:
        !           550:                        *error = 0;
        !           551:                        return ipsp_spd_inp(m, af, hlen, error, direction,
        !           552:                            tdbp, inp, ipo);
        !           553:                }
        !           554:        }
        !           555:
        !           556:        /* Shouldn't ever get this far. */
        !           557:        *error = EINVAL;
        !           558:        return NULL;
        !           559: }
        !           560:
        !           561: /*
        !           562:  * Delete a policy from the SPD.
        !           563:  */
        !           564: int
        !           565: ipsec_delete_policy(struct ipsec_policy *ipo)
        !           566: {
        !           567:        struct ipsec_acquire *ipa;
        !           568:        int err = 0;
        !           569:
        !           570:        if (--ipo->ipo_ref_count > 0)
        !           571:                return 0;
        !           572:
        !           573:        /* Delete from SPD. */
        !           574:        if (!(ipo->ipo_flags & IPSP_POLICY_SOCKET))
        !           575:                err = rtrequest(RTM_DELETE, (struct sockaddr *) &ipo->ipo_addr,
        !           576:                    (struct sockaddr *) 0,
        !           577:                    (struct sockaddr *) &ipo->ipo_mask,
        !           578:                    0, (struct rtentry **) 0, 0);       /* XXX other tables? */
        !           579:
        !           580:        if (ipo->ipo_tdb != NULL)
        !           581:                TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
        !           582:                    ipo_tdb_next);
        !           583:
        !           584:        while ((ipa = TAILQ_FIRST(&ipo->ipo_acquires)) != NULL)
        !           585:                ipsp_delete_acquire(ipa);
        !           586:
        !           587:        TAILQ_REMOVE(&ipsec_policy_head, ipo, ipo_list);
        !           588:
        !           589:        if (ipo->ipo_srcid)
        !           590:                ipsp_reffree(ipo->ipo_srcid);
        !           591:        if (ipo->ipo_dstid)
        !           592:                ipsp_reffree(ipo->ipo_dstid);
        !           593:        if (ipo->ipo_local_cred)
        !           594:                ipsp_reffree(ipo->ipo_local_cred);
        !           595:        if (ipo->ipo_local_auth)
        !           596:                ipsp_reffree(ipo->ipo_local_auth);
        !           597:
        !           598:        pool_put(&ipsec_policy_pool, ipo);
        !           599:
        !           600:        if (!(ipo->ipo_flags & IPSP_POLICY_SOCKET))
        !           601:                ipsec_in_use--;
        !           602:
        !           603:        return err;
        !           604: }
        !           605:
        !           606: /*
        !           607:  * Add a policy to the SPD.
        !           608:  */
        !           609: struct ipsec_policy *
        !           610: ipsec_add_policy(struct inpcb *inp, int af, int direction)
        !           611: {
        !           612:        struct ipsec_policy *ipon;
        !           613:
        !           614:        if (ipsec_policy_pool_initialized == 0) {
        !           615:                ipsec_policy_pool_initialized = 1;
        !           616:                pool_init(&ipsec_policy_pool, sizeof(struct ipsec_policy),
        !           617:                    0, 0, 0, "ipsec policy", NULL);
        !           618:        }
        !           619:
        !           620:        ipon = pool_get(&ipsec_policy_pool, 0);
        !           621:        if (ipon == NULL)
        !           622:                return NULL;
        !           623:
        !           624:        bzero(ipon, sizeof(struct ipsec_policy));
        !           625:
        !           626:        ipon->ipo_ref_count = 1;
        !           627:        ipon->ipo_flags |= IPSP_POLICY_SOCKET;
        !           628:
        !           629:        ipon->ipo_type = IPSP_IPSEC_REQUIRE; /* XXX */
        !           630:
        !           631:        /* XXX
        !           632:         * We should actually be creating a linked list of
        !           633:         * policies (for tunnel/transport and ESP/AH), as needed.
        !           634:         */
        !           635:        ipon->ipo_sproto = IPPROTO_ESP;
        !           636:
        !           637:        TAILQ_INIT(&ipon->ipo_acquires);
        !           638:        TAILQ_INSERT_HEAD(&ipsec_policy_head, ipon, ipo_list);
        !           639:
        !           640:        ipsec_update_policy(inp, ipon, af, direction);
        !           641:
        !           642:        return ipon;
        !           643: }
        !           644:
        !           645: /*
        !           646:  * Update a PCB-attached policy.
        !           647:  */
        !           648: void
        !           649: ipsec_update_policy(struct inpcb *inp, struct ipsec_policy *ipon, int af,
        !           650:     int direction)
        !           651: {
        !           652:        ipon->ipo_addr.sen_len = ipon->ipo_mask.sen_len = SENT_LEN;
        !           653:        ipon->ipo_addr.sen_family = ipon->ipo_mask.sen_family = PF_KEY;
        !           654:        ipon->ipo_src.sa.sa_family = ipon->ipo_dst.sa.sa_family = af;
        !           655:
        !           656:        switch (af) {
        !           657:        case AF_INET:
        !           658: #ifdef INET
        !           659:                ipon->ipo_addr.sen_type = ipon->ipo_mask.sen_type = SENT_IP4;
        !           660:                ipon->ipo_addr.sen_ip_src = inp->inp_laddr;
        !           661:                ipon->ipo_addr.sen_ip_dst = inp->inp_faddr;
        !           662:                ipon->ipo_addr.sen_sport = inp->inp_lport;
        !           663:                ipon->ipo_addr.sen_dport = inp->inp_fport;
        !           664:                ipon->ipo_addr.sen_proto =
        !           665:                    inp->inp_socket->so_proto->pr_protocol;
        !           666:                ipon->ipo_addr.sen_direction = direction;
        !           667:
        !           668:                ipon->ipo_mask.sen_ip_src.s_addr = 0xffffffff;
        !           669:                ipon->ipo_mask.sen_ip_dst.s_addr = 0xffffffff;
        !           670:                ipon->ipo_mask.sen_sport = ipon->ipo_mask.sen_dport = 0xffff;
        !           671:                ipon->ipo_mask.sen_proto = 0xff;
        !           672:                ipon->ipo_mask.sen_direction = direction;
        !           673:
        !           674:                ipon->ipo_src.sa.sa_len = sizeof(struct sockaddr_in);
        !           675:                ipon->ipo_dst.sa.sa_len = sizeof(struct sockaddr_in);
        !           676:                ipon->ipo_src.sin.sin_addr = inp->inp_laddr;
        !           677:                ipon->ipo_dst.sin.sin_addr = inp->inp_faddr;
        !           678: #endif /* INET */
        !           679:                break;
        !           680:
        !           681:        case AF_INET6:
        !           682: #ifdef INET6
        !           683:                ipon->ipo_addr.sen_type = ipon->ipo_mask.sen_type = SENT_IP6;
        !           684:                ipon->ipo_addr.sen_ip6_src = inp->inp_laddr6;
        !           685:                ipon->ipo_addr.sen_ip6_dst = inp->inp_faddr6;
        !           686:                ipon->ipo_addr.sen_ip6_sport = inp->inp_lport;
        !           687:                ipon->ipo_addr.sen_ip6_dport = inp->inp_fport;
        !           688:                ipon->ipo_addr.sen_ip6_proto =
        !           689:                    inp->inp_socket->so_proto->pr_protocol;
        !           690:                ipon->ipo_addr.sen_ip6_direction = direction;
        !           691:
        !           692:                ipon->ipo_mask.sen_ip6_src = in6mask128;
        !           693:                ipon->ipo_mask.sen_ip6_dst = in6mask128;
        !           694:                ipon->ipo_mask.sen_ip6_sport = 0xffff;
        !           695:                ipon->ipo_mask.sen_ip6_dport = 0xffff;
        !           696:                ipon->ipo_mask.sen_ip6_proto = 0xff;
        !           697:                ipon->ipo_mask.sen_ip6_direction = direction;
        !           698:
        !           699:                ipon->ipo_src.sa.sa_len = sizeof(struct sockaddr_in6);
        !           700:                ipon->ipo_dst.sa.sa_len = sizeof(struct sockaddr_in6);
        !           701:                ipon->ipo_src.sin6.sin6_addr = inp->inp_laddr6;
        !           702:                ipon->ipo_dst.sin6.sin6_addr = inp->inp_faddr6;
        !           703: #endif /* INET6 */
        !           704:                break;
        !           705:        }
        !           706: }
        !           707:
        !           708: /*
        !           709:  * Delete a pending IPsec acquire record.
        !           710:  */
        !           711: void
        !           712: ipsp_delete_acquire(void *v)
        !           713: {
        !           714:        struct ipsec_acquire *ipa = v;
        !           715:
        !           716:        timeout_del(&ipa->ipa_timeout);
        !           717:        TAILQ_REMOVE(&ipsec_acquire_head, ipa, ipa_next);
        !           718:        if (ipa->ipa_policy != NULL)
        !           719:                TAILQ_REMOVE(&ipa->ipa_policy->ipo_acquires, ipa,
        !           720:                    ipa_ipo_next);
        !           721:        pool_put(&ipsec_acquire_pool, ipa);
        !           722: }
        !           723:
        !           724: /*
        !           725:  * Find out if there's an ACQUIRE pending.
        !           726:  * XXX Need a better structure.
        !           727:  */
        !           728: struct ipsec_acquire *
        !           729: ipsp_pending_acquire(struct ipsec_policy *ipo, union sockaddr_union *gw)
        !           730: {
        !           731:        struct ipsec_acquire *ipa;
        !           732:
        !           733:        TAILQ_FOREACH (ipa, &ipo->ipo_acquires, ipa_ipo_next) {
        !           734:                if (!bcmp(gw, &ipa->ipa_addr, gw->sa.sa_len))
        !           735:                        return ipa;
        !           736:        }
        !           737:
        !           738:        return NULL;
        !           739: }
        !           740:
        !           741: /*
        !           742:  * Signal key management that we need an SA.
        !           743:  * XXX For outgoing policies, we could try to hold on to the mbuf.
        !           744:  */
        !           745: int
        !           746: ipsp_acquire_sa(struct ipsec_policy *ipo, union sockaddr_union *gw,
        !           747:     union sockaddr_union *laddr, struct sockaddr_encap *ddst, struct mbuf *m)
        !           748: {
        !           749:        struct ipsec_acquire *ipa;
        !           750:
        !           751:        /*
        !           752:         * If this is a socket policy, it has to have authentication
        !           753:         * information accompanying it --- can't tell key mgmt. to
        !           754:         * "find" it for us. This avoids abusing key mgmt. to authenticate
        !           755:         * on an application's behalf, even if the application doesn't
        !           756:         * have/know (and shouldn't) the appropriate authentication
        !           757:         * material (passphrase, private key, etc.)
        !           758:         */
        !           759:        if (ipo->ipo_flags & IPSP_POLICY_SOCKET &&
        !           760:            ipo->ipo_local_auth == NULL)
        !           761:                return EINVAL;
        !           762:
        !           763:        /* Check whether request has been made already. */
        !           764:        if ((ipa = ipsp_pending_acquire(ipo, gw)) != NULL)
        !           765:                return 0;
        !           766:
        !           767:        /* Add request in cache and proceed. */
        !           768:        if (ipsec_acquire_pool_initialized == 0) {
        !           769:                ipsec_acquire_pool_initialized = 1;
        !           770:                pool_init(&ipsec_acquire_pool, sizeof(struct ipsec_acquire),
        !           771:                    0, 0, 0, "ipsec acquire", NULL);
        !           772:        }
        !           773:
        !           774:        ipa = pool_get(&ipsec_acquire_pool, 0);
        !           775:        if (ipa == NULL)
        !           776:                return ENOMEM;
        !           777:
        !           778:        bzero(ipa, sizeof(struct ipsec_acquire));
        !           779:        bcopy(gw, &ipa->ipa_addr, sizeof(union sockaddr_union));
        !           780:
        !           781:        timeout_set(&ipa->ipa_timeout, ipsp_delete_acquire, ipa);
        !           782:
        !           783:        ipa->ipa_info.sen_len = ipa->ipa_mask.sen_len = SENT_LEN;
        !           784:        ipa->ipa_info.sen_family = ipa->ipa_mask.sen_family = PF_KEY;
        !           785:
        !           786:        /* Just copy the right information. */
        !           787:        switch (ipo->ipo_addr.sen_type) {
        !           788: #ifdef INET
        !           789:        case SENT_IP4:
        !           790:                ipa->ipa_info.sen_type = ipa->ipa_mask.sen_type = SENT_IP4;
        !           791:                ipa->ipa_info.sen_direction = ipo->ipo_addr.sen_direction;
        !           792:                ipa->ipa_mask.sen_direction = ipo->ipo_mask.sen_direction;
        !           793:
        !           794:                if (ipo->ipo_mask.sen_ip_src.s_addr == INADDR_ANY ||
        !           795:                    ipo->ipo_addr.sen_ip_src.s_addr == INADDR_ANY ||
        !           796:                    ipsp_is_unspecified(ipo->ipo_dst)) {
        !           797:                        ipa->ipa_info.sen_ip_src = ddst->sen_ip_src;
        !           798:                        ipa->ipa_mask.sen_ip_src.s_addr = INADDR_BROADCAST;
        !           799:                } else {
        !           800:                        ipa->ipa_info.sen_ip_src = ipo->ipo_addr.sen_ip_src;
        !           801:                        ipa->ipa_mask.sen_ip_src = ipo->ipo_mask.sen_ip_src;
        !           802:                }
        !           803:
        !           804:                if (ipo->ipo_mask.sen_ip_dst.s_addr == INADDR_ANY ||
        !           805:                    ipo->ipo_addr.sen_ip_dst.s_addr == INADDR_ANY ||
        !           806:                    ipsp_is_unspecified(ipo->ipo_dst)) {
        !           807:                        ipa->ipa_info.sen_ip_dst = ddst->sen_ip_dst;
        !           808:                        ipa->ipa_mask.sen_ip_dst.s_addr = INADDR_BROADCAST;
        !           809:                } else {
        !           810:                        ipa->ipa_info.sen_ip_dst = ipo->ipo_addr.sen_ip_dst;
        !           811:                        ipa->ipa_mask.sen_ip_dst = ipo->ipo_mask.sen_ip_dst;
        !           812:                }
        !           813:
        !           814:                ipa->ipa_info.sen_proto = ipo->ipo_addr.sen_proto;
        !           815:                ipa->ipa_mask.sen_proto = ipo->ipo_mask.sen_proto;
        !           816:
        !           817:                if (ipo->ipo_addr.sen_proto) {
        !           818:                        ipa->ipa_info.sen_sport = ipo->ipo_addr.sen_sport;
        !           819:                        ipa->ipa_mask.sen_sport = ipo->ipo_mask.sen_sport;
        !           820:
        !           821:                        ipa->ipa_info.sen_dport = ipo->ipo_addr.sen_dport;
        !           822:                        ipa->ipa_mask.sen_dport = ipo->ipo_mask.sen_dport;
        !           823:                }
        !           824:                break;
        !           825: #endif /* INET */
        !           826:
        !           827: #ifdef INET6
        !           828:        case SENT_IP6:
        !           829:                ipa->ipa_info.sen_type = ipa->ipa_mask.sen_type = SENT_IP6;
        !           830:                ipa->ipa_info.sen_ip6_direction =
        !           831:                    ipo->ipo_addr.sen_ip6_direction;
        !           832:                ipa->ipa_mask.sen_ip6_direction =
        !           833:                    ipo->ipo_mask.sen_ip6_direction;
        !           834:
        !           835:                if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_mask.sen_ip6_src) ||
        !           836:                    IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_addr.sen_ip6_src) ||
        !           837:                    ipsp_is_unspecified(ipo->ipo_dst)) {
        !           838:                        ipa->ipa_info.sen_ip6_src = ddst->sen_ip6_src;
        !           839:                        ipa->ipa_mask.sen_ip6_src = in6mask128;
        !           840:                } else {
        !           841:                        ipa->ipa_info.sen_ip6_src = ipo->ipo_addr.sen_ip6_src;
        !           842:                        ipa->ipa_mask.sen_ip6_src = ipo->ipo_mask.sen_ip6_src;
        !           843:                }
        !           844:
        !           845:                if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_mask.sen_ip6_dst) ||
        !           846:                    IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_addr.sen_ip6_dst) ||
        !           847:                    ipsp_is_unspecified(ipo->ipo_dst)) {
        !           848:                        ipa->ipa_info.sen_ip6_dst = ddst->sen_ip6_dst;
        !           849:                        ipa->ipa_mask.sen_ip6_dst = in6mask128;
        !           850:                } else {
        !           851:                        ipa->ipa_info.sen_ip6_dst = ipo->ipo_addr.sen_ip6_dst;
        !           852:                        ipa->ipa_mask.sen_ip6_dst = ipo->ipo_mask.sen_ip6_dst;
        !           853:                }
        !           854:
        !           855:                ipa->ipa_info.sen_ip6_proto = ipo->ipo_addr.sen_ip6_proto;
        !           856:                ipa->ipa_mask.sen_ip6_proto = ipo->ipo_mask.sen_ip6_proto;
        !           857:
        !           858:                if (ipo->ipo_mask.sen_ip6_proto) {
        !           859:                        ipa->ipa_info.sen_ip6_sport =
        !           860:                            ipo->ipo_addr.sen_ip6_sport;
        !           861:                        ipa->ipa_mask.sen_ip6_sport =
        !           862:                            ipo->ipo_mask.sen_ip6_sport;
        !           863:                        ipa->ipa_info.sen_ip6_dport =
        !           864:                            ipo->ipo_addr.sen_ip6_dport;
        !           865:                        ipa->ipa_mask.sen_ip6_dport =
        !           866:                            ipo->ipo_mask.sen_ip6_dport;
        !           867:                }
        !           868:                break;
        !           869: #endif /* INET6 */
        !           870:
        !           871:        default:
        !           872:                pool_put(&ipsec_acquire_pool, ipa);
        !           873:                return 0;
        !           874:        }
        !           875:
        !           876:        timeout_add(&ipa->ipa_timeout, ipsec_expire_acquire * hz);
        !           877:
        !           878:        TAILQ_INSERT_TAIL(&ipsec_acquire_head, ipa, ipa_next);
        !           879:        TAILQ_INSERT_TAIL(&ipo->ipo_acquires, ipa, ipa_ipo_next);
        !           880:        ipa->ipa_policy = ipo;
        !           881:
        !           882:        /* PF_KEYv2 notification message. */
        !           883:        return pfkeyv2_acquire(ipo, gw, laddr, &ipa->ipa_seq, ddst);
        !           884: }
        !           885:
        !           886: /*
        !           887:  * Deal with PCB security requirements.
        !           888:  */
        !           889: struct tdb *
        !           890: ipsp_spd_inp(struct mbuf *m, int af, int hlen, int *error, int direction,
        !           891:     struct tdb *tdbp, struct inpcb *inp, struct ipsec_policy *ipo)
        !           892: {
        !           893:        struct ipsec_policy sipon;
        !           894:        struct tdb_ident *tdbi;
        !           895:        struct m_tag *mtag;
        !           896:        struct tdb *tdb = NULL;
        !           897:
        !           898:        /* Sanity check. */
        !           899:        if (inp == NULL)
        !           900:                goto justreturn;
        !           901:
        !           902:        /* Verify that we need to check for socket policy. */
        !           903:        if ((inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS ||
        !           904:            inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_NONE) &&
        !           905:            (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS ||
        !           906:            inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_NONE) &&
        !           907:            (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS ||
        !           908:            inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_NONE))
        !           909:                goto justreturn;
        !           910:
        !           911:        switch (direction) {
        !           912:        case IPSP_DIRECTION_IN:
        !           913:                /*
        !           914:                 * Some further checking: if the socket has specified
        !           915:                 * that it will accept unencrypted traffic, don't
        !           916:                 * bother checking any further -- just accept the packet.
        !           917:                 */
        !           918:                if ((inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_AVAIL ||
        !           919:                    inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_USE) &&
        !           920:                    (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_AVAIL ||
        !           921:                    inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_USE) &&
        !           922:                    (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_AVAIL ||
        !           923:                    inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_USE))
        !           924:                        goto justreturn;
        !           925:
        !           926:                /* Initialize socket policy if unset. */
        !           927:                if (inp->inp_ipo == NULL) {
        !           928:                        inp->inp_ipo = ipsec_add_policy(inp, af,
        !           929:                            IPSP_DIRECTION_OUT);
        !           930:                        if (inp->inp_ipo == NULL) {
        !           931:                                *error = ENOBUFS;
        !           932:                                return NULL;
        !           933:                        }
        !           934:                }
        !           935:
        !           936:                /*
        !           937:                 * So we *must* have protected traffic. Let's see what
        !           938:                 * we have received then.
        !           939:                 */
        !           940:                if (inp->inp_tdb_in != NULL) {
        !           941:                        if (inp->inp_tdb_in == tdbp)
        !           942:                                goto justreturn; /* We received packet under a
        !           943:                                                  * previously-accepted TDB. */
        !           944:
        !           945:                        /*
        !           946:                         * We should be receiving protected traffic, and
        !           947:                         * have an SA in place, but packet was received
        !           948:                         * unprotected. Simply discard.
        !           949:                         */
        !           950:                        if (tdbp == NULL) {
        !           951:                                *error = -EINVAL;
        !           952:                                return NULL;
        !           953:                        }
        !           954:
        !           955:                        /* Update, since we may need all the relevant info. */
        !           956:                        ipsec_update_policy(inp, inp->inp_ipo, af,
        !           957:                            IPSP_DIRECTION_OUT);
        !           958:
        !           959:                        /*
        !           960:                         * Check that the TDB the packet was received under
        !           961:                         * is acceptable under the socket policy. If so,
        !           962:                         * accept the packet; otherwise, discard.
        !           963:                         */
        !           964:                        if (tdbp->tdb_sproto == inp->inp_ipo->ipo_sproto &&
        !           965:                            !bcmp(&tdbp->tdb_src, &inp->inp_ipo->ipo_dst,
        !           966:                                SA_LEN(&tdbp->tdb_src.sa)) &&
        !           967:                            ipsp_aux_match(tdbp,
        !           968:                                inp->inp_ipo->ipo_srcid,
        !           969:                                inp->inp_ipo->ipo_dstid,
        !           970:                                NULL, NULL,
        !           971:                                &inp->inp_ipo->ipo_addr,
        !           972:                                &inp->inp_ipo->ipo_mask))
        !           973:                                goto justreturn;
        !           974:                        else {
        !           975:                                *error = -EINVAL;
        !           976:                                return NULL;
        !           977:                        }
        !           978:                } else {
        !           979:                        /* Update, since we may need all the relevant info. */
        !           980:                        ipsec_update_policy(inp, inp->inp_ipo, af,
        !           981:                            IPSP_DIRECTION_OUT);
        !           982:
        !           983:                        /*
        !           984:                         * If the packet was received under an SA, see if
        !           985:                         * it's acceptable under socket policy. If it is,
        !           986:                         * accept the packet.
        !           987:                         */
        !           988:                        if (tdbp != NULL &&
        !           989:                            tdbp->tdb_sproto == inp->inp_ipo->ipo_sproto &&
        !           990:                            !bcmp(&tdbp->tdb_src, &inp->inp_ipo->ipo_dst,
        !           991:                                SA_LEN(&tdbp->tdb_src.sa)) &&
        !           992:                            ipsp_aux_match(tdbp,
        !           993:                                inp->inp_ipo->ipo_srcid,
        !           994:                                inp->inp_ipo->ipo_dstid,
        !           995:                                NULL, NULL,
        !           996:                                &inp->inp_ipo->ipo_addr,
        !           997:                                &inp->inp_ipo->ipo_mask))
        !           998:                                goto justreturn;
        !           999:
        !          1000:                        /*
        !          1001:                         * If the packet was not received under an SA, or
        !          1002:                         * if the SA it was received under is not acceptable,
        !          1003:                         * see if we already have an acceptable SA
        !          1004:                         * established. If we do, discard packet.
        !          1005:                         */
        !          1006:                        if (inp->inp_ipo->ipo_last_searched <=
        !          1007:                            ipsec_last_added) {
        !          1008:                                inp->inp_ipo->ipo_last_searched = time_second;
        !          1009:
        !          1010:                                /* Do we have an SA already established ? */
        !          1011:                                if (gettdbbysrc(&inp->inp_ipo->ipo_dst,
        !          1012:                                    inp->inp_ipo->ipo_sproto,
        !          1013:                                    inp->inp_ipo->ipo_srcid,
        !          1014:                                    inp->inp_ipo->ipo_dstid, m, af,
        !          1015:                                    &inp->inp_ipo->ipo_addr,
        !          1016:                                    &inp->inp_ipo->ipo_mask) != NULL) {
        !          1017:                                        *error = -EINVAL;
        !          1018:                                        return NULL;
        !          1019:                                }
        !          1020:                                /* Fall through */
        !          1021:                        }
        !          1022:
        !          1023:                        /*
        !          1024:                         * If we don't have an appropriate SA, acquire one
        !          1025:                         * and discard the packet.
        !          1026:                         */
        !          1027:                        ipsp_acquire_sa(inp->inp_ipo, &inp->inp_ipo->ipo_dst,
        !          1028:                            &inp->inp_ipo->ipo_src, &inp->inp_ipo->ipo_addr, m);
        !          1029:                        *error = -EINVAL;
        !          1030:                        return NULL;
        !          1031:                }
        !          1032:
        !          1033:                break;
        !          1034:
        !          1035:        case IPSP_DIRECTION_OUT:
        !          1036:                /* Do we have a cached entry ? */
        !          1037:                if (inp->inp_tdb_out != NULL) {
        !          1038:                        /*
        !          1039:                         * If we also have to apply a different TDB as
        !          1040:                         * a result of a system-wide policy, add a tag
        !          1041:                         * to the packet.
        !          1042:                         */
        !          1043:                        if (ipo != NULL && m != NULL &&
        !          1044:                            ipo->ipo_tdb != NULL &&
        !          1045:                            ipo->ipo_tdb != inp->inp_tdb_out) {
        !          1046:                                tdb = inp->inp_tdb_out;
        !          1047:                                goto tagandreturn;
        !          1048:                        } else
        !          1049:                                return inp->inp_tdb_out;
        !          1050:                }
        !          1051:
        !          1052:                /*
        !          1053:                 * We need to either find an SA with the appropriate
        !          1054:                 * characteristics and link it to the PCB, or acquire
        !          1055:                 * one.
        !          1056:                 */
        !          1057:                /* XXX Only support one policy/protocol for now. */
        !          1058:                if (inp->inp_ipo != NULL) {
        !          1059:                        if (inp->inp_ipo->ipo_last_searched <=
        !          1060:                            ipsec_last_added) {
        !          1061:                                inp->inp_ipo->ipo_last_searched = time_second;
        !          1062:
        !          1063:                                /* Update, just in case. */
        !          1064:                                ipsec_update_policy(inp, inp->inp_ipo, af,
        !          1065:                                    IPSP_DIRECTION_OUT);
        !          1066:
        !          1067:                                tdb = gettdbbyaddr(&inp->inp_ipo->ipo_dst,
        !          1068:                                    inp->inp_ipo->ipo_sproto,
        !          1069:                                    inp->inp_ipo->ipo_srcid,
        !          1070:                                    inp->inp_ipo->ipo_dstid,
        !          1071:                                    inp->inp_ipo->ipo_local_cred, m, af,
        !          1072:                                    &inp->inp_ipo->ipo_addr,
        !          1073:                                    &inp->inp_ipo->ipo_mask);
        !          1074:                        }
        !          1075:                } else {
        !          1076:                        /*
        !          1077:                         * Construct a pseudo-policy, with just the necessary
        !          1078:                         * fields.
        !          1079:                         */
        !          1080:                        ipsec_update_policy(inp, &sipon, af,
        !          1081:                            IPSP_DIRECTION_OUT);
        !          1082:
        !          1083:                        tdb = gettdbbyaddr(&sipon.ipo_dst, IPPROTO_ESP, NULL,
        !          1084:                            NULL, NULL, m, af, &sipon.ipo_addr,
        !          1085:                            &sipon.ipo_mask);
        !          1086:                }
        !          1087:
        !          1088:                /* If we found an appropriate SA... */
        !          1089:                if (tdb != NULL) {
        !          1090:                        tdb_add_inp(tdb, inp, 0); /* Latch onto PCB. */
        !          1091:
        !          1092:                        if (ipo != NULL && ipo->ipo_tdb != NULL &&
        !          1093:                            ipo->ipo_tdb != inp->inp_tdb_out && m != NULL)
        !          1094:                                goto tagandreturn;
        !          1095:                        else
        !          1096:                                return tdb;
        !          1097:                } else {
        !          1098:                        /* Do we need to acquire one ? */
        !          1099:                        switch (inp->inp_seclevel[SL_ESP_TRANS]) {
        !          1100:                        case IPSEC_LEVEL_BYPASS:
        !          1101:                        case IPSEC_LEVEL_AVAIL:
        !          1102:                                /* No need to do anything. */
        !          1103:                                goto justreturn;
        !          1104:                        case IPSEC_LEVEL_USE:
        !          1105:                        case IPSEC_LEVEL_REQUIRE:
        !          1106:                        case IPSEC_LEVEL_UNIQUE:
        !          1107:                                /* Initialize socket policy if unset. */
        !          1108:                                if (inp->inp_ipo == NULL) {
        !          1109:                                        inp->inp_ipo = ipsec_add_policy(inp, af, IPSP_DIRECTION_OUT);
        !          1110:                                        if (inp->inp_ipo == NULL) {
        !          1111:                                                *error = ENOBUFS;
        !          1112:                                                return NULL;
        !          1113:                                        }
        !          1114:                                }
        !          1115:
        !          1116:                                /* Acquire a new SA. */
        !          1117:                                if ((*error = ipsp_acquire_sa(inp->inp_ipo,
        !          1118:                                    &inp->inp_ipo->ipo_dst,
        !          1119:                                    &inp->inp_ipo->ipo_src,
        !          1120:                                    &inp->inp_ipo->ipo_addr, m)) == 0)
        !          1121:                                        *error = -EINVAL;
        !          1122:
        !          1123:                                return NULL;
        !          1124:                        default:
        !          1125:                                DPRINTF(("ipsp_spd_inp: unknown sock security"
        !          1126:                                    " level %d",
        !          1127:                                    inp->inp_seclevel[SL_ESP_TRANS]));
        !          1128:                                *error = -EINVAL;
        !          1129:                                return NULL;
        !          1130:                        }
        !          1131:                }
        !          1132:                break;
        !          1133:
        !          1134:        default:  /* Should never happen. */
        !          1135:                *error = -EINVAL;
        !          1136:                return NULL;
        !          1137:        }
        !          1138:
        !          1139:  tagandreturn:
        !          1140:        if (tdb == NULL)
        !          1141:                goto justreturn;
        !          1142:
        !          1143:        mtag = m_tag_get(PACKET_TAG_IPSEC_PENDING_TDB,
        !          1144:            sizeof (struct tdb_ident), M_NOWAIT);
        !          1145:        if (mtag == NULL) {
        !          1146:                *error = ENOMEM;
        !          1147:                return NULL;
        !          1148:        }
        !          1149:
        !          1150:        tdbi = (struct tdb_ident *)(mtag + 1);
        !          1151:        tdbi->spi = ipo->ipo_tdb->tdb_spi;
        !          1152:        tdbi->proto = ipo->ipo_tdb->tdb_sproto;
        !          1153:        bcopy(&ipo->ipo_tdb->tdb_dst, &tdbi->dst,
        !          1154:            ipo->ipo_tdb->tdb_dst.sa.sa_len);
        !          1155:        m_tag_prepend(m, mtag);
        !          1156:        return tdb;
        !          1157:
        !          1158:  justreturn:
        !          1159:        if (ipo != NULL)
        !          1160:                return ipo->ipo_tdb;
        !          1161:        else
        !          1162:                return NULL;
        !          1163: }
        !          1164:
        !          1165: /*
        !          1166:  * Find a pending ACQUIRE record based on its sequence number.
        !          1167:  * XXX Need to use a better data structure.
        !          1168:  */
        !          1169: struct ipsec_acquire *
        !          1170: ipsec_get_acquire(u_int32_t seq)
        !          1171: {
        !          1172:        struct ipsec_acquire *ipa;
        !          1173:
        !          1174:        TAILQ_FOREACH (ipa, &ipsec_acquire_head, ipa_next)
        !          1175:                if (ipa->ipa_seq == seq)
        !          1176:                        return ipa;
        !          1177:
        !          1178:        return NULL;
        !          1179: }

CVSweb