ip_sadb.c revision 930af642678ee3facd16f9ced3f72a773a8889bd
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <inet/ipsec_impl.h>
#include <inet/ipsecesp.h>
/*
* Returns B_TRUE if the identities in the SA match the identities
* in the "latch" structure.
*/
static boolean_t
{
}
/* l1 is packet label; l2 is SA label */
{
if (!is_system_labeled())
return (B_TRUE);
/*
* Check for NULL label. Unlabeled SA (l2) always matches;
* unlabeled user with labeled SA always fails
*/
return (B_TRUE);
return (B_FALSE);
/* Simple IPsec MLS policy: labels must be equal */
/* In future will need bit in policy saying whether this is the case */
/*
* label_equal() checks DOI and label contents. We should be
* good to go with this check.
*/
}
/*
* Look up a security association based on the unique ID generated by IP and
* transport or tunnel information, such as ports and upper-layer protocol,
* and the inner and outer address(es). Used for uniqueness testing and
* outbound packets. The outer source address may be ignored.
*
* I expect an SA hash bucket, and that its per-bucket mutex is held.
* The SA ptr I return will have its reference count incremented by one.
*/
ipsa_t *
{
/*
* Caller must set ip_xmit_attr_t structure such that we know
* whether this is tunnel mode or transport mode based on
* IXAF_IPSEC_TUNNEL. If this flag is set, we assume that
* there are valid inner src and destination addresses to compare.
*/
/*
* Fast path: do we have a latch structure, is it for this bucket,
* and does the generation number match? If so, refhold and return.
*/
/*
* NOTE: The isaf_gen check (incremented upon
* sadb_unlinkassoc()) protects against retval being a freed
* SA. (We're exploiting short-circuit evaluation.)
*/
return (retval);
}
}
/*
* Precompute mask for SA flags comparison: If we need a
* unique SA and an SA has already been used, or if the SA has
* a unique value which doesn't match, we aren't interested in
* the SA..
*/
if (need_unique)
/*
* Walk the hash bucket, matching on:
*
* - unique_id
* - destination
* - source
* - algorithms
* - inner dst
* - inner src
* - <MORE TBD>
*
* Make sure that wildcard sources are inserted at the end of the hash
* bucket.
*
* DEFINITIONS: A _shared_ SA is one with unique_id == 0 and USED.
* An _unused_ SA is one with unique_id == 0 and not USED.
* A _unique_ SA is one with unique_id != 0 and USED.
* An SA with unique_id != 0 and not USED never happens.
*/
/*
* Q: Should I lock this SA?
* A: For now, yes. I change and use too many fields in here
* (e.g. unique_id) that I may be racing with other threads.
* Also, the refcnt needs to be bumped up.
*/
/* My apologies for the use of goto instead of continue. */
/* Outer destination address */
goto next_ipsa; /* Destination mismatch. */
/* Outer source address */
goto next_ipsa; /* Specific source and not matched. */
if (tunnel_mode) {
/* Check tunnel mode */
goto next_ipsa; /* Not tunnel mode SA */
/* Inner destination address */
goto next_ipsa; /* not matched. */
}
/* Inner source address */
goto next_ipsa; /* not matched. */
}
} else {
/* Check transport mode */
goto next_ipsa; /* Not transport mode SA */
/*
* TODO - If we ever do RFC 3884's dream of transport-
* mode SAs with inner IP address selectors, we need
* to put some code here.
*/
}
/*
* to dodge this loop
*/
continue;
/*
* XXX ugly. should be better way to do this test
*/
if (protocol == IPPROTO_AH) {
continue;
continue;
continue;
} else {
continue;
continue;
continue;
continue;
continue;
}
}
/*
* Check key mgmt proto, cookie
*/
continue;
continue;
break;
}
goto next_ipsa; /* nothing matched */
/*
* Do identities match?
*/
goto next_ipsa;
/*
* Do labels match?
*/
goto next_ipsa;
/*
* At this point, we know that we have at least a match on:
*
* - dest
* - source (if source is specified, i.e. non-zeroes)
* - inner dest (if specified)
* - inner source (if specified)
* - auth alg (if auth alg is specified, i.e. non-zero)
* - encrypt. alg (if encrypt. alg is specified, i.e. non-zero)
* and we know that the SA keylengths are appropriate.
*
* (Keep in mind known-src SAs are hit before zero-src SAs,
* thanks to sadb_insertassoc().)
* If we need a unique asssociation, optimally we have
* ipsa_unique_id == unique_id, otherwise NOT USED
* is held in reserve (stored in candidate).
*
* For those stored in candidate, take best-match (i.e. given
* a choice, candidate should have non-zero ipsa_src).
*/
/*
* If SA has a unique value which matches, we're all set...
* "key management knows best"
*/
break;
/*
* If we need a unique SA and this SA has already been used,
* or if the SA has a unique value which doesn't match,
* this isn't for us.
*/
goto next_ipsa;
/*
* I found a candidate..
*/
/*
* and didn't already have one..
*/
continue;
} else {
/*
* If candidate's source address is zero and
* the current match (i.e. retval) address is
* not zero, we have a better candidate..
*/
continue;
}
}
}
/* Let caller react to a lookup failure when it gets NULL. */
return (NULL);
}
/*
* Even though I hold the mutex, since the reference counter is an
* atomic operation, I really have to use the IPSA_REFHOLD macro.
*/
/*
* This association is no longer unused.
*/
/*
* Cache a reference to this SA for the fast path.
*/
/* I'm now caching, so the cache-invalid flag goes away! */
}
/*
* Latch various things while we're here..
*/
if (!ipl->ipl_ids_latched) {
}
}
}
/*
* Set the uniqueness only first time.
*/
if (retval->ipsa_unique_id == 0) {
/*
* From now on, only this src, dst[ports, addr],
* proto, should use it.
*/
protocol, 0);
}
/*
* Set the source address and adjust the hash
* buckets only if src_addr is zero.
*/
/*
* sadb_unlinkassoc() will decrement the refcnt. Bump
* up when we have the lock so that we don't have to
* acquire locks when we come back from
* sadb_insertassoc().
*
* We don't need to bump the bucket's gen since
* we aren't moving to a new bucket.
*/
/*
* Since the bucket lock is held, we know
* sadb_insertassoc() will succeed.
*/
#ifdef DEBUG
"sadb_insertassoc() failed in "
"ipsec_getassocbyconn().\n");
}
#else /* non-DEBUG */
#endif /* DEBUG */
return (retval);
}
}
return (retval);
}
/*
* Look up a security association based on the security parameters index (SPI)
* and address(es). This is used for inbound packets and general SA lookups
* (even in outbound SA tables). The source address may be ignored. Return
* NULL if no association is available. If an SA is found, return it, with
* its refcnt incremented. The caller must REFRELE after using the SA.
* The hash bucket must be locked down before calling.
*/
ipsa_t *
{
/*
* Walk the hash bucket, matching exactly on SPI, then destination,
* then source.
*
* Per-SA locking doesn't need to happen, because I'm only matching
* from the hash bucket. Since the hash bucket lock is held, we don't
* need to worry about addresses changing.
*/
continue;
continue;
/*
* Assume that wildcard source addresses are inserted at the
* end of the hash bucket. (See sadb_insertassoc().)
* The following check for source addresses is a weak form
* SA has a source address, I only match an all-zeroes
* source address, or that particular one. If the SA has
* an all-zeroes source, then I match regardless.
*
* There is a weakness here in that a packet with all-zeroes
* for an address will match regardless of the source address
* stored in the packet.
*
* Note that port-level packet selectors, if present,
* are checked in ipsec_check_ipsecin_unique().
*/
break;
}
/*
* Just refhold the return value. The caller will then
* make the appropriate calls to set the USED flag.
*/
}
return (retval);
}
{
if (proto == IPPROTO_ESP) {
} else {
}
/*
* NOTE:Getting the outbound association is considerably
* painful. ipsec_getassocbyconn() will require more
* parameters as policy implementations mature.
*/
} else {
/* Same NOTE: applies here! */
}
return (B_FALSE);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Inbound IPsec SA selection.
* Can return a pulled up mblk.
* When it returns non-NULL ahp is updated
*/
mblk_t *
{
int ah_offset;
int pullup_len;
if (isv6) {
} else {
ah_offset <<= 2;
}
/*
* We assume that the IP header is pulled up until
* the options. We need to see whether we have the
* AH header in the same mblk or not.
*/
"ipsec_inbound_ah_sa: Small AH header\n");
&ipss->ipsec_dropper);
return (NULL);
}
if (isv6)
else
}
if (isv6) {
} else {
}
"ipsec_inbound_ah_sa: No association found for "
"spi 0x%x, dst addr %s\n",
}
return (NULL);
}
/* Not fully baked; swap the packet under a rock until then */
return (NULL);
}
/* Looks like the SA is no longer LARVAL. */
}
/* Are the IPsec fields initialized at all? */
}
/*
* Save a reference to the association so that it can
* be retrieved after execution. We free any AH SA reference
* already there (innermost SA "wins". The reference to
* the SA will also be used later when doing the policy checks.
*/
}
return (mp);
}
/*
* Can return a pulled up mblk.
* When it returns non-NULL esphp is updated
*/
mblk_t *
{
if (isv6) {
} else {
}
/*
* Put all data into one mblk if it's not there already.
* XXX This is probably bad long-term. Figure out better ways of doing
* this. Much of the inbound path depends on all of the data being
* in one mblk.
*
* XXX Jumbogram issues will have to be dealt with here.
* If the plen is 0, we'll have to scan for a HBH header with the
* actual packet length.
*/
if (placeholder == NULL) {
&ipss->ipsec_dropper);
return (NULL);
} else {
/* Reset packet with new pulled up mblk. */
}
}
/*
* Find the ESP header, point the address pointers at the appropriate
*/
if (isv6) {
/* There are options that need to be processed. */
} else {
}
} else {
}
/* Since hash is common on inbound (SPI value), hash here. */
af);
/* This is a loggable error! AUDIT ME! */
"ipsec_inbound_esp_sa: No association found for "
"spi 0x%x, dst addr %s\n",
}
return (NULL);
}
/* Not fully baked; swap the packet under a rock until then */
return (NULL);
}
/* Looks like the SA is no longer LARVAL. */
}
/* Are the IPsec fields initialized at all? */
}
/*
* Save a reference to the association so that it can
* be retrieved after execution. We free any AH SA reference
* already there (innermost SA "wins". The reference to
* the SA will also be used later when doing the policy checks.
*/
}
return (data_mp);
}