📄 key.c
字号:
if (ipsec_tunnel_device) {
for (req = newsp->req; req; req = req->next) {
struct ifnet *ifp;
int s;
struct sockaddr *me, *you;
if (req->saidx.mode != IPSEC_MODE_TUNNEL)
continue;
if (newsp->spidx.dir == IPSEC_DIR_OUTBOUND) {
me = (struct sockaddr *)&req->saidx.src;
you = (struct sockaddr *)&req->saidx.dst;
} else {
me = (struct sockaddr *)&req->saidx.dst;
you = (struct sockaddr *)&req->saidx.src;
}
s = splimp();
ifp = sec_establish(me, you);
/* bring the interface up, we are willing to receive */
if (ifp)
if_up(ifp);
splx(s);
if (!ifp) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
req->tunifp = ifp;
}
}
#endif
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
newsp->created = time_second;
newsp->lastused = time_second;
#else
newsp->created = time.tv_sec;
newsp->lastused = time.tv_sec;
#endif
newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0;
newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0;
newsp->refcnt = 1; /* do not reclaim until I say I do */
newsp->state = IPSEC_SPSTATE_ALIVE;
LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain);
/* delete the entry in spacqtree */
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
struct secspacq *spacq;
if ((spacq = key_getspacq(&spidx)) != NULL) {
/* reset counter in order to deletion by timehandler. */
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
spacq->created = time_second;
#else
spacq->created = time.tv_sec;
#endif
spacq->count = 0;
}
}
/* invalidate all cached SPD pointers on pcb */
ipsec_invalpcbcacheall();
{
struct mbuf *n, *mpolicy;
struct sadb_msg *newmsg;
int off;
/* create new sadb_msg to reply. */
if (lft) {
n = key_gather_mbuf(m, mhp, 2, 5, SADB_EXT_RESERVED,
SADB_X_EXT_POLICY, SADB_EXT_LIFETIME_HARD,
SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
} else {
n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED,
SADB_X_EXT_POLICY,
SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
}
if (!n)
return key_senderror(so, m, ENOBUFS);
if (n->m_len < sizeof(*newmsg)) {
n = m_pullup(n, sizeof(*newmsg));
if (!n)
return key_senderror(so, m, ENOBUFS);
}
newmsg = mtod(n, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
off = 0;
mpolicy = m_pulldown(n, PFKEY_ALIGN8(sizeof(struct sadb_msg)),
sizeof(*xpl), &off);
if (mpolicy == NULL) {
/* n is already freed */
return key_senderror(so, m, ENOBUFS);
}
xpl = (struct sadb_x_policy *)(mtod(mpolicy, caddr_t) + off);
if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) {
m_freem(n);
return key_senderror(so, m, EINVAL);
}
xpl->sadb_x_policy_id = newsp->id;
m_freem(m);
return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
/*
* get new policy id.
* OUT:
* 0: failure.
* others: success.
*/
static u_int32_t
key_getnewspid()
{
u_int32_t newid = 0;
int count = key_spi_trycnt; /* XXX */
struct secpolicy *sp;
/* when requesting to allocate spi ranged */
while (count--) {
newid = (policy_id = (policy_id == ~0 ? 1 : policy_id + 1));
if ((sp = key_getspbyid(newid)) == NULL)
break;
key_freesp(sp);
}
if (count == 0 || newid == 0) {
ipseclog((LOG_DEBUG, "key_getnewspid: to allocate policy id is failed.\n"));
return 0;
}
return newid;
}
/*
* SADB_SPDDELETE processing
* receive
* <base, address(SD), policy(*)>
* from the user(?), and set SADB_SASTATE_DEAD,
* and send,
* <base, address(SD), policy(*)>
* to the ikmpd.
* policy(*) including direction of policy.
*
* m will always be freed.
*/
static int
key_spddelete(so, m, mhp)
struct socket *so;
struct mbuf *m;
const struct sadb_msghdr *mhp;
{
struct sadb_address *src0, *dst0;
struct sadb_x_policy *xpl0;
struct secpolicyindex spidx;
struct secpolicy *sp;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spddelete: NULL pointer is passed.\n");
if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
mhp->ext[SADB_X_EXT_POLICY] == NULL) {
ipseclog((LOG_DEBUG, "key_spddelete: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
}
if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
ipseclog((LOG_DEBUG, "key_spddelete: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
}
src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY];
/* make secindex */
/* XXX boundary check against sa_len */
KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
src0 + 1,
dst0 + 1,
src0->sadb_address_prefixlen,
dst0->sadb_address_prefixlen,
src0->sadb_address_proto,
&spidx);
/* checking the direciton. */
switch (xpl0->sadb_x_policy_dir) {
case IPSEC_DIR_INBOUND:
case IPSEC_DIR_OUTBOUND:
break;
default:
ipseclog((LOG_DEBUG, "key_spddelete: Invalid SP direction.\n"));
return key_senderror(so, m, EINVAL);
}
/* Is there SP in SPD ? */
if ((sp = key_getsp(&spidx)) == NULL) {
ipseclog((LOG_DEBUG, "key_spddelete: no SP found.\n"));
return key_senderror(so, m, EINVAL);
}
/* save policy id to buffer to be returned. */
xpl0->sadb_x_policy_id = sp->id;
sp->state = IPSEC_SPSTATE_DEAD;
key_freesp(sp);
/* invalidate all cached SPD pointers on pcb */
ipsec_invalpcbcacheall();
{
struct mbuf *n;
struct sadb_msg *newmsg;
/* create new sadb_msg to reply. */
n = key_gather_mbuf(m, mhp, 1, 4, SADB_EXT_RESERVED,
SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST);
if (!n)
return key_senderror(so, m, ENOBUFS);
newmsg = mtod(n, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
m_freem(m);
return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
/*
* SADB_SPDDELETE2 processing
* receive
* <base, policy(*)>
* from the user(?), and set SADB_SASTATE_DEAD,
* and send,
* <base, policy(*)>
* to the ikmpd.
* policy(*) including direction of policy.
*
* m will always be freed.
*/
static int
key_spddelete2(so, m, mhp)
struct socket *so;
struct mbuf *m;
const struct sadb_msghdr *mhp;
{
u_int32_t id;
struct secpolicy *sp;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spddelete2: NULL pointer is passed.\n");
if (mhp->ext[SADB_X_EXT_POLICY] == NULL ||
mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
ipseclog((LOG_DEBUG, "key_spddelete2: invalid message is passed.\n"));
key_senderror(so, m, EINVAL);
return 0;
}
id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id;
/* Is there SP in SPD ? */
if ((sp = key_getspbyid(id)) == NULL) {
ipseclog((LOG_DEBUG, "key_spddelete2: no SP found id:%u.\n", id));
key_senderror(so, m, EINVAL);
}
sp->state = IPSEC_SPSTATE_DEAD;
key_freesp(sp);
/* invalidate all cached SPD pointers on pcb */
ipsec_invalpcbcacheall();
{
struct mbuf *n, *nn;
struct sadb_msg *newmsg;
int off, len;
/* create new sadb_msg to reply. */
len = PFKEY_ALIGN8(sizeof(struct sadb_msg));
if (len > MCLBYTES)
return key_senderror(so, m, ENOBUFS);
MGETHDR(n, M_DONTWAIT, MT_DATA);
if (n && len > MHLEN) {
MCLGET(n, M_DONTWAIT);
if ((n->m_flags & M_EXT) == 0) {
m_freem(n);
n = NULL;
}
}
if (!n)
return key_senderror(so, m, ENOBUFS);
n->m_len = len;
n->m_next = NULL;
off = 0;
m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off);
off += PFKEY_ALIGN8(sizeof(struct sadb_msg));
#ifdef DIAGNOSTIC
if (off != len)
panic("length inconsistency in key_spddelete2");
#endif
n->m_next = m_copym(m, mhp->extoff[SADB_X_EXT_POLICY],
mhp->extlen[SADB_X_EXT_POLICY], M_DONTWAIT);
if (!n->m_next) {
m_freem(n);
return key_senderror(so, m, ENOBUFS);
}
n->m_pkthdr.len = 0;
for (nn = n; nn; nn = nn->m_next)
n->m_pkthdr.len += nn->m_len;
newmsg = mtod(n, struct sadb_msg *);
newmsg->sadb_msg_errno = 0;
newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
m_freem(m);
return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
}
}
/*
* SADB_X_GET processing
* receive
* <base, policy(*)>
* from the user(?),
* and send,
* <base, address(SD), policy>
* to the ikmpd.
* policy(*) including direction of policy.
*
* m will always be freed.
*/
static int
key_spdget(so, m, mhp)
struct socket *so;
struct mbuf *m;
const struct sadb_msghdr *mhp;
{
u_int32_t id;
struct secpolicy *sp;
struct mbuf *n;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spdget: NULL pointer is passed.\n");
if (mhp->ext[SADB_X_EXT_POLICY] == NULL ||
mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
ipseclog((LOG_DEBUG, "key_spdget: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
}
id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id;
/* Is there SP in SPD ? */
if ((sp = key_getspbyid(id)) == NULL) {
ipseclog((LOG_DEBUG, "key_spdget: no SP found id:%u.\n", id));
return key_senderror(so, m, ENOENT);
}
n = key_setdumpsp(sp, SADB_X_SPDGET, 0, mhp->msg->sadb_msg_pid);
if (n != NULL) {
m_freem(m);
return key_sendup_mbuf(so, n, KEY_SENDUP_ONE);
} else
return key_senderror(so, m, ENOBUFS);
}
/*
* SADB_X_SPDACQUIRE processing.
* Acquire policy and SA(s) for a *OUTBOUND* packet.
* send
* <base, policy(*)>
* to KMD, and expect to receive
* <base> with SADB_X_SPDACQUIRE if error occured,
* or
* <base, policy>
* with SADB_X_SPDUPDATE from KMD by PF_KEY.
* policy(*) is without policy requests.
*
* 0 : succeed
* others: error number
*/
int
key_spdacquire(sp)
struct secpolicy *sp;
{
struct mbuf *result = NULL, *m;
struct secspacq *newspacq;
int error;
/* sanity check */
if (sp == NULL)
panic("key_spdacquire: NULL pointer is passed.\n");
if (sp->req != NULL)
panic("key_spdacquire: called but there is request.\n");
if (sp->policy != IPSEC_POLICY_IPSEC)
panic("key_spdacquire: policy mismathed. IPsec is expected.\n");
/* get a entry to check whether sent message or not. */
if ((newspacq = key_getspacq(&sp->spidx)) != NULL) {
if (key_blockacq_count < newspacq->count) {
/* reset counter and do send message. */
newspacq->count = 0;
} else {
/* increment counter and do nothing. */
newspacq->count++;
return 0;
}
} else {
/* make new entry for blocking to send SADB_ACQUIRE. */
if ((newspacq = key_newspacq(&sp->spidx)) == NULL)
return ENOBUFS;
/* add to acqtree */
LIST_INSERT_HEAD(&spacqtree, newspacq, chain);
}
/* create new sadb_msg to reply. */
m = key_setsadbmsg(SADB_X_SPDACQUIRE, 0, 0, 0, 0, 0);
if (!m) {
error = ENOBUFS;
goto fail;
}
result = m;
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);
return key_sendup_mbuf(NULL, m, KEY_SENDUP_REGISTERED);
fail:
if (result)
m_freem(result);
return error;
}
/*
* SADB_SPDFLUSH processing
* receive
* <base>
* from the user, and free all entries in secpctree.
* and send,
* <base>
* to the user.
* NOTE: what to do is only marking SADB_SASTATE_DEAD.
*
* m will always be freed.
*/
static int
key_spdflush(so, m, mhp)
struc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -