FreeBSD/sys/netipsec/key.c
/*
 * allocating a usable SA entry for a *INBOUND* packet.
 * Must call key_freesav() later.
 * OUT: positive:	pointer to a usable sav (i.e. MATURE or DYING state).
 *	NULL:		not found, or error occurred.
 *
 * In the comparison, no source address is used--for RFC2401 conformance.
 * To quote, from section 4.1:
 *	A security association is uniquely identified by a triple consisting
 *	of a Security Parameter Index (SPI), an IP Destination Address, and a
 *	security protocol (AH or ESP) identifier.
 * Note that, however, we do need to keep source address in IPsec SA.
 * IKE specification and PF_KEY specification do assume that we
 * keep source address in IPsec SA.  We see a tricky situation here.
 */
allocating a usable SA entry for a *INBOUND* packet.
Must call key_freesav() later.
OUT: positive:       pointer to a usable sav .
NULL:           not found, or error occurred.

In the comparison, no source address is used--for RFC2401 conformance.
To quote, from section 4.1:
A security association is uniquely identified by a triple consisting
of a Security Parameter Index (SPI), an IP Destination Address, and a
security protocol (AH or ESP) identifier.
Note that, however, we do need to keep source address in IPsec SA.
IKE specification and PF_KEY specification do assume that we
keep source address in IPsec SA.  We see a tricky situation here.
allocating a usable SA entry for a * INBOUND * packet . Must call key_freesav () later . OUT : positive : pointer to a usable sav . NULL : not found or error occurred . In the comparison no source address is used -- for RFC2401 conformance . To quote from section 4 . 1 : A security association is uniquely identified by a triple consisting of a Security Parameter Index ( SPI ) an IP Destination Address and a security protocol ( AH or ESP ) identifier . Note that however we do need to keep source address in IPsec SA . IKE specification and PF_KEY specification do assume that we keep source address in IPsec SA . We see a tricky situation here .
struct secasvar *
key_allocsa(union sockaddr_union *dst, u_int proto, u_int32_t spi,
    const char* where, int tag)
{
	struct secashead *sah;
	struct secasvar *sav;
	u_int stateidx, arraysize, state;
	const u_int *saorder_state_valid;
#ifdef IPSEC_NAT_T
	int natt_chkport;
#endif
	IPSEC_ASSERT(dst != NULL, ("null dst address"));
	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP %s from %s:%u\n", __func__, where, tag));
#ifdef IPSEC_NAT_T
        natt_chkport = (dst->sa.sa_family == AF_INET &&
	    dst->sa.sa_len == sizeof(struct sockaddr_in) &&
	    dst->sin.sin_port != 0);
#endif
	SAHTREE_LOCK();
	if (V_key_preferred_oldsa) {
		saorder_state_valid = saorder_state_valid_prefer_old;
		arraysize = _ARRAYLEN(saorder_state_valid_prefer_old);
	} else {
		saorder_state_valid = saorder_state_valid_prefer_new;
		arraysize = _ARRAYLEN(saorder_state_valid_prefer_new);
	}
	LIST_FOREACH(sah, &V_sahtree, chain) {
		int checkport;
		for (stateidx = 0; stateidx < arraysize; stateidx++) {
			state = saorder_state_valid[stateidx];
			LIST_FOREACH(sav, &sah->savtree[state], chain) {
				KEY_CHKSASTATE(sav->state, state, __func__);
				if (sav->state != SADB_SASTATE_MATURE &&
				    sav->state != SADB_SASTATE_DYING)
					continue;
				if (proto != sav->sah->saidx.proto)
					continue;
				if (spi != sav->spi)
					continue;
				checkport = 0;
#ifdef IPSEC_NAT_T
				if (sav->natt_type && natt_chkport)
					checkport = 1;
#endif
#if 0	
				if (key_sockaddrcmp(&src->sa,	
				    &sav->sah->saidx.src.sa, checkport) != 0)
					continue;
#endif
				if (key_sockaddrcmp(&dst->sa,
				    &sav->sah->saidx.dst.sa, checkport) != 0)
					continue;
				sa_addref(sav);
				goto done;
			}
		}
	}
	sav = NULL;
done:
	SAHTREE_UNLOCK();
	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP %s return SA:%p; refcnt %u\n", __func__,
			sav, sav ? sav->refcnt : 0));
	return sav;
}
struct secasvar * key_allocsa ( union sockaddr_union * dst , u_int proto , u_int32_t spi , const char * where , int tag ) { struct secashead * sah ; struct secasvar * sav ; u_int stateidx , arraysize , state ; const u_int * saorder_state_valid ; #ifdef IPSEC_NAT_T int natt_chkport ; #endif IPSEC_ASSERT ( dst != NULL , ( " " ) ) ; KEYDEBUG ( KEYDEBUG_IPSEC_STAMP , printf ( " \n " , __func__ , where , tag ) ) ; #ifdef IPSEC_NAT_T natt_chkport = ( dst -> sa . sa_family == AF_INET && dst -> sa . sa_len == sizeof ( struct sockaddr_in ) && dst -> sin . sin_port != 0 ) ; #endif SAHTREE_LOCK ( ) ; if ( V_key_preferred_oldsa ) { saorder_state_valid = saorder_state_valid_prefer_old ; arraysize = _ARRAYLEN ( saorder_state_valid_prefer_old ) ; } else { saorder_state_valid = saorder_state_valid_prefer_new ; arraysize = _ARRAYLEN ( saorder_state_valid_prefer_new ) ; } LIST_FOREACH ( sah , & V_sahtree , chain ) { int checkport ; for ( stateidx = 0 ; stateidx < arraysize ; stateidx ++ ) { state = saorder_state_valid [ stateidx ] ; LIST_FOREACH ( sav , & sah -> savtree [ state ] , chain ) { KEY_CHKSASTATE ( sav -> state , state , __func__ ) ; if ( sav -> state != SADB_SASTATE_MATURE && sav -> state != SADB_SASTATE_DYING ) continue ; if ( proto != sav -> sah -> saidx . proto ) continue ; if ( spi != sav -> spi ) continue ; checkport = 0 ; #ifdef IPSEC_NAT_T if ( sav -> natt_type && natt_chkport ) checkport = 1 ; #endif #if 0 if ( key_sockaddrcmp ( & src -> sa , & sav -> sah -> saidx . src . sa , checkport ) != 0 ) continue ; #endif if ( key_sockaddrcmp ( & dst -> sa , & sav -> sah -> saidx . dst . sa , checkport ) != 0 ) continue ; sa_addref ( sav ) ; goto done ; } } } sav = NULL ; done : SAHTREE_UNLOCK ( ) ; KEYDEBUG ( KEYDEBUG_IPSEC_STAMP , printf ( " \n " , __func__ , sav , sav ? sav -> refcnt : 0 ) ) ; return sav ; }
allocating a usable SA entry for a *INBOUND* packet.
allocating a usable SA entry for a * INBOUND * packet .
/*
	 * searching SAD.
	 * XXX: to be checked internal IP header somewhere.  Also when
	 * IPsec tunnel packet is received.  But ESP tunnel mode is
	 * encrypted so we can't check internal IP header.
	 */ /* search valid state */ /* sanity check */ /* do not return entries w/ unusable state */ /*
				 * Really only check ports when this is a NAT-T
				 * SA.  Otherwise other lookups providing ports
				 * might suffer.
				 */ /* don't check src */ /* check src address */ /* check dst address */