1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stream.h> 30 #include <sys/sunddi.h> 31 #include <sys/strlog.h> 32 33 #include <inet/common.h> 34 #include <inet/mib2.h> 35 #include <inet/ip.h> 36 #include <inet/ip6.h> 37 #include <inet/ipdrop.h> 38 39 #include <net/pfkeyv2.h> 40 #include <inet/ipsec_info.h> 41 #include <inet/sadb.h> 42 #include <inet/ipsec_impl.h> 43 #include <inet/ipsecesp.h> 44 #include <inet/ipsecah.h> 45 #include <sys/kstat.h> 46 47 /* stats */ 48 static kstat_t *ipsec_ksp; 49 ipsec_kstats_t *ipsec_kstats; 50 51 /* The IPsec SADBs for AH and ESP */ 52 sadbp_t ah_sadb, esp_sadb; 53 54 /* Packet dropper for IP IPsec processing failures */ 55 extern ipdropper_t ip_dropper; 56 57 void 58 ipsec_kstat_init(void) 59 { 60 ipsec_ksp = kstat_create("ip", 0, "ipsec_stat", "net", 61 KSTAT_TYPE_NAMED, sizeof (*ipsec_kstats) / sizeof (kstat_named_t), 62 KSTAT_FLAG_PERSISTENT); 63 64 ASSERT(ipsec_ksp != NULL); 65 66 ipsec_kstats = ipsec_ksp->ks_data; 67 68 #define KI(x) kstat_named_init(&ipsec_kstats->x, #x, KSTAT_DATA_UINT64) 69 KI(esp_stat_in_requests); 70 KI(esp_stat_in_discards); 71 KI(esp_stat_lookup_failure); 72 KI(ah_stat_in_requests); 73 KI(ah_stat_in_discards); 74 KI(ah_stat_lookup_failure); 75 KI(sadb_acquire_maxpackets); 76 KI(sadb_acquire_qhiwater); 77 #undef KI 78 79 kstat_install(ipsec_ksp); 80 } 81 82 void 83 ipsec_kstat_destroy(void) 84 { 85 kstat_delete(ipsec_ksp); 86 } 87 88 /* 89 * Returns B_TRUE if the identities in the SA match the identities 90 * in the "latch" structure. 91 */ 92 93 static boolean_t 94 ipsec_match_outbound_ids(ipsec_latch_t *ipl, ipsa_t *sa) 95 { 96 ASSERT(ipl->ipl_ids_latched == B_TRUE); 97 return ipsid_equal(ipl->ipl_local_cid, sa->ipsa_src_cid) && 98 ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid); 99 } 100 101 /* 102 * Look up a security association based on the unique ID generated by IP and 103 * transport information, such as ports and upper-layer protocol, and the 104 * address(es). Used for uniqueness testing and outbound packets. The 105 * source address may be ignored. 106 * 107 * I expect an SA hash bucket, and that its per-bucket mutex is held. 108 * The SA ptr I return will have its reference count incremented by one. 109 */ 110 ipsa_t * 111 ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src, 112 uint32_t *dst, sa_family_t af, uint8_t protocol) 113 { 114 ipsa_t *retval, *candidate; 115 ipsec_action_t *candact; 116 boolean_t need_unique; 117 uint64_t unique_id; 118 uint32_t old_flags, excludeflags; 119 ipsec_policy_t *pp = io->ipsec_out_policy; 120 ipsec_action_t *actlist = io->ipsec_out_act; 121 ipsec_action_t *act; 122 ipsec_latch_t *ipl = io->ipsec_out_latch; 123 ipsa_ref_t *ipr = NULL; 124 125 ASSERT(MUTEX_HELD(&bucket->isaf_lock)); 126 127 /* 128 * Fast path: do we have a latch structure, is it for this bucket, 129 * and does the generation number match? If so, refhold and return. 130 */ 131 132 if (ipl != NULL) { 133 ASSERT((protocol == IPPROTO_AH) || (protocol == IPPROTO_ESP)); 134 ipr = &ipl->ipl_ref[protocol - IPPROTO_ESP]; 135 136 retval = ipr->ipsr_sa; 137 138 /* 139 * NOTE: The isaf_gen check (incremented upon 140 * sadb_unlinkassoc()) protects against retval being a freed 141 * SA. (We're exploiting short-circuit evaluation.) 142 */ 143 if ((bucket == ipr->ipsr_bucket) && 144 (bucket->isaf_gen == ipr->ipsr_gen) && 145 (retval->ipsa_state != IPSA_STATE_DEAD) && 146 !(retval->ipsa_flags & IPSA_F_CINVALID)) { 147 IPSA_REFHOLD(retval); 148 return (retval); 149 } 150 } 151 152 ASSERT((pp != NULL) || (actlist != NULL)); 153 if (actlist == NULL) 154 actlist = pp->ipsp_act; 155 ASSERT(actlist != NULL); 156 157 need_unique = actlist->ipa_want_unique; 158 unique_id = SA_FORM_UNIQUE_ID(io); 159 160 /* 161 * Precompute mask for SA flags comparison: If we need a 162 * unique SA and an SA has already been used, or if the SA has 163 * a unique value which doesn't match, we aren't interested in 164 * the SA.. 165 */ 166 167 excludeflags = IPSA_F_UNIQUE; 168 if (need_unique) 169 excludeflags |= IPSA_F_USED; 170 171 /* 172 * Walk the hash bucket, matching on: 173 * 174 * - unique_id 175 * - destination 176 * - source 177 * - algorithms 178 * - <MORE TBD> 179 * 180 * Make sure that wildcard sources are inserted at the end of the hash 181 * bucket. 182 * 183 * DEFINITIONS: A _shared_ SA is one with unique_id == 0 and USED. 184 * An _unused_ SA is one with unique_id == 0 and not USED. 185 * A _unique_ SA is one with unique_id != 0 and USED. 186 * An SA with unique_id != 0 and not USED never happens. 187 */ 188 189 candidate = NULL; 190 191 for (retval = bucket->isaf_ipsa; retval != NULL; 192 retval = retval->ipsa_next) { 193 ASSERT((candidate == NULL) || 194 MUTEX_HELD(&candidate->ipsa_lock)); 195 196 /* 197 * Q: Should I lock this SA? 198 * A: For now, yes. I change and use too many fields in here 199 * (e.g. unique_id) that I may be racing with other threads. 200 * Also, the refcnt needs to be bumped up. 201 */ 202 203 mutex_enter(&retval->ipsa_lock); 204 205 /* My apologies for the use of goto instead of continue. */ 206 if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af)) 207 goto next_ipsa; /* Destination mismatch. */ 208 if (!IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) && 209 !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) 210 goto next_ipsa; /* Specific source and not matched. */ 211 212 /* 213 * XXX should be able to use cached/latched action 214 * to dodge this loop 215 */ 216 for (act = actlist; act != NULL; act = act->ipa_next) { 217 ipsec_act_t *ap = &act->ipa_act; 218 if (ap->ipa_type != IPSEC_POLICY_APPLY) 219 continue; 220 221 /* 222 * XXX ugly. should be better way to do this test 223 */ 224 if (protocol == IPPROTO_AH) { 225 if (!(ap->ipa_apply.ipp_use_ah)) 226 continue; 227 if (ap->ipa_apply.ipp_auth_alg != 228 retval->ipsa_auth_alg) 229 continue; 230 if (ap->ipa_apply.ipp_ah_minbits > 231 retval->ipsa_authkeybits) 232 continue; 233 } else { 234 if (!(ap->ipa_apply.ipp_use_esp)) 235 continue; 236 237 if ((ap->ipa_apply.ipp_encr_alg != 238 retval->ipsa_encr_alg)) 239 continue; 240 241 if (ap->ipa_apply.ipp_espe_minbits > 242 retval->ipsa_encrkeybits) 243 continue; 244 245 if (ap->ipa_apply.ipp_esp_auth_alg != 0) { 246 if (ap->ipa_apply.ipp_esp_auth_alg != 247 retval->ipsa_auth_alg) 248 continue; 249 if (ap->ipa_apply.ipp_espa_minbits > 250 retval->ipsa_authkeybits) 251 continue; 252 } 253 } 254 255 /* 256 * Check key mgmt proto, cookie 257 */ 258 if ((ap->ipa_apply.ipp_km_proto != 0) && 259 (retval->ipsa_kmp != 0) && 260 (ap->ipa_apply.ipp_km_proto != retval->ipsa_kmp)) 261 continue; 262 263 if ((ap->ipa_apply.ipp_km_cookie != 0) && 264 (retval->ipsa_kmc != 0) && 265 (ap->ipa_apply.ipp_km_cookie != retval->ipsa_kmc)) 266 continue; 267 268 break; 269 } 270 if (act == NULL) 271 goto next_ipsa; /* nothing matched */ 272 273 /* 274 * Do identities match? 275 */ 276 if (ipl && ipl->ipl_ids_latched && 277 !ipsec_match_outbound_ids(ipl, retval)) 278 goto next_ipsa; 279 280 /* 281 * At this point, we know that we have at least a match on: 282 * 283 * - dest 284 * - source (if source is specified, i.e. non-zeroes) 285 * - auth alg (if auth alg is specified, i.e. non-zero) 286 * - encrypt. alg (if encrypt. alg is specified, i.e. non-zero) 287 * and we know that the SA keylengths are appropriate. 288 * 289 * (Keep in mind known-src SAs are hit before zero-src SAs, 290 * thanks to sadb_insertassoc().) 291 * If we need a unique asssociation, optimally we have 292 * ipsa_unique_id == unique_id, otherwise NOT USED 293 * is held in reserve (stored in candidate). 294 * 295 * For those stored in candidate, take best-match (i.e. given 296 * a choice, candidate should have non-zero ipsa_src). 297 */ 298 299 /* 300 * If SA has a unique value which matches, we're all set... 301 * "key management knows best" 302 */ 303 if ((retval->ipsa_flags & IPSA_F_UNIQUE) && 304 ((unique_id & retval->ipsa_unique_mask) == 305 retval->ipsa_unique_id)) 306 break; 307 308 /* 309 * If we need a unique SA and this SA has already been used, 310 * or if the SA has a unique value which doesn't match, 311 * this isn't for us. 312 */ 313 314 if (retval->ipsa_flags & excludeflags) 315 goto next_ipsa; 316 317 318 /* 319 * I found a candidate.. 320 */ 321 if (candidate == NULL) { 322 /* 323 * and didn't already have one.. 324 */ 325 candidate = retval; 326 candact = act; 327 continue; 328 } else { 329 /* 330 * If candidate's source address is zero and 331 * the current match (i.e. retval) address is 332 * not zero, we have a better candidate.. 333 */ 334 if (IPSA_IS_ADDR_UNSPEC(candidate->ipsa_srcaddr, af) && 335 !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) { 336 mutex_exit(&candidate->ipsa_lock); 337 candidate = retval; 338 candact = act; 339 continue; 340 } 341 } 342 next_ipsa: 343 mutex_exit(&retval->ipsa_lock); 344 } 345 ASSERT((retval == NULL) || MUTEX_HELD(&retval->ipsa_lock)); 346 ASSERT((candidate == NULL) || MUTEX_HELD(&candidate->ipsa_lock)); 347 ASSERT((retval == NULL) || (act != NULL)); 348 ASSERT((candidate == NULL) || (candact != NULL)); 349 350 /* Let caller react to a lookup failure when it gets NULL. */ 351 if (retval == NULL && candidate == NULL) 352 return (NULL); 353 354 if (retval == NULL) { 355 ASSERT(MUTEX_HELD(&candidate->ipsa_lock)); 356 retval = candidate; 357 act = candact; 358 } else if (candidate != NULL) { 359 mutex_exit(&candidate->ipsa_lock); 360 } 361 ASSERT(MUTEX_HELD(&retval->ipsa_lock)); 362 ASSERT(act != NULL); 363 364 /* 365 * Even though I hold the mutex, since the reference counter is an 366 * atomic operation, I really have to use the IPSA_REFHOLD macro. 367 */ 368 IPSA_REFHOLD(retval); 369 370 /* 371 * This association is no longer unused. 372 */ 373 old_flags = retval->ipsa_flags; 374 retval->ipsa_flags |= IPSA_F_USED; 375 376 /* 377 * Cache a reference to this SA for the fast path. 378 */ 379 if (ipr != NULL) { 380 ipr->ipsr_bucket = bucket; 381 ipr->ipsr_gen = bucket->isaf_gen; 382 ipr->ipsr_sa = retval; 383 /* I'm now caching, so the cache-invalid flag goes away! */ 384 retval->ipsa_flags &= ~IPSA_F_CINVALID; 385 } 386 /* 387 * Latch various things while we're here.. 388 */ 389 if (ipl != NULL) { 390 if (!ipl->ipl_ids_latched) { 391 ipsec_latch_ids(ipl, 392 retval->ipsa_src_cid, retval->ipsa_dst_cid); 393 } 394 if (!ipl->ipl_out_action_latched) { 395 IPACT_REFHOLD(act); 396 ipl->ipl_out_action = act; 397 ipl->ipl_out_action_latched = B_TRUE; 398 } 399 } 400 401 /* 402 * Set the uniqueness only first time. 403 */ 404 if (need_unique && !(old_flags & IPSA_F_USED)) { 405 if (retval->ipsa_unique_id == 0) { 406 ASSERT((retval->ipsa_flags & IPSA_F_UNIQUE) == 0); 407 /* 408 * From now on, only this src, dst[ports, addr], 409 * proto, should use it. 410 */ 411 retval->ipsa_flags |= IPSA_F_UNIQUE; 412 retval->ipsa_unique_id = unique_id; 413 retval->ipsa_unique_mask = SA_UNIQUE_MASK( 414 io->ipsec_out_src_port, io->ipsec_out_dst_port, 415 protocol); 416 } 417 418 /* 419 * Set the source address and adjust the hash 420 * buckets only if src_addr is zero. 421 */ 422 if (IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) { 423 /* 424 * sadb_unlinkassoc() will decrement the refcnt. Bump 425 * up when we have the lock so that we don't have to 426 * acquire locks when we come back from 427 * sadb_insertassoc(). 428 * 429 * We don't need to bump the bucket's gen since 430 * we aren't moving to a new bucket. 431 */ 432 IPSA_REFHOLD(retval); 433 IPSA_COPY_ADDR(retval->ipsa_srcaddr, src, af); 434 mutex_exit(&retval->ipsa_lock); 435 sadb_unlinkassoc(retval); 436 /* 437 * Since the bucket lock is held, we know 438 * sadb_insertassoc() will succeed. 439 */ 440 #ifdef DEBUG 441 if (sadb_insertassoc(retval, bucket) != 0) { 442 cmn_err(CE_PANIC, 443 "sadb_insertassoc() failed in " 444 "ipsec_getassocbyconn().\n"); 445 } 446 #else /* non-DEBUG */ 447 (void) sadb_insertassoc(retval, bucket); 448 #endif /* DEBUG */ 449 return (retval); 450 } 451 } 452 mutex_exit(&retval->ipsa_lock); 453 454 return (retval); 455 } 456 457 /* 458 * Look up a security association based on the security parameters index (SPI) 459 * and address(es). This is used for inbound packets and general SA lookups 460 * (even in outbound SA tables). The source address may be ignored. Return 461 * NULL if no association is available. If an SA is found, return it, with 462 * its refcnt incremented. The caller must REFRELE after using the SA. 463 * The hash bucket must be locked down before calling. 464 */ 465 ipsa_t * 466 ipsec_getassocbyspi(isaf_t *bucket, uint32_t spi, uint32_t *src, uint32_t *dst, 467 sa_family_t af) 468 { 469 ipsa_t *retval; 470 471 ASSERT(MUTEX_HELD(&bucket->isaf_lock)); 472 473 /* 474 * Walk the hash bucket, matching exactly on SPI, then destination, 475 * then source. 476 * 477 * Per-SA locking doesn't need to happen, because I'm only matching 478 * on addresses. Addresses are only changed during insertion/deletion 479 * from the hash bucket. Since the hash bucket lock is held, we don't 480 * need to worry about addresses changing. 481 */ 482 483 for (retval = bucket->isaf_ipsa; retval != NULL; 484 retval = retval->ipsa_next) { 485 if (retval->ipsa_spi != spi) 486 continue; 487 if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af)) 488 continue; 489 490 /* 491 * Assume that wildcard source addresses are inserted at the 492 * end of the hash bucket. (See sadb_insertassoc().) 493 * The following check for source addresses is a weak form 494 * of access control/source identity verification. If an 495 * SA has a source address, I only match an all-zeroes 496 * source address, or that particular one. If the SA has 497 * an all-zeroes source, then I match regardless. 498 * 499 * There is a weakness here in that a packet with all-zeroes 500 * for an address will match regardless of the source address 501 * stored in the packet. 502 * 503 * Note that port-level packet selectors, if present, 504 * are checked in ipsec_check_ipsecin_unique(). 505 */ 506 if (IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) || 507 IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af) || 508 IPSA_IS_ADDR_UNSPEC(src, af)) 509 break; 510 } 511 512 if (retval != NULL) { 513 /* 514 * Just refhold the return value. The caller will then 515 * make the appropriate calls to set the USED flag. 516 */ 517 IPSA_REFHOLD(retval); 518 } 519 520 return (retval); 521 } 522 523 boolean_t 524 ipsec_outbound_sa(mblk_t *mp, uint_t proto) 525 { 526 mblk_t *data_mp; 527 ipsec_out_t *io; 528 ipaddr_t dst; 529 uint32_t *dst_ptr, *src_ptr; 530 isaf_t *bucket; 531 ipsa_t *assoc; 532 ip6_pkt_t ipp; 533 in6_addr_t dst6; 534 ipsa_t **sa; 535 sadbp_t *sadbp; 536 sadb_t *sp; 537 sa_family_t af; 538 539 data_mp = mp->b_cont; 540 io = (ipsec_out_t *)mp->b_rptr; 541 542 if (proto == IPPROTO_ESP) { 543 sa = &io->ipsec_out_esp_sa; 544 sadbp = &esp_sadb; 545 } else { 546 ASSERT(proto == IPPROTO_AH); 547 sa = &io->ipsec_out_ah_sa; 548 sadbp = &ah_sadb; 549 } 550 551 ASSERT(*sa == NULL); 552 553 if (io->ipsec_out_v4) { 554 ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 555 556 ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION); 557 dst = ip_get_dst(ipha); 558 sp = &sadbp->s_v4; 559 af = AF_INET; 560 561 /* 562 * NOTE:Getting the outbound association is considerably 563 * painful. ipsec_getassocbyconn() will require more 564 * parameters as policy implementations mature. 565 */ 566 bucket = OUTBOUND_BUCKET_V4(sp, dst); 567 src_ptr = (uint32_t *)&ipha->ipha_src; 568 dst_ptr = (uint32_t *)&dst; 569 } else { 570 ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 571 572 ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION); 573 dst6 = ip_get_dst_v6(ip6h, NULL); 574 af = AF_INET6; 575 576 bzero(&ipp, sizeof (ipp)); 577 sp = &sadbp->s_v6; 578 579 /* Same NOTE: applies here! */ 580 bucket = OUTBOUND_BUCKET_V6(sp, dst6); 581 src_ptr = (uint32_t *)&ip6h->ip6_src; 582 dst_ptr = (uint32_t *)&dst6; 583 } 584 585 mutex_enter(&bucket->isaf_lock); 586 assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af, proto); 587 mutex_exit(&bucket->isaf_lock); 588 589 if (assoc == NULL) 590 return (B_FALSE); 591 592 if (assoc->ipsa_state == IPSA_STATE_DEAD) { 593 IPSA_REFRELE(assoc); 594 return (B_FALSE); 595 } 596 597 ASSERT(assoc->ipsa_state != IPSA_STATE_LARVAL); 598 599 *sa = assoc; 600 return (B_TRUE); 601 } 602 603 /* 604 * Inbound IPsec SA selection. 605 */ 606 607 ah_t * 608 ipsec_inbound_ah_sa(mblk_t *mp) 609 { 610 mblk_t *ipsec_in; 611 ipha_t *ipha; 612 ipsa_t *assoc; 613 ah_t *ah; 614 isaf_t *hptr; 615 ipsec_in_t *ii; 616 boolean_t isv6; 617 ip6_t *ip6h; 618 int ah_offset; 619 uint32_t *src_ptr, *dst_ptr; 620 int pullup_len; 621 sadb_t *sp; 622 sa_family_t af; 623 624 IP_AH_BUMP_STAT(in_requests); 625 626 ASSERT(mp->b_datap->db_type == M_CTL); 627 628 ipsec_in = mp; 629 ii = (ipsec_in_t *)ipsec_in->b_rptr; 630 mp = mp->b_cont; 631 632 ASSERT(mp->b_datap->db_type == M_DATA); 633 634 isv6 = !ii->ipsec_in_v4; 635 if (isv6) { 636 ip6h = (ip6_t *)mp->b_rptr; 637 ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE); 638 } else { 639 ipha = (ipha_t *)mp->b_rptr; 640 ASSERT(ipha->ipha_protocol == IPPROTO_AH); 641 ah_offset = ipha->ipha_version_and_hdr_length - 642 (uint8_t)((IP_VERSION << 4)); 643 ah_offset <<= 2; 644 } 645 646 /* 647 * We assume that the IP header is pulled up until 648 * the options. We need to see whether we have the 649 * AH header in the same mblk or not. 650 */ 651 pullup_len = ah_offset + sizeof (ah_t); 652 if (mp->b_rptr + pullup_len > mp->b_wptr) { 653 if (!pullupmsg(mp, pullup_len)) { 654 ipsec_rl_strlog(ip_mod_info.mi_idnum, 0, 0, 655 SL_WARN | SL_ERROR, 656 "ipsec_inbound_ah_sa: Small AH header\n"); 657 IP_AH_BUMP_STAT(in_discards); 658 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, 659 &ipdrops_ah_bad_length, &ip_dropper); 660 return (NULL); 661 } 662 if (isv6) 663 ip6h = (ip6_t *)mp->b_rptr; 664 else 665 ipha = (ipha_t *)mp->b_rptr; 666 } 667 668 ah = (ah_t *)(mp->b_rptr + ah_offset); 669 670 if (isv6) { 671 src_ptr = (uint32_t *)&ip6h->ip6_src; 672 dst_ptr = (uint32_t *)&ip6h->ip6_dst; 673 sp = &ah_sadb.s_v6; 674 af = AF_INET6; 675 } else { 676 src_ptr = (uint32_t *)&ipha->ipha_src; 677 dst_ptr = (uint32_t *)&ipha->ipha_dst; 678 sp = &ah_sadb.s_v4; 679 af = AF_INET; 680 } 681 682 hptr = INBOUND_BUCKET(sp, ah->ah_spi); 683 mutex_enter(&hptr->isaf_lock); 684 assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af); 685 mutex_exit(&hptr->isaf_lock); 686 687 if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD) { 688 IP_AH_BUMP_STAT(lookup_failure); 689 IP_AH_BUMP_STAT(in_discards); 690 ipsecah_in_assocfailure(ipsec_in, 0, 691 SL_ERROR | SL_CONSOLE | SL_WARN, 692 "ipsec_inbound_ah_sa: No association found for " 693 "spi 0x%x, dst addr %s\n", 694 ah->ah_spi, dst_ptr, af); 695 if (assoc != NULL) { 696 IPSA_REFRELE(assoc); 697 } 698 return (NULL); 699 } 700 701 if (assoc->ipsa_state == IPSA_STATE_LARVAL) { 702 /* Not fully baked; swap the packet under a rock until then */ 703 sadb_set_lpkt(assoc, ipsec_in); 704 IPSA_REFRELE(assoc); 705 return (NULL); 706 } 707 708 /* 709 * Save a reference to the association so that it can 710 * be retrieved after execution. We free any AH SA reference 711 * already there (innermost SA "wins". The reference to 712 * the SA will also be used later when doing the policy checks. 713 */ 714 if (ii->ipsec_in_ah_sa != NULL) { 715 IPSA_REFRELE(ii->ipsec_in_ah_sa); 716 } 717 ii->ipsec_in_ah_sa = assoc; 718 719 return (ah); 720 } 721 722 esph_t * 723 ipsec_inbound_esp_sa(mblk_t *ipsec_in_mp) 724 { 725 mblk_t *data_mp, *placeholder; 726 uint32_t *src_ptr, *dst_ptr; 727 ipsec_in_t *ii; 728 ipha_t *ipha; 729 ip6_t *ip6h; 730 esph_t *esph; 731 ipsa_t *ipsa; 732 isaf_t *bucket; 733 uint_t preamble; 734 sa_family_t af; 735 boolean_t isv6; 736 sadb_t *sp; 737 738 IP_ESP_BUMP_STAT(in_requests); 739 ASSERT(ipsec_in_mp->b_datap->db_type == M_CTL); 740 741 /* We have IPSEC_IN already! */ 742 ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 743 data_mp = ipsec_in_mp->b_cont; 744 745 ASSERT(ii->ipsec_in_type == IPSEC_IN); 746 747 isv6 = !ii->ipsec_in_v4; 748 if (isv6) { 749 ip6h = (ip6_t *)data_mp->b_rptr; 750 } else { 751 ipha = (ipha_t *)data_mp->b_rptr; 752 } 753 754 /* 755 * Put all data into one mblk if it's not there already. 756 * XXX This is probably bad long-term. Figure out better ways of doing 757 * this. Much of the inbound path depends on all of the data being 758 * in one mblk. 759 * 760 * XXX Jumbogram issues will have to be dealt with here. 761 * If the plen is 0, we'll have to scan for a HBH header with the 762 * actual packet length. 763 */ 764 if (data_mp->b_datap->db_ref > 1 || 765 (data_mp->b_wptr - data_mp->b_rptr) < 766 (isv6 ? (ntohs(ip6h->ip6_plen) + sizeof (ip6_t)) 767 : ntohs(ipha->ipha_length))) { 768 placeholder = msgpullup(data_mp, -1); 769 if (placeholder == NULL) { 770 IP_ESP_BUMP_STAT(in_discards); 771 /* 772 * TODO: Extract inbound interface from the IPSEC_IN 773 * message's ii->ipsec_in_rill_index. 774 */ 775 ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 776 &ipdrops_esp_nomem, &ip_dropper); 777 return (NULL); 778 } else { 779 /* Reset packet with new pulled up mblk. */ 780 freemsg(data_mp); 781 data_mp = placeholder; 782 ipsec_in_mp->b_cont = data_mp; 783 } 784 } 785 786 /* 787 * Find the ESP header, point the address pointers at the appropriate 788 * IPv4/IPv6 places. 789 */ 790 if (isv6) { 791 ip6h = (ip6_t *)data_mp->b_rptr; 792 src_ptr = (uint32_t *)&ip6h->ip6_src; 793 dst_ptr = (uint32_t *)&ip6h->ip6_dst; 794 if (ip6h->ip6_nxt != IPPROTO_ESP) { 795 /* There are options that need to be processed. */ 796 preamble = ip_hdr_length_v6(data_mp, ip6h); 797 } else { 798 preamble = sizeof (ip6_t); 799 } 800 801 sp = &esp_sadb.s_v6; 802 af = AF_INET6; 803 } else { 804 ipha = (ipha_t *)data_mp->b_rptr; 805 src_ptr = (uint32_t *)&ipha->ipha_src; 806 dst_ptr = (uint32_t *)&ipha->ipha_dst; 807 preamble = IPH_HDR_LENGTH(ipha); 808 809 sp = &esp_sadb.s_v4; 810 af = AF_INET; 811 } 812 813 esph = (esph_t *)(data_mp->b_rptr + preamble); 814 815 /* Since hash is common on inbound (SPI value), hash here. */ 816 bucket = INBOUND_BUCKET(sp, esph->esph_spi); 817 mutex_enter(&bucket->isaf_lock); 818 ipsa = ipsec_getassocbyspi(bucket, esph->esph_spi, src_ptr, dst_ptr, 819 af); 820 mutex_exit(&bucket->isaf_lock); 821 822 if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD) { 823 /* This is a loggable error! AUDIT ME! */ 824 IP_ESP_BUMP_STAT(lookup_failure); 825 IP_ESP_BUMP_STAT(in_discards); 826 ipsecesp_in_assocfailure(ipsec_in_mp, 0, 827 SL_ERROR | SL_CONSOLE | SL_WARN, 828 "ipsec_inbound_esp_sa: No association found for " 829 "spi 0x%x, dst addr %s\n", 830 esph->esph_spi, dst_ptr, af); 831 if (ipsa != NULL) { 832 IPSA_REFRELE(ipsa); 833 } 834 return (NULL); 835 } 836 837 if (ipsa->ipsa_state == IPSA_STATE_LARVAL) { 838 /* Not fully baked; swap the packet under a rock until then */ 839 sadb_set_lpkt(ipsa, ipsec_in_mp); 840 IPSA_REFRELE(ipsa); 841 return (NULL); 842 } 843 844 /* 845 * Save a reference to the association so that it can 846 * be retrieved after execution. We free any AH SA reference 847 * already there (innermost SA "wins". The reference to 848 * the SA will also be used later when doing the policy checks. 849 */ 850 if (ii->ipsec_in_esp_sa != NULL) { 851 IPSA_REFRELE(ii->ipsec_in_esp_sa); 852 } 853 ii->ipsec_in_esp_sa = ipsa; 854 855 return (esph); 856 } 857