esp_output.c

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

C
728
字号
//==========================================================================////      src/sys/netinet6/esp_output.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: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $	*//* * Copyright (C) 1995, 1996, 1997, and 1998 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. *//* * RFC1827/2406 Encapsulated Security Payload. */#include <sys/param.h>#if !(defined(__FreeBSD__) && __FreeBSD__ >= 4)#include <sys/malloc.h>#endif#include <sys/mbuf.h>#include <sys/domain.h>#include <sys/protosw.h>#include <sys/socket.h>#include <sys/socketvar.h>#include <sys/errno.h>#include <sys/time.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/in_var.h>#ifdef INET6#include <netinet/ip6.h>#include <netinet6/ip6_var.h>#include <netinet/icmp6.h>#endif#include <netinet6/ipsec.h>#include <netinet6/ah.h>#include <netinet6/esp.h>#include <netkey/key.h>#include <netkey/keydb.h>static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,	struct ipsecrequest *, int));/* * compute ESP header size. */size_tesp_hdrsiz(isr)	struct ipsecrequest *isr;{	struct secasvar *sav;	const struct esp_algorithm *algo;	const struct ah_algorithm *aalgo;	size_t ivlen;	size_t authlen;	size_t hdrsiz;	/* sanity check */	if (isr == NULL)		panic("esp_hdrsiz: NULL was passed.\n");	sav = isr->sav;	if (isr->saidx.proto != IPPROTO_ESP)		panic("unsupported mode passed to esp_hdrsiz");	if (sav == NULL)		goto estimate;	if (sav->state != SADB_SASTATE_MATURE	 && sav->state != SADB_SASTATE_DYING)		goto estimate;	/* we need transport mode ESP. */	algo = esp_algorithm_lookup(sav->alg_enc);	if (!algo)		goto estimate;	ivlen = sav->ivlen;	if (ivlen < 0)		goto estimate;	/*	 * XXX	 * right now we don't calcurate the padding size.  simply	 * treat the padding size as constant, for simplicity.	 *	 * XXX variable size padding support	 */	if (sav->flags & SADB_X_EXT_OLD) {		/* RFC 1827 */		hdrsiz = sizeof(struct esp) + ivlen + 9;	} else {		/* RFC 2406 */		aalgo = ah_algorithm_lookup(sav->alg_auth);		if (aalgo && sav->replay && sav->key_auth)			authlen = (aalgo->sumsiz)(sav);		else			authlen = 0;		hdrsiz = sizeof(struct newesp) + ivlen + 9 + authlen;	}	return hdrsiz;   estimate:	/*	 * ASSUMING:	 *	sizeof(struct newesp) > sizeof(struct esp).	 *	esp_max_ivlen() = max ivlen for CBC mode	 *	9 = (maximum padding length without random padding length)	 *	   + (Pad Length field) + (Next Header field).	 *	16 = maximum ICV we support.	 */	return sizeof(struct newesp) + esp_max_ivlen() + 9 + 16;}/* * Modify the packet so that the payload is encrypted. * The mbuf (m) must start with IPv4 or IPv6 header. * On failure, free the given mbuf and return NULL. * * on invocation: *	m   nexthdrp md *	v   v        v *	IP ......... payload * during the encryption: *	m   nexthdrp mprev md *	v   v        v     v *	IP ............... esp iv payload pad padlen nxthdr *	                   <--><-><------><---------------> *	                   esplen plen    extendsiz *	                       ivlen *	                   <-----> esphlen *	<-> hlen *	<-----------------> espoff */static intesp_output(m, nexthdrp, md, isr, af)	struct mbuf *m;	u_char *nexthdrp;	struct mbuf *md;	struct ipsecrequest *isr;	int af;{	struct mbuf *n;	struct mbuf *mprev;	struct esp *esp;	struct esptail *esptail;	struct secasvar *sav = isr->sav;	const struct esp_algorithm *algo;	u_int32_t spi;	u_int8_t nxt = 0;	size_t plen;	/* payload length to be encrypted */	size_t espoff;	int ivlen;	int afnumber;	size_t extendsiz;	int error = 0;	struct ipsecstat *stat;	switch (af) {#ifdef INET	case AF_INET:		afnumber = 4;		stat = &ipsecstat;		break;#endif#ifdef INET6	case AF_INET6:		afnumber = 6;		stat = &ipsec6stat;		break;#endif	default:		ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));		return 0;	/* no change at all */	}	/* some sanity check */	if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {		switch (af) {#ifdef INET		case AF_INET:		    {			struct ip *ip;			ip = mtod(m, struct ip *);			ipseclog((LOG_DEBUG, "esp4_output: internal error: "				"sav->replay is null: %x->%x, SPI=%u\n",				(u_int32_t)ntohl(ip->ip_src.s_addr),				(u_int32_t)ntohl(ip->ip_dst.s_addr),				(u_int32_t)ntohl(sav->spi)));			ipsecstat.out_inval++;			break;		    }#endif /* INET */#ifdef INET6		case AF_INET6:			ipseclog((LOG_DEBUG, "esp6_output: internal error: "				"sav->replay is null: SPI=%u\n",				(u_int32_t)ntohl(sav->spi)));			ipsec6stat.out_inval++;			break;#endif /* INET6 */		default:			panic("esp_output: should not reach here");		}		m_freem(m);		return EINVAL;	}	algo = esp_algorithm_lookup(sav->alg_enc);	if (!algo) {		ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "		    "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));		m_freem(m);		return EINVAL;	}	spi = sav->spi;	ivlen = sav->ivlen;	/* should be okey */	if (ivlen < 0) {		panic("invalid ivlen");	}    {	/*	 * insert ESP header.	 * XXX inserts ESP header right after IPv4 header.  should	 * chase the header chain.	 * XXX sequential number	 */#ifdef INET	struct ip *ip = NULL;#endif#ifdef INET6	struct ip6_hdr *ip6 = NULL;#endif	size_t esplen;	/* sizeof(struct esp/newesp) */	size_t esphlen;	/* sizeof(struct esp/newesp) + ivlen */	size_t hlen = 0;	/* ip header len */	if (sav->flags & SADB_X_EXT_OLD) {		/* RFC 1827 */		esplen = sizeof(struct esp);	} else {		/* RFC 2406 */		if (sav->flags & SADB_X_EXT_DERIV)			esplen = sizeof(struct esp);		else			esplen = sizeof(struct newesp);	}	esphlen = esplen + ivlen;	for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)		;	if (mprev == NULL || mprev->m_next != md) {		ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",		    afnumber));		m_freem(m);		return EINVAL;	}	plen = 0;	for (n = md; n; n = n->m_next)		plen += n->m_len;	switch (af) {#ifdef INET	case AF_INET:		ip = mtod(m, struct ip *);#ifdef _IP_VHL		hlen = IP_VHL_HL(ip->ip_vhl) << 2;#else		hlen = ip->ip_hl << 2;#endif		break;#endif#ifdef INET6	case AF_INET6:		ip6 = mtod(m, struct ip6_hdr *);		hlen = sizeof(*ip6);		break;#endif	}	/* make the packet over-writable */	mprev->m_next = NULL;	if ((md = ipsec_copypkt(md)) == NULL) {		m_freem(m);		error = ENOBUFS;		goto fail;	}	mprev->m_next = md;	espoff = m->m_pkthdr.len - plen;	/*	 * grow the mbuf to accomodate ESP header.	 * before: IP ... payload	 * after:  IP ... ESP IV payload	 */	if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {		MGET(n, M_DONTWAIT, MT_DATA);		if (!n) {			m_freem(m);			error = ENOBUFS;			goto fail;		}		n->m_len = esphlen;		mprev->m_next = n;		n->m_next = md;		m->m_pkthdr.len += esphlen;		esp = mtod(n, struct esp *);	} else {		md->m_len += esphlen;		md->m_data -= esphlen;		m->m_pkthdr.len += esphlen;

⌨️ 快捷键说明

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