esp_output.c

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

C
728
字号
		esp = mtod(md, struct esp *);	}		nxt = *nexthdrp;	*nexthdrp = IPPROTO_ESP;	switch (af) {#ifdef INET	case AF_INET:		if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))			ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);		else {			ipseclog((LOG_ERR,			    "IPv4 ESP output: size exceeds limit\n"));			ipsecstat.out_inval++;			m_freem(m);			error = EMSGSIZE;			goto fail;		}		break;#endif#ifdef INET6	case AF_INET6:		/* total packet length will be computed in ip6_output() */		break;#endif	}    }	/* initialize esp header. */	esp->esp_spi = spi;	if ((sav->flags & SADB_X_EXT_OLD) == 0) {		struct newesp *nesp;		nesp = (struct newesp *)esp;		if (sav->replay->count == ~0) {			if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {				/* XXX Is it noisy ? */				ipseclog((LOG_WARNING,				    "replay counter overflowed. %s\n",				    ipsec_logsastr(sav)));				stat->out_inval++;				m_freem(m);				return EINVAL;			}		}		sav->replay->count++;		/*		 * XXX sequence number must not be cycled, if the SA is		 * installed by IKE daemon.		 */		nesp->esp_seq = htonl(sav->replay->count);	}    {	/*	 * find the last mbuf. make some room for ESP trailer.	 */#ifdef INET	struct ip *ip = NULL;#endif	size_t padbound;	u_char *extend;	int i;	int randpadmax;	if (algo->padbound)		padbound = algo->padbound;	else		padbound = 4;	/* ESP packet, including nxthdr field, must be length of 4n */	if (padbound < 4)		padbound = 4;		extendsiz = padbound - (plen % padbound);	if (extendsiz == 1)		extendsiz = padbound + 1;	/* random padding */	switch (af) {#ifdef INET	case AF_INET:		randpadmax = ip4_esp_randpad;		break;#endif#ifdef INET6	case AF_INET6:		randpadmax = ip6_esp_randpad;		break;#endif	default:		randpadmax = -1;		break;	}	if (randpadmax < 0 || plen + extendsiz >= randpadmax)		;	else {		int n;		/* round */		randpadmax = (randpadmax / padbound) * padbound;		n = (randpadmax - plen + extendsiz) / padbound;		if (n > 0)			n = (random() % n) * padbound;		else			n = 0;		/*		 * make sure we do not pad too much.		 * MLEN limitation comes from the trailer attachment		 * code below.		 * 256 limitation comes from sequential padding.		 * also, the 1-octet length field in ESP trailer imposes		 * limitation (but is less strict than sequential padding		 * as length field do not count the last 2 octets).		 */		if (extendsiz + n <= MLEN && extendsiz + n < 256)			extendsiz += n;	}#ifdef DIAGNOSTIC	if (extendsiz > MLEN || extendsiz >= 256)		panic("extendsiz too big in esp_output");#endif	n = m;	while (n->m_next)		n = n->m_next;	/*	 * if M_EXT, the external mbuf data may be shared among	 * two consequtive TCP packets, and it may be unsafe to use the	 * trailing space.	 */	if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {		extend = mtod(n, u_char *) + n->m_len;		n->m_len += extendsiz;		m->m_pkthdr.len += extendsiz;	} else {		struct mbuf *nn;		MGET(nn, M_DONTWAIT, MT_DATA);		if (!nn) {			ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",			    afnumber));			m_freem(m);			error = ENOBUFS;			goto fail;		}		extend = mtod(nn, u_char *);		nn->m_len = extendsiz;		nn->m_next = NULL;		n->m_next = nn;		n = nn;		m->m_pkthdr.len += extendsiz;	}	switch (sav->flags & SADB_X_EXT_PMASK) {	case SADB_X_EXT_PRAND:		key_randomfill(extend, extendsiz);		break;	case SADB_X_EXT_PZERO:		bzero(extend, extendsiz);		break;	case SADB_X_EXT_PSEQ:		for (i = 0; i < extendsiz; i++)			extend[i] = (i + 1) & 0xff;		break;	}	/* initialize esp trailer. */	esptail = (struct esptail *)		(mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));	esptail->esp_nxt = nxt;	esptail->esp_padlen = extendsiz - 2;	/* modify IP header (for ESP header part only) */	switch (af) {#ifdef INET	case AF_INET:		ip = mtod(m, struct ip *);		if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))			ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);		else {			ipseclog((LOG_ERR,			    "IPv4 ESP output: size exceeds limit\n"));			ipsecstat.out_inval++;			m_freem(m);			error = EMSGSIZE;			goto fail;		}		break;#endif#ifdef INET6	case AF_INET6:		/* total packet length will be computed in ip6_output() */		break;#endif	}    }	/*	 * pre-compute and cache intermediate key	 */	error = esp_schedule(algo, sav);	if (error) {		m_freem(m);		stat->out_inval++;		goto fail;	}	/*	 * encrypt the packet, based on security association	 * and the algorithm specified.	 */	if (!algo->encrypt)		panic("internal error: no encrypt function");	if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {		/* m is already freed */		ipseclog((LOG_ERR, "packet encryption failure\n"));		stat->out_inval++;		error = EINVAL;		goto fail;	}	/*	 * calculate ICV if required.	 */	if (!sav->replay)		goto noantireplay;	if (!sav->key_auth)		goto noantireplay;	if (sav->key_auth == SADB_AALG_NONE)		goto noantireplay;    {	const struct ah_algorithm *aalgo;	u_char authbuf[AH_MAXSUMSIZE];	struct mbuf *n;	u_char *p;	size_t siz;#ifdef INET	struct ip *ip;#endif	aalgo = ah_algorithm_lookup(sav->alg_auth);	if (!aalgo)		goto noantireplay;	siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);	if (AH_MAXSUMSIZE < siz)		panic("assertion failed for AH_MAXSUMSIZE");	if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {		ipseclog((LOG_ERR, "ESP checksum generation failure\n"));		m_freem(m);		error = EINVAL;		stat->out_inval++;		goto fail;	}	n = m;	while (n->m_next)		n = n->m_next;	if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */		n->m_len += siz;		m->m_pkthdr.len += siz;		p = mtod(n, u_char *) + n->m_len - siz;	} else {		struct mbuf *nn;		MGET(nn, M_DONTWAIT, MT_DATA);		if (!nn) {			ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",			    afnumber));			m_freem(m);			error = ENOBUFS;			goto fail;		}		nn->m_len = siz;		nn->m_next = NULL;		n->m_next = nn;		n = nn;		m->m_pkthdr.len += siz;		p = mtod(nn, u_char *);	}	bcopy(authbuf, p, siz);	/* modify IP header (for ESP header part only) */	switch (af) {#ifdef INET	case AF_INET:		ip = mtod(m, struct ip *);		if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))			ip->ip_len = htons(ntohs(ip->ip_len) + siz);		else {			ipseclog((LOG_ERR,			    "IPv4 ESP output: size exceeds limit\n"));			ipsecstat.out_inval++;			m_freem(m);			error = EMSGSIZE;			goto fail;		}		break;#endif#ifdef INET6	case AF_INET6:		/* total packet length will be computed in ip6_output() */		break;#endif	}    }noantireplay:	if (!m) {		ipseclog((LOG_ERR,		    "NULL mbuf after encryption in esp%d_output", afnumber));	} else		stat->out_success++;	stat->out_esphist[sav->alg_enc]++;	key_sa_recordxfer(sav, m);	return 0;fail:#if 1	return error;#else	panic("something bad in esp_output");#endif}#ifdef INETintesp4_output(m, isr)	struct mbuf *m;	struct ipsecrequest *isr;{	struct ip *ip;	if (m->m_len < sizeof(struct ip)) {		ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));		m_freem(m);		return 0;	}	ip = mtod(m, struct ip *);	/* XXX assumes that m->m_next points to payload */	return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);}#endif /* INET */#ifdef INET6intesp6_output(m, nexthdrp, md, isr)	struct mbuf *m;	u_char *nexthdrp;	struct mbuf *md;	struct ipsecrequest *isr;{	if (m->m_len < sizeof(struct ip6_hdr)) {		ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));		m_freem(m);		return 0;	}	return esp_output(m, nexthdrp, md, isr, AF_INET6);}#endif /* INET6 */

⌨️ 快捷键说明

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