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