📄 key.c
字号:
return NULL;
}
(*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto;
switch (xisr->sadb_x_ipsecrequest_mode) {
case IPSEC_MODE_TRANSPORT:
case IPSEC_MODE_TUNNEL:
break;
case IPSEC_MODE_ANY:
default:
ipseclog((LOG_DEBUG,
"key_msg2sp: invalid mode=%u\n",
xisr->sadb_x_ipsecrequest_mode));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
(*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode;
switch (xisr->sadb_x_ipsecrequest_level) {
case IPSEC_LEVEL_DEFAULT:
case IPSEC_LEVEL_USE:
case IPSEC_LEVEL_REQUIRE:
break;
case IPSEC_LEVEL_UNIQUE:
/* validity check */
/*
* If range violation of reqid, kernel will
* update it, don't refuse it.
*/
if (xisr->sadb_x_ipsecrequest_reqid
> IPSEC_MANUAL_REQID_MAX) {
ipseclog((LOG_DEBUG,
"key_msg2sp: reqid=%d range "
"violation, updated by kernel.\n",
xisr->sadb_x_ipsecrequest_reqid));
xisr->sadb_x_ipsecrequest_reqid = 0;
}
/* allocate new reqid id if reqid is zero. */
if (xisr->sadb_x_ipsecrequest_reqid == 0) {
u_int32_t reqid;
if ((reqid = key_newreqid()) == 0) {
key_freesp(newsp);
*error = ENOBUFS;
return NULL;
}
(*p_isr)->saidx.reqid = reqid;
xisr->sadb_x_ipsecrequest_reqid = reqid;
} else {
/* set it for manual keying. */
(*p_isr)->saidx.reqid =
xisr->sadb_x_ipsecrequest_reqid;
}
break;
default:
ipseclog((LOG_DEBUG, "key_msg2sp: invalid level=%u\n",
xisr->sadb_x_ipsecrequest_level));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
(*p_isr)->level = xisr->sadb_x_ipsecrequest_level;
/* set IP addresses if there */
if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
struct sockaddr *paddr;
paddr = (struct sockaddr *)(xisr + 1);
/* validity check */
if (paddr->sa_len
> sizeof((*p_isr)->saidx.src)) {
ipseclog((LOG_DEBUG, "key_msg2sp: invalid request "
"address length.\n"));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
bcopy(paddr, &(*p_isr)->saidx.src,
paddr->sa_len);
paddr = (struct sockaddr *)((caddr_t)paddr
+ paddr->sa_len);
/* validity check */
if (paddr->sa_len
> sizeof((*p_isr)->saidx.dst)) {
ipseclog((LOG_DEBUG, "key_msg2sp: invalid request "
"address length.\n"));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
bcopy(paddr, &(*p_isr)->saidx.dst,
paddr->sa_len);
}
(*p_isr)->sav = NULL;
(*p_isr)->sp = newsp;
/* initialization for the next. */
p_isr = &(*p_isr)->next;
tlen -= xisr->sadb_x_ipsecrequest_len;
/* validity check */
if (tlen < 0) {
ipseclog((LOG_DEBUG, "key_msg2sp: becoming tlen < 0.\n"));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr
+ xisr->sadb_x_ipsecrequest_len);
}
}
break;
default:
ipseclog((LOG_DEBUG, "key_msg2sp: invalid policy type.\n"));
key_freesp(newsp);
*error = EINVAL;
return NULL;
}
*error = 0;
return newsp;
}
static u_int32_t
key_newreqid()
{
static u_int32_t auto_reqid = IPSEC_MANUAL_REQID_MAX + 1;
auto_reqid = (auto_reqid == ~0
? IPSEC_MANUAL_REQID_MAX + 1 : auto_reqid + 1);
/* XXX should be unique check */
return auto_reqid;
}
/*
* copy secpolicy struct to sadb_x_policy structure indicated.
*/
struct mbuf *
key_sp2msg(sp)
struct secpolicy *sp;
{
struct sadb_x_policy *xpl;
int tlen;
caddr_t p;
struct mbuf *m;
/* sanity check. */
if (sp == NULL)
panic("key_sp2msg: NULL pointer was passed.\n");
tlen = key_getspreqmsglen(sp);
m = key_alloc_mbuf(tlen);
if (!m || m->m_next) { /*XXX*/
if (m)
m_freem(m);
return NULL;
}
m->m_len = tlen;
m->m_next = NULL;
xpl = mtod(m, struct sadb_x_policy *);
bzero(xpl, tlen);
xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen);
xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
xpl->sadb_x_policy_type = sp->policy;
xpl->sadb_x_policy_dir = sp->spidx.dir;
xpl->sadb_x_policy_id = sp->id;
p = (caddr_t)xpl + sizeof(*xpl);
/* if is the policy for ipsec ? */
if (sp->policy == IPSEC_POLICY_IPSEC) {
struct sadb_x_ipsecrequest *xisr;
struct ipsecrequest *isr;
for (isr = sp->req; isr != NULL; isr = isr->next) {
xisr = (struct sadb_x_ipsecrequest *)p;
xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto;
xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode;
xisr->sadb_x_ipsecrequest_level = isr->level;
xisr->sadb_x_ipsecrequest_reqid = isr->saidx.reqid;
p += sizeof(*xisr);
bcopy(&isr->saidx.src, p, isr->saidx.src.ss_len);
p += isr->saidx.src.ss_len;
bcopy(&isr->saidx.dst, p, isr->saidx.dst.ss_len);
p += isr->saidx.src.ss_len;
xisr->sadb_x_ipsecrequest_len =
PFKEY_ALIGN8(sizeof(*xisr)
+ isr->saidx.src.ss_len
+ isr->saidx.dst.ss_len);
}
}
return m;
}
/* m will not be freed nor modified */
static struct mbuf *
#ifdef __STDC__
key_gather_mbuf(struct mbuf *m, const struct sadb_msghdr *mhp,
int ndeep, int nitem, ...)
#else
key_gather_mbuf(m, mhp, ndeep, nitem, va_alist)
struct mbuf *m;
const struct sadb_msghdr *mhp;
int ndeep;
int nitem;
va_dcl
#endif
{
va_list ap;
int idx;
int i;
struct mbuf *result = NULL, *n;
int len;
if (m == NULL || mhp == NULL)
panic("null pointer passed to key_gather");
va_start(ap, nitem);
for (i = 0; i < nitem; i++) {
idx = va_arg(ap, int);
if (idx < 0 || idx > SADB_EXT_MAX)
goto fail;
/* don't attempt to pull empty extension */
if (idx == SADB_EXT_RESERVED && mhp->msg == NULL)
continue;
if (idx != SADB_EXT_RESERVED &&
(mhp->ext[idx] == NULL || mhp->extlen[idx] == 0))
continue;
if (idx == SADB_EXT_RESERVED) {
len = PFKEY_ALIGN8(sizeof(struct sadb_msg));
#ifdef DIAGNOSTIC
if (len > MHLEN)
panic("assumption failed");
#endif
MGETHDR(n, M_DONTWAIT, MT_DATA);
if (!n)
goto fail;
n->m_len = len;
n->m_next = NULL;
m_copydata(m, 0, sizeof(struct sadb_msg),
mtod(n, caddr_t));
} else if (i < ndeep) {
len = mhp->extlen[idx];
n = key_alloc_mbuf(len);
if (!n || n->m_next) { /*XXX*/
if (n)
m_freem(n);
goto fail;
}
m_copydata(m, mhp->extoff[idx], mhp->extlen[idx],
mtod(n, caddr_t));
} else {
n = m_copym(m, mhp->extoff[idx], mhp->extlen[idx],
M_DONTWAIT);
}
if (n == NULL)
goto fail;
if (result)
m_cat(result, n);
else
result = n;
}
va_end(ap);
if ((result->m_flags & M_PKTHDR) != 0) {
result->m_pkthdr.len = 0;
for (n = result; n; n = n->m_next)
result->m_pkthdr.len += n->m_len;
}
return result;
fail:
m_freem(result);
return NULL;
}
/*
* SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing
* add a entry to SP database, when received
* <base, address(SD), (lifetime(H),) policy>
* from the user(?).
* Adding to SP database,
* and send
* <base, address(SD), (lifetime(H),) policy>
* to the socket which was send.
*
* SPDADD set a unique policy entry.
* SPDSETIDX like SPDADD without a part of policy requests.
* SPDUPDATE replace a unique policy entry.
*
* m will always be freed.
*/
static int
key_spdadd(so, m, mhp)
struct socket *so;
struct mbuf *m;
const struct sadb_msghdr *mhp;
{
struct sadb_address *src0, *dst0;
struct sadb_x_policy *xpl0, *xpl;
struct sadb_lifetime *lft = NULL;
struct secpolicyindex spidx;
struct secpolicy *newsp;
struct ipsecrequest *req;
int error;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spdadd: 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_spdadd: 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_spdadd: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
}
if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) {
if (mhp->extlen[SADB_EXT_LIFETIME_HARD]
< sizeof(struct sadb_lifetime)) {
ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
}
lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD];
}
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_spdadd: Invalid SP direction.\n"));
mhp->msg->sadb_msg_errno = EINVAL;
return 0;
}
/* check policy */
/* key_spdadd() accepts DISCARD, NONE and IPSEC. */
if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST
|| xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) {
ipseclog((LOG_DEBUG, "key_spdadd: Invalid policy type.\n"));
return key_senderror(so, m, EINVAL);
}
/* policy requests are mandatory when action is ipsec. */
if (mhp->msg->sadb_msg_type != SADB_X_SPDSETIDX
&& xpl0->sadb_x_policy_type == IPSEC_POLICY_IPSEC
&& mhp->extlen[SADB_X_EXT_POLICY] <= sizeof(*xpl0)) {
ipseclog((LOG_DEBUG, "key_spdadd: some policy requests part required.\n"));
return key_senderror(so, m, EINVAL);
}
/*
* checking there is SP already or not.
* SPDUPDATE doesn't depend on whether there is a SP or not.
* If the type is either SPDADD or SPDSETIDX AND a SP is found,
* then error.
*/
newsp = key_getsp(&spidx);
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
if (newsp) {
newsp->state = IPSEC_SPSTATE_DEAD;
key_freesp(newsp);
}
} else {
if (newsp != NULL) {
key_freesp(newsp);
ipseclog((LOG_DEBUG, "key_spdadd: a SP entry exists already.\n"));
return key_senderror(so, m, EEXIST);
}
}
/* allocation new SP entry */
if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) {
return key_senderror(so, m, error);
}
if ((newsp->id = key_getnewspid()) == 0) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, ENOBUFS);
}
/* 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,
&newsp->spidx);
/* sanity check on addr pair */
if (((struct sockaddr *)(src0 + 1))->sa_family !=
((struct sockaddr *)(dst0 + 1))->sa_family) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
if (((struct sockaddr *)(src0 + 1))->sa_len !=
((struct sockaddr *)(dst0 + 1))->sa_len) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
/*
* bark if we have different address family on tunnel address
* specification. applies only if we decapsulate in RFC2401 IPsec
* (implementation limitation).
*/
if (!ipsec_tunnel_device) {
for (req = newsp->req; req; req = req->next) {
if (req->saidx.src.ss_family) {
struct sockaddr *sa;
sa = (struct sockaddr *)(src0 + 1);
if (sa->sa_family != req->saidx.src.ss_family) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
}
if (req->saidx.dst.ss_family) {
struct sockaddr *sa;
sa = (struct sockaddr *)(dst0 + 1);
if (sa->sa_family != req->saidx.dst.ss_family) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
}
}
}
#if defined(NSEC) && NSEC > 0
/*
* based on newsp->req, create/configure tunnels.
* TODO: reuse devices
* TODO: conflicting devices
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -