⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pfkey.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	u_int32_t seq;
{
	int len;

	if (policylen != sizeof(struct sadb_x_policy)) {
		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
		return -1;
	}

	if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
				src, prefs, dst, prefd, proto,
				0, 0,
				policy, policylen, seq)) < 0)
		return -1;

	return len;
}

/*
 * sending SADB_SPDFLUSH message to the kernel.
 * OUT:
 *	positive: success and return length sent.
 *	-1	: error occured, and set errno.
 */
int
pfkey_send_spdflush(so)
	int so;
{
	int len;

	if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
		return -1;

	return len;
}

/*
 * sending SADB_SPDDUMP message to the kernel.
 * OUT:
 *	positive: success and return length sent.
 *	-1	: error occured, and set errno.
 */
int
pfkey_send_spddump(so)
	int so;
{
	int len;

	if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
		return -1;

	return len;
}

/* sending SADB_ADD or SADB_UPDATE message to the kernel */
static int
pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
		keymat, e_type, e_keylen, a_type, a_keylen, flags,
		l_alloc, l_bytes, l_addtime, l_usetime, seq)
	int so;
	u_int type, satype, mode;
	struct sockaddr *src, *dst;
	u_int32_t spi, reqid;
	u_int wsize;
	caddr_t keymat;
	u_int e_type, e_keylen, a_type, a_keylen, flags;
	u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
{
	struct sadb_msg *newmsg;
	int len;
	caddr_t p;
	int plen;
	caddr_t ep;

	/* validity check */
	if (src == NULL || dst == NULL) {
		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
		return -1;
	}
	if (src->sa_family != dst->sa_family) {
		__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
		return -1;
	}
	switch (src->sa_family) {
	case AF_INET:
		plen = sizeof(struct in_addr) << 3;
		break;
	case AF_INET6:
		plen = sizeof(struct in6_addr) << 3;
		break;
	default:
		__ipsec_errcode = EIPSEC_INVAL_FAMILY;
		return -1;
	}

	switch (satype) {
	case SADB_SATYPE_ESP:
		if (e_type == SADB_EALG_NONE) {
			__ipsec_errcode = EIPSEC_NO_ALGS;
			return -1;
		}
		break;
	case SADB_SATYPE_AH:
		if (e_type != SADB_EALG_NONE) {
			__ipsec_errcode = EIPSEC_INVAL_ALGS;
			return -1;
		}
		if (a_type == SADB_AALG_NONE) {
			__ipsec_errcode = EIPSEC_NO_ALGS;
			return -1;
		}
		break;
	case SADB_X_SATYPE_IPCOMP:
		if (e_type == SADB_X_CALG_NONE) {
			__ipsec_errcode = EIPSEC_INVAL_ALGS;
			return -1;
		}
		if (a_type != SADB_AALG_NONE) {
			__ipsec_errcode = EIPSEC_NO_ALGS;
			return -1;
		}
		break;
	default:
		__ipsec_errcode = EIPSEC_INVAL_SATYPE;
		return -1;
	}

	/* create new sadb_msg to reply. */
	len = sizeof(struct sadb_msg)
		+ sizeof(struct sadb_sa)
		+ sizeof(struct sadb_x_sa2)
		+ sizeof(struct sadb_address)
		+ PFKEY_ALIGN8(src->sa_len)
		+ sizeof(struct sadb_address)
		+ PFKEY_ALIGN8(dst->sa_len)
		+ sizeof(struct sadb_lifetime)
		+ sizeof(struct sadb_lifetime);

	if (e_type != SADB_EALG_NONE)
		len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
	if (a_type != SADB_AALG_NONE)
		len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));

	if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
		__ipsec_set_strerror(strerror(errno));
		return -1;
	}
	ep = ((caddr_t)newmsg) + len;

	p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
	                     satype, seq, getpid());
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbxsa2(p, ep, mode, reqid);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
	    IPSEC_ULPROTO_ANY);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
	    IPSEC_ULPROTO_ANY);
	if (!p) {
		free(newmsg);
		return -1;
	}

	if (e_type != SADB_EALG_NONE) {
		p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
		                   keymat, e_keylen);
		if (!p) {
			free(newmsg);
			return -1;
		}
	}
	if (a_type != SADB_AALG_NONE) {
		p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
		                   keymat + e_keylen, a_keylen);
		if (!p) {
			free(newmsg);
			return -1;
		}
	}

	/* set sadb_lifetime for destination */
	p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
			l_alloc, l_bytes, l_addtime, l_usetime);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
			l_alloc, l_bytes, l_addtime, l_usetime);
	if (!p || p != ep) {
		free(newmsg);
		return -1;
	}

	/* send message */
	len = pfkey_send(so, newmsg, len);
	free(newmsg);

	if (len < 0)
		return -1;

	__ipsec_errcode = EIPSEC_NO_ERROR;
	return len;
}

/* sending SADB_DELETE or SADB_GET message to the kernel */
static int
pfkey_send_x2(so, type, satype, mode, src, dst, spi)
	int so;
	u_int type, satype, mode;
	struct sockaddr *src, *dst;
	u_int32_t spi;
{
	struct sadb_msg *newmsg;
	int len;
	caddr_t p;
	int plen;
	caddr_t ep;

	/* validity check */
	if (src == NULL || dst == NULL) {
		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
		return -1;
	}
	if (src->sa_family != dst->sa_family) {
		__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
		return -1;
	}
	switch (src->sa_family) {
	case AF_INET:
		plen = sizeof(struct in_addr) << 3;
		break;
	case AF_INET6:
		plen = sizeof(struct in6_addr) << 3;
		break;
	default:
		__ipsec_errcode = EIPSEC_INVAL_FAMILY;
		return -1;
	}

	/* create new sadb_msg to reply. */
	len = sizeof(struct sadb_msg)
		+ sizeof(struct sadb_sa)
		+ sizeof(struct sadb_address)
		+ PFKEY_ALIGN8(src->sa_len)
		+ sizeof(struct sadb_address)
		+ PFKEY_ALIGN8(dst->sa_len);

	if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
		__ipsec_set_strerror(strerror(errno));
		return -1;
	}
	ep = ((caddr_t)newmsg) + len;

	p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
	    getpid());
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
	    IPSEC_ULPROTO_ANY);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
	    IPSEC_ULPROTO_ANY);
	if (!p || p != ep) {
		free(newmsg);
		return -1;
	}

	/* send message */
	len = pfkey_send(so, newmsg, len);
	free(newmsg);

	if (len < 0)
		return -1;

	__ipsec_errcode = EIPSEC_NO_ERROR;
	return len;
}

/*
 * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
 * to the kernel
 */
static int
pfkey_send_x3(so, type, satype)
	int so;
	u_int type, satype;
{
	struct sadb_msg *newmsg;
	int len;
	caddr_t p;
	caddr_t ep;

	/* validity check */
	switch (type) {
	case SADB_X_PROMISC:
		if (satype != 0 && satype != 1) {
			__ipsec_errcode = EIPSEC_INVAL_SATYPE;
			return -1;
		}
		break;
	default:
		switch (satype) {
		case SADB_SATYPE_UNSPEC:
		case SADB_SATYPE_AH:
		case SADB_SATYPE_ESP:
		case SADB_X_SATYPE_IPCOMP:
			break;
		default:
			__ipsec_errcode = EIPSEC_INVAL_SATYPE;
			return -1;
		}
	}

	/* create new sadb_msg to send. */
	len = sizeof(struct sadb_msg);

	if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
		__ipsec_set_strerror(strerror(errno));
		return -1;
	}
	ep = ((caddr_t)newmsg) + len;

	p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
	    getpid());
	if (!p || p != ep) {
		free(newmsg);
		return -1;
	}

	/* send message */
	len = pfkey_send(so, newmsg, len);
	free(newmsg);

	if (len < 0)
		return -1;

	__ipsec_errcode = EIPSEC_NO_ERROR;
	return len;
}

