pfkey.c

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

C
2,135
字号
//==========================================================================////      src/pfkey.c////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD, // FreeBSD or other sources, and are covered by the appropriate// copyright disclaimers included herein.//// Portions created by Red Hat are// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================/*	$KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $	*//* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include <sys/types.h>#include <sys/param.h>#include <sys/socket.h>#include <net/pfkeyv2.h>#include <netkey/key_var.h>#include <netinet/in.h>#include <netinet6/ipsec.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <stdio.h>#include "ipsec_strerror.h"#include "libpfkey.h"#define CALLOC(size, cast) (cast)calloc(1, (size))static int findsupportedmap __P((int));static int setsupportedmap __P((struct sadb_supported *));static struct sadb_alg *findsupportedalg __P((u_int, u_int));static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,	struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,	u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,	u_int32_t, u_int32_t, u_int32_t));static int pfkey_send_x2 __P((int, u_int, u_int, u_int,	struct sockaddr *, struct sockaddr *, u_int32_t));static int pfkey_send_x3 __P((int, u_int, u_int));static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,	struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,	char *, int, u_int32_t));static int pfkey_send_x5 __P((int, u_int, u_int32_t));static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,	u_int, u_int32_t, pid_t));static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,	u_int, u_int, u_int32_t));static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,	struct sockaddr *, u_int, u_int));static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,	u_int32_t, u_int32_t, u_int32_t));static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));/* * make and search supported algorithm structure. */static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };static int supported_map[] = {	SADB_SATYPE_AH,	SADB_SATYPE_ESP,	SADB_X_SATYPE_IPCOMP,};static intfindsupportedmap(satype)	int satype;{	int i;	for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++)		if (supported_map[i] == satype)			return i;	return -1;}static struct sadb_alg *findsupportedalg(satype, alg_id)	u_int satype, alg_id;{	int algno;	int tlen;	caddr_t p;	/* validity check */	algno = findsupportedmap(satype);	if (algno == -1) {		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;		return NULL;	}	if (ipsec_supported[algno] == NULL) {		__ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;		return NULL;	}	tlen = ipsec_supported[algno]->sadb_supported_len		- sizeof(struct sadb_supported);	p = (caddr_t)(ipsec_supported[algno] + 1);	while (tlen > 0) {		if (tlen < sizeof(struct sadb_alg)) {			/* invalid format */			break;		}		if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)			return (struct sadb_alg *)p;		tlen -= sizeof(struct sadb_alg);		p += sizeof(struct sadb_alg);	}	__ipsec_errcode = EIPSEC_NOT_SUPPORTED;	return NULL;}static intsetsupportedmap(sup)	struct sadb_supported *sup;{	struct sadb_supported **ipsup;	switch (sup->sadb_supported_exttype) {	case SADB_EXT_SUPPORTED_AUTH:		ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];		break;	case SADB_EXT_SUPPORTED_ENCRYPT:		ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];		break;	default:		__ipsec_errcode = EIPSEC_INVAL_SATYPE;		return -1;	}	if (*ipsup)		free(*ipsup);	*ipsup = malloc(sup->sadb_supported_len);	if (!*ipsup) {		__ipsec_set_strerror(strerror(errno));		return -1;	}	memcpy(*ipsup, sup, sup->sadb_supported_len);	return 0;}/* * check key length against algorithm specified. * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the * augument, and only calls to ipsec_check_keylen2(); * keylen is the unit of bit. * OUT: *	-1: invalid. *	 0: valid. */intipsec_check_keylen(supported, alg_id, keylen)	u_int supported;	u_int alg_id;	u_int keylen;{	int satype;	/* validity check */	switch (supported) {	case SADB_EXT_SUPPORTED_AUTH:		satype = SADB_SATYPE_AH;		break;	case SADB_EXT_SUPPORTED_ENCRYPT:		satype = SADB_SATYPE_ESP;		break;	default:		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;		return -1;	}	return ipsec_check_keylen2(satype, alg_id, keylen);}/* * check key length against algorithm specified. * satype is one of satype defined at pfkeyv2.h. * keylen is the unit of bit. * OUT: *	-1: invalid. *	 0: valid. */intipsec_check_keylen2(satype, alg_id, keylen)	u_int satype;	u_int alg_id;	u_int keylen;{	struct sadb_alg *alg;	alg = findsupportedalg(satype, alg_id);	if (!alg)		return -1;	if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {		__ipsec_errcode = EIPSEC_INVAL_KEYLEN;		return -1;	}	__ipsec_errcode = EIPSEC_NO_ERROR;	return 0;}/* * get max/min key length against algorithm specified. * satype is one of satype defined at pfkeyv2.h. * keylen is the unit of bit. * OUT: *	-1: invalid. *	 0: valid. */intipsec_get_keylen(supported, alg_id, alg0)	u_int supported, alg_id;	struct sadb_alg *alg0;{	struct sadb_alg *alg;	u_int satype;	/* validity check */	if (!alg0) {		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;		return -1;	}	switch (supported) {	case SADB_EXT_SUPPORTED_AUTH:		satype = SADB_SATYPE_AH;		break;	case SADB_EXT_SUPPORTED_ENCRYPT:		satype = SADB_SATYPE_ESP;		break;	default:		__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;		return -1;	}	alg = findsupportedalg(satype, alg_id);	if (!alg)		return -1;	memcpy(alg0, alg, sizeof(*alg0));	__ipsec_errcode = EIPSEC_NO_ERROR;	return 0;}/* * set the rate for SOFT lifetime against HARD one. * If rate is more than 100 or equal to zero, then set to 100. */static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;u_intpfkey_set_softrate(type, rate)	u_int type, rate;{	__ipsec_errcode = EIPSEC_NO_ERROR;	if (rate > 100 || rate == 0)		rate = 100;	switch (type) {	case SADB_X_LIFETIME_ALLOCATIONS:		soft_lifetime_allocations_rate = rate;		return 0;	case SADB_X_LIFETIME_BYTES:		soft_lifetime_bytes_rate = rate;		return 0;	case SADB_X_LIFETIME_ADDTIME:		soft_lifetime_addtime_rate = rate;		return 0;	case SADB_X_LIFETIME_USETIME:		soft_lifetime_usetime_rate = rate;		return 0;	}	__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;	return 1;}/* * get current rate for SOFT lifetime against HARD one. * ATTENTION: ~0 is returned if invalid type was passed. */u_intpfkey_get_softrate(type)	u_int type;{	switch (type) {	case SADB_X_LIFETIME_ALLOCATIONS:		return soft_lifetime_allocations_rate;	case SADB_X_LIFETIME_BYTES:		return soft_lifetime_bytes_rate;	case SADB_X_LIFETIME_ADDTIME:		return soft_lifetime_addtime_rate;	case SADB_X_LIFETIME_USETIME:		return soft_lifetime_usetime_rate;	}	return ~0;}/* * sending SADB_GETSPI message to the kernel. * OUT: *	positive: success and return length sent. *	-1	: error occured, and set errno. */intpfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)	int so;	u_int satype, mode;	struct sockaddr *src, *dst;	u_int32_t min, max, reqid, seq;{	struct sadb_msg *newmsg;	caddr_t ep;	int len;	int need_spirange = 0;	caddr_t p;	int plen;	/* 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;	}	if (min > max || (min > 0 && min <= 255)) {		__ipsec_errcode = EIPSEC_INVAL_SPI;		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 send. */	len = sizeof(struct sadb_msg)		+ sizeof(struct sadb_x_sa2)		+ sizeof(struct sadb_address)		+ PFKEY_ALIGN8(src->sa_len)		+ sizeof(struct sadb_address)		+ PFKEY_ALIGN8(dst->sa_len);	if (min > 255 && max < ~0) {		need_spirange++;		len += sizeof(struct sadb_spirange);	}	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, SADB_GETSPI,	    len, satype, seq, getpid());	if (!p) {		free(newmsg);		return -1;	}	p = pfkey_setsadbxsa2(p, ep, mode, reqid);	if (!p) {		free(newmsg);		return -1;	}	/* set sadb_address for source */	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,	    IPSEC_ULPROTO_ANY);	if (!p) {		free(newmsg);		return -1;	}	/* set sadb_address for destination */	p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,	    IPSEC_ULPROTO_ANY);	if (!p) {		free(newmsg);		return -1;	}	/* proccessing spi range */	if (need_spirange) {		struct sadb_spirange spirange;		if (p + sizeof(spirange) > ep) {			free(newmsg);			return -1;		}		memset(&spirange, 0, sizeof(spirange));		spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));		spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;		spirange.sadb_spirange_min = min;		spirange.sadb_spirange_max = max;		memcpy(p, &spirange, sizeof(spirange));		p += sizeof(spirange);	}	if (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_UPDATE message to the kernel. * The length of key material is a_keylen + e_keylen. * OUT: *	positive: success and return length sent. *	-1	: error occured, and set errno. */intpfkey_send_update(so, 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 satype, mode, wsize;	struct sockaddr *src, *dst;	u_int32_t spi, reqid;	caddr_t keymat;	u_int e_type, e_keylen, a_type, a_keylen, flags;	u_int32_t l_alloc;	u_int64_t l_bytes, l_addtime, l_usetime;	u_int32_t seq;{	int len;	if ((len = pfkey_send_x1(so, SADB_UPDATE, 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)) < 0)		return -1;	return len;}/* * sending SADB_ADD message to the kernel. * The length of key material is a_keylen + e_keylen. * OUT: *	positive: success and return length sent. *	-1	: error occured, and set errno. */intpfkey_send_add(so, 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 satype, mode, wsize;	struct sockaddr *src, *dst;	u_int32_t spi, reqid;	caddr_t keymat;	u_int e_type, e_keylen, a_type, a_keylen, flags;	u_int32_t l_alloc;	u_int64_t l_bytes, l_addtime, l_usetime;	u_int32_t seq;{	int len;	if ((len = pfkey_send_x1(so, SADB_ADD, 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)) < 0)		return -1;	return len;}/* * sending SADB_DELETE message to the kernel. * OUT: *	positive: success and return length sent. *	-1	: error occured, and set errno. */intpfkey_send_delete(so, satype, mode, src, dst, spi)	int so;	u_int satype, mode;	struct sockaddr *src, *dst;	u_int32_t spi;{	int len;	if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)		return -1;	return len;}/* * sending SADB_DELETE without spi to the kernel.  This is * the "delete all" request (an extension also present in * Solaris). * * OUT: *	positive: success and return length sent *	-1	: error occured, and set errno */intpfkey_send_delete_all(so, satype, mode, src, dst)	int so;	u_int satype, mode;	struct sockaddr *src, *dst;{	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_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, SADB_DELETE, len, satype, 0,	    getpid());	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_GET message to the kernel. * OUT: *	positive: success and return length sent. *	-1	: error occured, and set errno. */intpfkey_send_get(so, satype, mode, src, dst, spi)	int so;	u_int satype, mode;	struct sockaddr *src, *dst;	u_int32_t spi;{	int len;	if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)		return -1;	return len;}/* * sending SADB_REGISTER message to the kernel. * OUT: *	positive: success and return length sent. *	-1	: error occured, and set errno. */intpfkey_send_register(so, satype)	int so;	u_int satype;{	int len, algno;	if (satype == PF_UNSPEC) {		for (algno = 0;		     algno < sizeof(supported_map)/sizeof(supported_map[0]);		     algno++) {			if (ipsec_supported[algno]) {				free(ipsec_supported[algno]);				ipsec_supported[algno] = NULL;			}		}	} else {		algno = findsupportedmap(satype);		if (algno == -1) {			__ipsec_errcode = EIPSEC_INVAL_ARGUMENT;			return -1;		}		if (ipsec_supported[algno]) {			free(ipsec_supported[algno]);			ipsec_supported[algno] = NULL;		}	}	if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)		return -1;	return len;}/* * receiving SADB_REGISTER message from the kernel, and copy buffer for

⌨️ 快捷键说明

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