diff options
author | gnn <gnn@FreeBSD.org> | 2007-07-02 04:02:21 +0000 |
---|---|---|
committer | gnn <gnn@FreeBSD.org> | 2007-07-02 04:02:21 +0000 |
commit | 1fb03182c6de3f7f75b2a9da7b8073d4841a2efb (patch) | |
tree | 6df8d4c96747b077dca8235520e509938099fd51 | |
parent | 5c6fefddf19dab2daf83978f2a7c91d83643b307 (diff) | |
download | FreeBSD-src-1fb03182c6de3f7f75b2a9da7b8073d4841a2efb.zip FreeBSD-src-1fb03182c6de3f7f75b2a9da7b8073d4841a2efb.tar.gz |
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
-rw-r--r-- | sys/netinet6/ah_aesxcbcmac.c | 190 | ||||
-rw-r--r-- | sys/netinet6/ah_core.c | 1644 | ||||
-rw-r--r-- | sys/netinet6/ah_input.c | 1024 | ||||
-rw-r--r-- | sys/netinet6/ah_output.c | 586 | ||||
-rw-r--r-- | sys/netinet6/esp_aesctr.c | 461 | ||||
-rw-r--r-- | sys/netinet6/esp_camellia.c | 93 | ||||
-rw-r--r-- | sys/netinet6/esp_core.c | 1134 | ||||
-rw-r--r-- | sys/netinet6/esp_input.c | 975 | ||||
-rw-r--r-- | sys/netinet6/esp_rijndael.c | 95 | ||||
-rw-r--r-- | sys/netinet6/ipcomp_core.c | 356 | ||||
-rw-r--r-- | sys/netinet6/ipcomp_input.c | 345 | ||||
-rw-r--r-- | sys/netinet6/ipcomp_output.c | 382 | ||||
-rw-r--r-- | sys/netinet6/ipsec.c | 3643 | ||||
-rw-r--r-- | sys/netkey/key.c | 7647 | ||||
-rw-r--r-- | sys/netkey/key_debug.c | 843 | ||||
-rw-r--r-- | sys/netkey/keydb.c | 259 | ||||
-rw-r--r-- | sys/netkey/keysock.c | 507 |
17 files changed, 0 insertions, 20184 deletions
diff --git a/sys/netinet6/ah_aesxcbcmac.c b/sys/netinet6/ah_aesxcbcmac.c deleted file mode 100644 index 3c83d33..0000000 --- a/sys/netinet6/ah_aesxcbcmac.c +++ /dev/null @@ -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); -} diff --git a/sys/netinet6/ah_core.c b/sys/netinet6/ah_core.c deleted file mode 100644 index c36a777..0000000 --- a/sys/netinet6/ah_core.c +++ /dev/null @@ -1,1644 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ah_core.c,v 1.59 2003/07/25 10:17:14 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. - */ - -/* TODO: have shared routines for hmac-* algorithms */ - -#include "opt_inet.h" -#include "opt_inet6.h" -#include "opt_ipsec.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/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 <netinet6/scope6_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 <netinet6/ah_aesxcbcmac.h> -#ifdef IPSEC_ESP -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#endif -#include <net/pfkeyv2.h> -#include <netkey/keydb.h> -#include <sys/md5.h> -#define MD5_RESULTLEN 16 -#include <crypto/sha1.h> -#include <crypto/sha2/sha2.h> -#include <opencrypto/rmd160.h> -#define RIPEMD160_RESULTLEN 20 - -static int ah_sumsiz_1216 __P((struct secasvar *)); -static int ah_sumsiz_zero __P((struct secasvar *)); -static int ah_common_mature __P((struct secasvar *)); -static int ah_none_mature __P((struct secasvar *)); -static int ah_none_init __P((struct ah_algorithm_state *, struct secasvar *)); -static void ah_none_loop __P((struct ah_algorithm_state *, u_int8_t *, size_t)); -static void ah_none_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_keyed_md5_mature __P((struct secasvar *)); -static int ah_keyed_md5_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_keyed_md5_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_keyed_md5_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_keyed_sha1_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_keyed_sha1_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_keyed_sha1_result __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static int ah_hmac_md5_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_md5_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_md5_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha1_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha1_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha1_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha2_256_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha2_256_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha2_256_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha2_384_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha2_384_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha2_384_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_sha2_512_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_sha2_512_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_sha2_512_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); -static int ah_hmac_ripemd160_init __P((struct ah_algorithm_state *, - struct secasvar *)); -static void ah_hmac_ripemd160_loop __P((struct ah_algorithm_state *, u_int8_t *, - size_t)); -static void ah_hmac_ripemd160_result __P((struct ah_algorithm_state *, - u_int8_t *, size_t)); - -static void ah_update_mbuf __P((struct mbuf *, int, int, - const struct ah_algorithm *, struct ah_algorithm_state *)); - -/* checksum algorithms */ -static const struct ah_algorithm ah_algorithms[] = { - { ah_sumsiz_1216, ah_common_mature, 128, 128, "hmac-md5", - ah_hmac_md5_init, ah_hmac_md5_loop, - ah_hmac_md5_result, }, - { ah_sumsiz_1216, ah_common_mature, 160, 160, "hmac-sha1", - ah_hmac_sha1_init, ah_hmac_sha1_loop, - ah_hmac_sha1_result, }, - { ah_sumsiz_1216, ah_keyed_md5_mature, 128, 128, "keyed-md5", - ah_keyed_md5_init, ah_keyed_md5_loop, - ah_keyed_md5_result, }, - { ah_sumsiz_1216, ah_common_mature, 160, 160, "keyed-sha1", - ah_keyed_sha1_init, ah_keyed_sha1_loop, - ah_keyed_sha1_result, }, - { ah_sumsiz_zero, ah_none_mature, 0, 2048, "none", - ah_none_init, ah_none_loop, ah_none_result, }, - { ah_sumsiz_1216, ah_common_mature, 256, 256, - "hmac-sha2-256", - ah_hmac_sha2_256_init, ah_hmac_sha2_256_loop, - ah_hmac_sha2_256_result, }, - { ah_sumsiz_1216, ah_common_mature, 384, 384, - "hmac-sha2-384", - ah_hmac_sha2_384_init, ah_hmac_sha2_384_loop, - ah_hmac_sha2_384_result, }, - { ah_sumsiz_1216, ah_common_mature, 512, 512, - "hmac-sha2-512", - ah_hmac_sha2_512_init, ah_hmac_sha2_512_loop, - ah_hmac_sha2_512_result, }, - { ah_sumsiz_1216, ah_common_mature, 160, 160, - "hmac-ripemd160", - ah_hmac_ripemd160_init, ah_hmac_ripemd160_loop, - ah_hmac_ripemd160_result, }, - { ah_sumsiz_1216, ah_common_mature, 128, 128, - "aes-xcbc-mac", - ah_aes_xcbc_mac_init, ah_aes_xcbc_mac_loop, - ah_aes_xcbc_mac_result, }, - { ah_sumsiz_1216, ah_none_mature, 8, 640, /* bits (RFC 2385) */ - "TCP-MD5", - ah_none_init, ah_none_loop, - ah_none_result, }, -}; - -const struct ah_algorithm * -ah_algorithm_lookup(idx) - int idx; -{ - - switch (idx) { - case SADB_AALG_MD5HMAC: - return &ah_algorithms[0]; - case SADB_AALG_SHA1HMAC: - return &ah_algorithms[1]; - case SADB_X_AALG_MD5: - return &ah_algorithms[2]; - case SADB_X_AALG_SHA: - return &ah_algorithms[3]; - case SADB_X_AALG_NULL: - return &ah_algorithms[4]; - case SADB_X_AALG_SHA2_256: - return &ah_algorithms[5]; - case SADB_X_AALG_SHA2_384: - return &ah_algorithms[6]; - case SADB_X_AALG_SHA2_512: - return &ah_algorithms[7]; - case SADB_X_AALG_RIPEMD160HMAC: - return &ah_algorithms[8]; - case SADB_X_AALG_AES_XCBC_MAC: - return &ah_algorithms[9]; - case SADB_X_AALG_TCP_MD5: - return &ah_algorithms[10]; - default: - return NULL; - } -} - - -static int -ah_sumsiz_1216(sav) - struct secasvar *sav; -{ - if (!sav) - panic("ah_sumsiz_1216: null pointer is passed"); - if (sav->flags & SADB_X_EXT_OLD) - return 16; - else - return 12; -} - -static int -ah_sumsiz_zero(sav) - struct secasvar *sav; -{ - if (!sav) - panic("ah_sumsiz_zero: null pointer is passed"); - return 0; -} - -static int -ah_common_mature(sav) - struct secasvar *sav; -{ - const struct ah_algorithm *algo; - - if (!sav->key_auth) { - ipseclog((LOG_ERR, "ah_common_mature: no key is given.\n")); - return 1; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_ERR, "ah_common_mature: unsupported algorithm.\n")); - return 1; - } - - if (sav->key_auth->sadb_key_bits < algo->keymin || - algo->keymax < sav->key_auth->sadb_key_bits) { - ipseclog((LOG_ERR, - "ah_common_mature: invalid key length %d for %s.\n", - sav->key_auth->sadb_key_bits, algo->name)); - return 1; - } - - return 0; -} - -static int -ah_none_mature(sav) - struct secasvar *sav; -{ - if (sav->sah->saidx.proto == IPPROTO_AH) { - ipseclog((LOG_ERR, - "ah_none_mature: protocol and algorithm mismatch.\n")); - return 1; - } - return 0; -} - -static int -ah_none_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - state->foo = NULL; - return 0; -} - -static void -ah_none_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ -} - -static void -ah_none_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ -} - -static int -ah_keyed_md5_mature(sav) - struct secasvar *sav; -{ - /* anything is okay */ - return 0; -} - -static int -ah_keyed_md5_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - - if (!state) - panic("ah_keyed_md5_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(sizeof(MD5_CTX), M_TEMP, M_NOWAIT); - if (state->foo == NULL) - return ENOBUFS; - - MD5Init((MD5_CTX *)state->foo); - if (state->sav) { - MD5Update((MD5_CTX *)state->foo, - (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - - /* - * Pad after the key. - * We cannot simply use md5_pad() since the function - * won't update the total length. - */ - if (_KEYLEN(state->sav->key_auth) < 56) - padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); - else - padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth); - keybitlen = _KEYLEN(state->sav->key_auth); - keybitlen *= 8; - - buf[0] = 0x80; - MD5Update((MD5_CTX *)state->foo, &buf[0], 1); - padlen--; - - bzero(buf, sizeof(buf)); - while (sizeof(buf) < padlen) { - MD5Update((MD5_CTX *)state->foo, &buf[0], sizeof(buf)); - padlen -= sizeof(buf); - } - if (padlen) { - MD5Update((MD5_CTX *)state->foo, &buf[0], padlen); - } - - buf[0] = (keybitlen >> 0) & 0xff; - buf[1] = (keybitlen >> 8) & 0xff; - buf[2] = (keybitlen >> 16) & 0xff; - buf[3] = (keybitlen >> 24) & 0xff; - MD5Update((MD5_CTX *)state->foo, buf, 8); - } - - return 0; -} - -static void -ah_keyed_md5_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - if (!state) - panic("ah_keyed_md5_loop: what?"); - - MD5Update((MD5_CTX *)state->foo, addr, len); -} - -static void -ah_keyed_md5_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[MD5_RESULTLEN]; - - if (!state) - panic("ah_keyed_md5_result: what?"); - - if (state->sav) { - MD5Update((MD5_CTX *)state->foo, - (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - } - MD5Final(digest, (MD5_CTX *)state->foo); - free(state->foo, M_TEMP); - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); -} - -static int -ah_keyed_sha1_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - SHA1_CTX *ctxt; - size_t padlen; - size_t keybitlen; - u_int8_t buf[32]; - - if (!state) - panic("ah_keyed_sha1_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(sizeof(SHA1_CTX), M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ctxt = (SHA1_CTX *)state->foo; - SHA1Init(ctxt); - - if (state->sav) { - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - - /* - * Pad after the key. - */ - if (_KEYLEN(state->sav->key_auth) < 56) - padlen = 64 - 8 - _KEYLEN(state->sav->key_auth); - else - padlen = 64 + 64 - 8 - _KEYLEN(state->sav->key_auth); - keybitlen = _KEYLEN(state->sav->key_auth); - keybitlen *= 8; - - buf[0] = 0x80; - SHA1Update(ctxt, &buf[0], 1); - padlen--; - - bzero(buf, sizeof(buf)); - while (sizeof(buf) < padlen) { - SHA1Update(ctxt, &buf[0], sizeof(buf)); - padlen -= sizeof(buf); - } - if (padlen) { - SHA1Update(ctxt, &buf[0], padlen); - } - - buf[0] = (keybitlen >> 0) & 0xff; - buf[1] = (keybitlen >> 8) & 0xff; - buf[2] = (keybitlen >> 16) & 0xff; - buf[3] = (keybitlen >> 24) & 0xff; - SHA1Update(ctxt, buf, 8); - } - - return 0; -} - -static void -ah_keyed_sha1_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_keyed_sha1_loop: what?"); - ctxt = (SHA1_CTX *)state->foo; - - SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len); -} - -static void -ah_keyed_sha1_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_keyed_sha1_result: what?"); - ctxt = (SHA1_CTX *)state->foo; - - if (state->sav) { - SHA1Update(ctxt, (u_int8_t *)_KEYBUF(state->sav->key_auth), - (u_int)_KEYLEN(state->sav->key_auth)); - } - SHA1Final((u_int8_t *)digest, ctxt); - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_md5_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - u_char tk[MD5_RESULTLEN]; - u_char *key; - size_t keylen; - size_t i; - MD5_CTX *ctxt; - - if (!state) - panic("ah_hmac_md5_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(MD5_CTX), M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (MD5_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - MD5Init(ctxt); - MD5Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - MD5Final(&tk[0], ctxt); - key = &tk[0]; - keylen = 16; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - MD5Init(ctxt); - MD5Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_md5_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - MD5_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_md5_loop: what?"); - ctxt = (MD5_CTX *)(((u_int8_t *)state->foo) + 128); - MD5Update(ctxt, addr, len); -} - -static void -ah_hmac_md5_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[MD5_RESULTLEN]; - u_char *ipad; - u_char *opad; - MD5_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_md5_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (MD5_CTX *)(opad + 64); - - MD5Final(digest, ctxt); - - MD5Init(ctxt); - MD5Update(ctxt, opad, 64); - MD5Update(ctxt, digest, sizeof(digest)); - MD5Final(digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha1_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA1_CTX *ctxt; - u_char tk[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha1_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA1_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA1_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - SHA1Init(ctxt); - SHA1Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA1Final(&tk[0], ctxt); - key = &tk[0]; - keylen = SHA1_RESULTLEN; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - SHA1Init(ctxt); - SHA1Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha1_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t * addr; - size_t len; -{ - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha1_loop: what?"); - - ctxt = (SHA1_CTX *)(((u_char *)state->foo) + 128); - SHA1Update(ctxt, (u_int8_t *)addr, (size_t)len); -} - -static void -ah_hmac_sha1_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA1_RESULTLEN]; /* SHA-1 generates 160 bits */ - u_char *ipad; - u_char *opad; - SHA1_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha1_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA1_CTX *)(opad + 64); - - SHA1Final((u_int8_t *)digest, ctxt); - - SHA1Init(ctxt); - SHA1Update(ctxt, opad, 64); - SHA1Update(ctxt, (u_int8_t *)digest, sizeof(digest)); - SHA1Final((u_int8_t *)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha2_256_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA256_CTX *ctxt; - u_char tk[SHA256_DIGEST_LENGTH]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha2_256_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA256_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA256_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - SHA256_Init(ctxt); - SHA256_Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA256_Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - SHA256_Init(ctxt); - SHA256_Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha2_256_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - SHA256_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_256_loop: what?"); - - ctxt = (SHA256_CTX *)(((u_char *)state->foo) + 128); - SHA256_Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_sha2_256_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA256_DIGEST_LENGTH]; - u_char *ipad; - u_char *opad; - SHA256_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_256_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA256_CTX *)(opad + 64); - - SHA256_Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - SHA256_Init(ctxt); - SHA256_Update(ctxt, opad, 64); - SHA256_Update(ctxt, (caddr_t)digest, sizeof(digest)); - SHA256_Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha2_384_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA384_CTX *ctxt; - u_char tk[SHA384_DIGEST_LENGTH]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha2_384_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA384_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, 64 + 64 + sizeof(SHA384_CTX)); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA384_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - SHA384_Init(ctxt); - SHA384_Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA384_Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - SHA384_Init(ctxt); - SHA384_Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha2_384_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - SHA384_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_384_loop: what?"); - - ctxt = (SHA384_CTX *)(((u_char *)state->foo) + 128); - SHA384_Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_sha2_384_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA384_DIGEST_LENGTH]; - u_char *ipad; - u_char *opad; - SHA384_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_384_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA384_CTX *)(opad + 64); - - SHA384_Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - SHA384_Init(ctxt); - SHA384_Update(ctxt, opad, 64); - SHA384_Update(ctxt, (caddr_t)digest, sizeof(digest)); - SHA384_Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_sha2_512_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - SHA512_CTX *ctxt; - u_char tk[SHA512_DIGEST_LENGTH]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_sha2_512_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(SHA512_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, 64 + 64 + sizeof(SHA512_CTX)); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA512_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - SHA512_Init(ctxt); - SHA512_Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - SHA512_Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - SHA512_Init(ctxt); - SHA512_Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_sha2_512_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - SHA512_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_512_loop: what?"); - - ctxt = (SHA512_CTX *)(((u_char *)state->foo) + 128); - SHA512_Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_sha2_512_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[SHA512_DIGEST_LENGTH]; - u_char *ipad; - u_char *opad; - SHA512_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_sha2_512_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (SHA512_CTX *)(opad + 64); - - SHA512_Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - SHA512_Init(ctxt); - SHA512_Update(ctxt, opad, 64); - SHA512_Update(ctxt, (caddr_t)digest, sizeof(digest)); - SHA512_Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -static int -ah_hmac_ripemd160_init(state, sav) - struct ah_algorithm_state *state; - struct secasvar *sav; -{ - u_char *ipad; - u_char *opad; - RMD160_CTX *ctxt; - u_char tk[RIPEMD160_RESULTLEN]; - u_char *key; - size_t keylen; - size_t i; - - if (!state) - panic("ah_hmac_ripemd160_init: what?"); - - state->sav = sav; - state->foo = (void *)malloc(64 + 64 + sizeof(RMD160_CTX), - M_TEMP, M_NOWAIT); - if (!state->foo) - return ENOBUFS; - bzero(state->foo, 64 + 64 + sizeof(RMD160_CTX)); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (RMD160_CTX *)(opad + 64); - - /* compress the key if necessery */ - if (64 < _KEYLEN(state->sav->key_auth)) { - bzero(tk, sizeof(tk)); - bzero(ctxt, sizeof(*ctxt)); - RMD160Init(ctxt); - RMD160Update(ctxt, _KEYBUF(state->sav->key_auth), - _KEYLEN(state->sav->key_auth)); - RMD160Final(&tk[0], ctxt); - key = &tk[0]; - keylen = sizeof(tk) < 64 ? sizeof(tk) : 64; - } else { - key = _KEYBUF(state->sav->key_auth); - keylen = _KEYLEN(state->sav->key_auth); - } - - bzero(ipad, 64); - bzero(opad, 64); - bcopy(key, ipad, keylen); - bcopy(key, opad, keylen); - for (i = 0; i < 64; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - bzero(ctxt, sizeof(*ctxt)); - RMD160Init(ctxt); - RMD160Update(ctxt, ipad, 64); - - return 0; -} - -static void -ah_hmac_ripemd160_loop(state, addr, len) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t len; -{ - RMD160_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_ripemd160_loop: what?"); - - ctxt = (RMD160_CTX *)(((u_char *)state->foo) + 128); - RMD160Update(ctxt, (caddr_t)addr, (size_t)len); -} - -static void -ah_hmac_ripemd160_result(state, addr, l) - struct ah_algorithm_state *state; - u_int8_t *addr; - size_t l; -{ - u_char digest[RIPEMD160_RESULTLEN]; - u_char *ipad; - u_char *opad; - RMD160_CTX *ctxt; - - if (!state || !state->foo) - panic("ah_hmac_ripemd160_result: what?"); - - ipad = (u_char *)state->foo; - opad = (u_char *)(ipad + 64); - ctxt = (RMD160_CTX *)(opad + 64); - - RMD160Final((caddr_t)digest, ctxt); - - bzero(ctxt, sizeof(*ctxt)); - RMD160Init(ctxt); - RMD160Update(ctxt, opad, 64); - RMD160Update(ctxt, (caddr_t)digest, sizeof(digest)); - RMD160Final((caddr_t)digest, ctxt); - - bcopy(digest, addr, sizeof(digest) > l ? l : sizeof(digest)); - - free(state->foo, M_TEMP); -} - -/*------------------------------------------------------------*/ - -/* - * go generate the checksum. - */ -static void -ah_update_mbuf(m, off, len, algo, algos) - struct mbuf *m; - int off; - int len; - const struct ah_algorithm *algo; - struct ah_algorithm_state *algos; -{ - struct mbuf *n; - int tlen; - - /* easy case first */ - if (off + len <= m->m_len) { - (algo->update)(algos, mtod(m, u_int8_t *) + off, len); - return; - } - - for (n = m; n; n = n->m_next) { - if (off < n->m_len) - break; - - off -= n->m_len; - } - - if (!n) - panic("ah_update_mbuf: wrong offset specified"); - - for (/* nothing */; n && len > 0; n = n->m_next) { - if (n->m_len == 0) - continue; - if (n->m_len - off < len) - tlen = n->m_len - off; - else - tlen = len; - - (algo->update)(algos, mtod(n, u_int8_t *) + off, tlen); - - len -= tlen; - off = 0; - } -} - -#ifdef INET -/* - * Go generate the checksum. This function won't modify the mbuf chain - * except AH itself. - * - * NOTE: the function does not free mbuf on failure. - * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. - */ -int -ah4_calccksum(m, ahdat, len, algo, sav) - struct mbuf *m; - u_int8_t * ahdat; - size_t len; - const struct ah_algorithm *algo; - struct secasvar *sav; -{ - int off; - int hdrtype; - size_t advancewidth; - struct ah_algorithm_state algos; - u_char sumbuf[AH_MAXSUMSIZE]; - int error = 0; - int ahseen; - struct mbuf *n = NULL; - - if ((m->m_flags & M_PKTHDR) == 0) - return EINVAL; - - ahseen = 0; - hdrtype = -1; /* dummy, it is called IPPROTO_IP */ - - off = 0; - - error = (algo->init)(&algos, sav); - if (error) - return error; - - advancewidth = 0; /* safety */ - -again: - /* gory. */ - switch (hdrtype) { - case -1: /* first one only */ - { - /* - * copy ip hdr, modify to fit the AH checksum rule, - * then take a checksum. - */ - struct ip iphdr; - size_t hlen; - - m_copydata(m, off, sizeof(iphdr), (caddr_t)&iphdr); -#ifdef _IP_VHL - hlen = IP_VHL_HL(iphdr.ip_vhl) << 2; -#else - hlen = iphdr.ip_hl << 2; -#endif - iphdr.ip_ttl = 0; - iphdr.ip_sum = htons(0); - if (ip4_ah_cleartos) - iphdr.ip_tos = 0; - iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask); - (algo->update)(&algos, (u_int8_t *)&iphdr, sizeof(struct ip)); - - if (hlen != sizeof(struct ip)) { - u_char *p; - int i, l, skip; - - if (hlen > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && hlen > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, hlen, mtod(n, caddr_t)); - - /* - * IP options processing. - * See RFC2402 appendix A. - */ - p = mtod(n, u_char *); - i = sizeof(struct ip); - while (i < hlen) { - if (i + IPOPT_OPTVAL >= hlen) { - ipseclog((LOG_ERR, "ah4_calccksum: " - "invalid IP option\n")); - error = EINVAL; - goto fail; - } - if (p[i + IPOPT_OPTVAL] == IPOPT_EOL || - p[i + IPOPT_OPTVAL] == IPOPT_NOP || - i + IPOPT_OLEN < hlen) - ; - else { - ipseclog((LOG_ERR, - "ah4_calccksum: invalid IP option " - "(type=%02x)\n", - p[i + IPOPT_OPTVAL])); - error = EINVAL; - goto fail; - } - - skip = 1; - switch (p[i + IPOPT_OPTVAL]) { - case IPOPT_EOL: - case IPOPT_NOP: - l = 1; - skip = 0; - break; - case IPOPT_SECURITY: /* 0x82 */ - case 0x85: /* Extended security */ - case 0x86: /* Commercial security */ - case 0x94: /* Router alert */ - case 0x95: /* RFC1770 */ - l = p[i + IPOPT_OLEN]; - if (l < 2) - goto invalopt; - skip = 0; - break; - default: - l = p[i + IPOPT_OLEN]; - if (l < 2) - goto invalopt; - skip = 1; - break; - } - if (l < 1 || hlen - i < l) { - invalopt: - ipseclog((LOG_ERR, - "ah4_calccksum: invalid IP option " - "(type=%02x len=%02x)\n", - p[i + IPOPT_OPTVAL], - p[i + IPOPT_OLEN])); - error = EINVAL; - goto fail; - } - if (skip) - bzero(p + i, l); - if (p[i + IPOPT_OPTVAL] == IPOPT_EOL) - break; - i += l; - } - p = mtod(n, u_char *) + sizeof(struct ip); - (algo->update)(&algos, p, hlen - sizeof(struct ip)); - - m_free(n); - n = NULL; - } - - hdrtype = (iphdr.ip_p) & 0xff; - advancewidth = hlen; - break; - } - - case IPPROTO_AH: - { - struct ah ah; - int siz; - int hdrsiz; - int totlen; - - m_copydata(m, off, sizeof(ah), (caddr_t)&ah); - hdrsiz = (sav->flags & SADB_X_EXT_OLD) - ? sizeof(struct ah) - : sizeof(struct newah); - siz = (*algo->sumsiz)(sav); - totlen = (ah.ah_len + 2) << 2; - - /* - * special treatment is necessary for the first one, not others - */ - if (!ahseen) { - if (totlen > m->m_pkthdr.len - off || - totlen > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && totlen > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, totlen, mtod(n, caddr_t)); - n->m_len = totlen; - bzero(mtod(n, u_int8_t *) + hdrsiz, siz); - (algo->update)(&algos, mtod(n, u_int8_t *), n->m_len); - m_free(n); - n = NULL; - } else - ah_update_mbuf(m, off, totlen, algo, &algos); - ahseen++; - - hdrtype = ah.ah_nxt; - advancewidth = totlen; - break; - } - - default: - ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, &algos); - advancewidth = m->m_pkthdr.len - off; - break; - } - - off += advancewidth; - if (off < m->m_pkthdr.len) - goto again; - - if (len < (*algo->sumsiz)(sav)) { - error = EINVAL; - goto fail; - } - - (algo->result)(&algos, sumbuf, sizeof(sumbuf)); - bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); - - if (n) - m_free(n); - return error; - -fail: - if (n) - m_free(n); - return error; -} -#endif - -#ifdef INET6 -/* - * Go generate the checksum. This function won't modify the mbuf chain - * except AH itself. - * - * NOTE: the function does not free mbuf on failure. - * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. - */ -int -ah6_calccksum(m, ahdat, len, algo, sav) - struct mbuf *m; - u_int8_t * ahdat; - size_t len; - const struct ah_algorithm *algo; - struct secasvar *sav; -{ - int newoff, off; - int proto, nxt; - struct mbuf *n = NULL; - int error; - int ahseen; - struct ah_algorithm_state algos; - u_char sumbuf[AH_MAXSUMSIZE]; - - if ((m->m_flags & M_PKTHDR) == 0) - return EINVAL; - - error = (algo->init)(&algos, sav); - if (error) - return error; - - off = 0; - proto = IPPROTO_IPV6; - nxt = -1; - ahseen = 0; - - again: - newoff = ip6_nexthdr(m, off, proto, &nxt); - if (newoff < 0) - newoff = m->m_pkthdr.len; - else if (newoff <= off) { - error = EINVAL; - goto fail; - } - - switch (proto) { - case IPPROTO_IPV6: - /* - * special treatment is necessary for the first one, not others - */ - if (off == 0) { - struct ip6_hdr ip6copy; - - if (newoff - off != sizeof(struct ip6_hdr)) { - error = EINVAL; - goto fail; - } - - m_copydata(m, off, newoff - off, (caddr_t)&ip6copy); - /* RFC2402 */ - ip6copy.ip6_flow = 0; - ip6copy.ip6_vfc &= ~IPV6_VERSION_MASK; - ip6copy.ip6_vfc |= IPV6_VERSION; - ip6copy.ip6_hlim = 0; - in6_clearscope(&ip6copy.ip6_src); /* XXX */ - in6_clearscope(&ip6copy.ip6_dst); /* XXX */ - (algo->update)(&algos, (u_int8_t *)&ip6copy, - sizeof(struct ip6_hdr)); - } else { - newoff = m->m_pkthdr.len; - ah_update_mbuf(m, off, m->m_pkthdr.len - off, algo, - &algos); - } - break; - - case IPPROTO_AH: - { - int siz; - int hdrsiz; - - hdrsiz = (sav->flags & SADB_X_EXT_OLD) - ? sizeof(struct ah) - : sizeof(struct newah); - siz = (*algo->sumsiz)(sav); - - /* - * special treatment is necessary for the first one, not others - */ - if (!ahseen) { - if (newoff - off > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && newoff - off > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, newoff - off, mtod(n, caddr_t)); - n->m_len = newoff - off; - bzero(mtod(n, u_int8_t *) + hdrsiz, siz); - (algo->update)(&algos, mtod(n, u_int8_t *), n->m_len); - m_free(n); - n = NULL; - } else - ah_update_mbuf(m, off, newoff - off, algo, &algos); - ahseen++; - break; - } - - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - { - struct ip6_ext *ip6e; - int hdrlen, optlen; - u_int8_t *p, *optend, *optp; - - if (newoff - off > MCLBYTES) { - error = EMSGSIZE; - goto fail; - } - MGET(n, M_DONTWAIT, MT_DATA); - if (n && newoff - off > MLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (n == NULL) { - error = ENOBUFS; - goto fail; - } - m_copydata(m, off, newoff - off, mtod(n, caddr_t)); - n->m_len = newoff - off; - - ip6e = mtod(n, struct ip6_ext *); - hdrlen = (ip6e->ip6e_len + 1) << 3; - if (newoff - off < hdrlen) { - error = EINVAL; - m_free(n); - n = NULL; - goto fail; - } - p = mtod(n, u_int8_t *); - optend = p + hdrlen; - - /* - * ICV calculation for the options header including all - * options. This part is a little tricky since there are - * two type of options; mutable and immutable. We try to - * null-out mutable ones here. - */ - optp = p + 2; - while (optp < optend) { - if (optp[0] == IP6OPT_PAD1) - optlen = 1; - else { - if (optp + 2 > optend) { - error = EINVAL; - m_free(n); - n = NULL; - goto fail; - } - optlen = optp[1] + 2; - } - - if (optp + optlen > optend) { - error = EINVAL; - m_free(n); - n = NULL; - goto fail; - } - - if (optp[0] & IP6OPT_MUTABLE) - bzero(optp + 2, optlen - 2); - - optp += optlen; - } - - (algo->update)(&algos, mtod(n, u_int8_t *), n->m_len); - m_free(n); - n = NULL; - break; - } - - case IPPROTO_ROUTING: - /* - * For an input packet, we can just calculate `as is'. - * For an output packet, we assume ip6_output have already - * made packet how it will be received at the final - * destination. - */ - /* FALLTHROUGH */ - - default: - ah_update_mbuf(m, off, newoff - off, algo, &algos); - break; - } - - if (newoff < m->m_pkthdr.len) { - proto = nxt; - off = newoff; - goto again; - } - - if (len < (*algo->sumsiz)(sav)) { - error = EINVAL; - goto fail; - } - - (algo->result)(&algos, sumbuf, sizeof(sumbuf)); - bcopy(&sumbuf[0], ahdat, (*algo->sumsiz)(sav)); - - /* just in case */ - if (n) - m_free(n); - return 0; -fail: - /* just in case */ - if (n) - m_free(n); - return error; -} -#endif diff --git a/sys/netinet6/ah_input.c b/sys/netinet6/ah_input.c deleted file mode 100644 index 4a65659..0000000 --- a/sys/netinet6/ah_input.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 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. - */ - -/* - * RFC1826/2402 authentication header. - */ - -#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 <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 <netinet6/ip6_ecn.h> -#endif - -#ifdef INET6 -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet/in_pcb.h> -#include <netinet6/in6_pcb.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 <netkey/key.h> -#include <netkey/keydb.h> -#ifdef IPSEC_DEBUG -#include <netkey/key_debug.h> -#else -#define KEYDEBUG(lev,arg) -#endif - -#include <machine/stdarg.h> - -#define IPLEN_FLIPPED - -#ifdef INET -extern struct protosw inetsw[]; - -void -ah4_input(m, off) - struct mbuf *m; - int off; -{ - struct ip *ip; - struct ah *ah; - u_int32_t spi; - const struct ah_algorithm *algo; - size_t siz; - size_t siz1; - u_int8_t cksum[AH_MAXSUMSIZE]; - struct secasvar *sav = NULL; - u_int16_t nxt; - size_t hlen; - size_t stripsiz = 0; - -#ifndef PULLDOWN_TEST - if (m->m_len < off + sizeof(struct newah)) { - m = m_pullup(m, off + sizeof(struct newah)); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_inval++; - goto fail; - } - } - - ip = mtod(m, struct ip *); - ah = (struct ah *)(((caddr_t)ip) + off); -#else - ip = mtod(m, struct ip *); - IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); - if (ah == NULL) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_inval++; - goto fail; - } -#endif - nxt = ah->ah_nxt; -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - - /* find the sassoc. */ - spi = ah->ah_spi; - - if ((sav = key_allocsa(AF_INET, - (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, - IPPROTO_AH, spi)) == 0) { - ipseclog((LOG_WARNING, - "IPv4 AH input: no key association found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_nosa++; - goto fail; - } - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input called to allocate SA:%p\n", sav)); - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) { - ipseclog((LOG_DEBUG, - "IPv4 AH input: non-mature/dying SA found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; - goto fail; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_DEBUG, "IPv4 AH input: " - "unsupported authentication algorithm for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; - goto fail; - } - - siz = (*algo->sumsiz)(sav); - siz1 = ((siz + 3) & ~(4 - 1)); - - /* - * sanity checks for header, 1. - */ - { - int sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - /* - * Here, we do not do "siz1 == siz". This is because the way - * RFC240[34] section 2 is written. They do not require truncation - * to 96 bits. - * For example, Microsoft IPsec stack attaches 160 bits of - * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1, - * 32 bits of padding is attached. - * - * There are two downsides to this specification. - * They have no real harm, however, they leave us fuzzy feeling. - * - if we attach more than 96 bits of authentication data onto AH, - * we will never notice about possible modification by rogue - * intermediate nodes. - * Since extra bits in AH checksum is never used, this constitutes - * no real issue, however, it is wacky. - * - even if the peer attaches big authentication data, we will never - * notice the difference, since longer authentication data will just - * work. - * - * We may need some clarification in the spec. - */ - if (siz1 < siz) { - ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input " - "(%lu, should be at least %lu): %s\n", - (u_long)siz1, (u_long)siz, - ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; - goto fail; - } - if ((ah->ah_len << 2) - sizoff != siz1) { - ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input " - "(%d should be %lu): %s\n", - (ah->ah_len << 2) - sizoff, (u_long)siz1, - ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; - goto fail; - } - if (siz1 > sizeof(cksum)) { - ipseclog((LOG_NOTICE, "sum length too large: %s\n", - ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; - goto fail; - } - -#ifndef PULLDOWN_TEST - if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) { - m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; - goto fail; - } - - ip = mtod(m, struct ip *); - ah = (struct ah *)(((caddr_t)ip) + off); - } -#else - IP6_EXTHDR_GET(ah, struct ah *, m, off, - sizeof(struct ah) + sizoff + siz1); - if (ah == NULL) { - ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; - goto fail; - } -#endif - } - - /* - * check for sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) - ; /* okey */ - else { - ipsecstat.in_ahreplay++; - ipseclog((LOG_WARNING, - "replay packet in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - goto fail; - } - } - - /* - * alright, it seems sane. now we are going to check the - * cryptographic checksum. - */ - - /* - * some of IP header fields are flipped to the host endian. - * convert them back to network endian. VERY stupid. - */ - ip->ip_len = htons(ip->ip_len + hlen); - ip->ip_off = htons(ip->ip_off); - if (ah4_calccksum(m, cksum, siz1, algo, sav)) { - ipsecstat.in_inval++; - goto fail; - } - ipsecstat.in_ahhist[sav->alg_auth]++; - /* - * flip them back. - */ - ip->ip_len = ntohs(ip->ip_len) - hlen; - ip->ip_off = ntohs(ip->ip_off); - - { - caddr_t sumpos = NULL; - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - sumpos = (caddr_t)(ah + 1); - } else { - /* RFC 2402 */ - sumpos = (caddr_t)(((struct newah *)ah) + 1); - } - - if (bcmp(sumpos, cksum, siz) != 0) { - ipseclog((LOG_WARNING, - "checksum mismatch in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_ahauthfail++; - goto fail; - } - } - - m->m_flags |= M_AUTHIPHDR; - m->m_flags |= M_AUTHIPDGM; - -#if 0 - /* - * looks okey, but we need more sanity check. - * XXX should elaborate. - */ - if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) { - struct ip *nip; - size_t sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) { - m = m_pullup(m, off + sizeof(struct ah) - + sizoff + siz1 + hlen); - if (!m) { - ipseclog((LOG_DEBUG, - "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; - goto fail; - } - } - - nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1); - if (nip->ip_src.s_addr != ip->ip_src.s_addr - || nip->ip_dst.s_addr != ip->ip_dst.s_addr) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } - } -#ifdef INET6 - else if (ah->ah_nxt == IPPROTO_IPV6) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } -#endif /* INET6 */ -#endif /* 0 */ - - if (m->m_flags & M_AUTHIPHDR - && m->m_flags & M_AUTHIPDGM) { -#if 0 - ipseclog((LOG_DEBUG, - "IPv4 AH input: authentication succeess\n")); -#endif - ipsecstat.in_ahauthsucc++; - } else { - ipseclog((LOG_WARNING, - "authentication failed in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_ahauthfail++; - goto fail; - } - - /* - * update sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { - ipsecstat.in_ahreplay++; - goto fail; - } - } - - /* was it transmitted over the IPsec tunnel SA? */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } - if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) { - /* - * strip off all the headers that precedes AH. - * IP xx AH IP' payload -> IP' payload - * - * XXX more sanity checks - * XXX relationship with gif? - */ - u_int8_t tos; - - tos = ip->ip_tos; - m_adj(m, off + stripsiz); - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (!m) { - ipsecstat.in_inval++; - goto fail; - } - } - ip = mtod(m, struct ip *); - /* ECN consideration. */ - if (!ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos)) { - ipsecstat.in_inval++; - goto fail; - } - if (!key_checktunnelsanity(sav, AF_INET, - (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { - ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " - "in IPv4 AH input: %s %s\n", - ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; - goto fail; - } - -#if 1 - /* - * Should the inner packet be considered authentic? - * My current answer is: NO. - * - * host1 -- gw1 === gw2 -- host2 - * In this case, gw2 can trust the authenticity of the - * outer packet, but NOT inner. Packet may be altered - * between host1 and gw1. - * - * host1 -- gw1 === host2 - * This case falls into the same scenario as above. - * - * host1 === host2 - * This case is the only case when we may be able to leave - * M_AUTHIPHDR and M_AUTHIPDGM set. - * However, if host1 is wrongly configured, and allows - * attacker to inject some packet with src=host1 and - * dst=host2, you are in risk. - */ - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; -#endif - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || - ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { - ipsecstat.in_nomem++; - goto fail; - } - - if (netisr_queue(NETISR_IP, m)) { /* (0) on success. */ - ipsecstat.in_inval++; - m = NULL; - goto fail; - } - m = NULL; - nxt = IPPROTO_DONE; - } else { - /* - * strip off AH. - */ - - ip = mtod(m, struct ip *); -#ifndef PULLDOWN_TEST - /* - * We do deep-copy since KAME requires that - * the packet is placed in a single external mbuf. - */ - ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; -#else - /* - * even in m_pulldown case, we need to strip off AH so that - * we can compute checksum for multiple AH correctly. - */ - if (m->m_len >= stripsiz + off) { - ovbcopy((caddr_t)ip, ((caddr_t)ip) + 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 fail; - } - m_adj(n, stripsiz); - /* m_cat does not update m_pkthdr.len */ - m->m_pkthdr.len += n->m_pkthdr.len; - m_cat(m, n); - } -#endif - - if (m->m_len < sizeof(*ip)) { - m = m_pullup(m, sizeof(*ip)); - if (m == NULL) { - ipsecstat.in_inval++; - goto fail; - } - } - 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; - /* forget about IP hdr checksum, the check has already been passed */ - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { - ipsecstat.in_nomem++; - goto fail; - } - - 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; - } - - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input call free SA:%p\n", sav)); - key_freesav(sav); - } - ipsecstat.in_success++; - return; - -fail: - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah4_input call free SA:%p\n", sav)); - key_freesav(sav); - } - if (m) - m_freem(m); - return; -} -#endif /* INET */ - -#ifdef INET6 -int -ah6_input(mp, offp, proto) - struct mbuf **mp; - int *offp, proto; -{ - struct mbuf *m = *mp; - int off = *offp; - struct ip6_hdr *ip6; - struct ah *ah; - u_int32_t spi; - const struct ah_algorithm *algo; - size_t siz; - size_t siz1; - u_int8_t cksum[AH_MAXSUMSIZE]; - struct secasvar *sav = NULL; - u_int16_t nxt; - size_t stripsiz = 0; - -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); - ah = (struct ah *)(mtod(m, caddr_t) + off); -#else - IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); - if (ah == NULL) { - ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); - ipsec6stat.in_inval++; - return IPPROTO_DONE; - } -#endif - ip6 = mtod(m, struct ip6_hdr *); - nxt = ah->ah_nxt; - - /* find the sassoc. */ - spi = ah->ah_spi; - - if (ntohs(ip6->ip6_plen) == 0) { - ipseclog((LOG_ERR, "IPv6 AH input: " - "AH with IPv6 jumbogram is not supported.\n")); - ipsec6stat.in_inval++; - goto fail; - } - - if ((sav = key_allocsa(AF_INET6, - (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, - IPPROTO_AH, spi)) == 0) { - ipseclog((LOG_WARNING, - "IPv6 AH input: no key association found for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_nosa++; - goto fail; - } - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input called to allocate SA:%p\n", sav)); - if (sav->state != SADB_SASTATE_MATURE - && sav->state != SADB_SASTATE_DYING) { - ipseclog((LOG_DEBUG, - "IPv6 AH input: non-mature/dying SA found for spi %u; ", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; - goto fail; - } - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_DEBUG, "IPv6 AH input: " - "unsupported authentication algorithm for spi %u\n", - (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; - goto fail; - } - - siz = (*algo->sumsiz)(sav); - siz1 = ((siz + 3) & ~(4 - 1)); - - /* - * sanity checks for header, 1. - */ - { - int sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - /* - * Here, we do not do "siz1 == siz". See ah4_input() for complete - * description. - */ - if (siz1 < siz) { - ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input " - "(%lu, should be at least %lu): %s\n", - (u_long)siz1, (u_long)siz, - ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; - goto fail; - } - if ((ah->ah_len << 2) - sizoff != siz1) { - ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input " - "(%d should be %lu): %s\n", - (ah->ah_len << 2) - sizoff, (u_long)siz1, - ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; - goto fail; - } - if (siz1 > sizeof(cksum)) { - ipseclog((LOG_NOTICE, "sum length too large: %s\n", - ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; - goto fail; - } - -#ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE); -#else - IP6_EXTHDR_GET(ah, struct ah *, m, off, - sizeof(struct ah) + sizoff + siz1); - if (ah == NULL) { - ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); - ipsec6stat.in_inval++; - m = NULL; - goto fail; - } -#endif - } - - /* - * check for sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) - ; /* okey */ - else { - ipsec6stat.in_ahreplay++; - ipseclog((LOG_WARNING, - "replay packet in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav))); - goto fail; - } - } - - /* - * alright, it seems sane. now we are going to check the - * cryptographic checksum. - */ - - if (ah6_calccksum(m, cksum, siz1, algo, sav)) { - ipsec6stat.in_inval++; - goto fail; - } - ipsec6stat.in_ahhist[sav->alg_auth]++; - - { - caddr_t sumpos = NULL; - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - sumpos = (caddr_t)(ah + 1); - } else { - /* RFC 2402 */ - sumpos = (caddr_t)(((struct newah *)ah) + 1); - } - - if (bcmp(sumpos, cksum, siz) != 0) { - ipseclog((LOG_WARNING, - "checksum mismatch in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_ahauthfail++; - goto fail; - } - } - - m->m_flags |= M_AUTHIPHDR; - m->m_flags |= M_AUTHIPDGM; - -#if 0 - /* - * looks okey, but we need more sanity check. - * XXX should elaborate. - */ - if (ah->ah_nxt == IPPROTO_IPV6) { - struct ip6_hdr *nip6; - size_t sizoff; - - sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4; - - IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1 - + sizeof(struct ip6_hdr), IPPROTO_DONE); - - nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1); - if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src) - || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } - } else if (ah->ah_nxt == IPPROTO_IPIP) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } else if (ah->ah_nxt == IPPROTO_IP) { - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; - } -#endif - - if (m->m_flags & M_AUTHIPHDR - && m->m_flags & M_AUTHIPDGM) { -#if 0 - ipseclog((LOG_DEBUG, - "IPv6 AH input: authentication succeess\n")); -#endif - ipsec6stat.in_ahauthsucc++; - } else { - ipseclog((LOG_WARNING, - "authentication failed in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_ahauthfail++; - goto fail; - } - - /* - * update sequence number. - */ - if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { - if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { - ipsec6stat.in_ahreplay++; - goto fail; - } - } - - /* was it transmitted over the IPsec tunnel SA? */ - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1826 */ - stripsiz = sizeof(struct ah) + siz1; - } else { - /* RFC 2402 */ - stripsiz = sizeof(struct newah) + siz1; - } - if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) { - /* - * strip off all the headers that precedes AH. - * IP6 xx AH 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 + stripsiz); - if (m->m_len < sizeof(*ip6)) { - m = m_pullup(m, sizeof(*ip6)); - if (!m) { - ipsec6stat.in_inval++; - goto fail; - } - } - ip6 = mtod(m, struct ip6_hdr *); - /* ECN consideration. */ - if (!ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow)) { - ipsec6stat.in_inval++; - goto fail; - } - if (!key_checktunnelsanity(sav, AF_INET6, - (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { - ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " - "in IPv6 AH input: %s %s\n", - ipsec6_logpacketstr(ip6, spi), - ipsec_logsastr(sav))); - ipsec6stat.in_inval++; - goto fail; - } - -#if 1 - /* - * should the inner packet be considered authentic? - * see comment in ah4_input(). - */ - m->m_flags &= ~M_AUTHIPHDR; - m->m_flags &= ~M_AUTHIPDGM; -#endif - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || - ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { - ipsec6stat.in_nomem++; - goto fail; - } - - if (netisr_queue(NETISR_IPV6, m)) { /* (0) on success. */ - ipsec6stat.in_inval++; - m = NULL; - goto fail; - } - m = NULL; - nxt = IPPROTO_DONE; - } else { - /* - * strip off AH. - */ - u_int8_t *prvnxtp; - - /* - * Copy the value of the next header field of AH to the - * next header field of the previous header. - * This is necessary because AH will be stripped off below. - */ - prvnxtp = ip6_get_prevhdr(m, off); /* XXX */ - *prvnxtp = nxt; - - ip6 = mtod(m, struct ip6_hdr *); -#ifndef PULLDOWN_TEST - /* - * We do deep-copy since KAME requires that - * the packet is placed in a single mbuf. - */ - ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off); - m->m_data += stripsiz; - m->m_len -= stripsiz; - m->m_pkthdr.len -= stripsiz; -#else - /* - * even in m_pulldown case, we need to strip off AH so that - * we can compute checksum for multiple AH correctly. - */ - 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 fail; - } - m_adj(n, stripsiz); - /* m_cat does not update m_pkthdr.len */ - m->m_pkthdr.len += n->m_pkthdr.len; - m_cat(m, n); - } -#endif - ip6 = mtod(m, struct ip6_hdr *); - /* XXX jumbogram */ - ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz); - - key_sa_recordxfer(sav, m); - if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { - ipsec6stat.in_nomem++; - goto fail; - } - } - - *offp = off; - *mp = m; - - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input call free SA:%p\n", sav)); - key_freesav(sav); - } - ipsec6stat.in_success++; - return nxt; - -fail: - if (sav) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ah6_input call free SA:%p\n", sav)); - key_freesav(sav); - } - if (m) - m_freem(m); - return IPPROTO_DONE; -} - -void -ah6_ctlinput(cmd, sa, d) - int cmd; - struct sockaddr *sa; - void *d; -{ - const struct newah *ahp; - struct newah ah; - struct secasvar *sav; - struct ip6_hdr *ip6; - struct mbuf *m; - struct ip6ctlparam *ip6cp = NULL; - 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) { - /* - * 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(ah)) - return; - - if (m->m_len < off + sizeof(ah)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(ah), (caddr_t)&ah); - ahp = &ah; - } else - ahp = (struct newah *)(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_AH, ahp->ah_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); - } - - /* we normally notify single pcb here */ - } else { - /* we normally notify any pcb here */ - } -} -#endif /* INET6 */ diff --git a/sys/netinet6/ah_output.c b/sys/netinet6/ah_output.c deleted file mode 100644 index c58ca0e..0000000 --- a/sys/netinet6/ah_output.c +++ /dev/null @@ -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 diff --git a/sys/netinet6/esp_aesctr.c b/sys/netinet6/esp_aesctr.c deleted file mode 100644 index a8655bd..0000000 --- a/sys/netinet6/esp_aesctr.c +++ /dev/null @@ -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; -} diff --git a/sys/netinet6/esp_camellia.c b/sys/netinet6/esp_camellia.c deleted file mode 100644 index b608518..0000000 --- a/sys/netinet6/esp_camellia.c +++ /dev/null @@ -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; -} diff --git a/sys/netinet6/esp_core.c b/sys/netinet6/esp_core.c deleted file mode 100644 index 7f45236..0000000 --- a/sys/netinet6/esp_core.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 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 "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 <netinet/in.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 <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#include <netinet6/esp_rijndael.h> -#include <netinet6/esp_camellia.h> -#include <netinet6/esp_aesctr.h> -#include <net/pfkeyv2.h> -#include <netkey/keydb.h> -#include <netkey/key.h> - -#include <crypto/des/des.h> -#include <crypto/blowfish/blowfish.h> - -#include <opencrypto/cast.h> -#define cast128_key cast_key -#define cast128_setkey(key, rawkey, keybytes) \ - cast_setkey((key), (rawkey), (keybytes)) -#define cast128_encrypt(key, inblock, outblock) \ - cast_encrypt((key), (inblock), (outblock)) -#define cast128_decrypt(key, inblock, outblock) \ - cast_decrypt((key), (inblock), (outblock)) - -static int esp_null_mature __P((struct secasvar *)); -static int esp_null_decrypt __P((struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_null_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_descbc_mature __P((struct secasvar *)); -static int esp_descbc_ivlen __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_des_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_des_schedlen __P((const struct esp_algorithm *)); -static int esp_des_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_des_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cbc_mature __P((struct secasvar *)); -static int esp_blowfish_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_blowfish_schedlen __P((const struct esp_algorithm *)); -static int esp_blowfish_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_blowfish_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cast128_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_cast128_schedlen __P((const struct esp_algorithm *)); -static int esp_cast128_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_cast128_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_3des_schedule __P((const struct esp_algorithm *, - struct secasvar *)); -static size_t esp_3des_schedlen __P((const struct esp_algorithm *)); -static int esp_3des_blockdecrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_3des_blockencrypt __P((const struct esp_algorithm *, - struct secasvar *, u_int8_t *, u_int8_t *)); -static int esp_common_ivlen __P((const struct esp_algorithm *, - struct secasvar *)); -static int esp_cbc_decrypt __P((struct mbuf *, size_t, - struct secasvar *, const struct esp_algorithm *, int)); -static int esp_cbc_encrypt __P((struct mbuf *, size_t, size_t, - struct secasvar *, const struct esp_algorithm *, int)); - -#define MAXIVLEN 16 - -static const struct esp_algorithm esp_algorithms[] = { - { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen, - "des-cbc", - esp_descbc_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_des_schedule, - esp_des_blockdecrypt, esp_des_blockencrypt, }, - { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen, - "3des-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_3des_schedule, - esp_3des_blockdecrypt, esp_3des_blockencrypt, }, - { 1, 0, esp_null_mature, 0, 2048, NULL, "null", - esp_common_ivlen, esp_null_decrypt, - esp_null_encrypt, NULL, }, - { 8, 8, esp_cbc_mature, 40, 448, esp_blowfish_schedlen, "blowfish-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_blowfish_schedule, - esp_blowfish_blockdecrypt, esp_blowfish_blockencrypt, }, - { 8, 8, esp_cbc_mature, 40, 128, esp_cast128_schedlen, - "cast128-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_cast128_schedule, - esp_cast128_blockdecrypt, esp_cast128_blockencrypt, }, - { 16, 16, esp_cbc_mature, 128, 256, esp_rijndael_schedlen, - "rijndael-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_rijndael_schedule, - esp_rijndael_blockdecrypt, esp_rijndael_blockencrypt }, - { 16, 8, esp_aesctr_mature, 160, 288, esp_aesctr_schedlen, "aes-ctr", - esp_common_ivlen, esp_aesctr_decrypt, - esp_aesctr_encrypt, esp_aesctr_schedule }, - { 16, 16, esp_cbc_mature, 128, 256, esp_camellia_schedlen, - "camellia-cbc", - esp_common_ivlen, esp_cbc_decrypt, - esp_cbc_encrypt, esp_camellia_schedule, - esp_camellia_blockdecrypt, esp_camellia_blockencrypt }, -}; - -const struct esp_algorithm * -esp_algorithm_lookup(idx) - int idx; -{ - - switch (idx) { - case SADB_EALG_DESCBC: - return &esp_algorithms[0]; - case SADB_EALG_3DESCBC: - return &esp_algorithms[1]; - case SADB_EALG_NULL: - return &esp_algorithms[2]; - case SADB_X_EALG_BLOWFISHCBC: - return &esp_algorithms[3]; - case SADB_X_EALG_CAST128CBC: - return &esp_algorithms[4]; - case SADB_X_EALG_RIJNDAELCBC: - return &esp_algorithms[5]; - case SADB_X_EALG_AESCTR: - return &esp_algorithms[6]; - case SADB_X_EALG_CAMELLIACBC: - return &esp_algorithms[7]; - default: - return NULL; - } -} - -int -esp_max_ivlen() -{ - int idx; - int ivlen; - - ivlen = 0; - for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]); - idx++) { - if (esp_algorithms[idx].ivlenval > ivlen) - ivlen = esp_algorithms[idx].ivlenval; - } - return ivlen; -} - -int -esp_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - int error; - - /* check for key length */ - if (_KEYBITS(sav->key_enc) < algo->keymin || - _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_schedule %s: unsupported key length %d: " - "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc), - algo->keymin, algo->keymax)); - return EINVAL; - } - - /* already allocated */ - if (sav->sched && sav->schedlen != 0) - return 0; - /* no schedule necessary */ - if (!algo->schedule || !algo->schedlen) - return 0; - - sav->schedlen = (*algo->schedlen)(algo); - sav->sched = malloc(sav->schedlen, M_SECA, M_NOWAIT); - if (!sav->sched) { - sav->schedlen = 0; - return ENOBUFS; - } - - error = (*algo->schedule)(algo, sav); - if (error) { - ipseclog((LOG_ERR, "esp_schedule %s: error %d\n", - algo->name, error)); - bzero(sav->sched, sav->schedlen); - free(sav->sched, M_SECA); - sav->sched = NULL; - sav->schedlen = 0; - } - return error; -} - -static int -esp_null_mature(sav) - struct secasvar *sav; -{ - - /* anything is okay */ - return 0; -} - -static int -esp_null_decrypt(m, off, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - - return 0; /* do nothing */ -} - -static int -esp_null_encrypt(m, off, plen, sav, algo, ivlen) - struct mbuf *m; - size_t off; /* offset to ESP header */ - size_t plen; /* payload length (to be encrypted) */ - struct secasvar *sav; - const struct esp_algorithm *algo; - int ivlen; -{ - - return 0; /* do nothing */ -} - -static int -esp_descbc_mature(sav) - struct secasvar *sav; -{ - const struct esp_algorithm *algo; - - if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) { - ipseclog((LOG_ERR, "esp_cbc_mature: " - "algorithm incompatible with 4 octets IV length\n")); - return 1; - } - - if (!sav->key_enc) { - ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n")); - return 1; - } - - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_ERR, - "esp_descbc_mature: unsupported algorithm.\n")); - return 1; - } - - if (_KEYBITS(sav->key_enc) < algo->keymin || - _KEYBITS(sav->key_enc) > algo->keymax) { - ipseclog((LOG_ERR, - "esp_descbc_mature: invalid key length %d.\n", - _KEYBITS(sav->key_enc))); - return 1; - } - - /* weak key check */ - if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) { - ipseclog((LOG_ERR, - "esp_descbc_mature: weak key was passed.\n")); - return 1; - } - - return 0; -} - -static int -esp_descbc_ivlen(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - if (!sav) - return 8; - if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) - return 4; - if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV)) - return 4; - return 8; -} - -static size_t -esp_des_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(des_key_schedule); -} - -static int -esp_des_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - if (des_key_sched((des_cblock *)_KEYBUF(sav->key_enc), - *(des_key_schedule *)sav->sched)) - return EINVAL; - else - return 0; -} - -static int -esp_des_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - /* assumption: d has a good alignment */ - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, - *(des_key_schedule *)sav->sched, DES_DECRYPT); - return 0; -} - -static int -esp_des_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - /* assumption: d has a good alignment */ - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb_encrypt((des_cblock *)d, (des_cblock *)d, - *(des_key_schedule *)sav->sched, DES_ENCRYPT); - return 0; -} - -static int -esp_cbc_mature(sav) - struct secasvar *sav; -{ - int keylen; - const struct esp_algorithm *algo; - - if (sav->flags & SADB_X_EXT_OLD) { - ipseclog((LOG_ERR, - "esp_cbc_mature: algorithm incompatible with esp-old\n")); - return 1; - } - if (sav->flags & SADB_X_EXT_DERIV) { - ipseclog((LOG_ERR, - "esp_cbc_mature: algorithm incompatible with derived\n")); - return 1; - } - - if (!sav->key_enc) { - ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n")); - return 1; - } - - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_ERR, - "esp_cbc_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_cbc_mature %s: invalid key length %d.\n", - algo->name, sav->key_enc->sadb_key_bits)); - return 1; - } - switch (sav->alg_enc) { - case SADB_EALG_3DESCBC: - /* weak key check */ - if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) || - des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) || - des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) { - ipseclog((LOG_ERR, - "esp_cbc_mature %s: weak key was passed.\n", - algo->name)); - return 1; - } - break; - case SADB_X_EALG_BLOWFISHCBC: - case SADB_X_EALG_CAST128CBC: - break; - case SADB_X_EALG_RIJNDAELCBC: - case SADB_X_EALG_CAMELLIACBC: - /* allows specific key sizes only */ - if (!(keylen == 128 || keylen == 192 || keylen == 256)) { - ipseclog((LOG_ERR, - "esp_cbc_mature %s: invalid key length %d.\n", - algo->name, keylen)); - return 1; - } - break; - } - - return 0; -} - -static size_t -esp_blowfish_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(BF_KEY); -} - -static int -esp_blowfish_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - BF_set_key((BF_KEY *)sav->sched, _KEYLEN(sav->key_enc), - _KEYBUF(sav->key_enc)); - return 0; -} - -static int -esp_blowfish_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - BF_ecb_encrypt(s, d, (BF_KEY *)sav->sched, 0); - return 0; -} - -static int -esp_blowfish_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - BF_ecb_encrypt(s, d, (BF_KEY *)sav->sched, 1); - return 0; -} - -static size_t -esp_cast128_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(cast128_key); -} - -static int -esp_cast128_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - cast128_setkey((cast128_key *)sav->sched, _KEYBUF(sav->key_enc), - _KEYLEN(sav->key_enc)); - return 0; -} - -static int -esp_cast128_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - cast128_decrypt((cast128_key *)sav->sched, s, d); - return 0; -} - -static int -esp_cast128_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - - cast128_encrypt((cast128_key *)sav->sched, s, d); - return 0; -} - -static size_t -esp_3des_schedlen(algo) - const struct esp_algorithm *algo; -{ - - return sizeof(des_key_schedule) * 3; -} - -static int -esp_3des_schedule(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - int error; - des_key_schedule *p; - int i; - u_int8_t *k; - - p = (des_key_schedule *)sav->sched; - k = _KEYBUF(sav->key_enc); - for (i = 0; i < 3; i++) { - error = des_key_sched((des_cblock *)(k + 8 * i), p[i]); - if (error) - return EINVAL; - } - return 0; -} - -static int -esp_3des_blockdecrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - des_key_schedule *p; - - /* assumption: d has a good alignment */ - p = (des_key_schedule *)sav->sched; - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, - p[0], p[1], p[2], DES_DECRYPT); - return 0; -} - -static int -esp_3des_blockencrypt(algo, sav, s, d) - const struct esp_algorithm *algo; - struct secasvar *sav; - u_int8_t *s; - u_int8_t *d; -{ - des_key_schedule *p; - - /* assumption: d has a good alignment */ - p = (des_key_schedule *)sav->sched; - bcopy(s, d, sizeof(DES_LONG) * 2); - des_ecb3_encrypt((des_cblock *)d, (des_cblock *)d, - p[0], p[1], p[2], DES_ENCRYPT); - return 0; -} - -static int -esp_common_ivlen(algo, sav) - const struct esp_algorithm *algo; - struct secasvar *sav; -{ - - if (!algo) - panic("esp_common_ivlen: unknown algorithm"); - return algo->ivlenval; -} - -static int -esp_cbc_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, *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; - u_int8_t iv[MAXIVLEN], *ivp; - u_int8_t sbuf[MAXIVLEN], *sp; - u_int8_t *p, *q; - struct mbuf *scut; - int scutoff; - int i; - int blocklen; - int derived; - - if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " - "unsupported ivlen %d\n", algo->name, ivlen)); - m_freem(m); - return EINVAL; - } - - /* assumes blocklen == padbound */ - blocklen = algo->padbound; - -#ifdef DIAGNOSTIC - if (blocklen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %s: " - "unsupported blocklen %d\n", algo->name, blocklen)); - m_freem(m); - return EINVAL; - } -#endif - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - - /* grab iv */ - m_copydata(m, ivoff, ivlen, (caddr_t)iv); - - /* extend iv */ - if (ivlen == blocklen) - ; - else if (ivlen == 4 && blocklen == 8) { - bcopy(&iv[0], &iv[4], 4); - iv[4] ^= 0xff; - iv[5] ^= 0xff; - iv[6] ^= 0xff; - iv[7] ^= 0xff; - } else { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported ivlen/blocklen: %d %d\n", - algo->name, ivlen, blocklen)); - m_freem(m); - return EINVAL; - } - - if (m->m_pkthdr.len < bodyoff) { - ipseclog((LOG_ERR, "esp_cbc_decrypt %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_cbc_decrypt %s: " - "payload length must be multiple of %d\n", - algo->name, blocklen)); - m_freem(m); - return EINVAL; - } - - 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, 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; - } - - /* decrypt */ - (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); - - /* xor */ - p = ivp ? ivp : iv; - q = mtod(d, u_int8_t *) + dn; - for (i = 0; i < blocklen; i++) - q[i] ^= p[i]; - - /* next iv */ - if (sp == sbuf) { - bcopy(sbuf, iv, blocklen); - ivp = NULL; - } else - ivp = sp; - - 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(iv, sizeof(iv)); - bzero(sbuf, sizeof(sbuf)); - - return 0; -} - -static int -esp_cbc_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; - u_int8_t iv[MAXIVLEN], *ivp; - u_int8_t sbuf[MAXIVLEN], *sp; - u_int8_t *p, *q; - struct mbuf *scut; - int scutoff; - int i; - int blocklen; - int derived; - - if (ivlen != sav->ivlen || ivlen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported ivlen %d\n", algo->name, ivlen)); - m_freem(m); - return EINVAL; - } - - /* assumes blocklen == padbound */ - blocklen = algo->padbound; - -#ifdef DIAGNOSTIC - if (blocklen > sizeof(iv)) { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported blocklen %d\n", algo->name, blocklen)); - m_freem(m); - return EINVAL; - } -#endif - - if (sav->flags & SADB_X_EXT_OLD) { - /* RFC 1827 */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + ivlen; - derived = 0; - } else { - /* RFC 2406 */ - if (sav->flags & SADB_X_EXT_DERIV) { - /* - * draft-ietf-ipsec-ciph-des-derived-00.txt - * uses sequence number field as IV field. - */ - ivoff = off + sizeof(struct esp); - bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t); - ivlen = sizeof(u_int32_t); - derived = 1; - } else { - ivoff = off + sizeof(struct newesp); - bodyoff = off + sizeof(struct newesp) + ivlen; - derived = 0; - } - } - - /* put iv into the packet. if we are in derived mode, use seqno. */ - if (derived) - m_copydata(m, ivoff, ivlen, (caddr_t)iv); - else { - bcopy(sav->iv, iv, ivlen); - /* maybe it is better to overwrite dest, not source */ - m_copyback(m, ivoff, ivlen, (caddr_t)iv); - } - - /* extend iv */ - if (ivlen == blocklen) - ; - else if (ivlen == 4 && blocklen == 8) { - bcopy(&iv[0], &iv[4], 4); - iv[4] ^= 0xff; - iv[5] ^= 0xff; - iv[6] ^= 0xff; - iv[7] ^= 0xff; - } else { - ipseclog((LOG_ERR, "esp_cbc_encrypt %s: " - "unsupported ivlen/blocklen: %d %d\n", - algo->name, ivlen, blocklen)); - m_freem(m); - return EINVAL; - } - - if (m->m_pkthdr.len < bodyoff) { - ipseclog((LOG_ERR, "esp_cbc_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_cbc_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; - 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) { - 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; - } - - /* xor */ - p = ivp ? ivp : iv; - q = sp; - for (i = 0; i < blocklen; i++) - q[i] ^= p[i]; - - /* encrypt */ - (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn); - - /* next iv */ - ivp = mtod(d, u_int8_t *) + dn; - - 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(iv, sizeof(iv)); - bzero(sbuf, sizeof(sbuf)); - - key_sa_stir_iv(sav); - - return 0; -} - -/*------------------------------------------------------------*/ - -/* does not free m0 on error */ -int -esp_auth(m0, skip, length, sav, sum) - struct mbuf *m0; - size_t skip; /* offset to ESP header */ - size_t length; /* payload length */ - struct secasvar *sav; - u_char *sum; -{ - struct mbuf *m; - size_t off; - struct ah_algorithm_state s; - u_char sumbuf[AH_MAXSUMSIZE]; - const struct ah_algorithm *algo; - size_t siz; - int error; - - /* sanity checks */ - if (m0->m_pkthdr.len < skip) { - ipseclog((LOG_DEBUG, "esp_auth: mbuf length < skip\n")); - return EINVAL; - } - if (m0->m_pkthdr.len < skip + length) { - ipseclog((LOG_DEBUG, - "esp_auth: mbuf length < skip + length\n")); - return EINVAL; - } - /* - * length of esp part (excluding authentication data) must be 4n, - * since nexthdr must be at offset 4n+3. - */ - if (length % 4) { - ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n")); - return EINVAL; - } - if (!sav) { - ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n")); - return EINVAL; - } - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_ERR, - "esp_auth: bad ESP auth algorithm passed: %d\n", - sav->alg_auth)); - return EINVAL; - } - - m = m0; - off = 0; - - siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1)); - if (sizeof(sumbuf) < siz) { - ipseclog((LOG_DEBUG, - "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n", - (u_long)siz)); - return EINVAL; - } - - /* skip the header */ - while (skip) { - if (!m) - panic("mbuf chain?"); - if (m->m_len <= skip) { - skip -= m->m_len; - m = m->m_next; - off = 0; - } else { - off = skip; - skip = 0; - } - } - - error = (*algo->init)(&s, sav); - if (error) - return error; - - while (0 < length) { - if (!m) - panic("mbuf chain?"); - - if (m->m_len - off < length) { - (*algo->update)(&s, mtod(m, u_char *) + off, - m->m_len - off); - length -= m->m_len - off; - m = m->m_next; - off = 0; - } else { - (*algo->update)(&s, mtod(m, u_char *) + off, length); - break; - } - } - (*algo->result)(&s, sumbuf, sizeof(sumbuf)); - bcopy(sumbuf, sum, siz); /* XXX */ - - return 0; -} diff --git a/sys/netinet6/esp_input.c b/sys/netinet6/esp_input.c deleted file mode 100644 index 9cdd108..0000000 --- a/sys/netinet6/esp_input.c +++ /dev/null @@ -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 */ diff --git a/sys/netinet6/esp_rijndael.c b/sys/netinet6/esp_rijndael.c deleted file mode 100644 index 97d52d3..0000000 --- a/sys/netinet6/esp_rijndael.c +++ /dev/null @@ -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; -} diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c deleted file mode 100644 index 66367b5..0000000 --- a/sys/netinet6/ipcomp_core.c +++ /dev/null @@ -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); -} diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c deleted file mode 100644 index abdebb2..0000000 --- a/sys/netinet6/ipcomp_input.c +++ /dev/null @@ -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 */ diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c deleted file mode 100644 index 3a89311..0000000 --- a/sys/netinet6/ipcomp_output.c +++ /dev/null @@ -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 */ diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c deleted file mode 100644 index 294711e..0000000 --- a/sys/netinet6/ipsec.c +++ /dev/null @@ -1,3643 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: ipsec.c,v 1.207 2004/01/13 03:30:42 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. - */ - -/* - * IPsec controller part. - */ - -#include "opt_inet.h" -#include "opt_inet6.h" -#include "opt_ipsec.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/priv.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/kernel.h> -#include <sys/syslog.h> -#include <sys/sysctl.h> -#include <sys/proc.h> - -#include <net/if.h> -#include <net/route.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/udp.h> -#include <netinet/udp_var.h> -#include <netinet/ip_ecn.h> -#ifdef INET6 -#include <netinet6/ip6_ecn.h> -#endif -#include <netinet/tcp.h> -#include <netinet/udp.h> - -#include <netinet/ip6.h> -#ifdef INET6 -#include <netinet6/ip6_var.h> -#include <netinet6/scope6_var.h> -#endif -#include <netinet/in_pcb.h> -#ifdef INET6 -#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 -#ifdef IPSEC_ESP -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#endif -#include <netinet6/ipcomp.h> -#ifdef INET6 -#include <netinet6/ipcomp6.h> -#endif -#include <netkey/key.h> -#include <netkey/keydb.h> -#include <netkey/key_debug.h> - -#include <machine/in_cksum.h> - -#ifdef IPSEC_DEBUG -int ipsec_debug = 1; -#else -int ipsec_debug = 0; -#endif - -NET_NEEDS_GIANT("ipsec"); - -struct ipsecstat ipsecstat; -int ip4_ah_cleartos = 1; -int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ -int ip4_ipsec_dfbit = 0; /* DF bit on encap. 0: clear 1: set 2: copy */ -int ip4_esp_trans_deflev = IPSEC_LEVEL_USE; -int ip4_esp_net_deflev = IPSEC_LEVEL_USE; -int ip4_ah_trans_deflev = IPSEC_LEVEL_USE; -int ip4_ah_net_deflev = IPSEC_LEVEL_USE; -struct secpolicy *ip4_def_policy; -int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ -int ip4_esp_randpad = -1; - -static int sp_cachegen = 1; /* cache generation # */ - -SYSCTL_DECL(_net_inet_ipsec); -#ifdef INET6 -SYSCTL_DECL(_net_inet6_ipsec6); -#endif - -/* net.inet.ipsec */ -SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS, - stats, CTLFLAG_RD, &ipsecstat, ipsecstat, ""); -#if 0 -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip4_def_policy->policy, 0, ""); -#endif -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, - CTLFLAG_RW, &ip4_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, - CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, - ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, - ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, - dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, - ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, - debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, - esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); - -#ifdef INET6 -struct ipsecstat ipsec6stat; -int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; -int ip6_esp_net_deflev = IPSEC_LEVEL_USE; -int ip6_ah_trans_deflev = IPSEC_LEVEL_USE; -int ip6_ah_net_deflev = IPSEC_LEVEL_USE; -struct secpolicy *ip6_def_policy; -int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ -int ip6_esp_randpad = -1; - -/* net.inet6.ipsec6 */ -SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, - stats, CTLFLAG_RD, &ipsec6stat, ipsecstat, ""); -#if 0 -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip6_def_policy->policy, 0, ""); -#endif -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, - CTLFLAG_RW, &ip6_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, - CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, - ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, - debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, - esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); -#endif /* INET6 */ - -static struct secpolicy *ipsec_checkpcbcache __P((struct mbuf *, - struct inpcbpolicy *, int)); -static int ipsec_fillpcbcache __P((struct inpcbpolicy *, struct mbuf *, - struct secpolicy *, int)); -static int ipsec_invalpcbcache __P((struct inpcbpolicy *, int)); -static int ipsec_setspidx_mbuf - __P((struct secpolicyindex *, int, struct mbuf *, int)); -static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int)); -static void ipsec4_get_ulp __P((struct mbuf *, struct secpolicyindex *, int)); -static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); -#ifdef INET6 -static void ipsec6_get_ulp __P((struct mbuf *, struct secpolicyindex *, int)); -static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *)); -#endif -static struct inpcbpolicy *ipsec_newpcbpolicy __P((void)); -static void ipsec_delpcbpolicy __P((struct inpcbpolicy *)); -#if 0 -static int ipsec_deepcopy_pcbpolicy __P((struct inpcbpolicy *)); -#endif -static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *)); -static int ipsec_set_policy - __P((struct secpolicy **, int, caddr_t, size_t, int)); -static int ipsec_get_policy __P((struct secpolicy *, struct mbuf **)); -static void vshiftl __P((unsigned char *, int, int)); -static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *)); -static size_t ipsec_hdrsiz __P((struct secpolicy *)); -#ifdef INET -static struct mbuf *ipsec4_splithdr __P((struct mbuf *)); -#endif -#ifdef INET6 -static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); -#endif -#ifdef INET -static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); -#endif -#ifdef INET6 -static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); -#endif -static struct ipsecaux *ipsec_addaux __P((struct mbuf *)); -static struct ipsecaux *ipsec_findaux __P((struct mbuf *)); -static void ipsec_optaux __P((struct mbuf *, struct ipsecaux *)); -#ifdef INET -static int ipsec4_checksa __P((struct ipsecrequest *, - struct ipsec_output_state *)); -#endif -#ifdef INET6 -static int ipsec6_checksa __P((struct ipsecrequest *, - struct ipsec_output_state *, int)); -#endif - -/* - * try to validate and use cached policy on a pcb. - */ -static struct secpolicy * -ipsec_checkpcbcache(m, pcbsp, dir) - struct mbuf *m; - struct inpcbpolicy *pcbsp; - int dir; -{ - struct secpolicyindex spidx; - struct timeval mono_time; - - microtime(&mono_time); - - switch (dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - case IPSEC_DIR_ANY: - break; - default: - return NULL; - } -#ifdef DIAGNOSTIC - if (dir >= sizeof(pcbsp->cache)/sizeof(pcbsp->cache[0])) - panic("dir too big in ipsec_checkpcbcache"); -#endif - /* SPD table change invalidates all the caches */ - if (pcbsp->cachegen[dir] == 0 || sp_cachegen > pcbsp->cachegen[dir]) { - ipsec_invalpcbcache(pcbsp, dir); - return NULL; - } - if (!pcbsp->cache[dir]) - return NULL; - if (pcbsp->cache[dir]->state != IPSEC_SPSTATE_ALIVE) { - ipsec_invalpcbcache(pcbsp, dir); - return NULL; - } - if ((pcbsp->cacheflags & IPSEC_PCBSP_CONNECTED) == 0) { - if (!pcbsp->cache[dir]) - return NULL; - if (ipsec_setspidx(m, &spidx, 1) != 0) - return NULL; - if (bcmp(&pcbsp->cacheidx[dir], &spidx, sizeof(spidx))) { - if (!pcbsp->cache[dir]->spidx || - !key_cmpspidx_withmask(pcbsp->cache[dir]->spidx, - &spidx)) - return NULL; - pcbsp->cacheidx[dir] = spidx; - } - } else { - /* - * The pcb is connected, and the L4 code is sure that: - * - outgoing side uses inp_[lf]addr - * - incoming side looks up policy after inpcb lookup - * and address pair is known to be stable. We do not need - * to generate spidx again, nor check the address match again. - * - * For IPv4/v6 SOCK_STREAM sockets, this assumption holds - * and there are calls to ipsec_pcbconn() from in_pcbconnect(). - */ - } - - pcbsp->cache[dir]->lastused = mono_time.tv_sec; - pcbsp->cache[dir]->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec_checkpcbcache cause refcnt++:%d SP:%p\n", - pcbsp->cache[dir]->refcnt, pcbsp->cache[dir])); - return pcbsp->cache[dir]; -} - -static int -ipsec_fillpcbcache(pcbsp, m, sp, dir) - struct inpcbpolicy *pcbsp; - struct mbuf *m; - struct secpolicy *sp; - int dir; -{ - - switch (dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - break; - default: - return EINVAL; - } -#ifdef DIAGNOSTIC - if (dir >= sizeof(pcbsp->cache)/sizeof(pcbsp->cache[0])) - panic("dir too big in ipsec_checkpcbcache"); -#endif - - if (pcbsp->cache[dir]) - key_freesp(pcbsp->cache[dir]); - pcbsp->cache[dir] = NULL; - if (ipsec_setspidx(m, &pcbsp->cacheidx[dir], 1) != 0) { - return EINVAL; - } - pcbsp->cache[dir] = sp; - if (pcbsp->cache[dir]) { - pcbsp->cache[dir]->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec_fillpcbcache cause refcnt++:%d SP:%p\n", - pcbsp->cache[dir]->refcnt, pcbsp->cache[dir])); - } - pcbsp->cachegen[dir] = sp_cachegen; - - return 0; -} - -static int -ipsec_invalpcbcache(pcbsp, dir) - struct inpcbpolicy *pcbsp; - int dir; -{ - int i; - - for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) { - if (dir != IPSEC_DIR_ANY && i != dir) - continue; - if (pcbsp->cache[i]) - key_freesp(pcbsp->cache[i]); - pcbsp->cache[i] = NULL; - pcbsp->cachegen[i] = 0; - bzero(&pcbsp->cacheidx[i], sizeof(pcbsp->cacheidx[i])); - } - return 0; -} - -int -ipsec_pcbconn(pcbsp) - struct inpcbpolicy *pcbsp; -{ - - pcbsp->cacheflags |= IPSEC_PCBSP_CONNECTED; - ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); - return 0; -} - -int -ipsec_pcbdisconn(pcbsp) - struct inpcbpolicy *pcbsp; -{ - - pcbsp->cacheflags &= ~IPSEC_PCBSP_CONNECTED; - ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY); - return 0; -} - -int -ipsec_invalpcbcacheall() -{ - - sp_cachegen++; - return 0; -} - -/* - * For OUTBOUND packet having a socket. Searching SPD for packet, - * and return a pointer to SP. - * OUT: NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - * others: a pointer to SP - * - * NOTE: IPv6 mapped adddress concern is implemented here. - */ -struct secpolicy * -ipsec4_getpolicybypcb(m, dir, inp, error) - struct mbuf *m; - u_int dir; - struct inpcb *inp; - int *error; -{ - struct inpcbpolicy *pcbsp = NULL; - struct secpolicy *currsp = NULL; /* policy on socket */ - struct secpolicy *kernsp = NULL; /* policy on kernel */ - struct secpolicyindex spidx; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || inp == NULL || error == NULL) - panic("ipsec4_getpolicybypcb: NULL pointer was passed."); - - pcbsp = inp->inp_sp; - -#ifdef DIAGNOSTIC - if (pcbsp == NULL) - panic("ipsec4_getpolicybypcb: pcbsp is NULL."); -#endif - - tag = 0; - - /* if we have a cached entry, and if it is still valid, use it. */ - ipsecstat.spdcachelookup++; - currsp = ipsec_checkpcbcache(m, pcbsp, dir); - if (currsp) { - *error = 0; - return currsp; - } - ipsecstat.spdcachemiss++; - - switch (dir) { - case IPSEC_DIR_INBOUND: - currsp = pcbsp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - currsp = pcbsp->sp_out; - break; - default: - panic("ipsec4_getpolicybypcb: illegal direction."); - } - - /* sanity check */ - if (currsp == NULL) - panic("ipsec4_getpolicybypcb: currsp is NULL."); - - /* when privileged socket */ - if (pcbsp->priv) { - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - case IPSEC_POLICY_ENTRUST: - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - ip4_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir); - return ip4_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, "ipsec4_getpolicybypcb: " - "Invalid policy for PCB %d\n", currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ - } - - /* when non-privileged socket */ - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - ipseclog((LOG_ERR, "ipsec4_getpolicybypcb: " - "Illegal policy for non-privileged defined %d\n", - currsp->policy)); - *error = EINVAL; - return NULL; - - case IPSEC_POLICY_ENTRUST: - ip4_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir); - return ip4_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, "ipsec4_getpolicybypcb: " - "Invalid policy for PCB %d\n", currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ -} - -/* - * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, - * and return a pointer to SP. - * OUT: positive: a pointer to the entry for security policy leaf matched. - * NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - */ -struct secpolicy * -ipsec4_getpolicybyaddr(m, dir, flag, error) - struct mbuf *m; - u_int dir; - int flag; - int *error; -{ - struct secpolicy *sp = NULL; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || error == NULL) - panic("ipsec4_getpolicybyaddr: NULL pointer was passed."); - - /* get a policy entry matched with the packet */ - { - struct secpolicyindex spidx; - - bzero(&spidx, sizeof(spidx)); - - /* make an index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, AF_INET, m, - (flag & IP_FORWARDING) ? 0 : 1); - - if (*error != 0) - return NULL; - - tag = 0; - - sp = key_allocsp(tag, &spidx, dir); - } - - /* SP found */ - if (sp != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_getpolicybyaddr called " - "to allocate SP:%p\n", sp)); - *error = 0; - return sp; - } - - /* no SP found */ - ip4_def_policy->refcnt++; - *error = 0; - return ip4_def_policy; -} - -#ifdef INET6 -/* - * For OUTBOUND packet having a socket. Searching SPD for packet, - * and return a pointer to SP. - * OUT: NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - * others: a pointer to SP - */ -struct secpolicy * -ipsec6_getpolicybypcb(m, dir, inp, error) - struct mbuf *m; - u_int dir; - struct inpcb *inp; - int *error; -{ - struct inpcbpolicy *pcbsp = NULL; - struct secpolicy *currsp = NULL; /* policy on socket */ - struct secpolicy *kernsp = NULL; /* policy on kernel */ - struct secpolicyindex spidx; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || inp == NULL || error == NULL) - panic("ipsec6_getpolicybypcb: NULL pointer was passed."); - -#ifdef DIAGNOSTIC - if ((inp->inp_vflag & INP_IPV6PROTO) == 0) - panic("ipsec6_getpolicybypcb: socket domain != inet6"); -#endif - - pcbsp = inp->in6p_sp; - -#ifdef DIAGNOSTIC - if (pcbsp == NULL) - panic("ipsec6_getpolicybypcb: pcbsp is NULL."); -#endif - - tag = 0; - - /* if we have a cached entry, and if it is still valid, use it. */ - ipsec6stat.spdcachelookup++; - currsp = ipsec_checkpcbcache(m, pcbsp, dir); - if (currsp) { - *error = 0; - return currsp; - } - ipsec6stat.spdcachemiss++; - - switch (dir) { - case IPSEC_DIR_INBOUND: - currsp = pcbsp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - currsp = pcbsp->sp_out; - break; - default: - panic("ipsec6_getpolicybypcb: illegal direction."); - } - - /* sanity check */ - if (currsp == NULL) - panic("ipsec6_getpolicybypcb: currsp is NULL."); - - /* when privileged socket */ - if (pcbsp->priv) { - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - case IPSEC_POLICY_ENTRUST: - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - ip6_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir); - return ip6_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, "ipsec6_getpolicybypcb: " - "Invalid policy for PCB %d\n", currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ - } - - /* when non-privileged socket */ - /* look for a policy in SPD */ - if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 && - (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) { - /* SP found */ - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_getpolicybypcb called " - "to allocate SP:%p\n", kernsp)); - *error = 0; - ipsec_fillpcbcache(pcbsp, m, kernsp, dir); - return kernsp; - } - - /* no SP found */ - switch (currsp->policy) { - case IPSEC_POLICY_BYPASS: - ipseclog((LOG_ERR, "ipsec6_getpolicybypcb: " - "Illegal policy for non-privileged defined %d\n", - currsp->policy)); - *error = EINVAL; - return NULL; - - case IPSEC_POLICY_ENTRUST: - ip6_def_policy->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir); - return ip6_def_policy; - - case IPSEC_POLICY_IPSEC: - currsp->refcnt++; - *error = 0; - ipsec_fillpcbcache(pcbsp, m, currsp, dir); - return currsp; - - default: - ipseclog((LOG_ERR, - "ipsec6_policybysock: Invalid policy for PCB %d\n", - currsp->policy)); - *error = EINVAL; - return NULL; - } - /* NOTREACHED */ -} - -/* - * For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet, - * and return a pointer to SP. - * `flag' means that packet is to be forwarded whether or not. - * flag = 1: forwad - * OUT: positive: a pointer to the entry for security policy leaf matched. - * NULL: no apropreate SP found, the following value is set to error. - * 0 : bypass - * EACCES : discard packet. - * ENOENT : ipsec_acquire() in progress, maybe. - * others : error occured. - */ -#ifndef IP_FORWARDING -#define IP_FORWARDING 1 -#endif - -struct secpolicy * -ipsec6_getpolicybyaddr(m, dir, flag, error) - struct mbuf *m; - u_int dir; - int flag; - int *error; -{ - struct secpolicy *sp = NULL; - u_int16_t tag; - - /* sanity check */ - if (m == NULL || error == NULL) - panic("ipsec6_getpolicybyaddr: NULL pointer was passed."); - - /* get a policy entry matched with the packet */ - { - struct secpolicyindex spidx; - - bzero(&spidx, sizeof(spidx)); - - /* make an index to look for a policy */ - *error = ipsec_setspidx_mbuf(&spidx, AF_INET6, m, - (flag & IP_FORWARDING) ? 0 : 1); - - if (*error != 0) - return NULL; - - tag = 0; - - sp = key_allocsp(tag, &spidx, dir); - } - - /* SP found */ - if (sp != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_getpolicybyaddr called " - "to allocate SP:%p\n", sp)); - *error = 0; - return sp; - } - - /* no SP found */ - ip6_def_policy->refcnt++; - *error = 0; - return ip6_def_policy; -} -#endif /* INET6 */ - -/* - * set IP address into spidx from mbuf. - * When Forwarding packet and ICMP echo reply, this function is used. - * - * IN: get the followings from mbuf. - * protocol family, src, dst, next protocol - * OUT: - * 0: success. - * other: failure, and set errno. - */ -int -ipsec_setspidx_mbuf(spidx, family, m, needport) - struct secpolicyindex *spidx; - int family; - struct mbuf *m; - int needport; -{ - int error; - - /* sanity check */ - if (spidx == NULL || m == NULL) - panic("ipsec_setspidx_mbuf: NULL pointer was passed."); - - bzero(spidx, sizeof(*spidx)); - - error = ipsec_setspidx(m, spidx, needport); - if (error) - goto bad; - - return 0; - - bad: - /* XXX initialize */ - bzero(spidx, sizeof(*spidx)); - return EINVAL; -} - -/* - * configure security policy index (src/dst/proto/sport/dport) - * by looking at the content of mbuf. - * the caller is responsible for error recovery (like clearing up spidx). - */ -static int -ipsec_setspidx(m, spidx, needport) - struct mbuf *m; - struct secpolicyindex *spidx; - int needport; -{ - struct ip *ip = NULL; - struct ip ipbuf; - u_int v; - struct mbuf *n; - int len; - int error; - - if (m == NULL) - panic("ipsec_setspidx: m == 0 passed."); - - bzero(spidx, sizeof(*spidx)); - - /* - * validate m->m_pkthdr.len. we see incorrect length if we - * mistakenly call this function with inconsistent mbuf chain - * (like 4.4BSD tcp/udp processing). XXX should we panic here? - */ - len = 0; - for (n = m; n; n = n->m_next) - len += n->m_len; - if (m->m_pkthdr.len != len) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "total of m_len(%d) != pkthdr.len(%d), " - "ignored.\n", - len, m->m_pkthdr.len)); - return EINVAL; - } - - if (m->m_pkthdr.len < sizeof(struct ip)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "pkthdr.len(%d) < sizeof(struct ip), ignored.\n", - m->m_pkthdr.len)); - return EINVAL; - } - - if (m->m_len >= sizeof(*ip)) - ip = mtod(m, struct ip *); - else { - m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); - ip = &ipbuf; - } -#ifdef _IP_VHL - v = _IP_VHL_V(ip->ip_vhl); -#else - v = ip->ip_v; -#endif - switch (v) { - case 4: - error = ipsec4_setspidx_ipaddr(m, spidx); - if (error) - return error; - ipsec4_get_ulp(m, spidx, needport); - return 0; -#ifdef INET6 - case 6: - if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) { - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "pkthdr.len(%d) < sizeof(struct ip6_hdr), " - "ignored.\n", m->m_pkthdr.len)); - return EINVAL; - } - error = ipsec6_setspidx_ipaddr(m, spidx); - if (error) - return error; - ipsec6_get_ulp(m, spidx, needport); - return 0; -#endif - default: - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_setspidx: " - "unknown IP version %u, ignored.\n", v)); - return EINVAL; - } -} - -static void -ipsec4_get_ulp(m, spidx, needport) - struct mbuf *m; - struct secpolicyindex *spidx; - int needport; -{ - struct ip ip; - struct ip6_ext ip6e; - u_int8_t nxt; - int off; - struct tcphdr th; - struct udphdr uh; - - /* sanity check */ - if (m == NULL) - panic("ipsec4_get_ulp: NULL pointer was passed."); - if (m->m_pkthdr.len < sizeof(ip)) - panic("ipsec4_get_ulp: too short"); - - /* set default */ - spidx->ul_proto = IPSEC_ULPROTO_ANY; - ((struct sockaddr_in *)&spidx->src)->sin_port = IPSEC_PORT_ANY; - ((struct sockaddr_in *)&spidx->dst)->sin_port = IPSEC_PORT_ANY; - - m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); - /* ip_input() flips it into host endian XXX need more checking */ - if (ip.ip_off & (IP_MF | IP_OFFMASK)) - return; - - nxt = ip.ip_p; -#ifdef _IP_VHL - off = _IP_VHL_HL(ip->ip_vhl) << 2; -#else - off = ip.ip_hl << 2; -#endif - while (off < m->m_pkthdr.len) { - switch (nxt) { - case IPPROTO_TCP: - spidx->ul_proto = nxt; - if (!needport) - return; - if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) - return; - m_copydata(m, off, sizeof(th), (caddr_t)&th); - ((struct sockaddr_in *)&spidx->src)->sin_port = - th.th_sport; - ((struct sockaddr_in *)&spidx->dst)->sin_port = - th.th_dport; - return; - case IPPROTO_UDP: - spidx->ul_proto = nxt; - if (!needport) - return; - if (off + sizeof(struct udphdr) > m->m_pkthdr.len) - return; - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - ((struct sockaddr_in *)&spidx->src)->sin_port = - uh.uh_sport; - ((struct sockaddr_in *)&spidx->dst)->sin_port = - uh.uh_dport; - return; - case IPPROTO_AH: - if (off + sizeof(ip6e) > m->m_pkthdr.len) - return; - m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); - off += (ip6e.ip6e_len + 2) << 2; - nxt = ip6e.ip6e_nxt; - break; - case IPPROTO_ICMP: - default: - /* XXX intermediate headers??? */ - spidx->ul_proto = nxt; - return; - } - } -} - -/* assumes that m is sane */ -static int -ipsec4_setspidx_ipaddr(m, spidx) - struct mbuf *m; - struct secpolicyindex *spidx; -{ - struct ip *ip = NULL; - struct ip ipbuf; - struct sockaddr_in *sin; - - if (m->m_len >= sizeof(*ip)) - ip = mtod(m, struct ip *); - else { - m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf); - ip = &ipbuf; - } - - sin = (struct sockaddr_in *)&spidx->src; - bzero(sin, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(struct sockaddr_in); - bcopy(&ip->ip_src, &sin->sin_addr, sizeof(ip->ip_src)); - spidx->prefs = sizeof(struct in_addr) << 3; - - sin = (struct sockaddr_in *)&spidx->dst; - bzero(sin, sizeof(*sin)); - sin->sin_family = AF_INET; - sin->sin_len = sizeof(struct sockaddr_in); - bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)); - spidx->prefd = sizeof(struct in_addr) << 3; - return 0; -} - -#ifdef INET6 -static void -ipsec6_get_ulp(m, spidx, needport) - struct mbuf *m; - struct secpolicyindex *spidx; - int needport; -{ - int off, nxt; - struct tcphdr th; - struct udphdr uh; - struct icmp6_hdr ih; - - /* sanity check */ - if (m == NULL) - panic("ipsec6_get_ulp: NULL pointer was passed."); - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m)); - - /* set default */ - spidx->ul_proto = IPSEC_ULPROTO_ANY; - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY; - - nxt = -1; - off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt); - if (off < 0 || m->m_pkthdr.len < off) - return; - - switch (nxt) { - case IPPROTO_TCP: - spidx->ul_proto = nxt; - if (!needport) - break; - if (off + sizeof(struct tcphdr) > m->m_pkthdr.len) - break; - m_copydata(m, off, sizeof(th), (caddr_t)&th); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport; - break; - case IPPROTO_UDP: - spidx->ul_proto = nxt; - if (!needport) - break; - if (off + sizeof(struct udphdr) > m->m_pkthdr.len) - break; - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport; - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport; - break; - case IPPROTO_ICMPV6: - spidx->ul_proto = nxt; - if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len) - break; - m_copydata(m, off, sizeof(ih), (caddr_t)&ih); - ((struct sockaddr_in6 *)&spidx->src)->sin6_port = - htons((u_int16_t)ih.icmp6_type); - ((struct sockaddr_in6 *)&spidx->dst)->sin6_port = - htons((u_int16_t)ih.icmp6_code); - break; - default: - /* XXX intermediate headers??? */ - spidx->ul_proto = nxt; - break; - } -} - -/* assumes that m is sane */ -static int -ipsec6_setspidx_ipaddr(m, spidx) - struct mbuf *m; - struct secpolicyindex *spidx; -{ - struct ip6_hdr *ip6 = NULL; - struct ip6_hdr ip6buf; - struct sockaddr_in6 *sin6; - - if (m->m_len >= sizeof(*ip6)) - ip6 = mtod(m, struct ip6_hdr *); - else { - m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf); - ip6 = &ip6buf; - } - - sin6 = (struct sockaddr_in6 *)&spidx->src; - bzero(sin6, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_addr = ip6->ip6_src; - spidx->prefs = sizeof(struct in6_addr) << 3; - - sin6 = (struct sockaddr_in6 *)&spidx->dst; - bzero(sin6, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(struct sockaddr_in6); - sin6->sin6_addr = ip6->ip6_dst; - spidx->prefd = sizeof(struct in6_addr) << 3; - - return 0; -} -#endif - -static struct inpcbpolicy * -ipsec_newpcbpolicy() -{ - struct inpcbpolicy *p; - - p = (struct inpcbpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT); - return p; -} - -static void -ipsec_delpcbpolicy(p) - struct inpcbpolicy *p; -{ - - free(p, M_SECA); -} - -/* initialize policy in PCB */ -int -ipsec_init_pcbpolicy(so, pcb_sp) - struct socket *so; - struct inpcbpolicy **pcb_sp; -{ - struct inpcbpolicy *new; - static int initialized = 0; - static struct secpolicy *in = NULL, *out = NULL; - - /* sanity check. */ - if (so == NULL || pcb_sp == NULL) - panic("ipsec_init_pcbpolicy: NULL pointer was passed."); - - if (!initialized) { - if ((in = key_newsp(0)) == NULL) - return ENOBUFS; - if ((out = key_newsp(0)) == NULL) { - key_freesp(in); - in = NULL; - return ENOBUFS; - } - - in->state = IPSEC_SPSTATE_ALIVE; - in->policy = IPSEC_POLICY_ENTRUST; - in->dir = IPSEC_DIR_INBOUND; - in->readonly = 1; - in->persist = 1; - in->so = NULL; - - out->state = IPSEC_SPSTATE_ALIVE; - out->policy = IPSEC_POLICY_ENTRUST; - out->dir = IPSEC_DIR_OUTBOUND; - out->readonly = 1; - out->persist = 1; - out->so = NULL; - - initialized++; - } - - new = ipsec_newpcbpolicy(); - if (new == NULL) { - ipseclog((LOG_DEBUG, "ipsec_init_pcbpolicy: No more memory.\n")); - return ENOBUFS; - } - bzero(new, sizeof(*new)); - - /* - * XXXRW: Can we avoid caching the privilege decision here, and - * instead cache the credential? - */ - if (so->so_cred != NULL && priv_check_cred(so->so_cred, - PRIV_NETINET_IPSEC, 0) == 0) - new->priv = 1; - else - new->priv = 0; - - new->sp_in = in; - new->sp_in->refcnt++; - new->sp_out = out; - new->sp_out->refcnt++; - - *pcb_sp = new; - - return 0; -} - -/* copy old ipsec policy into new */ -int -ipsec_copy_pcbpolicy(old, new) - struct inpcbpolicy *old, *new; -{ - - if (new->sp_in) - key_freesp(new->sp_in); - if (old->sp_in->policy == IPSEC_POLICY_IPSEC) - new->sp_in = ipsec_deepcopy_policy(old->sp_in); - else { - new->sp_in = old->sp_in; - new->sp_in->refcnt++; - } - - if (new->sp_out) - key_freesp(new->sp_out); - if (old->sp_out->policy == IPSEC_POLICY_IPSEC) - new->sp_out = ipsec_deepcopy_policy(old->sp_out); - else { - new->sp_out = old->sp_out; - new->sp_out->refcnt++; - } - - new->priv = old->priv; - - return 0; -} - -#if 0 -static int -ipsec_deepcopy_pcbpolicy(pcb_sp) - struct inpcbpolicy *pcb_sp; -{ - struct secpolicy *sp; - - sp = ipsec_deepcopy_policy(pcb_sp->sp_in); - if (sp) { - key_freesp(pcb_sp->sp_in); - pcb_sp->sp_in = sp; - } else - return ENOBUFS; - - sp = ipsec_deepcopy_policy(pcb_sp->sp_out); - if (sp) { - key_freesp(pcb_sp->sp_out); - pcb_sp->sp_out = sp; - } else - return ENOBUFS; - - return 0; -} -#endif - -/* deep-copy a policy in PCB */ -static struct secpolicy * -ipsec_deepcopy_policy(src) - struct secpolicy *src; -{ - struct ipsecrequest *newchain = NULL; - struct ipsecrequest *p; - struct ipsecrequest **q; - struct ipsecrequest *r; - struct secpolicy *dst; - - if (src == NULL) - return NULL; - - dst = key_newsp(0); - if (dst == NULL) - return NULL; - - /* - * deep-copy IPsec request chain. This is required since struct - * ipsecrequest is not reference counted. - */ - q = &newchain; - for (p = src->req; p; p = p->next) { - *q = (struct ipsecrequest *)malloc(sizeof(struct ipsecrequest), - M_SECA, M_NOWAIT); - if (*q == NULL) - goto fail; - bzero(*q, sizeof(**q)); - (*q)->next = NULL; - - (*q)->saidx.proto = p->saidx.proto; - (*q)->saidx.mode = p->saidx.mode; - (*q)->level = p->level; - (*q)->saidx.reqid = p->saidx.reqid; - - bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src)); - bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst)); - - (*q)->sav = NULL; - (*q)->sp = dst; - - q = &((*q)->next); - } - - if (src->spidx) - if (keydb_setsecpolicyindex(dst, src->spidx) != 0) - goto fail; - - dst->req = newchain; - dst->state = src->state; - dst->policy = src->policy; - dst->dir = src->dir; - dst->so = src->so; - /* do not touch the refcnt fields */ - - return dst; - -fail: - for (p = newchain; p; p = r) { - r = p->next; - free(p, M_SECA); - p = NULL; - } - key_freesp(dst); - return NULL; -} - -/* set policy and ipsec request if present. */ -static int -ipsec_set_policy(spp, optname, request, len, priv) - struct secpolicy **spp; - int optname; - caddr_t request; - size_t len; - int priv; -{ - struct sadb_x_policy *xpl; - struct secpolicy *newsp = NULL; - int error; - - /* sanity check. */ - if (spp == NULL || *spp == NULL || request == NULL) - return EINVAL; - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_set_policy: passed policy\n"); - kdebug_sadb_x_policy((struct sadb_ext *)xpl)); - - /* check policy type */ - /* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */ - if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD || - xpl->sadb_x_policy_type == IPSEC_POLICY_NONE) - return EINVAL; - - /* check privileged socket */ - if (priv == 0 && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) - return EACCES; - - /* allocation new SP entry */ - if ((newsp = key_msg2sp(xpl, len, &error)) == NULL) - return error; - - newsp->state = IPSEC_SPSTATE_ALIVE; - - /* clear old SP and set new SP */ - key_freesp(*spp); - *spp = newsp; - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_set_policy: new policy\n"); - kdebug_secpolicy(newsp)); - - return 0; -} - -static int -ipsec_get_policy(sp, mp) - struct secpolicy *sp; - struct mbuf **mp; -{ - - /* sanity check. */ - if (sp == NULL || mp == NULL) - return EINVAL; - - *mp = key_sp2msg(sp); - if (!*mp) { - ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n")); - return ENOBUFS; - } - - (*mp)->m_type = MT_DATA; - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_get_policy:\n"); - kdebug_mbuf(*mp)); - - return 0; -} - -int -ipsec4_set_policy(inp, optname, request, len, priv) - struct inpcb *inp; - int optname; - caddr_t request; - size_t len; - int priv; -{ - struct sadb_x_policy *xpl; - struct secpolicy **spp; - - /* sanity check. */ - if (inp == NULL || request == NULL) - return EINVAL; - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - spp = &inp->inp_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - spp = &inp->inp_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY); - return ipsec_set_policy(spp, optname, request, len, priv); -} - -int -ipsec4_get_policy(inp, request, len, mp) - struct inpcb *inp; - caddr_t request; - size_t len; - struct mbuf **mp; -{ - struct sadb_x_policy *xpl; - struct secpolicy *sp; - - /* sanity check. */ - if (inp == NULL || request == NULL || mp == NULL) - return EINVAL; - if (inp->inp_sp == NULL) - panic("policy in PCB is NULL"); - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - sp = inp->inp_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - sp = inp->inp_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec4_get_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - return ipsec_get_policy(sp, mp); -} - -/* delete policy in PCB */ -int -ipsec4_delete_pcbpolicy(inp) - struct inpcb *inp; -{ - /* sanity check. */ - if (inp == NULL) - panic("ipsec4_delete_pcbpolicy: NULL pointer was passed."); - - if (inp->inp_sp == NULL) - return 0; - - if (inp->inp_sp->sp_in != NULL) { - key_freesp(inp->inp_sp->sp_in); - inp->inp_sp->sp_in = NULL; - } - - if (inp->inp_sp->sp_out != NULL) { - key_freesp(inp->inp_sp->sp_out); - inp->inp_sp->sp_out = NULL; - } - - ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY); - - ipsec_delpcbpolicy(inp->inp_sp); - inp->inp_sp = NULL; - - return 0; -} - -#ifdef INET6 -int -ipsec6_set_policy(in6p, optname, request, len, priv) - struct in6pcb *in6p; - int optname; - caddr_t request; - size_t len; - int priv; -{ - struct sadb_x_policy *xpl; - struct secpolicy **spp; - - /* sanity check. */ - if (in6p == NULL || request == NULL) - return EINVAL; - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - spp = &in6p->in6p_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - spp = &in6p->in6p_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY); - return ipsec_set_policy(spp, optname, request, len, priv); -} - -int -ipsec6_get_policy(in6p, request, len, mp) - struct in6pcb *in6p; - caddr_t request; - size_t len; - struct mbuf **mp; -{ - struct sadb_x_policy *xpl; - struct secpolicy *sp; - - /* sanity check. */ - if (in6p == NULL || request == NULL || mp == NULL) - return EINVAL; - if (in6p->in6p_sp == NULL) - panic("policy in PCB is NULL"); - if (len < sizeof(*xpl)) - return EINVAL; - xpl = (struct sadb_x_policy *)request; - - /* select direction */ - switch (xpl->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - sp = in6p->in6p_sp->sp_in; - break; - case IPSEC_DIR_OUTBOUND: - sp = in6p->in6p_sp->sp_out; - break; - default: - ipseclog((LOG_ERR, "ipsec6_get_policy: invalid direction=%u\n", - xpl->sadb_x_policy_dir)); - return EINVAL; - } - - return ipsec_get_policy(sp, mp); -} - -int -ipsec6_delete_pcbpolicy(in6p) - struct in6pcb *in6p; -{ - /* sanity check. */ - if (in6p == NULL) - panic("ipsec6_delete_pcbpolicy: NULL pointer was passed."); - - if (in6p->in6p_sp == NULL) - return 0; - - if (in6p->in6p_sp->sp_in != NULL) { - key_freesp(in6p->in6p_sp->sp_in); - in6p->in6p_sp->sp_in = NULL; - } - - if (in6p->in6p_sp->sp_out != NULL) { - key_freesp(in6p->in6p_sp->sp_out); - in6p->in6p_sp->sp_out = NULL; - } - - ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY); - - ipsec_delpcbpolicy(in6p->in6p_sp); - in6p->in6p_sp = NULL; - - return 0; -} -#endif - -/* - * return current level. - * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. - */ -u_int -ipsec_get_reqlevel(isr, af) - struct ipsecrequest *isr; - int af; -{ - u_int level = 0; - u_int esp_trans_deflev, esp_net_deflev, ah_trans_deflev, ah_net_deflev; - - /* sanity check */ - if (isr == NULL || isr->sp == NULL) - panic("ipsec_get_reqlevel: NULL pointer is passed."); - - /* set default level */ - switch (af) { -#ifdef INET - case AF_INET: - esp_trans_deflev = ip4_esp_trans_deflev; - esp_net_deflev = ip4_esp_net_deflev; - ah_trans_deflev = ip4_ah_trans_deflev; - ah_net_deflev = ip4_ah_net_deflev; - break; -#endif -#ifdef INET6 - case AF_INET6: - esp_trans_deflev = ip6_esp_trans_deflev; - esp_net_deflev = ip6_esp_net_deflev; - ah_trans_deflev = ip6_ah_trans_deflev; - ah_net_deflev = ip6_ah_net_deflev; - break; -#endif /* INET6 */ - default: - panic("key_get_reqlevel: Unknown family. %d", - ((struct sockaddr *)&isr->sp->spidx->src)->sa_family); - } - - /* set level */ - switch (isr->level) { - case IPSEC_LEVEL_DEFAULT: - switch (isr->saidx.proto) { - case IPPROTO_ESP: - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - level = esp_net_deflev; - else - level = esp_trans_deflev; - break; - case IPPROTO_AH: - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - level = ah_net_deflev; - else - level = ah_trans_deflev; - break; - case IPPROTO_IPCOMP: - /* - * we don't really care, as IPcomp document says that - * we shouldn't compress small packets - */ - level = IPSEC_LEVEL_USE; - break; - default: - panic("ipsec_get_reqlevel: " - "Illegal protocol defined %u\n", - isr->saidx.proto); - } - break; - - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - level = isr->level; - break; - case IPSEC_LEVEL_UNIQUE: - level = IPSEC_LEVEL_REQUIRE; - break; - - default: - panic("ipsec_get_reqlevel: Illegal IPsec level %u", - isr->level); - } - - return level; -} - -/* - * Check AH/ESP integrity. - * OUT: - * 0: valid - * 1: invalid - */ -static int -ipsec_in_reject(sp, m) - struct secpolicy *sp; - struct mbuf *m; -{ - struct ipsecrequest *isr; - u_int level; - int need_auth, need_conf, need_icv; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec_in_reject: using SP\n"); - kdebug_secpolicy(sp)); - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - return 1; - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - return 0; - - case IPSEC_POLICY_IPSEC: - break; - - case IPSEC_POLICY_ENTRUST: - default: - panic("ipsec_in_reject: Invalid policy found. %d", sp->policy); - } - - need_auth = 0; - need_conf = 0; - need_icv = 0; - - /* XXX should compare policy against ipsec header history */ - - for (isr = sp->req; isr != NULL; isr = isr->next) { - /* get current level */ - level = ipsec_get_reqlevel(isr, AF_INET); - - switch (isr->saidx.proto) { - case IPPROTO_ESP: - if (level == IPSEC_LEVEL_REQUIRE) { - need_conf++; - - if (isr->sav != NULL - && isr->sav->flags == SADB_X_EXT_NONE - && isr->sav->alg_auth != SADB_AALG_NONE) - need_icv++; - } - break; - case IPPROTO_AH: - if (level == IPSEC_LEVEL_REQUIRE) { - need_auth++; - need_icv++; - } - break; - case IPPROTO_IPCOMP: - /* - * we don't really care, as IPcomp document says that - * we shouldn't compress small packets, IPComp policy - * should always be treated as being in "use" level. - */ - break; - } - } - - KEYDEBUG(KEYDEBUG_IPSEC_DUMP, - printf("ipsec_in_reject: auth:%d conf:%d icv:%d m_flags:%x\n", - need_auth, need_conf, need_icv, m->m_flags)); - - if ((need_conf && !(m->m_flags & M_DECRYPTED)) - || (!need_auth && need_icv && !(m->m_flags & M_AUTHIPDGM)) - || (need_auth && !(m->m_flags & M_AUTHIPHDR))) - return 1; - - return 0; -} - -/* - * Check AH/ESP integrity. - * This function is called from tcp_input(), udp_input(), - * and {ah,esp}4_input for tunnel mode - */ -int -ipsec4_in_reject(m, inp) - struct mbuf *m; - struct inpcb *inp; -{ - struct secpolicy *sp = NULL; - int error; - int result; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ - - /* get SP for this packet. - * When we are called from ip_forward(), we call - * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. - */ - if (inp == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); - else - sp = ipsec4_getpolicybypcb(m, IPSEC_DIR_INBOUND, inp, &error); - - /* XXX should be panic ? -> No, there may be error. */ - if (sp == NULL) - return 0; - - result = ipsec_in_reject(sp, m); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_in_reject call free SP:%p\n", sp)); - key_freesp(sp); - - return result; -} - -#ifdef INET6 -/* - * Check AH/ESP integrity. - * This function is called from tcp6_input(), udp6_input(), - * and {ah,esp}6_input for tunnel mode - */ -int -ipsec6_in_reject(m, in6p) - struct mbuf *m; - struct in6pcb *in6p; -{ - struct secpolicy *sp = NULL; - int error; - int result; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ - - /* get SP for this packet. - * When we are called from ip_forward(), we call - * ipsec6_getpolicybyaddr() with IP_FORWARDING flag. - */ - if (in6p == NULL) - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND, - IP_FORWARDING, &error); - else - sp = ipsec6_getpolicybypcb(m, IPSEC_DIR_INBOUND, in6p, &error); - - if (sp == NULL) - return 0; /* XXX should be panic ? */ - - result = ipsec_in_reject(sp, m); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_in_reject call free SP:%p\n", sp)); - key_freesp(sp); - - return result; -} -#endif - -/* - * compute the byte size to be occupied by IPsec header. - * in case it is tunneled, it includes the size of outer IP header. - * NOTE: SP passed is free in this function. - */ -static size_t -ipsec_hdrsiz(sp) - struct secpolicy *sp; -{ - struct ipsecrequest *isr; - size_t siz, clen; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec_hdrsiz: using SP\n"); - kdebug_secpolicy(sp)); - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - return 0; - - case IPSEC_POLICY_IPSEC: - break; - - case IPSEC_POLICY_ENTRUST: - default: - panic("ipsec_hdrsiz: Invalid policy found. %d", sp->policy); - } - - siz = 0; - - for (isr = sp->req; isr != NULL; isr = isr->next) { - - clen = 0; - - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - clen = esp_hdrsiz(isr); -#else - clen = 0; /* XXX */ -#endif - break; - case IPPROTO_AH: - clen = ah_hdrsiz(isr); - break; - case IPPROTO_IPCOMP: - clen = sizeof(struct ipcomp); - break; - } - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - switch (((struct sockaddr *)&isr->saidx.dst)->sa_family) { - case AF_INET: - clen += sizeof(struct ip); - break; -#ifdef INET6 - case AF_INET6: - clen += sizeof(struct ip6_hdr); - break; -#endif - default: - ipseclog((LOG_ERR, "ipsec_hdrsiz: " - "unknown AF %d in IPsec tunnel SA\n", - ((struct sockaddr *)&isr->saidx.dst)->sa_family)); - break; - } - } - siz += clen; - } - - return siz; -} - -/* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ -size_t -ipsec4_hdrsiz(m, dir, inp) - struct mbuf *m; - u_int dir; - struct inpcb *inp; -{ - struct secpolicy *sp = NULL; - int error; - size_t size; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ -#if 0 - /* this is possible in TIME_WAIT state */ - if (inp != NULL && inp->inp_socket == NULL) - panic("ipsec4_hdrsize: why is socket NULL but there is PCB."); -#endif - - /* get SP for this packet. - * When we are called from ip_forward(), we call - * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. - */ - if (inp == NULL) - sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error); - else - sp = ipsec4_getpolicybypcb(m, dir, inp, &error); - - if (sp == NULL) - return 0; /* XXX should be panic ? */ - - size = ipsec_hdrsiz(sp); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec4_hdrsiz call free SP:%p\n", sp)); - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec4_hdrsiz: size:%lu.\n", (unsigned long)size)); - key_freesp(sp); - - return size; -} - -#ifdef INET6 -/* This function is called from ipsec6_hdrsize_tcp(), - * and maybe from ip6_forward.() - */ -size_t -ipsec6_hdrsiz(m, dir, in6p) - struct mbuf *m; - u_int dir; - struct in6pcb *in6p; -{ - struct secpolicy *sp = NULL; - int error; - size_t size; - - /* sanity check */ - if (m == NULL) - return 0; /* XXX should be panic ? */ -#if 0 - /* this is possible in TIME_WAIT state */ - if (in6p != NULL && in6p->in6p_socket == NULL) - panic("ipsec6_hdrsize: why is socket NULL but there is PCB."); -#endif - - /* get SP for this packet */ - /* XXX Is it right to call with IP_FORWARDING. */ - if (in6p == NULL) - sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error); - else - sp = ipsec6_getpolicybypcb(m, dir, in6p, &error); - - if (sp == NULL) - return 0; - size = ipsec_hdrsiz(sp); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP ipsec6_hdrsiz call free SP:%p\n", sp)); - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_hdrsiz: size:%lu.\n", (unsigned long)size)); - key_freesp(sp); - - return size; -} -#endif /* INET6 */ - -#ifdef INET -/* - * encapsulate for ipsec tunnel. - * ip->ip_src must be fixed later on. - */ -static int -ipsec4_encapsulate(m, sav) - struct mbuf *m; - struct secasvar *sav; -{ - struct ip *oip; - struct ip *ip; - size_t hlen; - size_t plen; - - /* can't tunnel between different AFs */ - if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family - != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family - || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) { - m_freem(m); - return EINVAL; - } -#if 0 - /* XXX if the dst is myself, perform nothing. */ - if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { - m_freem(m); - return EINVAL; - } -#endif - - if (m->m_len < sizeof(*ip)) - panic("ipsec4_encapsulate: assumption failed (first mbuf length)"); - - 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("ipsec4_encapsulate: assumption failed (first mbuf length)"); - - /* generate header checksum */ - ip->ip_sum = 0; -#ifdef _IP_VHL - if (ip->ip_vhl == IP_VHL_BORING) - ip->ip_sum = in_cksum_hdr(ip); - else - ip->ip_sum = in_cksum(m, hlen); -#else - ip->ip_sum = in_cksum(m, hlen); -#endif - - plen = m->m_pkthdr.len; - - /* - * grow the mbuf to accomodate the new IPv4 header. - * NOTE: IPv4 options will never be copied. - */ - if (M_LEADINGSPACE(m->m_next) < hlen) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - m_freem(m); - return ENOBUFS; - } - n->m_len = hlen; - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += hlen; - oip = mtod(n, struct ip *); - } else { - m->m_next->m_len += hlen; - m->m_next->m_data -= hlen; - m->m_pkthdr.len += hlen; - oip = mtod(m->m_next, struct ip *); - } - ip = mtod(m, struct ip *); - ovbcopy((caddr_t)ip, (caddr_t)oip, hlen); - m->m_len = sizeof(struct ip); - m->m_pkthdr.len -= (hlen - sizeof(struct ip)); - - /* construct new IPv4 header. see RFC 2401 5.1.2.1 */ - /* ECN consideration. */ - ip_ecn_ingress(ip4_ipsec_ecn, &ip->ip_tos, &oip->ip_tos); -#ifdef _IP_VHL - ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); -#else - ip->ip_hl = sizeof(struct ip) >> 2; -#endif - ip->ip_off &= htons(~IP_OFFMASK); - ip->ip_off &= htons(~IP_MF); - switch (ip4_ipsec_dfbit) { - case 0: /* clear DF bit */ - ip->ip_off &= htons(~IP_DF); - break; - case 1: /* set DF bit */ - ip->ip_off |= htons(IP_DF); - break; - default: /* copy DF bit */ - break; - } - ip->ip_p = IPPROTO_IPIP; - if (plen + sizeof(struct ip) < IP_MAXPACKET) - ip->ip_len = htons(plen + sizeof(struct ip)); - else { - ipseclog((LOG_ERR, "IPv4 ipsec: size exceeds limit: " - "leave ip_len as is (invalid packet)\n")); - } - ip->ip_id = ip_newid(); - bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr, - &ip->ip_src, sizeof(ip->ip_src)); - bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr, - &ip->ip_dst, sizeof(ip->ip_dst)); - ip->ip_ttl = IPDEFTTL; - - /* XXX Should ip_src be updated later ? */ - - return 0; -} -#endif /* INET */ - -#ifdef INET6 -static int -ipsec6_encapsulate(m, sav) - struct mbuf *m; - struct secasvar *sav; -{ - struct sockaddr_in6 sa6; - struct ip6_hdr *oip6; - struct ip6_hdr *ip6; - size_t plen; - int error; - - /* can't tunnel between different AFs */ - if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family - != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family - || ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET6) { - m_freem(m); - return EINVAL; - } -#if 0 - /* XXX if the dst is myself, perform nothing. */ - if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { - m_freem(m); - return EINVAL; - } -#endif - - plen = m->m_pkthdr.len; - - /* - * grow the mbuf to accomodate the new IPv6 header. - */ - if (m->m_len != sizeof(struct ip6_hdr)) - panic("ipsec6_encapsulate: assumption failed (first mbuf length)"); - if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) { - struct mbuf *n; - MGET(n, M_DONTWAIT, MT_DATA); - if (!n) { - m_freem(m); - return ENOBUFS; - } - n->m_len = sizeof(struct ip6_hdr); - n->m_next = m->m_next; - m->m_next = n; - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(n, struct ip6_hdr *); - } else { - m->m_next->m_len += sizeof(struct ip6_hdr); - m->m_next->m_data -= sizeof(struct ip6_hdr); - m->m_pkthdr.len += sizeof(struct ip6_hdr); - oip6 = mtod(m->m_next, struct ip6_hdr *); - } - ip6 = mtod(m, struct ip6_hdr *); - ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr)); - - /* XXX: Fake scoped addresses */ - in6_clearscope(&oip6->ip6_src); - in6_clearscope(&oip6->ip6_dst); - - /* construct new IPv6 header. see RFC 2401 5.1.2.2 */ - /* ECN consideration. */ - ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); - if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr)) - ip6->ip6_plen = htons(plen); - else { - /* ip6->ip6_plen will be updated in ip6_output() */ - } - ip6->ip6_nxt = IPPROTO_IPV6; - - sa6 = *(struct sockaddr_in6 *)&sav->sah->saidx.src; - if ((error = sa6_embedscope(&sa6, 0)) != 0) - return (error); - ip6->ip6_src = sa6.sin6_addr; - - sa6 = *(struct sockaddr_in6 *)&sav->sah->saidx.dst; - if ((error = sa6_embedscope(&sa6, 0)) != 0) - return (error); - ip6->ip6_dst = sa6.sin6_addr; - - ip6->ip6_hlim = IPV6_DEFHLIM; - - /* XXX Should ip6_src be updated later ? */ - - return 0; -} -#endif /* INET6 */ - -/* - * Check the variable replay window. - * ipsec_chkreplay() performs replay check before ICV verification. - * ipsec_updatereplay() updates replay bitmap. This must be called after - * ICV verification (it also performs replay check, which is usually done - * beforehand). - * 0 (zero) is returned if packet disallowed, 1 if packet permitted. - * - * based on RFC 2401. - * - * XXX need to update for 64bit sequence number - 2401bis - */ -int -ipsec_chkreplay(seq, sav) - u_int32_t seq; - struct secasvar *sav; -{ - const struct secreplay *replay; - u_int32_t diff; - int fr; - u_int32_t wsizeb; /* constant: bits of window size */ - int frlast; /* constant: last frame */ - - /* sanity check */ - if (sav == NULL) - panic("ipsec_chkreplay: NULL pointer was passed."); - - replay = sav->replay; - - if (replay->wsize == 0) - return 1; /* no need to check replay. */ - - /* constant */ - frlast = replay->wsize - 1; - wsizeb = replay->wsize << 3; - - /* sequence number of 0 is invalid */ - if (seq == 0) - return 0; - - /* first time is always okay */ - if (replay->count == 0) - return 1; - - if (seq > replay->lastseq) { - /* larger sequences are okay */ - return 1; - } else { - /* seq is equal or less than lastseq. */ - diff = replay->lastseq - seq; - - /* over range to check, i.e. too old or wrapped */ - if (diff >= wsizeb) - return 0; - - fr = frlast - diff / 8; - - /* this packet already seen ? */ - if (replay->bitmap[fr] & (1 << (diff % 8))) - return 0; - - /* out of order but good */ - return 1; - } -} - -/* - * check replay counter whether to update or not. - * OUT: 0: OK - * 1: NG - * XXX need to update for 64bit sequence number - 2401bis - */ -int -ipsec_updatereplay(seq, sav) - u_int32_t seq; - struct secasvar *sav; -{ - struct secreplay *replay; - u_int64_t diff; - int fr; - u_int32_t wsizeb; /* constant: bits of window size */ - int frlast; /* constant: last frame */ - - /* sanity check */ - if (sav == NULL) - panic("ipsec_chkreplay: NULL pointer was passed."); - - replay = sav->replay; - - if (replay->wsize == 0) - goto ok; /* no need to check replay. */ - - /* constant */ - frlast = replay->wsize - 1; - wsizeb = replay->wsize << 3; - - /* sequence number of 0 is invalid */ - if (seq == 0) - return 1; - - /* first time */ - if (replay->count == 0) { - replay->lastseq = seq; - bzero(replay->bitmap, replay->wsize); - replay->bitmap[frlast] = 1; - goto ok; - } - - if (seq > replay->lastseq) { - /* seq is larger than lastseq. */ - diff = seq - replay->lastseq; - - /* new larger sequence number */ - if (diff < wsizeb) { - /* In window */ - /* set bit for this packet */ - vshiftl(replay->bitmap, diff, replay->wsize); - replay->bitmap[frlast] |= 1; - } else { - /* this packet has a "way larger" */ - bzero(replay->bitmap, replay->wsize); - replay->bitmap[frlast] = 1; - } - replay->lastseq = seq; - - /* larger is good */ - } else { - /* seq is equal or less than lastseq. */ - diff = replay->lastseq - seq; - - /* over range to check, i.e. too old or wrapped */ - if (diff >= wsizeb) - return 1; - - fr = frlast - diff / 8; - - /* this packet already seen ? */ - if (replay->bitmap[fr] & (1 << (diff % 8))) - return 1; - - /* mark as seen */ - replay->bitmap[fr] |= (1 << (diff % 8)); - - /* out of order but good */ - } - -ok: - if (replay->count == 0xffffffff) { - - /* set overflow flag */ - replay->overflow++; - - /* don't increment, no more packets accepted */ - if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) - return 1; - - ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n", - replay->overflow, ipsec_logsastr(sav))); - } - - replay->count++; - - return 0; -} - -/* - * shift variable length buffer to left. - * IN: bitmap: pointer to the buffer - * nbit: the number of to shift. - * wsize: buffer size (bytes). - */ -static void -vshiftl(bitmap, nbit, wsize) - unsigned char *bitmap; - int nbit, wsize; -{ - int s, j, i; - unsigned char over; - - for (j = 0; j < nbit; j += 8) { - s = (nbit - j < 8) ? (nbit - j): 8; - bitmap[0] <<= s; - for (i = 1; i < wsize; i++) { - over = (bitmap[i] >> (8 - s)); - bitmap[i] <<= s; - bitmap[i - 1] |= over; - } - } - - return; -} - -const char * -ipsec4_logpacketstr(ip, spi) - struct ip *ip; - u_int32_t spi; -{ - static char buf[256]; - char *p; - u_int8_t *s, *d; - - s = (u_int8_t *)(&ip->ip_src); - d = (u_int8_t *)(&ip->ip_dst); - - p = buf; - snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), "src=%u.%u.%u.%u", - s[0], s[1], s[2], s[3]); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), " dst=%u.%u.%u.%u", - d[0], d[1], d[2], d[3]); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), ")"); - - return buf; -} - -#ifdef INET6 -const char * -ipsec6_logpacketstr(ip6, spi) - struct ip6_hdr *ip6; - u_int32_t spi; -{ - static char buf[256]; - char ip6buf[INET6_ADDRSTRLEN]; - char *p; - - p = buf; - snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), "src=%s", - ip6_sprintf(ip6buf, &ip6->ip6_src)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), " dst=%s", - ip6_sprintf(ip6buf, &ip6->ip6_dst)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), ")"); - - return buf; -} -#endif /* INET6 */ - -const char * -ipsec_logsastr(sav) - struct secasvar *sav; -{ - static char buf[256]; - char *p; - struct secasindex *saidx = &sav->sah->saidx; - - /* validity check */ - if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family - != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) - panic("ipsec_logsastr: family mismatched."); - - p = buf; - snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi)); - while (*p) - p++; - if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET) { - u_int8_t *s, *d; - s = (u_int8_t *)&((struct sockaddr_in *)&saidx->src)->sin_addr; - d = (u_int8_t *)&((struct sockaddr_in *)&saidx->dst)->sin_addr; - snprintf(p, sizeof(buf) - (p - buf), - "src=%d.%d.%d.%d dst=%d.%d.%d.%d", - s[0], s[1], s[2], s[3], d[0], d[1], d[2], d[3]); - } -#ifdef INET6 - else if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET6) { - char ip6buf[INET6_ADDRSTRLEN]; - snprintf(p, sizeof(buf) - (p - buf), - "src=%s", - ip6_sprintf(ip6buf, - &((struct sockaddr_in6 *)&saidx->src)->sin6_addr)); - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), - " dst=%s", - ip6_sprintf(ip6buf, - &((struct sockaddr_in6 *)&saidx->dst)->sin6_addr)); - } -#endif - while (*p) - p++; - snprintf(p, sizeof(buf) - (p - buf), ")"); - - return buf; -} - -void -ipsec_dumpmbuf(m) - struct mbuf *m; -{ - int totlen; - int i; - u_char *p; - - totlen = 0; - printf("---\n"); - while (m) { - p = mtod(m, u_char *); - for (i = 0; i < m->m_len; i++) { - printf("%02x ", p[i]); - totlen++; - if (totlen % 16 == 0) - printf("\n"); - } - m = m->m_next; - } - if (totlen % 16 != 0) - printf("\n"); - printf("---\n"); -} - -#ifdef INET -static int -ipsec4_checksa(isr, state) - struct ipsecrequest *isr; - struct ipsec_output_state *state; -{ - struct ip *ip; - struct secasindex saidx; - struct sockaddr_in *sin; - - /* make SA index for search proper SA */ - ip = mtod(state->m, struct ip *); - bcopy(&isr->saidx, &saidx, sizeof(saidx)); - saidx.mode = isr->saidx.mode; - saidx.reqid = isr->saidx.reqid; - sin = (struct sockaddr_in *)&saidx.src; - if (sin->sin_len == 0) { - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = IPSEC_PORT_ANY; - bcopy(&ip->ip_src, &sin->sin_addr, sizeof(sin->sin_addr)); - } - sin = (struct sockaddr_in *)&saidx.dst; - if (sin->sin_len == 0) { - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = IPSEC_PORT_ANY; - bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(sin->sin_addr)); - } - - return key_checkrequest(isr, &saidx); -} -/* - * IPsec output logic for IPv4. - */ -int -ipsec4_output(state, sp, flags) - struct ipsec_output_state *state; - struct secpolicy *sp; - int flags; -{ - struct ip *ip = NULL; - struct ipsecrequest *isr = NULL; - int s; - int error; - struct sockaddr_in *dst4; - - if (!state) - panic("state == NULL in ipsec4_output"); - if (!state->m) - panic("state->m == NULL in ipsec4_output"); - if (!state->ro) - panic("state->ro == NULL in ipsec4_output"); - if (!state->dst) - panic("state->dst == NULL in ipsec4_output"); - state->encap = 0; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec4_output: applyed SP\n"); - kdebug_secpolicy(sp)); - - for (isr = sp->req; isr != NULL; isr = isr->next) { - -#if 0 /* give up to check restriction of transport mode */ - /* XXX but should be checked somewhere */ - /* - * some of the IPsec operation must be performed only in - * originating case. - */ - if (isr->saidx.mode == IPSEC_MODE_TRANSPORT - && (flags & IP_FORWARDING)) - continue; -#endif - error = ipsec4_checksa(isr, state); - if (error != 0) { - /* - * IPsec processing is required, but no SA found. - * I assume that key_acquire() had been called - * to get/establish the SA. Here I discard - * this packet because it is responsibility for - * upper layer to retransmit the packet. - */ - ipsecstat.out_nosa++; - goto bad; - } - - /* validity check */ - if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr, AF_INET)) { - case IPSEC_LEVEL_USE: - continue; - case IPSEC_LEVEL_REQUIRE: - /* must be not reached here. */ - panic("ipsec4_output: no SA found, but required."); - } - } - - /* - * If there is no valid SA, we give up to process any - * more. In such a case, the SA's status is changed - * from DYING to DEAD after allocating. If a packet - * send to the receiver by dead SA, the receiver can - * not decode a packet because SA has been dead. - */ - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) { - ipsecstat.out_nosa++; - error = EINVAL; - goto bad; - } - - /* - * There may be the case that SA status will be changed when - * we are refering to one. So calling splsoftnet(). - */ - s = splnet(); - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* - * build IPsec tunnel. - */ - /* XXX should be processed with other familiy */ - if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET) { - ipseclog((LOG_ERR, "ipsec4_output: " - "family mismatched between inner and outer spi=%u\n", - (u_int32_t)ntohl(isr->sav->spi))); - splx(s); - error = EAFNOSUPPORT; - goto bad; - } - - state->m = ipsec4_splithdr(state->m); - if (!state->m) { - splx(s); - error = ENOMEM; - goto bad; - } - error = ipsec4_encapsulate(state->m, isr->sav); - splx(s); - if (error) { - state->m = NULL; - goto bad; - } - ip = mtod(state->m, struct ip *); - - state->ro = &isr->sav->sah->sa_route; - state->dst = (struct sockaddr *)&state->ro->ro_dst; - dst4 = (struct sockaddr_in *)state->dst; - if (state->ro->ro_rt - && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0 - || dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) { - RTFREE(state->ro->ro_rt); - state->ro->ro_rt = NULL; - } - if (state->ro->ro_rt == 0) { - dst4->sin_family = AF_INET; - dst4->sin_len = sizeof(*dst4); - dst4->sin_addr = ip->ip_dst; - rtalloc(state->ro); - } - if (state->ro->ro_rt == 0) { - ipstat.ips_noroute++; - error = EHOSTUNREACH; - goto bad; - } - - /* adjust state->dst if tunnel endpoint is offlink */ - if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { - state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; - dst4 = (struct sockaddr_in *)state->dst; - } - - state->encap++; - } else - splx(s); - - state->m = ipsec4_splithdr(state->m); - if (!state->m) { - error = ENOMEM; - goto bad; - } - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - if ((error = esp4_output(state->m, isr)) != 0) { - state->m = NULL; - goto bad; - } - break; -#else - m_freem(state->m); - state->m = NULL; - error = EINVAL; - goto bad; -#endif - case IPPROTO_AH: - if ((error = ah4_output(state->m, isr)) != 0) { - state->m = NULL; - goto bad; - } - break; - case IPPROTO_IPCOMP: - if ((error = ipcomp4_output(state->m, isr)) != 0) { - state->m = NULL; - goto bad; - } - break; - default: - ipseclog((LOG_ERR, - "ipsec4_output: unknown ipsec protocol %d\n", - isr->saidx.proto)); - m_freem(state->m); - state->m = NULL; - error = EINVAL; - goto bad; - } - - if (state->m == 0) { - error = ENOMEM; - goto bad; - } - ip = mtod(state->m, struct ip *); - } - - return 0; - -bad: - m_freem(state->m); - state->m = NULL; - return error; -} -#endif - -#ifdef INET6 -static int -ipsec6_checksa(isr, state, tunnel) - struct ipsecrequest *isr; - struct ipsec_output_state *state; - int tunnel; -{ - struct ip6_hdr *ip6; - struct secasindex saidx; - struct sockaddr_in6 *sin6; - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { -#ifdef DIAGNOSTIC - if (!tunnel) - panic("ipsec6_checksa/inconsistent tunnel attribute"); -#endif - /* When tunnel mode, SA peers must be specified. */ - return key_checkrequest(isr, &isr->saidx); - } - - /* make SA index for search proper SA */ - ip6 = mtod(state->m, struct ip6_hdr *); - if (tunnel) { - bzero(&saidx, sizeof(saidx)); - saidx.proto = isr->saidx.proto; - } else - bcopy(&isr->saidx, &saidx, sizeof(saidx)); - saidx.mode = isr->saidx.mode; - saidx.reqid = isr->saidx.reqid; - sin6 = (struct sockaddr_in6 *)&saidx.src; - if (sin6->sin6_len == 0 || tunnel) { - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = IPSEC_PORT_ANY; - sin6->sin6_addr = ip6->ip6_src; - } - sin6 = (struct sockaddr_in6 *)&saidx.dst; - if (sin6->sin6_len == 0 || tunnel) { - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = IPSEC_PORT_ANY; - sin6->sin6_addr = ip6->ip6_dst; - } - - return key_checkrequest(isr, &saidx); -} - -/* - * IPsec output logic for IPv6, transport mode. - */ -int -ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) - struct ipsec_output_state *state; - u_char *nexthdrp; - struct mbuf *mprev; - struct secpolicy *sp; - int flags; - int *tun; -{ - struct ip6_hdr *ip6; - struct ipsecrequest *isr = NULL; - int error = 0; - int plen; - - if (!state) - panic("state == NULL in ipsec6_output_trans"); - if (!state->m) - panic("state->m == NULL in ipsec6_output_trans"); - if (!nexthdrp) - panic("nexthdrp == NULL in ipsec6_output_trans"); - if (!mprev) - panic("mprev == NULL in ipsec6_output_trans"); - if (!sp) - panic("sp == NULL in ipsec6_output_trans"); - if (!tun) - panic("tun == NULL in ipsec6_output_trans"); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output_trans: applyed SP\n"); - kdebug_secpolicy(sp)); - - *tun = 0; - for (isr = sp->req; isr; isr = isr->next) { - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* the rest will be handled by ipsec6_output_tunnel() */ - break; - } - - error = ipsec6_checksa(isr, state, 0); - if (error == EIO) - goto bad; - if (error == ENOENT) { - /* - * IPsec processing is required, but no SA found. - * I assume that key_acquire() had been called - * to get/establish the SA. Here I discard - * this packet because it is responsibility for - * upper layer to retransmit the packet. - */ - ipsec6stat.out_nosa++; - - /* - * Notify the fact that the packet is discarded - * to ourselves. I believe this is better than - * just silently discarding. (jinmei@kame.net) - * XXX: should we restrict the error to TCP packets? - * XXX: should we directly notify sockets via - * pfctlinputs? - * - * Noone have initialized rcvif until this point, - * so clear it. - */ - if ((state->m->m_flags & M_PKTHDR) != 0) - state->m->m_pkthdr.rcvif = NULL; - icmp6_error(state->m, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADMIN, 0); - state->m = NULL; /* icmp6_error freed the mbuf */ - goto bad; - } - - /* validity check */ - if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr, AF_INET6)) { - case IPSEC_LEVEL_USE: - continue; - case IPSEC_LEVEL_REQUIRE: - /* must be not reached here. */ - panic("ipsec6_output_trans: no SA found, but required."); - } - } - - /* - * If there is no valid SA, we give up to process. - * see same place at ipsec4_output(). - */ - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) { - ipsec6stat.out_nosa++; - error = EINVAL; - goto bad; - } - - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - error = esp6_output(state->m, nexthdrp, mprev->m_next, isr); -#else - m_freem(state->m); - error = EINVAL; -#endif - break; - case IPPROTO_AH: - error = ah6_output(state->m, nexthdrp, mprev->m_next, isr); - break; - case IPPROTO_IPCOMP: - error = ipcomp6_output(state->m, nexthdrp, mprev->m_next, isr); - break; - default: - ipseclog((LOG_ERR, "ipsec6_output_trans: " - "unknown ipsec protocol %d\n", isr->saidx.proto)); - m_freem(state->m); - ipsec6stat.out_inval++; - error = EINVAL; - break; - } - if (error) { - state->m = NULL; - goto bad; - } - plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); - if (plen > IPV6_MAXPACKET) { - ipseclog((LOG_ERR, "ipsec6_output_trans: " - "IPsec with IPv6 jumbogram is not supported\n")); - ipsec6stat.out_inval++; - error = EINVAL; /* XXX */ - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - ip6->ip6_plen = htons(plen); - } - - /* if we have more to go, we need a tunnel mode processing */ - if (isr != NULL) - *tun = 1; - - return 0; - -bad: - m_freem(state->m); - state->m = NULL; - return error; -} - -/* - * IPsec output logic for IPv6, tunnel mode. - */ -int -ipsec6_output_tunnel(state, sp, flags) - struct ipsec_output_state *state; - struct secpolicy *sp; - int flags; -{ - struct ip6_hdr *ip6; - struct ipsecrequest *isr = NULL; - int error = 0; - int plen; - struct sockaddr_in6 *dst6; - int s; - - if (!state) - panic("state == NULL in ipsec6_output_tunnel"); - if (!state->m) - panic("state->m == NULL in ipsec6_output_tunnel"); - if (!sp) - panic("sp == NULL in ipsec6_output_tunnel"); - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("ipsec6_output_tunnel: applyed SP\n"); - kdebug_secpolicy(sp)); - - /* - * transport mode ipsec (before the 1st tunnel mode) is already - * processed by ipsec6_output_trans(). - */ - for (isr = sp->req; isr; isr = isr->next) { - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) - break; - } - - for (/* already initialized */; isr; isr = isr->next) { - error = ipsec6_checksa(isr, state, 1); - if (error == EIO) - goto bad; - if (error == ENOENT) { - /* - * IPsec processing is required, but no SA found. - * I assume that key_acquire() had been called - * to get/establish the SA. Here I discard - * this packet because it is responsibility for - * upper layer to retransmit the packet. - */ - ipsec6stat.out_nosa++; - error = ENOENT; - goto bad; - } - - /* validity check */ - if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr, AF_INET6)) { - case IPSEC_LEVEL_USE: - continue; - case IPSEC_LEVEL_REQUIRE: - /* must be not reached here. */ - panic("ipsec6_output_tunnel: no SA found, but required."); - } - } - - /* - * If there is no valid SA, we give up to process. - * see same place at ipsec4_output(). - */ - if (isr->sav->state != SADB_SASTATE_MATURE - && isr->sav->state != SADB_SASTATE_DYING) { - ipsec6stat.out_nosa++; - error = EINVAL; - goto bad; - } - - /* - * There may be the case that SA status will be changed when - * we are refering to one. So calling splsoftnet(). - */ - s = splnet(); - - if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { - /* - * build IPsec tunnel. - */ - /* XXX should be processed with other familiy */ - if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET6) { - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "family mismatched between inner and outer, spi=%u\n", - (u_int32_t)ntohl(isr->sav->spi))); - splx(s); - ipsec6stat.out_inval++; - error = EAFNOSUPPORT; - goto bad; - } - - state->m = ipsec6_splithdr(state->m); - if (!state->m) { - splx(s); - ipsec6stat.out_nomem++; - error = ENOMEM; - goto bad; - } - error = ipsec6_encapsulate(state->m, isr->sav); - splx(s); - if (error) { - state->m = 0; - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - - state->ro = &isr->sav->sah->sa_route; - state->dst = (struct sockaddr *)&state->ro->ro_dst; - dst6 = (struct sockaddr_in6 *)state->dst; - if (state->ro->ro_rt && - (!(state->ro->ro_rt->rt_flags & RTF_UP) || - !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, - &ip6->ip6_dst))) { - RTFREE(state->ro->ro_rt); - state->ro->ro_rt = NULL; - } - if (state->ro->ro_rt == 0) { - bzero(dst6, sizeof(*dst6)); - dst6->sin6_family = AF_INET6; - dst6->sin6_len = sizeof(*dst6); - dst6->sin6_addr = ip6->ip6_dst; - rtalloc(state->ro); - } - if (state->ro->ro_rt == 0) { - ip6stat.ip6s_noroute++; - ipsec6stat.out_noroute++; - error = EHOSTUNREACH; - goto bad; - } - - /* adjust state->dst if tunnel endpoint is offlink */ - if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) { - state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway; - dst6 = (struct sockaddr_in6 *)state->dst; - } - } else - splx(s); - - state->m = ipsec6_splithdr(state->m); - if (!state->m) { - ipsec6stat.out_nomem++; - error = ENOMEM; - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - switch (isr->saidx.proto) { - case IPPROTO_ESP: -#ifdef IPSEC_ESP - error = esp6_output(state->m, &ip6->ip6_nxt, - state->m->m_next, isr); -#else - m_freem(state->m); - error = EINVAL; -#endif - break; - case IPPROTO_AH: - error = ah6_output(state->m, &ip6->ip6_nxt, - state->m->m_next, isr); - break; - case IPPROTO_IPCOMP: - /* XXX code should be here */ - /* FALLTHROUGH */ - default: - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "unknown ipsec protocol %d\n", isr->saidx.proto)); - m_freem(state->m); - ipsec6stat.out_inval++; - error = EINVAL; - break; - } - if (error) { - state->m = NULL; - goto bad; - } - plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr); - if (plen > IPV6_MAXPACKET) { - ipseclog((LOG_ERR, "ipsec6_output_tunnel: " - "IPsec with IPv6 jumbogram is not supported\n")); - ipsec6stat.out_inval++; - error = EINVAL; /* XXX */ - goto bad; - } - ip6 = mtod(state->m, struct ip6_hdr *); - ip6->ip6_plen = htons(plen); - } - - return 0; - -bad: - m_freem(state->m); - state->m = NULL; - return error; -} -#endif /* INET6 */ - -#ifdef INET -/* - * Chop IP header and option off from the payload. - */ -static struct mbuf * -ipsec4_splithdr(m) - struct mbuf *m; -{ - struct mbuf *mh; - struct ip *ip; - int hlen; - - if (m->m_len < sizeof(struct ip)) - panic("ipsec4_splithdr: first mbuf too short"); - 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) { - MGETHDR(mh, M_DONTWAIT, MT_HEADER); - if (!mh) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(mh, m); - MH_ALIGN(mh, hlen); - m->m_len -= hlen; - m->m_data += hlen; - mh->m_next = m; - m = mh; - m->m_len = hlen; - bcopy((caddr_t)ip, mtod(m, caddr_t), hlen); - } else if (m->m_len < hlen) { - m = m_pullup(m, hlen); - if (!m) - return NULL; - } - return m; -} -#endif - -#ifdef INET6 -static struct mbuf * -ipsec6_splithdr(m) - struct mbuf *m; -{ - struct mbuf *mh; - struct ip6_hdr *ip6; - int hlen; - - if (m->m_len < sizeof(struct ip6_hdr)) - panic("ipsec6_splithdr: first mbuf too short"); - ip6 = mtod(m, struct ip6_hdr *); - hlen = sizeof(struct ip6_hdr); - if (m->m_len > hlen) { - MGETHDR(mh, M_DONTWAIT, MT_HEADER); - if (!mh) { - m_freem(m); - return NULL; - } - M_MOVE_PKTHDR(mh, m); - MH_ALIGN(mh, hlen); - m->m_len -= hlen; - m->m_data += hlen; - mh->m_next = m; - m = mh; - m->m_len = hlen; - bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen); - } else if (m->m_len < hlen) { - m = m_pullup(m, hlen); - if (!m) - return NULL; - } - return m; -} -#endif - -/* validate inbound IPsec tunnel packet. */ -int -ipsec4_tunnel_validate(m, off, nxt0, sav) - struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ - int off; - u_int nxt0; - struct secasvar *sav; -{ - u_int8_t nxt = nxt0 & 0xff; - struct sockaddr_in *sin; - struct sockaddr_in osrc, odst, isrc, idst; - int hlen; - struct secpolicy *sp; - struct ip *oip; - -#ifdef DIAGNOSTIC - if (m->m_len < sizeof(struct ip)) - panic("too short mbuf on ipsec4_tunnel_validate"); -#endif - if (nxt != IPPROTO_IPV4) - return 0; - if (m->m_pkthdr.len < off + sizeof(struct ip)) - return 0; - /* do not decapsulate if the SA is for transport mode only */ - if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) - return 0; - - oip = mtod(m, struct ip *); - hlen = oip->ip_hl << 2; - if (hlen != sizeof(struct ip)) - return 0; - - /* AF_INET6 should be supported, but at this moment we don't. */ - sin = (struct sockaddr_in *)&sav->sah->saidx.dst; - if (sin->sin_family != AF_INET) - return 0; - if (bcmp(&oip->ip_dst, &sin->sin_addr, sizeof(oip->ip_dst)) != 0) - return 0; - - /* XXX slow */ - bzero(&osrc, sizeof(osrc)); - bzero(&odst, sizeof(odst)); - bzero(&isrc, sizeof(isrc)); - bzero(&idst, sizeof(idst)); - osrc.sin_family = odst.sin_family = isrc.sin_family = idst.sin_family = - AF_INET; - osrc.sin_len = odst.sin_len = isrc.sin_len = idst.sin_len = - sizeof(struct sockaddr_in); - osrc.sin_addr = oip->ip_src; - odst.sin_addr = oip->ip_dst; - m_copydata(m, off + offsetof(struct ip, ip_src), sizeof(isrc.sin_addr), - (caddr_t)&isrc.sin_addr); - m_copydata(m, off + offsetof(struct ip, ip_dst), sizeof(idst.sin_addr), - (caddr_t)&idst.sin_addr); - - /* - * RFC2401 5.2.1 (b): (assume that we are using tunnel mode) - * - if the inner destination is multicast address, there can be - * multiple permissible inner source address. implementation - * may want to skip verification of inner source address against - * SPD selector. - * - if the inner protocol is ICMP, the packet may be an error report - * from routers on the other side of the VPN cloud (R in the - * following diagram). in this case, we cannot verify inner source - * address against SPD selector. - * me -- gw === gw -- R -- you - * - * we consider the first bullet to be users responsibility on SPD entry - * configuration (if you need to encrypt multicast traffic, set - * the source range of SPD selector to 0.0.0.0/0, or have explicit - * address ranges for possible senders). - * the second bullet is not taken care of (yet). - * - * therefore, we do not do anything special about inner source. - */ - - sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, - (struct sockaddr *)&isrc, (struct sockaddr *)&idst); - /* - * when there is no suitable inbound policy for the packet of the ipsec - * tunnel mode, the kernel never decapsulate the tunneled packet - * as the ipsec tunnel mode even when the system wide policy is "none". - * then the kernel leaves the generic tunnel module to process this - * packet. if there is no rule of the generic tunnel, the packet - * is rejected and the statistics will be counted up. - */ - if (!sp) - return 0; - key_freesp(sp); - - return 1; -} - -#ifdef INET6 -/* validate inbound IPsec tunnel packet. */ -int -ipsec6_tunnel_validate(m, off, nxt0, sav) - struct mbuf *m; /* no pullup permitted, m->m_len >= ip */ - int off; - u_int nxt0; - struct secasvar *sav; -{ - u_int8_t nxt = nxt0 & 0xff; - struct sockaddr_in6 *sin6; - struct sockaddr_in6 osrc, odst, isrc, idst; - struct secpolicy *sp; - struct ip6_hdr *oip6; - -#ifdef DIAGNOSTIC - if (m->m_len < sizeof(struct ip6_hdr)) - panic("too short mbuf on ipsec6_tunnel_validate"); -#endif - if (nxt != IPPROTO_IPV6) - return 0; - if (m->m_pkthdr.len < off + sizeof(struct ip6_hdr)) - return 0; - /* do not decapsulate if the SA is for transport mode only */ - if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT) - return 0; - - oip6 = mtod(m, struct ip6_hdr *); - - /* AF_INET should be supported, but at this moment we don't. */ - sin6 = (struct sockaddr_in6 *)&sav->sah->saidx.dst; - if (sin6->sin6_family != AF_INET6) - return 0; - if (!IN6_ARE_ADDR_EQUAL(&oip6->ip6_dst, &sin6->sin6_addr)) - return 0; - - /* XXX slow */ - bzero(&osrc, sizeof(osrc)); - bzero(&odst, sizeof(odst)); - bzero(&isrc, sizeof(isrc)); - bzero(&idst, sizeof(idst)); - osrc.sin6_family = odst.sin6_family = isrc.sin6_family = - idst.sin6_family = AF_INET6; - osrc.sin6_len = odst.sin6_len = isrc.sin6_len = idst.sin6_len = - sizeof(struct sockaddr_in6); - osrc.sin6_addr = oip6->ip6_src; - odst.sin6_addr = oip6->ip6_dst; - m_copydata(m, off + offsetof(struct ip6_hdr, ip6_src), - sizeof(isrc.sin6_addr), (caddr_t)&isrc.sin6_addr); - m_copydata(m, off + offsetof(struct ip6_hdr, ip6_dst), - sizeof(idst.sin6_addr), (caddr_t)&idst.sin6_addr); - - /* - * regarding to inner source address validation, see a long comment - * in ipsec4_tunnel_validate. - */ - - sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, - (struct sockaddr *)&isrc, (struct sockaddr *)&idst); - if (!sp) - return 0; - key_freesp(sp); - - return 1; -} -#endif - -/* - * Make a mbuf chain for encryption. - * If the original mbuf chain contains a mbuf with a cluster, - * allocate a new cluster and copy the data to the new cluster. - * XXX: this hack is inefficient, but is necessary to handle cases - * of TCP retransmission... - */ -struct mbuf * -ipsec_copypkt(m) - struct mbuf *m; -{ - struct mbuf *n, **mpp, *mnew; - - for (n = m, mpp = &m; n; n = n->m_next) { - if (n->m_flags & M_EXT) { - /* - * Make a copy only if there is more than one - * references to the cluster. - * XXX: is this approach effective? - */ - if (!M_WRITABLE(n)) { - int remain, copied; - struct mbuf *mm; - - if (n->m_flags & M_PKTHDR) { - MGETHDR(mnew, M_DONTWAIT, MT_HEADER); - if (mnew == NULL) - goto fail; - M_MOVE_PKTHDR(mnew, n); - } - else { - MGET(mnew, M_DONTWAIT, MT_DATA); - if (mnew == NULL) - goto fail; - } - mnew->m_len = 0; - mm = mnew; - - /* - * Copy data. If we don't have enough space to - * store the whole data, allocate a cluster - * or additional mbufs. - * XXX: we don't use m_copyback(), since the - * function does not use clusters and thus is - * inefficient. - */ - remain = n->m_len; - copied = 0; - while (1) { - int len; - struct mbuf *mn; - - if (remain <= (mm->m_flags & M_PKTHDR ? MHLEN : MLEN)) - len = remain; - else { /* allocate a cluster */ - MCLGET(mm, M_DONTWAIT); - if (!(mm->m_flags & M_EXT)) { - m_free(mm); - goto fail; - } - len = remain < MCLBYTES ? - remain : MCLBYTES; - } - - bcopy(n->m_data + copied, mm->m_data, - len); - - copied += len; - remain -= len; - mm->m_len = len; - - if (remain <= 0) /* completed? */ - break; - - /* need another mbuf */ - MGETHDR(mn, M_DONTWAIT, MT_HEADER); - if (mn == NULL) - goto fail; - mn->m_pkthdr.rcvif = NULL; - mm->m_next = mn; - mm = mn; - } - - /* adjust chain */ - mm->m_next = m_free(n); - n = mm; - *mpp = mnew; - mpp = &n->m_next; - - continue; - } - } - *mpp = n; - mpp = &n->m_next; - } - - return (m); - fail: - m_freem(m); - return (NULL); -} - -static struct ipsecaux * -ipsec_addaux(m) - struct mbuf *m; -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL); - if (mtag == NULL) { - mtag = m_tag_get(PACKET_TAG_IPSEC_HISTORY, - sizeof(struct ipsecaux), M_NOWAIT); - if (mtag != NULL) - m_tag_prepend(m, mtag); - } - if (mtag == NULL) - return NULL; /* ENOBUFS */ - /* XXX is this necessary? */ - bzero((void *)(mtag + 1), sizeof(struct ipsecaux)); - return mtag ? (struct ipsecaux *)(mtag + 1) : NULL; -} - -static struct ipsecaux * -ipsec_findaux(m) - struct mbuf *m; -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL); - return mtag ? (struct ipsecaux *)(mtag + 1) : NULL; -} - -void -ipsec_delaux(m) - struct mbuf *m; -{ - struct m_tag *mtag; - - mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL); - if (mtag != NULL) - m_tag_delete(m, mtag); -} - -/* if the aux buffer is unnecessary, nuke it. */ -static void -ipsec_optaux(m, aux) - struct mbuf *m; - struct ipsecaux *aux; -{ - - if (aux == NULL) - return; - ipsec_delaux(m); -} - -int -ipsec_addhist(m, proto, spi) - struct mbuf *m; - int proto; - u_int32_t spi; -{ - struct ipsecaux *aux; - - aux = ipsec_addaux(m); - if (aux == NULL) - return ENOBUFS; - aux->hdrs++; - return 0; -} - -int -ipsec_getnhist(m) - struct mbuf *m; -{ - struct ipsecaux *aux; - - aux = ipsec_findaux(m); - if (aux == NULL) - return 0; - return aux->hdrs; -} - -void -ipsec_clearhist(m) - struct mbuf *m; -{ - struct ipsecaux *aux; - - aux = ipsec_findaux(m); - ipsec_optaux(m, aux); -} diff --git a/sys/netkey/key.c b/sys/netkey/key.c deleted file mode 100644 index d41ad96..0000000 --- a/sys/netkey/key.c +++ /dev/null @@ -1,7647 +0,0 @@ -/* $KAME: key.c,v 1.308 2003/09/07 20:35:59 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$"); - -/* - * This code is referd to RFC 2367 - */ - -#include "opt_inet.h" -#include "opt_inet6.h" -#include "opt_ipsec.h" - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/mbuf.h> -#include <sys/domain.h> -#include <sys/protosw.h> -#include <sys/malloc.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/sysctl.h> -#include <sys/errno.h> -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> -#include <net/raw_cb.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/in6_var.h> -#include <netinet6/ip6_var.h> -#include <netinet6/scope6_var.h> -#endif /* INET6 */ - -#ifdef INET -#include <netinet/in_pcb.h> -#endif -#ifdef INET6 -#include <netinet6/in6_pcb.h> -#endif /* INET6 */ - -#include <net/pfkeyv2.h> -#include <netkey/keydb.h> -#include <netkey/key.h> -#include <netkey/keysock.h> -#include <netkey/key_debug.h> - -#include <netinet6/ipsec.h> -#ifdef INET6 -#include <netinet6/ipsec6.h> -#endif -#include <netinet6/ah.h> -#ifdef INET6 -#include <netinet6/ah6.h> -#endif -#ifdef IPSEC_ESP -#include <netinet6/esp.h> -#ifdef INET6 -#include <netinet6/esp6.h> -#endif -#endif -#include <netinet6/ipcomp.h> -#ifdef INET6 -#include <netinet6/ipcomp6.h> -#endif - -#include <machine/stdarg.h> - -/* randomness */ -#include <sys/random.h> - -#ifndef satosin -#define satosin(s) ((struct sockaddr_in *)s) -#endif - -#define FULLMASK 0xff - -/* - * Note on SA reference counting: - * - SAs that are not in DEAD state will have (total external reference + 1) - * following value in reference count field. they cannot be freed and are - * referenced from SA header. - * - SAs that are in DEAD state will have (total external reference) - * in reference count field. they are ready to be freed. reference from - * SA header will be removed in keydb_delsecasvar(), when the reference count - * field hits 0 (= no external reference other than from SA header. - */ - -u_int32_t key_debug_level = 0; -static u_int key_spi_trycnt = 1000; -static u_int32_t key_spi_minval = 0x100; -static u_int32_t key_spi_maxval = 0x0fffffff; /* XXX */ -static u_int key_larval_lifetime = 30; /* interval to expire acquiring, 30(s)*/ -static int key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/ -static int key_blockacq_lifetime = 20; /* lifetime for blocking SADB_ACQUIRE.*/ -static int key_preferred_oldsa = 1; /* preferred old sa rather than new sa.*/ - -static u_int32_t acq_seq = 0; - -struct _satailq satailq; /* list of all SAD entry */ -struct _sptailq sptailq; /* SPD table + pcb */ -static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD table */ -static LIST_HEAD(_sahtree, secashead) sahtree; /* SAD */ -static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1]; - /* registed list */ - -#define SPIHASHSIZE 128 -#define SPIHASH(x) (((x) ^ ((x) >> 16)) % SPIHASHSIZE) -static LIST_HEAD(_spihash, secasvar) spihash[SPIHASHSIZE]; - -#ifndef IPSEC_NONBLOCK_ACQUIRE -static LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */ -#endif -static LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP acquiring list */ - -struct key_cb key_cb; - -/* search order for SAs */ -static const u_int saorder_state_valid_prefer_old[] = { - SADB_SASTATE_DYING, SADB_SASTATE_MATURE, -}; -static const u_int saorder_state_valid_prefer_new[] = { - SADB_SASTATE_MATURE, SADB_SASTATE_DYING, -}; -static const u_int saorder_state_alive[] = { - /* except DEAD */ - SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL -}; -static const u_int saorder_state_any[] = { - SADB_SASTATE_MATURE, SADB_SASTATE_DYING, - SADB_SASTATE_LARVAL, SADB_SASTATE_DEAD -}; - -static const int minsize[] = { - sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */ - sizeof(struct sadb_sa), /* SADB_EXT_SA */ - sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_CURRENT */ - sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_HARD */ - sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_SOFT */ - sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_SRC */ - sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_DST */ - sizeof(struct sadb_address), /* SADB_EXT_ADDRESS_PROXY */ - sizeof(struct sadb_key), /* SADB_EXT_KEY_AUTH */ - sizeof(struct sadb_key), /* SADB_EXT_KEY_ENCRYPT */ - sizeof(struct sadb_ident), /* SADB_EXT_IDENTITY_SRC */ - sizeof(struct sadb_ident), /* SADB_EXT_IDENTITY_DST */ - sizeof(struct sadb_sens), /* SADB_EXT_SENSITIVITY */ - sizeof(struct sadb_prop), /* SADB_EXT_PROPOSAL */ - sizeof(struct sadb_supported), /* SADB_EXT_SUPPORTED_AUTH */ - sizeof(struct sadb_supported), /* SADB_EXT_SUPPORTED_ENCRYPT */ - sizeof(struct sadb_spirange), /* SADB_EXT_SPIRANGE */ - 0, /* SADB_X_EXT_KMPRIVATE */ - sizeof(struct sadb_x_policy), /* SADB_X_EXT_POLICY */ - sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ -}; -static const int maxsize[] = { - sizeof(struct sadb_msg), /* SADB_EXT_RESERVED */ - sizeof(struct sadb_sa), /* SADB_EXT_SA */ - sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_CURRENT */ - sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_HARD */ - sizeof(struct sadb_lifetime), /* SADB_EXT_LIFETIME_SOFT */ - 0, /* SADB_EXT_ADDRESS_SRC */ - 0, /* SADB_EXT_ADDRESS_DST */ - 0, /* SADB_EXT_ADDRESS_PROXY */ - 0, /* SADB_EXT_KEY_AUTH */ - 0, /* SADB_EXT_KEY_ENCRYPT */ - 0, /* SADB_EXT_IDENTITY_SRC */ - 0, /* SADB_EXT_IDENTITY_DST */ - 0, /* SADB_EXT_SENSITIVITY */ - 0, /* SADB_EXT_PROPOSAL */ - 0, /* SADB_EXT_SUPPORTED_AUTH */ - 0, /* SADB_EXT_SUPPORTED_ENCRYPT */ - sizeof(struct sadb_spirange), /* SADB_EXT_SPIRANGE */ - 0, /* SADB_X_EXT_KMPRIVATE */ - 0, /* SADB_X_EXT_POLICY */ - sizeof(struct sadb_x_sa2), /* SADB_X_SA2 */ -}; - -static int ipsec_esp_keymin = 256; -#ifdef IPSEC_ESP -static int ipsec_esp_auth = 0; -#endif -static int ipsec_ah_keymin = 128; - -SYSCTL_DECL(_net_key); - -SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ - &key_debug_level, 0, ""); - -/* max count of trial for the decision of spi value */ -SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ - &key_spi_trycnt, 0, ""); - -/* minimum spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ - &key_spi_minval, 0, ""); - -/* maximun spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ - &key_spi_maxval, 0, ""); - -/* lifetime for larval SA */ -SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ - &key_larval_lifetime, 0, ""); - -/* counter for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ - &key_blockacq_count, 0, ""); - -/* lifetime for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ - &key_blockacq_lifetime, 0, ""); - -#ifdef IPSEC_ESP -/* ESP auth */ -SYSCTL_INT(_net_key, KEYCTL_ESP_AUTH, esp_auth, CTLFLAG_RW, \ - &ipsec_esp_auth, 0, "ESP auth"); -#endif - -/* minimum ESP key length */ -SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \ - &ipsec_esp_keymin, 0, ""); - -/* minimum AH key length */ -SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \ - &ipsec_ah_keymin, 0, ""); - -/* perfered old SA rather than new SA */ -SYSCTL_INT(_net_key, KEYCTL_PREFERED_OLDSA, preferred_oldsa, CTLFLAG_RW,\ - &key_preferred_oldsa, 0, ""); - -#define __LIST_CHAINED(elm) \ - (!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL)) -#define LIST_INSERT_TAIL(head, elm, type, field) \ -do {\ - struct type *curelm = LIST_FIRST(head); \ - if (curelm == NULL) {\ - LIST_INSERT_HEAD(head, elm, field); \ - } else { \ - while (LIST_NEXT(curelm, field)) \ - curelm = LIST_NEXT(curelm, field);\ - LIST_INSERT_AFTER(curelm, elm, field);\ - }\ -} while (/*CONSTCOND*/ 0) - -#define KEY_CHKSASTATE(head, sav, name) \ -do { \ - if ((head) != (sav)) { \ - ipseclog((LOG_DEBUG, "%s: state mismatched (TREE=%u SA=%u)\n", \ - (name), (head), (sav))); \ - continue; \ - } \ -} while (/*CONSTCOND*/ 0) - -#define KEY_CHKSPDIR(head, sp, name) \ -do { \ - if ((head) != (sp)) { \ - ipseclog((LOG_DEBUG, "%s: direction mismatched (TREE=%u SP=%u), " \ - "anyway continue.\n", \ - (name), (head), (sp))); \ - } \ -} while (/*CONSTCOND*/ 0) - -#if 1 -#define KMALLOC(p, t, n) \ - ((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT)) -#define KFREE(p) \ - free((caddr_t)(p), M_SECA) -#else -#define KMALLOC(p, t, n) \ -do { \ - ((p) = (t)malloc((unsigned long)(n), M_SECA, M_NOWAIT)); \ - printf("%s %d: %p <- KMALLOC(%s, %d)\n", \ - __FILE__, __LINE__, (p), #t, n); \ -} while (/*CONSTCOND*/ 0) - -#define KFREE(p) \ - do { \ - printf("%s %d: %p -> KFREE()\n", __FILE__, __LINE__, (p)); \ - free((caddr_t)(p), M_SECA); \ - } while (/*CONSTCOND*/ 0) -#endif - -/* - * set parameters into secpolicyindex buffer. - * Must allocate secpolicyindex buffer passed to this function. - */ -#define KEY_SETSECSPIDX(s, d, ps, pd, ulp, idx) \ -do { \ - bzero((idx), sizeof(struct secpolicyindex)); \ - (idx)->prefs = (ps); \ - (idx)->prefd = (pd); \ - (idx)->ul_proto = (ulp); \ - bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ - bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ -} while (/*CONSTCOND*/ 0) - -/* - * set parameters into secasindex buffer. - * Must allocate secasindex buffer before calling this function. - */ -#define KEY_SETSECASIDX(p, m, r, s, d, idx) \ -do { \ - bzero((idx), sizeof(struct secasindex)); \ - (idx)->proto = (p); \ - (idx)->mode = (m); \ - (idx)->reqid = (r); \ - bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \ - bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \ -} while (/*CONSTCOND*/ 0) - -/* key statistics */ -struct _keystat { - u_long getspi_count; /* the avarage of count to try to get new SPI */ -} keystat; - -struct sadb_msghdr { - struct sadb_msg *msg; - struct sadb_ext *ext[SADB_EXT_MAX + 1]; - int extoff[SADB_EXT_MAX + 1]; - int extlen[SADB_EXT_MAX + 1]; -}; - -static struct secasvar *key_allocsa_policy(struct secasindex *); -static struct secasvar *key_do_allocsa_policy(struct secashead *, u_int); -static void key_delsav(struct secasvar *); -static void key_delsp(struct secpolicy *); -static struct secpolicy *key_getsp(struct secpolicyindex *, int); -static struct secpolicy *key_getspbyid(u_int32_t); -static u_int32_t key_newreqid(void); -static struct mbuf *key_gather_mbuf(struct mbuf *, - const struct sadb_msghdr *, int, int, ...); -static int key_spdadd(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_spddelete(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_spddelete2(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_spdget(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_spdflush(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_spddump(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static struct mbuf *key_setdumpsp(struct secpolicy *, - u_int8_t, u_int32_t, u_int32_t); -static u_int key_getspreqmsglen(struct secpolicy *); -static int key_spdexpire(struct secpolicy *); -static struct secashead *key_newsah(struct secasindex *); -static void key_delsah(struct secashead *); -static struct secasvar *key_newsav(struct mbuf *, - const struct sadb_msghdr *, struct secashead *, int *); -static struct secashead *key_getsah(struct secasindex *); -static struct secasvar *key_checkspidup(struct secasindex *, u_int32_t); -static void key_setspi(struct secasvar *, u_int32_t); -static struct secasvar *key_getsavbyspi(struct secashead *, u_int32_t); -static int key_setsaval(struct secasvar *, struct mbuf *, - const struct sadb_msghdr *); -static int key_mature(struct secasvar *); -static struct mbuf *key_setdumpsa(struct secasvar *, u_int8_t, - u_int8_t, u_int32_t, u_int32_t); -static struct mbuf *key_setsadbmsg(u_int8_t, u_int16_t, u_int8_t, - u_int32_t, pid_t, u_int16_t); -static struct mbuf *key_setsadbsa(struct secasvar *); -static struct mbuf *key_setsadbaddr(u_int16_t, - struct sockaddr *, u_int8_t, u_int16_t); -#if 0 -static struct mbuf *key_setsadbident(u_int16_t, u_int16_t, caddr_t, - int, u_int64_t); -#endif -static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t, u_int32_t); -static struct mbuf *key_setsadblifetime(u_int16_t, u_int32_t, - u_int64_t, u_int64_t, u_int64_t); -static struct mbuf *key_setsadbxpolicy(u_int16_t, u_int8_t, - u_int32_t); -static void *key_newbuf(const void *, u_int); -static int key_ismyaddr(struct sockaddr *); -#ifdef INET6 -static int key_ismyaddr6(struct sockaddr_in6 *); -#endif - -/* flags for key_cmpsaidx() */ -#define CMP_HEAD 1 /* protocol, addresses. */ -#define CMP_MODE_REQID 2 /* additionally HEAD, reqid, mode. */ -#define CMP_REQID 3 /* additionally HEAD, reqid. not used */ -#define CMP_EXACTLY 4 /* all elements. */ -static int key_cmpsaidx(struct secasindex *, struct secasindex *, int); - -static int key_sockaddrcmp(struct sockaddr *, struct sockaddr *, int); -static int key_bbcmp(caddr_t, caddr_t, u_int); -static u_long key_random(void); -static u_int16_t key_satype2proto(u_int8_t); -static u_int8_t key_proto2satype(u_int16_t); - -static int key_getspi(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static u_int32_t key_do_getnewspi(struct sadb_spirange *, - struct secasindex *); -static int key_update(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -#ifdef IPSEC_DOSEQCHECK -static struct secasvar *key_getsavbyseq(struct secashead *, u_int32_t); -#endif -static int key_add(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_setident(struct secashead *, struct mbuf *, - const struct sadb_msghdr *); -static struct mbuf *key_getmsgbuf_x1(struct mbuf *, - const struct sadb_msghdr *); -static int key_delete(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_get(struct socket *, struct mbuf *, - const struct sadb_msghdr *); - -static void key_getcomb_setlifetime(struct sadb_comb *); -#ifdef IPSEC_ESP -static struct mbuf *key_getcomb_esp(void); -#endif -static struct mbuf *key_getcomb_ah(void); -static struct mbuf *key_getcomb_ipcomp(void); -static struct mbuf *key_getprop(const struct secasindex *); - -static int key_acquire(struct secasindex *, struct secpolicy *); -#ifndef IPSEC_NONBLOCK_ACQUIRE -static struct secacq *key_newacq(struct secasindex *); -static struct secacq *key_getacq(struct secasindex *); -static struct secacq *key_getacqbyseq(u_int32_t); -#endif -static struct secspacq *key_newspacq(struct secpolicyindex *); -static struct secspacq *key_getspacq(struct secpolicyindex *); -static int key_acquire2(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_register(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_expire(struct secasvar *); -static int key_flush(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_dump(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_promisc(struct socket *, struct mbuf *, - const struct sadb_msghdr *); -static int key_senderror(struct socket *, struct mbuf *, int); -static int key_validate_ext(struct sadb_ext *, int); -static int key_align(struct mbuf *, struct sadb_msghdr *); -#if 0 -static const char *key_getfqdn(void); -static const char *key_getuserfqdn(void); -#endif -static void key_sa_chgstate(struct secasvar *, u_int8_t); -static void key_sp_dead(struct secpolicy *); -static void key_sp_unlink(struct secpolicy *); -static struct mbuf *key_alloc_mbuf(int); -static struct callout key_timehandler_ch; - -/* %%% IPsec policy management */ -/* - * allocating a SP for OUTBOUND or INBOUND packet. - * Must call key_freesp() later. - * OUT: NULL: not found - * others: found and return the pointer. - */ -struct secpolicy * -key_allocsp(tag, spidx, dir) - u_int16_t tag; - struct secpolicyindex *spidx; - u_int dir; -{ - struct secpolicy *sp; - int s; - - /* check direction */ - switch (dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - break; - default: - panic("key_allocsp: Invalid direction is passed."); - } - - /* get a SP entry */ - s = splnet(); /*called from softclock()*/ - if (spidx) { - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("*** objects\n"); - kdebug_secpolicyindex(spidx)); - } - - LIST_FOREACH(sp, &sptree[dir], chain) { - if (sp->state == IPSEC_SPSTATE_DEAD) - continue; - if (sp->spidx) { - if (!spidx) - continue; - - KEYDEBUG(KEYDEBUG_IPSEC_DATA, - printf("*** in SPD\n"); - kdebug_secpolicyindex(sp->spidx)); - - if (key_cmpspidx_withmask(sp->spidx, spidx)) - goto found; - } - } - - splx(s); - return NULL; - -found: - /* sanity check */ - KEY_CHKSPDIR(sp->dir, dir, "key_allocsp"); - - /* found a SPD entry */ - sp->lastused = time_second; - sp->refcnt++; - splx(s); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP key_allocsp cause refcnt++:%d SP:%p\n", - sp->refcnt, sp)); - - return sp; -} - -/* - * return a policy that matches this particular inbound packet. - * XXX slow - */ -struct secpolicy * -key_gettunnel(osrc, odst, isrc, idst) - struct sockaddr *osrc, *odst, *isrc, *idst; -{ - struct secpolicy *sp; - const int dir = IPSEC_DIR_INBOUND; - int s; - struct ipsecrequest *r1, *r2, *p; - struct sockaddr *os, *od, *is, *id; - struct secpolicyindex spidx; - - if (isrc->sa_family != idst->sa_family) { - ipseclog((LOG_ERR, "protocol family mismatched %u != %u\n", - isrc->sa_family, idst->sa_family)); - return NULL; - } - - s = splnet(); /*called from softclock()*/ - LIST_FOREACH(sp, &sptree[dir], chain) { - if (sp->state == IPSEC_SPSTATE_DEAD) - continue; - - r1 = r2 = NULL; - for (p = sp->req; p; p = p->next) { - if (p->saidx.mode != IPSEC_MODE_TUNNEL) - continue; - - r1 = r2; - r2 = p; - - if (!r1) { - if (sp->spidx) { - /* - * here we look at address matches - * only - */ - spidx = *sp->spidx; - if (isrc->sa_len > sizeof(spidx.src) || - idst->sa_len > sizeof(spidx.dst)) - continue; - bcopy(isrc, &spidx.src, isrc->sa_len); - bcopy(idst, &spidx.dst, idst->sa_len); - if (!key_cmpspidx_withmask(sp->spidx, - &spidx)) - continue; - } else - ; /* can't check for tagged policy */ - } else { - is = (struct sockaddr *)&r1->saidx.src; - id = (struct sockaddr *)&r1->saidx.dst; - if (key_sockaddrcmp(is, isrc, 0) || - key_sockaddrcmp(id, idst, 0)) - continue; - } - - os = (struct sockaddr *)&r2->saidx.src; - od = (struct sockaddr *)&r2->saidx.dst; - if (key_sockaddrcmp(os, osrc, 0) || - key_sockaddrcmp(od, odst, 0)) - continue; - - goto found; - } - } - splx(s); - return NULL; - -found: - sp->lastused = time_second; - sp->refcnt++; - splx(s); - return sp; -} - -/* - * allocating an SA entry for an *OUTBOUND* packet. - * checking each request entries in SP, and acquire an SA if need. - * OUT: 0: there are valid requests. - * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. - */ -int -key_checkrequest(isr, saidx) - struct ipsecrequest *isr; - struct secasindex *saidx; -{ - u_int level; - int error; - - /* sanity check */ - if (isr == NULL || saidx == NULL) - panic("key_checkrequest: NULL pointer is passed."); - - /* check mode */ - switch (saidx->mode) { - case IPSEC_MODE_TRANSPORT: - case IPSEC_MODE_TUNNEL: - break; - case IPSEC_MODE_ANY: - default: - panic("key_checkrequest: Invalid policy defined."); - } - - /* get current level */ - level = ipsec_get_reqlevel(isr, saidx->src.ss_family); - -#if 0 - /* - * We do allocate new SA only if the state of SA in the holder is - * SADB_SASTATE_DEAD. The SA for outbound must be the oldest. - */ - if (isr->sav != NULL) { - if (isr->sav->sah == NULL) - panic("key_checkrequest: sah is null."); - if (isr->sav == - LIST_FIRST(&isr->sav->sah->savtree[SADB_SASTATE_DEAD])) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP checkrequest calls free SA:%p\n", - isr->sav)); - key_freesav(isr->sav); - isr->sav = NULL; - } - } -#else - /* - * we free any SA stashed in the IPsec request because a different - * SA may be involved each time this request is checked, either - * because new SAs are being configured, or this request is - * associated with an unconnected datagram socket, or this request - * is associated with a system default policy. - * - * The operation may have negative impact to performance. We may - * want to check cached SA carefully, rather than picking new SA - * every time. - */ - if (isr->sav != NULL) { - key_freesav(isr->sav); - isr->sav = NULL; - } -#endif - - /* - * new SA allocation if no SA found. - * key_allocsa_policy should allocate the oldest SA available. - * See key_do_allocsa_policy(), and draft-jenkins-ipsec-rekeying-03.txt. - */ - if (isr->sav == NULL) - isr->sav = key_allocsa_policy(saidx); - - /* When there is SA. */ - if (isr->sav != NULL) - return 0; - - /* there is no SA */ - if ((error = key_acquire(saidx, isr->sp)) != 0) { - /* XXX What should I do ? */ - ipseclog((LOG_DEBUG, "key_checkrequest: error %d returned " - "from key_acquire.\n", error)); - return error; - } - - return level == IPSEC_LEVEL_REQUIRE ? ENOENT : 0; -} - -/* - * allocating a SA for policy entry from SAD. - * NOTE: searching SAD of aliving state. - * OUT: NULL: not found. - * others: found and return the pointer. - */ -static struct secasvar * -key_allocsa_policy(saidx) - struct secasindex *saidx; -{ - struct secashead *sah; - struct secasvar *sav; - u_int stateidx, state; - const u_int *saorder_state_valid; - int arraysize; - - LIST_FOREACH(sah, &sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) - goto found; - } - - return NULL; - - found: - - /* - * search a valid state list for outbound packet. - * This search order is important. - */ - if (key_preferred_oldsa) { - saorder_state_valid = saorder_state_valid_prefer_old; - arraysize = _ARRAYLEN(saorder_state_valid_prefer_old); - } else { - saorder_state_valid = saorder_state_valid_prefer_new; - arraysize = _ARRAYLEN(saorder_state_valid_prefer_new); - } - - for (stateidx = 0; stateidx < arraysize; stateidx++) { - - state = saorder_state_valid[stateidx]; - - sav = key_do_allocsa_policy(sah, state); - if (sav != NULL) - return sav; - } - - return NULL; -} - -/* - * searching SAD with direction, protocol, mode and state. - * called by key_allocsa_policy(). - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secasvar * -key_do_allocsa_policy(sah, state) - struct secashead *sah; - u_int state; -{ - struct secasvar *sav, *nextsav, *candidate, *d; - - /* initilize */ - candidate = NULL; - - for (sav = LIST_FIRST(&sah->savtree[state]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - /* sanity check */ - KEY_CHKSASTATE(sav->state, state, "key_do_allocsa_policy"); - - /* initialize */ - if (candidate == NULL) { - candidate = sav; - continue; - } - - /* Which SA is the better ? */ - - /* sanity check 2 */ - if (candidate->lft_c == NULL || sav->lft_c == NULL) - panic("key_do_allocsa_policy: " - "lifetime_current is NULL."); - - /* What the best method is to compare ? */ - if (key_preferred_oldsa) { - if (candidate->lft_c->sadb_lifetime_addtime > - sav->lft_c->sadb_lifetime_addtime) { - candidate = sav; - } - continue; - /*NOTREACHED*/ - } - - /* preferred new sa rather than old sa */ - if (candidate->lft_c->sadb_lifetime_addtime < - sav->lft_c->sadb_lifetime_addtime) { - d = candidate; - candidate = sav; - } else - d = sav; - - /* - * prepared to delete the SA when there is more - * suitable candidate and the lifetime of the SA is not - * permanent. - */ - if (d->lft_c->sadb_lifetime_addtime != 0) { - struct mbuf *m, *result = NULL; - - key_sa_chgstate(d, SADB_SASTATE_DEAD); - - m = key_setsadbmsg(SADB_DELETE, 0, - key_proto2satype(d->sah->saidx.proto), - 0, 0, d->refcnt - 1); - if (!m) - goto msgfail; - result = m; - - /* set sadb_address for saidx's. */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&d->sah->saidx.src, - FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) - goto msgfail; - m_cat(result, m); - - /* set sadb_address for saidx's. */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&d->sah->saidx.dst, - FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) - goto msgfail; - m_cat(result, m); - - /* create SA extension */ - m = key_setsadbsa(d); - if (!m) - goto msgfail; - m_cat(result, m); - - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, - sizeof(struct sadb_msg)); - if (result == NULL) - goto msgfail; - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - if (key_sendup_mbuf(NULL, result, - KEY_SENDUP_REGISTERED)) - goto msgfail; - - result = NULL; - - msgfail: - if (result != NULL) - m_freem(result); - key_freesav(d); - } - } - - if (candidate) { - candidate->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP allocsa_policy cause " - "refcnt++:%d SA:%p\n", - candidate->refcnt, candidate)); - } - return candidate; -} - -/* - * allocating a SA entry for a *INBOUND* packet. - * Must call key_freesav() later. - * OUT: positive: pointer to a sav. - * NULL: not found, or error occured. - * - * In the comparison, source address will be ignored for RFC2401 conformance. - * To quote, from section 4.1: - * A security association is uniquely identified by a triple consisting - * of a Security Parameter Index (SPI), an IP Destination Address, and a - * security protocol (AH or ESP) identifier. - * Note that, however, we do need to keep source address in IPsec SA. - * IKE specification and PF_KEY specification do assume that we - * keep source address in IPsec SA. We see a tricky situation here. - */ -struct secasvar * -key_allocsa(family, src, dst, proto, spi) - u_int family, proto; - caddr_t src, dst; - u_int32_t spi; -{ - struct secasvar *sav, *match; - u_int stateidx, state, tmpidx, matchidx; - struct sockaddr_in sin; -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - int s; - const u_int *saorder_state_valid; - int arraysize; - - /* sanity check */ - if (src == NULL || dst == NULL) - panic("key_allocsa: NULL pointer is passed."); - - /* - * when both systems employ similar strategy to use a SA. - * the search order is important even in the inbound case. - */ - if (key_preferred_oldsa) { - saorder_state_valid = saorder_state_valid_prefer_old; - arraysize = _ARRAYLEN(saorder_state_valid_prefer_old); - } else { - saorder_state_valid = saorder_state_valid_prefer_new; - arraysize = _ARRAYLEN(saorder_state_valid_prefer_new); - } - - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(sin); -#ifdef INET6 - bzero(&sin6, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(sin6); -#endif - - /* - * searching SAD. - * XXX: to be checked internal IP header somewhere. Also when - * IPsec tunnel packet is received. But ESP tunnel mode is - * encrypted so we can't check internal IP header. - */ - s = splnet(); /*called from softclock()*/ - /* - * search a valid state list for inbound packet. - * the search order is not important. - */ - match = NULL; - matchidx = arraysize; - LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) { - if (sav->spi != spi) - continue; - if (proto != sav->sah->saidx.proto) - continue; - if (family != sav->sah->saidx.src.ss_family || - family != sav->sah->saidx.dst.ss_family) - continue; - tmpidx = arraysize; - for (stateidx = 0; stateidx < matchidx; stateidx++) { - state = saorder_state_valid[stateidx]; - if (sav->state == state) { - tmpidx = stateidx; - break; - } - } - if (tmpidx >= matchidx) - continue; - -#if 0 /* don't check src */ - /* check src address */ - switch (family) { - case AF_INET: - bcopy(src, &sin.sin_addr, sizeof(sin.sin_addr)); - if (key_sockaddrcmp((struct sockaddr*)&sin, - (struct sockaddr *)&sav->sah->saidx.src, 0) != 0) - continue; - - break; -#ifdef INET6 - case AF_INET6: - bcopy(src, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); - sin6.sin6_scope_id = 0; - if (sa6_recoverscope(&sin6)) - continue; - if (key_sockaddrcmp((struct sockaddr *)&sin6, - (struct sockaddr *)&sav->sah->saidx.src, 0) != 0) - continue; - break; -#endif - default: - ipseclog((LOG_DEBUG, "key_allocsa: " - "unknown address family=%d.\n", - family)); - continue; - } - -#endif - /* check dst address */ - switch (family) { - case AF_INET: - bcopy(dst, &sin.sin_addr, sizeof(sin.sin_addr)); - if (key_sockaddrcmp((struct sockaddr*)&sin, - (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0) - continue; - - break; -#ifdef INET6 - case AF_INET6: - bcopy(dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr)); - sin6.sin6_scope_id = 0; - if (sa6_recoverscope(&sin6)) - continue; - if (key_sockaddrcmp((struct sockaddr *)&sin6, - (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0) - continue; - break; -#endif - default: - ipseclog((LOG_DEBUG, "key_allocsa: " - "unknown address family=%d.\n", family)); - continue; - } - - match = sav; - matchidx = tmpidx; - } - - if (match) - goto found; - - /* not found */ - splx(s); - return NULL; - -found: - match->refcnt++; - splx(s); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP allocsa cause refcnt++:%d SA:%p\n", - match->refcnt, match)); - return match; -} - -/* - * Must be called after calling key_allocsp(). - * For both the packet without socket and key_freeso(). - */ -void -key_freesp(sp) - struct secpolicy *sp; -{ - /* sanity check */ - if (sp == NULL) - panic("key_freesp: NULL pointer is passed."); - - sp->refcnt--; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP freesp cause refcnt--:%d SP:%p\n", - sp->refcnt, sp)); - - if (sp->refcnt == 0) - key_delsp(sp); - - return; -} - -/* - * Must be called after calling key_allocsa(). - * This function is called by key_freesp() to free some SA allocated - * for a policy. - */ -void -key_freesav(sav) - struct secasvar *sav; -{ - /* sanity check */ - if (sav == NULL) - panic("key_freesav: NULL pointer is passed."); - - sav->refcnt--; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP freesav cause refcnt--:%d SA:%p SPI %u\n", - sav->refcnt, sav, (u_int32_t)ntohl(sav->spi))); - - if (sav->refcnt > 0) - return; - - key_delsav(sav); -} - -static void -key_delsav(sav) - struct secasvar *sav; -{ - int s; - - /* sanity check */ - if (sav == NULL) - panic("key_delsav: NULL pointer is passed."); - - if (sav->refcnt > 0) - panic("key_delsav: called with positive refcnt"); - - s = splnet(); - - if (__LIST_CHAINED(sav)) - LIST_REMOVE(sav, chain); - - if (sav->spihash.le_prev || sav->spihash.le_next) - LIST_REMOVE(sav, spihash); - - if (sav->key_auth != NULL) { - bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth)); - KFREE(sav->key_auth); - sav->key_auth = NULL; - } - if (sav->key_enc != NULL) { - bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc)); - KFREE(sav->key_enc); - sav->key_enc = NULL; - } - if (sav->sched) { - bzero(sav->sched, sav->schedlen); - KFREE(sav->sched); - sav->sched = NULL; - } - if (sav->replay != NULL) { - keydb_delsecreplay(sav->replay); - sav->replay = NULL; - } - if (sav->lft_c != NULL) { - KFREE(sav->lft_c); - sav->lft_c = NULL; - } - if (sav->lft_h != NULL) { - KFREE(sav->lft_h); - sav->lft_h = NULL; - } - if (sav->lft_s != NULL) { - KFREE(sav->lft_s); - sav->lft_s = NULL; - } - if (sav->iv != NULL) { - KFREE(sav->iv); - sav->iv = NULL; - } - - keydb_delsecasvar(sav); - - splx(s); -} - -/* %%% SPD management */ -/* - * free security policy entry. - */ -static void -key_delsp(sp) - struct secpolicy *sp; -{ - int s; - - /* sanity check */ - if (sp == NULL) - panic("key_delsp: NULL pointer is passed."); - - if (sp->refcnt > 0) - panic("key_delsp: called with positive refcnt"); - - s = splnet(); /*called from softclock()*/ - - { - struct ipsecrequest *isr = sp->req, *nextisr; - - while (isr != NULL) { - if (isr->sav != NULL) { - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP delsp calls free SA:%p\n", - isr->sav)); - key_freesav(isr->sav); - isr->sav = NULL; - } - - nextisr = isr->next; - KFREE(isr); - isr = nextisr; - } - } - - keydb_delsecpolicy(sp); - - splx(s); - - return; -} - -/* - * search SPD - * OUT: NULL : not found - * others : found, pointer to a SP. - */ -static struct secpolicy * -key_getsp(spidx, dir) - struct secpolicyindex *spidx; - int dir; -{ - struct secpolicy *sp; - - /* sanity check */ - if (spidx == NULL) - panic("key_getsp: NULL pointer is passed."); - - LIST_FOREACH(sp, &sptree[dir], chain) { - if (sp->state == IPSEC_SPSTATE_DEAD) - continue; - if (!sp->spidx) - continue; - if (key_cmpspidx_exactly(spidx, sp->spidx)) { - sp->refcnt++; - return sp; - } - } - - return NULL; -} - -/* - * get SP by index. - * OUT: NULL : not found - * others : found, pointer to a SP. - */ -static struct secpolicy * -key_getspbyid(id) - u_int32_t id; -{ - struct secpolicy *sp; - - TAILQ_FOREACH(sp, &sptailq, tailq) { - if (sp->id == id) { - sp->refcnt++; - return sp; - } - } - - return NULL; -} - -struct secpolicy * -key_newsp(id) - u_int32_t id; -{ - struct secpolicy *newsp = NULL, *sp; - u_int32_t newid; - - if (id > IPSEC_MANUAL_POLICYID_MAX) { - ipseclog((LOG_DEBUG, - "key_newsp: policy_id=%u range " - "violation, updated by kernel.\n", id)); - id = 0; - } - - if (id == 0) { - if ((newid = keydb_newspid()) == 0) { - ipseclog((LOG_DEBUG, - "key_newsp: new policy_id allocation failed.")); - return NULL; - } - } else { - sp = key_getspbyid(id); - if (sp != NULL) { - ipseclog((LOG_DEBUG, - "key_newsp: policy_id(%u) has been used.\n", id)); - key_freesp(sp); - return NULL; - } - newid = id; - } - - newsp = keydb_newsecpolicy(); - if (!newsp) - return newsp; - - newsp->id = newid; - newsp->refcnt = 1; - newsp->req = NULL; - - return newsp; -} - -/* - * create secpolicy structure from sadb_x_policy structure. - * NOTE: `state', `secpolicyindex' in secpolicy structure are not set, - * so must be set properly later. - */ -struct secpolicy * -key_msg2sp(xpl0, len, error) - struct sadb_x_policy *xpl0; - size_t len; - int *error; -{ - struct secpolicy *newsp; - - /* sanity check */ - if (xpl0 == NULL) - panic("key_msg2sp: NULL pointer was passed."); - if (len < sizeof(*xpl0)) - panic("key_msg2sp: invalid length."); - if (len != PFKEY_EXTLEN(xpl0)) { - ipseclog((LOG_DEBUG, "key_msg2sp: Invalid msg length.\n")); - *error = EINVAL; - return NULL; - } - - if ((newsp = key_newsp(xpl0->sadb_x_policy_id)) == NULL) { - *error = ENOBUFS; - return NULL; - } - - newsp->dir = xpl0->sadb_x_policy_dir; - newsp->policy = xpl0->sadb_x_policy_type; - - /* check policy */ - switch (xpl0->sadb_x_policy_type) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - case IPSEC_POLICY_ENTRUST: - case IPSEC_POLICY_BYPASS: - newsp->req = NULL; - break; - - case IPSEC_POLICY_IPSEC: - { - int tlen; - struct sadb_x_ipsecrequest *xisr; - struct ipsecrequest **p_isr = &newsp->req; - - /* validity check */ - if (PFKEY_EXTLEN(xpl0) < sizeof(*xpl0)) { - ipseclog((LOG_DEBUG, - "key_msg2sp: Invalid msg length.\n")); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - - tlen = PFKEY_EXTLEN(xpl0) - sizeof(*xpl0); - xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1); - - while (tlen > 0) { - - /* length check */ - if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { - ipseclog((LOG_DEBUG, "key_msg2sp: " - "invalid ipsecrequest length.\n")); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - - /* allocate request buffer */ - KMALLOC(*p_isr, struct ipsecrequest *, sizeof(**p_isr)); - if ((*p_isr) == NULL) { - ipseclog((LOG_DEBUG, - "key_msg2sp: No more memory.\n")); - key_freesp(newsp); - *error = ENOBUFS; - return NULL; - } - bzero(*p_isr, sizeof(**p_isr)); - - /* set values */ - (*p_isr)->next = NULL; - - switch (xisr->sadb_x_ipsecrequest_proto) { - case IPPROTO_ESP: - case IPPROTO_AH: - case IPPROTO_IPCOMP: - break; - default: - ipseclog((LOG_DEBUG, - "key_msg2sp: invalid proto type=%u\n", - xisr->sadb_x_ipsecrequest_proto)); - key_freesp(newsp); - *error = EPROTONOSUPPORT; - return NULL; - } - (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto; - - switch (xisr->sadb_x_ipsecrequest_mode) { - case IPSEC_MODE_TRANSPORT: - case IPSEC_MODE_TUNNEL: - break; - case IPSEC_MODE_ANY: - default: - ipseclog((LOG_DEBUG, - "key_msg2sp: invalid mode=%u\n", - xisr->sadb_x_ipsecrequest_mode)); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode; - - switch (xisr->sadb_x_ipsecrequest_level) { - case IPSEC_LEVEL_DEFAULT: - case IPSEC_LEVEL_USE: - case IPSEC_LEVEL_REQUIRE: - break; - case IPSEC_LEVEL_UNIQUE: - /* validity check */ - /* - * If range violation of reqid, kernel will - * update it, don't refuse it. - */ - if (xisr->sadb_x_ipsecrequest_reqid - > IPSEC_MANUAL_REQID_MAX) { - ipseclog((LOG_DEBUG, - "key_msg2sp: reqid=%u range " - "violation, updated by kernel.\n", - xisr->sadb_x_ipsecrequest_reqid)); - xisr->sadb_x_ipsecrequest_reqid = 0; - } - - /* allocate new reqid id if reqid is zero. */ - if (xisr->sadb_x_ipsecrequest_reqid == 0) { - u_int32_t reqid; - if ((reqid = key_newreqid()) == 0) { - key_freesp(newsp); - *error = ENOBUFS; - return NULL; - } - (*p_isr)->saidx.reqid = reqid; - xisr->sadb_x_ipsecrequest_reqid = reqid; - } else { - /* set it for manual keying. */ - (*p_isr)->saidx.reqid = - xisr->sadb_x_ipsecrequest_reqid; - } - break; - - default: - ipseclog((LOG_DEBUG, "key_msg2sp: invalid level=%u\n", - xisr->sadb_x_ipsecrequest_level)); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; - - /* set IP addresses if there */ - if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { - struct sockaddr *paddr; - - paddr = (struct sockaddr *)(xisr + 1); - - /* validity check */ - if (paddr->sa_len - > sizeof((*p_isr)->saidx.src)) { - ipseclog((LOG_DEBUG, "key_msg2sp: invalid request " - "address length.\n")); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - bcopy(paddr, &(*p_isr)->saidx.src, - paddr->sa_len); - - paddr = (struct sockaddr *)((caddr_t)paddr - + paddr->sa_len); - - /* validity check */ - if (paddr->sa_len - > sizeof((*p_isr)->saidx.dst)) { - ipseclog((LOG_DEBUG, "key_msg2sp: invalid request " - "address length.\n")); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - bcopy(paddr, &(*p_isr)->saidx.dst, - paddr->sa_len); - } - - (*p_isr)->sav = NULL; - (*p_isr)->sp = newsp; - - /* initialization for the next. */ - p_isr = &(*p_isr)->next; - tlen -= xisr->sadb_x_ipsecrequest_len; - - /* validity check */ - if (tlen < 0) { - ipseclog((LOG_DEBUG, "key_msg2sp: becoming tlen < 0.\n")); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr - + xisr->sadb_x_ipsecrequest_len); - } - } - break; - default: - ipseclog((LOG_DEBUG, "key_msg2sp: invalid policy type.\n")); - key_freesp(newsp); - *error = EINVAL; - return NULL; - } - - *error = 0; - return newsp; -} - -static u_int32_t -key_newreqid() -{ - static u_int32_t auto_reqid = IPSEC_MANUAL_REQID_MAX + 1; - - auto_reqid = (auto_reqid == ~0 - ? IPSEC_MANUAL_REQID_MAX + 1 : auto_reqid + 1); - - /* XXX should be unique check */ - - return auto_reqid; -} - -/* - * copy secpolicy struct to sadb_x_policy structure indicated. - */ -struct mbuf * -key_sp2msg(sp) - struct secpolicy *sp; -{ - struct sadb_x_policy *xpl; - int tlen; - caddr_t p; - struct mbuf *m; - - /* sanity check. */ - if (sp == NULL) - panic("key_sp2msg: NULL pointer was passed."); - - tlen = key_getspreqmsglen(sp); - - m = key_alloc_mbuf(tlen); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - m->m_len = tlen; - m->m_next = NULL; - xpl = mtod(m, struct sadb_x_policy *); - bzero(xpl, tlen); - - xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen); - xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; - xpl->sadb_x_policy_type = sp->policy; - xpl->sadb_x_policy_dir = sp->dir; - xpl->sadb_x_policy_id = sp->id; - p = (caddr_t)xpl + sizeof(*xpl); - - /* if is the policy for ipsec ? */ - if (sp->policy == IPSEC_POLICY_IPSEC) { - struct sadb_x_ipsecrequest *xisr; - struct ipsecrequest *isr; - - for (isr = sp->req; isr != NULL; isr = isr->next) { - - xisr = (struct sadb_x_ipsecrequest *)p; - - xisr->sadb_x_ipsecrequest_proto = isr->saidx.proto; - xisr->sadb_x_ipsecrequest_mode = isr->saidx.mode; - xisr->sadb_x_ipsecrequest_level = isr->level; - xisr->sadb_x_ipsecrequest_reqid = isr->saidx.reqid; - - p += sizeof(*xisr); - bcopy(&isr->saidx.src, p, isr->saidx.src.ss_len); - p += isr->saidx.src.ss_len; - bcopy(&isr->saidx.dst, p, isr->saidx.dst.ss_len); - p += isr->saidx.src.ss_len; - - xisr->sadb_x_ipsecrequest_len = - PFKEY_ALIGN8(sizeof(*xisr) + - isr->saidx.src.ss_len + isr->saidx.dst.ss_len); - } - } - - return m; -} - -/* m will not be freed nor modified */ -static struct mbuf * -#ifdef __STDC__ -key_gather_mbuf(struct mbuf *m, const struct sadb_msghdr *mhp, - int ndeep, int nitem, ...) -#else -key_gather_mbuf(m, mhp, ndeep, nitem, va_alist) - struct mbuf *m; - const struct sadb_msghdr *mhp; - int ndeep; - int nitem; - va_dcl -#endif -{ - va_list ap; - int idx; - int i; - struct mbuf *result = NULL, *n; - int len; - - if (m == NULL || mhp == NULL) - panic("null pointer passed to key_gather"); - - va_start(ap, nitem); - for (i = 0; i < nitem; i++) { - idx = va_arg(ap, int); - if (idx < 0 || idx > SADB_EXT_MAX) - goto fail; - /* don't attempt to pull empty extension */ - if (idx == SADB_EXT_RESERVED && mhp->msg == NULL) - continue; - if (idx != SADB_EXT_RESERVED && - (mhp->ext[idx] == NULL || mhp->extlen[idx] == 0)) - continue; - - if (idx == SADB_EXT_RESERVED) { - len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); -#ifdef DIAGNOSTIC - if (len > MHLEN) - panic("assumption failed"); -#endif - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (!n) - goto fail; - n->m_len = len; - n->m_next = NULL; - m_copydata(m, 0, sizeof(struct sadb_msg), - mtod(n, caddr_t)); - } else if (i < ndeep) { - len = mhp->extlen[idx]; - n = key_alloc_mbuf(len); - if (!n || n->m_next) { /*XXX*/ - if (n) - m_freem(n); - goto fail; - } - m_copydata(m, mhp->extoff[idx], mhp->extlen[idx], - mtod(n, caddr_t)); - } else { - n = m_copym(m, mhp->extoff[idx], mhp->extlen[idx], - M_DONTWAIT); - } - if (n == NULL) - goto fail; - - if (result) - m_cat(result, n); - else - result = n; - } - va_end(ap); - - if ((result->m_flags & M_PKTHDR) != 0) { - result->m_pkthdr.len = 0; - for (n = result; n; n = n->m_next) - result->m_pkthdr.len += n->m_len; - } - - return result; - -fail: - va_end(ap); - m_freem(result); - return NULL; -} - -/* - * SADB_X_SPDADD, SADB_X_SPDSETIDX or SADB_X_SPDUPDATE processing - * add an entry to SP database, when received - * <base, address(SD), (lifetime(H),) policy> - * from the user(?). - * Adding to SP database, - * and send - * <base, address(SD), (lifetime(H),) policy> - * to the socket which was send. - * - * SPDADD set a unique policy entry. - * SPDSETIDX like SPDADD without a part of policy requests. - * SPDUPDATE replace a unique policy entry. - * - * m will always be freed. - */ -static int -key_spdadd(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_address *src0 = NULL, *dst0 = NULL; - struct sadb_x_policy *xpl0, *xpl; - struct sadb_lifetime *lft = NULL; - struct secpolicyindex spidx; - struct secpolicy *newsp; - struct ipsecrequest *isr; - int error; - int spidxmode; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_spdadd: NULL pointer is passed."); - - if (mhp->ext[SADB_EXT_ADDRESS_SRC] != NULL && - mhp->ext[SADB_EXT_ADDRESS_DST] != NULL) { - ; - } else { - ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->ext[SADB_X_EXT_POLICY] == NULL) { - ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if ((mhp->extlen[SADB_EXT_ADDRESS_SRC] && - mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address)) || - (mhp->extlen[SADB_EXT_ADDRESS_DST] && - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) || - mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { - ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL) { - if (mhp->extlen[SADB_EXT_LIFETIME_HARD] - < sizeof(struct sadb_lifetime)) { - ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; - } - - /* spidx mode, or tag mode */ - spidxmode = (mhp->ext[SADB_EXT_ADDRESS_SRC] != NULL); - - if (spidxmode) { - src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; - dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - /* make secindex */ - /* XXX boundary check against sa_len */ - KEY_SETSECSPIDX(src0 + 1, dst0 + 1, - src0->sadb_address_prefixlen, dst0->sadb_address_prefixlen, - src0->sadb_address_proto, &spidx); - } - xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY]; - - /* checking the direciton. */ - switch (xpl0->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - break; - default: - ipseclog((LOG_DEBUG, "key_spdadd: Invalid SP direction.\n")); - mhp->msg->sadb_msg_errno = EINVAL; - return 0; - } - - /* check policy */ - /* key_spdadd() accepts DISCARD, NONE and IPSEC. */ - if (xpl0->sadb_x_policy_type == IPSEC_POLICY_ENTRUST || - xpl0->sadb_x_policy_type == IPSEC_POLICY_BYPASS) { - ipseclog((LOG_DEBUG, "key_spdadd: Invalid policy type.\n")); - return key_senderror(so, m, EINVAL); - } - - /* policy requests are mandatory when action is ipsec. */ - if (mhp->msg->sadb_msg_type != SADB_X_SPDSETIDX && - xpl0->sadb_x_policy_type == IPSEC_POLICY_IPSEC && - mhp->extlen[SADB_X_EXT_POLICY] <= sizeof(*xpl0)) { - ipseclog((LOG_DEBUG, "key_spdadd: some policy requests part required.\n")); - return key_senderror(so, m, EINVAL); - } - - /* - * checking there is SP already or not. - * SPDUPDATE doesn't depend on whether there is a SP or not. - * If the type is either SPDADD or SPDSETIDX AND a SP is found, - * then error. - */ - if (xpl0->sadb_x_policy_id != 0) - newsp = key_getspbyid(xpl0->sadb_x_policy_id); - else if (spidxmode) - newsp = key_getsp(&spidx, xpl0->sadb_x_policy_dir); - else - newsp = NULL; - - if (newsp && (newsp->readonly || newsp->persist)) { - ipseclog((LOG_DEBUG, - "key_spdadd: tried to alter readonly/persistent SP.\n")); - return key_senderror(so, m, EPERM); - } - - if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { - if (newsp) { - key_sp_dead(newsp); - key_freesp(newsp); /* ref gained by key_getsp */ - key_sp_unlink(newsp); - newsp = NULL; - } - } else { - if (newsp != NULL) { - key_freesp(newsp); - ipseclog((LOG_DEBUG, "key_spdadd: a SP entry exists already.\n")); - return key_senderror(so, m, EEXIST); - } - } - - /* allocation new SP entry */ - if ((newsp = key_msg2sp(xpl0, PFKEY_EXTLEN(xpl0), &error)) == NULL) { - return key_senderror(so, m, error); - } - - if (spidxmode) { - error = keydb_setsecpolicyindex(newsp, &spidx); - if (error) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, error); - } - - /* sanity check on addr pair */ - if (((struct sockaddr *)(src0 + 1))->sa_family != - ((struct sockaddr *)(dst0 + 1))->sa_family) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - if (((struct sockaddr *)(src0 + 1))->sa_len != - ((struct sockaddr *)(dst0 + 1))->sa_len) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - } - - for (isr = newsp->req; isr; isr = isr->next) { - struct sockaddr *sa; - - /* - * port spec is not permitted for tunnel mode - */ - if (isr->saidx.mode == IPSEC_MODE_TUNNEL && src0 && dst0) { - sa = (struct sockaddr *)(src0 + 1); - switch (sa->sa_family) { - case AF_INET: - if (((struct sockaddr_in *)sa)->sin_port) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - break; - case AF_INET6: - if (((struct sockaddr_in6 *)sa)->sin6_port) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - break; - default: - break; - } - sa = (struct sockaddr *)(dst0 + 1); - switch (sa->sa_family) { - case AF_INET: - if (((struct sockaddr_in *)sa)->sin_port) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - break; - case AF_INET6: - if (((struct sockaddr_in6 *)sa)->sin6_port) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - break; - default: - break; - } - } - } - - /* - * bark if we have different address family on tunnel address - * specification. applies only if we decapsulate in RFC2401 - * IPsec (implementation limitation). - */ - for (isr = newsp->req; isr; isr = isr->next) { - struct sockaddr *sa; - - if (isr->saidx.src.ss_family && src0) { - sa = (struct sockaddr *)(src0 + 1); - if (sa->sa_family != isr->saidx.src.ss_family) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - } - if (isr->saidx.dst.ss_family && dst0) { - sa = (struct sockaddr *)(dst0 + 1); - if (sa->sa_family != isr->saidx.dst.ss_family) { - keydb_delsecpolicy(newsp); - return key_senderror(so, m, EINVAL); - } - } - } - - newsp->created = time_second; - newsp->lastused = time_second; - newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0; - newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0; - - newsp->state = IPSEC_SPSTATE_ALIVE; - LIST_INSERT_TAIL(&sptree[newsp->dir], newsp, secpolicy, chain); - - /* delete the entry in spacqtree */ - if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE && - mhp->ext[SADB_EXT_ADDRESS_SRC]) { - struct secspacq *spacq; - if ((spacq = key_getspacq(&spidx)) != NULL) { - /* reset counter in order to deletion by timehandler. */ - spacq->created = time_second; - spacq->count = 0; - } - } - - /* invalidate all cached SPD pointers on pcb */ - ipsec_invalpcbcacheall(); - - { - struct mbuf *n, *mpolicy; - struct sadb_msg *newmsg; - int off; - - /* create new sadb_msg to reply. */ - if (lft) { - n = key_gather_mbuf(m, mhp, 2, 5, SADB_EXT_RESERVED, - SADB_X_EXT_POLICY, SADB_EXT_LIFETIME_HARD, - SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); - } else { - n = key_gather_mbuf(m, mhp, 2, 4, SADB_EXT_RESERVED, - SADB_X_EXT_POLICY, - SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); - } - if (!n) - return key_senderror(so, m, ENOBUFS); - - if (n->m_len < sizeof(*newmsg)) { - n = m_pullup(n, sizeof(*newmsg)); - if (!n) - return key_senderror(so, m, ENOBUFS); - } - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - - off = 0; - mpolicy = m_pulldown(n, PFKEY_ALIGN8(sizeof(struct sadb_msg)), - sizeof(*xpl), &off); - if (mpolicy == NULL) { - /* n is already freed */ - return key_senderror(so, m, ENOBUFS); - } - xpl = (struct sadb_x_policy *)(mtod(mpolicy, caddr_t) + off); - if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { - m_freem(n); - return key_senderror(so, m, EINVAL); - } - xpl->sadb_x_policy_id = newsp->id; - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* - * SADB_SPDDELETE processing - * receive - * <base, address(SD), policy(*)> - * from the user(?), and set SADB_SASTATE_DEAD, - * and send, - * <base, address(SD), policy(*)> - * to the ikmpd. - * policy(*) including the direction of the policy. - * - * m will always be freed. - */ -static int -key_spddelete(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_address *src0, *dst0; - struct sadb_x_policy *xpl0; - struct secpolicyindex spidx; - struct secpolicy *sp; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_spddelete: NULL pointer is passed."); - - if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || - mhp->ext[SADB_X_EXT_POLICY] == NULL) { - ipseclog((LOG_DEBUG, "key_spddelete: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) || - mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { - ipseclog((LOG_DEBUG, "key_spddelete: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; - dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY]; - - /* make secindex */ - /* XXX boundary check against sa_len */ - KEY_SETSECSPIDX(src0 + 1, - dst0 + 1, - src0->sadb_address_prefixlen, - dst0->sadb_address_prefixlen, - src0->sadb_address_proto, - &spidx); - - /* checking the direciton. */ - switch (xpl0->sadb_x_policy_dir) { - case IPSEC_DIR_INBOUND: - case IPSEC_DIR_OUTBOUND: - break; - default: - ipseclog((LOG_DEBUG, "key_spddelete: Invalid SP direction.\n")); - return key_senderror(so, m, EINVAL); - } - - /* Is there SP in SPD ? */ - if ((sp = key_getsp(&spidx, xpl0->sadb_x_policy_dir)) == NULL) { - ipseclog((LOG_DEBUG, "key_spddelete: no SP found.\n")); - return key_senderror(so, m, EINVAL); - } - - if (sp->persist) { - ipseclog((LOG_DEBUG, - "key_spddelete2: attempt to remove persistent SP:%u.\n", - sp->id)); - key_freesp(sp); /* ref gained by key_getsp */ - return key_senderror(so, m, EPERM); - } - - /* save policy id to be returned. */ - xpl0->sadb_x_policy_id = sp->id; - - key_sp_dead(sp); - key_freesp(sp); /* ref gained by key_getsp */ - key_sp_unlink(sp); - sp = NULL; - - /* invalidate all cached SPD pointers on pcb */ - ipsec_invalpcbcacheall(); - - { - struct mbuf *n; - struct sadb_msg *newmsg; - - /* create new sadb_msg to reply. */ - n = key_gather_mbuf(m, mhp, 1, 4, SADB_EXT_RESERVED, - SADB_X_EXT_POLICY, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); - if (!n) - return key_senderror(so, m, ENOBUFS); - - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* - * SADB_SPDDELETE2 processing - * receive - * <base, policy(*)> - * from the user(?), and set SADB_SASTATE_DEAD, - * and send, - * <base, policy(*)> - * to the ikmpd. - * policy(*) including the policy id. - * - * m will always be freed. - */ -static int -key_spddelete2(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - u_int32_t id; - struct secpolicy *sp; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_spddelete2: NULL pointer is passed."); - - if (mhp->ext[SADB_X_EXT_POLICY] == NULL || - mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { - ipseclog((LOG_DEBUG, "key_spddelete2: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id; - - /* Is there SP in SPD ? */ - if ((sp = key_getspbyid(id)) == NULL) { - ipseclog((LOG_DEBUG, "key_spddelete2: no SP found id:%u.\n", - id)); - return key_senderror(so, m, EINVAL); - } - - if (sp->persist) { - ipseclog((LOG_DEBUG, - "key_spddelete2: attempt to remove persistent SP:%u.\n", - id)); - key_freesp(sp); /* ref gained by key_getspbyid */ - return key_senderror(so, m, EPERM); - } - - key_sp_dead(sp); - key_freesp(sp); /* ref gained by key_getspbyid */ - key_sp_unlink(sp); - sp = NULL; - - /* invalidate all cached SPD pointers on pcb */ - ipsec_invalpcbcacheall(); - - { - struct mbuf *n, *nn; - struct sadb_msg *newmsg; - int off, len; - - /* create new sadb_msg to reply. */ - len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); - - if (len > MCLBYTES) - return key_senderror(so, m, ENOBUFS); - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n && len > MHLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - n = NULL; - } - } - if (!n) - return key_senderror(so, m, ENOBUFS); - - n->m_len = len; - n->m_next = NULL; - off = 0; - - m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off); - off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); - -#ifdef DIAGNOSTIC - if (off != len) - panic("length inconsistency in key_spddelete2"); -#endif - - n->m_next = m_copym(m, mhp->extoff[SADB_X_EXT_POLICY], - mhp->extlen[SADB_X_EXT_POLICY], M_DONTWAIT); - if (!n->m_next) { - m_freem(n); - return key_senderror(so, m, ENOBUFS); - } - - n->m_pkthdr.len = 0; - for (nn = n; nn; nn = nn->m_next) - n->m_pkthdr.len += nn->m_len; - - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* - * SADB_X_SPDGET processing - * receive - * <base, policy(*)> - * from the user(?), - * and send, - * <base, address(SD), policy> - * to the ikmpd. - * policy(*) including direction of policy. - * - * m will always be freed. - */ -static int -key_spdget(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - u_int32_t id; - struct secpolicy *sp; - struct mbuf *n; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_spdget: NULL pointer is passed."); - - if (mhp->ext[SADB_X_EXT_POLICY] == NULL || - mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { - ipseclog((LOG_DEBUG, "key_spdget: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id; - - /* Is there SP in SPD ? */ - if ((sp = key_getspbyid(id)) == NULL) { - ipseclog((LOG_DEBUG, "key_spdget: no SP found id:%u.\n", id)); - return key_senderror(so, m, ENOENT); - } - - n = key_setdumpsp(sp, SADB_X_SPDGET, 0, mhp->msg->sadb_msg_pid); - key_freesp(sp); /* ref gained by key_getspbyid */ - if (n != NULL) { - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); - } else - return key_senderror(so, m, ENOBUFS); -} - -/* - * SADB_X_SPDACQUIRE processing. - * Acquire policy and SA(s) for a *OUTBOUND* packet. - * send - * <base, policy(*)> - * to KMD, and expect to receive - * <base> with SADB_X_SPDACQUIRE if error occured, - * or - * <base, policy> - * with SADB_X_SPDUPDATE from KMD by PF_KEY. - * policy(*) is without policy requests. - * - * 0 : succeed - * others: error number - */ -int -key_spdacquire(sp) - struct secpolicy *sp; -{ - struct mbuf *result = NULL, *m; -#ifndef IPSEC_NONBLOCK_ACQUIRE - struct secspacq *newspacq; -#endif - int error = -1; - - /* sanity check */ - if (sp == NULL) - panic("key_spdacquire: NULL pointer is passed."); - if (sp->req != NULL) - panic("key_spdacquire: called but there is request."); - if (sp->policy != IPSEC_POLICY_IPSEC) - panic("key_spdacquire: policy mismathed. IPsec is expected."); - if (!sp->spidx) { - error = EOPNOTSUPP; - goto fail; - } - -#ifndef IPSEC_NONBLOCK_ACQUIRE - /* get an entry to check whether sent message or not. */ - if ((newspacq = key_getspacq(sp->spidx)) != NULL) { - if (key_blockacq_count < newspacq->count) { - /* reset counter and do send message. */ - newspacq->count = 0; - } else { - /* increment counter and do nothing. */ - newspacq->count++; - return 0; - } - } else { - /* make new entry for blocking to send SADB_ACQUIRE. */ - if ((newspacq = key_newspacq(sp->spidx)) == NULL) - return ENOBUFS; - - /* add to acqtree */ - LIST_INSERT_HEAD(&spacqtree, newspacq, chain); - } -#endif - - /* create new sadb_msg to reply. */ - m = key_setsadbmsg(SADB_X_SPDACQUIRE, 0, 0, 0, 0, 0); - if (!m) { - error = ENOBUFS; - goto fail; - } - result = m; - - /* set sadb_x_policy */ - if (sp) { - m = key_setsadbxpolicy(sp->policy, sp->dir, sp->id); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); - -fail: - if (result) - m_freem(result); - return error; -} - -/* - * SADB_SPDFLUSH processing - * receive - * <base> - * from the user, and free all entries in secpctree. - * and send, - * <base> - * to the user. - * NOTE: what to do is only marking SADB_SASTATE_DEAD. - * - * m will always be freed. - */ -static int -key_spdflush(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_msg *newmsg; - struct secpolicy *sp, *nextsp; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_spdflush: NULL pointer is passed."); - - if (m->m_len != PFKEY_ALIGN8(sizeof(struct sadb_msg))) - return key_senderror(so, m, EINVAL); - - for (sp = TAILQ_FIRST(&sptailq); sp; sp = nextsp) { - nextsp = TAILQ_NEXT(sp, tailq); - if (sp->persist) - continue; - if (sp->state == IPSEC_SPSTATE_DEAD) - continue; - key_sp_dead(sp); - key_sp_unlink(sp); - sp = NULL; - } - - /* invalidate all cached SPD pointers on pcb */ - ipsec_invalpcbcacheall(); - - if (sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) { - ipseclog((LOG_DEBUG, "key_spdflush: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - - if (m->m_next) - m_freem(m->m_next); - m->m_next = NULL; - m->m_pkthdr.len = m->m_len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); - newmsg = mtod(m, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); - - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); -} - -/* - * SADB_SPDDUMP processing - * receive - * <base> - * from the user, and dump all SP leaves - * and send, - * <base> ..... - * to the ikmpd. - * - * m will always be freed. - */ -static int -key_spddump(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct secpolicy *sp; - int cnt; - u_int dir; - struct mbuf *n; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_spddump: NULL pointer is passed."); - - /* search SPD entry and get buffer size. */ - cnt = 0; - for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - LIST_FOREACH(sp, &sptree[dir], chain) { - cnt++; - } - } - - if (cnt == 0) - return key_senderror(so, m, ENOENT); - - for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - LIST_FOREACH(sp, &sptree[dir], chain) { - --cnt; - n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, - mhp->msg->sadb_msg_pid); - - if (n) - key_sendup_mbuf(so, n, KEY_SENDUP_ONE); - } - } - - m_freem(m); - return 0; -} - -static struct mbuf * -key_setdumpsp(sp, type, seq, pid) - struct secpolicy *sp; - u_int8_t type; - u_int32_t seq, pid; -{ - struct mbuf *result = NULL, *m; - - m = key_setsadbmsg(type, 0, SADB_SATYPE_UNSPEC, seq, pid, sp->refcnt); - if (!m) - goto fail; - result = m; - - if (sp->spidx) { - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sp->spidx->src, sp->spidx->prefs, - sp->spidx->ul_proto); - if (!m) - goto fail; - m_cat(result, m); - - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sp->spidx->dst, sp->spidx->prefd, - sp->spidx->ul_proto); - if (!m) - goto fail; - m_cat(result, m); - } - - m = key_sp2msg(sp); - if (!m) - goto fail; - m_cat(result, m); - - m = key_setsadblifetime(SADB_EXT_LIFETIME_CURRENT, - 0, 0, (u_int64_t)sp->created, (u_int64_t)sp->lastused); - if (!m) - goto fail; - m_cat(result, m); - - m = key_setsadblifetime(SADB_EXT_LIFETIME_HARD, - 0, 0, (u_int64_t)sp->lifetime, (u_int64_t)sp->validtime); - if (!m) - goto fail; - m_cat(result, m); - - if ((result->m_flags & M_PKTHDR) == 0) - goto fail; - - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) - goto fail; - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - return result; - -fail: - m_freem(result); - return NULL; -} - -/* - * get PFKEY message length for security policy and request. - */ -static u_int -key_getspreqmsglen(sp) - struct secpolicy *sp; -{ - u_int tlen; - - tlen = sizeof(struct sadb_x_policy); - - /* if is the policy for ipsec ? */ - if (sp->policy != IPSEC_POLICY_IPSEC) - return tlen; - - /* get length of ipsec requests */ - { - struct ipsecrequest *isr; - int len; - - for (isr = sp->req; isr != NULL; isr = isr->next) { - len = sizeof(struct sadb_x_ipsecrequest) - + isr->saidx.src.ss_len - + isr->saidx.dst.ss_len; - - tlen += PFKEY_ALIGN8(len); - } - } - - return tlen; -} - -/* - * SADB_X_SPDEXPIRE processing - * send - * <base, address(SD), lifetime(CH), policy> - * to KMD by PF_KEY. - * - * OUT: 0 : succeed - * others : error number - */ -static int -key_spdexpire(sp) - struct secpolicy *sp; -{ - int s; - struct mbuf *result = NULL, *m; - int len; - int error = -1; - struct sadb_lifetime *lt; - - /* XXX: Why do we lock ? */ - s = splnet(); /*called from softclock()*/ - - /* sanity check */ - if (sp == NULL) - panic("key_spdexpire: NULL pointer is passed."); - - /* set msg header */ - m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0); - if (!m) { - error = ENOBUFS; - goto fail; - } - result = m; - - /* create lifetime extension (current and hard) */ - len = PFKEY_ALIGN8(sizeof(*lt)) * 2; - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - error = ENOBUFS; - goto fail; - } - bzero(mtod(m, caddr_t), len); - lt = mtod(m, struct sadb_lifetime *); - lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); - lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; - lt->sadb_lifetime_allocations = 0; - lt->sadb_lifetime_bytes = 0; - lt->sadb_lifetime_addtime = sp->created; - lt->sadb_lifetime_usetime = sp->lastused; - lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2); - lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); - lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; - lt->sadb_lifetime_allocations = 0; - lt->sadb_lifetime_bytes = 0; - lt->sadb_lifetime_addtime = sp->lifetime; - lt->sadb_lifetime_usetime = sp->validtime; - m_cat(result, m); - - /* set sadb_address for source */ - if (sp->spidx) { - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sp->spidx->src, - sp->spidx->prefs, sp->spidx->ul_proto); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - /* set sadb_address for destination */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sp->spidx->dst, - sp->spidx->prefd, sp->spidx->ul_proto); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - } - - /* set secpolicy */ - m = key_sp2msg(sp); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - if ((result->m_flags & M_PKTHDR) == 0) { - error = EINVAL; - goto fail; - } - - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) { - error = ENOBUFS; - goto fail; - } - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - splx(s); - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); - - fail: - if (result) - m_freem(result); - splx(s); - return error; -} - -/* %%% SAD management */ -/* - * allocating a memory for new SA head, and copy from the values of mhp. - * OUT: NULL : failure due to the lack of memory. - * others : pointer to new SA head. - */ -static struct secashead * -key_newsah(saidx) - struct secasindex *saidx; -{ - struct secashead *newsah; - - /* sanity check */ - if (saidx == NULL) - panic("key_newsaidx: NULL pointer is passed."); - - newsah = keydb_newsecashead(); - if (newsah == NULL) - return NULL; - - bcopy(saidx, &newsah->saidx, sizeof(newsah->saidx)); - - /* add to saidxtree */ - newsah->state = SADB_SASTATE_MATURE; - LIST_INSERT_HEAD(&sahtree, newsah, chain); - - return (newsah); -} - -/* - * delete SA index and all SA registerd. - */ -static void -key_delsah(sah) - struct secashead *sah; -{ - struct secasvar *sav, *nextsav; - u_int stateidx, state; - int s; - int zombie = 0; - - /* sanity check */ - if (sah == NULL) - panic("key_delsah: NULL pointer is passed."); - - s = splnet(); /*called from softclock()*/ - - /* searching all SA registerd in the secindex. */ - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_any); - stateidx++) { - - state = saorder_state_any[stateidx]; - for (sav = LIST_FIRST(&sah->savtree[state]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - if (sav->refcnt > 0) { - /* give up to delete this sa */ - zombie++; - continue; - } - - /* sanity check */ - KEY_CHKSASTATE(state, sav->state, "key_delsah"); - - /* remove back pointer */ - sav->sah = NULL; - - key_freesav(sav); - - sav = NULL; - } - } - - /* delete sah only if there's no sav. */ - if (zombie) { - splx(s); - return; - } - - if (sah->sa_route.ro_rt) { - RTFREE(sah->sa_route.ro_rt); - sah->sa_route.ro_rt = (struct rtentry *)NULL; - } - - /* remove from tree of SA index */ - if (__LIST_CHAINED(sah)) - LIST_REMOVE(sah, chain); - - KFREE(sah); - - splx(s); - return; -} - -/* - * allocating a new SA with LARVAL state. key_add() and key_getspi() call, - * and copy the values of mhp into new buffer. - * When SAD message type is GETSPI: - * to set sequence number from acq_seq++, - * to set zero to SPI. - * not to call key_setsava(). - * OUT: NULL : fail - * others : pointer to new secasvar. - * - * does not modify mbuf. does not free mbuf on error. - */ -static struct secasvar * -key_newsav(m, mhp, sah, errp) - struct mbuf *m; - const struct sadb_msghdr *mhp; - struct secashead *sah; - int *errp; -{ - struct secasvar *newsav; - const struct sadb_sa *xsa; - - /* sanity check */ - if (m == NULL || mhp == NULL || mhp->msg == NULL || sah == NULL) - panic("key_newsa: NULL pointer is passed."); - - newsav = keydb_newsecasvar(); - if (newsav == NULL) { - ipseclog((LOG_DEBUG, "key_newsa: No more memory.\n")); - *errp = ENOBUFS; - return NULL; - } - - switch (mhp->msg->sadb_msg_type) { - case SADB_GETSPI: - key_setspi(newsav, 0); - -#ifdef IPSEC_DOSEQCHECK - /* sync sequence number */ - if (mhp->msg->sadb_msg_seq == 0) - newsav->seq = - (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); - else -#endif - newsav->seq = mhp->msg->sadb_msg_seq; - break; - - case SADB_ADD: - /* sanity check */ - if (mhp->ext[SADB_EXT_SA] == NULL) { - KFREE(newsav); - ipseclog((LOG_DEBUG, "key_newsa: invalid message is passed.\n")); - *errp = EINVAL; - return NULL; - } - xsa = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - key_setspi(newsav, xsa->sadb_sa_spi); - newsav->seq = mhp->msg->sadb_msg_seq; - break; - default: - KFREE(newsav); - *errp = EINVAL; - return NULL; - } - - /* copy sav values */ - if (mhp->msg->sadb_msg_type != SADB_GETSPI) { - *errp = key_setsaval(newsav, m, mhp); - if (*errp) { - KFREE(newsav); - return NULL; - } - } - - /* reset created */ - newsav->created = time_second; - - newsav->pid = mhp->msg->sadb_msg_pid; - - /* add to satree */ - newsav->sah = sah; - newsav->refcnt = 1; - newsav->state = SADB_SASTATE_LARVAL; - LIST_INSERT_TAIL(&sah->savtree[SADB_SASTATE_LARVAL], newsav, - secasvar, chain); - - return newsav; -} - -/* - * search SAD. - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secashead * -key_getsah(saidx) - struct secasindex *saidx; -{ - struct secashead *sah; - - LIST_FOREACH(sah, &sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) - return sah; - } - - return NULL; -} - -/* - * check not to be duplicated SPI. - * NOTE: this function is too slow due to searching all SAD. - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secasvar * -key_checkspidup(saidx, spi) - struct secasindex *saidx; - u_int32_t spi; -{ - struct secasvar *sav; - u_int stateidx, state; - - /* check address family */ - if (saidx->src.ss_family != saidx->dst.ss_family) { - ipseclog((LOG_DEBUG, "key_checkspidup: address family mismatched.\n")); - return NULL; - } - - /* check all SAD */ - LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) { - if (sav->spi != spi) - continue; - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_alive); - stateidx++) { - state = saorder_state_alive[stateidx]; - if (sav->state == state && - key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) - return sav; - } - } - - return NULL; -} - -static void -key_setspi(sav, spi) - struct secasvar *sav; - u_int32_t spi; -{ - int s; - - s = splnet(); - sav->spi = spi; - if (sav->spihash.le_prev || sav->spihash.le_next) - LIST_REMOVE(sav, spihash); - LIST_INSERT_HEAD(&spihash[SPIHASH(spi)], sav, spihash); - splx(s); -} - -/* - * search SAD litmited alive SA, protocol, SPI. - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secasvar * -key_getsavbyspi(sah, spi) - struct secashead *sah; - u_int32_t spi; -{ - struct secasvar *sav, *match; - u_int stateidx, state, matchidx; - - match = NULL; - matchidx = _ARRAYLEN(saorder_state_alive); - LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) { - if (sav->spi != spi) - continue; - if (sav->sah != sah) - continue; - for (stateidx = 0; stateidx < matchidx; stateidx++) { - state = saorder_state_alive[stateidx]; - if (sav->state == state) { - match = sav; - matchidx = stateidx; - break; - } - } - } - - return match; -} - -/* - * copy SA values from PF_KEY message except *SPI, SEQ, PID, STATE and TYPE*. - * You must update these if need. - * OUT: 0: success. - * !0: failure. - * - * does not modify mbuf. does not free mbuf on error. - */ -static int -key_setsaval(sav, m, mhp) - struct secasvar *sav; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ -#ifdef IPSEC_ESP - const struct esp_algorithm *algo; -#endif - int error = 0; - - /* sanity check */ - if (m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_setsaval: NULL pointer is passed."); - - /* initialization */ - sav->replay = NULL; - sav->key_auth = NULL; - sav->key_enc = NULL; - sav->sched = NULL; - sav->schedlen = 0; - sav->iv = NULL; - sav->lft_c = NULL; - sav->lft_h = NULL; - sav->lft_s = NULL; - - /* SA */ - if (mhp->ext[SADB_EXT_SA] != NULL) { - const struct sadb_sa *sa0; - - sa0 = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - if (mhp->extlen[SADB_EXT_SA] < sizeof(*sa0)) { - error = EINVAL; - goto fail; - } - - sav->alg_auth = sa0->sadb_sa_auth; - sav->alg_enc = sa0->sadb_sa_encrypt; - sav->flags = sa0->sadb_sa_flags; - - /* replay window */ - if ((sa0->sadb_sa_flags & SADB_X_EXT_OLD) == 0) { - sav->replay = keydb_newsecreplay(sa0->sadb_sa_replay); - if (sav->replay == NULL) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - } - } - - /* Authentication keys */ - if (mhp->ext[SADB_EXT_KEY_AUTH] != NULL) { - const struct sadb_key *key0; - int len; - - key0 = (const struct sadb_key *)mhp->ext[SADB_EXT_KEY_AUTH]; - len = mhp->extlen[SADB_EXT_KEY_AUTH]; - - error = 0; - if (len < sizeof(*key0)) { - error = EINVAL; - goto fail; - } - switch (mhp->msg->sadb_msg_satype) { - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_TCPSIGNATURE: - if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && - sav->alg_auth != SADB_X_AALG_NULL) - error = EINVAL; - break; - case SADB_X_SATYPE_IPCOMP: - default: - error = EINVAL; - break; - } - if (error) { - ipseclog((LOG_DEBUG, "key_setsaval: invalid key_auth values.\n")); - goto fail; - } - - sav->key_auth = (struct sadb_key *)key_newbuf(key0, len); - if (sav->key_auth == NULL) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - } - - /* Encryption key */ - if (mhp->ext[SADB_EXT_KEY_ENCRYPT] != NULL) { - const struct sadb_key *key0; - int len; - - key0 = (const struct sadb_key *)mhp->ext[SADB_EXT_KEY_ENCRYPT]; - len = mhp->extlen[SADB_EXT_KEY_ENCRYPT]; - - error = 0; - if (len < sizeof(*key0)) { - error = EINVAL; - goto fail; - } - switch (mhp->msg->sadb_msg_satype) { - case SADB_SATYPE_ESP: - if (len == PFKEY_ALIGN8(sizeof(struct sadb_key)) && - sav->alg_enc != SADB_EALG_NULL) { - error = EINVAL; - break; - } - sav->key_enc = (struct sadb_key *)key_newbuf(key0, len); - if (sav->key_enc == NULL) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - break; - case SADB_X_SATYPE_IPCOMP: - if (len != PFKEY_ALIGN8(sizeof(struct sadb_key))) - error = EINVAL; - sav->key_enc = NULL; /*just in case*/ - break; - case SADB_SATYPE_AH: - case SADB_X_SATYPE_TCPSIGNATURE: - default: - error = EINVAL; - break; - } - if (error) { - ipseclog((LOG_DEBUG, "key_setsatval: invalid key_enc value.\n")); - goto fail; - } - } - - /* set iv */ - sav->ivlen = 0; - - switch (mhp->msg->sadb_msg_satype) { - case SADB_SATYPE_ESP: -#ifdef IPSEC_ESP - algo = esp_algorithm_lookup(sav->alg_enc); - if (algo && algo->ivlen) - sav->ivlen = (*algo->ivlen)(algo, sav); - if (sav->ivlen == 0) - break; - KMALLOC(sav->iv, caddr_t, sav->ivlen); - if (sav->iv == 0) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - - /* initialize */ - key_randomfill(sav->iv, sav->ivlen); -#endif - break; - case SADB_SATYPE_AH: - case SADB_X_SATYPE_IPCOMP: - case SADB_X_SATYPE_TCPSIGNATURE: - break; - default: - ipseclog((LOG_DEBUG, "key_setsaval: invalid SA type.\n")); - error = EINVAL; - goto fail; - } - - /* reset created */ - sav->created = time_second; - - /* make lifetime for CURRENT */ - KMALLOC(sav->lft_c, struct sadb_lifetime *, - sizeof(struct sadb_lifetime)); - if (sav->lft_c == NULL) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - - sav->lft_c->sadb_lifetime_len = - PFKEY_UNIT64(sizeof(struct sadb_lifetime)); - sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; - sav->lft_c->sadb_lifetime_allocations = 0; - sav->lft_c->sadb_lifetime_bytes = 0; - sav->lft_c->sadb_lifetime_addtime = time_second; - sav->lft_c->sadb_lifetime_usetime = 0; - - /* lifetimes for HARD and SOFT */ - { - const struct sadb_lifetime *lft0; - - lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD]; - if (lft0 != NULL) { - if (mhp->extlen[SADB_EXT_LIFETIME_HARD] < sizeof(*lft0)) { - error = EINVAL; - goto fail; - } - sav->lft_h = (struct sadb_lifetime *)key_newbuf(lft0, - sizeof(*lft0)); - if (sav->lft_h == NULL) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - /* we no longer support byte lifetime */ - if (sav->lft_h->sadb_lifetime_bytes) { - error = EINVAL; - goto fail; - } - /* initialize? */ - } - - lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_SOFT]; - if (lft0 != NULL) { - if (mhp->extlen[SADB_EXT_LIFETIME_SOFT] < sizeof(*lft0)) { - error = EINVAL; - goto fail; - } - sav->lft_s = (struct sadb_lifetime *)key_newbuf(lft0, - sizeof(*lft0)); - if (sav->lft_s == NULL) { - ipseclog((LOG_DEBUG, "key_setsaval: No more memory.\n")); - error = ENOBUFS; - goto fail; - } - /* we no longer support byte lifetime */ - if (sav->lft_s->sadb_lifetime_bytes) { - error = EINVAL; - goto fail; - } - /* initialize? */ - } - } - - return 0; - - fail: - /* initialization */ - if (sav->replay != NULL) { - keydb_delsecreplay(sav->replay); - sav->replay = NULL; - } - if (sav->key_auth != NULL) { - bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth)); - KFREE(sav->key_auth); - sav->key_auth = NULL; - } - if (sav->key_enc != NULL) { - bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc)); - KFREE(sav->key_enc); - sav->key_enc = NULL; - } - if (sav->sched) { - bzero(sav->sched, sav->schedlen); - KFREE(sav->sched); - sav->sched = NULL; - } - if (sav->iv != NULL) { - KFREE(sav->iv); - sav->iv = NULL; - } - if (sav->lft_c != NULL) { - KFREE(sav->lft_c); - sav->lft_c = NULL; - } - if (sav->lft_h != NULL) { - KFREE(sav->lft_h); - sav->lft_h = NULL; - } - if (sav->lft_s != NULL) { - KFREE(sav->lft_s); - sav->lft_s = NULL; - } - - return error; -} - -/* - * validation with a secasvar entry, and set SADB_SATYPE_MATURE. - * OUT: 0: valid - * other: errno - */ -static int -key_mature(sav) - struct secasvar *sav; -{ - int mature; - int checkmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ - int mustmask = 0; /* 2^0: ealg 2^1: aalg 2^2: calg */ - - mature = 0; - - /* check SPI value */ - switch (sav->sah->saidx.proto) { - case IPPROTO_ESP: - case IPPROTO_AH: - if (ntohl(sav->spi) >= 0 && ntohl(sav->spi) <= 255) { - ipseclog((LOG_DEBUG, - "key_mature: illegal range of SPI %u.\n", - (u_int32_t)ntohl(sav->spi))); - return EINVAL; - } - break; - } - - /* check satype */ - switch (sav->sah->saidx.proto) { - case IPPROTO_ESP: - /* check flags */ - if ((sav->flags & SADB_X_EXT_OLD) && - (sav->flags & SADB_X_EXT_DERIV)) { - ipseclog((LOG_DEBUG, "key_mature: " - "invalid flag (derived) given to old-esp.\n")); - return EINVAL; - } - if (sav->alg_auth == SADB_AALG_NONE) - checkmask = 1; - else - checkmask = 3; - mustmask = 1; - break; - case IPPROTO_AH: - /* check flags */ - if (sav->flags & SADB_X_EXT_DERIV) { - ipseclog((LOG_DEBUG, "key_mature: " - "invalid flag (derived) given to AH SA.\n")); - return EINVAL; - } - if (sav->alg_enc != SADB_EALG_NONE) { - ipseclog((LOG_DEBUG, "key_mature: " - "protocol and algorithm mismated.\n")); - return (EINVAL); - } - checkmask = 2; - mustmask = 2; - break; - case IPPROTO_IPCOMP: - if (sav->alg_auth != SADB_AALG_NONE) { - ipseclog((LOG_DEBUG, "key_mature: " - "protocol and algorithm mismated.\n")); - return (EINVAL); - } - if ((sav->flags & SADB_X_EXT_RAWCPI) == 0 && - ntohl(sav->spi) >= 0x10000) { - ipseclog((LOG_DEBUG, "key_mature: invalid cpi for IPComp.\n")); - return (EINVAL); - } - checkmask = 4; - mustmask = 4; - break; - case IPPROTO_TCP: - if (sav->alg_auth != SADB_X_AALG_TCP_MD5) { - ipseclog((LOG_DEBUG, "key_mature: unsupported authentication algorithm %u\n", - sav->alg_auth)); - return (EINVAL); - } - if (sav->alg_enc != SADB_EALG_NONE) { - ipseclog((LOG_DEBUG, "%s: protocol and algorithm " - "mismated.\n", __func__)); - return(EINVAL); - } - if (sav->spi != htonl(0x1000)) { - ipseclog((LOG_DEBUG, "key_mature: SPI must be TCP_SIG_SPI (0x1000)\n")); - return (EINVAL); - } - checkmask = 2; - mustmask = 2; - break; - default: - ipseclog((LOG_DEBUG, "key_mature: Invalid satype.\n")); - return EPROTONOSUPPORT; - } - - /* check authentication algorithm */ - if ((checkmask & 2) != 0) { - const struct ah_algorithm *algo; - int keylen; - - algo = ah_algorithm_lookup(sav->alg_auth); - if (!algo) { - ipseclog((LOG_DEBUG, "key_mature: " - "unknown authentication algorithm.\n")); - return EINVAL; - } - - /* algorithm-dependent check */ - if (sav->key_auth) - keylen = sav->key_auth->sadb_key_bits; - else - keylen = 0; - if (keylen < algo->keymin || algo->keymax < keylen) { - ipseclog((LOG_DEBUG, - "key_mature: invalid AH key length %d " - "(%d-%d allowed)\n", - keylen, algo->keymin, algo->keymax)); - return EINVAL; - } - - if (algo->mature) { - if ((*algo->mature)(sav)) { - /* message generated in per-algorithm function*/ - return EINVAL; - } else - mature = SADB_SATYPE_AH; - } - - if ((mustmask & 2) != 0 && mature != SADB_SATYPE_AH) { - ipseclog((LOG_DEBUG, "key_mature: no satisfy algorithm for AH\n")); - return EINVAL; - } - } - - /* check encryption algorithm */ - if ((checkmask & 1) != 0) { -#ifdef IPSEC_ESP - const struct esp_algorithm *algo; - int keylen; - - algo = esp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_DEBUG, "key_mature: unknown encryption algorithm.\n")); - return EINVAL; - } - - /* algorithm-dependent check */ - if (sav->key_enc) - keylen = sav->key_enc->sadb_key_bits; - else - keylen = 0; - if (keylen < algo->keymin || algo->keymax < keylen) { - ipseclog((LOG_DEBUG, - "key_mature: invalid ESP key length %d " - "(%d-%d allowed)\n", - keylen, algo->keymin, algo->keymax)); - return EINVAL; - } - - if (algo->mature) { - if ((*algo->mature)(sav)) { - /* message generated in per-algorithm function*/ - return EINVAL; - } else - mature = SADB_SATYPE_ESP; - } - - if ((mustmask & 1) != 0 && mature != SADB_SATYPE_ESP) { - ipseclog((LOG_DEBUG, "key_mature: no satisfy algorithm for ESP\n")); - return EINVAL; - } -#else /*IPSEC_ESP*/ - ipseclog((LOG_DEBUG, "key_mature: ESP not supported in this configuration\n")); - return EINVAL; -#endif - } - - /* check compression algorithm */ - if ((checkmask & 4) != 0) { - const struct ipcomp_algorithm *algo; - - /* algorithm-dependent check */ - algo = ipcomp_algorithm_lookup(sav->alg_enc); - if (!algo) { - ipseclog((LOG_DEBUG, "key_mature: unknown compression algorithm.\n")); - return EINVAL; - } - } - - key_sa_chgstate(sav, SADB_SASTATE_MATURE); - - return 0; -} - -/* - * subroutine for SADB_GET and SADB_DUMP. - */ -static struct mbuf * -key_setdumpsa(sav, type, satype, seq, pid) - struct secasvar *sav; - u_int8_t type, satype; - u_int32_t seq, pid; -{ - struct mbuf *result = NULL, *tres = NULL, *m; - int l = 0; - int i; - void *p; - int dumporder[] = { - SADB_EXT_SA, SADB_X_EXT_SA2, - SADB_EXT_LIFETIME_HARD, SADB_EXT_LIFETIME_SOFT, - SADB_EXT_LIFETIME_CURRENT, SADB_EXT_ADDRESS_SRC, - SADB_EXT_ADDRESS_DST, SADB_EXT_ADDRESS_PROXY, SADB_EXT_KEY_AUTH, - SADB_EXT_KEY_ENCRYPT, SADB_EXT_IDENTITY_SRC, - SADB_EXT_IDENTITY_DST, SADB_EXT_SENSITIVITY, - }; - - m = key_setsadbmsg(type, 0, satype, seq, pid, sav->refcnt); - if (m == NULL) - goto fail; - result = m; - - for (i = sizeof(dumporder)/sizeof(dumporder[0]) - 1; i >= 0; i--) { - m = NULL; - p = NULL; - switch (dumporder[i]) { - case SADB_EXT_SA: - m = key_setsadbsa(sav); - if (!m) - goto fail; - break; - - case SADB_X_EXT_SA2: - m = key_setsadbxsa2(sav->sah->saidx.mode, - sav->replay ? (sav->replay->count & 0xffffffff) : 0, - sav->sah->saidx.reqid); - if (!m) - goto fail; - break; - - case SADB_EXT_ADDRESS_SRC: - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sav->sah->saidx.src, - FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) - goto fail; - break; - - case SADB_EXT_ADDRESS_DST: - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sav->sah->saidx.dst, - FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) - goto fail; - break; - - case SADB_EXT_KEY_AUTH: - if (!sav->key_auth) - continue; - l = PFKEY_UNUNIT64(sav->key_auth->sadb_key_len); - p = sav->key_auth; - break; - - case SADB_EXT_KEY_ENCRYPT: - if (!sav->key_enc) - continue; - l = PFKEY_UNUNIT64(sav->key_enc->sadb_key_len); - p = sav->key_enc; - break; - - case SADB_EXT_LIFETIME_CURRENT: - if (!sav->lft_c) - continue; - l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_c)->sadb_ext_len); - p = sav->lft_c; - break; - - case SADB_EXT_LIFETIME_HARD: - if (!sav->lft_h) - continue; - l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_h)->sadb_ext_len); - p = sav->lft_h; - break; - - case SADB_EXT_LIFETIME_SOFT: - if (!sav->lft_s) - continue; - l = PFKEY_UNUNIT64(((struct sadb_ext *)sav->lft_s)->sadb_ext_len); - p = sav->lft_s; - break; - - case SADB_EXT_ADDRESS_PROXY: - case SADB_EXT_IDENTITY_SRC: - case SADB_EXT_IDENTITY_DST: - /* XXX: should we brought from SPD ? */ - case SADB_EXT_SENSITIVITY: - default: - continue; - } - - if ((!m && !p) || (m && p)) - goto fail; - if (p && tres) { - M_PREPEND(tres, l, M_DONTWAIT); - if (!tres) - goto fail; - bcopy(p, mtod(tres, caddr_t), l); - continue; - } - if (p) { - m = key_alloc_mbuf(l); - if (!m) - goto fail; - m_copyback(m, 0, l, p); - } - - if (tres) - m_cat(m, tres); - tres = m; - } - - m_cat(result, tres); - - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) - goto fail; - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - return result; - -fail: - m_freem(result); - m_freem(tres); - return NULL; -} - -/* - * set data into sadb_msg. - */ -static struct mbuf * -key_setsadbmsg(type, tlen, satype, seq, pid, reserved) - u_int8_t type, satype; - u_int16_t tlen; - u_int32_t seq; - pid_t pid; - u_int16_t reserved; -{ - struct mbuf *m; - struct sadb_msg *p; - int len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_msg)); - if (len > MCLBYTES) - return NULL; - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m && len > MHLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - m = NULL; - } - } - if (!m) - return NULL; - m->m_pkthdr.len = m->m_len = len; - m->m_next = NULL; - - p = mtod(m, struct sadb_msg *); - - bzero(p, len); - p->sadb_msg_version = PF_KEY_V2; - p->sadb_msg_type = type; - p->sadb_msg_errno = 0; - p->sadb_msg_satype = satype; - p->sadb_msg_len = PFKEY_UNIT64(tlen); - p->sadb_msg_reserved = reserved; - p->sadb_msg_seq = seq; - p->sadb_msg_pid = (u_int32_t)pid; - - return m; -} - -/* - * copy secasvar data into sadb_address. - */ -static struct mbuf * -key_setsadbsa(sav) - struct secasvar *sav; -{ - struct mbuf *m; - struct sadb_sa *p; - int len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_sa)); - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - p = mtod(m, struct sadb_sa *); - - bzero(p, len); - p->sadb_sa_len = PFKEY_UNIT64(len); - p->sadb_sa_exttype = SADB_EXT_SA; - p->sadb_sa_spi = sav->spi; - p->sadb_sa_replay = (sav->replay != NULL ? sav->replay->wsize : 0); - p->sadb_sa_state = sav->state; - p->sadb_sa_auth = sav->alg_auth; - p->sadb_sa_encrypt = sav->alg_enc; - p->sadb_sa_flags = sav->flags; - - return m; -} - -/* - * set data into sadb_address. - */ -static struct mbuf * -key_setsadbaddr(exttype, saddr, prefixlen, ul_proto) - u_int16_t exttype; - struct sockaddr *saddr; - u_int8_t prefixlen; - u_int16_t ul_proto; -{ - struct mbuf *m; - struct sadb_address *p; - size_t len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_address)) + - PFKEY_ALIGN8(saddr->sa_len); - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - p = mtod(m, struct sadb_address *); - - bzero(p, len); - p->sadb_address_len = PFKEY_UNIT64(len); - p->sadb_address_exttype = exttype; - p->sadb_address_proto = ul_proto; - if (prefixlen == FULLMASK) { - switch (saddr->sa_family) { - case AF_INET: - prefixlen = sizeof(struct in_addr) << 3; - break; - case AF_INET6: - prefixlen = sizeof(struct in6_addr) << 3; - break; - default: - ; /*XXX*/ - } - } - p->sadb_address_prefixlen = prefixlen; - p->sadb_address_reserved = 0; - - bcopy(saddr, - mtod(m, caddr_t) + PFKEY_ALIGN8(sizeof(struct sadb_address)), - saddr->sa_len); - - return m; -} - -#if 0 -/* - * set data into sadb_ident. - */ -static struct mbuf * -key_setsadbident(exttype, idtype, string, stringlen, id) - u_int16_t exttype, idtype; - caddr_t string; - int stringlen; - u_int64_t id; -{ - struct mbuf *m; - struct sadb_ident *p; - size_t len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_ident)) + PFKEY_ALIGN8(stringlen); - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - p = mtod(m, struct sadb_ident *); - - bzero(p, len); - p->sadb_ident_len = PFKEY_UNIT64(len); - p->sadb_ident_exttype = exttype; - p->sadb_ident_type = idtype; - p->sadb_ident_reserved = 0; - p->sadb_ident_id = id; - - bcopy(string, - mtod(m, caddr_t) + PFKEY_ALIGN8(sizeof(struct sadb_ident)), - stringlen); - - return m; -} -#endif - -/* - * set data into sadb_x_sa2. - */ -static struct mbuf * -key_setsadbxsa2(mode, seq, reqid) - u_int8_t mode; - u_int32_t seq, reqid; -{ - struct mbuf *m; - struct sadb_x_sa2 *p; - size_t len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_x_sa2)); - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - p = mtod(m, struct sadb_x_sa2 *); - - bzero(p, len); - p->sadb_x_sa2_len = PFKEY_UNIT64(len); - p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; - p->sadb_x_sa2_mode = mode; - p->sadb_x_sa2_reserved1 = 0; - p->sadb_x_sa2_reserved2 = 0; - p->sadb_x_sa2_sequence = seq; - p->sadb_x_sa2_reqid = reqid; - - return m; -} - -/* - * set data into sadb_lifetime - */ -static struct mbuf * -key_setsadblifetime(type, alloc, bytes, addtime, usetime) - u_int16_t type; - u_int32_t alloc; - u_int64_t bytes, addtime, usetime; -{ - struct mbuf *m; - struct sadb_lifetime *p; - size_t len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_lifetime)); - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - p = mtod(m, struct sadb_lifetime *); - - bzero(p, len); - p->sadb_lifetime_len = PFKEY_UNIT64(len); - p->sadb_lifetime_exttype = type; - p->sadb_lifetime_allocations = alloc; - p->sadb_lifetime_bytes = bytes; - p->sadb_lifetime_addtime = addtime; - p->sadb_lifetime_usetime = usetime; - - return m; -} - -/* - * set data into sadb_x_policy - */ -static struct mbuf * -key_setsadbxpolicy(type, dir, id) - u_int16_t type; - u_int8_t dir; - u_int32_t id; -{ - struct mbuf *m; - struct sadb_x_policy *p; - size_t len; - - len = PFKEY_ALIGN8(sizeof(struct sadb_x_policy)); - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - return NULL; - } - - p = mtod(m, struct sadb_x_policy *); - - bzero(p, len); - p->sadb_x_policy_len = PFKEY_UNIT64(len); - p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; - p->sadb_x_policy_type = type; - p->sadb_x_policy_dir = dir; - p->sadb_x_policy_id = id; - - return m; -} - -/* %%% utilities */ -/* - * copy a buffer into the new buffer allocated. - */ -static void * -key_newbuf(src, len) - const void *src; - u_int len; -{ - caddr_t new; - - KMALLOC(new, caddr_t, len); - if (new == NULL) { - ipseclog((LOG_DEBUG, "key_newbuf: No more memory.\n")); - return NULL; - } - bcopy(src, new, len); - - return new; -} - -/* compare my own address - * OUT: 1: true, i.e. my address. - * 0: false - */ -static int -key_ismyaddr(sa) - struct sockaddr *sa; -{ -#ifdef INET - struct sockaddr_in *sin; - struct in_ifaddr *ia; -#endif - - /* sanity check */ - if (sa == NULL) - panic("key_ismyaddr: NULL pointer is passed."); - - switch (sa->sa_family) { -#ifdef INET - case AF_INET: - sin = (struct sockaddr_in *)sa; - for (ia = in_ifaddrhead.tqh_first; ia; - ia = ia->ia_link.tqe_next) - { - if (sin->sin_family == ia->ia_addr.sin_family && - sin->sin_len == ia->ia_addr.sin_len && - sin->sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) - { - return 1; - } - } - break; -#endif -#ifdef INET6 - case AF_INET6: - return key_ismyaddr6((struct sockaddr_in6 *)sa); -#endif - } - - return 0; -} - -#ifdef INET6 -/* - * compare my own address for IPv6. - * 1: ours - * 0: other - * NOTE: derived ip6_input() in KAME. This is necessary to modify more. - */ -#include <netinet6/in6_var.h> - -static int -key_ismyaddr6(sin6) - struct sockaddr_in6 *sin6; -{ - struct in6_ifaddr *ia; - struct in6_multi *in6m; - - if (sa6_embedscope(sin6, 0) != 0) - return 0; - - for (ia = in6_ifaddr; ia; ia = ia->ia_next) { - if (key_sockaddrcmp((struct sockaddr *)&sin6, - (struct sockaddr *)&ia->ia_addr, 0) == 0) - return 1; - - /* - * XXX Multicast - * XXX why do we care about multlicast here while we don't care - * about IPv4 multicast?? - */ - in6m = NULL; - IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m); - if (in6m) - return 1; - } - - /* loopback, just for safety */ - if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) - return 1; - - return 0; -} -#endif /*INET6*/ - -/* - * compare two secasindex structure. - * flag can specify to compare 2 saidxes. - * compare two secasindex structure without both mode and reqid. - * don't compare port. - * IN: - * saidx0: source, it can be in SAD. - * saidx1: object. - * OUT: - * 1 : equal - * 0 : not equal - */ -static int -key_cmpsaidx(saidx0, saidx1, flag) - struct secasindex *saidx0, *saidx1; - int flag; -{ - /* sanity */ - if (saidx0 == NULL && saidx1 == NULL) - return 1; - - if (saidx0 == NULL || saidx1 == NULL) - return 0; - - if (saidx0->proto != saidx1->proto) - return 0; - - if (flag == CMP_EXACTLY) { - if (saidx0->mode != saidx1->mode) - return 0; - if (saidx0->reqid != saidx1->reqid) - return 0; - if (bcmp(&saidx0->src, &saidx1->src, saidx0->src.ss_len) != 0 || - bcmp(&saidx0->dst, &saidx1->dst, saidx0->dst.ss_len) != 0) - return 0; - } else { - - /* CMP_MODE_REQID, CMP_HEAD */ - if (flag == CMP_MODE_REQID) { - /* - * If reqid of SPD is non-zero, unique SA is required. - * The result must be of same reqid in this case. - */ - if (saidx1->reqid != 0 && saidx0->reqid != saidx1->reqid) - return 0; - } - - if (flag == CMP_MODE_REQID) { - if (saidx0->mode != IPSEC_MODE_ANY && - saidx0->mode != saidx1->mode) - return 0; - } - - if (key_sockaddrcmp((struct sockaddr *)&saidx0->src, - (struct sockaddr *)&saidx1->src, 0) != 0) { - return 0; - } - if (key_sockaddrcmp((struct sockaddr *)&saidx0->dst, - (struct sockaddr *)&saidx1->dst, 0) != 0) { - return 0; - } - } - - return 1; -} - -/* - * compare two secindex structure exactly. - * IN: - * spidx0: source, it is often in SPD. - * spidx1: object, it is often from PFKEY message. - * OUT: - * 1 : equal - * 0 : not equal - */ -int -key_cmpspidx_exactly(spidx0, spidx1) - struct secpolicyindex *spidx0, *spidx1; -{ - /* sanity */ - if (spidx0 == NULL && spidx1 == NULL) - return 1; - - if (spidx0 == NULL || spidx1 == NULL) - return 0; - - if (spidx0->prefs != spidx1->prefs || spidx0->prefd != spidx1->prefd || - spidx0->ul_proto != spidx1->ul_proto) - return 0; - - if (key_sockaddrcmp((struct sockaddr *)&spidx0->src, - (struct sockaddr *)&spidx1->src, 1) != 0) { - return 0; - } - if (key_sockaddrcmp((struct sockaddr *)&spidx0->dst, - (struct sockaddr *)&spidx1->dst, 1) != 0) { - return 0; - } - - return 1; -} - -/* - * compare two secindex structure with mask. - * IN: - * spidx0: source, it is often in SPD. - * spidx1: object, it is often from IP header. - * OUT: - * 1 : equal - * 0 : not equal - */ -int -key_cmpspidx_withmask(spidx0, spidx1) - struct secpolicyindex *spidx0, *spidx1; -{ - /* sanity */ - if (spidx0 == NULL && spidx1 == NULL) - return 1; - - if (spidx0 == NULL || spidx1 == NULL) - return 0; - - if (spidx0->src.ss_family != spidx1->src.ss_family || - spidx0->dst.ss_family != spidx1->dst.ss_family || - spidx0->src.ss_len != spidx1->src.ss_len || - spidx0->dst.ss_len != spidx1->dst.ss_len) - return 0; - - /* if spidx.ul_proto == IPSEC_ULPROTO_ANY, ignore. */ - if (spidx0->ul_proto != (u_int16_t)IPSEC_ULPROTO_ANY && - spidx0->ul_proto != spidx1->ul_proto) - return 0; - - switch (spidx0->src.ss_family) { - case AF_INET: - if (satosin(&spidx0->src)->sin_port != IPSEC_PORT_ANY && - satosin(&spidx0->src)->sin_port != - satosin(&spidx1->src)->sin_port) - return 0; - if (!key_bbcmp((caddr_t)&satosin(&spidx0->src)->sin_addr, - (caddr_t)&satosin(&spidx1->src)->sin_addr, spidx0->prefs)) - return 0; - break; - case AF_INET6: - if (satosin6(&spidx0->src)->sin6_port != IPSEC_PORT_ANY && - satosin6(&spidx0->src)->sin6_port != - satosin6(&spidx1->src)->sin6_port) - return 0; - /* - * scope_id check. if sin6_scope_id is 0, we regard it - * as a wildcard scope, which matches any scope zone ID. - */ - if (satosin6(&spidx0->src)->sin6_scope_id && - satosin6(&spidx1->src)->sin6_scope_id && - satosin6(&spidx0->src)->sin6_scope_id != - satosin6(&spidx1->src)->sin6_scope_id) - return 0; - if (!key_bbcmp((caddr_t)&satosin6(&spidx0->src)->sin6_addr, - (caddr_t)&satosin6(&spidx1->src)->sin6_addr, spidx0->prefs)) - return 0; - break; - default: - /* XXX */ - if (bcmp(&spidx0->src, &spidx1->src, spidx0->src.ss_len) != 0) - return 0; - break; - } - - switch (spidx0->dst.ss_family) { - case AF_INET: - if (satosin(&spidx0->dst)->sin_port != IPSEC_PORT_ANY && - satosin(&spidx0->dst)->sin_port != - satosin(&spidx1->dst)->sin_port) - return 0; - if (!key_bbcmp((caddr_t)&satosin(&spidx0->dst)->sin_addr, - (caddr_t)&satosin(&spidx1->dst)->sin_addr, spidx0->prefd)) - return 0; - break; - case AF_INET6: - if (satosin6(&spidx0->dst)->sin6_port != IPSEC_PORT_ANY && - satosin6(&spidx0->dst)->sin6_port != - satosin6(&spidx1->dst)->sin6_port) - return 0; - /* - * scope_id check. if sin6_scope_id is 0, we regard it - * as a wildcard scope, which matches any scope zone ID. - */ - if (satosin6(&spidx0->src)->sin6_scope_id && - satosin6(&spidx1->src)->sin6_scope_id && - satosin6(&spidx0->dst)->sin6_scope_id != - satosin6(&spidx1->dst)->sin6_scope_id) - return 0; - if (!key_bbcmp((caddr_t)&satosin6(&spidx0->dst)->sin6_addr, - (caddr_t)&satosin6(&spidx1->dst)->sin6_addr, spidx0->prefd)) - return 0; - break; - default: - /* XXX */ - if (bcmp(&spidx0->dst, &spidx1->dst, spidx0->dst.ss_len) != 0) - return 0; - break; - } - - /* XXX Do we check other field ? e.g. flowinfo */ - - return 1; -} - -/* returns 0 on match */ -static int -key_sockaddrcmp(sa1, sa2, port) - struct sockaddr *sa1; - struct sockaddr *sa2; - int port; -{ - if (sa1->sa_family != sa2->sa_family || sa1->sa_len != sa2->sa_len) - return 1; - - switch (sa1->sa_family) { - case AF_INET: - if (sa1->sa_len != sizeof(struct sockaddr_in)) - return 1; - if (satosin(sa1)->sin_addr.s_addr != - satosin(sa2)->sin_addr.s_addr) { - return 1; - } - if (port && satosin(sa1)->sin_port != satosin(sa2)->sin_port) - return 1; - break; - case AF_INET6: - if (sa1->sa_len != sizeof(struct sockaddr_in6)) - return 1; /*EINVAL*/ - if (satosin6(sa1)->sin6_scope_id != - satosin6(sa2)->sin6_scope_id) { - return 1; - } - if (!IN6_ARE_ADDR_EQUAL(&satosin6(sa1)->sin6_addr, - &satosin6(sa2)->sin6_addr)) { - return 1; - } - if (port && - satosin6(sa1)->sin6_port != satosin6(sa2)->sin6_port) { - return 1; - } - break; - default: - if (bcmp(sa1, sa2, sa1->sa_len) != 0) - return 1; - break; - } - - return 0; -} - -/* - * compare two buffers with mask. - * IN: - * addr1: source - * addr2: object - * bits: Number of bits to compare - * OUT: - * 1 : equal - * 0 : not equal - */ -static int -key_bbcmp(p1, p2, bits) - caddr_t p1, p2; - u_int bits; -{ - u_int8_t mask; - - /* XXX: This could be considerably faster if we compare a word - * at a time, but it is complicated on LSB Endian machines */ - - /* Handle null pointers */ - if (p1 == NULL || p2 == NULL) - return (p1 == p2); - - while (bits >= 8) { - if (*p1++ != *p2++) - return 0; - bits -= 8; - } - - if (bits > 0) { - mask = ~((1<<(8-bits))-1); - if ((*p1 & mask) != (*p2 & mask)) - return 0; - } - return 1; /* Match! */ -} - -/* - * time handler. - * scanning SPD and SAD to check status for each entries, - * and do to remove or to expire. - * XXX: year 2038 problem may remain. - */ -void -key_timehandler(arg) - void *arg; -{ - u_int dir; - int s; - struct timeval tv; - - microtime(&tv); - - s = splnet(); /*called from softclock()*/ - - /* SPD */ - { - struct secpolicy *sp, *nextsp; - - for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - for (sp = LIST_FIRST(&sptree[dir]); - sp != NULL; - sp = nextsp) { - nextsp = LIST_NEXT(sp, chain); - - if (sp->state == IPSEC_SPSTATE_DEAD) { - key_sp_unlink(sp); /*XXX*/ - sp = NULL; - continue; - } - - if (sp->lifetime == 0 && sp->validtime == 0) - continue; - - /* the deletion will occur next time */ - if ((sp->lifetime && - tv.tv_sec - sp->created > sp->lifetime) || - (sp->validtime && - tv.tv_sec - sp->lastused > sp->validtime)) { - key_sp_dead(sp); - key_spdexpire(sp); - continue; - } - } - } - - /* invalidate all cached SPD pointers on pcb */ - ipsec_invalpcbcacheall(); - } - - /* SAD */ - { - struct secashead *sah, *nextsah; - struct secasvar *sav, *nextsav; - - for (sah = LIST_FIRST(&sahtree); - sah != NULL; - sah = nextsah) { - - nextsah = LIST_NEXT(sah, chain); - - /* if sah has been dead, then delete it and process next sah. */ - if (sah->state == SADB_SASTATE_DEAD) { - key_delsah(sah); - continue; - } - - /* if LARVAL entry doesn't become MATURE, delete it. */ - for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_LARVAL]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - if (tv.tv_sec - sav->created > key_larval_lifetime) { - key_freesav(sav); - } - } - - /* - * check MATURE entry to start to send expire message - * whether or not. - */ - for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_MATURE]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - /* we don't need to check. */ - if (sav->lft_s == NULL) - continue; - - /* sanity check */ - if (sav->lft_c == NULL) { - ipseclog((LOG_DEBUG, "key_timehandler: " - "There is no CURRENT time, why?\n")); - continue; - } - - /* check SOFT lifetime */ - if (sav->lft_s->sadb_lifetime_addtime != 0 && - tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { - /* - * check the SA if it has been used. - * when it hasn't been used, delete it. - * i don't think such SA will be used. - */ - if (sav->lft_c->sadb_lifetime_usetime == 0) { - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - key_freesav(sav); - sav = NULL; - } else { - key_sa_chgstate(sav, SADB_SASTATE_DYING); - /* - * XXX If we keep to send expire - * message in the status of - * DYING. Do remove below code. - */ - key_expire(sav); - } - } - - /* check SOFT lifetime by bytes */ - /* - * XXX I don't know the way to delete this SA - * when new SA is installed. Caution when it's - * installed too big lifetime by time. - */ - else if (sav->lft_s->sadb_lifetime_bytes != 0 - && sav->lft_s->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { - - key_sa_chgstate(sav, SADB_SASTATE_DYING); - /* - * XXX If we keep to send expire - * message in the status of - * DYING. Do remove below code. - */ - key_expire(sav); - } - } - - /* check DYING entry to change status to DEAD. */ - for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DYING]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - /* we don't need to check. */ - if (sav->lft_h == NULL) - continue; - - /* sanity check */ - if (sav->lft_c == NULL) { - ipseclog((LOG_DEBUG, "key_timehandler: " - "There is no CURRENT time, why?\n")); - continue; - } - - if (sav->lft_h->sadb_lifetime_addtime != 0 && - tv.tv_sec - sav->created > sav->lft_h->sadb_lifetime_addtime) { - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - key_freesav(sav); - sav = NULL; - } -#if 0 /* XXX Should we keep to send expire message until HARD lifetime ? */ - else if (sav->lft_s != NULL - && sav->lft_s->sadb_lifetime_addtime != 0 - && tv.tv_sec - sav->created > sav->lft_s->sadb_lifetime_addtime) { - /* - * XXX: should be checked to be - * installed the valid SA. - */ - - /* - * If there is no SA then sending - * expire message. - */ - key_expire(sav); - } -#endif - /* check HARD lifetime by bytes */ - else if (sav->lft_h->sadb_lifetime_bytes != 0 - && sav->lft_h->sadb_lifetime_bytes < sav->lft_c->sadb_lifetime_bytes) { - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - key_freesav(sav); - sav = NULL; - } - } - - /* delete entry in DEAD */ - for (sav = LIST_FIRST(&sah->savtree[SADB_SASTATE_DEAD]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - /* sanity check */ - if (sav->state != SADB_SASTATE_DEAD) { - ipseclog((LOG_DEBUG, "key_timehandler: " - "invalid sav->state " - "(queue: %u SA: %u): " - "kill it anyway\n", - SADB_SASTATE_DEAD, sav->state)); - } - - /* - * do not call key_freesav() here. - * sav should already be freed, and sav->refcnt - * shows other references to sav - * (such as from SPD). - */ - } - } - } - -#ifndef IPSEC_NONBLOCK_ACQUIRE - /* ACQ tree */ - { - struct secacq *acq, *nextacq; - - for (acq = LIST_FIRST(&acqtree); - acq != NULL; - acq = nextacq) { - - nextacq = LIST_NEXT(acq, chain); - - if (tv.tv_sec - acq->created > key_blockacq_lifetime && - __LIST_CHAINED(acq)) { - LIST_REMOVE(acq, chain); - KFREE(acq); - } - } - } -#endif - - /* SP ACQ tree */ - { - struct secspacq *acq, *nextacq; - - for (acq = LIST_FIRST(&spacqtree); - acq != NULL; - acq = nextacq) { - - nextacq = LIST_NEXT(acq, chain); - - if (tv.tv_sec - acq->created > key_blockacq_lifetime && - __LIST_CHAINED(acq)) { - LIST_REMOVE(acq, chain); - KFREE(acq); - } - } - } - - /* - * should set timeout based on the most closest timer expiration. - * we don't bother to do that yet. - */ - callout_reset(&key_timehandler_ch, hz, key_timehandler, (void *)0); - - splx(s); - return; -} - -static u_long -key_random() -{ - u_long value; - - key_randomfill(&value, sizeof(value)); - return value; -} - -void -key_randomfill(p, l) - void *p; - size_t l; -{ - size_t n; - u_long v; - static int warn = 1; - - n = 0; - n = (size_t)read_random(p, (u_int)l); - /* last resort */ - while (n < l) { - v = random(); - bcopy(&v, (u_int8_t *)p + n, - l - n < sizeof(v) ? l - n : sizeof(v)); - n += sizeof(v); - - if (warn) { - printf("WARNING: pseudo-random number generator " - "used for IPsec processing\n"); - warn = 0; - } - } -} - -/* - * map SADB_SATYPE_* to IPPROTO_*. - * if satype == SADB_SATYPE then satype is mapped to ~0. - * OUT: - * 0: invalid satype. - */ -static u_int16_t -key_satype2proto(satype) - u_int8_t satype; -{ - switch (satype) { - case SADB_SATYPE_UNSPEC: - return IPSEC_PROTO_ANY; - case SADB_SATYPE_AH: - return IPPROTO_AH; - case SADB_SATYPE_ESP: - return IPPROTO_ESP; - case SADB_X_SATYPE_IPCOMP: - return IPPROTO_IPCOMP; - case SADB_X_SATYPE_TCPSIGNATURE: - return IPPROTO_TCP; - default: - return 0; - } - /* NOTREACHED */ -} - -/* - * map IPPROTO_* to SADB_SATYPE_* - * OUT: - * 0: invalid protocol type. - */ -static u_int8_t -key_proto2satype(proto) - u_int16_t proto; -{ - switch (proto) { - case IPPROTO_AH: - return SADB_SATYPE_AH; - case IPPROTO_ESP: - return SADB_SATYPE_ESP; - case IPPROTO_IPCOMP: - return SADB_X_SATYPE_IPCOMP; - case IPPROTO_TCP: - return SADB_X_SATYPE_TCPSIGNATURE; - default: - return 0; - } - /* NOTREACHED */ -} - -/* %%% PF_KEY */ -/* - * SADB_GETSPI processing is to receive - * <base, (SA2), src address, dst address, (SPI range)> - * from the IKMPd, to assign a unique spi value, to hang on the INBOUND - * tree with the status of LARVAL, and send - * <base, SA(*), address(SD)> - * to the IKMPd. - * - * IN: mhp: pointer to the pointer to each header. - * OUT: NULL if fail. - * other if success, return pointer to the message to send. - */ -static int -key_getspi(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *newsah; - struct secasvar *newsav; - u_int8_t proto; - u_int32_t spi; - u_int8_t mode; - u_int32_t reqid; - int error; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_getspi: NULL pointer is passed."); - - if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { - ipseclog((LOG_DEBUG, "key_getspi: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { - ipseclog((LOG_DEBUG, "key_getspi: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->ext[SADB_X_EXT_SA2] != NULL) { - mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode; - reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid; - } else { - mode = IPSEC_MODE_ANY; - reqid = 0; - } - - src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_getspi: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - /* make sure if port number is zero. */ - switch (((struct sockaddr *)(src0 + 1))->sa_family) { - case AF_INET: - if (((struct sockaddr *)(src0 + 1))->sa_len != - sizeof(struct sockaddr_in)) - return key_senderror(so, m, EINVAL); - ((struct sockaddr_in *)(src0 + 1))->sin_port = 0; - break; - case AF_INET6: - if (((struct sockaddr *)(src0 + 1))->sa_len != - sizeof(struct sockaddr_in6)) - return key_senderror(so, m, EINVAL); - ((struct sockaddr_in6 *)(src0 + 1))->sin6_port = 0; - break; - default: - ; /*???*/ - } - switch (((struct sockaddr *)(dst0 + 1))->sa_family) { - case AF_INET: - if (((struct sockaddr *)(dst0 + 1))->sa_len != - sizeof(struct sockaddr_in)) - return key_senderror(so, m, EINVAL); - ((struct sockaddr_in *)(dst0 + 1))->sin_port = 0; - break; - case AF_INET6: - if (((struct sockaddr *)(dst0 + 1))->sa_len != - sizeof(struct sockaddr_in6)) - return key_senderror(so, m, EINVAL); - ((struct sockaddr_in6 *)(dst0 + 1))->sin6_port = 0; - break; - default: - ; /*???*/ - } - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); - - /* SPI allocation */ - spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE], - &saidx); - if (spi == 0) - return key_senderror(so, m, EINVAL); - - /* get a SA index */ - if ((newsah = key_getsah(&saidx)) == NULL) { - /* create a new SA index */ - if ((newsah = key_newsah(&saidx)) == NULL) { - ipseclog((LOG_DEBUG, "key_getspi: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - } - - /* get a new SA */ - /* XXX rewrite */ - newsav = key_newsav(m, mhp, newsah, &error); - if (newsav == NULL) { - /* XXX don't free new SA index allocated in above. */ - return key_senderror(so, m, error); - } - - /* set spi */ - key_setspi(newsav, htonl(spi)); - -#ifndef IPSEC_NONBLOCK_ACQUIRE - /* delete the entry in acqtree */ - if (mhp->msg->sadb_msg_seq != 0) { - struct secacq *acq; - if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) { - /* reset counter in order to deletion by timehandler. */ - acq->created = time_second; - acq->count = 0; - } - } -#endif - - { - struct mbuf *n, *nn; - struct sadb_sa *m_sa; - struct sadb_msg *newmsg; - int off, len; - - /* create new sadb_msg to reply. */ - len = PFKEY_ALIGN8(sizeof(struct sadb_msg)) + - PFKEY_ALIGN8(sizeof(struct sadb_sa)); - if (len > MCLBYTES) - return key_senderror(so, m, ENOBUFS); - - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (len > MHLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - n = NULL; - } - } - if (!n) - return key_senderror(so, m, ENOBUFS); - - n->m_len = len; - n->m_next = NULL; - off = 0; - - m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off); - off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); - - m_sa = (struct sadb_sa *)(mtod(n, caddr_t) + off); - m_sa->sadb_sa_len = PFKEY_UNIT64(sizeof(struct sadb_sa)); - m_sa->sadb_sa_exttype = SADB_EXT_SA; - m_sa->sadb_sa_spi = htonl(spi); - off += PFKEY_ALIGN8(sizeof(struct sadb_sa)); - -#ifdef DIAGNOSTIC - if (off != len) - panic("length inconsistency in key_getspi"); -#endif - - n->m_next = key_gather_mbuf(m, mhp, 0, 2, SADB_EXT_ADDRESS_SRC, - SADB_EXT_ADDRESS_DST); - if (!n->m_next) { - m_freem(n); - return key_senderror(so, m, ENOBUFS); - } - - if (n->m_len < sizeof(struct sadb_msg)) { - n = m_pullup(n, sizeof(struct sadb_msg)); - if (n == NULL) - return key_sendup_mbuf(so, m, KEY_SENDUP_ONE); - } - - n->m_pkthdr.len = 0; - for (nn = n; nn; nn = nn->m_next) - n->m_pkthdr.len += nn->m_len; - - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_seq = newsav->seq; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); - } -} - -/* - * allocating new SPI - * called by key_getspi(). - * OUT: - * 0: failure. - * others: success. - */ -static u_int32_t -key_do_getnewspi(spirange, saidx) - struct sadb_spirange *spirange; - struct secasindex *saidx; -{ - u_int32_t newspi; - u_int32_t min, max; - int count = key_spi_trycnt; - - /* set spi range to allocate */ - if (spirange != NULL) { - min = spirange->sadb_spirange_min; - max = spirange->sadb_spirange_max; - } else { - min = key_spi_minval; - max = key_spi_maxval; - } - /* IPCOMP needs 2-byte SPI */ - if (saidx->proto == IPPROTO_IPCOMP) { - u_int32_t t; - if (min >= 0x10000) - min = 0xffff; - if (max >= 0x10000) - max = 0xffff; - if (min > max) { - t = min; min = max; max = t; - } - } - - if (min == max) { - if (key_checkspidup(saidx, min) != NULL) { - ipseclog((LOG_DEBUG, "key_do_getnewspi: SPI %u exists already.\n", min)); - return 0; - } - - count--; /* taking one cost. */ - newspi = min; - - } else { - - /* init SPI */ - newspi = 0; - - /* when requesting to allocate spi ranged */ - while (count--) { - /* generate pseudo-random SPI value ranged. */ - newspi = min + (key_random() % (max - min + 1)); - - if (key_checkspidup(saidx, newspi) == NULL) - break; - } - - if (count == 0 || newspi == 0) { - ipseclog((LOG_DEBUG, "key_do_getnewspi: to allocate spi is failed.\n")); - return 0; - } - } - - /* statistics */ - keystat.getspi_count = - (keystat.getspi_count + key_spi_trycnt - count) / 2; - - return newspi; -} - -/* - * SADB_UPDATE processing - * receive - * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),) - * key(AE), (identity(SD),) (sensitivity)> - * from the ikmpd, and update a secasvar entry whose status is SADB_SASTATE_LARVAL. - * and send - * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),) - * (identity(SD),) (sensitivity)> - * to the ikmpd. - * - * m will always be freed. - */ -static int -key_update(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_sa *sa0; - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *sah; - struct secasvar *sav; - u_int16_t proto; - u_int8_t mode; - u_int32_t reqid; - int error; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_update: NULL pointer is passed."); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_update: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->ext[SADB_EXT_SA] == NULL || - mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || - (mhp->msg->sadb_msg_satype == SADB_SATYPE_ESP && - mhp->ext[SADB_EXT_KEY_ENCRYPT] == NULL) || - (mhp->msg->sadb_msg_satype == SADB_SATYPE_AH && - mhp->ext[SADB_EXT_KEY_AUTH] == NULL) || - (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL && - mhp->ext[SADB_EXT_LIFETIME_SOFT] == NULL) || - (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL && - mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) { - ipseclog((LOG_DEBUG, "key_update: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || - mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { - ipseclog((LOG_DEBUG, "key_update: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->ext[SADB_X_EXT_SA2] != NULL) { - mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode; - reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid; - } else { - mode = IPSEC_MODE_ANY; - reqid = 0; - } - /* XXX boundary checking for other extensions */ - - sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); - - /* get a SA header */ - if ((sah = key_getsah(&saidx)) == NULL) { - ipseclog((LOG_DEBUG, "key_update: no SA index found.\n")); - return key_senderror(so, m, ENOENT); - } - - /* set spidx if there */ - /* XXX rewrite */ - error = key_setident(sah, m, mhp); - if (error) - return key_senderror(so, m, error); - - /* find a SA with sequence number. */ -#ifdef IPSEC_DOSEQCHECK - if (mhp->msg->sadb_msg_seq != 0 && - (sav = key_getsavbyseq(sah, mhp->msg->sadb_msg_seq)) == NULL) { - ipseclog((LOG_DEBUG, - "key_update: no larval SA with sequence %u exists.\n", - mhp->msg->sadb_msg_seq)); - return key_senderror(so, m, ENOENT); - } -#else - if ((sav = key_getsavbyspi(sah, sa0->sadb_sa_spi)) == NULL) { - ipseclog((LOG_DEBUG, - "key_update: no such a SA found (spi:%u)\n", - (u_int32_t)ntohl(sa0->sadb_sa_spi))); - return key_senderror(so, m, EINVAL); - } -#endif - - /* validity check */ - if (sav->sah->saidx.proto != proto) { - ipseclog((LOG_DEBUG, - "key_update: protocol mismatched (DB=%u param=%u)\n", - sav->sah->saidx.proto, proto)); - return key_senderror(so, m, EINVAL); - } -#ifdef IPSEC_DOSEQCHECK - if (sav->spi != sa0->sadb_sa_spi) { - ipseclog((LOG_DEBUG, - "key_update: SPI mismatched (DB:%u param:%u)\n", - (u_int32_t)ntohl(sav->spi), - (u_int32_t)ntohl(sa0->sadb_sa_spi))); - return key_senderror(so, m, EINVAL); - } -#endif - if (sav->pid != mhp->msg->sadb_msg_pid) { - ipseclog((LOG_DEBUG, - "key_update: pid mismatched (DB:%u param:%u)\n", - sav->pid, mhp->msg->sadb_msg_pid)); - return key_senderror(so, m, EINVAL); - } - - /* copy sav values */ - error = key_setsaval(sav, m, mhp); - if (error) { - key_freesav(sav); - return key_senderror(so, m, error); - } - - /* check SA values to be mature. */ - if ((error = key_mature(sav)) != 0) { - key_freesav(sav); - return key_senderror(so, m, error); - } - - { - struct mbuf *n; - - /* set msg buf from mhp */ - n = key_getmsgbuf_x1(m, mhp); - if (n == NULL) { - ipseclog((LOG_DEBUG, "key_update: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* - * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL. - * only called by key_update(). - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -#ifdef IPSEC_DOSEQCHECK -static struct secasvar * -key_getsavbyseq(sah, seq) - struct secashead *sah; - u_int32_t seq; -{ - struct secasvar *sav; - u_int state; - - state = SADB_SASTATE_LARVAL; - - /* search SAD with sequence number ? */ - LIST_FOREACH(sav, &sah->savtree[state], chain) { - - KEY_CHKSASTATE(state, sav->state, "key_getsabyseq"); - - if (sav->seq == seq) { - sav->refcnt++; - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP key_getsavbyseq cause " - "refcnt++:%d SA:%p\n", - sav->refcnt, sav)); - return sav; - } - } - - return NULL; -} -#endif - -/* - * SADB_ADD processing - * add an entry to SA database, when received - * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),) - * key(AE), (identity(SD),) (sensitivity)> - * from the ikmpd, - * and send - * <base, SA, (SA2), (lifetime(HSC),) address(SD), (address(P),) - * (identity(SD),) (sensitivity)> - * to the ikmpd. - * - * IGNORE identity and sensitivity messages. - * - * m will always be freed. - */ -static int -key_add(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_sa *sa0; - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *newsah; - struct secasvar *newsav; - u_int16_t proto; - u_int8_t mode; - u_int32_t reqid; - int error; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_add: NULL pointer is passed."); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_add: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->ext[SADB_EXT_SA] == NULL || - mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || - (mhp->msg->sadb_msg_satype == SADB_SATYPE_ESP && - mhp->ext[SADB_EXT_KEY_ENCRYPT] == NULL) || - (mhp->msg->sadb_msg_satype == SADB_SATYPE_AH && - mhp->ext[SADB_EXT_KEY_AUTH] == NULL) || - (mhp->ext[SADB_EXT_LIFETIME_HARD] != NULL && - mhp->ext[SADB_EXT_LIFETIME_SOFT] == NULL) || - (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL && - mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) { - ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || - mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { - /* XXX need more */ - ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->ext[SADB_X_EXT_SA2] != NULL) { - mode = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_mode; - reqid = ((struct sadb_x_sa2 *)mhp->ext[SADB_X_EXT_SA2])->sadb_x_sa2_reqid; - } else { - mode = IPSEC_MODE_ANY; - reqid = 0; - } - - sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; - dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); - - /* get a SA header */ - if ((newsah = key_getsah(&saidx)) == NULL) { - /* create a new SA header */ - if ((newsah = key_newsah(&saidx)) == NULL) { - ipseclog((LOG_DEBUG, "key_add: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - } - - /* set spidx if there */ - /* XXX rewrite */ - error = key_setident(newsah, m, mhp); - if (error) { - return key_senderror(so, m, error); - } - - /* create new SA entry. */ - /* We can create new SA only if SPI is differenct. */ - if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) { - ipseclog((LOG_DEBUG, "key_add: SA already exists.\n")); - return key_senderror(so, m, EEXIST); - } - newsav = key_newsav(m, mhp, newsah, &error); - if (newsav == NULL) { - return key_senderror(so, m, error); - } - - /* check SA values to be mature. */ - if ((error = key_mature(newsav)) != 0) { - key_freesav(newsav); - return key_senderror(so, m, error); - } - - /* - * don't call key_freesav() here, as we would like to keep the SA - * in the database on success. - */ - - { - struct mbuf *n; - - /* set msg buf from mhp */ - n = key_getmsgbuf_x1(m, mhp); - if (n == NULL) { - ipseclog((LOG_DEBUG, "key_update: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* m is retained */ -static int -key_setident(sah, m, mhp) - struct secashead *sah; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - const struct sadb_ident *idsrc, *iddst; - int idsrclen, iddstlen; - - /* sanity check */ - if (sah == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_setident: NULL pointer is passed."); - - /* don't make buffer if not there */ - if (mhp->ext[SADB_EXT_IDENTITY_SRC] == NULL && - mhp->ext[SADB_EXT_IDENTITY_DST] == NULL) { - sah->idents = NULL; - sah->identd = NULL; - return 0; - } - - if (mhp->ext[SADB_EXT_IDENTITY_SRC] == NULL || - mhp->ext[SADB_EXT_IDENTITY_DST] == NULL) { - ipseclog((LOG_DEBUG, "key_setident: invalid identity.\n")); - return EINVAL; - } - - idsrc = (const struct sadb_ident *)mhp->ext[SADB_EXT_IDENTITY_SRC]; - iddst = (const struct sadb_ident *)mhp->ext[SADB_EXT_IDENTITY_DST]; - idsrclen = mhp->extlen[SADB_EXT_IDENTITY_SRC]; - iddstlen = mhp->extlen[SADB_EXT_IDENTITY_DST]; - - /* validity check */ - if (idsrc->sadb_ident_type != iddst->sadb_ident_type) { - ipseclog((LOG_DEBUG, "key_setident: ident type mismatch.\n")); - return EINVAL; - } - - switch (idsrc->sadb_ident_type) { - case SADB_IDENTTYPE_PREFIX: - case SADB_IDENTTYPE_FQDN: - case SADB_IDENTTYPE_USERFQDN: - default: - /* XXX do nothing */ - sah->idents = NULL; - sah->identd = NULL; - return 0; - } - - /* make structure */ - KMALLOC(sah->idents, struct sadb_ident *, idsrclen); - if (sah->idents == NULL) { - ipseclog((LOG_DEBUG, "key_setident: No more memory.\n")); - return ENOBUFS; - } - KMALLOC(sah->identd, struct sadb_ident *, iddstlen); - if (sah->identd == NULL) { - KFREE(sah->idents); - sah->idents = NULL; - ipseclog((LOG_DEBUG, "key_setident: No more memory.\n")); - return ENOBUFS; - } - bcopy(idsrc, sah->idents, idsrclen); - bcopy(iddst, sah->identd, iddstlen); - - return 0; -} - -/* - * m will not be freed on return. - * it is caller's responsibility to free the result. - */ -static struct mbuf * -key_getmsgbuf_x1(m, mhp) - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct mbuf *n; - - /* sanity check */ - if (m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_getmsgbuf_x1: NULL pointer is passed."); - - /* create new sadb_msg to reply. */ - n = key_gather_mbuf(m, mhp, 1, 9, SADB_EXT_RESERVED, - SADB_EXT_SA, SADB_X_EXT_SA2, - SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST, - SADB_EXT_LIFETIME_HARD, SADB_EXT_LIFETIME_SOFT, - SADB_EXT_IDENTITY_SRC, SADB_EXT_IDENTITY_DST); - if (!n) - return NULL; - - if (n->m_len < sizeof(struct sadb_msg)) { - n = m_pullup(n, sizeof(struct sadb_msg)); - if (n == NULL) - return NULL; - } - mtod(n, struct sadb_msg *)->sadb_msg_errno = 0; - mtod(n, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(n->m_pkthdr.len); - - return n; -} - -static int key_delete_all(struct socket *, struct mbuf *, - const struct sadb_msghdr *, u_int16_t); - -/* - * SADB_DELETE processing - * receive - * <base, SA(*), address(SD)> - * from the ikmpd, and set SADB_SASTATE_DEAD, - * and send, - * <base, SA(*), address(SD)> - * to the ikmpd. - * - * m will always be freed. - */ -static int -key_delete(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_sa *sa0; - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *sah; - struct secasvar *sav = NULL; - u_int16_t proto; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_delete: NULL pointer is passed."); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_delete: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { - ipseclog((LOG_DEBUG, "key_delete: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { - ipseclog((LOG_DEBUG, "key_delete: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->ext[SADB_EXT_SA] == NULL) { - /* - * Caller wants us to delete all non-LARVAL SAs - * that match the src/dst. This is used during - * IKE INITIAL-CONTACT. - */ - ipseclog((LOG_DEBUG, "key_delete: doing delete all.\n")); - return key_delete_all(so, m, mhp, proto); - } else if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa)) { - ipseclog((LOG_DEBUG, "key_delete: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); - - /* get a SA header */ - LIST_FOREACH(sah, &sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, &saidx, CMP_HEAD) == 0) - continue; - - /* get a SA with SPI. */ - sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); - if (sav) - break; - } - if (sah == NULL) { - ipseclog((LOG_DEBUG, "key_delete: no SA found.\n")); - return key_senderror(so, m, ENOENT); - } - - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - key_freesav(sav); - sav = NULL; - - { - struct mbuf *n; - struct sadb_msg *newmsg; - - /* create new sadb_msg to reply. */ - n = key_gather_mbuf(m, mhp, 1, 4, SADB_EXT_RESERVED, - SADB_EXT_SA, SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); - if (!n) - return key_senderror(so, m, ENOBUFS); - - if (n->m_len < sizeof(struct sadb_msg)) { - n = m_pullup(n, sizeof(struct sadb_msg)); - if (n == NULL) - return key_senderror(so, m, ENOBUFS); - } - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* - * delete all SAs for src/dst. Called from key_delete(). - */ -static int -key_delete_all(so, m, mhp, proto) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; - u_int16_t proto; -{ - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *sah; - struct secasvar *sav, *nextsav; - u_int stateidx, state; - - src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); - - LIST_FOREACH(sah, &sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, &saidx, CMP_HEAD) == 0) - continue; - - /* Delete all non-LARVAL SAs. */ - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_alive); - stateidx++) { - state = saorder_state_alive[stateidx]; - if (state == SADB_SASTATE_LARVAL) - continue; - for (sav = LIST_FIRST(&sah->savtree[state]); - sav != NULL; sav = nextsav) { - nextsav = LIST_NEXT(sav, chain); - /* sanity check */ - if (sav->state != state) { - ipseclog((LOG_DEBUG, "key_delete_all: " - "invalid sav->state " - "(queue: %u SA: %u)\n", - state, sav->state)); - continue; - } - - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - key_freesav(sav); - } - } - } - { - struct mbuf *n; - struct sadb_msg *newmsg; - - /* create new sadb_msg to reply. */ - n = key_gather_mbuf(m, mhp, 1, 3, SADB_EXT_RESERVED, - SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST); - if (!n) - return key_senderror(so, m, ENOBUFS); - - if (n->m_len < sizeof(struct sadb_msg)) { - n = m_pullup(n, sizeof(struct sadb_msg)); - if (n == NULL) - return key_senderror(so, m, ENOBUFS); - } - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); - } -} - -/* - * SADB_GET processing - * receive - * <base, SA(*), address(SD)> - * from the ikmpd, and get a SP and a SA to respond, - * and send, - * <base, SA, (lifetime(HSC),) address(SD), (address(P),) key(AE), - * (identity(SD),) (sensitivity)> - * to the ikmpd. - * - * m will always be freed. - */ -static int -key_get(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_sa *sa0; - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *sah; - struct secasvar *sav = NULL; - u_int16_t proto; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_get: NULL pointer is passed."); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_get: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->ext[SADB_EXT_SA] == NULL || - mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { - ipseclog((LOG_DEBUG, "key_get: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) || - mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) { - ipseclog((LOG_DEBUG, "key_get: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - sa0 = (struct sadb_sa *)mhp->ext[SADB_EXT_SA]; - src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; - dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); - - /* get a SA header */ - LIST_FOREACH(sah, &sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, &saidx, CMP_HEAD) == 0) - continue; - - /* get a SA with SPI. */ - sav = key_getsavbyspi(sah, sa0->sadb_sa_spi); - if (sav) - break; - } - if (sah == NULL) { - ipseclog((LOG_DEBUG, "key_get: no SA found.\n")); - return key_senderror(so, m, ENOENT); - } - - { - struct mbuf *n; - u_int8_t satype; - - /* map proto to satype */ - if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { - ipseclog((LOG_DEBUG, "key_get: there was invalid proto in SAD.\n")); - return key_senderror(so, m, EINVAL); - } - - /* create new sadb_msg to reply. */ - n = key_setdumpsa(sav, SADB_GET, satype, mhp->msg->sadb_msg_seq, - mhp->msg->sadb_msg_pid); - if (!n) - return key_senderror(so, m, ENOBUFS); - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); - } -} - -/* XXX make it sysctl-configurable? */ -static void -key_getcomb_setlifetime(comb) - struct sadb_comb *comb; -{ - - comb->sadb_comb_soft_allocations = 1; - comb->sadb_comb_hard_allocations = 1; - comb->sadb_comb_soft_bytes = 0; - comb->sadb_comb_hard_bytes = 0; - comb->sadb_comb_hard_addtime = 86400; /* 1 day */ - comb->sadb_comb_soft_addtime = comb->sadb_comb_hard_addtime * 80 / 100; - comb->sadb_comb_hard_usetime = 28800; /* 8 hours */ - comb->sadb_comb_soft_usetime = comb->sadb_comb_hard_usetime * 80 / 100; -} - -#ifdef IPSEC_ESP -/* - * XXX reorder combinations by preference - * XXX no idea if the user wants ESP authentication or not - */ -static struct mbuf * -key_getcomb_esp() -{ - struct sadb_comb *comb; - const struct esp_algorithm *algo; - struct mbuf *result = NULL, *m, *n; - int encmin; - int i, off, o; - int totlen; - const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); - - m = NULL; - for (i = 1; i <= SADB_EALG_MAX; i++) { - algo = esp_algorithm_lookup(i); - if (!algo) - continue; - - if (algo->keymax < ipsec_esp_keymin) - continue; - if (algo->keymin < ipsec_esp_keymin) - encmin = ipsec_esp_keymin; - else - encmin = algo->keymin; - - if (ipsec_esp_auth) - m = key_getcomb_ah(); - else { -#ifdef DIAGNOSTIC - if (l > MLEN) - panic("assumption failed in key_getcomb_esp"); -#endif - MGET(m, M_DONTWAIT, MT_DATA); - if (m) { - M_ALIGN(m, l); - m->m_len = l; - m->m_next = NULL; - bzero(mtod(m, caddr_t), m->m_len); - } - } - if (!m) - goto fail; - - totlen = 0; - for (n = m; n; n = n->m_next) - totlen += n->m_len; -#ifdef DIAGNOSTIC - if (totlen % l) - panic("assumption failed in key_getcomb_esp"); -#endif - - for (off = 0; off < totlen; off += l) { - n = m_pulldown(m, off, l, &o); - if (!n) { - /* m is already freed */ - goto fail; - } - comb = (struct sadb_comb *)(mtod(n, caddr_t) + o); - bzero(comb, sizeof(*comb)); - key_getcomb_setlifetime(comb); - comb->sadb_comb_encrypt = i; - comb->sadb_comb_encrypt_minbits = encmin; - comb->sadb_comb_encrypt_maxbits = algo->keymax; - } - - if (!result) - result = m; - else - m_cat(result, m); - } - - return result; - - fail: - if (result) - m_freem(result); - return NULL; -} -#endif - -/* - * XXX reorder combinations by preference - */ -static struct mbuf * -key_getcomb_ah() -{ - struct sadb_comb *comb; - const struct ah_algorithm *algo; - struct mbuf *m; - int min; - int i; - const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); - - m = NULL; - for (i = 1; i <= SADB_AALG_MAX; i++) { -#if 1 - /* we prefer HMAC algorithms, not old algorithms */ - if (i != SADB_AALG_SHA1HMAC && i != SADB_AALG_MD5HMAC) - continue; -#endif - algo = ah_algorithm_lookup(i); - if (!algo) - continue; - - if (algo->keymax < ipsec_ah_keymin) - continue; - if (algo->keymin < ipsec_ah_keymin) - min = ipsec_ah_keymin; - else - min = algo->keymin; - - if (!m) { -#ifdef DIAGNOSTIC - if (l > MLEN) - panic("assumption failed in key_getcomb_ah"); -#endif - MGET(m, M_DONTWAIT, MT_DATA); - if (m) { - M_ALIGN(m, l); - m->m_len = l; - m->m_next = NULL; - } - } else - M_PREPEND(m, l, M_DONTWAIT); - if (!m) - return NULL; - - comb = mtod(m, struct sadb_comb *); - bzero(comb, sizeof(*comb)); - key_getcomb_setlifetime(comb); - comb->sadb_comb_auth = i; - comb->sadb_comb_auth_minbits = min; - comb->sadb_comb_auth_maxbits = algo->keymax; - } - - return m; -} - -/* - * not really an official behavior. discussed in pf_key@inner.net in Sep2000. - * XXX reorder combinations by preference - */ -static struct mbuf * -key_getcomb_ipcomp() -{ - struct sadb_comb *comb; - const struct ipcomp_algorithm *algo; - struct mbuf *m; - int i; - const int l = PFKEY_ALIGN8(sizeof(struct sadb_comb)); - - m = NULL; - for (i = 1; i <= SADB_X_CALG_MAX; i++) { - algo = ipcomp_algorithm_lookup(i); - if (!algo) - continue; - - if (!m) { -#ifdef DIAGNOSTIC - if (l > MLEN) - panic("assumption failed in key_getcomb_ipcomp"); -#endif - MGET(m, M_DONTWAIT, MT_DATA); - if (m) { - M_ALIGN(m, l); - m->m_len = l; - m->m_next = NULL; - } - } else - M_PREPEND(m, l, M_DONTWAIT); - if (!m) - return NULL; - - comb = mtod(m, struct sadb_comb *); - bzero(comb, sizeof(*comb)); - key_getcomb_setlifetime(comb); - comb->sadb_comb_encrypt = i; - /* what should we set into sadb_comb_*_{min,max}bits? */ - } - - return m; -} - -/* - * XXX no way to pass mode (transport/tunnel) to userland - * XXX replay checking? - * XXX sysctl interface to ipsec_{ah,esp}_keymin - */ -static struct mbuf * -key_getprop(saidx) - const struct secasindex *saidx; -{ - struct sadb_prop *prop; - struct mbuf *m, *n; - const int l = PFKEY_ALIGN8(sizeof(struct sadb_prop)); - int totlen; - - switch (saidx->proto) { -#ifdef IPSEC_ESP - case IPPROTO_ESP: - m = key_getcomb_esp(); - break; -#endif - case IPPROTO_AH: - m = key_getcomb_ah(); - break; - case IPPROTO_IPCOMP: - m = key_getcomb_ipcomp(); - break; - default: - return NULL; - } - - if (!m) - return NULL; - M_PREPEND(m, l, M_DONTWAIT); - if (!m) - return NULL; - - totlen = 0; - for (n = m; n; n = n->m_next) - totlen += n->m_len; - - prop = mtod(m, struct sadb_prop *); - bzero(prop, sizeof(*prop)); - prop->sadb_prop_len = PFKEY_UNIT64(totlen); - prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; - prop->sadb_prop_replay = 32; /* XXX */ - - return m; -} - -/* - * SADB_ACQUIRE processing called by key_checkrequest() and key_acquire2(). - * send - * <base, SA, address(SD), (address(P)), x_policy, - * (identity(SD),) (sensitivity,) proposal> - * to KMD, and expect to receive - * <base> with SADB_ACQUIRE if error occured, - * or - * <base, src address, dst address, (SPI range)> with SADB_GETSPI - * from KMD by PF_KEY. - * - * XXX x_policy is outside of RFC2367 (KAME extension). - * XXX sensitivity is not supported. - * XXX for ipcomp, RFC2367 does not define how to fill in proposal. - * see comment for key_getcomb_ipcomp(). - * - * OUT: - * 0 : succeed - * others: error number - */ -static int -key_acquire(saidx, sp) - struct secasindex *saidx; - struct secpolicy *sp; -{ - struct mbuf *result = NULL, *m; -#ifndef IPSEC_NONBLOCK_ACQUIRE - struct secacq *newacq; -#endif - u_int8_t satype; - int error = -1; - u_int32_t seq; - - /* sanity check */ - if (saidx == NULL) - panic("key_acquire: NULL pointer is passed."); - if ((satype = key_proto2satype(saidx->proto)) == 0) - panic("key_acquire: invalid proto is passed."); - -#ifndef IPSEC_NONBLOCK_ACQUIRE - /* - * We never do anything about acquirng SA. There is anather - * solution that kernel blocks to send SADB_ACQUIRE message until - * getting something message from IKEd. In later case, to be - * managed with ACQUIRING list. - */ - /* get an entry to check whether sending message or not. */ - if ((newacq = key_getacq(saidx)) != NULL) { - if (key_blockacq_count < newacq->count) { - /* reset counter and do send message. */ - newacq->count = 0; - } else { - /* increment counter and do nothing. */ - newacq->count++; - return 0; - } - } else { - /* make new entry for blocking to send SADB_ACQUIRE. */ - if ((newacq = key_newacq(saidx)) == NULL) - return ENOBUFS; - - /* add to acqtree */ - LIST_INSERT_HEAD(&acqtree, newacq, chain); - } -#endif - - -#ifndef IPSEC_NONBLOCK_ACQUIRE - seq = newacq->seq; -#else - seq = (acq_seq = (acq_seq == ~0 ? 1 : ++acq_seq)); -#endif - m = key_setsadbmsg(SADB_ACQUIRE, 0, satype, seq, 0, 0); - if (!m) { - error = ENOBUFS; - goto fail; - } - result = m; - - /* set sadb_address for saidx's. */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&saidx->src, FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&saidx->dst, FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - /* XXX proxy address (optional) */ - - /* set sadb_x_policy */ - if (sp) { - m = key_setsadbxpolicy(sp->policy, sp->dir, sp->id); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - } - - /* XXX identity (optional) */ -#if 0 - if (idexttype && fqdn) { - /* create identity extension (FQDN) */ - struct sadb_ident *id; - int fqdnlen; - - fqdnlen = strlen(fqdn) + 1; /* +1 for terminating-NUL */ - id = (struct sadb_ident *)p; - bzero(id, sizeof(*id) + PFKEY_ALIGN8(fqdnlen)); - id->sadb_ident_len = PFKEY_UNIT64(sizeof(*id) + PFKEY_ALIGN8(fqdnlen)); - id->sadb_ident_exttype = idexttype; - id->sadb_ident_type = SADB_IDENTTYPE_FQDN; - bcopy(fqdn, id + 1, fqdnlen); - p += sizeof(struct sadb_ident) + PFKEY_ALIGN8(fqdnlen); - } - - if (idexttype) { - /* create identity extension (USERFQDN) */ - struct sadb_ident *id; - int userfqdnlen; - - if (userfqdn) { - /* +1 for terminating-NUL */ - userfqdnlen = strlen(userfqdn) + 1; - } else - userfqdnlen = 0; - id = (struct sadb_ident *)p; - bzero(id, sizeof(*id) + PFKEY_ALIGN8(userfqdnlen)); - id->sadb_ident_len = PFKEY_UNIT64(sizeof(*id) + PFKEY_ALIGN8(userfqdnlen)); - id->sadb_ident_exttype = idexttype; - id->sadb_ident_type = SADB_IDENTTYPE_USERFQDN; - /* XXX is it correct? */ - if (curproc && curproc->p_cred) - id->sadb_ident_id = curproc->p_cred->p_ruid; - if (userfqdn && userfqdnlen) - bcopy(userfqdn, id + 1, userfqdnlen); - p += sizeof(struct sadb_ident) + PFKEY_ALIGN8(userfqdnlen); - } -#endif - - /* XXX sensitivity (optional) */ - - /* create proposal/combination extension */ - m = key_getprop(saidx); -#if 0 - /* - * spec conformant: always attach proposal/combination extension, - * the problem is that we have no way to attach it for ipcomp, - * due to the way sadb_comb is declared in RFC2367. - */ - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); -#else - /* - * outside of spec; make proposal/combination extension optional. - */ - if (m) - m_cat(result, m); -#endif - - if ((result->m_flags & M_PKTHDR) == 0) { - error = EINVAL; - goto fail; - } - - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) { - error = ENOBUFS; - goto fail; - } - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); - - fail: - if (result) - m_freem(result); - return error; -} - -#ifndef IPSEC_NONBLOCK_ACQUIRE -static struct secacq * -key_newacq(saidx) - struct secasindex *saidx; -{ - struct secacq *newacq; - - /* get new entry */ - KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); - if (newacq == NULL) { - ipseclog((LOG_DEBUG, "key_newacq: No more memory.\n")); - return NULL; - } - bzero(newacq, sizeof(*newacq)); - - /* copy secindex */ - bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); - newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); - newacq->created = time_second; - newacq->count = 0; - - return newacq; -} - -static struct secacq * -key_getacq(saidx) - struct secasindex *saidx; -{ - struct secacq *acq; - - LIST_FOREACH(acq, &acqtree, chain) { - if (key_cmpsaidx(saidx, &acq->saidx, CMP_EXACTLY)) - return acq; - } - - return NULL; -} - -static struct secacq * -key_getacqbyseq(seq) - u_int32_t seq; -{ - struct secacq *acq; - - LIST_FOREACH(acq, &acqtree, chain) { - if (acq->seq == seq) - return acq; - } - - return NULL; -} -#endif - -static struct secspacq * -key_newspacq(spidx) - struct secpolicyindex *spidx; -{ - struct secspacq *acq; - - if (!spidx) - return NULL; - - /* get new entry */ - KMALLOC(acq, struct secspacq *, sizeof(struct secspacq)); - if (acq == NULL) { - ipseclog((LOG_DEBUG, "key_newspacq: No more memory.\n")); - return NULL; - } - bzero(acq, sizeof(*acq)); - - /* copy secindex */ - bcopy(spidx, &acq->spidx, sizeof(acq->spidx)); - acq->created = time_second; - acq->count = 1; - - return acq; -} - -static struct secspacq * -key_getspacq(spidx) - struct secpolicyindex *spidx; -{ - struct secspacq *acq; - - if (!spidx) - return NULL; - - LIST_FOREACH(acq, &spacqtree, chain) { - if (key_cmpspidx_exactly(spidx, &acq->spidx)) - return acq; - } - - return NULL; -} - -/* - * SADB_ACQUIRE processing, - * in first situation, is receiving - * <base> - * from the ikmpd, and clear sequence of its secasvar entry. - * - * In second situation, is receiving - * <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal> - * from a user land process, and return - * <base, address(SD), (address(P),) (identity(SD),) (sensitivity,) proposal> - * to the socket. - * - * m will always be freed. - */ -static int -key_acquire2(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_address *src0, *dst0; - struct secasindex saidx; - struct secashead *sah; - u_int16_t proto; - int error; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_acquire2: NULL pointer is passed."); - - /* - * Error message from KMd. - * We assume that if error was occured in IKEd, the length of PFKEY - * message is equal to the size of sadb_msg structure. - * We do not raise error even if error occured in this function. - */ - if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) { -#ifndef IPSEC_NONBLOCK_ACQUIRE - struct secacq *acq; - - /* check sequence number */ - if (mhp->msg->sadb_msg_seq == 0) { - ipseclog((LOG_DEBUG, "key_acquire2: must specify sequence number.\n")); - m_freem(m); - return 0; - } - - if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) { - /* - * the specified larval SA is already gone, or we got - * a bogus sequence number. we can silently ignore it. - */ - m_freem(m); - return 0; - } - - /* reset acq counter in order to deletion by timehander. */ - acq->created = time_second; - acq->count = 0; -#endif - m_freem(m); - return 0; - } - - /* - * This message is from user land. - */ - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_acquire2: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || - mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || - mhp->ext[SADB_EXT_PROPOSAL] == NULL) { - /* error */ - ipseclog((LOG_DEBUG, "key_acquire2: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) || - mhp->extlen[SADB_EXT_PROPOSAL] < sizeof(struct sadb_prop)) { - /* error */ - ipseclog((LOG_DEBUG, "key_acquire2: invalid message is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC]; - dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST]; - - /* XXX boundary check against sa_len */ - KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); - - /* get a SA index */ - LIST_FOREACH(sah, &sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, &saidx, CMP_MODE_REQID)) - break; - } - if (sah != NULL) { - ipseclog((LOG_DEBUG, "key_acquire2: a SA exists already.\n")); - return key_senderror(so, m, EEXIST); - } - - error = key_acquire(&saidx, NULL); - if (error != 0) { - ipseclog((LOG_DEBUG, "key_acquire2: error %d returned " - "from key_acquire.\n", mhp->msg->sadb_msg_errno)); - return key_senderror(so, m, error); - } - - return key_sendup_mbuf(so, m, KEY_SENDUP_REGISTERED); -} - -/* - * SADB_REGISTER processing. - * If SATYPE_UNSPEC has been passed as satype, only return sabd_supported. - * receive - * <base> - * from the ikmpd, and register a socket to send PF_KEY messages, - * and send - * <base, supported> - * to KMD by PF_KEY. - * If socket is detached, must free from regnode. - * - * m will always be freed. - */ -static int -key_register(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct secreg *reg, *newreg = 0; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_register: NULL pointer is passed."); - - /* check for invalid register message */ - if (mhp->msg->sadb_msg_satype >= sizeof(regtree)/sizeof(regtree[0])) - return key_senderror(so, m, EINVAL); - - /* When SATYPE_UNSPEC is specified, only return sabd_supported. */ - if (mhp->msg->sadb_msg_satype == SADB_SATYPE_UNSPEC) - goto setmsg; - - /* check whether existing or not */ - LIST_FOREACH(reg, ®tree[mhp->msg->sadb_msg_satype], chain) { - if (reg->so == so) { - ipseclog((LOG_DEBUG, "key_register: socket exists already.\n")); - return key_senderror(so, m, EEXIST); - } - } - - /* create regnode */ - KMALLOC(newreg, struct secreg *, sizeof(*newreg)); - if (newreg == NULL) { - ipseclog((LOG_DEBUG, "key_register: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - bzero((caddr_t)newreg, sizeof(*newreg)); - - newreg->so = so; - ((struct keycb *)sotorawcb(so))->kp_registered++; - - /* add regnode to regtree. */ - LIST_INSERT_HEAD(®tree[mhp->msg->sadb_msg_satype], newreg, chain); - - setmsg: - { - struct mbuf *n; - struct sadb_msg *newmsg; - struct sadb_supported *sup; - u_int len, alen, elen; - int off; - int i; - struct sadb_alg *alg; - - /* create new sadb_msg to reply. */ - alen = 0; - for (i = 1; i <= SADB_AALG_MAX; i++) { - if (ah_algorithm_lookup(i)) - alen += sizeof(struct sadb_alg); - } - if (alen) - alen += sizeof(struct sadb_supported); - elen = 0; -#ifdef IPSEC_ESP - for (i = 1; i <= SADB_EALG_MAX; i++) { - if (esp_algorithm_lookup(i)) - elen += sizeof(struct sadb_alg); - } - if (elen) - elen += sizeof(struct sadb_supported); -#endif - - len = sizeof(struct sadb_msg) + alen + elen; - - if (len > MCLBYTES) - return key_senderror(so, m, ENOBUFS); - - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (len > MHLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_freem(n); - n = NULL; - } - } - if (!n) - return key_senderror(so, m, ENOBUFS); - - n->m_pkthdr.len = n->m_len = len; - n->m_next = NULL; - off = 0; - - m_copydata(m, 0, sizeof(struct sadb_msg), mtod(n, caddr_t) + off); - newmsg = mtod(n, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - off += PFKEY_ALIGN8(sizeof(struct sadb_msg)); - - /* for authentication algorithm */ - if (alen) { - sup = (struct sadb_supported *)(mtod(n, caddr_t) + off); - sup->sadb_supported_len = PFKEY_UNIT64(alen); - sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; - off += PFKEY_ALIGN8(sizeof(*sup)); - - for (i = 1; i <= SADB_AALG_MAX; i++) { - const struct ah_algorithm *aalgo; - - aalgo = ah_algorithm_lookup(i); - if (!aalgo) - continue; - alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); - alg->sadb_alg_id = i; - alg->sadb_alg_ivlen = 0; - alg->sadb_alg_minbits = aalgo->keymin; - alg->sadb_alg_maxbits = aalgo->keymax; - off += PFKEY_ALIGN8(sizeof(*alg)); - } - } - -#ifdef IPSEC_ESP - /* for encryption algorithm */ - if (elen) { - sup = (struct sadb_supported *)(mtod(n, caddr_t) + off); - sup->sadb_supported_len = PFKEY_UNIT64(elen); - sup->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; - off += PFKEY_ALIGN8(sizeof(*sup)); - - for (i = 1; i <= SADB_EALG_MAX; i++) { - const struct esp_algorithm *ealgo; - - ealgo = esp_algorithm_lookup(i); - if (!ealgo) - continue; - alg = (struct sadb_alg *)(mtod(n, caddr_t) + off); - alg->sadb_alg_id = i; - if (ealgo && ealgo->ivlen) { - /* - * give NULL to get the value preferred by - * algorithm XXX SADB_X_EXT_DERIV ? - */ - alg->sadb_alg_ivlen = - (*ealgo->ivlen)(ealgo, NULL); - } else - alg->sadb_alg_ivlen = 0; - alg->sadb_alg_minbits = ealgo->keymin; - alg->sadb_alg_maxbits = ealgo->keymax; - off += PFKEY_ALIGN8(sizeof(struct sadb_alg)); - } - } -#endif - -#ifdef DIGAGNOSTIC - if (off != len) - panic("length assumption failed in key_register"); -#endif - - m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_REGISTERED); - } -} - -/* - * free secreg entry registered. - * XXX: I want to do free a socket marked done SADB_RESIGER to socket. - */ -void -key_freereg(so) - struct socket *so; -{ - struct secreg *reg; - int i; - - /* sanity check */ - if (so == NULL) - panic("key_freereg: NULL pointer is passed."); - - /* - * check whether existing or not. - * check all type of SA, because there is a potential that - * one socket is registered to multiple type of SA. - */ - for (i = 0; i <= SADB_SATYPE_MAX; i++) { - LIST_FOREACH(reg, ®tree[i], chain) { - if (reg->so == so && __LIST_CHAINED(reg)) { - LIST_REMOVE(reg, chain); - KFREE(reg); - break; - } - } - } - - return; -} - -/* - * SADB_EXPIRE processing - * send - * <base, SA, SA2, lifetime(C and one of HS), address(SD)> - * to KMD by PF_KEY. - * NOTE: We send only soft lifetime extension. - * - * OUT: 0 : succeed - * others : error number - */ -static int -key_expire(sav) - struct secasvar *sav; -{ - int s; - int satype; - struct mbuf *result = NULL, *m; - int len; - int error = -1; - struct sadb_lifetime *lt; - - /* XXX: Why do we lock ? */ - s = splnet(); /*called from softclock()*/ - - /* sanity check */ - if (sav == NULL) - panic("key_expire: NULL pointer is passed."); - if (sav->sah == NULL) - panic("key_expire: Why was SA index in SA NULL."); - if ((satype = key_proto2satype(sav->sah->saidx.proto)) == 0) - panic("key_expire: invalid proto is passed."); - - /* set msg header */ - m = key_setsadbmsg(SADB_EXPIRE, 0, satype, sav->seq, 0, sav->refcnt); - if (!m) { - error = ENOBUFS; - goto fail; - } - result = m; - - /* create SA extension */ - m = key_setsadbsa(sav); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - /* create SA extension */ - m = key_setsadbxsa2(sav->sah->saidx.mode, - sav->replay ? (sav->replay->count & 0xffffffff) : 0, - sav->sah->saidx.reqid); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - /* create lifetime extension (current and soft) */ - len = PFKEY_ALIGN8(sizeof(*lt)) * 2; - m = key_alloc_mbuf(len); - if (!m || m->m_next) { /*XXX*/ - if (m) - m_freem(m); - error = ENOBUFS; - goto fail; - } - bzero(mtod(m, caddr_t), len); - lt = mtod(m, struct sadb_lifetime *); - lt->sadb_lifetime_len = PFKEY_UNIT64(sizeof(struct sadb_lifetime)); - lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; - lt->sadb_lifetime_allocations = sav->lft_c->sadb_lifetime_allocations; - lt->sadb_lifetime_bytes = sav->lft_c->sadb_lifetime_bytes; - lt->sadb_lifetime_addtime = sav->lft_c->sadb_lifetime_addtime; - lt->sadb_lifetime_usetime = sav->lft_c->sadb_lifetime_usetime; - lt = (struct sadb_lifetime *)(mtod(m, caddr_t) + len / 2); - bcopy(sav->lft_s, lt, sizeof(*lt)); - m_cat(result, m); - - /* set sadb_address for source */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - (struct sockaddr *)&sav->sah->saidx.src, - FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - /* set sadb_address for destination */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - (struct sockaddr *)&sav->sah->saidx.dst, - FULLMASK, IPSEC_ULPROTO_ANY); - if (!m) { - error = ENOBUFS; - goto fail; - } - m_cat(result, m); - - if ((result->m_flags & M_PKTHDR) == 0) { - error = EINVAL; - goto fail; - } - - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, sizeof(struct sadb_msg)); - if (result == NULL) { - error = ENOBUFS; - goto fail; - } - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - splx(s); - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); - - fail: - if (result) - m_freem(result); - splx(s); - return error; -} - -/* - * SADB_FLUSH processing - * receive - * <base> - * from the ikmpd, and free all entries in secastree. - * and send, - * <base> - * to the ikmpd. - * NOTE: to do is only marking SADB_SASTATE_DEAD. - * - * m will always be freed. - */ -static int -key_flush(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct sadb_msg *newmsg; - struct secashead *sah, *nextsah; - struct secasvar *sav, *nextsav; - u_int16_t proto; - u_int8_t state; - u_int stateidx; - - /* sanity check */ - if (so == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_flush: NULL pointer is passed."); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_flush: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - /* no SATYPE specified, i.e. flushing all SA. */ - for (sah = LIST_FIRST(&sahtree); sah != NULL; sah = nextsah) { - nextsah = LIST_NEXT(sah, chain); - - if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && - proto != sah->saidx.proto) - continue; - - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_alive); - stateidx++) { - state = saorder_state_any[stateidx]; - for (sav = LIST_FIRST(&sah->savtree[state]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - key_sa_chgstate(sav, SADB_SASTATE_DEAD); - key_freesav(sav); - } - } - - sah->state = SADB_SASTATE_DEAD; - } - - if (m->m_len < sizeof(struct sadb_msg) || - sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) { - ipseclog((LOG_DEBUG, "key_flush: No more memory.\n")); - return key_senderror(so, m, ENOBUFS); - } - - if (m->m_next) - m_freem(m->m_next); - m->m_next = NULL; - m->m_pkthdr.len = m->m_len = sizeof(struct sadb_msg); - newmsg = mtod(m, struct sadb_msg *); - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); - - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); -} - -/* - * SADB_DUMP processing - * dump all entries including status of DEAD in SAD. - * receive - * <base> - * from the ikmpd, and dump all secasvar leaves - * and send, - * <base> ..... - * to the ikmpd. - * - * m will always be freed. - */ -static int -key_dump(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - struct secashead *sah; - struct secasvar *sav; - u_int16_t proto; - u_int stateidx; - u_int8_t satype; - u_int8_t state; - int cnt; - struct mbuf *n; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_dump: NULL pointer is passed."); - - /* map satype to proto */ - if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { - ipseclog((LOG_DEBUG, "key_dump: invalid satype is passed.\n")); - return key_senderror(so, m, EINVAL); - } - - /* count sav entries to be sent to the userland. */ - cnt = 0; - LIST_FOREACH(sah, &sahtree, chain) { - if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && - proto != sah->saidx.proto) - continue; - - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_any); - stateidx++) { - state = saorder_state_any[stateidx]; - LIST_FOREACH(sav, &sah->savtree[state], chain) { - cnt++; - } - } - } - - if (cnt == 0) - return key_senderror(so, m, ENOENT); - - /* send this to the userland, one at a time. */ - LIST_FOREACH(sah, &sahtree, chain) { - if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && - proto != sah->saidx.proto) - continue; - - /* map proto to satype */ - if ((satype = key_proto2satype(sah->saidx.proto)) == 0) { - ipseclog((LOG_DEBUG, "key_dump: there was invalid proto in SAD.\n")); - return key_senderror(so, m, EINVAL); - } - - for (stateidx = 0; - stateidx < _ARRAYLEN(saorder_state_any); - stateidx++) { - state = saorder_state_any[stateidx]; - LIST_FOREACH(sav, &sah->savtree[state], chain) { - n = key_setdumpsa(sav, SADB_DUMP, satype, - --cnt, mhp->msg->sadb_msg_pid); - if (!n) - return key_senderror(so, m, ENOBUFS); - - key_sendup_mbuf(so, n, KEY_SENDUP_ONE); - } - } - } - - m_freem(m); - return 0; -} - -/* - * SADB_X_PROMISC processing - * - * m will always be freed. - */ -static int -key_promisc(so, m, mhp) - struct socket *so; - struct mbuf *m; - const struct sadb_msghdr *mhp; -{ - int olen; - - /* sanity check */ - if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) - panic("key_promisc: NULL pointer is passed."); - - olen = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len); - - if (olen < sizeof(struct sadb_msg)) { -#if 1 - return key_senderror(so, m, EINVAL); -#else - m_freem(m); - return 0; -#endif - } else if (olen == sizeof(struct sadb_msg)) { - /* enable/disable promisc mode */ - struct keycb *kp; - - if ((kp = (struct keycb *)sotorawcb(so)) == NULL) - return key_senderror(so, m, EINVAL); - mhp->msg->sadb_msg_errno = 0; - switch (mhp->msg->sadb_msg_satype) { - case 0: - case 1: - kp->kp_promisc = mhp->msg->sadb_msg_satype; - break; - default: - return key_senderror(so, m, EINVAL); - } - - /* send the original message back to everyone */ - mhp->msg->sadb_msg_errno = 0; - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); - } else { - /* send packet as is */ - - m_adj(m, PFKEY_ALIGN8(sizeof(struct sadb_msg))); - - /* TODO: if sadb_msg_seq is specified, send to specific pid */ - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); - } -} - -static int (*key_typesw[])(struct socket *, struct mbuf *, - const struct sadb_msghdr *) = { - NULL, /* SADB_RESERVED */ - key_getspi, /* SADB_GETSPI */ - key_update, /* SADB_UPDATE */ - key_add, /* SADB_ADD */ - key_delete, /* SADB_DELETE */ - key_get, /* SADB_GET */ - key_acquire2, /* SADB_ACQUIRE */ - key_register, /* SADB_REGISTER */ - NULL, /* SADB_EXPIRE */ - key_flush, /* SADB_FLUSH */ - key_dump, /* SADB_DUMP */ - key_promisc, /* SADB_X_PROMISC */ - NULL, /* SADB_X_PCHANGE */ - key_spdadd, /* SADB_X_SPDUPDATE */ - key_spdadd, /* SADB_X_SPDADD */ - key_spddelete, /* SADB_X_SPDDELETE */ - key_spdget, /* SADB_X_SPDGET */ - NULL, /* SADB_X_SPDACQUIRE */ - key_spddump, /* SADB_X_SPDDUMP */ - key_spdflush, /* SADB_X_SPDFLUSH */ - key_spdadd, /* SADB_X_SPDSETIDX */ - NULL, /* SADB_X_SPDEXPIRE */ - key_spddelete2, /* SADB_X_SPDDELETE2 */ -}; - -/* - * parse sadb_msg buffer to process PFKEYv2, - * and create a data to response if needed. - * I think to be dealed with mbuf directly. - * IN: - * msgp : pointer to pointer to a received buffer pulluped. - * This is rewrited to response. - * so : pointer to socket. - * OUT: - * length for buffer to send to user process. - */ -int -key_parse(m, so) - struct mbuf *m; - struct socket *so; -{ - struct sadb_msg *msg; - struct sadb_msghdr mh; - u_int orglen; - int error; - int target; -#ifdef INET6 - struct sockaddr_in6 *sin6; -#endif - - /* sanity check */ - if (m == NULL || so == NULL) - panic("key_parse: NULL pointer is passed."); - -#if 0 /*kdebug_sadb assumes msg in linear buffer*/ - KEYDEBUG(KEYDEBUG_KEY_DUMP, - ipseclog((LOG_DEBUG, "key_parse: passed sadb_msg\n")); - kdebug_sadb(msg)); -#endif - - if (m->m_len < sizeof(struct sadb_msg)) { - m = m_pullup(m, sizeof(struct sadb_msg)); - if (!m) - return ENOBUFS; - } - msg = mtod(m, struct sadb_msg *); - orglen = PFKEY_UNUNIT64(msg->sadb_msg_len); - target = KEY_SENDUP_ONE; - - if ((m->m_flags & M_PKTHDR) == 0 || - m->m_pkthdr.len != m->m_pkthdr.len) { - ipseclog((LOG_DEBUG, "key_parse: invalid message length.\n")); - pfkeystat.out_invlen++; - error = EINVAL; - goto senderror; - } - - if (msg->sadb_msg_version != PF_KEY_V2) { - ipseclog((LOG_DEBUG, - "key_parse: PF_KEY version %u is mismatched.\n", - msg->sadb_msg_version)); - pfkeystat.out_invver++; - error = EINVAL; - goto senderror; - } - - if (msg->sadb_msg_type > SADB_MAX) { - ipseclog((LOG_DEBUG, "key_parse: invalid type %u is passed.\n", - msg->sadb_msg_type)); - pfkeystat.out_invmsgtype++; - error = EINVAL; - goto senderror; - } - - /* for old-fashioned code - should be nuked */ - if (m->m_pkthdr.len > MCLBYTES) { - m_freem(m); - return ENOBUFS; - } - if (m->m_next) { - struct mbuf *n; - - MGETHDR(n, M_DONTWAIT, MT_DATA); - if (n && m->m_pkthdr.len > MHLEN) { - MCLGET(n, M_DONTWAIT); - if ((n->m_flags & M_EXT) == 0) { - m_free(n); - n = NULL; - } - } - if (!n) { - m_freem(m); - return ENOBUFS; - } - m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t)); - n->m_pkthdr.len = n->m_len = m->m_pkthdr.len; - n->m_next = NULL; - m_freem(m); - m = n; - } - - /* align the mbuf chain so that extensions are in contiguous region. */ - error = key_align(m, &mh); - if (error) - return error; - - msg = mh.msg; - - /* check SA type */ - switch (msg->sadb_msg_satype) { - case SADB_SATYPE_UNSPEC: - switch (msg->sadb_msg_type) { - case SADB_GETSPI: - case SADB_UPDATE: - case SADB_ADD: - case SADB_DELETE: - case SADB_GET: - case SADB_ACQUIRE: - case SADB_EXPIRE: - ipseclog((LOG_DEBUG, "key_parse: must specify satype " - "when msg type=%u.\n", msg->sadb_msg_type)); - pfkeystat.out_invsatype++; - error = EINVAL; - goto senderror; - } - break; - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_IPCOMP: - case SADB_X_SATYPE_TCPSIGNATURE: - switch (msg->sadb_msg_type) { - case SADB_X_SPDADD: - case SADB_X_SPDDELETE: - case SADB_X_SPDGET: - case SADB_X_SPDDUMP: - case SADB_X_SPDFLUSH: - case SADB_X_SPDSETIDX: - case SADB_X_SPDUPDATE: - case SADB_X_SPDDELETE2: - ipseclog((LOG_DEBUG, "key_parse: illegal satype=%u\n", - msg->sadb_msg_type)); - pfkeystat.out_invsatype++; - error = EINVAL; - goto senderror; - } - break; - case SADB_SATYPE_RSVP: - case SADB_SATYPE_OSPFV2: - case SADB_SATYPE_RIPV2: - case SADB_SATYPE_MIP: - ipseclog((LOG_DEBUG, "key_parse: type %u isn't supported.\n", - msg->sadb_msg_satype)); - pfkeystat.out_invsatype++; - error = EOPNOTSUPP; - goto senderror; - case 1: /* XXX: What does it do? */ - if (msg->sadb_msg_type == SADB_X_PROMISC) - break; - /*FALLTHROUGH*/ - default: - ipseclog((LOG_DEBUG, "key_parse: invalid type %u is passed.\n", - msg->sadb_msg_satype)); - pfkeystat.out_invsatype++; - error = EINVAL; - goto senderror; - } - - /* check field of upper layer protocol and address family */ - if (mh.ext[SADB_EXT_ADDRESS_SRC] != NULL && - mh.ext[SADB_EXT_ADDRESS_DST] != NULL) { - struct sadb_address *src0, *dst0; - u_int plen; - - src0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_SRC]); - dst0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_DST]); - - /* check upper layer protocol */ - if (src0->sadb_address_proto != dst0->sadb_address_proto) { - ipseclog((LOG_DEBUG, "key_parse: upper layer protocol mismatched.\n")); - pfkeystat.out_invaddr++; - error = EINVAL; - goto senderror; - } - - /* check family */ - if (PFKEY_ADDR_SADDR(src0)->sa_family != - PFKEY_ADDR_SADDR(dst0)->sa_family) { - ipseclog((LOG_DEBUG, "key_parse: address family mismatched.\n")); - pfkeystat.out_invaddr++; - error = EINVAL; - goto senderror; - } - if (PFKEY_ADDR_SADDR(src0)->sa_len != - PFKEY_ADDR_SADDR(dst0)->sa_len) { - ipseclog((LOG_DEBUG, - "key_parse: address struct size mismatched.\n")); - pfkeystat.out_invaddr++; - error = EINVAL; - goto senderror; - } - - switch (PFKEY_ADDR_SADDR(src0)->sa_family) { - case AF_INET: - if (PFKEY_ADDR_SADDR(src0)->sa_len != - sizeof(struct sockaddr_in)) { - pfkeystat.out_invaddr++; - error = EINVAL; - goto senderror; - } - break; - case AF_INET6: - if (PFKEY_ADDR_SADDR(src0)->sa_len != - sizeof(struct sockaddr_in6)) { - pfkeystat.out_invaddr++; - error = EINVAL; - goto senderror; - } -#ifdef INET6 - /* - * Check validity of the scope zone ID of the - * addresses, and embed the zone ID into the address - * if necessary. - */ - sin6 = (struct sockaddr_in6 *)PFKEY_ADDR_SADDR(src0); - if ((error = sa6_embedscope(sin6, 0)) != 0) - goto senderror; - sin6 = (struct sockaddr_in6 *)PFKEY_ADDR_SADDR(dst0); - if ((error = sa6_embedscope(sin6, 0)) != 0) - goto senderror; -#endif - break; - default: - ipseclog((LOG_DEBUG, - "key_parse: unsupported address family.\n")); - pfkeystat.out_invaddr++; - error = EAFNOSUPPORT; - goto senderror; - } - - switch (PFKEY_ADDR_SADDR(src0)->sa_family) { - case AF_INET: - plen = sizeof(struct in_addr) << 3; - break; - case AF_INET6: - plen = sizeof(struct in6_addr) << 3; - break; - default: - plen = 0; /*fool gcc*/ - break; - } - - /* check max prefix length */ - if (src0->sadb_address_prefixlen > plen || - dst0->sadb_address_prefixlen > plen) { - ipseclog((LOG_DEBUG, - "key_parse: illegal prefixlen.\n")); - pfkeystat.out_invaddr++; - error = EINVAL; - goto senderror; - } - - /* - * prefixlen == 0 is valid because there can be a case when - * all addresses are matched. - */ - } - - if (msg->sadb_msg_type >= sizeof(key_typesw)/sizeof(key_typesw[0]) || - key_typesw[msg->sadb_msg_type] == NULL) { - pfkeystat.out_invmsgtype++; - error = EINVAL; - goto senderror; - } - - return (*key_typesw[msg->sadb_msg_type])(so, m, &mh); - -senderror: - msg->sadb_msg_errno = error; - return key_sendup_mbuf(so, m, target); -} - -static int -key_senderror(so, m, code) - struct socket *so; - struct mbuf *m; - int code; -{ - struct sadb_msg *msg; - - if (m->m_len < sizeof(struct sadb_msg)) - panic("invalid mbuf passed to key_senderror"); - - msg = mtod(m, struct sadb_msg *); - msg->sadb_msg_errno = code; - return key_sendup_mbuf(so, m, KEY_SENDUP_ONE); -} - -/* - * set the pointer to each header into message buffer. - * m will be freed on error. - * XXX larger-than-MCLBYTES extension? - */ -static int -key_align(m, mhp) - struct mbuf *m; - struct sadb_msghdr *mhp; -{ - struct mbuf *n; - struct sadb_ext *ext; - size_t off, end; - int extlen; - int toff; - - /* sanity check */ - if (m == NULL || mhp == NULL) - panic("key_align: NULL pointer is passed."); - if (m->m_len < sizeof(struct sadb_msg)) - panic("invalid mbuf passed to key_align"); - - /* initialize */ - bzero(mhp, sizeof(*mhp)); - - mhp->msg = mtod(m, struct sadb_msg *); - mhp->ext[0] = (struct sadb_ext *)mhp->msg; /*XXX backward compat */ - - end = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len); - extlen = end; /*just in case extlen is not updated*/ - for (off = sizeof(struct sadb_msg); off < end; off += extlen) { - n = m_pulldown(m, off, sizeof(struct sadb_ext), &toff); - if (!n) { - /* m is already freed */ - return ENOBUFS; - } - ext = (struct sadb_ext *)(mtod(n, caddr_t) + toff); - - /* set pointer */ - switch (ext->sadb_ext_type) { - case SADB_EXT_SA: - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_EXT_ADDRESS_PROXY: - case SADB_EXT_LIFETIME_CURRENT: - case SADB_EXT_LIFETIME_HARD: - case SADB_EXT_LIFETIME_SOFT: - case SADB_EXT_KEY_AUTH: - case SADB_EXT_KEY_ENCRYPT: - case SADB_EXT_IDENTITY_SRC: - case SADB_EXT_IDENTITY_DST: - case SADB_EXT_SENSITIVITY: - case SADB_EXT_PROPOSAL: - case SADB_EXT_SUPPORTED_AUTH: - case SADB_EXT_SUPPORTED_ENCRYPT: - case SADB_EXT_SPIRANGE: - case SADB_X_EXT_POLICY: - case SADB_X_EXT_SA2: - /* duplicate check */ - /* - * XXX Are there duplication payloads of either - * KEY_AUTH or KEY_ENCRYPT ? - */ - if (mhp->ext[ext->sadb_ext_type] != NULL) { - ipseclog((LOG_DEBUG, - "key_align: duplicate ext_type %u " - "is passed.\n", ext->sadb_ext_type)); - m_freem(m); - pfkeystat.out_dupext++; - return EINVAL; - } - break; - default: - ipseclog((LOG_DEBUG, - "key_align: invalid ext_type %u is passed.\n", - ext->sadb_ext_type)); - m_freem(m); - pfkeystat.out_invexttype++; - return EINVAL; - } - - extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); - - if (key_validate_ext(ext, extlen)) { - m_freem(m); - pfkeystat.out_invlen++; - return EINVAL; - } - - n = m_pulldown(m, off, extlen, &toff); - if (!n) { - /* m is already freed */ - return ENOBUFS; - } - ext = (struct sadb_ext *)(mtod(n, caddr_t) + toff); - - mhp->ext[ext->sadb_ext_type] = ext; - mhp->extoff[ext->sadb_ext_type] = off; - mhp->extlen[ext->sadb_ext_type] = extlen; - } - - if (off != end) { - m_freem(m); - pfkeystat.out_invlen++; - return EINVAL; - } - - return 0; -} - -static int -key_validate_ext(ext, len) - struct sadb_ext *ext; - int len; -{ - struct sockaddr *sa; - enum { NONE, ADDR } checktype = NONE; - int baselen = 0; - const int sal = offsetof(struct sockaddr, sa_len) + sizeof(sa->sa_len); - - if (len != PFKEY_UNUNIT64(ext->sadb_ext_len)) - return EINVAL; - - /* if it does not match minimum/maximum length, bail */ - if (ext->sadb_ext_type >= sizeof(minsize) / sizeof(minsize[0]) || - ext->sadb_ext_type >= sizeof(maxsize) / sizeof(maxsize[0])) - return EINVAL; - if (!minsize[ext->sadb_ext_type] || len < minsize[ext->sadb_ext_type]) - return EINVAL; - if (maxsize[ext->sadb_ext_type] && len > maxsize[ext->sadb_ext_type]) - return EINVAL; - - /* more checks based on sadb_ext_type XXX need more */ - switch (ext->sadb_ext_type) { - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_EXT_ADDRESS_PROXY: - baselen = PFKEY_ALIGN8(sizeof(struct sadb_address)); - checktype = ADDR; - break; - case SADB_EXT_IDENTITY_SRC: - case SADB_EXT_IDENTITY_DST: - if (((struct sadb_ident *)ext)->sadb_ident_type == - SADB_X_IDENTTYPE_ADDR) { - baselen = PFKEY_ALIGN8(sizeof(struct sadb_ident)); - checktype = ADDR; - } else - checktype = NONE; - break; - default: - checktype = NONE; - break; - } - - switch (checktype) { - case NONE: - break; - case ADDR: - sa = (struct sockaddr *)((caddr_t)ext + baselen); - if (len < baselen + sal) - return EINVAL; - if (baselen + PFKEY_ALIGN8(sa->sa_len) != len) - return EINVAL; - break; - } - - return 0; -} - -void -key_init() -{ - int i; - - bzero((caddr_t)&key_cb, sizeof(key_cb)); - - callout_init(&key_timehandler_ch, 0); - - for (i = 0; i < IPSEC_DIR_MAX; i++) - LIST_INIT(&sptree[i]); - - LIST_INIT(&sahtree); - - for (i = 0; i <= SADB_SATYPE_MAX; i++) - LIST_INIT(®tree[i]); - - for (i = 0; i < SPIHASHSIZE; i++) - LIST_INIT(&spihash[i]); - -#ifndef IPSEC_NONBLOCK_ACQUIRE - LIST_INIT(&acqtree); -#endif - LIST_INIT(&spacqtree); - - TAILQ_INIT(&satailq); - TAILQ_INIT(&sptailq); - - /* system default */ -#ifdef INET - ip4_def_policy = key_newsp(0); - if (!ip4_def_policy) - panic("could not initialize IPv4 default security policy"); - ip4_def_policy->state = IPSEC_SPSTATE_ALIVE; - ip4_def_policy->policy = IPSEC_POLICY_NONE; - ip4_def_policy->dir = IPSEC_DIR_ANY; - ip4_def_policy->readonly = 1; - ip4_def_policy->persist = 1; -#endif -#ifdef INET6 - ip6_def_policy = key_newsp(0); - if (!ip6_def_policy) - panic("could not initialize IPv6 default security policy"); - ip6_def_policy->state = IPSEC_SPSTATE_ALIVE; - ip6_def_policy->policy = IPSEC_POLICY_NONE; - ip6_def_policy->dir = IPSEC_DIR_ANY; - ip6_def_policy->readonly = 1; - ip6_def_policy->persist = 1; -#endif - - callout_reset(&key_timehandler_ch, hz, key_timehandler, (void *)0); - - /* initialize key statistics */ - keystat.getspi_count = 1; - - printf("IPsec: Initialized Security Association Processing.\n"); - - return; -} - -/* - * XXX: maybe This function is called after INBOUND IPsec processing. - * - * Special check for tunnel-mode packets. - * We must make some checks for consistency between inner and outer IP header. - * - * xxx more checks to be provided - */ -int -key_checktunnelsanity(sav, family, src, dst) - struct secasvar *sav; - u_int family; - caddr_t src; - caddr_t dst; -{ - /* sanity check */ - if (sav->sah == NULL) - panic("sav->sah == NULL at key_checktunnelsanity"); - - /* XXX: check inner IP header */ - - return 1; -} - -#if 0 -/* - * Get FQDN for the host. - * If the administrator configured hostname (by hostname(1)) without - * domain name, returns nothing. - */ -static const char * -key_getfqdn() -{ - int i; - int hasdot; - static char fqdn[MAXHOSTNAMELEN + 1]; - int hostnamelen = strlen(hostname); - - if (!hostnamelen) - return NULL; - - /* check if it comes with domain name. */ - hasdot = 0; - for (i = 0; i < hostnamelen; i++) { - if (hostname[i] == '.') - hasdot++; - } - if (!hasdot) - return NULL; - - /* NOTE: hostname may not be NUL-terminated. */ - bzero(fqdn, sizeof(fqdn)); - bcopy(hostname, fqdn, hostnamelen); - fqdn[hostnamelen] = '\0'; - return fqdn; -} - -/* - * get username@FQDN for the host/user. - */ -static const char * -key_getuserfqdn() -{ - const char *host; - static char userfqdn[MAXHOSTNAMELEN + MAXLOGNAME + 2]; - struct proc *p = curproc; - char *q; - - PROC_LOCK(p); - if (!p || !p->p_pgrp || !p->p_pgrp->pg_session) { - PROC_UNLOCK(p); - return NULL; - } - if (!(host = key_getfqdn())) { - PROC_UNLOCK(p); - return NULL; - } - - /* NOTE: s_login may not be-NUL terminated. */ - bzero(userfqdn, sizeof(userfqdn)); - SESS_LOCK(p->p_session); - bcopy(p->p_pgrp->pg_session->s_login, userfqdn, MAXLOGNAME); - SESS_UNLOCK(p->p_session); - PROC_UNLOCK(p); - userfqdn[MAXLOGNAME] = '\0'; /* safeguard */ - q = userfqdn + strlen(userfqdn); - *q++ = '@'; - bcopy(host, q, strlen(host)); - q += strlen(host); - *q++ = '\0'; - - return userfqdn; -} -#endif - -/* record data transfer on SA, and update timestamps */ -void -key_sa_recordxfer(sav, m) - struct secasvar *sav; - struct mbuf *m; -{ - if (!sav) - panic("key_sa_recordxfer called with sav == NULL"); - if (!m) - panic("key_sa_recordxfer called with m == NULL"); - if (!sav->lft_c) - return; - - /* - * XXX Currently, there is a difference of bytes size - * between inbound and outbound processing. - */ - sav->lft_c->sadb_lifetime_bytes += m->m_pkthdr.len; - /* to check bytes lifetime is done in key_timehandler(). */ - - /* - * We use the number of packets as the unit of - * sadb_lifetime_allocations. We increment the variable - * whenever {esp,ah}_{in,out}put is called. - */ - sav->lft_c->sadb_lifetime_allocations++; - /* XXX check for expires? */ - - /* - * NOTE: We record CURRENT sadb_lifetime_usetime by using wall clock, - * in seconds. HARD and SOFT lifetime are measured by the time - * difference (again in seconds) from sadb_lifetime_usetime. - * - * usetime - * v expire expire - * -----+-----+--------+---> t - * <--------------> HARD - * <-----> SOFT - */ - { - sav->lft_c->sadb_lifetime_usetime = time_second; - /* XXX check for expires? */ - } - - return; -} - -/* dumb version */ -void -key_sa_routechange(dst) - struct sockaddr *dst; -{ - struct secashead *sah; - struct route *ro; - - LIST_FOREACH(sah, &sahtree, chain) { - ro = &sah->sa_route; - if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len && - bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { - RTFREE(ro->ro_rt); - ro->ro_rt = (struct rtentry *)NULL; - } - } - - return; -} - -static void -key_sa_chgstate(sav, state) - struct secasvar *sav; - u_int8_t state; -{ - if (sav == NULL) - panic("key_sa_chgstate called with sav == NULL"); - - if (sav->state == state) - return; - - if (__LIST_CHAINED(sav)) - LIST_REMOVE(sav, chain); - - sav->state = state; - LIST_INSERT_HEAD(&sav->sah->savtree[state], sav, chain); -} - -void -key_sa_stir_iv(sav) - struct secasvar *sav; -{ - - if (!sav->iv) - panic("key_sa_stir_iv called with sav == NULL"); - key_randomfill(sav->iv, sav->ivlen); -} - -static void -key_sp_dead(sp) - struct secpolicy *sp; -{ - - /* mark the SP dead */ - sp->state = IPSEC_SPSTATE_DEAD; -} - -static void -key_sp_unlink(sp) - struct secpolicy *sp; -{ - - /* remove from SP index */ - if (__LIST_CHAINED(sp)) { - LIST_REMOVE(sp, chain); - key_freesp(sp); - } -} - -/* XXX too much? */ -static struct mbuf * -key_alloc_mbuf(l) - int l; -{ - struct mbuf *m = NULL, *n; - int len, t; - - len = l; - while (len > 0) { - MGET(n, M_DONTWAIT, MT_DATA); - if (n && len > MLEN) - MCLGET(n, M_DONTWAIT); - if (!n) { - m_freem(m); - return NULL; - } - - n->m_next = NULL; - n->m_len = 0; - n->m_len = M_TRAILINGSPACE(n); - /* use the bottom of mbuf, hoping we can prepend afterwards */ - if (n->m_len > len) { - t = (n->m_len - len) & ~(sizeof(long) - 1); - n->m_data += t; - n->m_len = len; - } - - len -= n->m_len; - - if (m) - m_cat(m, n); - else - m = n; - } - - return m; -} diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c deleted file mode 100644 index 3cd2191..0000000 --- a/sys/netkey/key_debug.c +++ /dev/null @@ -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; -} diff --git a/sys/netkey/keydb.c b/sys/netkey/keydb.c deleted file mode 100644 index a41d505..0000000 --- a/sys/netkey/keydb.c +++ /dev/null @@ -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); -} diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c deleted file mode 100644 index abf59d3..0000000 --- a/sys/netkey/keysock.c +++ /dev/null @@ -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); |