📄 key.c
字号:
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,
(struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
continue;
break;
default:
ipseclog((LOG_DEBUG, "key_allocsa: "
"unknown address family=%d.\n",
family));
continue;
}
#endif
/* check dst address */
switch (family) {
case AF_INET:
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
bcopy(dst, &sin.sin_addr,
sizeof(sin.sin_addr));
if (key_sockaddrcmp((struct sockaddr*)&sin,
(struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
continue;
break;
case AF_INET6:
bzero(&sin6, sizeof(sin6));
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(sin6);
bcopy(dst, &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,
(struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
continue;
break;
default:
ipseclog((LOG_DEBUG, "key_allocsa: "
"unknown address family=%d.\n",
family));
continue;
}
goto found;
}
}
}
/* not found */
splx(s);
return NULL;
found:
sav->refcnt++;
splx(s);
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP allocsa cause refcnt++:%d SA:%p\n",
sav->refcnt, sav));
return sav;
}
/*
* Must be called after calling key_allocsp().
* For both the packet without socket and key_freeso().
*/
void
key_freesp(sp)
struct secpolicy *sp;
{
/* sanity check */
if (sp == NULL)
panic("key_freesp: NULL pointer is passed.\n");
sp->refcnt--;
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP freesp cause refcnt--:%d SP:%p\n",
sp->refcnt, sp));
if (sp->refcnt == 0)
key_delsp(sp);
return;
}
/*
* Must be called after calling key_allocsp().
* For the packet with socket.
*/
void
key_freeso(so)
struct socket *so;
{
/* sanity check */
if (so == NULL)
panic("key_freeso: NULL pointer is passed.\n");
switch (so->so_proto->pr_domain->dom_family) {
#ifdef INET
case PF_INET:
{
struct inpcb *pcb = sotoinpcb(so);
/* Does it have a PCB ? */
if (pcb == NULL)
return;
key_freesp_so(&pcb->inp_sp->sp_in);
key_freesp_so(&pcb->inp_sp->sp_out);
}
break;
#endif
#ifdef INET6
case PF_INET6:
{
#ifdef HAVE_NRL_INPCB
struct inpcb *pcb = sotoinpcb(so);
/* Does it have a PCB ? */
if (pcb == NULL)
return;
key_freesp_so(&pcb->inp_sp->sp_in);
key_freesp_so(&pcb->inp_sp->sp_out);
#else
struct in6pcb *pcb = sotoin6pcb(so);
/* Does it have a PCB ? */
if (pcb == NULL)
return;
key_freesp_so(&pcb->in6p_sp->sp_in);
key_freesp_so(&pcb->in6p_sp->sp_out);
#endif
}
break;
#endif /* INET6 */
default:
ipseclog((LOG_DEBUG, "key_freeso: unknown address family=%d.\n",
so->so_proto->pr_domain->dom_family));
return;
}
return;
}
static void
key_freesp_so(sp)
struct secpolicy **sp;
{
/* sanity check */
if (sp == NULL || *sp == NULL)
panic("key_freesp_so: sp == NULL\n");
switch ((*sp)->policy) {
case IPSEC_POLICY_IPSEC:
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP freeso calls free SP:%p\n", *sp));
key_freesp(*sp);
*sp = NULL;
break;
case IPSEC_POLICY_ENTRUST:
case IPSEC_POLICY_BYPASS:
return;
default:
panic("key_freesp_so: Invalid policy found %d", (*sp)->policy);
}
return;
}
/*
* Must be called after calling key_allocsa().
* This function is called by key_freesp() to free some SA allocated
* for a policy.
*/
void
key_freesav(sav)
struct secasvar *sav;
{
/* sanity check */
if (sav == NULL)
panic("key_freesav: NULL pointer is passed.\n");
sav->refcnt--;
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n",
sav->refcnt, sav, (u_int32_t)ntohl(sav->spi)));
if (sav->refcnt == 0)
key_delsav(sav);
return;
}
/* %%% SPD management */
/*
* free security policy entry.
*/
static void
key_delsp(sp)
struct secpolicy *sp;
{
int s;
/* sanity check */
if (sp == NULL)
panic("key_delsp: NULL pointer is passed.\n");
sp->state = IPSEC_SPSTATE_DEAD;
if (sp->refcnt > 0)
return; /* can't free */
#ifdef __NetBSD__
s = splsoftnet(); /*called from softclock()*/
#else
s = splnet(); /*called from softclock()*/
#endif
/* remove from SP index */
if (__LIST_CHAINED(sp))
LIST_REMOVE(sp, chain);
{
struct ipsecrequest *isr = sp->req, *nextisr;
while (isr != NULL) {
if (isr->sav != NULL) {
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP delsp calls free SA:%p\n",
isr->sav));
key_freesav(isr->sav);
isr->sav = NULL;
}
#if defined(NSEC) && NSEC > 0
if (isr->tunifp) {
int s;
s = splimp();
sec_demolish(isr->tunifp);
splx(s);
/* XXX more garbage-collection */
isr->tunifp = NULL;
}
#endif
nextisr = isr->next;
KFREE(isr);
isr = nextisr;
}
}
keydb_delsecpolicy(sp);
splx(s);
return;
}
/*
* search SPD
* OUT: NULL : not found
* others : found, pointer to a SP.
*/
static struct secpolicy *
key_getsp(spidx)
struct secpolicyindex *spidx;
{
struct secpolicy *sp;
/* sanity check */
if (spidx == NULL)
panic("key_getsp: NULL pointer is passed.\n");
LIST_FOREACH(sp, &sptree[spidx->dir], chain) {
if (sp->state == IPSEC_SPSTATE_DEAD)
continue;
if (key_cmpspidx_exactly(spidx, &sp->spidx)) {
sp->refcnt++;
return sp;
}
}
return NULL;
}
/*
* get SP by index.
* OUT: NULL : not found
* others : found, pointer to a SP.
*/
static struct secpolicy *
key_getspbyid(id)
u_int32_t id;
{
struct secpolicy *sp;
LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) {
if (sp->state == IPSEC_SPSTATE_DEAD)
continue;
if (sp->id == id) {
sp->refcnt++;
return sp;
}
}
LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) {
if (sp->state == IPSEC_SPSTATE_DEAD)
continue;
if (sp->id == id) {
sp->refcnt++;
return sp;
}
}
return NULL;
}
struct secpolicy *
key_newsp()
{
struct secpolicy *newsp = NULL;
newsp = keydb_newsecpolicy();
if (!newsp)
return newsp;
newsp->refcnt = 1;
newsp->req = NULL;
return newsp;
}
/*
* create secpolicy structure from sadb_x_policy structure.
* NOTE: `state', `secpolicyindex' in secpolicy structure are not set,
* so must be set properly later.
*/
struct secpolicy *
key_msg2sp(xpl0, len, error)
struct sadb_x_policy *xpl0;
size_t len;
int *error;
{
struct secpolicy *newsp;
/* sanity check */
if (xpl0 == NULL)
panic("key_msg2sp: NULL pointer was passed.\n");
if (len < sizeof(*xpl0))
panic("key_msg2sp: invalid length.\n");
if (len != PFKEY_EXTLEN(xpl0)) {
ipseclog((LOG_DEBUG, "key_msg2sp: Invalid msg length.\n"));
*error = EINVAL;
return NULL;
}
if ((newsp = key_newsp()) == NULL) {
*error = ENOBUFS;
return NULL;
}
newsp->spidx.dir = xpl0->sadb_x_policy_dir;
newsp->policy = xpl0->sadb_x_policy_type;
/* check policy */
switch (xpl0->sadb_x_policy_type) {
case IPSEC_POLICY_DISCARD:
case IPSEC_POLICY_NONE:
case IPSEC_POLICY_ENTRUST:
case IPSEC_POLICY_BYPASS:
newsp->req = NULL;
break;
case IPSEC_POLICY_IPSEC:
{
int tlen;
struct sadb_x_ipsecrequest *xisr;
struct ipsecrequest **p_isr = &newsp->req;
/* validity check */
if (PFKEY_EXTLEN(xpl0) < sizeof(*xpl0)) {
ipseclog((LOG_DEBUG,
"key_msg2sp: Invalid msg length.\n"));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0);
xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1);
while (tlen > 0) {
/* length check */
if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
ipseclog((LOG_DEBUG, "key_msg2sp: "
"invalid ipsecrequest length.\n"));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
/* allocate request buffer */
KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr));
if ((*p_isr) == NULL) {
ipseclog((LOG_DEBUG,
"key_msg2sp: No more memory.\n"));
key_freesp(newsp);
*error = ENOBUFS;
return NULL;
}
bzero(*p_isr, sizeof(**p_isr));
/* set values */
(*p_isr)->next = NULL;
switch (xisr->sadb_x_ipsecrequest_proto) {
case IPPROTO_ESP:
case IPPROTO_AH:
case IPPROTO_IPCOMP:
break;
default:
ipseclog((LOG_DEBUG,
"key_msg2sp: invalid proto type=%u\n",
xisr->sadb_x_ipsecrequest_proto));
key_freesp(newsp);
*error = EPROTONOSUPPORT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -