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