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:
George V. Neville-Neil 2007-07-02 04:02:21 +00:00
parent ae259a3d16
commit e66ff7fc8e
17 changed files with 0 additions and 20184 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);