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