mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
Removing old, dead, KAME IPsec files as part of the move to the
new FAST_IPSEC based IPsec stack. Approved by: re Reviewed by: bz
This commit is contained in:
parent
ae259a3d16
commit
e66ff7fc8e
17 changed files with 0 additions and 20184 deletions
|
|
@ -1,190 +0,0 @@
|
|||
/* $KAME: ah_aesxcbcmac.c,v 1.6 2003/07/22 02:30:54 itojun Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996, 1997, 1998 and 2003 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#include <netinet6/ah.h>
|
||||
#include <netinet6/ah_aesxcbcmac.h>
|
||||
|
||||
#include <netkey/key.h>
|
||||
|
||||
#include <crypto/rijndael/rijndael.h>
|
||||
|
||||
#define AES_BLOCKSIZE 16
|
||||
|
||||
typedef struct {
|
||||
u_int8_t e[AES_BLOCKSIZE];
|
||||
u_int8_t buf[AES_BLOCKSIZE];
|
||||
size_t buflen;
|
||||
u_int32_t r_k1s[(RIJNDAEL_MAXNR+1)*4];
|
||||
u_int32_t r_k2s[(RIJNDAEL_MAXNR+1)*4];
|
||||
u_int32_t r_k3s[(RIJNDAEL_MAXNR+1)*4];
|
||||
int r_nr; /* key-length-dependent number of rounds */
|
||||
u_int8_t k2[AES_BLOCKSIZE];
|
||||
u_int8_t k3[AES_BLOCKSIZE];
|
||||
} aesxcbc_ctx;
|
||||
|
||||
int
|
||||
ah_aes_xcbc_mac_init(state, sav)
|
||||
struct ah_algorithm_state *state;
|
||||
struct secasvar *sav;
|
||||
{
|
||||
u_int8_t k1seed[AES_BLOCKSIZE] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 };
|
||||
u_int8_t k2seed[AES_BLOCKSIZE] = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 };
|
||||
u_int8_t k3seed[AES_BLOCKSIZE] = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 };
|
||||
u_int32_t r_ks[(RIJNDAEL_MAXNR+1)*4];
|
||||
aesxcbc_ctx *ctx;
|
||||
u_int8_t k1[AES_BLOCKSIZE];
|
||||
|
||||
if (!state)
|
||||
panic("ah_aes_xcbc_mac_init: what?");
|
||||
|
||||
state->sav = sav;
|
||||
state->foo = (void *)malloc(sizeof(aesxcbc_ctx), M_TEMP, M_NOWAIT);
|
||||
if (!state->foo)
|
||||
return ENOBUFS;
|
||||
bzero(state->foo, sizeof(aesxcbc_ctx));
|
||||
|
||||
ctx = (aesxcbc_ctx *)state->foo;
|
||||
|
||||
if ((ctx->r_nr = rijndaelKeySetupEnc(r_ks,
|
||||
(char *)_KEYBUF(sav->key_auth), AES_BLOCKSIZE * 8)) == 0)
|
||||
return -1;
|
||||
rijndaelEncrypt(r_ks, ctx->r_nr, k1seed, k1);
|
||||
rijndaelEncrypt(r_ks, ctx->r_nr, k2seed, ctx->k2);
|
||||
rijndaelEncrypt(r_ks, ctx->r_nr, k3seed, ctx->k3);
|
||||
if (rijndaelKeySetupEnc(ctx->r_k1s, k1, AES_BLOCKSIZE * 8) == 0)
|
||||
return -1;
|
||||
if (rijndaelKeySetupEnc(ctx->r_k2s, ctx->k2, AES_BLOCKSIZE * 8) == 0)
|
||||
return -1;
|
||||
if (rijndaelKeySetupEnc(ctx->r_k3s, ctx->k3, AES_BLOCKSIZE * 8) == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ah_aes_xcbc_mac_loop(state, addr, len)
|
||||
struct ah_algorithm_state *state;
|
||||
u_int8_t *addr;
|
||||
size_t len;
|
||||
{
|
||||
u_int8_t buf[AES_BLOCKSIZE];
|
||||
aesxcbc_ctx *ctx;
|
||||
u_int8_t *ep;
|
||||
int i;
|
||||
|
||||
if (!state || !state->foo)
|
||||
panic("ah_aes_xcbc_mac_loop: what?");
|
||||
|
||||
ctx = (aesxcbc_ctx *)state->foo;
|
||||
ep = addr + len;
|
||||
|
||||
if (ctx->buflen == sizeof(ctx->buf)) {
|
||||
for (i = 0; i < sizeof(ctx->e); i++)
|
||||
ctx->buf[i] ^= ctx->e[i];
|
||||
rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, ctx->e);
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
if (ctx->buflen + len < sizeof(ctx->buf)) {
|
||||
bcopy(addr, ctx->buf + ctx->buflen, len);
|
||||
ctx->buflen += len;
|
||||
return;
|
||||
}
|
||||
if (ctx->buflen && ctx->buflen + len > sizeof(ctx->buf)) {
|
||||
bcopy(addr, ctx->buf + ctx->buflen,
|
||||
sizeof(ctx->buf) - ctx->buflen);
|
||||
for (i = 0; i < sizeof(ctx->e); i++)
|
||||
ctx->buf[i] ^= ctx->e[i];
|
||||
rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, ctx->e);
|
||||
addr += sizeof(ctx->buf) - ctx->buflen;
|
||||
ctx->buflen = 0;
|
||||
}
|
||||
/* due to the special processing for M[n], "=" case is not included */
|
||||
while (addr + AES_BLOCKSIZE < ep) {
|
||||
bcopy(addr, buf, AES_BLOCKSIZE);
|
||||
for (i = 0; i < sizeof(buf); i++)
|
||||
buf[i] ^= ctx->e[i];
|
||||
rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, buf, ctx->e);
|
||||
addr += AES_BLOCKSIZE;
|
||||
}
|
||||
if (addr < ep) {
|
||||
bcopy(addr, ctx->buf + ctx->buflen, ep - addr);
|
||||
ctx->buflen += ep - addr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ah_aes_xcbc_mac_result(state, addr, l)
|
||||
struct ah_algorithm_state *state;
|
||||
u_int8_t *addr;
|
||||
size_t l;
|
||||
{
|
||||
u_char digest[AES_BLOCKSIZE];
|
||||
aesxcbc_ctx *ctx;
|
||||
int i;
|
||||
|
||||
ctx = (aesxcbc_ctx *)state->foo;
|
||||
|
||||
if (ctx->buflen == sizeof(ctx->buf)) {
|
||||
for (i = 0; i < sizeof(ctx->buf); i++) {
|
||||
ctx->buf[i] ^= ctx->e[i];
|
||||
ctx->buf[i] ^= ctx->k2[i];
|
||||
}
|
||||
rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, digest);
|
||||
} else {
|
||||
for (i = ctx->buflen; i < sizeof(ctx->buf); i++)
|
||||
ctx->buf[i] = (i == ctx->buflen) ? 0x80 : 0x00;
|
||||
for (i = 0; i < sizeof(ctx->buf); i++) {
|
||||
ctx->buf[i] ^= ctx->e[i];
|
||||
ctx->buf[i] ^= ctx->k3[i];
|
||||
}
|
||||
rijndaelEncrypt(ctx->r_k1s, ctx->r_nr, ctx->buf, digest);
|
||||
}
|
||||
|
||||
bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest));
|
||||
|
||||
free(state->foo, M_TEMP);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,586 +0,0 @@
|
|||
/* $FreeBSD$ */
|
||||
/* $KAME: ah_output.c,v 1.38 2003/09/06 05:15:43 itojun 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RFC1826/2402 authentication header.
|
||||
*/
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#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 <sys/syslog.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>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipsec6.h>
|
||||
#endif
|
||||
#include <netinet6/ah.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ah6.h>
|
||||
#endif
|
||||
#include <netkey/key.h>
|
||||
#include <netkey/keydb.h>
|
||||
|
||||
#ifdef INET
|
||||
static struct in_addr *ah4_finaldst __P((struct mbuf *));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* compute AH header size.
|
||||
* transport mode only. for tunnel mode, we should implement
|
||||
* virtual interface, and control MTU/MSS by the interface MTU.
|
||||
*/
|
||||
size_t
|
||||
ah_hdrsiz(isr)
|
||||
struct ipsecrequest *isr;
|
||||
{
|
||||
const struct ah_algorithm *algo;
|
||||
size_t hdrsiz;
|
||||
|
||||
/* sanity check */
|
||||
if (isr == NULL)
|
||||
panic("ah_hdrsiz: NULL was passed.");
|
||||
|
||||
if (isr->saidx.proto != IPPROTO_AH)
|
||||
panic("unsupported mode passed to ah_hdrsiz");
|
||||
|
||||
if (isr->sav == NULL)
|
||||
goto estimate;
|
||||
if (isr->sav->state != SADB_SASTATE_MATURE
|
||||
&& isr->sav->state != SADB_SASTATE_DYING)
|
||||
goto estimate;
|
||||
|
||||
/* we need transport mode AH. */
|
||||
algo = ah_algorithm_lookup(isr->sav->alg_auth);
|
||||
if (!algo)
|
||||
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
|
||||
*/
|
||||
hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1));
|
||||
if (isr->sav->flags & SADB_X_EXT_OLD)
|
||||
hdrsiz += sizeof(struct ah);
|
||||
else
|
||||
hdrsiz += sizeof(struct newah);
|
||||
|
||||
return hdrsiz;
|
||||
|
||||
estimate:
|
||||
/* ASSUMING:
|
||||
* sizeof(struct newah) > sizeof(struct ah).
|
||||
* AH_MAXSUMSIZE is multiple of 4.
|
||||
*/
|
||||
return sizeof(struct newah) + AH_MAXSUMSIZE;
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
/*
|
||||
* Modify the packet so that it includes the authentication data.
|
||||
* The mbuf passed must start with IPv4 header.
|
||||
*
|
||||
* assumes that the first mbuf contains IPv4 header + option only.
|
||||
* the function does not modify m.
|
||||
*/
|
||||
int
|
||||
ah4_output(m, isr)
|
||||
struct mbuf *m;
|
||||
struct ipsecrequest *isr;
|
||||
{
|
||||
struct secasvar *sav = isr->sav;
|
||||
const struct ah_algorithm *algo;
|
||||
u_int32_t spi;
|
||||
u_char *ahdrpos;
|
||||
u_int8_t *ahsumpos = NULL;
|
||||
size_t hlen = 0; /* IP header+option in bytes */
|
||||
size_t plen = 0; /* AH payload size in bytes */
|
||||
size_t ahlen = 0; /* plen + sizeof(ah) */
|
||||
struct ip *ip;
|
||||
in_addr_t saveaddr = { 0 };
|
||||
struct in_addr *finaldst;
|
||||
int error;
|
||||
|
||||
/* sanity checks */
|
||||
if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
|
||||
struct ip *ip;
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
ipseclog((LOG_DEBUG, "ah4_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++;
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
algo = ah_algorithm_lookup(sav->alg_auth);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: "
|
||||
"SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
|
||||
ipsecstat.out_inval++;
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
spi = sav->spi;
|
||||
|
||||
/*
|
||||
* determine the size to grow.
|
||||
*/
|
||||
if (sav->flags & SADB_X_EXT_OLD) {
|
||||
/* RFC 1826 */
|
||||
plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
|
||||
ahlen = plen + sizeof(struct ah);
|
||||
} else {
|
||||
/* RFC 2402 */
|
||||
plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
|
||||
ahlen = plen + sizeof(struct newah);
|
||||
}
|
||||
|
||||
/*
|
||||
* grow the mbuf to accomodate AH.
|
||||
*/
|
||||
ip = mtod(m, struct ip *);
|
||||
#ifdef _IP_VHL
|
||||
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
||||
#else
|
||||
hlen = ip->ip_hl << 2;
|
||||
#endif
|
||||
|
||||
if (m->m_len != hlen)
|
||||
panic("ah4_output: assumption failed (first mbuf length)");
|
||||
if (M_LEADINGSPACE(m->m_next) < ahlen) {
|
||||
struct mbuf *n;
|
||||
MGET(n, M_DONTWAIT, MT_DATA);
|
||||
if (!n) {
|
||||
ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n",
|
||||
__LINE__));
|
||||
m_freem(m);
|
||||
return ENOBUFS;
|
||||
}
|
||||
n->m_len = ahlen;
|
||||
n->m_next = m->m_next;
|
||||
m->m_next = n;
|
||||
m->m_pkthdr.len += ahlen;
|
||||
ahdrpos = mtod(n, u_char *);
|
||||
} else {
|
||||
m->m_next->m_len += ahlen;
|
||||
m->m_next->m_data -= ahlen;
|
||||
m->m_pkthdr.len += ahlen;
|
||||
ahdrpos = mtod(m->m_next, u_char *);
|
||||
}
|
||||
|
||||
ip = mtod(m, struct ip *); /* just to be sure */
|
||||
|
||||
/*
|
||||
* initialize AH.
|
||||
*/
|
||||
if (sav->flags & SADB_X_EXT_OLD) {
|
||||
struct ah *ahdr;
|
||||
|
||||
ahdr = (struct ah *)ahdrpos;
|
||||
ahsumpos = (u_char *)(ahdr + 1);
|
||||
ahdr->ah_len = plen >> 2;
|
||||
ahdr->ah_nxt = ip->ip_p;
|
||||
ahdr->ah_reserve = htons(0);
|
||||
ahdr->ah_spi = spi;
|
||||
bzero(ahdr + 1, plen);
|
||||
} else {
|
||||
struct newah *ahdr;
|
||||
|
||||
ahdr = (struct newah *)ahdrpos;
|
||||
ahsumpos = (u_char *)(ahdr + 1);
|
||||
ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */
|
||||
ahdr->ah_nxt = ip->ip_p;
|
||||
ahdr->ah_reserve = htons(0);
|
||||
ahdr->ah_spi = spi;
|
||||
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)));
|
||||
ipsecstat.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.
|
||||
*/
|
||||
ahdr->ah_seq = htonl(sav->replay->count & 0xffffffff);
|
||||
bzero(ahdr + 1, plen);
|
||||
}
|
||||
|
||||
/*
|
||||
* modify IPv4 header.
|
||||
*/
|
||||
ip->ip_p = IPPROTO_AH;
|
||||
if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
|
||||
ip->ip_len = htons(ntohs(ip->ip_len) + ahlen);
|
||||
else {
|
||||
ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n"));
|
||||
ipsecstat.out_inval++;
|
||||
m_freem(m);
|
||||
return EMSGSIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is source routing option, update destination field in
|
||||
* the IPv4 header to the final destination.
|
||||
* Note that we do not need to update source routing option itself
|
||||
* (as done in IPv4 AH processing -- see ip6_output()), since
|
||||
* source routing option is not part of the ICV computation.
|
||||
*/
|
||||
finaldst = ah4_finaldst(m);
|
||||
if (finaldst) {
|
||||
saveaddr = ip->ip_dst.s_addr;
|
||||
ip->ip_dst.s_addr = finaldst->s_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* calcurate the checksum, based on security association
|
||||
* and the algorithm specified.
|
||||
*/
|
||||
error = ah4_calccksum(m, ahsumpos, plen, algo, sav);
|
||||
if (error) {
|
||||
ipseclog((LOG_ERR,
|
||||
"error after ah4_calccksum, called from ah4_output"));
|
||||
m_freem(m);
|
||||
m = NULL;
|
||||
ipsecstat.out_inval++;
|
||||
return error;
|
||||
}
|
||||
|
||||
if (finaldst) {
|
||||
ip = mtod(m, struct ip *); /* just to make sure */
|
||||
ip->ip_dst.s_addr = saveaddr;
|
||||
}
|
||||
ipsecstat.out_success++;
|
||||
ipsecstat.out_ahhist[sav->alg_auth]++;
|
||||
key_sa_recordxfer(sav, m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate AH length */
|
||||
int
|
||||
ah_hdrlen(sav)
|
||||
struct secasvar *sav;
|
||||
{
|
||||
const struct ah_algorithm *algo;
|
||||
int plen, ahlen;
|
||||
|
||||
algo = ah_algorithm_lookup(sav->alg_auth);
|
||||
if (!algo)
|
||||
return 0;
|
||||
if (sav->flags & SADB_X_EXT_OLD) {
|
||||
/* RFC 1826 */
|
||||
plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
|
||||
ahlen = plen + sizeof(struct ah);
|
||||
} else {
|
||||
/* RFC 2402 */
|
||||
plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /* XXX pad to 8byte? */
|
||||
ahlen = plen + sizeof(struct newah);
|
||||
}
|
||||
|
||||
return (ahlen);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
/*
|
||||
* Fill in the Authentication Header and calculate checksum.
|
||||
*/
|
||||
int
|
||||
ah6_output(m, nexthdrp, md, isr)
|
||||
struct mbuf *m;
|
||||
u_char *nexthdrp;
|
||||
struct mbuf *md;
|
||||
struct ipsecrequest *isr;
|
||||
{
|
||||
struct mbuf *mprev;
|
||||
struct mbuf *mah;
|
||||
struct secasvar *sav = isr->sav;
|
||||
const struct ah_algorithm *algo;
|
||||
u_int32_t spi;
|
||||
u_int8_t *ahsumpos = NULL;
|
||||
size_t plen; /* AH payload size in bytes */
|
||||
int error = 0;
|
||||
int ahlen;
|
||||
struct ip6_hdr *ip6;
|
||||
|
||||
if (m->m_len < sizeof(struct ip6_hdr)) {
|
||||
ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n"));
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ahlen = ah_hdrlen(sav);
|
||||
if (ahlen == 0)
|
||||
return 0;
|
||||
|
||||
for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
|
||||
;
|
||||
if (!mprev || mprev->m_next != md) {
|
||||
ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n"));
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
MGET(mah, M_DONTWAIT, MT_DATA);
|
||||
if (!mah) {
|
||||
m_freem(m);
|
||||
return ENOBUFS;
|
||||
}
|
||||
if (ahlen > MLEN) {
|
||||
MCLGET(mah, M_DONTWAIT);
|
||||
if ((mah->m_flags & M_EXT) == 0) {
|
||||
m_free(mah);
|
||||
m_freem(m);
|
||||
return ENOBUFS;
|
||||
}
|
||||
}
|
||||
mah->m_len = ahlen;
|
||||
mah->m_next = md;
|
||||
mprev->m_next = mah;
|
||||
m->m_pkthdr.len += ahlen;
|
||||
|
||||
/* fix plen */
|
||||
if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) {
|
||||
ipseclog((LOG_ERR,
|
||||
"ah6_output: AH with IPv6 jumbogram is not supported\n"));
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
|
||||
|
||||
if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
|
||||
ipseclog((LOG_DEBUG, "ah6_output: internal error: "
|
||||
"sav->replay is null: SPI=%u\n",
|
||||
(u_int32_t)ntohl(sav->spi)));
|
||||
ipsec6stat.out_inval++;
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
algo = ah_algorithm_lookup(sav->alg_auth);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: "
|
||||
"SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
|
||||
ipsec6stat.out_inval++;
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
spi = sav->spi;
|
||||
|
||||
/*
|
||||
* initialize AH.
|
||||
*/
|
||||
if (sav->flags & SADB_X_EXT_OLD) {
|
||||
struct ah *ahdr = mtod(mah, struct ah *);
|
||||
|
||||
plen = mah->m_len - sizeof(struct ah);
|
||||
ahsumpos = (u_char *)(ahdr + 1);
|
||||
ahdr->ah_nxt = *nexthdrp;
|
||||
*nexthdrp = IPPROTO_AH;
|
||||
ahdr->ah_len = plen >> 2;
|
||||
ahdr->ah_reserve = htons(0);
|
||||
ahdr->ah_spi = spi;
|
||||
bzero(ahdr + 1, plen);
|
||||
} else {
|
||||
struct newah *ahdr = mtod(mah, struct newah *);
|
||||
|
||||
plen = mah->m_len - sizeof(struct newah);
|
||||
ahsumpos = (u_char *)(ahdr + 1);
|
||||
ahdr->ah_nxt = *nexthdrp;
|
||||
*nexthdrp = IPPROTO_AH;
|
||||
ahdr->ah_len = (plen >> 2) + 1; /* plus one for seq# */
|
||||
ahdr->ah_reserve = htons(0);
|
||||
ahdr->ah_spi = spi;
|
||||
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)));
|
||||
ipsec6stat.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.
|
||||
*/
|
||||
ahdr->ah_seq = htonl(sav->replay->count);
|
||||
bzero(ahdr + 1, plen);
|
||||
}
|
||||
|
||||
/*
|
||||
* calcurate the checksum, based on security association
|
||||
* and the algorithm specified.
|
||||
*/
|
||||
error = ah6_calccksum(m, ahsumpos, plen, algo, sav);
|
||||
if (error) {
|
||||
ipsec6stat.out_inval++;
|
||||
m_freem(m);
|
||||
} else {
|
||||
ipsec6stat.out_success++;
|
||||
key_sa_recordxfer(sav, m);
|
||||
}
|
||||
ipsec6stat.out_ahhist[sav->alg_auth]++;
|
||||
|
||||
return (error);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET
|
||||
/*
|
||||
* Find the final destination if there is loose/strict source routing option.
|
||||
* Returns NULL if there's no source routing options.
|
||||
* Returns NULL on errors too.
|
||||
* Note that this function will return a pointer INTO the given parameter,
|
||||
* struct mbuf *m.
|
||||
* The mbuf must be pulled up toward, at least, ip option part.
|
||||
*/
|
||||
static struct in_addr *
|
||||
ah4_finaldst(m)
|
||||
struct mbuf *m;
|
||||
{
|
||||
struct ip *ip;
|
||||
int optlen;
|
||||
u_char *q;
|
||||
int i;
|
||||
int hlen;
|
||||
|
||||
if (!m)
|
||||
panic("ah4_finaldst: m == NULL");
|
||||
ip = mtod(m, struct ip *);
|
||||
hlen = (ip->ip_hl << 2);
|
||||
|
||||
if (m->m_len < hlen) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"ah4_finaldst: parameter mbuf wrong (not pulled up)\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hlen == sizeof(struct ip))
|
||||
return NULL;
|
||||
|
||||
optlen = hlen - sizeof(struct ip);
|
||||
if (optlen < 0) {
|
||||
ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n",
|
||||
optlen));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
q = (u_char *)(ip + 1);
|
||||
i = 0;
|
||||
while (i < optlen) {
|
||||
if (i + IPOPT_OPTVAL >= optlen)
|
||||
return NULL;
|
||||
if (q[i + IPOPT_OPTVAL] == IPOPT_EOL ||
|
||||
q[i + IPOPT_OPTVAL] == IPOPT_NOP ||
|
||||
i + IPOPT_OLEN < optlen)
|
||||
;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
switch (q[i + IPOPT_OPTVAL]) {
|
||||
case IPOPT_EOL:
|
||||
i = optlen; /* bye */
|
||||
break;
|
||||
case IPOPT_NOP:
|
||||
i++;
|
||||
break;
|
||||
case IPOPT_LSRR:
|
||||
case IPOPT_SSRR:
|
||||
if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) ||
|
||||
optlen - i < q[i + IPOPT_OLEN]) {
|
||||
ipseclog((LOG_ERR,
|
||||
"ip_finaldst: invalid IP option "
|
||||
"(code=%02x len=%02x)\n",
|
||||
q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
|
||||
return NULL;
|
||||
}
|
||||
i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
|
||||
return (struct in_addr *)(q + i);
|
||||
default:
|
||||
if (q[i + IPOPT_OLEN] < 2 ||
|
||||
optlen - i < q[i + IPOPT_OLEN]) {
|
||||
ipseclog((LOG_ERR,
|
||||
"ip_finaldst: invalid IP option "
|
||||
"(code=%02x len=%02x)\n",
|
||||
q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
|
||||
return NULL;
|
||||
}
|
||||
i += q[i + IPOPT_OLEN];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,461 +0,0 @@
|
|||
/* $KAME: esp_aesctr.c,v 1.2 2003/07/20 00:29:37 itojun Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 1995, 1996, 1997, 1998 and 2003 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.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#include <netinet6/esp.h>
|
||||
#include <netinet6/esp_aesctr.h>
|
||||
|
||||
#include <netkey/key.h>
|
||||
|
||||
#include <crypto/rijndael/rijndael.h>
|
||||
|
||||
#define AES_BLOCKSIZE 16
|
||||
|
||||
#define NONCESIZE 4
|
||||
union cblock {
|
||||
struct {
|
||||
u_int8_t nonce[4];
|
||||
u_int8_t iv[8];
|
||||
u_int32_t ctr;
|
||||
} __packed v;
|
||||
u_int8_t cblock[16];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u_int32_t r_ek[(RIJNDAEL_MAXNR+1)*4];
|
||||
int r_nr; /* key-length-dependent number of rounds */
|
||||
} aesctr_ctx;
|
||||
|
||||
int
|
||||
esp_aesctr_mature(sav)
|
||||
struct secasvar *sav;
|
||||
{
|
||||
int keylen;
|
||||
const struct esp_algorithm *algo;
|
||||
|
||||
algo = esp_algorithm_lookup(sav->alg_enc);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_ERR,
|
||||
"esp_aeesctr_mature %s: unsupported algorithm.\n",
|
||||
algo->name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
keylen = sav->key_enc->sadb_key_bits;
|
||||
if (keylen < algo->keymin || algo->keymax < keylen) {
|
||||
ipseclog((LOG_ERR,
|
||||
"esp_aesctr_mature %s: invalid key length %d.\n",
|
||||
algo->name, sav->key_enc->sadb_key_bits));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* rijndael key + nonce */
|
||||
if (!(keylen == 128 + 32 || keylen == 192 + 32 || keylen == 256 + 32)) {
|
||||
ipseclog((LOG_ERR,
|
||||
"esp_aesctr_mature %s: invalid key length %d.\n",
|
||||
algo->name, keylen));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
esp_aesctr_schedlen(algo)
|
||||
const struct esp_algorithm *algo;
|
||||
{
|
||||
|
||||
return sizeof(aesctr_ctx);
|
||||
}
|
||||
|
||||
int
|
||||
esp_aesctr_schedule(algo, sav)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
{
|
||||
aesctr_ctx *ctx;
|
||||
int keylen;
|
||||
|
||||
/* SA key = AES key + nonce */
|
||||
keylen = _KEYLEN(sav->key_enc) * 8 - NONCESIZE * 8;
|
||||
|
||||
ctx = (aesctr_ctx *)sav->sched;
|
||||
if ((ctx->r_nr = rijndaelKeySetupEnc(ctx->r_ek,
|
||||
(char *)_KEYBUF(sav->key_enc), keylen)) == 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
esp_aesctr_decrypt(m, off, sav, algo, ivlen)
|
||||
struct mbuf *m;
|
||||
size_t off;
|
||||
struct secasvar *sav;
|
||||
const struct esp_algorithm *algo;
|
||||
int ivlen;
|
||||
{
|
||||
struct mbuf *s;
|
||||
struct mbuf *d, *d0 = NULL, *dp;
|
||||
int soff, doff; /* offset from the head of chain, to head of this mbuf */
|
||||
int sn, dn; /* offset from the head of the mbuf, to meat */
|
||||
size_t ivoff, bodyoff;
|
||||
union cblock cblock;
|
||||
u_int8_t keystream[AES_BLOCKSIZE], *nonce;
|
||||
u_int32_t ctr;
|
||||
u_int8_t *ivp;
|
||||
u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
|
||||
struct mbuf *scut;
|
||||
int scutoff;
|
||||
int i;
|
||||
int blocklen;
|
||||
aesctr_ctx *ctx;
|
||||
|
||||
if (ivlen != sav->ivlen) {
|
||||
ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
|
||||
"unsupported ivlen %d\n", algo->name, ivlen));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* assumes blocklen == padbound */
|
||||
blocklen = algo->padbound;
|
||||
|
||||
ivoff = off + sizeof(struct newesp);
|
||||
bodyoff = off + sizeof(struct newesp) + ivlen;
|
||||
|
||||
/* setup counter block */
|
||||
nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
|
||||
bcopy(nonce, cblock.v.nonce, NONCESIZE);
|
||||
m_copydata(m, ivoff, ivlen, cblock.v.iv);
|
||||
ctr = 1;
|
||||
|
||||
if (m->m_pkthdr.len < bodyoff) {
|
||||
ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: bad len %d/%lu\n",
|
||||
algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
|
||||
goto fail;
|
||||
}
|
||||
if ((m->m_pkthdr.len - bodyoff) % blocklen) {
|
||||
ipseclog((LOG_ERR, "esp_aesctr_decrypt %s: "
|
||||
"payload length must be multiple of %d\n",
|
||||
algo->name, blocklen));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s = m;
|
||||
d = d0 = dp = NULL;
|
||||
soff = doff = sn = dn = 0;
|
||||
ivp = sp = NULL;
|
||||
|
||||
/* skip bodyoff */
|
||||
while (soff < bodyoff) {
|
||||
if (soff + s->m_len > bodyoff) {
|
||||
sn = bodyoff - soff;
|
||||
break;
|
||||
}
|
||||
|
||||
soff += s->m_len;
|
||||
s = s->m_next;
|
||||
}
|
||||
scut = s;
|
||||
scutoff = sn;
|
||||
|
||||
/* skip over empty mbuf */
|
||||
while (s && s->m_len == 0)
|
||||
s = s->m_next;
|
||||
|
||||
while (soff < m->m_pkthdr.len) {
|
||||
/* source */
|
||||
if (sn + blocklen <= s->m_len) {
|
||||
/* body is continuous */
|
||||
sp = mtod(s, u_int8_t *) + sn;
|
||||
} else {
|
||||
/* body is non-continuous */
|
||||
m_copydata(s, sn, blocklen, (caddr_t)sbuf);
|
||||
sp = sbuf;
|
||||
}
|
||||
|
||||
/* destination */
|
||||
if (!d || dn + blocklen > d->m_len) {
|
||||
if (d)
|
||||
dp = d;
|
||||
MGET(d, M_DONTWAIT, MT_DATA);
|
||||
i = m->m_pkthdr.len - (soff + sn);
|
||||
if (d && i > MLEN) {
|
||||
MCLGET(d, M_DONTWAIT);
|
||||
if ((d->m_flags & M_EXT) == 0) {
|
||||
m_free(d);
|
||||
d = NULL;
|
||||
}
|
||||
}
|
||||
if (!d) {
|
||||
goto nomem;
|
||||
}
|
||||
if (!d0)
|
||||
d0 = d;
|
||||
if (dp)
|
||||
dp->m_next = d;
|
||||
d->m_len = 0;
|
||||
d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
|
||||
if (d->m_len > i)
|
||||
d->m_len = i;
|
||||
dn = 0;
|
||||
}
|
||||
|
||||
/* put counter into counter block */
|
||||
cblock.v.ctr = htonl(ctr);
|
||||
|
||||
/* setup keystream */
|
||||
ctx = (aesctr_ctx *)sav->sched;
|
||||
rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
|
||||
|
||||
bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
|
||||
dst = mtod(d, u_int8_t *) + dn;
|
||||
for (i = 0; i < blocklen; i++)
|
||||
dst[i] ^= keystream[i];
|
||||
|
||||
ctr++;
|
||||
|
||||
sn += blocklen;
|
||||
dn += blocklen;
|
||||
|
||||
/* find the next source block */
|
||||
while (s && sn >= s->m_len) {
|
||||
sn -= s->m_len;
|
||||
soff += s->m_len;
|
||||
s = s->m_next;
|
||||
}
|
||||
|
||||
/* skip over empty mbuf */
|
||||
while (s && s->m_len == 0)
|
||||
s = s->m_next;
|
||||
}
|
||||
|
||||
m_freem(scut->m_next);
|
||||
scut->m_len = scutoff;
|
||||
scut->m_next = d0;
|
||||
|
||||
/* just in case */
|
||||
bzero(&cblock, sizeof(cblock));
|
||||
bzero(keystream, sizeof(keystream));
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
m_freem(m);
|
||||
if (d0)
|
||||
m_freem(d0);
|
||||
return EINVAL;
|
||||
|
||||
nomem:
|
||||
m_freem(m);
|
||||
if (d0)
|
||||
m_freem(d0);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
int
|
||||
esp_aesctr_encrypt(m, off, plen, sav, algo, ivlen)
|
||||
struct mbuf *m;
|
||||
size_t off;
|
||||
size_t plen;
|
||||
struct secasvar *sav;
|
||||
const struct esp_algorithm *algo;
|
||||
int ivlen;
|
||||
{
|
||||
struct mbuf *s;
|
||||
struct mbuf *d, *d0, *dp;
|
||||
int soff, doff; /* offset from the head of chain, to head of this mbuf */
|
||||
int sn, dn; /* offset from the head of the mbuf, to meat */
|
||||
size_t ivoff, bodyoff;
|
||||
union cblock cblock;
|
||||
u_int8_t keystream[AES_BLOCKSIZE], *nonce;
|
||||
u_int32_t ctr;
|
||||
u_int8_t sbuf[AES_BLOCKSIZE], *sp, *dst;
|
||||
struct mbuf *scut;
|
||||
int scutoff;
|
||||
int i;
|
||||
int blocklen;
|
||||
aesctr_ctx *ctx;
|
||||
|
||||
if (ivlen != sav->ivlen) {
|
||||
ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
|
||||
"unsupported ivlen %d\n", algo->name, ivlen));
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* assumes blocklen == padbound */
|
||||
blocklen = algo->padbound;
|
||||
|
||||
ivoff = off + sizeof(struct newesp);
|
||||
bodyoff = off + sizeof(struct newesp) + ivlen;
|
||||
|
||||
/* put iv into the packet. */
|
||||
/* maybe it is better to overwrite dest, not source */
|
||||
m_copyback(m, ivoff, ivlen, sav->iv);
|
||||
|
||||
/* setup counter block */
|
||||
nonce = _KEYBUF(sav->key_enc) + _KEYLEN(sav->key_enc) - NONCESIZE;
|
||||
bcopy(nonce, cblock.v.nonce, NONCESIZE);
|
||||
m_copydata(m, ivoff, ivlen, cblock.v.iv);
|
||||
ctr = 1;
|
||||
|
||||
if (m->m_pkthdr.len < bodyoff) {
|
||||
ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: bad len %d/%lu\n",
|
||||
algo->name, m->m_pkthdr.len, (unsigned long)bodyoff));
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
if ((m->m_pkthdr.len - bodyoff) % blocklen) {
|
||||
ipseclog((LOG_ERR, "esp_aesctr_encrypt %s: "
|
||||
"payload length must be multiple of %lu\n",
|
||||
algo->name, (unsigned long)algo->padbound));
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
s = m;
|
||||
d = d0 = dp = NULL;
|
||||
soff = doff = sn = dn = 0;
|
||||
sp = NULL;
|
||||
|
||||
/* skip bodyoff */
|
||||
while (soff < bodyoff) {
|
||||
if (soff + s->m_len > bodyoff) {
|
||||
sn = bodyoff - soff;
|
||||
break;
|
||||
}
|
||||
|
||||
soff += s->m_len;
|
||||
s = s->m_next;
|
||||
}
|
||||
scut = s;
|
||||
scutoff = sn;
|
||||
|
||||
/* skip over empty mbuf */
|
||||
while (s && s->m_len == 0)
|
||||
s = s->m_next;
|
||||
|
||||
while (soff < m->m_pkthdr.len) {
|
||||
/* source */
|
||||
if (sn + blocklen <= s->m_len) {
|
||||
/* body is continuous */
|
||||
sp = mtod(s, u_int8_t *) + sn;
|
||||
} else {
|
||||
/* body is non-continuous */
|
||||
m_copydata(s, sn, blocklen, (caddr_t)sbuf);
|
||||
sp = sbuf;
|
||||
}
|
||||
|
||||
/* destination */
|
||||
if (!d || dn + blocklen > d->m_len) {
|
||||
if (d)
|
||||
dp = d;
|
||||
MGET(d, M_DONTWAIT, MT_DATA);
|
||||
i = m->m_pkthdr.len - (soff + sn);
|
||||
if (d && i > MLEN) {
|
||||
MCLGET(d, M_DONTWAIT);
|
||||
if ((d->m_flags & M_EXT) == 0) {
|
||||
m_free(d);
|
||||
d = NULL;
|
||||
}
|
||||
}
|
||||
if (!d) {
|
||||
m_freem(m);
|
||||
if (d0)
|
||||
m_freem(d0);
|
||||
return ENOBUFS;
|
||||
}
|
||||
if (!d0)
|
||||
d0 = d;
|
||||
if (dp)
|
||||
dp->m_next = d;
|
||||
d->m_len = 0;
|
||||
d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
|
||||
if (d->m_len > i)
|
||||
d->m_len = i;
|
||||
dn = 0;
|
||||
}
|
||||
|
||||
/* put counter into counter block */
|
||||
cblock.v.ctr = htonl(ctr);
|
||||
|
||||
/* setup keystream */
|
||||
ctx = (aesctr_ctx *)sav->sched;
|
||||
rijndaelEncrypt(ctx->r_ek, ctx->r_nr, cblock.cblock, keystream);
|
||||
|
||||
bcopy(sp, mtod(d, u_int8_t *) + dn, blocklen);
|
||||
dst = mtod(d, u_int8_t *) + dn;
|
||||
for (i = 0; i < blocklen; i++)
|
||||
dst[i] ^= keystream[i];
|
||||
|
||||
ctr++;
|
||||
|
||||
sn += blocklen;
|
||||
dn += blocklen;
|
||||
|
||||
/* find the next source block */
|
||||
while (s && sn >= s->m_len) {
|
||||
sn -= s->m_len;
|
||||
soff += s->m_len;
|
||||
s = s->m_next;
|
||||
}
|
||||
|
||||
/* skip over empty mbuf */
|
||||
while (s && s->m_len == 0)
|
||||
s = s->m_next;
|
||||
}
|
||||
|
||||
m_freem(scut->m_next);
|
||||
scut->m_len = scutoff;
|
||||
scut->m_next = d0;
|
||||
|
||||
/* just in case */
|
||||
bzero(&cblock, sizeof(cblock));
|
||||
bzero(keystream, sizeof(keystream));
|
||||
|
||||
key_sa_stir_iv(sav);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Copyright (c) 2006
|
||||
* NTT (Nippon Telegraph and Telephone Corporation) . 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 as
|
||||
* the first lines of this file unmodified.
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NTT ``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 NTT 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/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#include <netinet6/esp.h>
|
||||
#include <netinet6/esp_camellia.h>
|
||||
|
||||
#include <crypto/camellia/camellia.h>
|
||||
|
||||
size_t
|
||||
esp_camellia_schedlen(algo)
|
||||
const struct esp_algorithm *algo;
|
||||
{
|
||||
|
||||
return sizeof(camellia_ctx);
|
||||
}
|
||||
|
||||
int
|
||||
esp_camellia_schedule(algo, sav)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
{
|
||||
camellia_ctx *ctx;
|
||||
|
||||
ctx = (camellia_ctx *)sav->sched;
|
||||
camellia_set_key(ctx,
|
||||
(u_char *)_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc) * 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
esp_camellia_blockdecrypt(algo, sav, s, d)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
u_int8_t *s;
|
||||
u_int8_t *d;
|
||||
{
|
||||
camellia_ctx *ctx;
|
||||
|
||||
ctx = (camellia_ctx *)sav->sched;
|
||||
camellia_decrypt(ctx, s, d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
esp_camellia_blockencrypt(algo, sav, s, d)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
u_int8_t *s;
|
||||
u_int8_t *d;
|
||||
{
|
||||
camellia_ctx *ctx;
|
||||
|
||||
ctx = (camellia_ctx *)sav->sched;
|
||||
camellia_encrypt(ctx, s, d);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,975 +0,0 @@
|
|||
/* $FreeBSD$ */
|
||||
/* $KAME: esp_input.c,v 1.62 2002/01/07 11:39:57 kjc 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 "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netisr.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip_ecn.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ip6_ecn.h>
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/in_pcb.h>
|
||||
#include <netinet6/in6_pcb.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet6/ip6protosw.h>
|
||||
#endif
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipsec6.h>
|
||||
#endif
|
||||
#include <netinet6/ah.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ah6.h>
|
||||
#endif
|
||||
#include <netinet6/esp.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/esp6.h>
|
||||
#endif
|
||||
#include <netkey/key.h>
|
||||
#include <netkey/keydb.h>
|
||||
#include <netkey/key_debug.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#define IPLEN_FLIPPED
|
||||
|
||||
#define ESPMAXLEN \
|
||||
(sizeof(struct esp) < sizeof(struct newesp) \
|
||||
? sizeof(struct newesp) : sizeof(struct esp))
|
||||
|
||||
#ifdef INET
|
||||
extern struct protosw inetsw[];
|
||||
|
||||
void
|
||||
esp4_input(m, off)
|
||||
struct mbuf *m;
|
||||
int off;
|
||||
{
|
||||
struct ip *ip;
|
||||
struct esp *esp;
|
||||
struct esptail esptail;
|
||||
u_int32_t spi;
|
||||
struct secasvar *sav = NULL;
|
||||
size_t taillen;
|
||||
u_int16_t nxt;
|
||||
const struct esp_algorithm *algo;
|
||||
int ivlen;
|
||||
size_t hlen;
|
||||
size_t esplen;
|
||||
|
||||
/* sanity check for alignment. */
|
||||
if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
|
||||
ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem "
|
||||
"(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (m->m_len < off + ESPMAXLEN) {
|
||||
m = m_pullup(m, off + ESPMAXLEN);
|
||||
if (!m) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"IPv4 ESP input: can't pullup in esp4_input\n"));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
esp = (struct esp *)(((u_int8_t *)ip) + off);
|
||||
#ifdef _IP_VHL
|
||||
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
||||
#else
|
||||
hlen = ip->ip_hl << 2;
|
||||
#endif
|
||||
|
||||
/* find the sassoc. */
|
||||
spi = esp->esp_spi;
|
||||
|
||||
if ((sav = key_allocsa(AF_INET,
|
||||
(caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
|
||||
IPPROTO_ESP, spi)) == 0) {
|
||||
ipseclog((LOG_WARNING,
|
||||
"IPv4 ESP input: no key association found for spi %u\n",
|
||||
(u_int32_t)ntohl(spi)));
|
||||
ipsecstat.in_nosa++;
|
||||
goto bad;
|
||||
}
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
printf("DP esp4_input called to allocate SA:%p\n", sav));
|
||||
if (sav->state != SADB_SASTATE_MATURE
|
||||
&& sav->state != SADB_SASTATE_DYING) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"IPv4 ESP input: non-mature/dying SA found for spi %u\n",
|
||||
(u_int32_t)ntohl(spi)));
|
||||
ipsecstat.in_badspi++;
|
||||
goto bad;
|
||||
}
|
||||
algo = esp_algorithm_lookup(sav->alg_enc);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_DEBUG, "IPv4 ESP input: "
|
||||
"unsupported encryption algorithm for spi %u\n",
|
||||
(u_int32_t)ntohl(spi)));
|
||||
ipsecstat.in_badspi++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* check if we have proper ivlen information */
|
||||
ivlen = sav->ivlen;
|
||||
if (ivlen < 0) {
|
||||
ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n",
|
||||
ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay
|
||||
&& (sav->alg_auth && sav->key_auth)))
|
||||
goto noreplaycheck;
|
||||
|
||||
if (sav->alg_auth == SADB_X_AALG_NULL ||
|
||||
sav->alg_auth == SADB_AALG_NONE)
|
||||
goto noreplaycheck;
|
||||
|
||||
/*
|
||||
* check for sequence number.
|
||||
*/
|
||||
if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav))
|
||||
; /* okey */
|
||||
else {
|
||||
ipsecstat.in_espreplay++;
|
||||
ipseclog((LOG_WARNING,
|
||||
"replay packet in IPv4 ESP input: %s %s\n",
|
||||
ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* check ICV */
|
||||
{
|
||||
u_int8_t sum0[AH_MAXSUMSIZE];
|
||||
u_int8_t sum[AH_MAXSUMSIZE];
|
||||
const struct ah_algorithm *sumalgo;
|
||||
size_t siz;
|
||||
|
||||
sumalgo = ah_algorithm_lookup(sav->alg_auth);
|
||||
if (!sumalgo)
|
||||
goto noreplaycheck;
|
||||
siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
|
||||
if (m->m_pkthdr.len < off + ESPMAXLEN + siz) {
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
if (AH_MAXSUMSIZE < siz) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"internal error: AH_MAXSUMSIZE must be larger than %lu\n",
|
||||
(u_long)siz));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t)&sum0[0]);
|
||||
|
||||
if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
|
||||
ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
|
||||
ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
|
||||
ipsecstat.in_espauthfail++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (bcmp(sum0, sum, siz) != 0) {
|
||||
ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
|
||||
ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
|
||||
ipsecstat.in_espauthfail++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* strip off the authentication data */
|
||||
m_adj(m, -siz);
|
||||
ip = mtod(m, struct ip *);
|
||||
#ifdef IPLEN_FLIPPED
|
||||
ip->ip_len = ip->ip_len - siz;
|
||||
#else
|
||||
ip->ip_len = htons(ntohs(ip->ip_len) - siz);
|
||||
#endif
|
||||
m->m_flags |= M_AUTHIPDGM;
|
||||
ipsecstat.in_espauthsucc++;
|
||||
}
|
||||
|
||||
/*
|
||||
* update sequence number.
|
||||
*/
|
||||
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
|
||||
if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
|
||||
ipsecstat.in_espreplay++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
noreplaycheck:
|
||||
|
||||
/* process main esp header. */
|
||||
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);
|
||||
}
|
||||
|
||||
if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
|
||||
ipseclog((LOG_WARNING,
|
||||
"IPv4 ESP input: packet too short\n"));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (m->m_len < off + esplen + ivlen) {
|
||||
m = m_pullup(m, off + esplen + ivlen);
|
||||
if (!m) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"IPv4 ESP input: can't pullup in esp4_input\n"));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* pre-compute and cache intermediate key
|
||||
*/
|
||||
if (esp_schedule(algo, sav) != 0) {
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* decrypt the packet.
|
||||
*/
|
||||
if (!algo->decrypt)
|
||||
panic("internal error: no decrypt function");
|
||||
if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
|
||||
/* m is already freed */
|
||||
m = NULL;
|
||||
ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n",
|
||||
ipsec_logsastr(sav)));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
ipsecstat.in_esphist[sav->alg_enc]++;
|
||||
|
||||
m->m_flags |= M_DECRYPTED;
|
||||
|
||||
/*
|
||||
* find the trailer of the ESP.
|
||||
*/
|
||||
m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
|
||||
(caddr_t)&esptail);
|
||||
nxt = esptail.esp_nxt;
|
||||
taillen = esptail.esp_padlen + sizeof(esptail);
|
||||
|
||||
if (m->m_pkthdr.len < taillen ||
|
||||
m->m_pkthdr.len - taillen < off + esplen + ivlen + sizeof(esptail)) {
|
||||
ipseclog((LOG_WARNING,
|
||||
"bad pad length in IPv4 ESP input: %s %s\n",
|
||||
ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* strip off the trailing pad area. */
|
||||
m_adj(m, -taillen);
|
||||
|
||||
#ifdef IPLEN_FLIPPED
|
||||
ip->ip_len = ip->ip_len - taillen;
|
||||
#else
|
||||
ip->ip_len = htons(ntohs(ip->ip_len) - taillen);
|
||||
#endif
|
||||
|
||||
/* was it transmitted over the IPsec tunnel SA? */
|
||||
if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) {
|
||||
/*
|
||||
* strip off all the headers that precedes ESP header.
|
||||
* IP4 xx ESP IP4' payload -> IP4' payload
|
||||
*
|
||||
* XXX more sanity checks
|
||||
* XXX relationship with gif?
|
||||
*/
|
||||
u_int8_t tos;
|
||||
|
||||
tos = ip->ip_tos;
|
||||
m_adj(m, off + esplen + ivlen);
|
||||
if (m->m_len < sizeof(*ip)) {
|
||||
m = m_pullup(m, sizeof(*ip));
|
||||
if (!m) {
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
/* ECN consideration. */
|
||||
if (!ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos)) {
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
if (!key_checktunnelsanity(sav, AF_INET,
|
||||
(caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
|
||||
ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
|
||||
"in IPv4 ESP input: %s %s\n",
|
||||
ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
|
||||
ipsecstat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
key_sa_recordxfer(sav, m);
|
||||
if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
|
||||
ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
|
||||
ipsecstat.in_nomem++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (netisr_queue(NETISR_IP, m)) { /* (0) on success. */
|
||||
ipsecstat.in_inval++;
|
||||
m = NULL;
|
||||
goto bad;
|
||||
}
|
||||
m = NULL;
|
||||
nxt = IPPROTO_DONE;
|
||||
} else {
|
||||
/*
|
||||
* strip off ESP header and IV.
|
||||
* even in m_pulldown case, we need to strip off ESP so that
|
||||
* we can always compute checksum for AH correctly.
|
||||
*/
|
||||
size_t stripsiz;
|
||||
|
||||
stripsiz = esplen + ivlen;
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
|
||||
m->m_data += stripsiz;
|
||||
m->m_len -= stripsiz;
|
||||
m->m_pkthdr.len -= stripsiz;
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
#ifdef IPLEN_FLIPPED
|
||||
ip->ip_len = ip->ip_len - stripsiz;
|
||||
#else
|
||||
ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
|
||||
#endif
|
||||
ip->ip_p = nxt;
|
||||
|
||||
key_sa_recordxfer(sav, m);
|
||||
if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
|
||||
ipsecstat.in_nomem++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (nxt != IPPROTO_DONE) {
|
||||
if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
|
||||
ipsec4_in_reject(m, NULL)) {
|
||||
ipsecstat.in_polvio++;
|
||||
goto bad;
|
||||
}
|
||||
(*inetsw[ip_protox[nxt]].pr_input)(m, off);
|
||||
} else
|
||||
m_freem(m);
|
||||
m = NULL;
|
||||
}
|
||||
|
||||
if (sav) {
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
printf("DP esp4_input call free SA:%p\n", sav));
|
||||
key_freesav(sav);
|
||||
}
|
||||
ipsecstat.in_success++;
|
||||
return;
|
||||
|
||||
bad:
|
||||
if (sav) {
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
printf("DP esp4_input call free SA:%p\n", sav));
|
||||
key_freesav(sav);
|
||||
}
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
int
|
||||
esp6_input(mp, offp, proto)
|
||||
struct mbuf **mp;
|
||||
int *offp, proto;
|
||||
{
|
||||
struct mbuf *m = *mp;
|
||||
int off = *offp;
|
||||
struct ip6_hdr *ip6;
|
||||
struct esp *esp;
|
||||
struct esptail esptail;
|
||||
u_int32_t spi;
|
||||
struct secasvar *sav = NULL;
|
||||
size_t taillen;
|
||||
u_int16_t nxt;
|
||||
const struct esp_algorithm *algo;
|
||||
int ivlen;
|
||||
size_t esplen;
|
||||
|
||||
/* sanity check for alignment. */
|
||||
if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
|
||||
ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem "
|
||||
"(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, IPPROTO_DONE);
|
||||
esp = (struct esp *)(mtod(m, caddr_t) + off);
|
||||
#else
|
||||
IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN);
|
||||
if (esp == NULL) {
|
||||
ipsec6stat.in_inval++;
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
|
||||
if (ntohs(ip6->ip6_plen) == 0) {
|
||||
ipseclog((LOG_ERR, "IPv6 ESP input: "
|
||||
"ESP with IPv6 jumbogram is not supported.\n"));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* find the sassoc. */
|
||||
spi = esp->esp_spi;
|
||||
|
||||
if ((sav = key_allocsa(AF_INET6,
|
||||
(caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
|
||||
IPPROTO_ESP, spi)) == 0) {
|
||||
ipseclog((LOG_WARNING,
|
||||
"IPv6 ESP input: no key association found for spi %u\n",
|
||||
(u_int32_t)ntohl(spi)));
|
||||
ipsec6stat.in_nosa++;
|
||||
goto bad;
|
||||
}
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
printf("DP esp6_input called to allocate SA:%p\n", sav));
|
||||
if (sav->state != SADB_SASTATE_MATURE
|
||||
&& sav->state != SADB_SASTATE_DYING) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"IPv6 ESP input: non-mature/dying SA found for spi %u\n",
|
||||
(u_int32_t)ntohl(spi)));
|
||||
ipsec6stat.in_badspi++;
|
||||
goto bad;
|
||||
}
|
||||
algo = esp_algorithm_lookup(sav->alg_enc);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_DEBUG, "IPv6 ESP input: "
|
||||
"unsupported encryption algorithm for spi %u\n",
|
||||
(u_int32_t)ntohl(spi)));
|
||||
ipsec6stat.in_badspi++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* check if we have proper ivlen information */
|
||||
ivlen = sav->ivlen;
|
||||
if (ivlen < 0) {
|
||||
ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n",
|
||||
ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
|
||||
ipsec6stat.in_badspi++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay
|
||||
&& (sav->alg_auth && sav->key_auth)))
|
||||
goto noreplaycheck;
|
||||
|
||||
if (sav->alg_auth == SADB_X_AALG_NULL ||
|
||||
sav->alg_auth == SADB_AALG_NONE)
|
||||
goto noreplaycheck;
|
||||
|
||||
/*
|
||||
* check for sequence number.
|
||||
*/
|
||||
if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav))
|
||||
; /* okey */
|
||||
else {
|
||||
ipsec6stat.in_espreplay++;
|
||||
ipseclog((LOG_WARNING,
|
||||
"replay packet in IPv6 ESP input: %s %s\n",
|
||||
ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* check ICV */
|
||||
{
|
||||
u_char sum0[AH_MAXSUMSIZE];
|
||||
u_char sum[AH_MAXSUMSIZE];
|
||||
const struct ah_algorithm *sumalgo;
|
||||
size_t siz;
|
||||
|
||||
sumalgo = ah_algorithm_lookup(sav->alg_auth);
|
||||
if (!sumalgo)
|
||||
goto noreplaycheck;
|
||||
siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
|
||||
if (m->m_pkthdr.len < off + ESPMAXLEN + siz) {
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
if (AH_MAXSUMSIZE < siz) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"internal error: AH_MAXSUMSIZE must be larger than %lu\n",
|
||||
(u_long)siz));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t)&sum0[0]);
|
||||
|
||||
if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
|
||||
ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
|
||||
ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
|
||||
ipsec6stat.in_espauthfail++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (bcmp(sum0, sum, siz) != 0) {
|
||||
ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
|
||||
ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
|
||||
ipsec6stat.in_espauthfail++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* strip off the authentication data */
|
||||
m_adj(m, -siz);
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz);
|
||||
|
||||
m->m_flags |= M_AUTHIPDGM;
|
||||
ipsec6stat.in_espauthsucc++;
|
||||
}
|
||||
|
||||
/*
|
||||
* update sequence number.
|
||||
*/
|
||||
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
|
||||
if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
|
||||
ipsec6stat.in_espreplay++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
noreplaycheck:
|
||||
|
||||
/* process main esp header. */
|
||||
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);
|
||||
}
|
||||
|
||||
if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
|
||||
ipseclog((LOG_WARNING,
|
||||
"IPv6 ESP input: packet too short\n"));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
IP6_EXTHDR_CHECK(m, off, esplen + ivlen, IPPROTO_DONE); /* XXX */
|
||||
#else
|
||||
IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen);
|
||||
if (esp == NULL) {
|
||||
ipsec6stat.in_inval++;
|
||||
m = NULL;
|
||||
goto bad;
|
||||
}
|
||||
#endif
|
||||
ip6 = mtod(m, struct ip6_hdr *); /* set it again just in case */
|
||||
|
||||
/*
|
||||
* pre-compute and cache intermediate key
|
||||
*/
|
||||
if (esp_schedule(algo, sav) != 0) {
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* decrypt the packet.
|
||||
*/
|
||||
if (!algo->decrypt)
|
||||
panic("internal error: no decrypt function");
|
||||
if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
|
||||
/* m is already freed */
|
||||
m = NULL;
|
||||
ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n",
|
||||
ipsec_logsastr(sav)));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
ipsec6stat.in_esphist[sav->alg_enc]++;
|
||||
|
||||
m->m_flags |= M_DECRYPTED;
|
||||
|
||||
/*
|
||||
* find the trailer of the ESP.
|
||||
*/
|
||||
m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
|
||||
(caddr_t)&esptail);
|
||||
nxt = esptail.esp_nxt;
|
||||
taillen = esptail.esp_padlen + sizeof(esptail);
|
||||
|
||||
if (m->m_pkthdr.len < taillen
|
||||
|| m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) { /* ? */
|
||||
ipseclog((LOG_WARNING,
|
||||
"bad pad length in IPv6 ESP input: %s %s\n",
|
||||
ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* strip off the trailing pad area. */
|
||||
m_adj(m, -taillen);
|
||||
|
||||
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
|
||||
|
||||
/* was it transmitted over the IPsec tunnel SA? */
|
||||
if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) {
|
||||
/*
|
||||
* strip off all the headers that precedes ESP header.
|
||||
* IP6 xx ESP IP6' payload -> IP6' payload
|
||||
*
|
||||
* XXX more sanity checks
|
||||
* XXX relationship with gif?
|
||||
*/
|
||||
u_int32_t flowinfo; /* net endian */
|
||||
flowinfo = ip6->ip6_flow;
|
||||
m_adj(m, off + esplen + ivlen);
|
||||
if (m->m_len < sizeof(*ip6)) {
|
||||
m = m_pullup(m, sizeof(*ip6));
|
||||
if (!m) {
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
/* ECN consideration. */
|
||||
if (!ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow)) {
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
if (!key_checktunnelsanity(sav, AF_INET6,
|
||||
(caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
|
||||
ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
|
||||
"in IPv6 ESP input: %s %s\n",
|
||||
ipsec6_logpacketstr(ip6, spi),
|
||||
ipsec_logsastr(sav)));
|
||||
ipsec6stat.in_inval++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
key_sa_recordxfer(sav, m);
|
||||
if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
|
||||
ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
|
||||
ipsec6stat.in_nomem++;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (netisr_queue(NETISR_IPV6, m)) { /* (0) on success. */
|
||||
ipsec6stat.in_inval++;
|
||||
m = NULL;
|
||||
goto bad;
|
||||
}
|
||||
m = NULL;
|
||||
nxt = IPPROTO_DONE;
|
||||
} else {
|
||||
/*
|
||||
* strip off ESP header and IV.
|
||||
* even in m_pulldown case, we need to strip off ESP so that
|
||||
* we can always compute checksum for AH correctly.
|
||||
*/
|
||||
size_t stripsiz;
|
||||
u_int8_t *prvnxtp;
|
||||
|
||||
/*
|
||||
* Set the next header field of the previous header correctly.
|
||||
*/
|
||||
prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
|
||||
*prvnxtp = nxt;
|
||||
|
||||
stripsiz = esplen + ivlen;
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
if (m->m_len >= stripsiz + off) {
|
||||
ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
|
||||
m->m_data += stripsiz;
|
||||
m->m_len -= stripsiz;
|
||||
m->m_pkthdr.len -= stripsiz;
|
||||
} else {
|
||||
/*
|
||||
* this comes with no copy if the boundary is on
|
||||
* cluster
|
||||
*/
|
||||
struct mbuf *n;
|
||||
|
||||
n = m_split(m, off, M_DONTWAIT);
|
||||
if (n == NULL) {
|
||||
/* m is retained by m_split */
|
||||
goto bad;
|
||||
}
|
||||
m_adj(n, stripsiz);
|
||||
/* m_cat does not update m_pkthdr.len */
|
||||
m->m_pkthdr.len += n->m_pkthdr.len;
|
||||
m_cat(m, n);
|
||||
}
|
||||
|
||||
#ifndef PULLDOWN_TEST
|
||||
/*
|
||||
* KAME requires that the packet to be contiguous on the
|
||||
* mbuf. We need to make that sure.
|
||||
* this kind of code should be avoided.
|
||||
* XXX other conditions to avoid running this part?
|
||||
*/
|
||||
if (m->m_len != m->m_pkthdr.len) {
|
||||
struct mbuf *n = NULL;
|
||||
int maxlen;
|
||||
|
||||
MGETHDR(n, M_DONTWAIT, MT_HEADER);
|
||||
maxlen = MHLEN;
|
||||
if (n)
|
||||
M_MOVE_PKTHDR(n, m);
|
||||
if (n && n->m_pkthdr.len > maxlen) {
|
||||
MCLGET(n, M_DONTWAIT);
|
||||
maxlen = MCLBYTES;
|
||||
if ((n->m_flags & M_EXT) == 0) {
|
||||
m_free(n);
|
||||
n = NULL;
|
||||
}
|
||||
}
|
||||
if (!n) {
|
||||
printf("esp6_input: mbuf allocation failed\n");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (n->m_pkthdr.len <= maxlen) {
|
||||
m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t));
|
||||
n->m_len = n->m_pkthdr.len;
|
||||
n->m_next = NULL;
|
||||
m_freem(m);
|
||||
} else {
|
||||
m_copydata(m, 0, maxlen, mtod(n, caddr_t));
|
||||
n->m_len = maxlen;
|
||||
n->m_next = m;
|
||||
m_adj(m, maxlen);
|
||||
}
|
||||
m = n;
|
||||
}
|
||||
#endif
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
|
||||
|
||||
key_sa_recordxfer(sav, m);
|
||||
if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
|
||||
ipsec6stat.in_nomem++;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
*offp = off;
|
||||
*mp = m;
|
||||
|
||||
if (sav) {
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
printf("DP esp6_input call free SA:%p\n", sav));
|
||||
key_freesav(sav);
|
||||
}
|
||||
ipsec6stat.in_success++;
|
||||
return nxt;
|
||||
|
||||
bad:
|
||||
if (sav) {
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
||||
printf("DP esp6_input call free SA:%p\n", sav));
|
||||
key_freesav(sav);
|
||||
}
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
|
||||
void
|
||||
esp6_ctlinput(cmd, sa, d)
|
||||
int cmd;
|
||||
struct sockaddr *sa;
|
||||
void *d;
|
||||
{
|
||||
const struct newesp *espp;
|
||||
struct newesp esp;
|
||||
struct ip6ctlparam *ip6cp = NULL, ip6cp1;
|
||||
struct secasvar *sav;
|
||||
struct ip6_hdr *ip6;
|
||||
struct mbuf *m;
|
||||
int off;
|
||||
struct sockaddr_in6 *sa6_src, *sa6_dst;
|
||||
|
||||
if (sa->sa_family != AF_INET6 ||
|
||||
sa->sa_len != sizeof(struct sockaddr_in6))
|
||||
return;
|
||||
if ((unsigned)cmd >= PRC_NCMDS)
|
||||
return;
|
||||
|
||||
/* if the parameter is from icmp6, decode it. */
|
||||
if (d != NULL) {
|
||||
ip6cp = (struct ip6ctlparam *)d;
|
||||
m = ip6cp->ip6c_m;
|
||||
ip6 = ip6cp->ip6c_ip6;
|
||||
off = ip6cp->ip6c_off;
|
||||
} else {
|
||||
m = NULL;
|
||||
ip6 = NULL;
|
||||
off = 0; /* calm gcc */
|
||||
}
|
||||
|
||||
if (ip6) {
|
||||
/*
|
||||
* Notify the error to all possible sockets via pfctlinput2.
|
||||
* Since the upper layer information (such as protocol type,
|
||||
* source and destination ports) is embedded in the encrypted
|
||||
* data and might have been cut, we can't directly call
|
||||
* an upper layer ctlinput function. However, the pcbnotify
|
||||
* function will consider source and destination addresses
|
||||
* as well as the flow info value, and may be able to find
|
||||
* some PCB that should be notified.
|
||||
* Although pfctlinput2 will call esp6_ctlinput(), there is
|
||||
* no possibility of an infinite loop of function calls,
|
||||
* because we don't pass the inner IPv6 header.
|
||||
*/
|
||||
bzero(&ip6cp1, sizeof(ip6cp1));
|
||||
ip6cp1.ip6c_src = ip6cp->ip6c_src;
|
||||
pfctlinput2(cmd, sa, (void *)&ip6cp1);
|
||||
|
||||
/*
|
||||
* Then go to special cases that need ESP header information.
|
||||
* XXX: We assume that when ip6 is non NULL,
|
||||
* M and OFF are valid.
|
||||
*/
|
||||
|
||||
/* check if we can safely examine src and dst ports */
|
||||
if (m->m_pkthdr.len < off + sizeof(esp))
|
||||
return;
|
||||
|
||||
if (m->m_len < off + sizeof(esp)) {
|
||||
/*
|
||||
* this should be rare case,
|
||||
* so we compromise on this copy...
|
||||
*/
|
||||
m_copydata(m, off, sizeof(esp), (caddr_t)&esp);
|
||||
espp = &esp;
|
||||
} else
|
||||
espp = (struct newesp*)(mtod(m, caddr_t) + off);
|
||||
|
||||
if (cmd == PRC_MSGSIZE) {
|
||||
int valid = 0;
|
||||
|
||||
/*
|
||||
* Check to see if we have a valid SA corresponding to
|
||||
* the address in the ICMP message payload.
|
||||
*/
|
||||
sa6_src = ip6cp->ip6c_src;
|
||||
sa6_dst = (struct sockaddr_in6 *)sa;
|
||||
sav = key_allocsa(AF_INET6,
|
||||
(caddr_t)&sa6_src->sin6_addr,
|
||||
(caddr_t)&sa6_dst->sin6_addr,
|
||||
IPPROTO_ESP, espp->esp_spi);
|
||||
if (sav) {
|
||||
if (sav->state == SADB_SASTATE_MATURE ||
|
||||
sav->state == SADB_SASTATE_DYING)
|
||||
valid++;
|
||||
key_freesav(sav);
|
||||
}
|
||||
|
||||
/* XXX Further validation? */
|
||||
|
||||
/*
|
||||
* Depending on the value of "valid" and routing table
|
||||
* size (mtudisc_{hi,lo}wat), we will:
|
||||
* - recalcurate the new MTU and create the
|
||||
* corresponding routing entry, or
|
||||
* - ignore the MTU change notification.
|
||||
*/
|
||||
icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
|
||||
}
|
||||
} else {
|
||||
/* we normally notify any pcb here */
|
||||
}
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/* $FreeBSD$ */
|
||||
/* $KAME: esp_rijndael.c,v 1.14 2003/08/28 08:23:20 itojun 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.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#include <netinet6/esp.h>
|
||||
#include <netinet6/esp_rijndael.h>
|
||||
|
||||
#include <crypto/rijndael/rijndael.h>
|
||||
|
||||
size_t
|
||||
esp_rijndael_schedlen(algo)
|
||||
const struct esp_algorithm *algo;
|
||||
{
|
||||
|
||||
return sizeof(rijndael_ctx);
|
||||
}
|
||||
|
||||
int
|
||||
esp_rijndael_schedule(algo, sav)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
{
|
||||
rijndael_ctx *ctx;
|
||||
|
||||
ctx = (rijndael_ctx *)sav->sched;
|
||||
rijndael_set_key(ctx,
|
||||
(u_char *)_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc) * 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
esp_rijndael_blockdecrypt(algo, sav, s, d)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
u_int8_t *s;
|
||||
u_int8_t *d;
|
||||
{
|
||||
rijndael_ctx *ctx;
|
||||
|
||||
ctx = (rijndael_ctx *)sav->sched;
|
||||
rijndael_decrypt(ctx, s, d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
esp_rijndael_blockencrypt(algo, sav, s, d)
|
||||
const struct esp_algorithm *algo;
|
||||
struct secasvar *sav;
|
||||
u_int8_t *s;
|
||||
u_int8_t *d;
|
||||
{
|
||||
rijndael_ctx *ctx;
|
||||
|
||||
ctx = (rijndael_ctx *)sav->sched;
|
||||
rijndael_encrypt(ctx, s, d);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,356 +0,0 @@
|
|||
/* $FreeBSD$ */
|
||||
/* $KAME: ipcomp_core.c,v 1.25 2001/07/26 06:53:17 jinmei Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RFC2393 IP payload compression protocol (IPComp).
|
||||
*/
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/zlib.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <netinet6/ipcomp.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipcomp6.h>
|
||||
#endif
|
||||
#include <netinet6/ipsec.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipsec6.h>
|
||||
#endif
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
static void *deflate_alloc __P((void *, u_int, u_int));
|
||||
static void deflate_free __P((void *, void *));
|
||||
static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int));
|
||||
static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *));
|
||||
static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *));
|
||||
|
||||
/*
|
||||
* We need to use default window size (2^15 = 32Kbytes as of writing) for
|
||||
* inbound case. Otherwise we get interop problem.
|
||||
* Use negative value to avoid Adler32 checksum. This is an undocumented
|
||||
* feature in zlib (see ipsec wg mailing list archive in January 2000).
|
||||
*/
|
||||
static int deflate_policy = Z_DEFAULT_COMPRESSION;
|
||||
static int deflate_window_out = -12;
|
||||
static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
|
||||
static int deflate_memlevel = MAX_MEM_LEVEL;
|
||||
|
||||
static const struct ipcomp_algorithm ipcomp_algorithms[] = {
|
||||
{ deflate_compress, deflate_decompress, 90 },
|
||||
};
|
||||
|
||||
const struct ipcomp_algorithm *
|
||||
ipcomp_algorithm_lookup(idx)
|
||||
int idx;
|
||||
{
|
||||
|
||||
if (idx == SADB_X_CALG_DEFLATE)
|
||||
return &ipcomp_algorithms[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
deflate_alloc(aux, items, siz)
|
||||
void *aux;
|
||||
u_int items;
|
||||
u_int siz;
|
||||
{
|
||||
void *ptr;
|
||||
ptr = malloc(items * siz, M_TEMP, M_NOWAIT);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void
|
||||
deflate_free(aux, ptr)
|
||||
void *aux;
|
||||
void *ptr;
|
||||
{
|
||||
free(ptr, M_TEMP);
|
||||
}
|
||||
|
||||
static int
|
||||
deflate_common(m, md, lenp, mode)
|
||||
struct mbuf *m;
|
||||
struct mbuf *md;
|
||||
size_t *lenp;
|
||||
int mode; /* 0: compress 1: decompress */
|
||||
{
|
||||
struct mbuf *mprev;
|
||||
struct mbuf *p;
|
||||
struct mbuf *n = NULL, *n0 = NULL, **np;
|
||||
z_stream zs;
|
||||
int error = 0;
|
||||
int zerror;
|
||||
size_t offset;
|
||||
|
||||
#define MOREBLOCK() \
|
||||
do { \
|
||||
/* keep the reply buffer into our chain */ \
|
||||
if (n) { \
|
||||
n->m_len = zs.total_out - offset; \
|
||||
offset = zs.total_out; \
|
||||
*np = n; \
|
||||
np = &n->m_next; \
|
||||
n = NULL; \
|
||||
} \
|
||||
\
|
||||
/* get a fresh reply buffer */ \
|
||||
MGET(n, M_DONTWAIT, MT_DATA); \
|
||||
if (n) { \
|
||||
MCLGET(n, M_DONTWAIT); \
|
||||
} \
|
||||
if (!n) { \
|
||||
error = ENOBUFS; \
|
||||
goto fail; \
|
||||
} \
|
||||
n->m_len = 0; \
|
||||
n->m_len = M_TRAILINGSPACE(n); \
|
||||
n->m_next = NULL; \
|
||||
/* \
|
||||
* if this is the first reply buffer, reserve \
|
||||
* region for ipcomp header. \
|
||||
*/ \
|
||||
if (*np == NULL) { \
|
||||
n->m_len -= sizeof(struct ipcomp); \
|
||||
n->m_data += sizeof(struct ipcomp); \
|
||||
} \
|
||||
\
|
||||
zs.next_out = mtod(n, u_int8_t *); \
|
||||
zs.avail_out = n->m_len; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
|
||||
;
|
||||
if (!mprev)
|
||||
panic("md is not in m in deflate_common");
|
||||
|
||||
bzero(&zs, sizeof(zs));
|
||||
zs.zalloc = deflate_alloc;
|
||||
zs.zfree = deflate_free;
|
||||
|
||||
zerror = mode ? inflateInit2(&zs, deflate_window_in)
|
||||
: deflateInit2(&zs, deflate_policy, Z_DEFLATED,
|
||||
deflate_window_out, deflate_memlevel,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
if (zerror != Z_OK) {
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
n0 = n = NULL;
|
||||
np = &n0;
|
||||
offset = 0;
|
||||
zerror = 0;
|
||||
p = md;
|
||||
while (p && p->m_len == 0) {
|
||||
p = p->m_next;
|
||||
}
|
||||
|
||||
/* input stream and output stream are available */
|
||||
while (p && zs.avail_in == 0) {
|
||||
/* get input buffer */
|
||||
if (p && zs.avail_in == 0) {
|
||||
zs.next_in = mtod(p, u_int8_t *);
|
||||
zs.avail_in = p->m_len;
|
||||
p = p->m_next;
|
||||
while (p && p->m_len == 0) {
|
||||
p = p->m_next;
|
||||
}
|
||||
}
|
||||
|
||||
/* get output buffer */
|
||||
if (zs.next_out == NULL || zs.avail_out == 0) {
|
||||
MOREBLOCK();
|
||||
}
|
||||
|
||||
zerror = mode ? inflate(&zs, Z_NO_FLUSH)
|
||||
: deflate(&zs, Z_NO_FLUSH);
|
||||
|
||||
if (zerror == Z_STREAM_END)
|
||||
; /* once more. */
|
||||
else if (zerror == Z_OK) {
|
||||
/* inflate: Z_OK can indicate the end of decode */
|
||||
if (mode && !p && zs.avail_out != 0)
|
||||
goto terminate;
|
||||
else
|
||||
; /* once more. */
|
||||
} else {
|
||||
if (zs.msg) {
|
||||
ipseclog((LOG_ERR, "ipcomp_%scompress: "
|
||||
"%sflate(Z_NO_FLUSH): %s\n",
|
||||
mode ? "de" : "", mode ? "in" : "de",
|
||||
zs.msg));
|
||||
} else {
|
||||
ipseclog((LOG_ERR, "ipcomp_%scompress: "
|
||||
"%sflate(Z_NO_FLUSH): unknown error (%d)\n",
|
||||
mode ? "de" : "", mode ? "in" : "de",
|
||||
zerror));
|
||||
}
|
||||
mode ? inflateEnd(&zs) : deflateEnd(&zs);
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (zerror == Z_STREAM_END)
|
||||
goto terminate;
|
||||
|
||||
/* termination */
|
||||
while (1) {
|
||||
/* get output buffer */
|
||||
if (zs.next_out == NULL || zs.avail_out == 0) {
|
||||
MOREBLOCK();
|
||||
}
|
||||
|
||||
zerror = mode ? inflate(&zs, Z_SYNC_FLUSH)
|
||||
: deflate(&zs, Z_FINISH);
|
||||
|
||||
if (zerror == Z_STREAM_END)
|
||||
break;
|
||||
else if (zerror == Z_OK) {
|
||||
if (mode && zs.avail_out != 0)
|
||||
goto terminate;
|
||||
else
|
||||
; /* once more. */
|
||||
} else {
|
||||
if (zs.msg) {
|
||||
ipseclog((LOG_ERR, "ipcomp_%scompress: "
|
||||
"%sflate(Z_FINISH): %s\n",
|
||||
mode ? "de" : "", mode ? "in" : "de",
|
||||
zs.msg));
|
||||
} else {
|
||||
ipseclog((LOG_ERR, "ipcomp_%scompress: "
|
||||
"%sflate(Z_FINISH): unknown error (%d)\n",
|
||||
mode ? "de" : "", mode ? "in" : "de",
|
||||
zerror));
|
||||
}
|
||||
mode ? inflateEnd(&zs) : deflateEnd(&zs);
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
terminate:
|
||||
zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
|
||||
if (zerror != Z_OK) {
|
||||
if (zs.msg) {
|
||||
ipseclog((LOG_ERR, "ipcomp_%scompress: "
|
||||
"%sflateEnd: %s\n",
|
||||
mode ? "de" : "", mode ? "in" : "de",
|
||||
zs.msg));
|
||||
} else {
|
||||
ipseclog((LOG_ERR, "ipcomp_%scompress: "
|
||||
"%sflateEnd: unknown error (%d)\n",
|
||||
mode ? "de" : "", mode ? "in" : "de",
|
||||
zerror));
|
||||
}
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
/* keep the final reply buffer into our chain */
|
||||
if (n) {
|
||||
n->m_len = zs.total_out - offset;
|
||||
offset = zs.total_out;
|
||||
*np = n;
|
||||
np = &n->m_next;
|
||||
n = NULL;
|
||||
}
|
||||
|
||||
/* switch the mbuf to the new one */
|
||||
mprev->m_next = n0;
|
||||
m_freem(md);
|
||||
*lenp = zs.total_out;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
if (n)
|
||||
m_freem(n);
|
||||
if (n0)
|
||||
m_freem(n0);
|
||||
return error;
|
||||
#undef MOREBLOCK
|
||||
}
|
||||
|
||||
static int
|
||||
deflate_compress(m, md, lenp)
|
||||
struct mbuf *m;
|
||||
struct mbuf *md;
|
||||
size_t *lenp;
|
||||
{
|
||||
if (!m)
|
||||
panic("m == NULL in deflate_compress");
|
||||
if (!md)
|
||||
panic("md == NULL in deflate_compress");
|
||||
if (!lenp)
|
||||
panic("lenp == NULL in deflate_compress");
|
||||
|
||||
return deflate_common(m, md, lenp, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
deflate_decompress(m, md, lenp)
|
||||
struct mbuf *m;
|
||||
struct mbuf *md;
|
||||
size_t *lenp;
|
||||
{
|
||||
if (!m)
|
||||
panic("m == NULL in deflate_decompress");
|
||||
if (!md)
|
||||
panic("md == NULL in deflate_decompress");
|
||||
if (!lenp)
|
||||
panic("lenp == NULL in deflate_decompress");
|
||||
|
||||
return deflate_common(m, md, lenp, 1);
|
||||
}
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
/* $FreeBSD$ */
|
||||
/* $KAME: ipcomp_input.c,v 1.25 2001/03/01 09:12:09 itojun Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RFC2393 IP payload compression protocol (IPComp).
|
||||
*/
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/zlib.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_ecn.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
#include <netinet6/ipcomp.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipcomp6.h>
|
||||
#endif
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipsec6.h>
|
||||
#endif
|
||||
#include <netkey/key.h>
|
||||
#include <netkey/keydb.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#define IPLEN_FLIPPED
|
||||
|
||||
#ifdef INET
|
||||
extern struct protosw inetsw[];
|
||||
|
||||
void
|
||||
ipcomp4_input(m, off)
|
||||
struct mbuf *m;
|
||||
int off;
|
||||
{
|
||||
struct mbuf *md;
|
||||
struct ip *ip;
|
||||
struct ipcomp *ipcomp;
|
||||
const struct ipcomp_algorithm *algo;
|
||||
u_int16_t cpi; /* host order */
|
||||
u_int16_t nxt;
|
||||
size_t hlen;
|
||||
int error;
|
||||
size_t newlen, olen;
|
||||
struct secasvar *sav = NULL;
|
||||
|
||||
if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) {
|
||||
ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
|
||||
"(packet too short)\n"));
|
||||
ipsecstat.in_inval++;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
|
||||
if (!md) {
|
||||
m = NULL; /* already freed */
|
||||
ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
|
||||
"(pulldown failure)\n"));
|
||||
ipsecstat.in_inval++;
|
||||
goto fail;
|
||||
}
|
||||
ipcomp = mtod(md, struct ipcomp *);
|
||||
ip = mtod(m, struct ip *);
|
||||
nxt = ipcomp->comp_nxt;
|
||||
#ifdef _IP_VHL
|
||||
hlen = IP_VHL_HL(ip->ip_vhl) << 2;
|
||||
#else
|
||||
hlen = ip->ip_hl << 2;
|
||||
#endif
|
||||
|
||||
cpi = ntohs(ipcomp->comp_cpi);
|
||||
|
||||
if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
|
||||
sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src,
|
||||
(caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi));
|
||||
if (sav != NULL
|
||||
&& (sav->state == SADB_SASTATE_MATURE
|
||||
|| sav->state == SADB_SASTATE_DYING)) {
|
||||
cpi = sav->alg_enc; /* XXX */
|
||||
/* other parameters to look at? */
|
||||
}
|
||||
}
|
||||
algo = ipcomp_algorithm_lookup(cpi);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
|
||||
cpi));
|
||||
ipsecstat.in_nosa++;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* chop ipcomp header */
|
||||
ipcomp = NULL;
|
||||
md->m_data += sizeof(struct ipcomp);
|
||||
md->m_len -= sizeof(struct ipcomp);
|
||||
m->m_pkthdr.len -= sizeof(struct ipcomp);
|
||||
#ifdef IPLEN_FLIPPED
|
||||
ip->ip_len -= sizeof(struct ipcomp);
|
||||
#else
|
||||
ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
|
||||
#endif
|
||||
|
||||
olen = m->m_pkthdr.len;
|
||||
newlen = m->m_pkthdr.len - off;
|
||||
error = (*algo->decompress)(m, m->m_next, &newlen);
|
||||
if (error != 0) {
|
||||
if (error == EINVAL)
|
||||
ipsecstat.in_inval++;
|
||||
else if (error == ENOBUFS)
|
||||
ipsecstat.in_nomem++;
|
||||
m = NULL;
|
||||
goto fail;
|
||||
}
|
||||
ipsecstat.in_comphist[cpi]++;
|
||||
|
||||
/*
|
||||
* returning decompressed packet onto icmp is meaningless.
|
||||
* mark it decrypted to prevent icmp from attaching original packet.
|
||||
*/
|
||||
m->m_flags |= M_DECRYPTED;
|
||||
|
||||
m->m_pkthdr.len = off + newlen;
|
||||
ip = mtod(m, struct ip *);
|
||||
{
|
||||
size_t len;
|
||||
#ifdef IPLEN_FLIPPED
|
||||
len = ip->ip_len;
|
||||
#else
|
||||
len = ntohs(ip->ip_len);
|
||||
#endif
|
||||
/*
|
||||
* be careful about underflow. also, do not assign exact value
|
||||
* as ip_len is manipulated differently on *BSDs.
|
||||
*/
|
||||
len += m->m_pkthdr.len;
|
||||
len -= olen;
|
||||
if (len & ~0xffff) {
|
||||
/* packet too big after decompress */
|
||||
ipsecstat.in_inval++;
|
||||
goto fail;
|
||||
}
|
||||
#ifdef IPLEN_FLIPPED
|
||||
ip->ip_len = len & 0xffff;
|
||||
#else
|
||||
ip->ip_len = htons(len & 0xffff);
|
||||
#endif
|
||||
ip->ip_p = nxt;
|
||||
}
|
||||
|
||||
if (sav) {
|
||||
key_sa_recordxfer(sav, m);
|
||||
if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
|
||||
ipsecstat.in_nomem++;
|
||||
goto fail;
|
||||
}
|
||||
key_freesav(sav);
|
||||
sav = NULL;
|
||||
}
|
||||
|
||||
if (nxt != IPPROTO_DONE) {
|
||||
if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
|
||||
ipsec4_in_reject(m, NULL)) {
|
||||
ipsecstat.in_polvio++;
|
||||
goto fail;
|
||||
}
|
||||
(*inetsw[ip_protox[nxt]].pr_input)(m, off);
|
||||
} else
|
||||
m_freem(m);
|
||||
m = NULL;
|
||||
|
||||
ipsecstat.in_success++;
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (sav)
|
||||
key_freesav(sav);
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
int
|
||||
ipcomp6_input(mp, offp, proto)
|
||||
struct mbuf **mp;
|
||||
int *offp, proto;
|
||||
{
|
||||
struct mbuf *m, *md;
|
||||
int off;
|
||||
struct ip6_hdr *ip6;
|
||||
struct ipcomp *ipcomp;
|
||||
const struct ipcomp_algorithm *algo;
|
||||
u_int16_t cpi; /* host order */
|
||||
u_int16_t nxt;
|
||||
int error;
|
||||
size_t newlen;
|
||||
struct secasvar *sav = NULL;
|
||||
u_int8_t *prvnxtp;
|
||||
|
||||
m = *mp;
|
||||
off = *offp;
|
||||
|
||||
md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
|
||||
if (!md) {
|
||||
m = NULL; /* already freed */
|
||||
ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed "
|
||||
"(pulldown failure)\n"));
|
||||
ipsec6stat.in_inval++;
|
||||
goto fail;
|
||||
}
|
||||
ipcomp = mtod(md, struct ipcomp *);
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
nxt = ipcomp->comp_nxt;
|
||||
|
||||
cpi = ntohs(ipcomp->comp_cpi);
|
||||
|
||||
if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
|
||||
sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src,
|
||||
(caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi));
|
||||
if (sav != NULL
|
||||
&& (sav->state == SADB_SASTATE_MATURE
|
||||
|| sav->state == SADB_SASTATE_DYING)) {
|
||||
cpi = sav->alg_enc; /* XXX */
|
||||
/* other parameters to look at? */
|
||||
}
|
||||
}
|
||||
algo = ipcomp_algorithm_lookup(cpi);
|
||||
if (!algo) {
|
||||
ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
|
||||
"dropping the packet for simplicity\n", cpi));
|
||||
ipsec6stat.in_nosa++;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* chop ipcomp header */
|
||||
ipcomp = NULL;
|
||||
md->m_data += sizeof(struct ipcomp);
|
||||
md->m_len -= sizeof(struct ipcomp);
|
||||
m->m_pkthdr.len -= sizeof(struct ipcomp);
|
||||
|
||||
newlen = m->m_pkthdr.len - off;
|
||||
error = (*algo->decompress)(m, md, &newlen);
|
||||
if (error != 0) {
|
||||
if (error == EINVAL)
|
||||
ipsec6stat.in_inval++;
|
||||
else if (error == ENOBUFS)
|
||||
ipsec6stat.in_nomem++;
|
||||
m = NULL;
|
||||
goto fail;
|
||||
}
|
||||
ipsec6stat.in_comphist[cpi]++;
|
||||
m->m_pkthdr.len = off + newlen;
|
||||
|
||||
/*
|
||||
* returning decompressed packet onto icmp is meaningless.
|
||||
* mark it decrypted to prevent icmp from attaching original packet.
|
||||
*/
|
||||
m->m_flags |= M_DECRYPTED;
|
||||
|
||||
/* update next header field */
|
||||
prvnxtp = ip6_get_prevhdr(m, off);
|
||||
*prvnxtp = nxt;
|
||||
|
||||
/*
|
||||
* no need to adjust payload length, as all the IPv6 protocols
|
||||
* look at m->m_pkthdr.len
|
||||
*/
|
||||
|
||||
if (sav) {
|
||||
key_sa_recordxfer(sav, m);
|
||||
if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
|
||||
ipsec6stat.in_nomem++;
|
||||
goto fail;
|
||||
}
|
||||
key_freesav(sav);
|
||||
sav = NULL;
|
||||
}
|
||||
*offp = off;
|
||||
*mp = m;
|
||||
ipsec6stat.in_success++;
|
||||
return nxt;
|
||||
|
||||
fail:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
if (sav)
|
||||
key_freesav(sav);
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
|
@ -1,382 +0,0 @@
|
|||
/* $FreeBSD$ */
|
||||
/* $KAME: ipcomp_output.c,v 1.25 2002/06/09 14:44:00 itojun Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RFC2393 IP payload compression protocol (IPComp).
|
||||
*/
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/zlib.h>
|
||||
#include <machine/cpu.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_ecn.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
#include <netinet6/ipcomp.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipcomp6.h>
|
||||
#endif
|
||||
|
||||
#include <netinet6/ipsec.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ipsec6.h>
|
||||
#endif
|
||||
#include <netkey/key.h>
|
||||
#include <netkey/keydb.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *,
|
||||
struct ipsecrequest *, int));
|
||||
|
||||
/*
|
||||
* Modify the packet so that the payload is compressed.
|
||||
* The mbuf (m) must start with IPv4 or IPv6 header.
|
||||
* On failure, free the given mbuf and return non-zero.
|
||||
*
|
||||
* on invocation:
|
||||
* m nexthdrp md
|
||||
* v v v
|
||||
* IP ......... payload
|
||||
* during the encryption:
|
||||
* m nexthdrp mprev md
|
||||
* v v v v
|
||||
* IP ............... ipcomp payload
|
||||
* <-----><----->
|
||||
* complen plen
|
||||
* <-> hlen
|
||||
* <-----------------> compoff
|
||||
*/
|
||||
static int
|
||||
ipcomp_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 *md0;
|
||||
struct mbuf *mcopy;
|
||||
struct mbuf *mprev;
|
||||
struct ipcomp *ipcomp;
|
||||
struct secasvar *sav = isr->sav;
|
||||
const struct ipcomp_algorithm *algo;
|
||||
u_int16_t cpi; /* host order */
|
||||
size_t plen0, plen; /* payload length to be compressed */
|
||||
size_t compoff;
|
||||
int afnumber;
|
||||
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, "ipcomp_output: unsupported af %d\n", af));
|
||||
return 0; /* no change at all */
|
||||
}
|
||||
|
||||
/* grab parameters */
|
||||
algo = ipcomp_algorithm_lookup(sav->alg_enc);
|
||||
if ((ntohl(sav->spi) & ~0xffff) != 0 || !algo) {
|
||||
stat->out_inval++;
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
|
||||
cpi = sav->alg_enc;
|
||||
else
|
||||
cpi = ntohl(sav->spi) & 0xffff;
|
||||
|
||||
/* compute original payload length */
|
||||
plen = 0;
|
||||
for (n = md; n; n = n->m_next)
|
||||
plen += n->m_len;
|
||||
|
||||
/* if the payload is short enough, we don't need to compress */
|
||||
if (plen < algo->minplen)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* retain the original packet for two purposes:
|
||||
* (1) we need to backout our changes when compression is not necessary.
|
||||
* (2) byte lifetime computation should use the original packet.
|
||||
* see RFC2401 page 23.
|
||||
* compromise two m_copym(). we will be going through every byte of
|
||||
* the payload during compression process anyways.
|
||||
*/
|
||||
mcopy = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
|
||||
if (mcopy == NULL) {
|
||||
error = ENOBUFS;
|
||||
return 0;
|
||||
}
|
||||
md0 = m_copym(md, 0, M_COPYALL, M_DONTWAIT);
|
||||
if (md0 == NULL) {
|
||||
m_freem(mcopy);
|
||||
error = ENOBUFS;
|
||||
return 0;
|
||||
}
|
||||
plen0 = plen;
|
||||
|
||||
/* make the packet over-writable */
|
||||
for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
|
||||
;
|
||||
if (mprev == NULL || mprev->m_next != md) {
|
||||
ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n",
|
||||
afnumber));
|
||||
stat->out_inval++;
|
||||
m_freem(m);
|
||||
m_freem(md0);
|
||||
m_freem(mcopy);
|
||||
return EINVAL;
|
||||
}
|
||||
mprev->m_next = NULL;
|
||||
if ((md = ipsec_copypkt(md)) == NULL) {
|
||||
m_freem(m);
|
||||
m_freem(md0);
|
||||
m_freem(mcopy);
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
mprev->m_next = md;
|
||||
|
||||
/* compress data part */
|
||||
if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) {
|
||||
ipseclog((LOG_ERR, "packet compression failure\n"));
|
||||
m = NULL;
|
||||
m_freem(md0);
|
||||
m_freem(mcopy);
|
||||
stat->out_inval++;
|
||||
error = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
stat->out_comphist[sav->alg_enc]++;
|
||||
md = mprev->m_next;
|
||||
|
||||
/*
|
||||
* if the packet became bigger, meaningless to use IPComp.
|
||||
* we've only wasted our cpu time.
|
||||
*/
|
||||
if (plen0 < plen) {
|
||||
m_freem(md);
|
||||
m_freem(mcopy);
|
||||
mprev->m_next = md0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* no need to backout change beyond here.
|
||||
*/
|
||||
m_freem(md0);
|
||||
md0 = NULL;
|
||||
|
||||
m->m_pkthdr.len -= plen0;
|
||||
m->m_pkthdr.len += plen;
|
||||
|
||||
{
|
||||
/*
|
||||
* insert IPComp header.
|
||||
*/
|
||||
#ifdef INET
|
||||
struct ip *ip = NULL;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
struct ip6_hdr *ip6 = NULL;
|
||||
#endif
|
||||
size_t hlen = 0; /* ip header len */
|
||||
size_t complen = sizeof(struct ipcomp);
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
compoff = m->m_pkthdr.len - plen;
|
||||
|
||||
/*
|
||||
* grow the mbuf to accomodate ipcomp header.
|
||||
* before: IP ... payload
|
||||
* after: IP ... ipcomp payload
|
||||
*/
|
||||
if (M_LEADINGSPACE(md) < complen) {
|
||||
MGET(n, M_DONTWAIT, MT_DATA);
|
||||
if (!n) {
|
||||
m_freem(m);
|
||||
error = ENOBUFS;
|
||||
goto fail;
|
||||
}
|
||||
n->m_len = complen;
|
||||
mprev->m_next = n;
|
||||
n->m_next = md;
|
||||
m->m_pkthdr.len += complen;
|
||||
ipcomp = mtod(n, struct ipcomp *);
|
||||
} else {
|
||||
md->m_len += complen;
|
||||
md->m_data -= complen;
|
||||
m->m_pkthdr.len += complen;
|
||||
ipcomp = mtod(md, struct ipcomp *);
|
||||
}
|
||||
|
||||
bzero(ipcomp, sizeof(*ipcomp));
|
||||
ipcomp->comp_nxt = *nexthdrp;
|
||||
*nexthdrp = IPPROTO_IPCOMP;
|
||||
ipcomp->comp_cpi = htons(cpi);
|
||||
switch (af) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (compoff + complen + plen < IP_MAXPACKET)
|
||||
ip->ip_len = htons(compoff + complen + plen);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
ipseclog((LOG_DEBUG,
|
||||
"NULL mbuf after compression in ipcomp%d_output",
|
||||
afnumber));
|
||||
stat->out_inval++;
|
||||
}
|
||||
stat->out_success++;
|
||||
|
||||
/* compute byte lifetime against original packet */
|
||||
key_sa_recordxfer(sav, mcopy);
|
||||
m_freem(mcopy);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
#if 1
|
||||
return error;
|
||||
#else
|
||||
panic("something bad in ipcomp_output");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
int
|
||||
ipcomp4_output(m, isr)
|
||||
struct mbuf *m;
|
||||
struct ipsecrequest *isr;
|
||||
{
|
||||
struct ip *ip;
|
||||
if (m->m_len < sizeof(struct ip)) {
|
||||
ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n"));
|
||||
ipsecstat.out_inval++;
|
||||
m_freem(m);
|
||||
return 0;
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
/* XXX assumes that m->m_next points to payload */
|
||||
return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
int
|
||||
ipcomp6_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, "ipcomp6_output: first mbuf too short\n"));
|
||||
ipsec6stat.out_inval++;
|
||||
m_freem(m);
|
||||
return 0;
|
||||
}
|
||||
return ipcomp_output(m, nexthdrp, md, isr, AF_INET6);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
3643
sys/netinet6/ipsec.c
3643
sys/netinet6/ipsec.c
File diff suppressed because it is too large
Load diff
7647
sys/netkey/key.c
7647
sys/netkey/key.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,843 +0,0 @@
|
|||
/* $KAME: key_debug.c,v 1.38 2003/09/06 05:15:44 itojun 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_ipsec.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#ifdef _KERNEL
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netkey/key_var.h>
|
||||
#include <netkey/key_debug.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet6/ipsec.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif /* !_KERNEL */
|
||||
|
||||
struct typestr {
|
||||
const char *string;
|
||||
u_int type;
|
||||
};
|
||||
#define TYPESTR(x) { "SADB_" #x, SADB_ ## x }
|
||||
|
||||
static const char *kdebug_typestr(u_int, const struct typestr *);
|
||||
static const char *kdebug_sadb_msg_typestr(u_int);
|
||||
static const char *kdebug_sadb_ext_typestr(u_int);
|
||||
static void kdebug_sadb_prop(struct sadb_ext *);
|
||||
static void kdebug_sadb_identity(struct sadb_ext *);
|
||||
static void kdebug_sadb_supported(struct sadb_ext *);
|
||||
static void kdebug_sadb_lifetime(struct sadb_ext *);
|
||||
static void kdebug_sadb_sa(struct sadb_ext *);
|
||||
static void kdebug_sadb_address(struct sadb_ext *);
|
||||
static void kdebug_sadb_key(struct sadb_ext *);
|
||||
static void kdebug_sadb_x_sa2(struct sadb_ext *);
|
||||
|
||||
#ifdef _KERNEL
|
||||
static void kdebug_secreplay(struct secreplay *);
|
||||
#endif
|
||||
|
||||
#ifndef _KERNEL
|
||||
#define panic(param) { printf(param); exit(1); }
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
kdebug_typestr(type, list)
|
||||
u_int type;
|
||||
const struct typestr *list;
|
||||
{
|
||||
static char buf[32];
|
||||
|
||||
while (list->string != NULL) {
|
||||
if (type == list->type)
|
||||
return (list->string);
|
||||
list++;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%u", type);
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static const char *
|
||||
kdebug_sadb_msg_typestr(type)
|
||||
u_int type;
|
||||
{
|
||||
static const struct typestr list[] = {
|
||||
TYPESTR(RESERVED),
|
||||
TYPESTR(GETSPI),
|
||||
TYPESTR(UPDATE),
|
||||
TYPESTR(ADD),
|
||||
TYPESTR(DELETE),
|
||||
TYPESTR(GET),
|
||||
TYPESTR(ACQUIRE),
|
||||
TYPESTR(REGISTER),
|
||||
TYPESTR(EXPIRE),
|
||||
TYPESTR(FLUSH),
|
||||
TYPESTR(DUMP),
|
||||
TYPESTR(X_PROMISC),
|
||||
TYPESTR(X_PCHANGE),
|
||||
TYPESTR(X_SPDUPDATE),
|
||||
TYPESTR(X_SPDADD),
|
||||
TYPESTR(X_SPDDELETE),
|
||||
TYPESTR(X_SPDGET),
|
||||
TYPESTR(X_SPDACQUIRE),
|
||||
TYPESTR(X_SPDDUMP),
|
||||
TYPESTR(X_SPDFLUSH),
|
||||
TYPESTR(X_SPDSETIDX),
|
||||
TYPESTR(X_SPDEXPIRE),
|
||||
TYPESTR(X_SPDDELETE2),
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return kdebug_typestr(type, list);
|
||||
}
|
||||
|
||||
static const char *
|
||||
kdebug_sadb_ext_typestr(type)
|
||||
u_int type;
|
||||
{
|
||||
static const struct typestr list[] = {
|
||||
TYPESTR(EXT_RESERVED),
|
||||
TYPESTR(EXT_SA),
|
||||
TYPESTR(EXT_LIFETIME_CURRENT),
|
||||
TYPESTR(EXT_LIFETIME_HARD),
|
||||
TYPESTR(EXT_LIFETIME_SOFT),
|
||||
TYPESTR(EXT_ADDRESS_SRC),
|
||||
TYPESTR(EXT_ADDRESS_DST),
|
||||
TYPESTR(EXT_ADDRESS_PROXY),
|
||||
TYPESTR(EXT_KEY_AUTH),
|
||||
TYPESTR(EXT_KEY_ENCRYPT),
|
||||
TYPESTR(EXT_IDENTITY_SRC),
|
||||
TYPESTR(EXT_IDENTITY_DST),
|
||||
TYPESTR(EXT_SENSITIVITY),
|
||||
TYPESTR(EXT_PROPOSAL),
|
||||
TYPESTR(EXT_SUPPORTED_AUTH),
|
||||
TYPESTR(EXT_SUPPORTED_ENCRYPT),
|
||||
TYPESTR(EXT_SPIRANGE),
|
||||
TYPESTR(X_EXT_KMPRIVATE),
|
||||
TYPESTR(X_EXT_POLICY),
|
||||
TYPESTR(X_EXT_SA2),
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return kdebug_typestr(type, list);
|
||||
}
|
||||
|
||||
/* NOTE: host byte order */
|
||||
|
||||
/* %%%: about struct sadb_msg */
|
||||
void
|
||||
kdebug_sadb(base)
|
||||
struct sadb_msg *base;
|
||||
{
|
||||
struct sadb_ext *ext;
|
||||
int tlen, extlen;
|
||||
|
||||
/* sanity check */
|
||||
if (base == NULL)
|
||||
panic("kdebug_sadb: NULL pointer was passed.");
|
||||
|
||||
printf("sadb_msg{ version=%u type=%s errno=%u satype=%u\n",
|
||||
base->sadb_msg_version,
|
||||
kdebug_sadb_msg_typestr(base->sadb_msg_type),
|
||||
base->sadb_msg_errno, base->sadb_msg_satype);
|
||||
printf(" len=%u reserved=%u seq=%u pid=%u\n",
|
||||
base->sadb_msg_len, base->sadb_msg_reserved,
|
||||
base->sadb_msg_seq, base->sadb_msg_pid);
|
||||
|
||||
tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg);
|
||||
ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg));
|
||||
|
||||
while (tlen > 0) {
|
||||
printf("sadb_ext{ len=%u type=%s }\n",
|
||||
ext->sadb_ext_len,
|
||||
kdebug_sadb_ext_typestr(ext->sadb_ext_type));
|
||||
|
||||
if (ext->sadb_ext_len == 0) {
|
||||
printf("kdebug_sadb: invalid ext_len=0 was passed.\n");
|
||||
return;
|
||||
}
|
||||
if (ext->sadb_ext_len > tlen) {
|
||||
printf("kdebug_sadb: ext_len exceeds end of buffer.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ext->sadb_ext_type) {
|
||||
case SADB_EXT_SA:
|
||||
kdebug_sadb_sa(ext);
|
||||
break;
|
||||
case SADB_EXT_LIFETIME_CURRENT:
|
||||
case SADB_EXT_LIFETIME_HARD:
|
||||
case SADB_EXT_LIFETIME_SOFT:
|
||||
kdebug_sadb_lifetime(ext);
|
||||
break;
|
||||
case SADB_EXT_ADDRESS_SRC:
|
||||
case SADB_EXT_ADDRESS_DST:
|
||||
case SADB_EXT_ADDRESS_PROXY:
|
||||
kdebug_sadb_address(ext);
|
||||
break;
|
||||
case SADB_EXT_KEY_AUTH:
|
||||
case SADB_EXT_KEY_ENCRYPT:
|
||||
kdebug_sadb_key(ext);
|
||||
break;
|
||||
case SADB_EXT_IDENTITY_SRC:
|
||||
case SADB_EXT_IDENTITY_DST:
|
||||
kdebug_sadb_identity(ext);
|
||||
break;
|
||||
case SADB_EXT_SENSITIVITY:
|
||||
break;
|
||||
case SADB_EXT_PROPOSAL:
|
||||
kdebug_sadb_prop(ext);
|
||||
break;
|
||||
case SADB_EXT_SUPPORTED_AUTH:
|
||||
case SADB_EXT_SUPPORTED_ENCRYPT:
|
||||
kdebug_sadb_supported(ext);
|
||||
break;
|
||||
case SADB_EXT_SPIRANGE:
|
||||
case SADB_X_EXT_KMPRIVATE:
|
||||
break;
|
||||
case SADB_X_EXT_POLICY:
|
||||
kdebug_sadb_x_policy(ext);
|
||||
break;
|
||||
case SADB_X_EXT_SA2:
|
||||
kdebug_sadb_x_sa2(ext);
|
||||
break;
|
||||
default:
|
||||
printf("kdebug_sadb: invalid ext_type %u was passed.\n",
|
||||
ext->sadb_ext_type);
|
||||
return;
|
||||
}
|
||||
|
||||
extlen = PFKEY_UNUNIT64(ext->sadb_ext_len);
|
||||
tlen -= extlen;
|
||||
ext = (struct sadb_ext *)((caddr_t)ext + extlen);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_prop(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_prop *prop = (struct sadb_prop *)ext;
|
||||
struct sadb_comb *comb;
|
||||
int len;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_prop: NULL pointer was passed.");
|
||||
|
||||
len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop))
|
||||
/ sizeof(*comb);
|
||||
comb = (struct sadb_comb *)(prop + 1);
|
||||
printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay);
|
||||
|
||||
while (len--) {
|
||||
printf("sadb_comb{ auth=%u encrypt=%u "
|
||||
"flags=0x%04x reserved=0x%08x\n",
|
||||
comb->sadb_comb_auth, comb->sadb_comb_encrypt,
|
||||
comb->sadb_comb_flags, comb->sadb_comb_reserved);
|
||||
|
||||
printf(" auth_minbits=%u auth_maxbits=%u "
|
||||
"encrypt_minbits=%u encrypt_maxbits=%u\n",
|
||||
comb->sadb_comb_auth_minbits,
|
||||
comb->sadb_comb_auth_maxbits,
|
||||
comb->sadb_comb_encrypt_minbits,
|
||||
comb->sadb_comb_encrypt_maxbits);
|
||||
|
||||
printf(" soft_alloc=%u hard_alloc=%u "
|
||||
"soft_bytes=%lu hard_bytes=%lu\n",
|
||||
comb->sadb_comb_soft_allocations,
|
||||
comb->sadb_comb_hard_allocations,
|
||||
(unsigned long)comb->sadb_comb_soft_bytes,
|
||||
(unsigned long)comb->sadb_comb_hard_bytes);
|
||||
|
||||
printf(" soft_alloc=%lu hard_alloc=%lu "
|
||||
"soft_bytes=%lu hard_bytes=%lu }\n",
|
||||
(unsigned long)comb->sadb_comb_soft_addtime,
|
||||
(unsigned long)comb->sadb_comb_hard_addtime,
|
||||
(unsigned long)comb->sadb_comb_soft_usetime,
|
||||
(unsigned long)comb->sadb_comb_hard_usetime);
|
||||
comb++;
|
||||
}
|
||||
printf("}\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_identity(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_ident *id = (struct sadb_ident *)ext;
|
||||
int len;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_identity: NULL pointer was passed.");
|
||||
|
||||
len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id);
|
||||
printf("sadb_ident_%s{",
|
||||
id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst");
|
||||
switch (id->sadb_ident_type) {
|
||||
default:
|
||||
printf(" type=%u id=%lu",
|
||||
id->sadb_ident_type, (u_long)id->sadb_ident_id);
|
||||
if (len) {
|
||||
#ifdef _KERNEL
|
||||
ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/
|
||||
#else
|
||||
char *p, *ep;
|
||||
printf("\n str=\"");
|
||||
p = (char *)(id + 1);
|
||||
ep = p + len;
|
||||
for (/*nothing*/; *p && p < ep; p++) {
|
||||
if (isprint(*p))
|
||||
printf("%c", *p & 0xff);
|
||||
else
|
||||
printf("\\%03o", *p & 0xff);
|
||||
}
|
||||
#endif
|
||||
printf("\"");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" }\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_supported(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_supported *sup = (struct sadb_supported *)ext;
|
||||
struct sadb_alg *alg;
|
||||
int len;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_supported: NULL pointer was passed.");
|
||||
|
||||
len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup))
|
||||
/ sizeof(*alg);
|
||||
alg = (struct sadb_alg *)(sup + 1);
|
||||
printf("sadb_sup{\n");
|
||||
while (len--) {
|
||||
printf(" { id=%u ivlen=%u min=%u max=%u }\n",
|
||||
alg->sadb_alg_id, alg->sadb_alg_ivlen,
|
||||
alg->sadb_alg_minbits, alg->sadb_alg_maxbits);
|
||||
alg++;
|
||||
}
|
||||
printf("}\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_lifetime(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_lifetime *lft = (struct sadb_lifetime *)ext;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
printf("kdebug_sadb_lifetime: NULL pointer was passed.\n");
|
||||
|
||||
printf("sadb_lifetime{ alloc=%u, bytes=%u\n",
|
||||
lft->sadb_lifetime_allocations,
|
||||
(u_int32_t)lft->sadb_lifetime_bytes);
|
||||
printf(" addtime=%u, usetime=%u }\n",
|
||||
(u_int32_t)lft->sadb_lifetime_addtime,
|
||||
(u_int32_t)lft->sadb_lifetime_usetime);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_sa(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_sa *sa = (struct sadb_sa *)ext;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_sa: NULL pointer was passed.");
|
||||
|
||||
printf("sadb_sa{ spi=%u replay=%u state=%u\n",
|
||||
(u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay,
|
||||
sa->sadb_sa_state);
|
||||
printf(" auth=%u encrypt=%u flags=0x%08x }\n",
|
||||
sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_address(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_address *addr = (struct sadb_address *)ext;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_address: NULL pointer was passed.");
|
||||
|
||||
printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n",
|
||||
addr->sadb_address_proto, addr->sadb_address_prefixlen,
|
||||
((u_char *)&addr->sadb_address_reserved)[0],
|
||||
((u_char *)&addr->sadb_address_reserved)[1]);
|
||||
|
||||
kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_key(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_key *key = (struct sadb_key *)ext;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_key: NULL pointer was passed.");
|
||||
|
||||
printf("sadb_key{ bits=%u reserved=%u\n",
|
||||
key->sadb_key_bits, key->sadb_key_reserved);
|
||||
printf(" key=");
|
||||
|
||||
/* sanity check 2 */
|
||||
if ((key->sadb_key_bits >> 3) >
|
||||
(PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) {
|
||||
printf("kdebug_sadb_key: key length mismatch, bit:%u len:%ld.\n",
|
||||
key->sadb_key_bits >> 3,
|
||||
(long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key));
|
||||
}
|
||||
|
||||
ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key),
|
||||
key->sadb_key_bits >> 3);
|
||||
printf(" }\n");
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_sadb_x_sa2(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_x_sa2: NULL pointer was passed.");
|
||||
|
||||
printf("sadb_x_sa2{ mode=%u reqid=%u\n",
|
||||
sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid);
|
||||
printf(" reserved1=%u reserved2=%u sequence=%u }\n",
|
||||
sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved2,
|
||||
sa2->sadb_x_sa2_sequence);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_sadb_x_policy(ext)
|
||||
struct sadb_ext *ext;
|
||||
{
|
||||
struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext;
|
||||
struct sockaddr *addr;
|
||||
|
||||
/* sanity check */
|
||||
if (ext == NULL)
|
||||
panic("kdebug_sadb_x_policy: NULL pointer was passed.");
|
||||
|
||||
printf("sadb_x_policy{ type=%u dir=%u id=%x }\n",
|
||||
xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir,
|
||||
xpl->sadb_x_policy_id);
|
||||
|
||||
if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) {
|
||||
int tlen;
|
||||
struct sadb_x_ipsecrequest *xisr;
|
||||
|
||||
tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl);
|
||||
xisr = (struct sadb_x_ipsecrequest *)(xpl + 1);
|
||||
|
||||
while (tlen > 0) {
|
||||
printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n",
|
||||
xisr->sadb_x_ipsecrequest_len,
|
||||
xisr->sadb_x_ipsecrequest_proto,
|
||||
xisr->sadb_x_ipsecrequest_mode,
|
||||
xisr->sadb_x_ipsecrequest_level,
|
||||
xisr->sadb_x_ipsecrequest_reqid);
|
||||
|
||||
if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
|
||||
addr = (struct sockaddr *)(xisr + 1);
|
||||
kdebug_sockaddr(addr);
|
||||
addr = (struct sockaddr *)((caddr_t)addr
|
||||
+ addr->sa_len);
|
||||
kdebug_sockaddr(addr);
|
||||
}
|
||||
|
||||
printf(" }\n");
|
||||
|
||||
/* prevent infinite loop */
|
||||
if (xisr->sadb_x_ipsecrequest_len <= 0) {
|
||||
printf("kdebug_sadb_x_policy: wrong policy struct.\n");
|
||||
return;
|
||||
}
|
||||
/* prevent overflow */
|
||||
if (xisr->sadb_x_ipsecrequest_len > tlen) {
|
||||
printf("invalid ipsec policy length\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tlen -= xisr->sadb_x_ipsecrequest_len;
|
||||
|
||||
xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr
|
||||
+ xisr->sadb_x_ipsecrequest_len);
|
||||
}
|
||||
|
||||
if (tlen != 0)
|
||||
panic("kdebug_sadb_x_policy: wrong policy struct.");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* %%%: about SPD and SAD */
|
||||
void
|
||||
kdebug_secpolicy(sp)
|
||||
struct secpolicy *sp;
|
||||
{
|
||||
/* sanity check */
|
||||
if (sp == NULL)
|
||||
panic("kdebug_secpolicy: NULL pointer was passed.");
|
||||
|
||||
printf("secpolicy{ refcnt=%u state=%u policy=%u dir=%u\n",
|
||||
sp->refcnt, sp->state, sp->policy, sp->dir);
|
||||
|
||||
if (sp->spidx)
|
||||
kdebug_secpolicyindex(sp->spidx);
|
||||
|
||||
switch (sp->policy) {
|
||||
case IPSEC_POLICY_DISCARD:
|
||||
printf(" type=discard }\n");
|
||||
break;
|
||||
case IPSEC_POLICY_NONE:
|
||||
printf(" type=none }\n");
|
||||
break;
|
||||
case IPSEC_POLICY_IPSEC:
|
||||
{
|
||||
struct ipsecrequest *isr;
|
||||
for (isr = sp->req; isr != NULL; isr = isr->next) {
|
||||
|
||||
printf(" level=%u\n", isr->level);
|
||||
kdebug_secasindex(&isr->saidx);
|
||||
|
||||
if (isr->sav != NULL)
|
||||
kdebug_secasv(isr->sav);
|
||||
}
|
||||
printf(" }\n");
|
||||
}
|
||||
break;
|
||||
case IPSEC_POLICY_BYPASS:
|
||||
printf(" type=bypass }\n");
|
||||
break;
|
||||
case IPSEC_POLICY_ENTRUST:
|
||||
printf(" type=entrust }\n");
|
||||
break;
|
||||
default:
|
||||
printf("kdebug_secpolicy: Invalid policy found. %u\n",
|
||||
sp->policy);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_secpolicyindex(spidx)
|
||||
struct secpolicyindex *spidx;
|
||||
{
|
||||
/* sanity check */
|
||||
if (spidx == NULL)
|
||||
panic("kdebug_secpolicyindex: NULL pointer was passed.");
|
||||
|
||||
printf("secpolicyindex{ prefs=%u prefd=%u ul_proto=%u\n",
|
||||
spidx->prefs, spidx->prefd, spidx->ul_proto);
|
||||
|
||||
ipsec_hexdump((caddr_t)&spidx->src,
|
||||
((struct sockaddr *)&spidx->src)->sa_len);
|
||||
printf("\n");
|
||||
ipsec_hexdump((caddr_t)&spidx->dst,
|
||||
((struct sockaddr *)&spidx->dst)->sa_len);
|
||||
printf("}\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_secasindex(saidx)
|
||||
struct secasindex *saidx;
|
||||
{
|
||||
/* sanity check */
|
||||
if (saidx == NULL)
|
||||
panic("kdebug_secpolicyindex: NULL pointer was passed.");
|
||||
|
||||
printf("secasindex{ mode=%u proto=%u\n", saidx->mode, saidx->proto);
|
||||
|
||||
ipsec_hexdump((caddr_t)&saidx->src,
|
||||
((struct sockaddr *)&saidx->src)->sa_len);
|
||||
printf("\n");
|
||||
ipsec_hexdump((caddr_t)&saidx->dst,
|
||||
((struct sockaddr *)&saidx->dst)->sa_len);
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_secasv(sav)
|
||||
struct secasvar *sav;
|
||||
{
|
||||
/* sanity check */
|
||||
if (sav == NULL)
|
||||
panic("kdebug_secasv: NULL pointer was passed.");
|
||||
|
||||
printf("secas{");
|
||||
kdebug_secasindex(&sav->sah->saidx);
|
||||
|
||||
printf(" refcnt=%u state=%u auth=%u enc=%u\n",
|
||||
sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc);
|
||||
printf(" spi=%u flags=%u\n",
|
||||
(u_int32_t)ntohl(sav->spi), sav->flags);
|
||||
|
||||
if (sav->key_auth != NULL)
|
||||
kdebug_sadb_key((struct sadb_ext *)sav->key_auth);
|
||||
if (sav->key_enc != NULL)
|
||||
kdebug_sadb_key((struct sadb_ext *)sav->key_enc);
|
||||
if (sav->iv != NULL) {
|
||||
printf(" iv=");
|
||||
ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (sav->replay != NULL)
|
||||
kdebug_secreplay(sav->replay);
|
||||
if (sav->lft_c != NULL)
|
||||
kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c);
|
||||
if (sav->lft_h != NULL)
|
||||
kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h);
|
||||
if (sav->lft_s != NULL)
|
||||
kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s);
|
||||
|
||||
#ifdef notyet
|
||||
/* XXX: misc[123] ? */
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
kdebug_secreplay(rpl)
|
||||
struct secreplay *rpl;
|
||||
{
|
||||
int len, l;
|
||||
|
||||
/* sanity check */
|
||||
if (rpl == NULL)
|
||||
panic("kdebug_secreplay: NULL pointer was passed.");
|
||||
|
||||
printf(" secreplay{ count=%llu wsize=%u seq=%llu lastseq=%llu",
|
||||
(unsigned long long)rpl->count, rpl->wsize,
|
||||
(unsigned long long)rpl->seq, (unsigned long long)rpl->lastseq);
|
||||
|
||||
if (rpl->bitmap == NULL) {
|
||||
printf(" }\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\n bitmap { ");
|
||||
|
||||
for (len = 0; len < rpl->wsize; len++) {
|
||||
for (l = 7; l >= 0; l--)
|
||||
printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0);
|
||||
}
|
||||
printf(" }\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_mbufhdr(m)
|
||||
struct mbuf *m;
|
||||
{
|
||||
/* sanity check */
|
||||
if (m == NULL)
|
||||
return;
|
||||
|
||||
printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p "
|
||||
"m_len:%d m_type:0x%02x m_flags:0x%02x }\n",
|
||||
m, m->m_next, m->m_nextpkt, m->m_data,
|
||||
m->m_len, m->m_type, m->m_flags);
|
||||
|
||||
if (m->m_flags & M_PKTHDR) {
|
||||
printf(" m_pkthdr{ len:%d rcvif:%p }\n",
|
||||
m->m_pkthdr.len, m->m_pkthdr.rcvif);
|
||||
}
|
||||
|
||||
if (m->m_flags & M_EXT) {
|
||||
printf(" m_ext{ ext_buf:%p ext_free:%p "
|
||||
"ext_size:%u }\n",
|
||||
m->m_ext.ext_buf, m->m_ext.ext_free,
|
||||
m->m_ext.ext_size);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_mbuf(m0)
|
||||
struct mbuf *m0;
|
||||
{
|
||||
struct mbuf *m = m0;
|
||||
int i, j;
|
||||
|
||||
for (j = 0; m; m = m->m_next) {
|
||||
kdebug_mbufhdr(m);
|
||||
printf(" m_data:\n");
|
||||
for (i = 0; i < m->m_len; i++) {
|
||||
if (i && i % 32 == 0)
|
||||
printf("\n");
|
||||
if (i % 4 == 0)
|
||||
printf(" ");
|
||||
printf("%02x", mtod(m, u_char *)[i]);
|
||||
j++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
void
|
||||
kdebug_sockaddr(addr)
|
||||
struct sockaddr *addr;
|
||||
{
|
||||
struct sockaddr_in *sin4;
|
||||
#ifdef INET6
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif
|
||||
|
||||
/* sanity check */
|
||||
if (addr == NULL)
|
||||
panic("kdebug_sockaddr: NULL pointer was passed.");
|
||||
|
||||
/* NOTE: We deal with port number as host byte order. */
|
||||
printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family);
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
sin4 = (struct sockaddr_in *)addr;
|
||||
printf(" port=%u\n", ntohs(sin4->sin_port));
|
||||
ipsec_hexdump((caddr_t)&sin4->sin_addr, sizeof(sin4->sin_addr));
|
||||
break;
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *)addr;
|
||||
printf(" port=%u\n", ntohs(sin6->sin6_port));
|
||||
printf(" flowinfo=0x%08x, scope_id=0x%08x\n",
|
||||
sin6->sin6_flowinfo, sin6->sin6_scope_id);
|
||||
ipsec_hexdump((caddr_t)&sin6->sin6_addr,
|
||||
sizeof(sin6->sin6_addr));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
printf(" }\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
ipsec_bindump(buf, len)
|
||||
caddr_t buf;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%c", (unsigned char)buf[i]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipsec_hexdump(buf, len)
|
||||
caddr_t buf;
|
||||
int len;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i != 0 && i % 32 == 0) printf("\n");
|
||||
if (i % 4 == 0) printf(" ");
|
||||
printf("%02x", (unsigned char)buf[i]);
|
||||
}
|
||||
#if 0
|
||||
if (i % 32 != 0) printf("\n");
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1,259 +0,0 @@
|
|||
/* $KAME: keydb.c,v 1.82 2003/09/07 07:47:33 itojun 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <net/pfkeyv2.h>
|
||||
#include <netkey/keydb.h>
|
||||
#include <netkey/key.h>
|
||||
#include <netinet6/ipsec.h>
|
||||
|
||||
MALLOC_DEFINE(M_SECA, "key_mgmt", "security associations, key management");
|
||||
|
||||
/*
|
||||
* secpolicy management
|
||||
*/
|
||||
struct secpolicy *
|
||||
keydb_newsecpolicy()
|
||||
{
|
||||
struct secpolicy *p;
|
||||
|
||||
p = (struct secpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
|
||||
if (!p)
|
||||
return p;
|
||||
bzero(p, sizeof(*p));
|
||||
TAILQ_INSERT_TAIL(&sptailq, p, tailq);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
keydb_newspid(void)
|
||||
{
|
||||
u_int32_t newid = 0;
|
||||
static u_int32_t lastalloc = IPSEC_MANUAL_POLICYID_MAX;
|
||||
struct secpolicy *sp;
|
||||
|
||||
newid = lastalloc + 1;
|
||||
/* XXX possible infinite loop */
|
||||
again:
|
||||
TAILQ_FOREACH(sp, &sptailq, tailq) {
|
||||
if (sp->id == newid)
|
||||
break;
|
||||
}
|
||||
if (sp != NULL) {
|
||||
if (newid + 1 < newid) /* wraparound */
|
||||
newid = IPSEC_MANUAL_POLICYID_MAX + 1;
|
||||
else
|
||||
newid++;
|
||||
goto again;
|
||||
}
|
||||
lastalloc = newid;
|
||||
|
||||
return newid;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_delsecpolicy(p)
|
||||
struct secpolicy *p;
|
||||
{
|
||||
|
||||
TAILQ_REMOVE(&sptailq, p, tailq);
|
||||
if (p->spidx)
|
||||
free(p->spidx, M_SECA);
|
||||
free(p, M_SECA);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_setsecpolicyindex(p, idx)
|
||||
struct secpolicy *p;
|
||||
struct secpolicyindex *idx;
|
||||
{
|
||||
|
||||
if (!p->spidx)
|
||||
p->spidx = (struct secpolicyindex *)malloc(sizeof(*p->spidx),
|
||||
M_SECA, M_NOWAIT);
|
||||
if (!p->spidx)
|
||||
return ENOMEM;
|
||||
memcpy(p->spidx, idx, sizeof(*p->spidx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* secashead management
|
||||
*/
|
||||
struct secashead *
|
||||
keydb_newsecashead()
|
||||
{
|
||||
struct secashead *p;
|
||||
int i;
|
||||
|
||||
p = (struct secashead *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
|
||||
if (!p)
|
||||
return p;
|
||||
bzero(p, sizeof(*p));
|
||||
for (i = 0; i < sizeof(p->savtree)/sizeof(p->savtree[0]); i++)
|
||||
LIST_INIT(&p->savtree[i]);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_delsecashead(p)
|
||||
struct secashead *p;
|
||||
{
|
||||
|
||||
free(p, M_SECA);
|
||||
}
|
||||
|
||||
/*
|
||||
* secasvar management (reference counted)
|
||||
*/
|
||||
struct secasvar *
|
||||
keydb_newsecasvar()
|
||||
{
|
||||
struct secasvar *p, *q;
|
||||
static u_int32_t said = 0;
|
||||
|
||||
p = (struct secasvar *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
|
||||
if (!p)
|
||||
return p;
|
||||
|
||||
again:
|
||||
said++;
|
||||
if (said == 0)
|
||||
said++;
|
||||
TAILQ_FOREACH(q, &satailq, tailq) {
|
||||
if (q->id == said)
|
||||
goto again;
|
||||
if (TAILQ_NEXT(q, tailq)) {
|
||||
if (q->id < said && said < TAILQ_NEXT(q, tailq)->id)
|
||||
break;
|
||||
if (q->id + 1 < TAILQ_NEXT(q, tailq)->id) {
|
||||
said = q->id + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bzero(p, sizeof(*p));
|
||||
p->id = said;
|
||||
if (q)
|
||||
TAILQ_INSERT_AFTER(&satailq, q, p, tailq);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&satailq, p, tailq);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_delsecasvar(p)
|
||||
struct secasvar *p;
|
||||
{
|
||||
|
||||
TAILQ_REMOVE(&satailq, p, tailq);
|
||||
|
||||
free(p, M_SECA);
|
||||
}
|
||||
|
||||
/*
|
||||
* secreplay management
|
||||
*/
|
||||
struct secreplay *
|
||||
keydb_newsecreplay(wsize)
|
||||
size_t wsize;
|
||||
{
|
||||
struct secreplay *p;
|
||||
|
||||
p = (struct secreplay *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
|
||||
if (!p)
|
||||
return p;
|
||||
|
||||
bzero(p, sizeof(*p));
|
||||
if (wsize != 0) {
|
||||
p->bitmap = malloc(wsize, M_SECA, M_NOWAIT);
|
||||
if (!p->bitmap) {
|
||||
free(p, M_SECA);
|
||||
return NULL;
|
||||
}
|
||||
bzero(p->bitmap, wsize);
|
||||
}
|
||||
p->wsize = wsize;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_delsecreplay(p)
|
||||
struct secreplay *p;
|
||||
{
|
||||
|
||||
if (p->bitmap)
|
||||
free(p->bitmap, M_SECA);
|
||||
free(p, M_SECA);
|
||||
}
|
||||
|
||||
/*
|
||||
* secreg management
|
||||
*/
|
||||
struct secreg *
|
||||
keydb_newsecreg()
|
||||
{
|
||||
struct secreg *p;
|
||||
|
||||
p = (struct secreg *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
|
||||
if (p)
|
||||
bzero(p, sizeof(*p));
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_delsecreg(p)
|
||||
struct secreg *p;
|
||||
{
|
||||
|
||||
free(p, M_SECA);
|
||||
}
|
||||
|
|
@ -1,507 +0,0 @@
|
|||
/* $KAME: keysock.c,v 1.32 2003/08/22 05:45:08 itojun 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_ipsec.h"
|
||||
|
||||
/* This code has derived from sys/net/rtsock.c on FreeBSD 2.2.5 */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <net/raw_cb.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <net/pfkeyv2.h>
|
||||
#include <netkey/keydb.h>
|
||||
#include <netkey/key.h>
|
||||
#include <netkey/keysock.h>
|
||||
#include <netkey/key_debug.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
struct sockaddr key_dst = { 2, PF_KEY, };
|
||||
struct sockaddr key_src = { 2, PF_KEY, };
|
||||
|
||||
static int key_sendup0(struct rawcb *, struct mbuf *, int);
|
||||
|
||||
struct pfkeystat pfkeystat;
|
||||
|
||||
/*
|
||||
* key_output()
|
||||
*/
|
||||
int
|
||||
key_output(struct mbuf *m, struct socket *so)
|
||||
{
|
||||
struct sadb_msg *msg;
|
||||
int len, error = 0;
|
||||
int s;
|
||||
|
||||
if (m == 0)
|
||||
panic("key_output: NULL pointer was passed.");
|
||||
|
||||
pfkeystat.out_total++;
|
||||
pfkeystat.out_bytes += m->m_pkthdr.len;
|
||||
|
||||
len = m->m_pkthdr.len;
|
||||
if (len < sizeof(struct sadb_msg)) {
|
||||
pfkeystat.out_tooshort++;
|
||||
error = EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (m->m_len < sizeof(struct sadb_msg)) {
|
||||
if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) {
|
||||
pfkeystat.out_nomem++;
|
||||
error = ENOBUFS;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
|
||||
KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m));
|
||||
|
||||
msg = mtod(m, struct sadb_msg *);
|
||||
pfkeystat.out_msgtype[msg->sadb_msg_type]++;
|
||||
if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) {
|
||||
pfkeystat.out_invlen++;
|
||||
error = EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*XXX giant lock*/
|
||||
s = splnet();
|
||||
error = key_parse(m, so);
|
||||
m = NULL;
|
||||
splx(s);
|
||||
end:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* send message to the socket.
|
||||
*/
|
||||
static int
|
||||
key_sendup0(rp, m, promisc)
|
||||
struct rawcb *rp;
|
||||
struct mbuf *m;
|
||||
int promisc;
|
||||
{
|
||||
int error;
|
||||
|
||||
if (promisc) {
|
||||
struct sadb_msg *pmsg;
|
||||
|
||||
M_PREPEND(m, sizeof(struct sadb_msg), M_DONTWAIT);
|
||||
if (m && m->m_len < sizeof(struct sadb_msg))
|
||||
m = m_pullup(m, sizeof(struct sadb_msg));
|
||||
if (!m) {
|
||||
pfkeystat.in_nomem++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
m->m_pkthdr.len += sizeof(*pmsg);
|
||||
|
||||
pmsg = mtod(m, struct sadb_msg *);
|
||||
bzero(pmsg, sizeof(*pmsg));
|
||||
pmsg->sadb_msg_version = PF_KEY_V2;
|
||||
pmsg->sadb_msg_type = SADB_X_PROMISC;
|
||||
pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len);
|
||||
/* pid and seq? */
|
||||
|
||||
pfkeystat.in_msgtype[pmsg->sadb_msg_type]++;
|
||||
}
|
||||
|
||||
if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src,
|
||||
m, NULL)) {
|
||||
pfkeystat.in_nomem++;
|
||||
m_freem(m);
|
||||
error = ENOBUFS;
|
||||
} else
|
||||
error = 0;
|
||||
sorwakeup(rp->rcb_socket);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* so can be NULL if target != KEY_SENDUP_ONE */
|
||||
int
|
||||
key_sendup_mbuf(so, m, target)
|
||||
struct socket *so;
|
||||
struct mbuf *m;
|
||||
int target;
|
||||
{
|
||||
struct mbuf *n;
|
||||
struct keycb *kp;
|
||||
int sendup;
|
||||
struct rawcb *rp;
|
||||
int error = 0;
|
||||
|
||||
if (m == NULL)
|
||||
panic("key_sendup_mbuf: NULL pointer was passed.");
|
||||
if (so == NULL && target == KEY_SENDUP_ONE)
|
||||
panic("key_sendup_mbuf: NULL pointer was passed.");
|
||||
|
||||
pfkeystat.in_total++;
|
||||
pfkeystat.in_bytes += m->m_pkthdr.len;
|
||||
if (m->m_len < sizeof(struct sadb_msg)) {
|
||||
m = m_pullup(m, sizeof(struct sadb_msg));
|
||||
if (m == NULL) {
|
||||
pfkeystat.in_nomem++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
}
|
||||
if (m->m_len >= sizeof(struct sadb_msg)) {
|
||||
struct sadb_msg *msg;
|
||||
msg = mtod(m, struct sadb_msg *);
|
||||
pfkeystat.in_msgtype[msg->sadb_msg_type]++;
|
||||
}
|
||||
|
||||
LIST_FOREACH(rp, &rawcb_list, list) {
|
||||
if (rp->rcb_proto.sp_family != PF_KEY)
|
||||
continue;
|
||||
if (rp->rcb_proto.sp_protocol &&
|
||||
rp->rcb_proto.sp_protocol != PF_KEY_V2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kp = (struct keycb *)rp;
|
||||
|
||||
/*
|
||||
* If you are in promiscuous mode, and when you get broadcasted
|
||||
* reply, you'll get two PF_KEY messages.
|
||||
* (based on pf_key@inner.net message on 14 Oct 1998)
|
||||
*/
|
||||
if (((struct keycb *)rp)->kp_promisc) {
|
||||
if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) {
|
||||
(void)key_sendup0(rp, n, 1);
|
||||
n = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* the exact target will be processed later */
|
||||
if (so && sotorawcb(so) == rp)
|
||||
continue;
|
||||
|
||||
sendup = 0;
|
||||
switch (target) {
|
||||
case KEY_SENDUP_ONE:
|
||||
/* the statement has no effect */
|
||||
if (so && sotorawcb(so) == rp)
|
||||
sendup++;
|
||||
break;
|
||||
case KEY_SENDUP_ALL:
|
||||
sendup++;
|
||||
break;
|
||||
case KEY_SENDUP_REGISTERED:
|
||||
if (kp->kp_registered)
|
||||
sendup++;
|
||||
break;
|
||||
}
|
||||
pfkeystat.in_msgtarget[target]++;
|
||||
|
||||
if (!sendup)
|
||||
continue;
|
||||
|
||||
if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) {
|
||||
m_freem(m);
|
||||
pfkeystat.in_nomem++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
/*
|
||||
* ignore error even if queue is full. PF_KEY does not
|
||||
* guarantee the delivery of the message.
|
||||
* this is important when target == KEY_SENDUP_ALL.
|
||||
*/
|
||||
key_sendup0(rp, n, 0);
|
||||
|
||||
n = NULL;
|
||||
}
|
||||
|
||||
if (so) {
|
||||
error = key_sendup0(sotorawcb(so), m, 0);
|
||||
m = NULL;
|
||||
} else {
|
||||
error = 0;
|
||||
m_freem(m);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_abort()
|
||||
* derived from net/rtsock.c:rts_abort()
|
||||
*/
|
||||
static void
|
||||
key_abort(struct socket *so)
|
||||
{
|
||||
|
||||
raw_usrreqs.pru_abort(so);
|
||||
}
|
||||
|
||||
/*
|
||||
* key_attach()
|
||||
* derived from net/rtsock.c:rts_attach()
|
||||
*/
|
||||
static int
|
||||
key_attach(struct socket *so, int proto, struct thread *p)
|
||||
{
|
||||
struct keycb *kp;
|
||||
int s, error;
|
||||
|
||||
KASSERT(sotorawcb(so) == NULL, ("key_attach: so_pcb != NULL"));
|
||||
kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK); /* XXX */
|
||||
if (kp == 0)
|
||||
return ENOBUFS;
|
||||
bzero(kp, sizeof *kp);
|
||||
|
||||
/*
|
||||
* The splnet() is necessary to block protocols from sending
|
||||
* error notifications (like RTM_REDIRECT or RTM_LOSING) while
|
||||
* this PCB is extant but incompletely initialized.
|
||||
* Probably we should try to do more of this work beforehand and
|
||||
* eliminate the spl.
|
||||
*/
|
||||
s = splnet();
|
||||
so->so_pcb = (caddr_t)kp;
|
||||
error = raw_usrreqs.pru_attach(so, proto, p);
|
||||
kp = (struct keycb *)sotorawcb(so);
|
||||
if (error) {
|
||||
free(kp, M_PCB);
|
||||
so->so_pcb = (caddr_t) 0;
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
kp->kp_promisc = kp->kp_registered = 0;
|
||||
|
||||
if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */
|
||||
key_cb.key_count++;
|
||||
key_cb.any_count++;
|
||||
kp->kp_raw.rcb_laddr = &key_src;
|
||||
kp->kp_raw.rcb_faddr = &key_dst;
|
||||
soisconnected(so);
|
||||
so->so_options |= SO_USELOOPBACK;
|
||||
|
||||
splx(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_bind()
|
||||
* derived from net/rtsock.c:rts_bind()
|
||||
*/
|
||||
static int
|
||||
key_bind(struct socket *so, struct sockaddr *nam, struct thread *p)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_bind(so, nam, p); /* xxx just EINVAL */
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_close()
|
||||
* derived from net/rtsock.c:rts_close()
|
||||
*/
|
||||
static void
|
||||
key_close(struct socket *so)
|
||||
{
|
||||
|
||||
raw_usrreqs.pru_close(so);
|
||||
}
|
||||
|
||||
/*
|
||||
* key_connect()
|
||||
* derived from net/rtsock.c:rts_connect()
|
||||
*/
|
||||
static int
|
||||
key_connect(struct socket *so, struct sockaddr *nam, struct thread *p)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_connect(so, nam, p); /* XXX just EINVAL */
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_detach()
|
||||
* derived from net/rtsock.c:rts_detach()
|
||||
*/
|
||||
static void
|
||||
key_detach(struct socket *so)
|
||||
{
|
||||
struct keycb *kp = (struct keycb *)sotorawcb(so);
|
||||
|
||||
KASSERT(kp != NULL, ("key_detach: kp == NULL"));
|
||||
if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */
|
||||
key_cb.key_count--;
|
||||
key_cb.any_count--;
|
||||
key_freereg(so);
|
||||
raw_usrreqs.pru_detach(so);
|
||||
}
|
||||
|
||||
/*
|
||||
* key_disconnect()
|
||||
* derived from net/rtsock.c:key_disconnect()
|
||||
*/
|
||||
static int
|
||||
key_disconnect(struct socket *so)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_disconnect(so);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_peeraddr()
|
||||
* derived from net/rtsock.c:rts_peeraddr()
|
||||
*/
|
||||
static int
|
||||
key_peeraddr(struct socket *so, struct sockaddr **nam)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_peeraddr(so, nam);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_send()
|
||||
* derived from net/rtsock.c:rts_send()
|
||||
*/
|
||||
static int
|
||||
key_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
|
||||
struct mbuf *control, struct thread *p)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_send(so, flags, m, nam, control, p);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_shutdown()
|
||||
* derived from net/rtsock.c:rts_shutdown()
|
||||
*/
|
||||
static int
|
||||
key_shutdown(struct socket *so)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_shutdown(so);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_sockaddr()
|
||||
* derived from net/rtsock.c:rts_sockaddr()
|
||||
*/
|
||||
static int
|
||||
key_sockaddr(struct socket *so, struct sockaddr **nam)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet();
|
||||
error = raw_usrreqs.pru_sockaddr(so, nam);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
struct pr_usrreqs key_usrreqs = {
|
||||
.pru_abort = key_abort,
|
||||
.pru_attach = key_attach,
|
||||
.pru_bind = key_bind,
|
||||
.pru_connect = key_connect,
|
||||
.pru_detach = key_detach,
|
||||
.pru_disconnect = key_disconnect,
|
||||
.pru_peeraddr = key_peeraddr,
|
||||
.pru_send = key_send,
|
||||
.pru_shutdown = key_shutdown,
|
||||
.pru_sockaddr = key_sockaddr,
|
||||
.pru_close = key_close,
|
||||
};
|
||||
|
||||
/* sysctl */
|
||||
SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family");
|
||||
|
||||
/*
|
||||
* Definitions of protocols supported in the KEY domain.
|
||||
*/
|
||||
|
||||
extern struct domain keydomain;
|
||||
|
||||
struct protosw keysw[] = {
|
||||
{
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &keydomain,
|
||||
.pr_protocol = PF_KEY_V2,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_output = key_output,
|
||||
.pr_ctlinput = raw_ctlinput,
|
||||
.pr_init = raw_init,
|
||||
.pr_usrreqs = &key_usrreqs
|
||||
}
|
||||
};
|
||||
|
||||
struct domain keydomain = {
|
||||
.dom_family = PF_KEY,
|
||||
.dom_name = "key",
|
||||
.dom_init = key_init,
|
||||
.dom_protosw = keysw,
|
||||
.dom_protoswNPROTOSW = &keysw[sizeof(keysw)/sizeof(keysw[0])]
|
||||
};
|
||||
|
||||
DOMAIN_SET(key);
|
||||
Loading…
Reference in a new issue