key.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,476 行 · 第 1/5 页

C
2,476
字号
#ifdef __NetBSD__struct callout key_timehandler_ch;#endif/* %%% IPsec policy management *//* * allocating a SP for OUTBOUND or INBOUND packet. * Must call key_freesp() later. * OUT:	NULL:	not found *	others:	found and return the pointer. */struct secpolicy *key_allocsp(spidx, dir)	struct secpolicyindex *spidx;	u_int dir;{	struct secpolicy *sp;	int s;	/* sanity check */	if (spidx == NULL)		panic("key_allocsp: NULL pointer is passed.\n");	/* check direction */	switch (dir) {	case IPSEC_DIR_INBOUND:	case IPSEC_DIR_OUTBOUND:		break;	default:		panic("key_allocsp: Invalid direction is passed.\n");	}	/* get a SP entry */#ifdef __NetBSD__	s = splsoftnet();	/*called from softclock()*/#else	s = splnet();	/*called from softclock()*/#endif	KEYDEBUG(KEYDEBUG_IPSEC_DATA,		printf("*** objects\n");		kdebug_secpolicyindex(spidx));	LIST_FOREACH(sp, &sptree[dir], chain) {		KEYDEBUG(KEYDEBUG_IPSEC_DATA,			printf("*** in SPD\n");			kdebug_secpolicyindex(&sp->spidx));		if (sp->state == IPSEC_SPSTATE_DEAD)			continue;		if (key_cmpspidx_withmask(&sp->spidx, spidx))			goto found;	}	splx(s);	return NULL;found:	/* sanity check */	KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp");	/* found a SPD entry */#if defined(__FreeBSD__) && __FreeBSD__ >= 3	sp->lastused = time_second;#else	sp->lastused = time.tv_sec;#endif	sp->refcnt++;	splx(s);	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,		printf("DP key_allocsp cause refcnt++:%d SP:%p\n",			sp->refcnt, sp));	return sp;}/* * return a policy that matches this particular inbound packet. * XXX slow */struct secpolicy *key_gettunnel(osrc, odst, isrc, idst)	struct sockaddr *osrc, *odst, *isrc, *idst;{	struct secpolicy *sp;	const int dir = IPSEC_DIR_INBOUND;	int s;	struct ipsecrequest *r1, *r2, *p;	struct sockaddr *os, *od, *is, *id;	struct secpolicyindex spidx;	if (isrc->sa_family != idst->sa_family) {		ipseclog((LOG_ERR, "protocol family mismatched %d != %d\n.",			isrc->sa_family, idst->sa_family));		return NULL;	}#ifdef __NetBSD__	s = splsoftnet();	/*called from softclock()*/#else	s = splnet();	/*called from softclock()*/#endif	LIST_FOREACH(sp, &sptree[dir], chain) {		if (sp->state == IPSEC_SPSTATE_DEAD)			continue;		r1 = r2 = NULL;		for (p = sp->req; p; p = p->next) {			if (p->saidx.mode != IPSEC_MODE_TUNNEL)				continue;			r1 = r2;			r2 = p;			if (!r1) {				/* here we look at address matches only */				spidx = sp->spidx;				if (isrc->sa_len > sizeof(spidx.src) ||				    idst->sa_len > sizeof(spidx.dst))					continue;				bcopy(isrc, &spidx.src, isrc->sa_len);				bcopy(idst, &spidx.dst, idst->sa_len);				if (!key_cmpspidx_withmask(&sp->spidx, &spidx))					continue;			} else {				is = (struct sockaddr *)&r1->saidx.src;				id = (struct sockaddr *)&r1->saidx.dst;				if (key_sockaddrcmp(is, isrc, 0) ||				    key_sockaddrcmp(id, idst, 0))					continue;			}			os = (struct sockaddr *)&r2->saidx.src;			od = (struct sockaddr *)&r2->saidx.dst;			if (key_sockaddrcmp(os, osrc, 0) ||			    key_sockaddrcmp(od, odst, 0))				continue;			goto found;		}	}	splx(s);	return NULL;found:#if defined(__FreeBSD__) && __FreeBSD__ >= 3	sp->lastused = time_second;#else	sp->lastused = time.tv_sec;#endif	sp->refcnt++;	splx(s);	return sp;}/* * allocating an SA entry for an *OUTBOUND* packet. * checking each request entries in SP, and acquire an SA if need. * OUT:	0: there are valid requests. *	ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. */intkey_checkrequest(isr, saidx)	struct ipsecrequest *isr;	struct secasindex *saidx;{	u_int level;	int error;	/* sanity check */	if (isr == NULL || saidx == NULL)		panic("key_checkrequest: NULL pointer is passed.\n");	/* check mode */	switch (saidx->mode) {	case IPSEC_MODE_TRANSPORT:	case IPSEC_MODE_TUNNEL:		break;	case IPSEC_MODE_ANY:	default:		panic("key_checkrequest: Invalid policy defined.\n");	}	/* get current level */	level = ipsec_get_reqlevel(isr);#if 0	/*	 * We do allocate new SA only if the state of SA in the holder is	 * SADB_SASTATE_DEAD.  The SA for outbound must be the oldest.	 */	if (isr->sav != NULL) {		if (isr->sav->sah == NULL)			panic("key_checkrequest: sah is null.\n");		if (isr->sav == (struct secasvar *)LIST_FIRST(			    &isr->sav->sah->savtree[SADB_SASTATE_DEAD])) {			KEYDEBUG(KEYDEBUG_IPSEC_STAMP,				printf("DP checkrequest calls free SA:%p\n",					isr->sav));			key_freesav(isr->sav);			isr->sav = NULL;		}	}#else	/*	 * we free any SA stashed in the IPsec request because a different	 * SA may be involved each time this request is checked, either	 * because new SAs are being configured, or this request is	 * associated with an unconnected datagram socket, or this request	 * is associated with a system default policy.	 *	 * The operation may have negative impact to performance.  We may	 * want to check cached SA carefully, rather than picking new SA	 * every time.	 */	if (isr->sav != NULL) {		key_freesav(isr->sav);		isr->sav = NULL;	}#endif	/*	 * new SA allocation if no SA found.	 * key_allocsa_policy should allocate the oldest SA available.	 * See key_do_allocsa_policy(), and draft-jenkins-ipsec-rekeying-03.txt.	 */	if (isr->sav == NULL)		isr->sav = key_allocsa_policy(saidx);	/* When there is SA. */	if (isr->sav != NULL)		return 0;	/* there is no SA */	if ((error = key_acquire(saidx, isr->sp)) != 0) {		/* XXX What should I do ? */		ipseclog((LOG_DEBUG, "key_checkrequest: error %d returned "			"from key_acquire.\n", error));		return error;	}	return level == IPSEC_LEVEL_REQUIRE ? ENOENT : 0;}/* * allocating a SA for policy entry from SAD. * NOTE: searching SAD of aliving state. * OUT:	NULL:	not found. *	others:	found and return the pointer. */static struct secasvar *key_allocsa_policy(saidx)	struct secasindex *saidx;{	struct secashead *sah;	struct secasvar *sav;	u_int stateidx, state;	LIST_FOREACH(sah, &sahtree, chain) {		if (sah->state == SADB_SASTATE_DEAD)			continue;		if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID))			goto found;	}	return NULL;    found:	/* search valid state */	for (stateidx = 0;	     stateidx < _ARRAYLEN(saorder_state_valid);	     stateidx++) {		state = saorder_state_valid[stateidx];		sav = key_do_allocsa_policy(sah, state);		if (sav != NULL)			return sav;	}	return NULL;}/* * searching SAD with direction, protocol, mode and state. * called by key_allocsa_policy(). * OUT: *	NULL	: not found *	others	: found, pointer to a SA. */static struct secasvar *key_do_allocsa_policy(sah, state)	struct secashead *sah;	u_int state;{	struct secasvar *sav, *nextsav, *candidate, *d;	/* initilize */	candidate = NULL;	for (sav = LIST_FIRST(&sah->savtree[state]);	     sav != NULL;	     sav = nextsav) {		nextsav = LIST_NEXT(sav, chain);		/* sanity check */		KEY_CHKSASTATE(sav->state, state, "key_do_allocsa_policy");		/* initialize */		if (candidate == NULL) {			candidate = sav;			continue;		}		/* Which SA is the better ? */		/* sanity check 2 */		if (candidate->lft_c == NULL || sav->lft_c == NULL)			panic("key_do_allocsa_policy: "				"lifetime_current is NULL.\n");		/* What the best method is to compare ? */		if (key_preferred_oldsa) {			if (candidate->lft_c->sadb_lifetime_addtime >					sav->lft_c->sadb_lifetime_addtime) {				candidate = sav;			}			continue;			/*NOTREACHED*/		}		/* preferred new sa rather than old sa */		if (candidate->lft_c->sadb_lifetime_addtime <				sav->lft_c->sadb_lifetime_addtime) {			d = candidate;			candidate = sav;		} else			d = sav;		/*		 * prepared to delete the SA when there is more		 * suitable candidate and the lifetime of the SA is not		 * permanent.		 */		if (d->lft_c->sadb_lifetime_addtime != 0) {			struct mbuf *m, *result;			key_sa_chgstate(d, SADB_SASTATE_DEAD);			key_freesav(d);			m = key_setsadbmsg(SADB_DELETE, 0,					sav->sah->saidx.proto, 0, 0, d->refcnt);			if (!m)				return NULL;			result = m;			/* set sadb_address for saidx's. */			m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,				(struct sockaddr *)&d->sah->saidx.src,				FULLMASK, IPSEC_ULPROTO_ANY);			if (!m)				return NULL;			m_cat(result, m);			/* set sadb_address for saidx's. */			m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,				(struct sockaddr *)&d->sah->saidx.dst,				FULLMASK, IPSEC_ULPROTO_ANY);			if (!m)				return NULL;			m_cat(result, m);			/* create SA extension */			m = key_setsadbsa(d);			if (!m)				return NULL;			m_cat(result, m);			if (result->m_len < sizeof(struct sadb_msg)) {				result = m_pullup(result,						sizeof(struct sadb_msg));				if (result == NULL)					return NULL;			}			result->m_pkthdr.len = 0;			for (m = result; m; m = m->m_next)				result->m_pkthdr.len += m->m_len;			mtod(result, struct sadb_msg *)->sadb_msg_len =				PFKEY_UNIT64(result->m_pkthdr.len);			if (key_sendup_mbuf(NULL, result,					KEY_SENDUP_REGISTERED))				return NULL;		}	}	if (candidate) {		candidate->refcnt++;		KEYDEBUG(KEYDEBUG_IPSEC_STAMP,			printf("DP allocsa_policy cause "				"refcnt++:%d SA:%p\n",				candidate->refcnt, candidate));	}	return candidate;}/* * allocating a SA entry for a *INBOUND* packet. * Must call key_freesav() later. * OUT: positive:	pointer to a sav. *	NULL:		not found, or error occured. * * In the comparison, source address will be ignored 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(family, src, dst, proto, spi)	u_int family, proto;	caddr_t src, dst;	u_int32_t spi;{	struct secashead *sah;	struct secasvar *sav;	u_int stateidx, state;	struct sockaddr_in sin;	struct sockaddr_in6 sin6;	int s;	/* sanity check */	if (src == NULL || dst == NULL)		panic("key_allocsa: NULL pointer is passed.\n");	/*	 * 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.	 */#ifdef __NetBSD__	s = splsoftnet();	/*called from softclock()*/#else	s = splnet();	/*called from softclock()*/#endif	LIST_FOREACH(sah, &sahtree, chain) {		/* search valid state */		for (stateidx = 0;		     stateidx < _ARRAYLEN(saorder_state_valid);		     stateidx++) {			state = saorder_state_valid[stateidx];			LIST_FOREACH(sav, &sah->savtree[state], chain) {				/* sanity check */				KEY_CHKSASTATE(sav->state, state, "key_allocsav");				if (proto != sav->sah->saidx.proto)					continue;				if (spi != sav->spi)					continue;				if (family != sav->sah->saidx.src.ss_family ||				    family != sav->sah->saidx.dst.ss_family)					continue;#if 0	/* don't check src */				/* check src address */				switch (family) {				case AF_INET:					bzero(&sin, sizeof(sin));					sin.sin_family = AF_INET;					sin.sin_len = sizeof(sin);					bcopy(src, &sin.sin_addr,					    sizeof(sin.sin_addr));					if (key_sockaddrcmp((struct sockaddr*)&sin,					    (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)						continue;					break;				case AF_INET6:					bzero(&sin6, sizeof(sin6));					sin6.sin6_family = AF_INET6;					sin6.sin6_len = sizeof(sin6);					bcopy(src, &sin6.sin6_addr,					    sizeof(sin6.sin6_addr));					if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {						/* kame fake scopeid */						sin6.sin6_scope_id =						    ntohs(sin6.sin6_addr.s6_addr16[1]);						sin6.sin6_addr.s6_addr16[1] = 0;					}					if (key_sockaddrcmp((struct sockaddr*)&sin6,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?