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