/* sending SADB_X_SPDADD message to the kernel */
static int
pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
		ltime, vtime, policy, policylen, seq)
	int so;
	struct sockaddr *src, *dst;
	u_int type, prefs, prefd, proto;
	u_int64_t ltime, vtime;
	char *policy;
	int policylen;
	u_int32_t seq;
{
	struct sadb_msg *newmsg;
	int len;
	caddr_t p;
	int plen;
	caddr_t ep;

	/* validity check */
	if (src == NULL || dst == NULL) {
		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
		return -1;
	}
	if (src->sa_family != dst->sa_family) {
		__ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
		return -1;
	}

	switch (src->sa_family) {
	case AF_INET:
		plen = sizeof(struct in_addr) << 3;
		break;
	case AF_INET6:
		plen = sizeof(struct in6_addr) << 3;
		break;
	default:
		__ipsec_errcode = EIPSEC_INVAL_FAMILY;
		return -1;
	}
	if (prefs > plen || prefd > plen) {
		__ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
		return -1;
	}

	/* create new sadb_msg to reply. */
	len = sizeof(struct sadb_msg)
		+ sizeof(struct sadb_address)
		+ PFKEY_ALIGN8(src->sa_len)
		+ sizeof(struct sadb_address)
		+ PFKEY_ALIGN8(src->sa_len)
		+ sizeof(struct sadb_lifetime)
		+ policylen;

	if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
		__ipsec_set_strerror(strerror(errno));
		return -1;
	}
	ep = ((caddr_t)newmsg) + len;

	p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
	    SADB_SATYPE_UNSPEC, seq, getpid());
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
	if (!p) {
		free(newmsg);
		return -1;
	}
	p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
			0, 0, ltime, vtime);
	if (!p || p + policylen != ep) {
		free(newmsg);
		return -1;
	}
	memcpy(p, policy, policylen);

	/* send message */
	len = pfkey_send(so, newmsg, len);
	free(newmsg);

	if (len < 0)
		return -1;

	__ipsec_errcode = EIPSEC_NO_ERROR;
	return len;
}

/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
static int
pfkey_send_x5(so, type, spid)
	int so;
	u_int type;
	u_int32_t spid;
{
	struct sadb_msg *newmsg;
	struct sadb_x_policy xpl;
	int len;
	caddr_t p;
	caddr_t ep;

	/* create new sadb_msg to reply. */
	len = sizeof(struct sadb_msg)
		+ sizeof(xpl);

	if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
		__ipsec_set_strerror(strerror(errno));
		return -1;
	}
	ep = ((caddr_t)newmsg) + len;

	p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
	    SADB_SATYPE_UNSPEC, 0, getpid());
	if (!p) {
		free(newmsg);
		return -1;
	}

	if (p + sizeof(xpl) != ep) {
		free(newmsg);
		return -1;
	}
	memset(&xpl, 0, sizeof(xpl));
	xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl));
	xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
	xpl.sadb_x_policy_id = spid;
	memcpy(p, &xpl, sizeof(xpl));

	/* send message */
	len = pfkey_send(so, newmsg, len);
	free(newmsg);

	if (len < 0)
		return -1;

	__ipsec_errcode = EIPSEC_NO_ERROR;
	return len;
}

/*
 * open a socket.
 * OUT:
 *	-1: fail.
 *	others : success and return value of socket.
 */
int
pfkey_open()
{
	int so;
	const int bufsiz = 128 * 1024;	/*is 128K enough?*/

	if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
		__ipsec_set_strerror(strerror(errno));
		return -1;
	}

	/*
	 * This is a temporary workaround for KAME PR 154.
	 * Don't really care even if it fails.
	 */
	(void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
	(void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));

⌨️ 快捷键说明

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