Initial import of Sam Leffler's `Fast-IPsec' from FreeBSD 4.
Fast-IPsec is a rework of the OpenBSD and KAME IPsec code, using the OpenCryptoFramework (and thus hardware crypto accelerators) and numerous detailed performance improvements. This import is (aside from SPL-level names) the FreeBSD source, imported ``as-is'' as a historical snapshot, for future maintenance and comparison against the FreeBSD source. For now, several minor kernel-API differences are hidden by macros a shim file, ipsec_osdep.h, which (aside from SPL names) can be targeted at either NetBSD or FreeBSD.
This commit is contained in:
parent
2d11b64df0
commit
740290313e
|
@ -0,0 +1,57 @@
|
|||
/* $NetBSD: ah.h,v 1.1 2003/08/13 20:06:49 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ah.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ah.h,v 1.13 2000/10/18 21:28:00 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_AH_H_
|
||||
#define _NETIPSEC_AH_H_
|
||||
|
||||
struct ah {
|
||||
u_int8_t ah_nxt; /* Next Header */
|
||||
u_int8_t ah_len; /* Length of data, in 32bit */
|
||||
u_int16_t ah_reserve; /* Reserved for future use */
|
||||
u_int32_t ah_spi; /* Security parameter index */
|
||||
/* variable size, 32bit bound*/ /* Authentication data */
|
||||
};
|
||||
|
||||
struct newah {
|
||||
u_int8_t ah_nxt; /* Next Header */
|
||||
u_int8_t ah_len; /* Length of data + 1, in 32bit */
|
||||
u_int16_t ah_reserve; /* Reserved for future use */
|
||||
u_int32_t ah_spi; /* Security parameter index */
|
||||
u_int32_t ah_seq; /* Sequence number field */
|
||||
/* variable size, 32bit bound*/ /* Authentication data */
|
||||
};
|
||||
#endif /*_NETIPSEC_AH_H_*/
|
|
@ -0,0 +1,79 @@
|
|||
/* $NetBSD: ah_var.h,v 1.1 2003/08/13 20:06:49 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ah_var.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $OpenBSD: ip_ah.h,v 1.29 2002/06/09 16:26:10 itojun Exp $ */
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de).
|
||||
*
|
||||
* The original version of this code was written by John Ioannidis
|
||||
* for BSD/OS in Athens, Greece, in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Additional features in 1999 by Angelos D. Keromytis.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998, 1999 John Ioannidis,
|
||||
* Angelos D. Keromytis and Niels Provos.
|
||||
* Copyright (c) 2001 Angelos D. Keromytis.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_AH_VAR_H_
|
||||
#define _NETIPSEC_AH_VAR_H_
|
||||
|
||||
/*
|
||||
* These define the algorithm indices into the histogram. They're
|
||||
* presently based on the PF_KEY v2 protocol values which is bogus;
|
||||
* they should be decoupled from the protocol at which time we can
|
||||
* pack them and reduce the size of the array to a minimum.
|
||||
*/
|
||||
#define AH_ALG_MAX 16
|
||||
|
||||
struct ahstat {
|
||||
u_int32_t ahs_hdrops; /* Packet shorter than header shows */
|
||||
u_int32_t ahs_nopf; /* Protocol family not supported */
|
||||
u_int32_t ahs_notdb;
|
||||
u_int32_t ahs_badkcr;
|
||||
u_int32_t ahs_badauth;
|
||||
u_int32_t ahs_noxform;
|
||||
u_int32_t ahs_qfull;
|
||||
u_int32_t ahs_wrap;
|
||||
u_int32_t ahs_replay;
|
||||
u_int32_t ahs_badauthl; /* Bad authenticator length */
|
||||
u_int32_t ahs_input; /* Input AH packets */
|
||||
u_int32_t ahs_output; /* Output AH packets */
|
||||
u_int32_t ahs_invalid; /* Trying to use an invalid TDB */
|
||||
u_int64_t ahs_ibytes; /* Input bytes */
|
||||
u_int64_t ahs_obytes; /* Output bytes */
|
||||
u_int32_t ahs_toobig; /* Packet got larger than IP_MAXPACKET */
|
||||
u_int32_t ahs_pdrops; /* Packet blocked due to policy */
|
||||
u_int32_t ahs_crypto; /* Crypto processing failure */
|
||||
u_int32_t ahs_tunnel; /* Tunnel sanity check failure */
|
||||
u_int32_t ahs_hist[AH_ALG_MAX]; /* Per-algorithm op count */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern int ah_enable;
|
||||
extern int ah_cleartos;
|
||||
extern struct ahstat ahstat;
|
||||
#endif /* _KERNEL */
|
||||
#endif /*_NETIPSEC_AH_VAR_H_*/
|
|
@ -0,0 +1,70 @@
|
|||
/* $NetBSD: esp.h,v 1.1 2003/08/13 20:06:49 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/esp.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: esp.h,v 1.16 2000/10/18 21:28:00 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* RFC1827/2406 Encapsulated Security Payload.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_ESP_H_
|
||||
#define _NETIPSEC_ESP_H_
|
||||
|
||||
struct esp {
|
||||
u_int32_t esp_spi; /* ESP */
|
||||
/*variable size, 32bit bound*/ /* Initialization Vector */
|
||||
/*variable size*/ /* Payload data */
|
||||
/*variable size*/ /* padding */
|
||||
/*8bit*/ /* pad size */
|
||||
/*8bit*/ /* next header */
|
||||
/*8bit*/ /* next header */
|
||||
/*variable size, 32bit bound*/ /* Authentication data (new IPsec) */
|
||||
};
|
||||
|
||||
struct newesp {
|
||||
u_int32_t esp_spi; /* ESP */
|
||||
u_int32_t esp_seq; /* Sequence number */
|
||||
/*variable size*/ /* (IV and) Payload data */
|
||||
/*variable size*/ /* padding */
|
||||
/*8bit*/ /* pad size */
|
||||
/*8bit*/ /* next header */
|
||||
/*8bit*/ /* next header */
|
||||
/*variable size, 32bit bound*/ /* Authentication data */
|
||||
};
|
||||
|
||||
struct esptail {
|
||||
u_int8_t esp_padlen; /* pad length */
|
||||
u_int8_t esp_nxt; /* Next header */
|
||||
/*variable size, 32bit bound*/ /* Authentication data (new IPsec)*/
|
||||
};
|
||||
|
||||
#define ESP_ALEN 12 /* 96-bit authenticator */
|
||||
#endif /*_NETIPSEC_ESP_H_*/
|
|
@ -0,0 +1,79 @@
|
|||
/* $NetBSD: esp_var.h,v 1.1 2003/08/13 20:06:49 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/esp_var.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $OpenBSD: ip_esp.h,v 1.37 2002/06/09 16:26:10 itojun Exp $ */
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de).
|
||||
*
|
||||
* The original version of this code was written by John Ioannidis
|
||||
* for BSD/OS in Athens, Greece, in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Additional features in 1999 by Angelos D. Keromytis.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
|
||||
* Angelos D. Keromytis and Niels Provos.
|
||||
* Copyright (c) 2001 Angelos D. Keromytis.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_ESP_VAR_H_
|
||||
#define _NETIPSEC_ESP_VAR_H_
|
||||
|
||||
/*
|
||||
* These define the algorithm indices into the histogram. They're
|
||||
* presently based on the PF_KEY v2 protocol values which is bogus;
|
||||
* they should be decoupled from the protocol at which time we can
|
||||
* pack them and reduce the size of the array to a reasonable value.
|
||||
*/
|
||||
#define ESP_ALG_MAX 256 /* NB: could be < but skipjack is 249 */
|
||||
|
||||
struct espstat {
|
||||
u_int32_t esps_hdrops; /* Packet shorter than header shows */
|
||||
u_int32_t esps_nopf; /* Protocol family not supported */
|
||||
u_int32_t esps_notdb;
|
||||
u_int32_t esps_badkcr;
|
||||
u_int32_t esps_qfull;
|
||||
u_int32_t esps_noxform;
|
||||
u_int32_t esps_badilen;
|
||||
u_int32_t esps_wrap; /* Replay counter wrapped around */
|
||||
u_int32_t esps_badenc; /* Bad encryption detected */
|
||||
u_int32_t esps_badauth; /* Only valid for transforms with auth */
|
||||
u_int32_t esps_replay; /* Possible packet replay detected */
|
||||
u_int32_t esps_input; /* Input ESP packets */
|
||||
u_int32_t esps_output; /* Output ESP packets */
|
||||
u_int32_t esps_invalid; /* Trying to use an invalid TDB */
|
||||
u_int64_t esps_ibytes; /* Input bytes */
|
||||
u_int64_t esps_obytes; /* Output bytes */
|
||||
u_int32_t esps_toobig; /* Packet got larger than IP_MAXPACKET */
|
||||
u_int32_t esps_pdrops; /* Packet blocked due to policy */
|
||||
u_int32_t esps_crypto; /* Crypto processing failure */
|
||||
u_int32_t esps_tunnel; /* Tunnel sanity check failure */
|
||||
u_int32_t esps_hist[ESP_ALG_MAX]; /* Per-algorithm op count */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern int esp_enable;
|
||||
extern struct espstat espstat;
|
||||
#endif /* _KERNEL */
|
||||
#endif /*_NETIPSEC_ESP_VAR_H_*/
|
|
@ -0,0 +1,56 @@
|
|||
/* $NetBSD: ipcomp.h,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipcomp.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 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).
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_IPCOMP_H_
|
||||
#define _NETIPSEC_IPCOMP_H_
|
||||
|
||||
struct ipcomp {
|
||||
u_int8_t comp_nxt; /* Next Header */
|
||||
u_int8_t comp_flags; /* reserved, must be zero */
|
||||
u_int16_t comp_cpi; /* Compression parameter index */
|
||||
};
|
||||
|
||||
#define IPCOMP_HLENGTH 4 /* Length of IPCOMP header */
|
||||
|
||||
/* well-known algorithm number (in CPI), from RFC2409 */
|
||||
#define IPCOMP_OUI 1 /* vendor specific */
|
||||
#define IPCOMP_DEFLATE 2 /* RFC2394 */
|
||||
#define IPCOMP_LZS 3 /* RFC2395 */
|
||||
#define IPCOMP_MAX 4
|
||||
|
||||
#define IPCOMP_CPI_NEGOTIATE_MIN 256
|
||||
#endif /*_NETIPSEC_IPCOMP_H_*/
|
|
@ -0,0 +1,68 @@
|
|||
/* $NetBSD: ipcomp_var.h,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipcomp_var.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ipcomp.h,v 1.8 2000/09/26 07:55:14 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_IPCOMP_VAR_H_
|
||||
#define _NETIPSEC_IPCOMP_VAR_H_
|
||||
|
||||
/*
|
||||
* These define the algorithm indices into the histogram. They're
|
||||
* presently based on the PF_KEY v2 protocol values which is bogus;
|
||||
* they should be decoupled from the protocol at which time we can
|
||||
* pack them and reduce the size of the array to a minimum.
|
||||
*/
|
||||
#define IPCOMP_ALG_MAX 8
|
||||
|
||||
struct ipcompstat {
|
||||
u_int32_t ipcomps_hdrops; /* Packet shorter than header shows */
|
||||
u_int32_t ipcomps_nopf; /* Protocol family not supported */
|
||||
u_int32_t ipcomps_notdb;
|
||||
u_int32_t ipcomps_badkcr;
|
||||
u_int32_t ipcomps_qfull;
|
||||
u_int32_t ipcomps_noxform;
|
||||
u_int32_t ipcomps_wrap;
|
||||
u_int32_t ipcomps_input; /* Input IPcomp packets */
|
||||
u_int32_t ipcomps_output; /* Output IPcomp packets */
|
||||
u_int32_t ipcomps_invalid;/* Trying to use an invalid TDB */
|
||||
u_int64_t ipcomps_ibytes; /* Input bytes */
|
||||
u_int64_t ipcomps_obytes; /* Output bytes */
|
||||
u_int32_t ipcomps_toobig; /* Packet got > IP_MAXPACKET */
|
||||
u_int32_t ipcomps_pdrops; /* Packet blocked due to policy */
|
||||
u_int32_t ipcomps_crypto; /* "Crypto" processing failure */
|
||||
u_int32_t ipcomps_hist[IPCOMP_ALG_MAX];/* Per-algorithm op count */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern int ipcomp_enable;
|
||||
extern struct ipcompstat ipcompstat;
|
||||
#endif /* _KERNEL */
|
||||
#endif /*_NETIPSEC_IPCOMP_VAR_H_*/
|
|
@ -0,0 +1,66 @@
|
|||
/* $NetBSD: ipip_var.h,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipip_var.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $OpenBSD: ip_ipip.h,v 1.5 2002/06/09 16:26:10 itojun Exp $ */
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de).
|
||||
*
|
||||
* The original version of this code was written by John Ioannidis
|
||||
* for BSD/OS in Athens, Greece, in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Additional features in 1999 by Angelos D. Keromytis.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
|
||||
* Angelos D. Keromytis and Niels Provos.
|
||||
* Copyright (c) 2001, Angelos D. Keromytis.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#ifndef _NETINET_IPIP_H_
|
||||
#define _NETINET_IPIP_H_
|
||||
|
||||
/*
|
||||
* IP-inside-IP processing.
|
||||
* Not quite all the functionality of RFC-1853, but the main idea is there.
|
||||
*/
|
||||
|
||||
struct ipipstat
|
||||
{
|
||||
u_int32_t ipips_ipackets; /* total input packets */
|
||||
u_int32_t ipips_opackets; /* total output packets */
|
||||
u_int32_t ipips_hdrops; /* packet shorter than header shows */
|
||||
u_int32_t ipips_qfull;
|
||||
u_int64_t ipips_ibytes;
|
||||
u_int64_t ipips_obytes;
|
||||
u_int32_t ipips_pdrops; /* packet dropped due to policy */
|
||||
u_int32_t ipips_spoof; /* IP spoofing attempts */
|
||||
u_int32_t ipips_family; /* Protocol family mismatch */
|
||||
u_int32_t ipips_unspec; /* Missing tunnel endpoint address */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern int ipip_allow;
|
||||
extern struct ipipstat ipipstat;
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _NETINET_IPIP_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,460 @@
|
|||
/* $NetBSD: ipsec.h,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipsec.h,v 1.2.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ipsec.h,v 1.53 2001/11/20 08:32: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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IPsec controller part.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_IPSEC_H_
|
||||
#define _NETIPSEC_IPSEC_H_
|
||||
|
||||
#if defined(_KERNEL) && !defined(_LKM) && !defined(KLD_MODULE)
|
||||
#include "opt_inet.h"
|
||||
#include "opt_ipsec.h"
|
||||
#endif
|
||||
|
||||
#include <net/pfkeyv2.h>
|
||||
#include <netipsec/keydb.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
/*
|
||||
* Security Policy Index
|
||||
* Ensure that both address families in the "src" and "dst" are same.
|
||||
* When the value of the ul_proto is ICMPv6, the port field in "src"
|
||||
* specifies ICMPv6 type, and the port field in "dst" specifies ICMPv6 code.
|
||||
*/
|
||||
struct secpolicyindex {
|
||||
u_int8_t dir; /* direction of packet flow, see blow */
|
||||
union sockaddr_union src; /* IP src address for SP */
|
||||
union sockaddr_union dst; /* IP dst address for SP */
|
||||
u_int8_t prefs; /* prefix length in bits for src */
|
||||
u_int8_t prefd; /* prefix length in bits for dst */
|
||||
u_int16_t ul_proto; /* upper layer Protocol */
|
||||
#ifdef notyet
|
||||
uid_t uids;
|
||||
uid_t uidd;
|
||||
gid_t gids;
|
||||
gid_t gidd;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Security Policy Data Base */
|
||||
struct secpolicy {
|
||||
LIST_ENTRY(secpolicy) chain;
|
||||
|
||||
u_int refcnt; /* reference count */
|
||||
struct secpolicyindex spidx; /* selector */
|
||||
u_int32_t id; /* It's unique number on the system. */
|
||||
u_int state; /* 0: dead, others: alive */
|
||||
#define IPSEC_SPSTATE_DEAD 0
|
||||
#define IPSEC_SPSTATE_ALIVE 1
|
||||
|
||||
u_int policy; /* DISCARD, NONE or IPSEC, see keyv2.h */
|
||||
struct ipsecrequest *req;
|
||||
/* pointer to the ipsec request tree, */
|
||||
/* if policy == IPSEC else this value == NULL.*/
|
||||
|
||||
/*
|
||||
* lifetime handler.
|
||||
* the policy can be used without limitiation if both lifetime and
|
||||
* validtime are zero.
|
||||
* "lifetime" is passed by sadb_lifetime.sadb_lifetime_addtime.
|
||||
* "validtime" is passed by sadb_lifetime.sadb_lifetime_usetime.
|
||||
*/
|
||||
long created; /* time created the policy */
|
||||
long lastused; /* updated every when kernel sends a packet */
|
||||
long lifetime; /* duration of the lifetime of this policy */
|
||||
long validtime; /* duration this policy is valid without use */
|
||||
};
|
||||
|
||||
/* Request for IPsec */
|
||||
struct ipsecrequest {
|
||||
struct ipsecrequest *next;
|
||||
/* pointer to next structure */
|
||||
/* If NULL, it means the end of chain. */
|
||||
struct secasindex saidx;/* hint for search proper SA */
|
||||
/* if __ss_len == 0 then no address specified.*/
|
||||
u_int level; /* IPsec level defined below. */
|
||||
|
||||
struct secasvar *sav; /* place holder of SA for use */
|
||||
struct secpolicy *sp; /* back pointer to SP */
|
||||
};
|
||||
|
||||
/* security policy in PCB */
|
||||
struct inpcbpolicy {
|
||||
struct secpolicy *sp_in;
|
||||
struct secpolicy *sp_out;
|
||||
int priv; /* privileged socket ? */
|
||||
};
|
||||
|
||||
/* SP acquiring list table. */
|
||||
struct secspacq {
|
||||
LIST_ENTRY(secspacq) chain;
|
||||
|
||||
struct secpolicyindex spidx;
|
||||
|
||||
long created; /* for lifetime */
|
||||
int count; /* for lifetime */
|
||||
/* XXX: here is mbuf place holder to be sent ? */
|
||||
};
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/* according to IANA assignment, port 0x0000 and proto 0xff are reserved. */
|
||||
#define IPSEC_PORT_ANY 0
|
||||
#define IPSEC_ULPROTO_ANY 255
|
||||
#define IPSEC_PROTO_ANY 255
|
||||
|
||||
/* mode of security protocol */
|
||||
/* NOTE: DON'T use IPSEC_MODE_ANY at SPD. It's only use in SAD */
|
||||
#define IPSEC_MODE_ANY 0 /* i.e. wildcard. */
|
||||
#define IPSEC_MODE_TRANSPORT 1
|
||||
#define IPSEC_MODE_TUNNEL 2
|
||||
|
||||
/*
|
||||
* Direction of security policy.
|
||||
* NOTE: Since INVALID is used just as flag.
|
||||
* The other are used for loop counter too.
|
||||
*/
|
||||
#define IPSEC_DIR_ANY 0
|
||||
#define IPSEC_DIR_INBOUND 1
|
||||
#define IPSEC_DIR_OUTBOUND 2
|
||||
#define IPSEC_DIR_MAX 3
|
||||
#define IPSEC_DIR_INVALID 4
|
||||
|
||||
/* Policy level */
|
||||
/*
|
||||
* IPSEC, ENTRUST and BYPASS are allowed for setsockopt() in PCB,
|
||||
* DISCARD, IPSEC and NONE are allowed for setkey() in SPD.
|
||||
* DISCARD and NONE are allowed for system default.
|
||||
*/
|
||||
#define IPSEC_POLICY_DISCARD 0 /* discarding packet */
|
||||
#define IPSEC_POLICY_NONE 1 /* through IPsec engine */
|
||||
#define IPSEC_POLICY_IPSEC 2 /* do IPsec */
|
||||
#define IPSEC_POLICY_ENTRUST 3 /* consulting SPD if present. */
|
||||
#define IPSEC_POLICY_BYPASS 4 /* only for privileged socket. */
|
||||
|
||||
/* Security protocol level */
|
||||
#define IPSEC_LEVEL_DEFAULT 0 /* reference to system default */
|
||||
#define IPSEC_LEVEL_USE 1 /* use SA if present. */
|
||||
#define IPSEC_LEVEL_REQUIRE 2 /* require SA. */
|
||||
#define IPSEC_LEVEL_UNIQUE 3 /* unique SA. */
|
||||
|
||||
#define IPSEC_MANUAL_REQID_MAX 0x3fff
|
||||
/*
|
||||
* if security policy level == unique, this id
|
||||
* indicate to a relative SA for use, else is
|
||||
* zero.
|
||||
* 1 - 0x3fff are reserved for manual keying.
|
||||
* 0 are reserved for above reason. Others is
|
||||
* for kernel use.
|
||||
* Note that this id doesn't identify SA
|
||||
* by only itself.
|
||||
*/
|
||||
#define IPSEC_REPLAYWSIZE 32
|
||||
|
||||
/* old statistics for ipsec processing */
|
||||
struct ipsecstat {
|
||||
u_quad_t in_success; /* succeeded inbound process */
|
||||
u_quad_t in_polvio;
|
||||
/* security policy violation for inbound process */
|
||||
u_quad_t in_nosa; /* inbound SA is unavailable */
|
||||
u_quad_t in_inval; /* inbound processing failed due to EINVAL */
|
||||
u_quad_t in_nomem; /* inbound processing failed due to ENOBUFS */
|
||||
u_quad_t in_badspi; /* failed getting a SPI */
|
||||
u_quad_t in_ahreplay; /* AH replay check failed */
|
||||
u_quad_t in_espreplay; /* ESP replay check failed */
|
||||
u_quad_t in_ahauthsucc; /* AH authentication success */
|
||||
u_quad_t in_ahauthfail; /* AH authentication failure */
|
||||
u_quad_t in_espauthsucc; /* ESP authentication success */
|
||||
u_quad_t in_espauthfail; /* ESP authentication failure */
|
||||
u_quad_t in_esphist[256];
|
||||
u_quad_t in_ahhist[256];
|
||||
u_quad_t in_comphist[256];
|
||||
u_quad_t out_success; /* succeeded outbound process */
|
||||
u_quad_t out_polvio;
|
||||
/* security policy violation for outbound process */
|
||||
u_quad_t out_nosa; /* outbound SA is unavailable */
|
||||
u_quad_t out_inval; /* outbound process failed due to EINVAL */
|
||||
u_quad_t out_nomem; /* inbound processing failed due to ENOBUFS */
|
||||
u_quad_t out_noroute; /* there is no route */
|
||||
u_quad_t out_esphist[256];
|
||||
u_quad_t out_ahhist[256];
|
||||
u_quad_t out_comphist[256];
|
||||
};
|
||||
|
||||
/* statistics for ipsec processing */
|
||||
struct newipsecstat {
|
||||
u_int32_t ips_in_polvio; /* input: sec policy violation */
|
||||
u_int32_t ips_out_polvio; /* output: sec policy violation */
|
||||
u_int32_t ips_out_nosa; /* output: SA unavailable */
|
||||
u_int32_t ips_out_nomem; /* output: no memory available */
|
||||
u_int32_t ips_out_noroute; /* output: no route available */
|
||||
u_int32_t ips_out_inval; /* output: generic error */
|
||||
u_int32_t ips_out_bundlesa; /* output: bundled SA processed */
|
||||
u_int32_t ips_mbcoalesced; /* mbufs coalesced during clone */
|
||||
u_int32_t ips_clcoalesced; /* clusters coalesced during clone */
|
||||
u_int32_t ips_clcopied; /* clusters copied during clone */
|
||||
u_int32_t ips_mbinserted; /* mbufs inserted during makespace */
|
||||
/*
|
||||
* Temporary statistics for performance analysis.
|
||||
*/
|
||||
/* See where ESP/AH/IPCOMP header land in mbuf on input */
|
||||
u_int32_t ips_input_front;
|
||||
u_int32_t ips_input_middle;
|
||||
u_int32_t ips_input_end;
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX JRS FIXME: later replace NetBSD sourcecode with an IPSECSTAT_POLVIO() macro.
|
||||
* for now, map the old fields to the new fields. */
|
||||
#define ipsecstat newipsecstat
|
||||
|
||||
#define in_polvio ips_in_polvio
|
||||
#define out_polvio ips_out_polvio
|
||||
#define out_inval ips_out_inval
|
||||
|
||||
/*
|
||||
* Definitions for IPsec & Key sysctl operations.
|
||||
*/
|
||||
/*
|
||||
* Names for IPsec & Key sysctl objects
|
||||
*/
|
||||
#define IPSECCTL_STATS 1 /* stats */
|
||||
#define IPSECCTL_DEF_POLICY 2
|
||||
#define IPSECCTL_DEF_ESP_TRANSLEV 3 /* int; ESP transport mode */
|
||||
#define IPSECCTL_DEF_ESP_NETLEV 4 /* int; ESP tunnel mode */
|
||||
#define IPSECCTL_DEF_AH_TRANSLEV 5 /* int; AH transport mode */
|
||||
#define IPSECCTL_DEF_AH_NETLEV 6 /* int; AH tunnel mode */
|
||||
#if 0 /* obsolete, do not reuse */
|
||||
#define IPSECCTL_INBOUND_CALL_IKE 7
|
||||
#endif
|
||||
#define IPSECCTL_AH_CLEARTOS 8
|
||||
#define IPSECCTL_AH_OFFSETMASK 9
|
||||
#define IPSECCTL_DFBIT 10
|
||||
#define IPSECCTL_ECN 11
|
||||
#define IPSECCTL_DEBUG 12
|
||||
#define IPSECCTL_ESP_RANDPAD 13
|
||||
#define IPSECCTL_MAXID 14
|
||||
|
||||
#define IPSECCTL_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
{ 0, 0 }, \
|
||||
{ "def_policy", CTLTYPE_INT }, \
|
||||
{ "esp_trans_deflev", CTLTYPE_INT }, \
|
||||
{ "esp_net_deflev", CTLTYPE_INT }, \
|
||||
{ "ah_trans_deflev", CTLTYPE_INT }, \
|
||||
{ "ah_net_deflev", CTLTYPE_INT }, \
|
||||
{ 0, 0 }, \
|
||||
{ "ah_cleartos", CTLTYPE_INT }, \
|
||||
{ "ah_offsetmask", CTLTYPE_INT }, \
|
||||
{ "dfbit", CTLTYPE_INT }, \
|
||||
{ "ecn", CTLTYPE_INT }, \
|
||||
{ "debug", CTLTYPE_INT }, \
|
||||
{ "esp_randpad", CTLTYPE_INT }, \
|
||||
}
|
||||
|
||||
#define IPSEC6CTL_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
{ 0, 0 }, \
|
||||
{ "def_policy", CTLTYPE_INT }, \
|
||||
{ "esp_trans_deflev", CTLTYPE_INT }, \
|
||||
{ "esp_net_deflev", CTLTYPE_INT }, \
|
||||
{ "ah_trans_deflev", CTLTYPE_INT }, \
|
||||
{ "ah_net_deflev", CTLTYPE_INT }, \
|
||||
{ 0, 0 }, \
|
||||
{ 0, 0 }, \
|
||||
{ 0, 0 }, \
|
||||
{ 0, 0 }, \
|
||||
{ "ecn", CTLTYPE_INT }, \
|
||||
{ "debug", CTLTYPE_INT }, \
|
||||
{ "esp_randpad", CTLTYPE_INT }, \
|
||||
}
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct ipsec_output_state {
|
||||
struct mbuf *m;
|
||||
struct route *ro;
|
||||
struct sockaddr *dst;
|
||||
};
|
||||
|
||||
struct ipsec_history {
|
||||
int ih_proto;
|
||||
u_int32_t ih_spi;
|
||||
};
|
||||
|
||||
extern int ipsec_debug;
|
||||
|
||||
extern struct newipsecstat newipsecstat;
|
||||
extern struct secpolicy ip4_def_policy;
|
||||
extern int ip4_esp_trans_deflev;
|
||||
extern int ip4_esp_net_deflev;
|
||||
extern int ip4_ah_trans_deflev;
|
||||
extern int ip4_ah_net_deflev;
|
||||
extern int ip4_ah_cleartos;
|
||||
extern int ip4_ah_offsetmask;
|
||||
extern int ip4_ipsec_dfbit;
|
||||
extern int ip4_ipsec_ecn;
|
||||
extern int ip4_esp_randpad;
|
||||
extern int crypto_support;
|
||||
|
||||
#define ipseclog(x) do { if (ipsec_debug) log x; } while (0)
|
||||
/* for openbsd compatibility */
|
||||
#define DPRINTF(x) do { if (ipsec_debug) printf x; } while (0)
|
||||
|
||||
struct tdb_ident;
|
||||
extern struct secpolicy *ipsec_getpolicy __P((struct tdb_ident*, u_int));
|
||||
struct inpcb;
|
||||
extern struct secpolicy *ipsec4_checkpolicy __P((struct mbuf *, u_int, u_int,
|
||||
int *, struct inpcb *));
|
||||
extern struct secpolicy *ipsec_getpolicybysock(struct mbuf *, u_int,
|
||||
struct inpcb *, int *);
|
||||
extern struct secpolicy * ipsec_getpolicybyaddr(struct mbuf *, u_int,
|
||||
int, int *);
|
||||
|
||||
|
||||
static __inline struct secpolicy*
|
||||
ipsec4_getpolicybysock(struct mbuf *m, u_int dir, const struct socket *so, int *err)
|
||||
{
|
||||
panic("ipsec4_getpolicybysock");
|
||||
}
|
||||
|
||||
static __inline int
|
||||
ipsec_copy_pcbpolicy(struct inpcbpolicy *old, struct inpcbpolicy *new)
|
||||
{
|
||||
/*XXX do nothing */
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct inpcb;
|
||||
#define ipsec_init_pcbpolicy ipsec_init_policy
|
||||
extern int ipsec_init_policy __P((struct socket *so, struct inpcbpolicy **));
|
||||
extern int ipsec_copy_policy
|
||||
__P((struct inpcbpolicy *, struct inpcbpolicy *));
|
||||
extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *));
|
||||
extern int ipsec_in_reject __P((struct secpolicy *, struct mbuf *));
|
||||
|
||||
extern int ipsec4_set_policy __P((struct inpcb *inp, int optname,
|
||||
caddr_t request, size_t len, int priv));
|
||||
extern int ipsec4_get_policy __P((struct inpcb *inpcb, caddr_t request,
|
||||
size_t len, struct mbuf **mp));
|
||||
extern int ipsec4_delete_pcbpolicy __P((struct inpcb *));
|
||||
extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *));
|
||||
/*
|
||||
* KAME ipsec4_in_reject_so(struct mbuf*, struct so) compatibility shim
|
||||
*/
|
||||
#define ipsec4_in_reject_so(m, _so) \
|
||||
ipsec4_in_reject(m, ((_so) == NULL? NULL : sotoinpcb(_so)))
|
||||
|
||||
|
||||
struct secas;
|
||||
struct tcpcb;
|
||||
extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *));
|
||||
extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *));
|
||||
|
||||
extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
|
||||
#ifdef __FreeBSD__
|
||||
extern size_t ipsec_hdrsiz_tcp __P((struct tcpcb *));
|
||||
#else
|
||||
extern size_t ipsec4_hdrsiz_tcp __P((struct tcpcb *));
|
||||
#define ipsec4_getpolicybyaddr ipsec_getpolicybyaddr
|
||||
#endif
|
||||
|
||||
union sockaddr_union;
|
||||
extern char * ipsec_address(union sockaddr_union* sa);
|
||||
extern const char *ipsec_logsastr __P((struct secasvar *));
|
||||
|
||||
extern void ipsec_dumpmbuf __P((struct mbuf *));
|
||||
|
||||
/* NetBSD protosw ctlin entrypoint */
|
||||
extern void *esp4_ctlinput __P((int, struct sockaddr *, void *));
|
||||
extern void *ah4_ctlinput __P((int, struct sockaddr *, void *));
|
||||
extern int ipsec_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
|
||||
|
||||
struct m_tag;
|
||||
extern int ipsec4_common_input(struct mbuf *m, ...);
|
||||
extern int ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
|
||||
int skip, int protoff, struct m_tag *mt);
|
||||
extern int ipsec4_process_packet __P((struct mbuf *, struct ipsecrequest *,
|
||||
int, int));
|
||||
extern int ipsec_process_done __P((struct mbuf *, struct ipsecrequest *));
|
||||
|
||||
extern struct mbuf *ipsec_copypkt __P((struct mbuf *));
|
||||
|
||||
extern void m_checkalignment(const char* where, struct mbuf *m0,
|
||||
int off, int len);
|
||||
extern struct mbuf *m_clone(struct mbuf *m0);
|
||||
extern struct mbuf *m_makespace(struct mbuf *m0, int skip, int hlen, int *off);
|
||||
extern caddr_t m_pad(struct mbuf *m, int n);
|
||||
extern int m_striphdr(struct mbuf *m, int skip, int hlen);
|
||||
|
||||
/* Per-socket caching of IPsec output policy */
|
||||
static __inline int ipsec_clear_socket_cache(struct mbuf *m)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#ifndef _KERNEL
|
||||
extern caddr_t ipsec_set_policy __P((char *, int));
|
||||
extern int ipsec_get_policylen __P((caddr_t));
|
||||
extern char *ipsec_dump_policy __P((caddr_t, char *));
|
||||
|
||||
extern const char *ipsec_strerror __P((void));
|
||||
#endif /* !_KERNEL */
|
||||
|
||||
/*
|
||||
* Porting glue for impedance mismatches between {free,net,open}bsd
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
#define IPSEC_ASSERT(x, y) KASSERT(x, y)
|
||||
#define INITFN static
|
||||
#endif
|
||||
#ifdef __NetBSD__
|
||||
#define IPSEC_ASSERT(x, y) KASSERT(x)
|
||||
#define INITFN extern
|
||||
|
||||
/* External declarations of per-file init functions */
|
||||
INITFN void ah_attach(void);
|
||||
INITFN void esp_attach(void);
|
||||
INITFN void ipcomp_attach(void);
|
||||
INITFN void ipe4_attach(void);
|
||||
|
||||
INITFN void ipsec_attach(void);
|
||||
#endif /* __NetBSD __ */
|
||||
|
||||
#endif /* _NETIPSEC_IPSEC_H_ */
|
|
@ -0,0 +1,90 @@
|
|||
/* $NetBSD: ipsec6.h,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipsec6.h,v 1.1.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ipsec.h,v 1.44 2001/03/23 08:08:47 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_IPSEC6_H_
|
||||
#define _NETIPSEC_IPSEC6_H_
|
||||
|
||||
#include <net/pfkeyv2.h>
|
||||
#include <netipsec/keydb.h>
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern int ip6_esp_trans_deflev;
|
||||
extern int ip6_esp_net_deflev;
|
||||
extern int ip6_ah_trans_deflev;
|
||||
extern int ip6_ah_net_deflev;
|
||||
extern int ip6_ipsec_ecn;
|
||||
extern int ip6_esp_randpad;
|
||||
|
||||
struct inpcb;
|
||||
|
||||
/* KAME compatibility shims */
|
||||
#define ipsec6_getpolicybyaddr ipsec_getpolicybyaddr
|
||||
#define ipsec6_getpolicybysock ipsec_getpolicybysock
|
||||
#define ipsec6stat newipsecstat
|
||||
#define out_inval ips_out_inval
|
||||
#define in_polvio ips_in_polvio
|
||||
#define out_polvio ips_out_polvio
|
||||
#define key_freesp(_x) KEY_FREESP(&_x)
|
||||
|
||||
extern int ipsec6_delete_pcbpolicy __P((struct inpcb *));
|
||||
extern int ipsec6_set_policy __P((struct inpcb *inp, int optname,
|
||||
caddr_t request, size_t len, int priv));
|
||||
extern int ipsec6_get_policy
|
||||
__P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp));
|
||||
extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *));
|
||||
|
||||
struct tcp6cb;
|
||||
|
||||
extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *));
|
||||
|
||||
struct ip6_hdr;
|
||||
extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t));
|
||||
|
||||
struct m_tag;
|
||||
extern int ipsec6_common_input(struct mbuf **mp, int *offp, int proto);
|
||||
extern int ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav,
|
||||
int skip, int protoff, struct m_tag *mt);
|
||||
extern void esp6_ctlinput(int, struct sockaddr *, void *);
|
||||
|
||||
struct ipsec_output_state;
|
||||
extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *,
|
||||
struct mbuf *, struct secpolicy *, int, int *));
|
||||
extern int ipsec6_output_tunnel __P((struct ipsec_output_state *,
|
||||
struct secpolicy *, int));
|
||||
#endif /*_KERNEL*/
|
||||
|
||||
#endif /*_NETIPSEC_IPSEC6_H_*/
|
|
@ -0,0 +1,734 @@
|
|||
/* $NetBSD: ipsec_input.c,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipsec_input.c,v 1.2.4.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ipsec_input.c,v 1.1 2003/08/13 20:06:50 jonathan Exp $");
|
||||
|
||||
/*
|
||||
* IPsec input processing.
|
||||
*/
|
||||
|
||||
#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/errno.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netisr.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/ip6.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
#include <netinet/in_pcb.h>
|
||||
#ifdef INET6
|
||||
#include <netinet/icmp6.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/ipsec.h>
|
||||
#ifdef INET6
|
||||
#include <netipsec/ipsec6.h>
|
||||
#endif
|
||||
#include <netipsec/ah_var.h>
|
||||
#include <netipsec/esp.h>
|
||||
#include <netipsec/esp_var.h>
|
||||
#include <netipsec/ipcomp_var.h>
|
||||
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/keydb.h>
|
||||
|
||||
#include <netipsec/xform.h>
|
||||
#include <netinet6/ip6protosw.h>
|
||||
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#include <net/net_osdep.h>
|
||||
|
||||
#define IPSEC_ISTAT(p,x,y,z) ((p) == IPPROTO_ESP ? (x)++ : \
|
||||
(p) == IPPROTO_AH ? (y)++ : (z)++)
|
||||
|
||||
/*
|
||||
* ipsec_common_input gets called when an IPsec-protected packet
|
||||
* is received by IPv4 or IPv6. It's job is to find the right SA
|
||||
# and call the appropriate transform. The transform callback
|
||||
* takes care of further processing (like ingress filtering).
|
||||
*/
|
||||
static int
|
||||
ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
|
||||
{
|
||||
union sockaddr_union dst_address;
|
||||
struct secasvar *sav;
|
||||
u_int32_t spi;
|
||||
int s, error;
|
||||
|
||||
IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
|
||||
ipcompstat.ipcomps_input);
|
||||
|
||||
IPSEC_ASSERT(m != NULL, ("ipsec_common_input: null packet"));
|
||||
|
||||
if ((sproto == IPPROTO_ESP && !esp_enable) ||
|
||||
(sproto == IPPROTO_AH && !ah_enable) ||
|
||||
(sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
|
||||
m_freem(m);
|
||||
IPSEC_ISTAT(sproto, espstat.esps_pdrops, ahstat.ahs_pdrops,
|
||||
ipcompstat.ipcomps_pdrops);
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) {
|
||||
m_freem(m);
|
||||
IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
|
||||
ipcompstat.ipcomps_hdrops);
|
||||
DPRINTF(("ipsec_common_input: packet too small\n"));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Retrieve the SPI from the relevant IPsec header */
|
||||
if (sproto == IPPROTO_ESP)
|
||||
m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
|
||||
else if (sproto == IPPROTO_AH)
|
||||
m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
|
||||
(caddr_t) &spi);
|
||||
else if (sproto == IPPROTO_IPCOMP) {
|
||||
u_int16_t cpi;
|
||||
m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
|
||||
(caddr_t) &cpi);
|
||||
spi = ntohl(htons(cpi));
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the SA and (indirectly) call the appropriate
|
||||
* kernel crypto routine. The resulting mbuf chain is a valid
|
||||
* IP packet ready to go through input processing.
|
||||
*/
|
||||
bzero(&dst_address, sizeof (dst_address));
|
||||
dst_address.sa.sa_family = af;
|
||||
switch (af) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
dst_address.sin.sin_len = sizeof(struct sockaddr_in);
|
||||
m_copydata(m, offsetof(struct ip, ip_dst),
|
||||
sizeof(struct in_addr),
|
||||
(caddr_t) &dst_address.sin.sin_addr);
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
|
||||
sizeof(struct in6_addr),
|
||||
(caddr_t) &dst_address.sin6.sin6_addr);
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
DPRINTF(("ipsec_common_input: unsupported protocol "
|
||||
"family %u\n", af));
|
||||
m_freem(m);
|
||||
IPSEC_ISTAT(sproto, espstat.esps_nopf, ahstat.ahs_nopf,
|
||||
ipcompstat.ipcomps_nopf);
|
||||
return EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
s = splsoftnet();
|
||||
|
||||
/* NB: only pass dst since key_allocsa follows RFC2401 */
|
||||
sav = KEY_ALLOCSA(&dst_address, sproto, spi);
|
||||
if (sav == NULL) {
|
||||
DPRINTF(("ipsec_common_input: no key association found for"
|
||||
" SA %s/%08lx/%u\n",
|
||||
ipsec_address(&dst_address),
|
||||
(u_long) ntohl(spi), sproto));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
|
||||
ipcompstat.ipcomps_notdb);
|
||||
splx(s);
|
||||
m_freem(m);
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
if (sav->tdb_xform == NULL) {
|
||||
DPRINTF(("ipsec_common_input: attempted to use uninitialized"
|
||||
" SA %s/%08lx/%u\n",
|
||||
ipsec_address(&dst_address),
|
||||
(u_long) ntohl(spi), sproto));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform,
|
||||
ipcompstat.ipcomps_noxform);
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
m_freem(m);
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call appropriate transform and return -- callback takes care of
|
||||
* everything else.
|
||||
*/
|
||||
error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
/*
|
||||
* Common input handler for IPv4 AH, ESP, and IPCOMP.
|
||||
*/
|
||||
int
|
||||
ipsec4_common_input(struct mbuf *m, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int off, nxt;
|
||||
|
||||
va_start(ap, m);
|
||||
off = va_arg(ap, int);
|
||||
nxt = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
return ipsec_common_input(m, off, offsetof(struct ip, ip_p),
|
||||
AF_INET, nxt);
|
||||
}
|
||||
|
||||
/*
|
||||
* IPsec input callback for INET protocols.
|
||||
* This routine is called as the transform callback.
|
||||
* Takes care of filtering and other sanity checks on
|
||||
* the processed packet.
|
||||
*/
|
||||
int
|
||||
ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
|
||||
int skip, int protoff, struct m_tag *mt)
|
||||
{
|
||||
int prot, af, sproto;
|
||||
struct ip *ip;
|
||||
struct m_tag *mtag;
|
||||
struct tdb_ident *tdbi;
|
||||
struct secasindex *saidx;
|
||||
int error;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("ipsec4_common_input_cb");
|
||||
|
||||
IPSEC_ASSERT(m != NULL, ("ipsec4_common_input_cb: null mbuf"));
|
||||
IPSEC_ASSERT(sav != NULL, ("ipsec4_common_input_cb: null SA"));
|
||||
IPSEC_ASSERT(sav->sah != NULL, ("ipsec4_common_input_cb: null SAH"));
|
||||
saidx = &sav->sah->saidx;
|
||||
af = saidx->dst.sa.sa_family;
|
||||
IPSEC_ASSERT(af == AF_INET, ("ipsec4_common_input_cb: unexpected af %u",af));
|
||||
sproto = saidx->proto;
|
||||
IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
|
||||
sproto == IPPROTO_IPCOMP,
|
||||
("ipsec4_common_input_cb: unexpected security protocol %u",
|
||||
sproto));
|
||||
|
||||
/* Sanity check */
|
||||
if (m == NULL) {
|
||||
DPRINTF(("ipsec4_common_input_cb: null mbuf"));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
|
||||
ipcompstat.ipcomps_badkcr);
|
||||
KEY_FREESAV(&sav);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (skip != 0) {
|
||||
/* Fix IPv4 header */
|
||||
if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
|
||||
DPRINTF(("ipsec4_common_input_cb: processing failed "
|
||||
"for SA %s/%08lx\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
|
||||
ipcompstat.ipcomps_hdrops);
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
ip->ip_len = htons(m->m_pkthdr.len);
|
||||
ip->ip_off = htons(ip->ip_off);
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
|
||||
} else {
|
||||
ip = mtod(m, struct ip *);
|
||||
}
|
||||
prot = ip->ip_p;
|
||||
|
||||
/* IP-in-IP encapsulation */
|
||||
if (prot == IPPROTO_IPIP) {
|
||||
struct ip ipn;
|
||||
|
||||
/* ipn will now contain the inner IPv4 header */
|
||||
m_copydata(m, ip->ip_hl << 2, sizeof(struct ip),
|
||||
(caddr_t) &ipn);
|
||||
|
||||
#ifdef notyet
|
||||
/* XXX PROXY address isn't recorded in SAH */
|
||||
/*
|
||||
* Check that the inner source address is the same as
|
||||
* the proxy address, if available.
|
||||
*/
|
||||
if ((saidx->proxy.sa.sa_family == AF_INET &&
|
||||
saidx->proxy.sin.sin_addr.s_addr !=
|
||||
INADDR_ANY &&
|
||||
ipn.ip_src.s_addr !=
|
||||
saidx->proxy.sin.sin_addr.s_addr) ||
|
||||
(saidx->proxy.sa.sa_family != AF_INET &&
|
||||
saidx->proxy.sa.sa_family != 0)) {
|
||||
|
||||
DPRINTF(("ipsec4_common_input_cb: inner "
|
||||
"source address %s doesn't correspond to "
|
||||
"expected proxy source %s, SA %s/%08lx\n",
|
||||
inet_ntoa4(ipn.ip_src),
|
||||
ipsp_address(saidx->proxy),
|
||||
ipsp_address(saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
|
||||
IPSEC_ISTAT(sproto, espstat.esps_pdrops,
|
||||
ahstat.ahs_pdrops,
|
||||
ipcompstat.ipcomps_pdrops);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
#endif /*XXX*/
|
||||
}
|
||||
#if INET6
|
||||
/* IPv6-in-IP encapsulation. */
|
||||
if (prot == IPPROTO_IPV6) {
|
||||
struct ip6_hdr ip6n;
|
||||
|
||||
/* ip6n will now contain the inner IPv6 header. */
|
||||
m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr),
|
||||
(caddr_t) &ip6n);
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Check that the inner source address is the same as
|
||||
* the proxy address, if available.
|
||||
*/
|
||||
if ((saidx->proxy.sa.sa_family == AF_INET6 &&
|
||||
!IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
|
||||
!IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
|
||||
&saidx->proxy.sin6.sin6_addr)) ||
|
||||
(saidx->proxy.sa.sa_family != AF_INET6 &&
|
||||
saidx->proxy.sa.sa_family != 0)) {
|
||||
|
||||
DPRINTF(("ipsec4_common_input_cb: inner "
|
||||
"source address %s doesn't correspond to "
|
||||
"expected proxy source %s, SA %s/%08lx\n",
|
||||
ip6_sprintf(&ip6n.ip6_src),
|
||||
ipsec_address(&saidx->proxy),
|
||||
ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
|
||||
IPSEC_ISTAT(sproto, espstat.esps_pdrops,
|
||||
ahstat.ahs_pdrops,
|
||||
ipcompstat.ipcomps_pdrops);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
#endif /*XXX*/
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
/*
|
||||
* Record what we've done to the packet (under what SA it was
|
||||
* processed). If we've been passed an mtag, it means the packet
|
||||
* was already processed by an ethernet/crypto combo card and
|
||||
* thus has a tag attached with all the right information, but
|
||||
* with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
|
||||
* PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
|
||||
*/
|
||||
if (mt == NULL && sproto != IPPROTO_IPCOMP) {
|
||||
mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
|
||||
sizeof(struct tdb_ident), M_NOWAIT);
|
||||
if (mtag == NULL) {
|
||||
DPRINTF(("ipsec4_common_input_cb: failed to get tag\n"));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_hdrops,
|
||||
ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
|
||||
error = ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
tdbi = (struct tdb_ident *)(mtag + 1);
|
||||
bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
|
||||
tdbi->proto = sproto;
|
||||
tdbi->spi = sav->spi;
|
||||
|
||||
m_tag_prepend(m, mtag);
|
||||
} else {
|
||||
mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
|
||||
/* XXX do we need to mark m_flags??? */
|
||||
}
|
||||
|
||||
key_sa_recordxfer(sav, m); /* record data transfer */
|
||||
|
||||
/*
|
||||
* Re-dispatch via software interrupt.
|
||||
*/
|
||||
if (!IF_HANDOFF(&ipintrq, m, NULL)) {
|
||||
IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull,
|
||||
ipcompstat.ipcomps_qfull);
|
||||
|
||||
DPRINTF(("ipsec4_common_input_cb: queue full; "
|
||||
"proto %u packet dropped\n", sproto));
|
||||
return ENOBUFS;
|
||||
}
|
||||
schednetisr(NETISR_IP);
|
||||
return 0;
|
||||
bad:
|
||||
m_freem(m);
|
||||
return error;
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
/* IPv6 AH wrapper. */
|
||||
int
|
||||
ipsec6_common_input(struct mbuf **mp, int *offp, int proto)
|
||||
{
|
||||
int l = 0;
|
||||
int protoff;
|
||||
struct ip6_ext ip6e;
|
||||
|
||||
if (*offp < sizeof(struct ip6_hdr)) {
|
||||
DPRINTF(("ipsec6_common_input: bad offset %u\n", *offp));
|
||||
return IPPROTO_DONE;
|
||||
} else if (*offp == sizeof(struct ip6_hdr)) {
|
||||
protoff = offsetof(struct ip6_hdr, ip6_nxt);
|
||||
} else {
|
||||
/* Chase down the header chain... */
|
||||
protoff = sizeof(struct ip6_hdr);
|
||||
|
||||
do {
|
||||
protoff += l;
|
||||
m_copydata(*mp, protoff, sizeof(ip6e),
|
||||
(caddr_t) &ip6e);
|
||||
|
||||
if (ip6e.ip6e_nxt == IPPROTO_AH)
|
||||
l = (ip6e.ip6e_len + 2) << 2;
|
||||
else
|
||||
l = (ip6e.ip6e_len + 1) << 3;
|
||||
IPSEC_ASSERT(l > 0, ("ah6_input: l went zero or negative"));
|
||||
} while (protoff + l < *offp);
|
||||
|
||||
/* Malformed packet check */
|
||||
if (protoff + l != *offp) {
|
||||
DPRINTF(("ipsec6_common_input: bad packet header chain, "
|
||||
"protoff %u, l %u, off %u\n", protoff, l, *offp));
|
||||
IPSEC_ISTAT(proto, espstat.esps_hdrops,
|
||||
ahstat.ahs_hdrops,
|
||||
ipcompstat.ipcomps_hdrops);
|
||||
m_freem(*mp);
|
||||
*mp = NULL;
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
protoff += offsetof(struct ip6_ext, ip6e_nxt);
|
||||
}
|
||||
(void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto);
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
|
||||
void
|
||||
esp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
|
||||
{
|
||||
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) {
|
||||
struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
|
||||
struct mbuf *m = ip6cp->ip6c_m;
|
||||
int off = ip6cp->ip6c_off;
|
||||
|
||||
struct ip6ctlparam ip6cp1;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
if (cmd == PRC_MSGSIZE) {
|
||||
struct secasvar *sav;
|
||||
u_int32_t spi;
|
||||
int valid;
|
||||
|
||||
/* check header length before using m_copydata */
|
||||
if (m->m_pkthdr.len < off + sizeof (struct esp))
|
||||
return;
|
||||
m_copydata(m, off + offsetof(struct esp, esp_spi),
|
||||
sizeof(u_int32_t), (caddr_t) &spi);
|
||||
/*
|
||||
* Check to see if we have a valid SA corresponding to
|
||||
* the address in the ICMP message payload.
|
||||
*/
|
||||
sav = KEY_ALLOCSA((union sockaddr_union *)sa,
|
||||
IPPROTO_ESP, spi);
|
||||
valid = (sav != NULL);
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
|
||||
/* XXX Further validation? */
|
||||
|
||||
/*
|
||||
* Depending on whether the SA is "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(ip6cp, valid);
|
||||
}
|
||||
} else {
|
||||
/* we normally notify any pcb here */
|
||||
}
|
||||
}
|
||||
|
||||
extern struct ip6protosw inet6sw[];
|
||||
extern u_char ip6_protox[];
|
||||
|
||||
/*
|
||||
* IPsec input callback, called by the transform callback. Takes care of
|
||||
* filtering and other sanity checks on the processed packet.
|
||||
*/
|
||||
int
|
||||
ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff,
|
||||
struct m_tag *mt)
|
||||
{
|
||||
int prot, af, sproto;
|
||||
struct ip6_hdr *ip6;
|
||||
struct m_tag *mtag;
|
||||
struct tdb_ident *tdbi;
|
||||
struct secasindex *saidx;
|
||||
int nxt;
|
||||
u_int8_t nxt8;
|
||||
int error, nest;
|
||||
|
||||
IPSEC_ASSERT(m != NULL, ("ipsec6_common_input_cb: null mbuf"));
|
||||
IPSEC_ASSERT(sav != NULL, ("ipsec6_common_input_cb: null SA"));
|
||||
IPSEC_ASSERT(sav->sah != NULL, ("ipsec6_common_input_cb: null SAH"));
|
||||
saidx = &sav->sah->saidx;
|
||||
af = saidx->dst.sa.sa_family;
|
||||
IPSEC_ASSERT(af == AF_INET6,
|
||||
("ipsec6_common_input_cb: unexpected af %u", af));
|
||||
sproto = saidx->proto;
|
||||
IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
|
||||
sproto == IPPROTO_IPCOMP,
|
||||
("ipsec6_common_input_cb: unexpected security protocol %u",
|
||||
sproto));
|
||||
|
||||
/* Sanity check */
|
||||
if (m == NULL) {
|
||||
DPRINTF(("ipsec4_common_input_cb: null mbuf"));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
|
||||
ipcompstat.ipcomps_badkcr);
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Fix IPv6 header */
|
||||
if (m->m_len < sizeof(struct ip6_hdr) &&
|
||||
(m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
|
||||
|
||||
DPRINTF(("ipsec_common_input_cb: processing failed "
|
||||
"for SA %s/%08lx\n", ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
|
||||
IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
|
||||
ipcompstat.ipcomps_hdrops);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
|
||||
|
||||
/* Save protocol */
|
||||
m_copydata(m, protoff, 1, (unsigned char *) &prot);
|
||||
|
||||
#ifdef INET
|
||||
/* IP-in-IP encapsulation */
|
||||
if (prot == IPPROTO_IPIP) {
|
||||
struct ip ipn;
|
||||
|
||||
/* ipn will now contain the inner IPv4 header */
|
||||
m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Check that the inner source address is the same as
|
||||
* the proxy address, if available.
|
||||
*/
|
||||
if ((saidx->proxy.sa.sa_family == AF_INET &&
|
||||
saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY &&
|
||||
ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) ||
|
||||
(saidx->proxy.sa.sa_family != AF_INET &&
|
||||
saidx->proxy.sa.sa_family != 0)) {
|
||||
|
||||
DPRINTF(("ipsec_common_input_cb: inner "
|
||||
"source address %s doesn't correspond to "
|
||||
"expected proxy source %s, SA %s/%08lx\n",
|
||||
inet_ntoa4(ipn.ip_src),
|
||||
ipsec_address(&saidx->proxy),
|
||||
ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
|
||||
IPSEC_ISTATsproto, (espstat.esps_pdrops,
|
||||
ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
#endif /*XXX*/
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
/* IPv6-in-IP encapsulation */
|
||||
if (prot == IPPROTO_IPV6) {
|
||||
struct ip6_hdr ip6n;
|
||||
|
||||
/* ip6n will now contain the inner IPv6 header. */
|
||||
m_copydata(m, skip, sizeof(struct ip6_hdr),
|
||||
(caddr_t) &ip6n);
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Check that the inner source address is the same as
|
||||
* the proxy address, if available.
|
||||
*/
|
||||
if ((saidx->proxy.sa.sa_family == AF_INET6 &&
|
||||
!IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
|
||||
!IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
|
||||
&saidx->proxy.sin6.sin6_addr)) ||
|
||||
(saidx->proxy.sa.sa_family != AF_INET6 &&
|
||||
saidx->proxy.sa.sa_family != 0)) {
|
||||
|
||||
DPRINTF(("ipsec_common_input_cb: inner "
|
||||
"source address %s doesn't correspond to "
|
||||
"expected proxy source %s, SA %s/%08lx\n",
|
||||
ip6_sprintf(&ip6n.ip6_src),
|
||||
ipsec_address(&saidx->proxy),
|
||||
ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
|
||||
IPSEC_ISTAT(sproto, espstat.esps_pdrops,
|
||||
ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
#endif /*XXX*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Record what we've done to the packet (under what SA it was
|
||||
* processed). If we've been passed an mtag, it means the packet
|
||||
* was already processed by an ethernet/crypto combo card and
|
||||
* thus has a tag attached with all the right information, but
|
||||
* with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
|
||||
* PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
|
||||
*/
|
||||
if (mt == NULL && sproto != IPPROTO_IPCOMP) {
|
||||
mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
|
||||
sizeof(struct tdb_ident), M_NOWAIT);
|
||||
if (mtag == NULL) {
|
||||
DPRINTF(("ipsec_common_input_cb: failed to "
|
||||
"get tag\n"));
|
||||
IPSEC_ISTAT(sproto, espstat.esps_hdrops,
|
||||
ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
|
||||
error = ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
tdbi = (struct tdb_ident *)(mtag + 1);
|
||||
bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
|
||||
tdbi->proto = sproto;
|
||||
tdbi->spi = sav->spi;
|
||||
|
||||
m_tag_prepend(m, mtag);
|
||||
} else {
|
||||
mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
|
||||
/* XXX do we need to mark m_flags??? */
|
||||
}
|
||||
|
||||
key_sa_recordxfer(sav, m);
|
||||
|
||||
/* Retrieve new protocol */
|
||||
m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
|
||||
|
||||
/*
|
||||
* See the end of ip6_input for this logic.
|
||||
* IPPROTO_IPV[46] case will be processed just like other ones
|
||||
*/
|
||||
nest = 0;
|
||||
nxt = nxt8;
|
||||
while (nxt != IPPROTO_DONE) {
|
||||
if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
|
||||
ip6stat.ip6s_toomanyhdr++;
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protection against faulty packet - there should be
|
||||
* more sanity checks in header chain processing.
|
||||
*/
|
||||
if (m->m_pkthdr.len < skip) {
|
||||
ip6stat.ip6s_tooshort++;
|
||||
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* Enforce IPsec policy checking if we are seeing last header.
|
||||
* note that we do not visit this with protocols with pcb layer
|
||||
* code - like udp/tcp/raw ip.
|
||||
*/
|
||||
if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
|
||||
ipsec6_in_reject(m, NULL)) {
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt);
|
||||
}
|
||||
return 0;
|
||||
bad:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return error;
|
||||
}
|
||||
#endif /* INET6 */
|
|
@ -0,0 +1,462 @@
|
|||
/* $NetBSD: ipsec_mbuf.c,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipsec_mbuf.c,v 1.5.2.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ipsec_mbuf.c,v 1.1 2003/08/13 20:06:50 jonathan Exp $");
|
||||
|
||||
/*
|
||||
* IPsec-specific mbuf routines.
|
||||
*/
|
||||
|
||||
#include "opt_param.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <netipsec/ipsec.h>
|
||||
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
#include <net/net_osdep.h>
|
||||
|
||||
extern struct mbuf *m_getptr(struct mbuf *, int, int *);
|
||||
|
||||
/*
|
||||
* Create a writable copy of the mbuf chain. While doing this
|
||||
* we compact the chain with a goal of producing a chain with
|
||||
* at most two mbufs. The second mbuf in this chain is likely
|
||||
* to be a cluster. The primary purpose of this work is to create
|
||||
* a writable packet for encryption, compression, etc. The
|
||||
* secondary goal is to linearize the data so the data can be
|
||||
* passed to crypto hardware in the most efficient manner possible.
|
||||
*/
|
||||
struct mbuf *
|
||||
m_clone(struct mbuf *m0)
|
||||
{
|
||||
struct mbuf *m, *mprev;
|
||||
struct mbuf *n, *mfirst, *mlast;
|
||||
int len, off;
|
||||
|
||||
IPSEC_ASSERT(m0 != NULL, ("m_clone: null mbuf"));
|
||||
|
||||
mprev = NULL;
|
||||
for (m = m0; m != NULL; m = mprev->m_next) {
|
||||
/*
|
||||
* Regular mbufs are ignored unless there's a cluster
|
||||
* in front of it that we can use to coalesce. We do
|
||||
* the latter mainly so later clusters can be coalesced
|
||||
* also w/o having to handle them specially (i.e. convert
|
||||
* mbuf+cluster -> cluster). This optimization is heavily
|
||||
* influenced by the assumption that we're running over
|
||||
* Ethernet where MCLBYTES is large enough that the max
|
||||
* packet size will permit lots of coalescing into a
|
||||
* single cluster. This in turn permits efficient
|
||||
* crypto operations, especially when using hardware.
|
||||
*/
|
||||
if ((m->m_flags & M_EXT) == 0) {
|
||||
if (mprev && (mprev->m_flags & M_EXT) &&
|
||||
m->m_len <= M_TRAILINGSPACE(mprev)) {
|
||||
/* XXX: this ignores mbuf types */
|
||||
memcpy(mtod(mprev, caddr_t) + mprev->m_len,
|
||||
mtod(m, caddr_t), m->m_len);
|
||||
mprev->m_len += m->m_len;
|
||||
mprev->m_next = m->m_next; /* unlink from chain */
|
||||
m_free(m); /* reclaim mbuf */
|
||||
newipsecstat.ips_mbcoalesced++;
|
||||
} else {
|
||||
mprev = m;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Writable mbufs are left alone (for now). Note
|
||||
* that for 4.x systems it's not possible to identify
|
||||
* whether or not mbufs with external buffers are
|
||||
* writable unless they use clusters.
|
||||
*/
|
||||
if (M_EXT_WRITABLE(m)) {
|
||||
mprev = m;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not writable, replace with a copy or coalesce with
|
||||
* the previous mbuf if possible (since we have to copy
|
||||
* it anyway, we try to reduce the number of mbufs and
|
||||
* clusters so that future work is easier).
|
||||
*/
|
||||
IPSEC_ASSERT(m->m_flags & M_EXT,
|
||||
("m_clone: m_flags 0x%x", m->m_flags));
|
||||
/* NB: we only coalesce into a cluster or larger */
|
||||
if (mprev != NULL && (mprev->m_flags & M_EXT) &&
|
||||
m->m_len <= M_TRAILINGSPACE(mprev)) {
|
||||
/* XXX: this ignores mbuf types */
|
||||
memcpy(mtod(mprev, caddr_t) + mprev->m_len,
|
||||
mtod(m, caddr_t), m->m_len);
|
||||
mprev->m_len += m->m_len;
|
||||
mprev->m_next = m->m_next; /* unlink from chain */
|
||||
m_free(m); /* reclaim mbuf */
|
||||
newipsecstat.ips_clcoalesced++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate new space to hold the copy...
|
||||
*/
|
||||
/* XXX why can M_PKTHDR be set past the first mbuf? */
|
||||
if (mprev == NULL && (m->m_flags & M_PKTHDR)) {
|
||||
/*
|
||||
* NB: if a packet header is present we must
|
||||
* allocate the mbuf separately from any cluster
|
||||
* because M_MOVE_PKTHDR will smash the data
|
||||
* pointer and drop the M_EXT marker.
|
||||
*/
|
||||
MGETHDR(n, M_DONTWAIT, m->m_type);
|
||||
if (n == NULL) {
|
||||
m_freem(m0);
|
||||
return (NULL);
|
||||
}
|
||||
M_MOVE_PKTHDR(n, m);
|
||||
MCLGET(n, M_DONTWAIT);
|
||||
if ((n->m_flags & M_EXT) == 0) {
|
||||
m_free(n);
|
||||
m_freem(m0);
|
||||
return (NULL);
|
||||
}
|
||||
} else {
|
||||
n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags);
|
||||
if (n == NULL) {
|
||||
m_freem(m0);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* ... and copy the data. We deal with jumbo mbufs
|
||||
* (i.e. m_len > MCLBYTES) by splitting them into
|
||||
* clusters. We could just malloc a buffer and make
|
||||
* it external but too many device drivers don't know
|
||||
* how to break up the non-contiguous memory when
|
||||
* doing DMA.
|
||||
*/
|
||||
len = m->m_len;
|
||||
off = 0;
|
||||
mfirst = n;
|
||||
mlast = NULL;
|
||||
for (;;) {
|
||||
int cc = min(len, MCLBYTES);
|
||||
memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off, cc);
|
||||
n->m_len = cc;
|
||||
if (mlast != NULL)
|
||||
mlast->m_next = n;
|
||||
mlast = n;
|
||||
newipsecstat.ips_clcopied++;
|
||||
|
||||
len -= cc;
|
||||
if (len <= 0)
|
||||
break;
|
||||
off += cc;
|
||||
|
||||
n = m_getcl(M_DONTWAIT, m->m_type, m->m_flags);
|
||||
if (n == NULL) {
|
||||
m_freem(mfirst);
|
||||
m_freem(m0);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
n->m_next = m->m_next;
|
||||
if (mprev == NULL)
|
||||
m0 = mfirst; /* new head of chain */
|
||||
else
|
||||
mprev->m_next = mfirst; /* replace old mbuf */
|
||||
m_free(m); /* release old mbuf */
|
||||
mprev = mfirst;
|
||||
}
|
||||
return (m0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make space for a new header of length hlen at skip bytes
|
||||
* into the packet. When doing this we allocate new mbufs only
|
||||
* when absolutely necessary. The mbuf where the new header
|
||||
* is to go is returned together with an offset into the mbuf.
|
||||
* If NULL is returned then the mbuf chain may have been modified;
|
||||
* the caller is assumed to always free the chain.
|
||||
*/
|
||||
struct mbuf *
|
||||
m_makespace(struct mbuf *m0, int skip, int hlen, int *off)
|
||||
{
|
||||
struct mbuf *m;
|
||||
unsigned remain;
|
||||
|
||||
IPSEC_ASSERT(m0 != NULL, ("m_dmakespace: null mbuf"));
|
||||
IPSEC_ASSERT(hlen < MHLEN, ("m_makespace: hlen too big: %u", hlen));
|
||||
|
||||
for (m = m0; m && skip > m->m_len; m = m->m_next)
|
||||
skip -= m->m_len;
|
||||
if (m == NULL)
|
||||
return (NULL);
|
||||
/*
|
||||
* At this point skip is the offset into the mbuf m
|
||||
* where the new header should be placed. Figure out
|
||||
* if there's space to insert the new header. If so,
|
||||
* and copying the remainder makese sense then do so.
|
||||
* Otherwise insert a new mbuf in the chain, splitting
|
||||
* the contents of m as needed.
|
||||
*/
|
||||
remain = m->m_len - skip; /* data to move */
|
||||
if (hlen > M_TRAILINGSPACE(m)) {
|
||||
struct mbuf *n;
|
||||
|
||||
/* XXX code doesn't handle clusters XXX */
|
||||
IPSEC_ASSERT(remain < MLEN,
|
||||
("m_makespace: remainder too big: %u", remain));
|
||||
/*
|
||||
* Not enough space in m, split the contents
|
||||
* of m, inserting new mbufs as required.
|
||||
*
|
||||
* NB: this ignores mbuf types.
|
||||
*/
|
||||
MGET(n, M_DONTWAIT, MT_DATA);
|
||||
if (n == NULL)
|
||||
return (NULL);
|
||||
n->m_next = m->m_next; /* splice new mbuf */
|
||||
m->m_next = n;
|
||||
newipsecstat.ips_mbinserted++;
|
||||
if (hlen <= M_TRAILINGSPACE(m) + remain) {
|
||||
/*
|
||||
* New header fits in the old mbuf if we copy
|
||||
* the remainder; just do the copy to the new
|
||||
* mbuf and we're good to go.
|
||||
*/
|
||||
memcpy(mtod(n, caddr_t),
|
||||
mtod(m, caddr_t) + skip, remain);
|
||||
n->m_len = remain;
|
||||
m->m_len = skip + hlen;
|
||||
*off = skip;
|
||||
} else {
|
||||
/*
|
||||
* No space in the old mbuf for the new header.
|
||||
* Make space in the new mbuf and check the
|
||||
* remainder'd data fits too. If not then we
|
||||
* must allocate an additional mbuf (yech).
|
||||
*/
|
||||
n->m_len = 0;
|
||||
if (remain + hlen > M_TRAILINGSPACE(n)) {
|
||||
struct mbuf *n2;
|
||||
|
||||
MGET(n2, M_DONTWAIT, MT_DATA);
|
||||
/* NB: new mbuf is on chain, let caller free */
|
||||
if (n2 == NULL)
|
||||
return (NULL);
|
||||
n2->m_len = 0;
|
||||
memcpy(mtod(n2, caddr_t),
|
||||
mtod(m, caddr_t) + skip, remain);
|
||||
n2->m_len = remain;
|
||||
/* splice in second mbuf */
|
||||
n2->m_next = n->m_next;
|
||||
n->m_next = n2;
|
||||
newipsecstat.ips_mbinserted++;
|
||||
} else {
|
||||
memcpy(mtod(n, caddr_t) + hlen,
|
||||
mtod(m, caddr_t) + skip, remain);
|
||||
n->m_len += remain;
|
||||
}
|
||||
m->m_len -= remain;
|
||||
n->m_len += hlen;
|
||||
m = n; /* header is at front ... */
|
||||
*off = 0; /* ... of new mbuf */
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Copy the remainder to the back of the mbuf
|
||||
* so there's space to write the new header.
|
||||
*/
|
||||
/* XXX can this be memcpy? does it handle overlap? */
|
||||
ovbcopy(mtod(m, caddr_t) + skip,
|
||||
mtod(m, caddr_t) + skip + hlen, remain);
|
||||
m->m_len += hlen;
|
||||
*off = skip;
|
||||
}
|
||||
m0->m_pkthdr.len += hlen; /* adjust packet length */
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
|
||||
* length is updated, and a pointer to the first byte of the padding
|
||||
* (which is guaranteed to be all in one mbuf) is returned.
|
||||
*/
|
||||
caddr_t
|
||||
m_pad(struct mbuf *m, int n)
|
||||
{
|
||||
register struct mbuf *m0, *m1;
|
||||
register int len, pad;
|
||||
caddr_t retval;
|
||||
|
||||
if (n <= 0) { /* No stupid arguments. */
|
||||
DPRINTF(("m_pad: pad length invalid (%d)\n", n));
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = m->m_pkthdr.len;
|
||||
pad = n;
|
||||
m0 = m;
|
||||
|
||||
while (m0->m_len < len) {
|
||||
IPSEC_ASSERT(m0->m_next != NULL, ("m_pad: m0 null, len %u m_len %u", len, m0->m_len));/*XXX*/
|
||||
len -= m0->m_len;
|
||||
m0 = m0->m_next;
|
||||
}
|
||||
|
||||
if (m0->m_len != len) {
|
||||
DPRINTF(("m_pad: length mismatch (should be %d instead of %d)\n",
|
||||
m->m_pkthdr.len, m->m_pkthdr.len + m0->m_len - len));
|
||||
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Check for zero-length trailing mbufs, and find the last one. */
|
||||
for (m1 = m0; m1->m_next; m1 = m1->m_next) {
|
||||
if (m1->m_next->m_len != 0) {
|
||||
DPRINTF(("m_pad: length mismatch (should be %d "
|
||||
"instead of %d)\n",
|
||||
m->m_pkthdr.len,
|
||||
m->m_pkthdr.len + m1->m_next->m_len));
|
||||
|
||||
m_freem(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m0 = m1->m_next;
|
||||
}
|
||||
|
||||
if (pad > M_TRAILINGSPACE(m0)) {
|
||||
/* Add an mbuf to the chain. */
|
||||
MGET(m1, M_DONTWAIT, MT_DATA);
|
||||
if (m1 == 0) {
|
||||
m_freem(m0);
|
||||
DPRINTF(("m_pad: unable to get extra mbuf\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m0->m_next = m1;
|
||||
m0 = m1;
|
||||
m0->m_len = 0;
|
||||
}
|
||||
|
||||
retval = m0->m_data + m0->m_len;
|
||||
m0->m_len += pad;
|
||||
m->m_pkthdr.len += pad;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove hlen data at offset skip in the packet. This is used by
|
||||
* the protocols strip protocol headers and associated data (e.g. IV,
|
||||
* authenticator) on input.
|
||||
*/
|
||||
int
|
||||
m_striphdr(struct mbuf *m, int skip, int hlen)
|
||||
{
|
||||
struct mbuf *m1;
|
||||
int roff;
|
||||
|
||||
/* Find beginning of header */
|
||||
m1 = m_getptr(m, skip, &roff);
|
||||
if (m1 == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/* Remove the header and associated data from the mbuf. */
|
||||
if (roff == 0) {
|
||||
/* The header was at the beginning of the mbuf */
|
||||
newipsecstat.ips_input_front++;
|
||||
m_adj(m1, hlen);
|
||||
if ((m1->m_flags & M_PKTHDR) == 0)
|
||||
m->m_pkthdr.len -= hlen;
|
||||
} else if (roff + hlen >= m1->m_len) {
|
||||
struct mbuf *mo;
|
||||
|
||||
/*
|
||||
* Part or all of the header is at the end of this mbuf,
|
||||
* so first let's remove the remainder of the header from
|
||||
* the beginning of the remainder of the mbuf chain, if any.
|
||||
*/
|
||||
newipsecstat.ips_input_end++;
|
||||
if (roff + hlen > m1->m_len) {
|
||||
/* Adjust the next mbuf by the remainder */
|
||||
m_adj(m1->m_next, roff + hlen - m1->m_len);
|
||||
|
||||
/* The second mbuf is guaranteed not to have a pkthdr... */
|
||||
m->m_pkthdr.len -= (roff + hlen - m1->m_len);
|
||||
}
|
||||
|
||||
/* Now, let's unlink the mbuf chain for a second...*/
|
||||
mo = m1->m_next;
|
||||
m1->m_next = NULL;
|
||||
|
||||
/* ...and trim the end of the first part of the chain...sick */
|
||||
m_adj(m1, -(m1->m_len - roff));
|
||||
if ((m1->m_flags & M_PKTHDR) == 0)
|
||||
m->m_pkthdr.len -= (m1->m_len - roff);
|
||||
|
||||
/* Finally, let's relink */
|
||||
m1->m_next = mo;
|
||||
} else {
|
||||
/*
|
||||
* The header lies in the "middle" of the mbuf; copy
|
||||
* the remainder of the mbuf down over the header.
|
||||
*/
|
||||
newipsecstat.ips_input_middle++;
|
||||
bcopy(mtod(m1, u_char *) + roff + hlen,
|
||||
mtod(m1, u_char *) + roff,
|
||||
m1->m_len - (roff + hlen));
|
||||
m1->m_len -= hlen;
|
||||
m->m_pkthdr.len -= hlen;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diagnostic routine to check mbuf alignment as required by the
|
||||
* crypto device drivers (that use DMA).
|
||||
*/
|
||||
void
|
||||
m_checkalignment(const char* where, struct mbuf *m0, int off, int len)
|
||||
{
|
||||
int roff;
|
||||
struct mbuf *m = m_getptr(m0, off, &roff);
|
||||
caddr_t addr;
|
||||
|
||||
if (m == NULL)
|
||||
return;
|
||||
printf("%s (off %u len %u): ", where, off, len);
|
||||
addr = mtod(m, caddr_t) + roff;
|
||||
do {
|
||||
int mlen;
|
||||
|
||||
if (((uintptr_t) addr) & 3) {
|
||||
printf("addr misaligned %p,", addr);
|
||||
break;
|
||||
}
|
||||
mlen = m->m_len;
|
||||
if (mlen > len)
|
||||
mlen = len;
|
||||
len -= mlen;
|
||||
if (len && (mlen & 3)) {
|
||||
printf("len mismatch %u,", mlen);
|
||||
break;
|
||||
}
|
||||
m = m->m_next;
|
||||
addr = m ? mtod(m, caddr_t) : NULL;
|
||||
} while (m && len > 0);
|
||||
for (m = m0; m; m = m->m_next)
|
||||
printf(" [%p:%u]", mtod(m, caddr_t), m->m_len);
|
||||
printf("\n");
|
||||
}
|
|
@ -0,0 +1,407 @@
|
|||
/* $NetBSD: ipsec_netbsd.c,v 1.1 2003/08/13 20:06:50 jonathan Exp $ */
|
||||
/* $KAME: esp_input.c,v 1.60 2001/09/04 08:43:19 itojun Exp $ */
|
||||
/* $KAME: ah_input.c,v 1.64 2001/09/04 08:43:19 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>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ipsec_netbsd.c,v 1.1 2003/08/13 20:06:50 jonathan Exp $");
|
||||
|
||||
#include "opt_inet.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/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.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>
|
||||
#include <netinet/ip_icmp.h>
|
||||
|
||||
#ifdef IPSEC
|
||||
#include <netkey/key.h>
|
||||
#include <netkey/keydb.h>
|
||||
#include <netkey/key_debug.h>
|
||||
#endif
|
||||
|
||||
#ifdef FAST_IPSEC
|
||||
#include <netipsec/ipsec.h>
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/keydb.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
#include <netipsec/ah_var.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
|
||||
|
||||
#include <netipsec/key.h>
|
||||
|
||||
/* assumes that ip header and ah header are contiguous on mbuf */
|
||||
void *
|
||||
ah4_ctlinput(cmd, sa, v)
|
||||
int cmd;
|
||||
struct sockaddr *sa;
|
||||
void *v;
|
||||
{
|
||||
struct ip *ip = v;
|
||||
struct ah *ah;
|
||||
struct icmp *icp;
|
||||
struct secasvar *sav;
|
||||
|
||||
if (sa->sa_family != AF_INET ||
|
||||
sa->sa_len != sizeof(struct sockaddr_in))
|
||||
return NULL;
|
||||
if ((unsigned)cmd >= PRC_NCMDS)
|
||||
return NULL;
|
||||
#ifndef notyet
|
||||
(void) ip; (void) ah; (void) icp; (void) sav;
|
||||
#else
|
||||
if (cmd == PRC_MSGSIZE && ip_mtudisc && ip && ip->ip_v == 4) {
|
||||
/*
|
||||
* Check to see if we have a valid SA corresponding to
|
||||
* the address in the ICMP message payload.
|
||||
*/
|
||||
ah = (struct ah *)((caddr_t)ip + (ip->ip_hl << 2));
|
||||
if ((sav = key_allocsa(AF_INET,
|
||||
(caddr_t) &ip->ip_src,
|
||||
(caddr_t) &ip->ip_dst,
|
||||
IPPROTO_AH, ah->ah_spi)) == NULL)
|
||||
return NULL;
|
||||
if (sav->state != SADB_SASTATE_MATURE &&
|
||||
sav->state != SADB_SASTATE_DYING) {
|
||||
key_freesav(sav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* XXX Further validation? */
|
||||
|
||||
key_freesav(sav);
|
||||
|
||||
/*
|
||||
* Now that we've validated that we are actually communicating
|
||||
* with the host indicated in the ICMP message, locate the
|
||||
* ICMP header, recalculate the new MTU, and create the
|
||||
* corresponding routing entry.
|
||||
*/
|
||||
icp = (struct icmp *)((caddr_t)ip -
|
||||
offsetof(struct icmp, icmp_ip));
|
||||
icmp_mtudisc(icp, ip->ip_dst);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* assumes that ip header and esp header are contiguous on mbuf */
|
||||
void *
|
||||
esp4_ctlinput(cmd, sa, v)
|
||||
int cmd;
|
||||
struct sockaddr *sa;
|
||||
void *v;
|
||||
{
|
||||
struct ip *ip = v;
|
||||
struct esp *esp;
|
||||
struct icmp *icp;
|
||||
struct secasvar *sav;
|
||||
|
||||
if (sa->sa_family != AF_INET ||
|
||||
sa->sa_len != sizeof(struct sockaddr_in))
|
||||
return NULL;
|
||||
if ((unsigned)cmd >= PRC_NCMDS)
|
||||
return NULL;
|
||||
#ifndef notyet
|
||||
(void) ip; (void) esp; (void) icp; (void) sav;
|
||||
#else
|
||||
if (cmd == PRC_MSGSIZE && ip_mtudisc && ip && ip->ip_v == 4) {
|
||||
/*
|
||||
* Check to see if we have a valid SA corresponding to
|
||||
* the address in the ICMP message payload.
|
||||
*/
|
||||
esp = (struct esp *)((caddr_t)ip + (ip->ip_hl << 2));
|
||||
if ((sav = key_allocsa(AF_INET,
|
||||
(caddr_t) &ip->ip_src,
|
||||
(caddr_t) &ip->ip_dst,
|
||||
IPPROTO_ESP, esp->esp_spi)) == NULL)
|
||||
return NULL;
|
||||
if (sav->state != SADB_SASTATE_MATURE &&
|
||||
sav->state != SADB_SASTATE_DYING) {
|
||||
key_freesav(sav);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* XXX Further validation? */
|
||||
|
||||
key_freesav(sav);
|
||||
|
||||
/*
|
||||
* Now that we've validated that we are actually communicating
|
||||
* with the host indicated in the ICMP message, locate the
|
||||
* ICMP header, recalculate the new MTU, and create the
|
||||
* corresponding routing entry.
|
||||
*/
|
||||
icp = (struct icmp *)((caddr_t)ip -
|
||||
offsetof(struct icmp, icmp_ip));
|
||||
icmp_mtudisc(icp, ip->ip_dst);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
/*FIXME: placebo for invalpcbcacheall. Fast-IPsec has no pcb cache? */
|
||||
|
||||
void ipsec_invalpcbcacheall(void);
|
||||
void
|
||||
ipsec_invalpcbcacheall(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* XXX will need a different oid at parent */
|
||||
int
|
||||
ipsec_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
|
||||
int *name;
|
||||
u_int namelen;
|
||||
void *oldp;
|
||||
size_t *oldlenp;
|
||||
void *newp;
|
||||
size_t newlen;
|
||||
{
|
||||
/* All sysctl names at this level are terminal. */
|
||||
if (namelen != 1)
|
||||
return ENOTDIR;
|
||||
|
||||
/* common sanity checks */
|
||||
switch (name[0]) {
|
||||
case IPSECCTL_DEF_ESP_TRANSLEV:
|
||||
case IPSECCTL_DEF_ESP_NETLEV:
|
||||
case IPSECCTL_DEF_AH_TRANSLEV:
|
||||
case IPSECCTL_DEF_AH_NETLEV:
|
||||
if (newp != NULL && newlen == sizeof(int)) {
|
||||
switch (*(int *)newp) {
|
||||
case IPSEC_LEVEL_USE:
|
||||
case IPSEC_LEVEL_REQUIRE:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IPSECCTL_DEF_POLICY:
|
||||
if (newp != NULL && newlen == sizeof(int)) {
|
||||
switch (*(int *)newp) {
|
||||
case IPSEC_POLICY_DISCARD:
|
||||
case IPSEC_POLICY_NONE:
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
ipsec_invalpcbcacheall();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (name[0]) {
|
||||
case IPSECCTL_STATS:
|
||||
return sysctl_struct(oldp, oldlenp, newp, newlen,
|
||||
&ipsecstat, sizeof(ipsecstat));
|
||||
case IPSECCTL_DEF_POLICY:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_def_policy.policy);
|
||||
case IPSECCTL_DEF_ESP_TRANSLEV:
|
||||
if (newp != NULL)
|
||||
ipsec_invalpcbcacheall();
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_esp_trans_deflev);
|
||||
case IPSECCTL_DEF_ESP_NETLEV:
|
||||
if (newp != NULL)
|
||||
ipsec_invalpcbcacheall();
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_esp_net_deflev);
|
||||
case IPSECCTL_DEF_AH_TRANSLEV:
|
||||
if (newp != NULL)
|
||||
ipsec_invalpcbcacheall();
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_ah_trans_deflev);
|
||||
case IPSECCTL_DEF_AH_NETLEV:
|
||||
if (newp != NULL)
|
||||
ipsec_invalpcbcacheall();
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_ah_net_deflev);
|
||||
case IPSECCTL_AH_CLEARTOS:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&/*ip4_*/ah_cleartos);
|
||||
case IPSECCTL_AH_OFFSETMASK:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_ah_offsetmask);
|
||||
case IPSECCTL_DFBIT:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen,
|
||||
&ip4_ipsec_dfbit);
|
||||
case IPSECCTL_ECN:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen, &ip4_ipsec_ecn);
|
||||
case IPSECCTL_DEBUG:
|
||||
return sysctl_int(oldp, oldlenp, newp, newlen, &ipsec_debug);
|
||||
default:
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
/* $NetBSD: ipsec_osdep.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
|
||||
#ifndef NETIPSEC_OSDEP_H
|
||||
#define NETIPSEC_OSDEP_H
|
||||
|
||||
/*
|
||||
* Hide porting differences across different 4.4BSD-derived platforms.
|
||||
*
|
||||
* 1. KASSERT() differences:
|
||||
* 2. Kernel Random-number API differences.
|
||||
* 3. Is packet data in an mbuf object writeable?
|
||||
* 4. Packet-header semantics.
|
||||
* 5. Fast mbuf-cluster allocation.
|
||||
* 6. Network packet-output macros.
|
||||
* 7. Elased time, in seconds.
|
||||
* 8. Test if a socket object opened by a privileged (super) user.
|
||||
* 9. Global SLIST of all open raw sockets.
|
||||
* 10. Global SLIST of known interface addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 1. KASSERT and spl differences
|
||||
*
|
||||
* FreeBSD takes an expression and parenthesized printf() argument-list.
|
||||
* NetBSD takes one arg: the expression being asserted.
|
||||
* FreeBSD's SPLASSERT() takes an SPL level as 1st arg and a
|
||||
* parenthesized printf-format argument list as the second argument.
|
||||
*
|
||||
* This difference is hidden by two 2-argument macros and one 1-arg macro:
|
||||
* IPSEC_ASSERT(expr, msg)
|
||||
* IPSEC_SPLASSERT(spl, msg)
|
||||
* One further difference is the spl names:
|
||||
* NetBSD splsoftnet equates to FreeBSD splnet;
|
||||
* NetBSD splnet equates to FreeBSD splimp.
|
||||
* which is hidden by the macro IPSEC_SPLASSERT_SOFTNET(msg).
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
#define IPSEC_SPLASSERT(x,y) SPLASSERT(x, y)
|
||||
#define IPSEC_ASSERT(c,m) KASSERT(c, m)
|
||||
#define IPSEC_SPLASSERT_SOFTNET(m) SPLASSERT(splnet, m)
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#define IPSEC_SPLASSERT(x,y) (void)0
|
||||
#define IPSEC_ASSERT(c,m) KASSERT(c)
|
||||
#define IPSEC_SPLASSERT_SOFTNET(m) IPSEC_SPLASSERT(softnet, m)
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 2. Kernel Randomness API.
|
||||
* FreeBSD uses:
|
||||
* u_int read_random(void *outbuf, int nbytes).
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/random.h>
|
||||
/* do nothing, use native random code. */
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/rnd.h>
|
||||
static __inline u_int read_random(void *p, u_int len);
|
||||
|
||||
static __inline u_int
|
||||
read_random(void *bufp, u_int len)
|
||||
{
|
||||
return rnd_extract_data(bufp, len, RND_EXTRACT_ANY /*XXX FIXME */);
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 3. Test for mbuf mutability
|
||||
* FreeBSD 4.x uses: M_EXT_WRITABLE
|
||||
* NetBSD has M_READONLY(). Use !M_READONLY().
|
||||
* Not an exact match to FreeBSD semantics, but adequate for IPsec purposes.
|
||||
*
|
||||
*/
|
||||
#ifdef __NetBSD__
|
||||
/* XXX wrong, but close enough for restricted ipsec usage. */
|
||||
#define M_EXT_WRITABLE(m) (!M_READONLY(m))
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 4. mbuf packet-header/packet-tag semantics.
|
||||
* Sam Leffler explains, in private email, some problems with
|
||||
* M_COPY_PKTHDR(), and why FreeBSD deprecated it and replaced it
|
||||
* with new, explicit macros M_MOVE_PKTHDR()/M_DUP_PKTHDR().
|
||||
* he original fast-ipsec source uses M_MOVE_PKTHDR.
|
||||
* NetBSD currently still uses M_COPY_PKTHDR(), so we define
|
||||
* M_MOVE_PKTHDR in terms of M_COPY_PKTHDR(). Fast-IPsec
|
||||
* will delete the source mbuf shortly after copying packet tags,
|
||||
* so we are safe for fast-ipsec but not in general..
|
||||
*/
|
||||
#ifdef __NetBSD__
|
||||
#define M_MOVE_PKTHDR(_f, _t) M_COPY_PKTHDR(_f, _t)
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
|
||||
/*
|
||||
* 5. Fast mbuf-cluster allocation.
|
||||
* FreeBSD 4.6 introduce m_getcl(), which performs `fast' allocation
|
||||
* mbuf clusters from a cache of recently-freed clusters. (If the cache
|
||||
* is empty, new clusters are allocated en-masse).
|
||||
* On NetBSD, for now, implement the `cache' as an inline function
|
||||
*using normal NetBSD mbuf/cluster allocation macros. Replace this
|
||||
* with fast-cache code, if and when netBSD implements one.
|
||||
*/
|
||||
#ifdef __NetBSD__
|
||||
static __inline struct mbuf *
|
||||
m_getcl(int how, short type, int flags)
|
||||
{
|
||||
struct mbuf *mp;
|
||||
if (flags & M_PKTHDR)
|
||||
MGETHDR(mp, how, type);
|
||||
else
|
||||
MGET(mp, how, type);
|
||||
if (mp == NULL)
|
||||
return NULL;
|
||||
|
||||
MCLGET(mp, how);
|
||||
return mp;
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 6. Network output macros
|
||||
* FreeBSD uses the IF_HANDOFF(), which raises SPL, enqueues
|
||||
* a packet, and updates interface counters. NetBSD has IFQ_ENQUE(),
|
||||
* which leaves SPL changes up to the caller.
|
||||
* For now, we provide an emulation of IF_HANOOFF() which works
|
||||
* for protocol input queues.
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
/* nothing to do */
|
||||
#endif /* __FreeBSD__ */
|
||||
#ifdef __NetBSD__
|
||||
#define IF_HANDOFF(ifq, m, f) if_handoff(ifq, m, f, 0)
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
static __inline int
|
||||
if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
|
||||
{
|
||||
int need_if_start = 0;
|
||||
int s = splnet();
|
||||
|
||||
if (IF_QFULL(ifq)) {
|
||||
IF_DROP(ifq);
|
||||
splx(s);
|
||||
m_freem(m);
|
||||
return (0);
|
||||
}
|
||||
if (ifp != NULL) {
|
||||
ifp->if_obytes += m->m_pkthdr.len + adjust;
|
||||
if (m->m_flags & M_MCAST)
|
||||
ifp->if_omcasts++;
|
||||
need_if_start = !(ifp->if_flags & IFF_OACTIVE);
|
||||
}
|
||||
IF_ENQUEUE(ifq, m);
|
||||
if (need_if_start)
|
||||
(*ifp->if_start)(ifp);
|
||||
splx(s);
|
||||
return (1);
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 7. Elapsed Time: time_second as time in seconds.
|
||||
* Original FreeBSD fast-ipsec code references a FreeBSD kernel global,
|
||||
* time_second(). NetBSD: kludge #define to use time_mono_time.tv_sec.
|
||||
*/
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/kernel.h>
|
||||
#define time_second mono_time.tv_sec
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/* protosw glue */
|
||||
#ifdef __NetBSD__
|
||||
#include <sys/protosw.h>
|
||||
#define ipprotosw protosw
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 8. Test for "privileged" socket opened by superuser.
|
||||
* FreeBSD tests ((so)->so_cred && (so)->so_cred.cr_uid == 0),
|
||||
* NetBSD (1.6N) tests (so)->so_uid == 0).
|
||||
* This difference is wrapped inside the IPSEC_PRIVILEGED_SO() macro.
|
||||
*
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
#define IPSEC_PRIVILEGED_SO(so) ((so)->so_cred && (so)->so_cred.cr_uid == 0)
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
#ifdef __NetBSD__
|
||||
/* superuser opened socket? */
|
||||
#define IPSEC_PRIVILEGED_SO(so) ((so)->so_uid == 0)
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
/*
|
||||
* 9. Raw socket list
|
||||
* FreeBSD uses: listhead = rawcb_list, SLIST()-next field "list".
|
||||
* NetBSD uses: listhead = rawcb, SLIST()-next field "list"
|
||||
*
|
||||
* This version of fast-ipsec source code uses rawcb_list as the head,
|
||||
* and (to avoid namespace collisions) uses rcb_list as the "next" field.
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
#define rcb_list list
|
||||
#endif /* __FreeBSD__ */
|
||||
#ifdef __NetBSD__
|
||||
#define rawcb_list rawcb
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
|
||||
/*
|
||||
* 10. List of all known network interfaces.
|
||||
* FreeBSD has listhead in_ifaddread, with ia_link as link.
|
||||
* NetBSD has listhead in_ifaddr, with ia_list as link.
|
||||
* No name-clahses, so just #define the appropriate names on NetBSD.
|
||||
* NB: Is it worth introducing iterator (find-first-list/find-next-list)
|
||||
* functions or macros to encapsulate these?
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
/* nothing to do for raw interface list */
|
||||
#endif /* FreeBSD */
|
||||
#ifdef __NetBSD__
|
||||
/* For now, use FreeBSD-compatible names for raw interface list. */
|
||||
#define in_ifaddrhead in_ifaddr
|
||||
#define ia_link ia_list
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Differences that we don't attempt to hide:
|
||||
*
|
||||
* A. Initialization code. This is the largest difference of all.
|
||||
*
|
||||
* FreeBSD uses compile/link-time perl hackery to generate special
|
||||
* .o files with linker sections that give the moral equivalent of
|
||||
* C++ file-level-object constructors. NetBSD has no such facility.
|
||||
*
|
||||
* Either we implement it (ideally, in a way that can emulate
|
||||
* FreeBSD's SYSINIT() macros), or we must take other means
|
||||
* to have the per-file init functions called at some appropriate time.
|
||||
*
|
||||
* In the absence of SYSINIT(), all the file-level init functions
|
||||
* now have "extern" linkage. There is a new fast-ipsec init()
|
||||
* function which calls each of the per-file in an appropriate order.
|
||||
* init_main will arrange to call the fast-ipsec init function
|
||||
* after the crypto framework has registered its transforms (including
|
||||
* any autoconfigured hardware crypto accelerators) but before
|
||||
* initializing the network stack to send or receive packet.
|
||||
*
|
||||
* B. Protosw() differences.
|
||||
* CSRG-style BSD TCP/IP uses a generic protocol-dispatch-function
|
||||
* where the specific request is identified by an enum argument.
|
||||
* FreeBSD replaced that with an array of request-specific
|
||||
* function pointers.
|
||||
*
|
||||
* These differences affect the handlers for key-protocol user requests
|
||||
* so pervasively that I gave up on the fast-ipsec code, and re-worked the
|
||||
* NetBSD KAME code to match the (relative few) API differences
|
||||
* between NetBSD and FreeBSD's KAME netkey, and Fast-IPsec netkey.
|
||||
*
|
||||
* C. Timeout() versus callout(9):
|
||||
* The FreeBSD 4.x netipsec/ code still uses timeout().
|
||||
* FreeBSD 4.7 has callout(9), so I just replaced
|
||||
* timeout_*() with the nearest callout_*() equivalents,
|
||||
* and added a callout handle to the ipsec context.
|
||||
*
|
||||
* D. SPL name differences.
|
||||
* FreeBSD splnet() equates directly to NetBSD's splsoftnet();
|
||||
* FreeBSD uses splimp() where (for networking) NetBSD would use splnet().
|
||||
*/
|
||||
#endif NETIPSEC_OSDEP_H
|
||||
|
|
@ -0,0 +1,738 @@
|
|||
/* $NetBSD: ipsec_output.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/ipsec_output.c,v 1.3.2.1 2003/01/24 05:11:35 sam Exp $ */
|
||||
/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $");
|
||||
|
||||
/*
|
||||
* IPsec output processing.
|
||||
*/
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_ipsec.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/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/ip_var.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip_ecn.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ip6_ecn.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/ip6.h>
|
||||
#ifdef INET6
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
#include <netinet/in_pcb.h>
|
||||
#ifdef INET6
|
||||
#include <netinet/icmp6.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/ipsec.h>
|
||||
#ifdef INET6
|
||||
#include <netipsec/ipsec6.h>
|
||||
#endif
|
||||
#include <netipsec/ah_var.h>
|
||||
#include <netipsec/esp_var.h>
|
||||
#include <netipsec/ipcomp_var.h>
|
||||
|
||||
#include <netipsec/xform.h>
|
||||
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/keydb.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
|
||||
int
|
||||
ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
|
||||
{
|
||||
struct tdb_ident *tdbi;
|
||||
struct m_tag *mtag;
|
||||
struct secasvar *sav;
|
||||
struct secasindex *saidx;
|
||||
int error;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
|
||||
|
||||
IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
|
||||
IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
|
||||
sav = isr->sav;
|
||||
IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
|
||||
IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
|
||||
|
||||
saidx = &sav->sah->saidx;
|
||||
switch (saidx->dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
/* Fix the header length, for AH processing. */
|
||||
mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
/* Fix the header length, for AH processing. */
|
||||
if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
|
||||
error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
|
||||
/* No jumbogram support. */
|
||||
error = ENXIO; /*?*/
|
||||
goto bad;
|
||||
}
|
||||
mtod(m, struct ip6_hdr *)->ip6_plen =
|
||||
htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
|
||||
saidx->dst.sa.sa_family));
|
||||
error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a record of what we've done or what needs to be done to the
|
||||
* packet.
|
||||
*/
|
||||
mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
|
||||
sizeof(struct tdb_ident), M_NOWAIT);
|
||||
if (mtag == NULL) {
|
||||
DPRINTF(("ipsec_process_done: could not get packet tag\n"));
|
||||
error = ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
tdbi = (struct tdb_ident *)(mtag + 1);
|
||||
tdbi->dst = saidx->dst;
|
||||
tdbi->proto = saidx->proto;
|
||||
tdbi->spi = sav->spi;
|
||||
m_tag_prepend(m, mtag);
|
||||
|
||||
/*
|
||||
* If there's another (bundled) SA to apply, do so.
|
||||
* Note that this puts a burden on the kernel stack size.
|
||||
* If this is a problem we'll need to introduce a queue
|
||||
* to set the packet on so we can unwind the stack before
|
||||
* doing further processing.
|
||||
*/
|
||||
if (isr->next) {
|
||||
newipsecstat.ips_out_bundlesa++;
|
||||
return ipsec4_process_packet(m, isr->next, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We're done with IPsec processing, transmit the packet using the
|
||||
* appropriate network protocol (IP or IPv6). SPD lookup will be
|
||||
* performed again there.
|
||||
*/
|
||||
switch (saidx->dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
struct ip *ip;
|
||||
case AF_INET:
|
||||
ip = mtod(m, struct ip *);
|
||||
#ifdef __FreeBSD__
|
||||
/* FreeBSD ip_output() expects ip_len, ip_off in host endian */
|
||||
ip->ip_len = ntohs(ip->ip_len);
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
#endif /* __FreeBSD_ */
|
||||
return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
/*
|
||||
* We don't need massage, IPv6 header fields are always in
|
||||
* net endian.
|
||||
*/
|
||||
return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
|
||||
#endif /* INET6 */
|
||||
}
|
||||
panic("ipsec_process_done");
|
||||
bad:
|
||||
m_freem(m);
|
||||
KEY_FREESAV(&sav);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static struct ipsecrequest *
|
||||
ipsec_nextisr(
|
||||
struct mbuf *m,
|
||||
struct ipsecrequest *isr,
|
||||
int af,
|
||||
struct secasindex *saidx,
|
||||
int *error
|
||||
)
|
||||
{
|
||||
#define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \
|
||||
isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++)
|
||||
struct secasvar *sav;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
|
||||
IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
|
||||
("ipsec_nextisr: invalid address family %u", af));
|
||||
again:
|
||||
/*
|
||||
* Craft SA index to search for proper SA. Note that
|
||||
* we only fillin unspecified SA peers for transport
|
||||
* mode; for tunnel mode they must already be filled in.
|
||||
*/
|
||||
*saidx = isr->saidx;
|
||||
if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
|
||||
/* Fillin unspecified SA peers only for transport mode */
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in *sin;
|
||||
struct ip *ip = mtod(m, struct ip *);
|
||||
|
||||
if (saidx->src.sa.sa_len == 0) {
|
||||
sin = &saidx->src.sin;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_port = IPSEC_PORT_ANY;
|
||||
sin->sin_addr = ip->ip_src;
|
||||
}
|
||||
if (saidx->dst.sa.sa_len == 0) {
|
||||
sin = &saidx->dst.sin;
|
||||
sin->sin_len = sizeof(*sin);
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_port = IPSEC_PORT_ANY;
|
||||
sin->sin_addr = ip->ip_dst;
|
||||
}
|
||||
} else {
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
||||
|
||||
if (saidx->src.sin6.sin6_len == 0) {
|
||||
sin6 = (struct sockaddr_in6 *)&saidx->src;
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_port = IPSEC_PORT_ANY;
|
||||
sin6->sin6_addr = ip6->ip6_src;
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
|
||||
/* fix scope id for comparing SPD */
|
||||
sin6->sin6_addr.s6_addr16[1] = 0;
|
||||
sin6->sin6_scope_id =
|
||||
ntohs(ip6->ip6_src.s6_addr16[1]);
|
||||
}
|
||||
}
|
||||
if (saidx->dst.sin6.sin6_len == 0) {
|
||||
sin6 = (struct sockaddr_in6 *)&saidx->dst;
|
||||
sin6->sin6_len = sizeof(*sin6);
|
||||
sin6->sin6_family = AF_INET6;
|
||||
sin6->sin6_port = IPSEC_PORT_ANY;
|
||||
sin6->sin6_addr = ip6->ip6_dst;
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
|
||||
/* fix scope id for comparing SPD */
|
||||
sin6->sin6_addr.s6_addr16[1] = 0;
|
||||
sin6->sin6_scope_id =
|
||||
ntohs(ip6->ip6_dst.s6_addr16[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup SA and validate it.
|
||||
*/
|
||||
*error = key_checkrequest(isr, saidx);
|
||||
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.
|
||||
*/
|
||||
newipsecstat.ips_out_nosa++;
|
||||
goto bad;
|
||||
}
|
||||
sav = isr->sav;
|
||||
if (sav == NULL) { /* XXX valid return */
|
||||
IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
|
||||
("ipsec_nextisr: no SA found, but required; level %u",
|
||||
ipsec_get_reqlevel(isr)));
|
||||
isr = isr->next;
|
||||
if (isr == NULL) {
|
||||
/*XXXstatistic??*/
|
||||
*error = EINVAL; /*XXX*/
|
||||
return isr;
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check system global policy controls.
|
||||
*/
|
||||
if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
|
||||
(isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
|
||||
(isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
|
||||
DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
|
||||
" to policy (check your sysctls)\n"));
|
||||
IPSEC_OSTAT(espstat.esps_pdrops, ahstat.ahs_pdrops,
|
||||
ipcompstat.ipcomps_pdrops);
|
||||
*error = EHOSTUNREACH;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity check the SA contents for the caller
|
||||
* before they invoke the xform output method.
|
||||
*/
|
||||
if (sav->tdb_xform == NULL) {
|
||||
DPRINTF(("ipsec_nextisr: no transform for SA\n"));
|
||||
IPSEC_OSTAT(espstat.esps_noxform, ahstat.ahs_noxform,
|
||||
ipcompstat.ipcomps_noxform);
|
||||
*error = EHOSTUNREACH;
|
||||
goto bad;
|
||||
}
|
||||
return isr;
|
||||
bad:
|
||||
IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
|
||||
return NULL;
|
||||
#undef IPSEC_OSTAT
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
/*
|
||||
* IPsec output logic for IPv4.
|
||||
*/
|
||||
int
|
||||
ipsec4_process_packet(
|
||||
struct mbuf *m,
|
||||
struct ipsecrequest *isr,
|
||||
int flags,
|
||||
int tunalready)
|
||||
{
|
||||
struct secasindex saidx;
|
||||
struct secasvar *sav;
|
||||
struct ip *ip;
|
||||
int s, error, i, off;
|
||||
|
||||
IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
|
||||
IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
|
||||
|
||||
s = splsoftnet(); /* insure SA contents don't change */
|
||||
|
||||
isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
|
||||
if (isr == NULL)
|
||||
goto bad;
|
||||
|
||||
sav = isr->sav;
|
||||
if (!tunalready) {
|
||||
union sockaddr_union *dst = &sav->sah->saidx.dst;
|
||||
int setdf;
|
||||
|
||||
/*
|
||||
* Collect IP_DF state from the outer header.
|
||||
*/
|
||||
if (dst->sa.sa_family == AF_INET) {
|
||||
if (m->m_len < sizeof (struct ip) &&
|
||||
(m = m_pullup(m, sizeof (struct ip))) == NULL) {
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
/* Honor system-wide control of how to handle IP_DF */
|
||||
switch (ip4_ipsec_dfbit) {
|
||||
case 0: /* clear in outer header */
|
||||
case 1: /* set in outer header */
|
||||
setdf = ip4_ipsec_dfbit;
|
||||
break;
|
||||
default: /* propagate to outer header */
|
||||
setdf = ntohs(ip->ip_off & IP_DF);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ip = NULL; /* keep compiler happy */
|
||||
setdf = 0;
|
||||
}
|
||||
/* Do the appropriate encapsulation, if necessary */
|
||||
if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
|
||||
dst->sa.sa_family != AF_INET || /* PF mismatch */
|
||||
#if 0
|
||||
(sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
|
||||
sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
|
||||
#endif
|
||||
(dst->sa.sa_family == AF_INET && /* Proxy */
|
||||
dst->sin.sin_addr.s_addr != INADDR_ANY &&
|
||||
dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
|
||||
struct mbuf *mp;
|
||||
|
||||
/* Fix IPv4 header checksum and length */
|
||||
if (m->m_len < sizeof (struct ip) &&
|
||||
(m = m_pullup(m, sizeof (struct ip))) == NULL) {
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
ip->ip_len = htons(m->m_pkthdr.len);
|
||||
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,
|
||||
_IP_VHL_HL(ip->ip_vhl) << 2);
|
||||
#else
|
||||
ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
|
||||
#endif
|
||||
|
||||
/* Encapsulate the packet */
|
||||
error = ipip_output(m, isr, &mp, 0, 0);
|
||||
if (mp == NULL && !error) {
|
||||
/* Should never happen. */
|
||||
DPRINTF(("ipsec4_process_packet: ipip_output "
|
||||
"returns no mbuf and no error!"));
|
||||
error = EFAULT;
|
||||
}
|
||||
if (error) {
|
||||
if (mp)
|
||||
m_freem(mp);
|
||||
goto bad;
|
||||
}
|
||||
m = mp, mp = NULL;
|
||||
/*
|
||||
* ipip_output clears IP_DF in the new header. If
|
||||
* we need to propagate IP_DF from the outer header,
|
||||
* then we have to do it here.
|
||||
*
|
||||
* XXX shouldn't assume what ipip_output does.
|
||||
*/
|
||||
if (dst->sa.sa_family == AF_INET && setdf) {
|
||||
if (m->m_len < sizeof (struct ip) &&
|
||||
(m = m_pullup(m, sizeof (struct ip))) == NULL) {
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
ip->ip_off |= IP_DF;
|
||||
ip->ip_off = htons(ip->ip_off);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch to the appropriate IPsec transform logic. The
|
||||
* packet will be returned for transmission after crypto
|
||||
* processing, etc. are completed. For encapsulation we
|
||||
* bypass this call because of the explicit call done above
|
||||
* (necessary to deal with IP_DF handling for IPv4).
|
||||
*
|
||||
* NB: m & sav are ``passed to caller'' who's reponsible for
|
||||
* for reclaiming their resources.
|
||||
*/
|
||||
if (sav->tdb_xform->xf_type != XF_IP4) {
|
||||
ip = mtod(m, struct ip *);
|
||||
i = ip->ip_hl << 2;
|
||||
off = offsetof(struct ip, ip_p);
|
||||
error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
|
||||
} else {
|
||||
error = ipsec_process_done(m, isr);
|
||||
}
|
||||
splx(s);
|
||||
return error;
|
||||
bad:
|
||||
splx(s);
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
/*
|
||||
* Chop IP6 header from the payload.
|
||||
*/
|
||||
static struct mbuf *
|
||||
ipsec6_splithdr(struct mbuf *m)
|
||||
{
|
||||
struct mbuf *mh;
|
||||
struct ip6_hdr *ip6;
|
||||
int hlen;
|
||||
|
||||
IPSEC_ASSERT(m->m_len >= sizeof (struct ip6_hdr),
|
||||
("ipsec6_splithdr: first mbuf too short, len %u", m->m_len));
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* IPsec output logic for IPv6, transport mode.
|
||||
*/
|
||||
int
|
||||
ipsec6_output_trans(
|
||||
struct ipsec_output_state *state,
|
||||
u_char *nexthdrp,
|
||||
struct mbuf *mprev,
|
||||
struct secpolicy *sp,
|
||||
int flags,
|
||||
int *tun)
|
||||
{
|
||||
struct ipsecrequest *isr;
|
||||
struct secasindex saidx;
|
||||
int error = 0;
|
||||
struct mbuf *m;
|
||||
|
||||
IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state"));
|
||||
IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m"));
|
||||
IPSEC_ASSERT(nexthdrp != NULL, ("ipsec6_output: null nexthdrp"));
|
||||
IPSEC_ASSERT(mprev != NULL, ("ipsec6_output: null mprev"));
|
||||
IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp"));
|
||||
IPSEC_ASSERT(tun != NULL, ("ipsec6_output: null tun"));
|
||||
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
||||
printf("ipsec6_output_trans: applyed SP\n");
|
||||
kdebug_secpolicy(sp));
|
||||
|
||||
isr = sp->req;
|
||||
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
||||
/* the rest will be handled by ipsec6_output_tunnel() */
|
||||
*tun = 1; /* need tunnel-mode processing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
*tun = 0;
|
||||
m = state->m;
|
||||
|
||||
isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
|
||||
if (isr == NULL) {
|
||||
#ifdef notdef
|
||||
/* XXX should notification be done for all errors ? */
|
||||
/*
|
||||
* 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?
|
||||
*/
|
||||
icmp6_error(m, ICMP6_DST_UNREACH,
|
||||
ICMP6_DST_UNREACH_ADMIN, 0);
|
||||
m = NULL; /* NB: icmp6_error frees mbuf */
|
||||
#endif
|
||||
goto bad;
|
||||
}
|
||||
|
||||
return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
|
||||
sizeof (struct ip6_hdr),
|
||||
offsetof(struct ip6_hdr, ip6_nxt));
|
||||
bad:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
state->m = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav)
|
||||
{
|
||||
struct ip6_hdr *oip6;
|
||||
struct ip6_hdr *ip6;
|
||||
size_t plen;
|
||||
|
||||
/* can't tunnel between different AFs */
|
||||
if (sav->sah->saidx.src.sa.sa_family != AF_INET6 ||
|
||||
sav->sah->saidx.dst.sa.sa_family != AF_INET6) {
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
IPSEC_ASSERT(m->m_len != sizeof (struct ip6_hdr),
|
||||
("ipsec6_encapsulate: mbuf wrong size; len %u", m->m_len));
|
||||
|
||||
|
||||
/*
|
||||
* grow the mbuf to accomodate the new IPv6 header.
|
||||
*/
|
||||
plen = m->m_pkthdr.len;
|
||||
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));
|
||||
|
||||
/* Fake link-local scope-class addresses */
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
|
||||
oip6->ip6_src.s6_addr16[1] = 0;
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
|
||||
oip6->ip6_dst.s6_addr16[1] = 0;
|
||||
|
||||
/* 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;
|
||||
sav->sah->saidx.src.sin6.sin6_addr = ip6->ip6_src;
|
||||
sav->sah->saidx.dst.sin6.sin6_addr = ip6->ip6_dst;
|
||||
ip6->ip6_hlim = IPV6_DEFHLIM;
|
||||
|
||||
/* XXX Should ip6_src be updated later ? */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* IPsec output logic for IPv6, tunnel mode.
|
||||
*/
|
||||
int
|
||||
ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int flags)
|
||||
{
|
||||
struct ip6_hdr *ip6;
|
||||
struct ipsecrequest *isr;
|
||||
struct secasindex saidx;
|
||||
int error;
|
||||
struct sockaddr_in6* dst6;
|
||||
struct mbuf *m;
|
||||
|
||||
IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state"));
|
||||
IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m"));
|
||||
IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp"));
|
||||
|
||||
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
||||
printf("ipsec6_output_tunnel: applyed SP\n");
|
||||
kdebug_secpolicy(sp));
|
||||
|
||||
m = state->m;
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
|
||||
if (isr == NULL)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* There may be the case that SA status will be changed when
|
||||
* we are refering to one. So calling splsoftnet().
|
||||
*/
|
||||
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
||||
/*
|
||||
* build IPsec tunnel.
|
||||
*/
|
||||
/* XXX should be processed with other familiy */
|
||||
if (isr->sav->sah->saidx.src.sa.sa_family != AF_INET6) {
|
||||
ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
|
||||
"family mismatched between inner and outer, spi=%lu\n",
|
||||
ntohl(isr->sav->spi)));
|
||||
newipsecstat.ips_out_inval++;
|
||||
error = EAFNOSUPPORT;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
m = ipsec6_splithdr(m);
|
||||
if (!m) {
|
||||
newipsecstat.ips_out_nomem++;
|
||||
error = ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
error = ipsec6_encapsulate(m, isr->sav);
|
||||
if (error) {
|
||||
m = NULL;
|
||||
goto bad;
|
||||
}
|
||||
ip6 = mtod(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) == 0
|
||||
|| !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++;
|
||||
newipsecstat.ips_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;
|
||||
}
|
||||
}
|
||||
|
||||
m = ipsec6_splithdr(m);
|
||||
if (!m) {
|
||||
newipsecstat.ips_out_nomem++;
|
||||
error = ENOMEM;
|
||||
goto bad;
|
||||
}
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
|
||||
sizeof (struct ip6_hdr),
|
||||
offsetof(struct ip6_hdr, ip6_nxt));
|
||||
bad:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
state->m = NULL;
|
||||
return error;
|
||||
}
|
||||
#endif /*INET6*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,115 @@
|
|||
/* $NetBSD: key.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/key.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: key.h,v 1.21 2001/07/27 03:51:30 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_KEY_H_
|
||||
#define _NETIPSEC_KEY_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
struct secpolicy;
|
||||
struct secpolicyindex;
|
||||
struct ipsecrequest;
|
||||
struct secasvar;
|
||||
struct sockaddr;
|
||||
struct socket;
|
||||
struct sadb_msg;
|
||||
struct sadb_x_policy;
|
||||
struct secasindex;
|
||||
union sockaddr_union;
|
||||
|
||||
extern int key_havesp(u_int dir);
|
||||
extern struct secpolicy *key_allocsp(struct secpolicyindex *, u_int,
|
||||
const char*, int);
|
||||
extern struct secpolicy *key_allocsp2(u_int32_t spi, union sockaddr_union *dst,
|
||||
u_int8_t proto, u_int dir, const char*, int);
|
||||
extern struct secpolicy *key_newsp(const char*, int);
|
||||
extern struct secpolicy *key_gettunnel(const struct sockaddr *,
|
||||
const struct sockaddr *, const struct sockaddr *,
|
||||
const struct sockaddr *, const char*, int);
|
||||
/* NB: prepend with _ for KAME IPv6 compatbility */
|
||||
extern void _key_freesp(struct secpolicy **, const char*, int);
|
||||
|
||||
/*
|
||||
* Access to the SADB are interlocked with splsoftnet. In particular,
|
||||
* holders of SA's use this to block accesses by protocol processing
|
||||
* that can happen either by network swi's or by continuations that
|
||||
* occur on crypto callbacks. Much of this could go away if
|
||||
* key_checkrequest were redone.
|
||||
*/
|
||||
#define KEY_ALLOCSP(spidx, dir) \
|
||||
key_allocsp(spidx, dir, __FILE__, __LINE__)
|
||||
#define KEY_ALLOCSP2(spi, dst, proto, dir) \
|
||||
key_allocsp2(spi, dst, proto, dir, __FILE__, __LINE__)
|
||||
#define KEY_NEWSP() \
|
||||
key_newsp(__FILE__, __LINE__)
|
||||
#define KEY_GETTUNNEL(osrc, odst, isrc, idst) \
|
||||
key_gettunnel(osrc, odst, isrc, idst, __FILE__, __LINE__)
|
||||
#define KEY_FREESP(spp) \
|
||||
_key_freesp(spp, __FILE__, __LINE__)
|
||||
|
||||
extern struct secasvar *key_allocsa(union sockaddr_union *, u_int, u_int32_t,
|
||||
const char*, int);
|
||||
extern void key_freesav(struct secasvar **, const char*, int);
|
||||
|
||||
#define KEY_ALLOCSA(dst, proto, spi) \
|
||||
key_allocsa(dst, proto, spi, __FILE__, __LINE__)
|
||||
#define KEY_FREESAV(psav) \
|
||||
key_freesav(psav, __FILE__, __LINE__)
|
||||
|
||||
extern void key_freeso __P((struct socket *));
|
||||
extern int key_checktunnelsanity __P((struct secasvar *, u_int,
|
||||
caddr_t, caddr_t));
|
||||
extern int key_checkrequest
|
||||
__P((struct ipsecrequest *isr, const struct secasindex *));
|
||||
|
||||
extern struct secpolicy *key_msg2sp __P((struct sadb_x_policy *,
|
||||
size_t, int *));
|
||||
extern struct mbuf *key_sp2msg __P((struct secpolicy *));
|
||||
extern int key_ismyaddr __P((struct sockaddr *));
|
||||
extern int key_spdacquire __P((struct secpolicy *));
|
||||
extern void key_timehandler __P((void*));
|
||||
extern u_long key_random __P((void));
|
||||
extern void key_randomfill __P((void *, size_t));
|
||||
extern void key_freereg __P((struct socket *));
|
||||
extern int key_parse __P((struct mbuf *, struct socket *));
|
||||
extern void key_init __P((void));
|
||||
extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *));
|
||||
extern void key_sa_routechange __P((struct sockaddr *));
|
||||
extern void key_sa_stir_iv __P((struct secasvar *));
|
||||
|
||||
#ifdef MALLOC_DECLARE
|
||||
MALLOC_DECLARE(M_SECA);
|
||||
#endif /* MALLOC_DECLARE */
|
||||
|
||||
#endif /* defined(_KERNEL) */
|
||||
#endif /* _NETIPSEC_KEY_H_ */
|
|
@ -0,0 +1,753 @@
|
|||
/* $NetBSD: key_debug.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/key_debug.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: key_debug.c,v 1.26 2001/06/27 10:46:50 sakane 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.
|
||||
*/
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: key_debug.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $");
|
||||
#endif
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#include "opt_ipsec.h"
|
||||
|
||||
#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 <netipsec/key_var.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netipsec/ipsec.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif /* !_KERNEL */
|
||||
|
||||
static void kdebug_sadb_prop __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_identity __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_supported __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_lifetime __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_sa __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_address __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_key __P((struct sadb_ext *));
|
||||
static void kdebug_sadb_x_sa2 __P((struct sadb_ext *));
|
||||
|
||||
#ifdef _KERNEL
|
||||
static void kdebug_secreplay __P((struct secreplay *));
|
||||
#endif
|
||||
|
||||
#ifndef _KERNEL
|
||||
#define panic(param) { printf(param); exit(-1); }
|
||||
#endif
|
||||
|
||||
/* 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.\n");
|
||||
|
||||
printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n",
|
||||
base->sadb_msg_version, 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=%u }\n",
|
||||
ext->sadb_ext_len, 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.\n");
|
||||
|
||||
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.\n");
|
||||
|
||||
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=%d 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.\n");
|
||||
|
||||
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=%d ivlen=%d min=%d max=%d }\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.\n");
|
||||
|
||||
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.\n");
|
||||
|
||||
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.\n");
|
||||
|
||||
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:%d 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.\n");
|
||||
|
||||
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.\n");
|
||||
|
||||
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.\n");
|
||||
}
|
||||
|
||||
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.\n");
|
||||
|
||||
printf("secpolicy{ refcnt=%u state=%u policy=%u\n",
|
||||
sp->refcnt, sp->state, sp->policy);
|
||||
|
||||
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. %d\n",
|
||||
sp->policy);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
kdebug_secpolicyindex(spidx)
|
||||
struct secpolicyindex *spidx;
|
||||
{
|
||||
/* sanity check */
|
||||
if (spidx == NULL)
|
||||
panic("kdebug_secpolicyindex: NULL pointer was passed.\n");
|
||||
|
||||
printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n",
|
||||
spidx->dir, 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.\n");
|
||||
|
||||
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.\n");
|
||||
|
||||
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);
|
||||
|
||||
#if 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.\n");
|
||||
|
||||
printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u",
|
||||
rpl->count, rpl->wsize, rpl->seq, 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) {
|
||||
#ifdef __FreeBSD__ /* mbuf differences */
|
||||
printf(" m_ext{ ext_buf:%p ext_free:%p "
|
||||
"ext_size:%u ext_ref:%p }\n",
|
||||
m->m_ext.ext_buf, m->m_ext.ext_free,
|
||||
m->m_ext.ext_size, m->m_ext.ext_ref);
|
||||
#endif __FreeBSD__
|
||||
}
|
||||
|
||||
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.\n");
|
||||
|
||||
/* 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;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/* $NetBSD: key_debug.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/key_debug.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: key_debug.h,v 1.10 2001/08/05 08:37:52 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_KEY_DEBUG_H_
|
||||
#define _NETIPSEC_KEY_DEBUG_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* debug flags */
|
||||
#define KEYDEBUG_STAMP 0x00000001 /* path */
|
||||
#define KEYDEBUG_DATA 0x00000002 /* data */
|
||||
#define KEYDEBUG_DUMP 0x00000004 /* dump */
|
||||
|
||||
#define KEYDEBUG_KEY 0x00000010 /* key processing */
|
||||
#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */
|
||||
#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */
|
||||
|
||||
#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP)
|
||||
#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA)
|
||||
#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP)
|
||||
#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP)
|
||||
#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA)
|
||||
#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP)
|
||||
#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP)
|
||||
#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA)
|
||||
#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP)
|
||||
|
||||
#define KEYDEBUG(lev,arg) \
|
||||
do { if ((key_debug_level & (lev)) == (lev)) { arg; } } while (/*CONSTCOND*/ 0)
|
||||
|
||||
extern u_int32_t key_debug_level;
|
||||
#endif /*_KERNEL*/
|
||||
|
||||
struct sadb_msg;
|
||||
struct sadb_ext;
|
||||
extern void kdebug_sadb __P((struct sadb_msg *));
|
||||
extern void kdebug_sadb_x_policy __P((struct sadb_ext *));
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct secpolicy;
|
||||
struct secpolicyindex;
|
||||
struct secasindex;
|
||||
struct secasvar;
|
||||
struct secreplay;
|
||||
struct mbuf;
|
||||
extern void kdebug_secpolicy __P((struct secpolicy *));
|
||||
extern void kdebug_secpolicyindex __P((struct secpolicyindex *));
|
||||
extern void kdebug_secasindex __P((struct secasindex *));
|
||||
extern void kdebug_secasv __P((struct secasvar *));
|
||||
extern void kdebug_mbufhdr __P((struct mbuf *));
|
||||
extern void kdebug_mbuf __P((struct mbuf *));
|
||||
#endif /*_KERNEL*/
|
||||
|
||||
struct sockaddr;
|
||||
extern void kdebug_sockaddr __P((struct sockaddr *));
|
||||
|
||||
extern void ipsec_hexdump __P((caddr_t, int));
|
||||
extern void ipsec_bindump __P((caddr_t, int));
|
||||
|
||||
#endif /* _NETIPSEC_KEY_DEBUG_H_ */
|
|
@ -0,0 +1,91 @@
|
|||
/* $NetBSD: key_var.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/key_var.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: key_var.h,v 1.11 2001/09/12 23:05:07 sakane 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_KEY_VAR_H_
|
||||
#define _NETIPSEC_KEY_VAR_H_
|
||||
|
||||
/* sysctl */
|
||||
#define KEYCTL_DEBUG_LEVEL 1
|
||||
#define KEYCTL_SPI_TRY 2
|
||||
#define KEYCTL_SPI_MIN_VALUE 3
|
||||
#define KEYCTL_SPI_MAX_VALUE 4
|
||||
#define KEYCTL_RANDOM_INT 5
|
||||
#define KEYCTL_LARVAL_LIFETIME 6
|
||||
#define KEYCTL_BLOCKACQ_COUNT 7
|
||||
#define KEYCTL_BLOCKACQ_LIFETIME 8
|
||||
#define KEYCTL_ESP_KEYMIN 9
|
||||
#define KEYCTL_ESP_AUTH 10
|
||||
#define KEYCTL_AH_KEYMIN 11
|
||||
#define KEYCTL_PREFERED_OLDSA 12
|
||||
#define KEYCTL_MAXID 13
|
||||
|
||||
#define KEYCTL_NAMES { \
|
||||
{ 0, 0 }, \
|
||||
{ "debug", CTLTYPE_INT }, \
|
||||
{ "spi_try", CTLTYPE_INT }, \
|
||||
{ "spi_min_value", CTLTYPE_INT }, \
|
||||
{ "spi_max_value", CTLTYPE_INT }, \
|
||||
{ "random_int", CTLTYPE_INT }, \
|
||||
{ "larval_lifetime", CTLTYPE_INT }, \
|
||||
{ "blockacq_count", CTLTYPE_INT }, \
|
||||
{ "blockacq_lifetime", CTLTYPE_INT }, \
|
||||
{ "esp_keymin", CTLTYPE_INT }, \
|
||||
{ "esp_auth", CTLTYPE_INT }, \
|
||||
{ "ah_keymin", CTLTYPE_INT }, \
|
||||
{ "prefered_oldsa", CTLTYPE_INT }, \
|
||||
}
|
||||
|
||||
#define KEYCTL_VARS { \
|
||||
0, \
|
||||
0, \
|
||||
&key_spi_trycnt, \
|
||||
&key_spi_minval, \
|
||||
&key_spi_maxval, \
|
||||
&key_int_random, \
|
||||
&key_larval_lifetime, \
|
||||
&key_blockacq_count, \
|
||||
&key_blockacq_lifetime, \
|
||||
&ipsec_esp_keymin, \
|
||||
&ipsec_esp_auth, \
|
||||
&ipsec_ah_keymin, \
|
||||
&key_prefered_oldsa, \
|
||||
}
|
||||
|
||||
#ifdef _KERNEL
|
||||
#define _ARRAYLEN(p) (sizeof(p)/sizeof(p[0]))
|
||||
#define _KEYLEN(key) ((u_int)((key)->sadb_key_bits >> 3))
|
||||
#define _KEYBITS(key) ((u_int)((key)->sadb_key_bits))
|
||||
#define _KEYBUF(key) ((u_int8_t *)((u_int8_t*)(key) + sizeof(struct sadb_key)))
|
||||
#endif /*_KERNEL*/
|
||||
|
||||
#endif /* _NETIPSEC_KEY_VAR_H_ */
|
|
@ -0,0 +1,184 @@
|
|||
/* $NetBSD: keydb.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/keydb.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_KEYDB_H_
|
||||
#define _NETIPSEC_KEYDB_H_
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <netipsec/key_var.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/*
|
||||
* The union of all possible address formats we handle.
|
||||
*/
|
||||
union sockaddr_union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
};
|
||||
|
||||
/* Security Assocciation Index */
|
||||
/* NOTE: Ensure to be same address family */
|
||||
struct secasindex {
|
||||
union sockaddr_union src; /* srouce address for SA */
|
||||
union sockaddr_union dst; /* destination address for SA */
|
||||
u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */
|
||||
u_int8_t mode; /* mode of protocol, see ipsec.h */
|
||||
u_int32_t reqid; /* reqid id who owned this SA */
|
||||
/* see IPSEC_MANUAL_REQID_MAX. */
|
||||
};
|
||||
|
||||
/* Security Association Data Base */
|
||||
struct secashead {
|
||||
LIST_ENTRY(secashead) chain;
|
||||
|
||||
struct secasindex saidx;
|
||||
|
||||
struct sadb_ident *idents; /* source identity */
|
||||
struct sadb_ident *identd; /* destination identity */
|
||||
/* XXX I don't know how to use them. */
|
||||
|
||||
u_int8_t state; /* MATURE or DEAD. */
|
||||
LIST_HEAD(_satree, secasvar) savtree[SADB_SASTATE_MAX+1];
|
||||
/* SA chain */
|
||||
/* The first of this list is newer SA */
|
||||
|
||||
struct route sa_route; /* route cache */
|
||||
};
|
||||
|
||||
struct xformsw;
|
||||
struct enc_xform;
|
||||
struct auth_hash;
|
||||
struct comp_algo;
|
||||
|
||||
/* Security Association */
|
||||
struct secasvar {
|
||||
LIST_ENTRY(secasvar) chain;
|
||||
|
||||
u_int refcnt; /* reference count */
|
||||
u_int8_t state; /* Status of this Association */
|
||||
|
||||
u_int8_t alg_auth; /* Authentication Algorithm Identifier*/
|
||||
u_int8_t alg_enc; /* Cipher Algorithm Identifier */
|
||||
u_int8_t alg_comp; /* Compression Algorithm Identifier */
|
||||
u_int32_t spi; /* SPI Value, network byte order */
|
||||
u_int32_t flags; /* holder for SADB_KEY_FLAGS */
|
||||
|
||||
struct sadb_key *key_auth; /* Key for Authentication */
|
||||
struct sadb_key *key_enc; /* Key for Encryption */
|
||||
caddr_t iv; /* Initilization Vector */
|
||||
u_int ivlen; /* length of IV */
|
||||
void *sched; /* intermediate encryption key */
|
||||
size_t schedlen;
|
||||
|
||||
struct secreplay *replay; /* replay prevention */
|
||||
long created; /* for lifetime */
|
||||
|
||||
struct sadb_lifetime *lft_c; /* CURRENT lifetime, it's constant. */
|
||||
struct sadb_lifetime *lft_h; /* HARD lifetime */
|
||||
struct sadb_lifetime *lft_s; /* SOFT lifetime */
|
||||
|
||||
u_int32_t seq; /* sequence number */
|
||||
pid_t pid; /* message's pid */
|
||||
|
||||
struct secashead *sah; /* back pointer to the secashead */
|
||||
|
||||
/*
|
||||
* NB: Fields with a tdb_ prefix are part of the "glue" used
|
||||
* to interface to the OpenBSD crypto support. This was done
|
||||
* to distinguish this code from the mainline KAME code.
|
||||
*/
|
||||
struct xformsw *tdb_xform; /* transform */
|
||||
struct enc_xform *tdb_encalgxform; /* encoding algorithm */
|
||||
struct auth_hash *tdb_authalgxform; /* authentication algorithm */
|
||||
struct comp_algo *tdb_compalgxform; /* compression algorithm */
|
||||
u_int64_t tdb_cryptoid; /* crypto session id */
|
||||
};
|
||||
|
||||
/* replay prevention */
|
||||
struct secreplay {
|
||||
u_int32_t count;
|
||||
u_int wsize; /* window size, i.g. 4 bytes */
|
||||
u_int32_t seq; /* used by sender */
|
||||
u_int32_t lastseq; /* used by receiver */
|
||||
caddr_t bitmap; /* used by receiver */
|
||||
int overflow; /* overflow flag */
|
||||
};
|
||||
|
||||
/* socket table due to send PF_KEY messages. */
|
||||
struct secreg {
|
||||
LIST_ENTRY(secreg) chain;
|
||||
|
||||
struct socket *so;
|
||||
};
|
||||
|
||||
#ifndef IPSEC_NONBLOCK_ACQUIRE
|
||||
/* acquiring list table. */
|
||||
struct secacq {
|
||||
LIST_ENTRY(secacq) chain;
|
||||
|
||||
struct secasindex saidx;
|
||||
|
||||
u_int32_t seq; /* sequence number */
|
||||
long created; /* for lifetime */
|
||||
int count; /* for lifetime */
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Sensitivity Level Specification */
|
||||
/* nothing */
|
||||
|
||||
#define SADB_KILL_INTERVAL 600 /* six seconds */
|
||||
|
||||
/* secpolicy */
|
||||
extern struct secpolicy *keydb_newsecpolicy __P((void));
|
||||
extern void keydb_delsecpolicy __P((struct secpolicy *));
|
||||
/* secashead */
|
||||
extern struct secashead *keydb_newsecashead __P((void));
|
||||
extern void keydb_delsecashead __P((struct secashead *));
|
||||
/* secasvar */
|
||||
extern struct secasvar *keydb_newsecasvar __P((void));
|
||||
extern void keydb_refsecasvar __P((struct secasvar *));
|
||||
extern void keydb_freesecasvar __P((struct secasvar *));
|
||||
/* secreplay */
|
||||
extern struct secreplay *keydb_newsecreplay __P((size_t));
|
||||
extern void keydb_delsecreplay __P((struct secreplay *));
|
||||
/* secreg */
|
||||
extern struct secreg *keydb_newsecreg __P((void));
|
||||
extern void keydb_delsecreg __P((struct secreg *));
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _NETIPSEC_KEYDB_H_ */
|
|
@ -0,0 +1,695 @@
|
|||
/* $NetBSD: keysock.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/keysock.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: keysock.c,v 1.25 2001/08/13 20:07:41 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>
|
||||
__KERNEL_RCSID(0, "$NetBSD: keysock.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $");
|
||||
|
||||
#include "opt_ipsec.h"
|
||||
|
||||
/* This code has derived from sys/net/rtsock.c on FreeBSD2.2.5 */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.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 <net/pfkeyv2.h>
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/keysock.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
typedef int pr_output_t (struct mbuf *, struct socket *);
|
||||
|
||||
struct key_cb {
|
||||
int key_count;
|
||||
int any_count;
|
||||
};
|
||||
static struct key_cb key_cb;
|
||||
|
||||
static struct sockaddr key_dst = { 2, PF_KEY, };
|
||||
static struct sockaddr key_src = { 2, PF_KEY, };
|
||||
|
||||
static int key_sendup0 __P((struct rawcb *, struct mbuf *, int));
|
||||
|
||||
struct pfkeystat pfkeystat;
|
||||
|
||||
/*
|
||||
* key_output()
|
||||
*/
|
||||
int
|
||||
#if __STDC__
|
||||
key_output(struct mbuf *m, ...)
|
||||
#else
|
||||
key_output(m, va_alist)
|
||||
struct mbuf *m;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
struct sadb_msg *msg;
|
||||
int len, error = 0;
|
||||
int s;
|
||||
struct socket *so;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, m);
|
||||
so = va_arg(ap, struct socket *);
|
||||
va_end(ap);
|
||||
|
||||
if (m == 0)
|
||||
panic("key_output: NULL pointer was passed.\n");
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if ((m->m_flags & M_PKTHDR) == 0)
|
||||
panic("key_output: not M_PKTHDR ??");
|
||||
|
||||
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 = splsoftnet();
|
||||
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++;
|
||||
m_freem(m);
|
||||
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;
|
||||
}
|
||||
|
||||
/* XXX this interface should be obsoleted. */
|
||||
int
|
||||
key_sendup(so, msg, len, target)
|
||||
struct socket *so;
|
||||
struct sadb_msg *msg;
|
||||
u_int len;
|
||||
int target; /*target of the resulting message*/
|
||||
{
|
||||
struct mbuf *m, *n, *mprev;
|
||||
int tlen;
|
||||
|
||||
/* sanity check */
|
||||
if (so == 0 || msg == 0)
|
||||
panic("key_sendup: NULL pointer was passed.\n");
|
||||
|
||||
KEYDEBUG(KEYDEBUG_KEY_DUMP,
|
||||
printf("key_sendup: \n");
|
||||
kdebug_sadb(msg));
|
||||
|
||||
/*
|
||||
* we increment statistics here, just in case we have ENOBUFS
|
||||
* in this function.
|
||||
*/
|
||||
pfkeystat.in_total++;
|
||||
pfkeystat.in_bytes += len;
|
||||
pfkeystat.in_msgtype[msg->sadb_msg_type]++;
|
||||
|
||||
/*
|
||||
* Get mbuf chain whenever possible (not clusters),
|
||||
* to save socket buffer. We'll be generating many SADB_ACQUIRE
|
||||
* messages to listening key sockets. If we simply allocate clusters,
|
||||
* sbappendaddr() will raise ENOBUFS due to too little sbspace().
|
||||
* sbspace() computes # of actual data bytes AND mbuf region.
|
||||
*
|
||||
* TODO: SADB_ACQUIRE filters should be implemented.
|
||||
*/
|
||||
tlen = len;
|
||||
m = mprev = NULL;
|
||||
while (tlen > 0) {
|
||||
if (tlen == len) {
|
||||
MGETHDR(n, M_DONTWAIT, MT_DATA);
|
||||
n->m_len = MHLEN;
|
||||
} else {
|
||||
MGET(n, M_DONTWAIT, MT_DATA);
|
||||
n->m_len = MLEN;
|
||||
}
|
||||
if (!n) {
|
||||
pfkeystat.in_nomem++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
if (tlen >= MCLBYTES) { /*XXX better threshold? */
|
||||
MCLGET(n, M_DONTWAIT);
|
||||
if ((n->m_flags & M_EXT) == 0) {
|
||||
m_free(n);
|
||||
m_freem(m);
|
||||
pfkeystat.in_nomem++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
n->m_len = MCLBYTES;
|
||||
}
|
||||
|
||||
if (tlen < n->m_len)
|
||||
n->m_len = tlen;
|
||||
n->m_next = NULL;
|
||||
if (m == NULL)
|
||||
m = mprev = n;
|
||||
else {
|
||||
mprev->m_next = n;
|
||||
mprev = n;
|
||||
}
|
||||
tlen -= n->m_len;
|
||||
n = NULL;
|
||||
}
|
||||
m->m_pkthdr.len = len;
|
||||
m->m_pkthdr.rcvif = NULL;
|
||||
m_copyback(m, 0, len, (caddr_t)msg);
|
||||
|
||||
/* avoid duplicated statistics */
|
||||
pfkeystat.in_total--;
|
||||
pfkeystat.in_bytes -= len;
|
||||
pfkeystat.in_msgtype[msg->sadb_msg_type]--;
|
||||
|
||||
return key_sendup_mbuf(so, m, target);
|
||||
}
|
||||
|
||||
/* 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.\n");
|
||||
if (so == NULL && target == KEY_SENDUP_ONE)
|
||||
panic("key_sendup_mbuf: NULL pointer was passed.\n");
|
||||
|
||||
pfkeystat.in_total++;
|
||||
pfkeystat.in_bytes += m->m_pkthdr.len;
|
||||
if (m->m_len < sizeof(struct sadb_msg)) {
|
||||
#if 1
|
||||
m = m_pullup(m, sizeof(struct sadb_msg));
|
||||
if (m == NULL) {
|
||||
pfkeystat.in_nomem++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
#else
|
||||
/* don't bother pulling it up just for stats */
|
||||
#endif
|
||||
}
|
||||
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, rcb_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;
|
||||
}
|
||||
|
||||
if ((error = key_sendup0(rp, n, 0)) != 0) {
|
||||
m_freem(m);
|
||||
return error;
|
||||
}
|
||||
|
||||
n = NULL;
|
||||
}
|
||||
|
||||
if (so) {
|
||||
error = key_sendup0(sotorawcb(so), m, 0);
|
||||
m = NULL;
|
||||
} else {
|
||||
error = 0;
|
||||
m_freem(m);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
||||
/*
|
||||
* key_abort()
|
||||
* derived from net/rtsock.c:rts_abort()
|
||||
*/
|
||||
static int
|
||||
key_abort(struct socket *so)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet(); /* FreeBSD */
|
||||
error = raw_usrreqs.pru_abort(so);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_attach()
|
||||
* derived from net/rtsock.c:rts_attach()
|
||||
*/
|
||||
static int
|
||||
key_attach(struct socket *so, int proto, struct proc *td)
|
||||
{
|
||||
struct keycb *kp;
|
||||
int s, error;
|
||||
|
||||
if (sotorawcb(so) != 0)
|
||||
return EISCONN; /* XXX panic? */
|
||||
kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK|M_ZERO); /* XXX */
|
||||
if (kp == 0)
|
||||
return ENOBUFS;
|
||||
|
||||
/*
|
||||
* The spl[soft]net() 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(); /* FreeBSD */
|
||||
so->so_pcb = (caddr_t)kp;
|
||||
error = raw_usrreqs.pru_attach(so, proto, td);
|
||||
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 proc *td)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet(); /* FreeBSD */
|
||||
error = raw_usrreqs.pru_bind(so, nam, td); /* xxx just EINVAL */
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_connect()
|
||||
* derived from net/rtsock.c:rts_connect()
|
||||
*/
|
||||
static int
|
||||
key_connect(struct socket *so, struct sockaddr *nam, struct proc *td)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet(); /* FreeBSD */
|
||||
error = raw_usrreqs.pru_connect(so, nam, td); /* XXX just EINVAL */
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_detach()
|
||||
* derived from net/rtsock.c:rts_detach()
|
||||
*/
|
||||
static int
|
||||
key_detach(struct socket *so)
|
||||
{
|
||||
struct keycb *kp = (struct keycb *)sotorawcb(so);
|
||||
int s, error;
|
||||
|
||||
s = splnet(); /* FreeBSD */
|
||||
if (kp != 0) {
|
||||
if (kp->kp_raw.rcb_proto.sp_protocol
|
||||
== PF_KEY) /* XXX: AF_KEY */
|
||||
key_cb.key_count--;
|
||||
key_cb.any_count--;
|
||||
|
||||
key_freereg(so);
|
||||
}
|
||||
error = raw_usrreqs.pru_detach(so);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* key_disconnect()
|
||||
* derived from net/rtsock.c:key_disconnect()
|
||||
*/
|
||||
static int
|
||||
key_disconnect(struct socket *so)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet(); /* FreeBSD */
|
||||
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(); /* FreeBSD */
|
||||
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 proc *td)
|
||||
{
|
||||
int s, error;
|
||||
s = splnet(); /* FreeBSD */
|
||||
error = raw_usrreqs.pru_send(so, flags, m, nam, control, td);
|
||||
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(); /* FreeBSD */
|
||||
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(); /* FreeBSD */
|
||||
error = raw_usrreqs.pru_sockaddr(so, nam);
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
#else /*!__FreeBSD__ -- traditional proto_usrreq() switch */
|
||||
|
||||
/*
|
||||
* key_usrreq()
|
||||
* derived from net/rtsock.c:route_usrreq()
|
||||
*/
|
||||
int
|
||||
key_usrreq(so, req, m, nam, control, p)
|
||||
struct socket *so;
|
||||
int req;
|
||||
struct mbuf *m, *nam, *control;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
struct keycb *kp = (struct keycb *)sotorawcb(so);
|
||||
int s;
|
||||
|
||||
s = splsoftnet();
|
||||
if (req == PRU_ATTACH) {
|
||||
kp = (struct keycb *)malloc(sizeof(*kp), M_PCB, M_WAITOK);
|
||||
so->so_pcb = (caddr_t)kp;
|
||||
if (so->so_pcb)
|
||||
bzero(so->so_pcb, sizeof(*kp));
|
||||
}
|
||||
if (req == PRU_DETACH && kp) {
|
||||
int af = kp->kp_raw.rcb_proto.sp_protocol;
|
||||
if (af == PF_KEY) /* XXX: AF_KEY */
|
||||
key_cb.key_count--;
|
||||
key_cb.any_count--;
|
||||
|
||||
key_freereg(so);
|
||||
}
|
||||
|
||||
error = raw_usrreq(so, req, m, nam, control, p);
|
||||
m = control = NULL; /* reclaimed in raw_usrreq */
|
||||
kp = (struct keycb *)sotorawcb(so);
|
||||
if (req == PRU_ATTACH && kp) {
|
||||
int af = kp->kp_raw.rcb_proto.sp_protocol;
|
||||
if (error) {
|
||||
pfkeystat.sockerr++;
|
||||
free((caddr_t)kp, M_PCB);
|
||||
so->so_pcb = (caddr_t) 0;
|
||||
splx(s);
|
||||
return (error);
|
||||
}
|
||||
|
||||
kp->kp_promisc = kp->kp_registered = 0;
|
||||
|
||||
if (af == 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 (error);
|
||||
}
|
||||
#endif /*!__FreeBSD__*/
|
||||
|
||||
/* sysctl */
|
||||
#ifdef SYSCTL_NODE
|
||||
SYSCTL_NODE(_net, PF_KEY, key, CTLFLAG_RW, 0, "Key Family");
|
||||
#endif SYSCTL_NODE
|
||||
|
||||
/*
|
||||
* Definitions of protocols supported in the KEY domain.
|
||||
*/
|
||||
|
||||
/* This extern declaration is all that's common... */
|
||||
extern struct domain keydomain;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
struct pr_usrreqs key_usrreqs = {
|
||||
key_abort, pru_accept_notsupp, key_attach, key_bind,
|
||||
key_connect,
|
||||
pru_connect2_notsupp, pru_control_notsupp, key_detach,
|
||||
key_disconnect, pru_listen_notsupp, key_peeraddr,
|
||||
pru_rcvd_notsupp,
|
||||
pru_rcvoob_notsupp, key_send, pru_sense_null, key_shutdown,
|
||||
key_sockaddr, sosend, soreceive, sopoll
|
||||
};
|
||||
|
||||
struct protosw keysw[] = {
|
||||
{ SOCK_RAW, &keydomain, PF_KEY_V2, PR_ATOMIC|PR_ADDR,
|
||||
0, (pr_output_t *)key_output, raw_ctlinput, 0,
|
||||
0,
|
||||
raw_init, 0, 0, 0,
|
||||
&key_usrreqs
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
key_init0(void)
|
||||
{
|
||||
bzero((caddr_t)&key_cb, sizeof(key_cb));
|
||||
key_init();
|
||||
}
|
||||
|
||||
struct domain keydomain =
|
||||
{ PF_KEY, "key", key_init0, 0, 0,
|
||||
keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] };
|
||||
|
||||
DOMAIN_SET(key);
|
||||
|
||||
#else /* !__FreeBSD__ */
|
||||
|
||||
|
||||
struct protosw keysw[] = {
|
||||
{ SOCK_RAW, &keydomain, PF_KEY_V2, PR_ATOMIC|PR_ADDR,
|
||||
0, key_output, raw_ctlinput, 0,
|
||||
key_usrreq,
|
||||
raw_init, 0, 0, 0,
|
||||
key_sysctl,
|
||||
}
|
||||
};
|
||||
|
||||
struct domain keydomain =
|
||||
{ PF_KEY, "key", key_init, 0, 0,
|
||||
keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] };
|
||||
|
||||
#endif
|
|
@ -0,0 +1,89 @@
|
|||
/* $NetBSD: keysock.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/keysock.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $KAME: keysock.h,v 1.8 2000/03/27 05:11:06 sumikawa 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.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_KEYSOCK_H_
|
||||
#define _NETIPSEC_KEYSOCK_H_
|
||||
|
||||
/* statistics for pfkey socket */
|
||||
struct pfkeystat {
|
||||
/* kernel -> userland */
|
||||
u_quad_t out_total; /* # of total calls */
|
||||
u_quad_t out_bytes; /* total bytecount */
|
||||
u_quad_t out_msgtype[256]; /* message type histogram */
|
||||
u_quad_t out_invlen; /* invalid length field */
|
||||
u_quad_t out_invver; /* invalid version field */
|
||||
u_quad_t out_invmsgtype; /* invalid message type field */
|
||||
u_quad_t out_tooshort; /* msg too short */
|
||||
u_quad_t out_nomem; /* memory allocation failure */
|
||||
u_quad_t out_dupext; /* duplicate extension */
|
||||
u_quad_t out_invexttype; /* invalid extension type */
|
||||
u_quad_t out_invsatype; /* invalid sa type */
|
||||
u_quad_t out_invaddr; /* invalid address extension */
|
||||
/* userland -> kernel */
|
||||
u_quad_t in_total; /* # of total calls */
|
||||
u_quad_t in_bytes; /* total bytecount */
|
||||
u_quad_t in_msgtype[256]; /* message type histogram */
|
||||
u_quad_t in_msgtarget[3]; /* one/all/registered */
|
||||
u_quad_t in_nomem; /* memory allocation failure */
|
||||
/* others */
|
||||
u_quad_t sockerr; /* # of socket related errors */
|
||||
};
|
||||
|
||||
#define KEY_SENDUP_ONE 0
|
||||
#define KEY_SENDUP_ALL 1
|
||||
#define KEY_SENDUP_REGISTERED 2
|
||||
|
||||
#ifdef _KERNEL
|
||||
struct keycb {
|
||||
struct rawcb kp_raw; /* rawcb */
|
||||
int kp_promisc; /* promiscuous mode */
|
||||
int kp_registered; /* registered socket */
|
||||
};
|
||||
|
||||
extern struct pfkeystat pfkeystat;
|
||||
|
||||
extern int key_output __P((struct mbuf *, ...));
|
||||
#ifndef __NetBSD__
|
||||
extern int key_usrreq __P((struct socket *,
|
||||
int, struct mbuf *, struct mbuf *, struct mbuf *));
|
||||
#else
|
||||
extern int key_usrreq __P((struct socket *,
|
||||
int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *));
|
||||
extern int key_sysctl __P((int *, u_int, void *, size_t *, void *, size_t));
|
||||
#endif
|
||||
|
||||
extern int key_sendup __P((struct socket *, struct sadb_msg *, u_int, int));
|
||||
extern int key_sendup_mbuf __P((struct socket *, struct mbuf *, int));
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /*_NETIPSEC_KEYSOCK_H_*/
|
|
@ -0,0 +1,127 @@
|
|||
/* $NetBSD: xform.h,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/xform.h,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $OpenBSD: ip_ipsp.h,v 1.119 2002/03/14 01:27:11 millert Exp $ */
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr),
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de) and
|
||||
* Niklas Hallqvist (niklas@appli.se).
|
||||
*
|
||||
* The original version of this code was written by John Ioannidis
|
||||
* for BSD/OS in Athens, Greece, in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
|
||||
*
|
||||
* Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
|
||||
* Angelos D. Keromytis and Niels Provos.
|
||||
* Copyright (c) 1999 Niklas Hallqvist.
|
||||
* Copyright (c) 2001, Angelos D. Keromytis.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#ifndef _NETIPSEC_XFORM_H_
|
||||
#define _NETIPSEC_XFORM_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <opencrypto/xform.h>
|
||||
|
||||
#define AH_HMAC_HASHLEN 12 /* 96 bits of authenticator */
|
||||
#define AH_HMAC_INITIAL_RPL 1 /* replay counter initial value */
|
||||
|
||||
/*
|
||||
* Packet tag assigned on completion of IPsec processing; used
|
||||
* to speedup processing when/if the packet comes back for more
|
||||
* processing.
|
||||
*/
|
||||
struct tdb_ident {
|
||||
u_int32_t spi;
|
||||
union sockaddr_union dst;
|
||||
u_int8_t proto;
|
||||
};
|
||||
|
||||
/*
|
||||
* Opaque data structure hung off a crypto operation descriptor.
|
||||
*/
|
||||
struct tdb_crypto {
|
||||
struct ipsecrequest *tc_isr; /* ipsec request state */
|
||||
u_int32_t tc_spi; /* associated SPI */
|
||||
union sockaddr_union tc_dst; /* dst addr of packet */
|
||||
u_int8_t tc_proto; /* current protocol, e.g. AH */
|
||||
u_int8_t tc_nxt; /* next protocol, e.g. IPV4 */
|
||||
int tc_protoff; /* current protocol offset */
|
||||
int tc_skip; /* data offset */
|
||||
caddr_t tc_ptr; /* associated crypto data */
|
||||
};
|
||||
|
||||
struct secasvar;
|
||||
struct ipescrequest;
|
||||
|
||||
struct xformsw {
|
||||
u_short xf_type; /* xform ID */
|
||||
#define XF_IP4 1 /* IP inside IP */
|
||||
#define XF_AH 2 /* AH */
|
||||
#define XF_ESP 3 /* ESP */
|
||||
#define XF_TCPSIGNATURE 5 /* TCP MD5 Signature option, RFC 2358 */
|
||||
#define XF_IPCOMP 6 /* IPCOMP */
|
||||
u_short xf_flags;
|
||||
#define XFT_AUTH 0x0001
|
||||
#define XFT_CONF 0x0100
|
||||
#define XFT_COMP 0x1000
|
||||
char *xf_name; /* human-readable name */
|
||||
int (*xf_init)(struct secasvar*, struct xformsw*); /* setup */
|
||||
int (*xf_zeroize)(struct secasvar*); /* cleanup */
|
||||
int (*xf_input)(struct mbuf*, struct secasvar*, /* input */
|
||||
int, int);
|
||||
int (*xf_output)(struct mbuf*, /* output */
|
||||
struct ipsecrequest *, struct mbuf **, int, int);
|
||||
struct xformsw *xf_next; /* list of registered xforms */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern void xform_register(struct xformsw*);
|
||||
extern int xform_init(struct secasvar *sav, int xftype);
|
||||
|
||||
struct cryptoini;
|
||||
|
||||
/* XF_IP4 */
|
||||
extern int ip4_input6(struct mbuf **m, int *offp, int proto);
|
||||
extern void ip4_input(struct mbuf *m, ...);
|
||||
extern int ipip_output(struct mbuf *, struct ipsecrequest *,
|
||||
struct mbuf **, int, int);
|
||||
|
||||
/* XF_AH */
|
||||
extern int ah_init0(struct secasvar *, struct xformsw *, struct cryptoini *);
|
||||
extern int ah_zeroize(struct secasvar *sav);
|
||||
extern struct auth_hash *ah_algorithm_lookup(int alg);
|
||||
extern size_t ah_hdrsiz(struct secasvar *);
|
||||
|
||||
/* XF_ESP */
|
||||
extern struct enc_xform *esp_algorithm_lookup(int alg);
|
||||
extern size_t esp_hdrsiz(struct secasvar *sav);
|
||||
|
||||
/* XF_COMP */
|
||||
extern struct comp_algo *ipcomp_algorithm_lookup(int alg);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _NETIPSEC_XFORM_H_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,975 @@
|
|||
/* $NetBSD: xform_esp.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/xform_esp.c,v 1.2.2.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $OpenBSD: ip_esp.c,v 1.69 2001/06/26 06:18:59 angelos Exp $ */
|
||||
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de).
|
||||
*
|
||||
* The original version of this code was written by John Ioannidis
|
||||
* for BSD/OS in Athens, Greece, in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Additional features in 1999 by Angelos D. Keromytis.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
|
||||
* Angelos D. Keromytis and Niels Provos.
|
||||
* Copyright (c) 2001 Angelos D. Keromytis.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: xform_esp.c,v 1.1 2003/08/13 20:06:51 jonathan Exp $");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/kernel.h>
|
||||
/*#include <sys/random.h>*/
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_ecn.h>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
#include <net/route.h>
|
||||
#include <netipsec/ipsec.h>
|
||||
#include <netipsec/ah.h>
|
||||
#include <netipsec/ah_var.h>
|
||||
#include <netipsec/esp.h>
|
||||
#include <netipsec/esp_var.h>
|
||||
#include <netipsec/xform.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netipsec/ipsec6.h>
|
||||
#include <netinet6/ip6_ecn.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
|
||||
#include <opencrypto/cryptodev.h>
|
||||
#include <opencrypto/xform.h>
|
||||
|
||||
int esp_enable = 1;
|
||||
struct espstat espstat;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
SYSCTL_DECL(_net_inet_esp);
|
||||
SYSCTL_INT(_net_inet_esp, OID_AUTO,
|
||||
esp_enable, CTLFLAG_RW, &esp_enable, 0, "");
|
||||
SYSCTL_STRUCT(_net_inet_esp, IPSECCTL_STATS,
|
||||
stats, CTLFLAG_RD, &espstat, espstat, "");
|
||||
#endif __FreeBSD__
|
||||
|
||||
static int esp_max_ivlen; /* max iv length over all algorithms */
|
||||
|
||||
static int esp_input_cb(struct cryptop *op);
|
||||
static int esp_output_cb(struct cryptop *crp);
|
||||
|
||||
/*
|
||||
* NB: this is public for use by the PF_KEY support.
|
||||
* NB: if you add support here; be sure to add code to esp_attach below!
|
||||
*/
|
||||
struct enc_xform *
|
||||
esp_algorithm_lookup(int alg)
|
||||
{
|
||||
if (alg >= ESP_ALG_MAX)
|
||||
return NULL;
|
||||
switch (alg) {
|
||||
case SADB_EALG_DESCBC:
|
||||
return &enc_xform_des;
|
||||
case SADB_EALG_3DESCBC:
|
||||
return &enc_xform_3des;
|
||||
case SADB_X_EALG_AES:
|
||||
return &enc_xform_rijndael128;
|
||||
case SADB_X_EALG_BLOWFISHCBC:
|
||||
return &enc_xform_blf;
|
||||
case SADB_X_EALG_CAST128CBC:
|
||||
return &enc_xform_cast5;
|
||||
case SADB_X_EALG_SKIPJACK:
|
||||
return &enc_xform_skipjack;
|
||||
case SADB_EALG_NULL:
|
||||
return &enc_xform_null;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
esp_hdrsiz(struct secasvar *sav)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (sav != NULL) {
|
||||
/*XXX not right for null algorithm--does it matter??*/
|
||||
IPSEC_ASSERT(sav->tdb_encalgxform != NULL,
|
||||
("esp_hdrsiz: SA with null xform"));
|
||||
if (sav->flags & SADB_X_EXT_OLD)
|
||||
size = sizeof (struct esp);
|
||||
else
|
||||
size = sizeof (struct newesp);
|
||||
size += sav->tdb_encalgxform->blocksize + 9;
|
||||
/*XXX need alg check???*/
|
||||
if (sav->tdb_authalgxform != NULL && sav->replay)
|
||||
size += ah_hdrsiz(sav);
|
||||
} else {
|
||||
/*
|
||||
* base header size
|
||||
* + max iv length for CBC mode
|
||||
* + max pad length
|
||||
* + sizeof (pad length field)
|
||||
* + sizeof (next header field)
|
||||
* + max icv supported.
|
||||
*/
|
||||
size = sizeof (struct newesp) + esp_max_ivlen + 9 + 16;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* esp_init() is called when an SPI is being set up.
|
||||
*/
|
||||
static int
|
||||
esp_init(struct secasvar *sav, struct xformsw *xsp)
|
||||
{
|
||||
struct enc_xform *txform;
|
||||
struct cryptoini cria, crie;
|
||||
int keylen;
|
||||
int error;
|
||||
|
||||
txform = esp_algorithm_lookup(sav->alg_enc);
|
||||
if (txform == NULL) {
|
||||
DPRINTF(("esp_init: unsupported encryption algorithm %d\n",
|
||||
sav->alg_enc));
|
||||
return EINVAL;
|
||||
}
|
||||
if (sav->key_enc == NULL) {
|
||||
DPRINTF(("esp_init: no encoding key for %s algorithm\n",
|
||||
txform->name));
|
||||
return EINVAL;
|
||||
}
|
||||
if ((sav->flags&(SADB_X_EXT_OLD|SADB_X_EXT_IV4B)) == SADB_X_EXT_IV4B) {
|
||||
DPRINTF(("esp_init: 4-byte IV not supported with protocol\n"));
|
||||
return EINVAL;
|
||||
}
|
||||
keylen = _KEYLEN(sav->key_enc);
|
||||
if (txform->minkey > keylen || keylen > txform->maxkey) {
|
||||
DPRINTF(("esp_init: invalid key length %u, must be in "
|
||||
"the range [%u..%u] for algorithm %s\n",
|
||||
keylen, txform->minkey, txform->maxkey,
|
||||
txform->name));
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: The null xform needs a non-zero blocksize to keep the
|
||||
* crypto code happy but if we use it to set ivlen then
|
||||
* the ESP header will be processed incorrectly. The
|
||||
* compromise is to force it to zero here.
|
||||
*/
|
||||
sav->ivlen = (txform == &enc_xform_null ? 0 : txform->blocksize);
|
||||
sav->iv = (caddr_t) malloc(sav->ivlen, M_XDATA, M_WAITOK);
|
||||
if (sav->iv == NULL) {
|
||||
DPRINTF(("esp_init: no memory for IV\n"));
|
||||
return EINVAL;
|
||||
}
|
||||
key_randomfill(sav->iv, sav->ivlen); /*XXX*/
|
||||
|
||||
/*
|
||||
* Setup AH-related state.
|
||||
*/
|
||||
if (sav->alg_auth != 0) {
|
||||
error = ah_init0(sav, xsp, &cria);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
/* NB: override anything set in ah_init0 */
|
||||
sav->tdb_xform = xsp;
|
||||
sav->tdb_encalgxform = txform;
|
||||
|
||||
/* Initialize crypto session. */
|
||||
bzero(&crie, sizeof (crie));
|
||||
crie.cri_alg = sav->tdb_encalgxform->type;
|
||||
crie.cri_klen = _KEYBITS(sav->key_enc);
|
||||
crie.cri_key = _KEYBUF(sav->key_enc);
|
||||
/* XXX Rounds ? */
|
||||
|
||||
if (sav->tdb_authalgxform && sav->tdb_encalgxform) {
|
||||
/* init both auth & enc */
|
||||
crie.cri_next = &cria;
|
||||
error = crypto_newsession(&sav->tdb_cryptoid,
|
||||
&crie, crypto_support);
|
||||
} else if (sav->tdb_encalgxform) {
|
||||
error = crypto_newsession(&sav->tdb_cryptoid,
|
||||
&crie, crypto_support);
|
||||
} else if (sav->tdb_authalgxform) {
|
||||
error = crypto_newsession(&sav->tdb_cryptoid,
|
||||
&cria, crypto_support);
|
||||
} else {
|
||||
/* XXX cannot happen? */
|
||||
DPRINTF(("esp_init: no encoding OR authentication xform!\n"));
|
||||
error = EINVAL;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Paranoia.
|
||||
*/
|
||||
static int
|
||||
esp_zeroize(struct secasvar *sav)
|
||||
{
|
||||
/* NB: ah_zerorize free's the crypto session state */
|
||||
int error = ah_zeroize(sav);
|
||||
|
||||
if (sav->key_enc)
|
||||
bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc));
|
||||
/* NB: sav->iv is freed elsewhere, even though we malloc it! */
|
||||
sav->tdb_encalgxform = NULL;
|
||||
sav->tdb_xform = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP input processing, called (eventually) through the protocol switch.
|
||||
*/
|
||||
static int
|
||||
esp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
|
||||
{
|
||||
struct auth_hash *esph;
|
||||
struct enc_xform *espx;
|
||||
struct tdb_ident *tdbi;
|
||||
struct tdb_crypto *tc;
|
||||
int plen, alen, hlen;
|
||||
struct m_tag *mtag;
|
||||
struct newesp *esp;
|
||||
|
||||
struct cryptodesc *crde;
|
||||
struct cryptop *crp;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("esp_input");
|
||||
|
||||
IPSEC_ASSERT(sav != NULL, ("esp_input: null SA"));
|
||||
IPSEC_ASSERT(sav->tdb_encalgxform != NULL,
|
||||
("esp_input: null encoding xform"));
|
||||
IPSEC_ASSERT((skip&3) == 0 && (m->m_pkthdr.len&3) == 0,
|
||||
("esp_input: misaligned packet, skip %u pkt len %u",
|
||||
skip, m->m_pkthdr.len));
|
||||
|
||||
/* XXX don't pullup, just copy header */
|
||||
IP6_EXTHDR_GET(esp, struct newesp *, m, skip, sizeof (struct newesp));
|
||||
|
||||
esph = sav->tdb_authalgxform;
|
||||
espx = sav->tdb_encalgxform;
|
||||
|
||||
/* Determine the ESP header length */
|
||||
if (sav->flags & SADB_X_EXT_OLD)
|
||||
hlen = sizeof (struct esp) + sav->ivlen;
|
||||
else
|
||||
hlen = sizeof (struct newesp) + sav->ivlen;
|
||||
/* Authenticator hash size */
|
||||
alen = esph ? AH_HMAC_HASHLEN : 0;
|
||||
|
||||
/*
|
||||
* Verify payload length is multiple of encryption algorithm
|
||||
* block size.
|
||||
*
|
||||
* NB: This works for the null algorithm because the blocksize
|
||||
* is 4 and all packets must be 4-byte aligned regardless
|
||||
* of the algorithm.
|
||||
*/
|
||||
plen = m->m_pkthdr.len - (skip + hlen + alen);
|
||||
if ((plen & (espx->blocksize - 1)) || (plen <= 0)) {
|
||||
DPRINTF(("esp_input: "
|
||||
"payload of %d octets not a multiple of %d octets,"
|
||||
" SA %s/%08lx\n",
|
||||
plen, espx->blocksize,
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
espstat.esps_badilen++;
|
||||
m_freem(m);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check sequence number.
|
||||
*/
|
||||
if (esph && sav->replay && !ipsec_chkreplay(ntohl(esp->esp_seq), sav)) {
|
||||
DPRINTF(("esp_input: packet replay check for %s\n",
|
||||
ipsec_logsastr(sav))); /*XXX*/
|
||||
espstat.esps_replay++;
|
||||
m_freem(m);
|
||||
return ENOBUFS; /*XXX*/
|
||||
}
|
||||
|
||||
/* Update the counters */
|
||||
espstat.esps_ibytes += m->m_pkthdr.len - skip - hlen - alen;
|
||||
|
||||
/* Find out if we've already done crypto */
|
||||
for (mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, NULL);
|
||||
mtag != NULL;
|
||||
mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_CRYPTO_DONE, mtag)) {
|
||||
tdbi = (struct tdb_ident *) (mtag + 1);
|
||||
if (tdbi->proto == sav->sah->saidx.proto &&
|
||||
tdbi->spi == sav->spi &&
|
||||
!bcmp(&tdbi->dst, &sav->sah->saidx.dst,
|
||||
sizeof(union sockaddr_union)))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get crypto descriptors */
|
||||
crp = crypto_getreq(esph && espx ? 2 : 1);
|
||||
if (crp == NULL) {
|
||||
DPRINTF(("esp_input: failed to acquire crypto descriptors\n"));
|
||||
espstat.esps_crypto++;
|
||||
m_freem(m);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
/* Get IPsec-specific opaque pointer */
|
||||
if (esph == NULL || mtag != NULL)
|
||||
tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
|
||||
M_XDATA, M_NOWAIT|M_ZERO);
|
||||
else
|
||||
tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto) + alen,
|
||||
M_XDATA, M_NOWAIT|M_ZERO);
|
||||
if (tc == NULL) {
|
||||
crypto_freereq(crp);
|
||||
DPRINTF(("esp_input: failed to allocate tdb_crypto\n"));
|
||||
espstat.esps_crypto++;
|
||||
m_freem(m);
|
||||
return ENOBUFS;
|
||||
}
|
||||
|
||||
tc->tc_ptr = (caddr_t) mtag;
|
||||
|
||||
if (esph) {
|
||||
struct cryptodesc *crda = crp->crp_desc;
|
||||
|
||||
IPSEC_ASSERT(crda != NULL, ("esp_input: null ah crypto descriptor"));
|
||||
|
||||
/* Authentication descriptor */
|
||||
crda->crd_skip = skip;
|
||||
crda->crd_len = m->m_pkthdr.len - (skip + alen);
|
||||
crda->crd_inject = m->m_pkthdr.len - alen;
|
||||
|
||||
crda->crd_alg = esph->type;
|
||||
crda->crd_key = _KEYBUF(sav->key_auth);
|
||||
crda->crd_klen = _KEYBITS(sav->key_auth);
|
||||
|
||||
/* Copy the authenticator */
|
||||
if (mtag == NULL)
|
||||
m_copydata(m, m->m_pkthdr.len - alen, alen,
|
||||
(caddr_t) (tc + 1));
|
||||
|
||||
/* Chain authentication request */
|
||||
crde = crda->crd_next;
|
||||
} else {
|
||||
crde = crp->crp_desc;
|
||||
}
|
||||
|
||||
/* Crypto operation descriptor */
|
||||
crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
|
||||
crp->crp_flags = CRYPTO_F_IMBUF;
|
||||
crp->crp_buf = (caddr_t) m;
|
||||
crp->crp_callback = esp_input_cb;
|
||||
crp->crp_sid = sav->tdb_cryptoid;
|
||||
crp->crp_opaque = (caddr_t) tc;
|
||||
|
||||
/* These are passed as-is to the callback */
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = sav->sah->saidx.dst;
|
||||
tc->tc_proto = sav->sah->saidx.proto;
|
||||
tc->tc_protoff = protoff;
|
||||
tc->tc_skip = skip;
|
||||
|
||||
/* Decryption descriptor */
|
||||
if (espx) {
|
||||
IPSEC_ASSERT(crde != NULL, ("esp_input: null esp crypto descriptor"));
|
||||
crde->crd_skip = skip + hlen;
|
||||
crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
|
||||
crde->crd_inject = skip + hlen - sav->ivlen;
|
||||
|
||||
crde->crd_alg = espx->type;
|
||||
crde->crd_key = _KEYBUF(sav->key_enc);
|
||||
crde->crd_klen = _KEYBITS(sav->key_enc);
|
||||
/* XXX Rounds ? */
|
||||
}
|
||||
|
||||
if (mtag == NULL)
|
||||
return crypto_dispatch(crp);
|
||||
else
|
||||
return esp_input_cb(crp);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
#define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do { \
|
||||
if (saidx->dst.sa.sa_family == AF_INET6) { \
|
||||
error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \
|
||||
} else { \
|
||||
error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) \
|
||||
(error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ESP input callback from the crypto driver.
|
||||
*/
|
||||
static int
|
||||
esp_input_cb(struct cryptop *crp)
|
||||
{
|
||||
u_int8_t lastthree[3], aalg[AH_HMAC_HASHLEN];
|
||||
int s, hlen, skip, protoff, error;
|
||||
struct mbuf *m;
|
||||
struct cryptodesc *crd;
|
||||
struct auth_hash *esph;
|
||||
struct enc_xform *espx;
|
||||
struct tdb_crypto *tc;
|
||||
struct m_tag *mtag;
|
||||
struct secasvar *sav;
|
||||
struct secasindex *saidx;
|
||||
caddr_t ptr;
|
||||
|
||||
crd = crp->crp_desc;
|
||||
IPSEC_ASSERT(crd != NULL, ("esp_input_cb: null crypto descriptor!"));
|
||||
|
||||
tc = (struct tdb_crypto *) crp->crp_opaque;
|
||||
IPSEC_ASSERT(tc != NULL, ("esp_input_cb: null opaque crypto data area!"));
|
||||
skip = tc->tc_skip;
|
||||
protoff = tc->tc_protoff;
|
||||
mtag = (struct m_tag *) tc->tc_ptr;
|
||||
m = (struct mbuf *) crp->crp_buf;
|
||||
|
||||
s = splsoftnet();
|
||||
|
||||
sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
|
||||
if (sav == NULL) {
|
||||
espstat.esps_notdb++;
|
||||
DPRINTF(("esp_input_cb: SA expired while in crypto "
|
||||
"(SA %s/%08lx proto %u)\n", ipsec_address(&tc->tc_dst),
|
||||
(u_long) ntohl(tc->tc_spi), tc->tc_proto));
|
||||
error = ENOBUFS; /*XXX*/
|
||||
goto bad;
|
||||
}
|
||||
|
||||
saidx = &sav->sah->saidx;
|
||||
IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
|
||||
saidx->dst.sa.sa_family == AF_INET6,
|
||||
("ah_input_cb: unexpected protocol family %u",
|
||||
saidx->dst.sa.sa_family));
|
||||
|
||||
esph = sav->tdb_authalgxform;
|
||||
espx = sav->tdb_encalgxform;
|
||||
|
||||
/* Check for crypto errors */
|
||||
if (crp->crp_etype) {
|
||||
/* Reset the session ID */
|
||||
if (sav->tdb_cryptoid != 0)
|
||||
sav->tdb_cryptoid = crp->crp_sid;
|
||||
|
||||
if (crp->crp_etype == EAGAIN) {
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return crypto_dispatch(crp);
|
||||
}
|
||||
|
||||
espstat.esps_noxform++;
|
||||
DPRINTF(("esp_input_cb: crypto error %d\n", crp->crp_etype));
|
||||
error = crp->crp_etype;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Shouldn't happen... */
|
||||
if (m == NULL) {
|
||||
espstat.esps_crypto++;
|
||||
DPRINTF(("esp_input_cb: bogus returned buffer from crypto\n"));
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
espstat.esps_hist[sav->alg_enc]++;
|
||||
|
||||
/* If authentication was performed, check now. */
|
||||
if (esph != NULL) {
|
||||
/*
|
||||
* If we have a tag, it means an IPsec-aware NIC did
|
||||
* the verification for us. Otherwise we need to
|
||||
* check the authentication calculation.
|
||||
*/
|
||||
ahstat.ahs_hist[sav->alg_auth]++;
|
||||
if (mtag == NULL) {
|
||||
/* Copy the authenticator from the packet */
|
||||
m_copydata(m, m->m_pkthdr.len - esph->authsize,
|
||||
esph->authsize, aalg);
|
||||
|
||||
ptr = (caddr_t) (tc + 1);
|
||||
|
||||
/* Verify authenticator */
|
||||
if (bcmp(ptr, aalg, esph->authsize) != 0) {
|
||||
DPRINTF(("esp_input_cb: "
|
||||
"authentication hash mismatch for packet in SA %s/%08lx\n",
|
||||
ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
espstat.esps_badauth++;
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove trailing authenticator */
|
||||
m_adj(m, -(esph->authsize));
|
||||
}
|
||||
|
||||
/* Release the crypto descriptors */
|
||||
free(tc, M_XDATA), tc = NULL;
|
||||
crypto_freereq(crp), crp = NULL;
|
||||
|
||||
/*
|
||||
* Packet is now decrypted.
|
||||
*/
|
||||
m->m_flags |= M_DECRYPTED;
|
||||
|
||||
/* Determine the ESP header length */
|
||||
if (sav->flags & SADB_X_EXT_OLD)
|
||||
hlen = sizeof (struct esp) + sav->ivlen;
|
||||
else
|
||||
hlen = sizeof (struct newesp) + sav->ivlen;
|
||||
|
||||
/* Remove the ESP header and IV from the mbuf. */
|
||||
error = m_striphdr(m, skip, hlen);
|
||||
if (error) {
|
||||
espstat.esps_hdrops++;
|
||||
DPRINTF(("esp_input_cb: bad mbuf chain, SA %s/%08lx\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Save the last three bytes of decrypted data */
|
||||
m_copydata(m, m->m_pkthdr.len - 3, 3, lastthree);
|
||||
|
||||
/* Verify pad length */
|
||||
if (lastthree[1] + 2 > m->m_pkthdr.len - skip) {
|
||||
espstat.esps_badilen++;
|
||||
DPRINTF(("esp_input_cb: invalid padding length %d "
|
||||
"for %u byte packet in SA %s/%08lx\n",
|
||||
lastthree[1], m->m_pkthdr.len - skip,
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Verify correct decryption by checking the last padding bytes */
|
||||
if ((sav->flags & SADB_X_EXT_PMASK) != SADB_X_EXT_PRAND) {
|
||||
if (lastthree[1] != lastthree[0] && lastthree[1] != 0) {
|
||||
espstat.esps_badenc++;
|
||||
DPRINTF(("esp_input_cb: decryption failed "
|
||||
"for packet in SA %s/%08lx\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
DPRINTF(("esp_input_cb: %x %x\n", lastthree[0], lastthree[1]));
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/* Trim the mbuf chain to remove trailing authenticator and padding */
|
||||
m_adj(m, -(lastthree[1] + 2));
|
||||
|
||||
/* Restore the Next Protocol field */
|
||||
m_copyback(m, protoff, sizeof (u_int8_t), lastthree + 2);
|
||||
|
||||
IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag);
|
||||
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return error;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
if (m != NULL)
|
||||
m_freem(m);
|
||||
if (tc != NULL)
|
||||
free(tc, M_XDATA);
|
||||
if (crp != NULL)
|
||||
crypto_freereq(crp);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP output routine, called by ipsec[46]_process_packet().
|
||||
*/
|
||||
static int
|
||||
esp_output(
|
||||
struct mbuf *m,
|
||||
struct ipsecrequest *isr,
|
||||
struct mbuf **mp,
|
||||
int skip,
|
||||
int protoff
|
||||
)
|
||||
{
|
||||
struct enc_xform *espx;
|
||||
struct auth_hash *esph;
|
||||
int hlen, rlen, plen, padding, blks, alen, i, roff;
|
||||
struct mbuf *mo = (struct mbuf *) NULL;
|
||||
struct tdb_crypto *tc;
|
||||
struct secasvar *sav;
|
||||
struct secasindex *saidx;
|
||||
unsigned char *pad;
|
||||
u_int8_t prot;
|
||||
int error, maxpacketsize;
|
||||
|
||||
struct cryptodesc *crde = NULL, *crda = NULL;
|
||||
struct cryptop *crp;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("esp_output");
|
||||
|
||||
sav = isr->sav;
|
||||
IPSEC_ASSERT(sav != NULL, ("esp_output: null SA"));
|
||||
esph = sav->tdb_authalgxform;
|
||||
espx = sav->tdb_encalgxform;
|
||||
IPSEC_ASSERT(espx != NULL, ("esp_output: null encoding xform"));
|
||||
|
||||
if (sav->flags & SADB_X_EXT_OLD)
|
||||
hlen = sizeof (struct esp) + sav->ivlen;
|
||||
else
|
||||
hlen = sizeof (struct newesp) + sav->ivlen;
|
||||
|
||||
rlen = m->m_pkthdr.len - skip; /* Raw payload length. */
|
||||
/*
|
||||
* NB: The null encoding transform has a blocksize of 4
|
||||
* so that headers are properly aligned.
|
||||
*/
|
||||
blks = espx->blocksize; /* IV blocksize */
|
||||
|
||||
/* XXX clamp padding length a la KAME??? */
|
||||
padding = ((blks - ((rlen + 2) % blks)) % blks) + 2;
|
||||
plen = rlen + padding; /* Padded payload length. */
|
||||
|
||||
if (esph)
|
||||
alen = AH_HMAC_HASHLEN;
|
||||
else
|
||||
alen = 0;
|
||||
|
||||
espstat.esps_output++;
|
||||
|
||||
saidx = &sav->sah->saidx;
|
||||
/* Check for maximum packet size violations. */
|
||||
switch (saidx->dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
maxpacketsize = IP_MAXPACKET;
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
maxpacketsize = IPV6_MAXPACKET;
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
DPRINTF(("esp_output: unknown/unsupported protocol "
|
||||
"family %d, SA %s/%08lx\n",
|
||||
saidx->dst.sa.sa_family, ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
espstat.esps_nopf++;
|
||||
error = EPFNOSUPPORT;
|
||||
goto bad;
|
||||
}
|
||||
if (skip + hlen + rlen + padding + alen > maxpacketsize) {
|
||||
DPRINTF(("esp_output: packet in SA %s/%08lx got too big "
|
||||
"(len %u, max len %u)\n",
|
||||
ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi),
|
||||
skip + hlen + rlen + padding + alen, maxpacketsize));
|
||||
espstat.esps_toobig++;
|
||||
error = EMSGSIZE;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Update the counters. */
|
||||
espstat.esps_obytes += m->m_pkthdr.len - skip;
|
||||
|
||||
m = m_clone(m);
|
||||
if (m == NULL) {
|
||||
DPRINTF(("esp_output: cannot clone mbuf chain, SA %s/%08lx\n",
|
||||
ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
|
||||
espstat.esps_hdrops++;
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Inject ESP header. */
|
||||
mo = m_makespace(m, skip, hlen, &roff);
|
||||
if (mo == NULL) {
|
||||
DPRINTF(("esp_output: failed to inject %u byte ESP hdr for SA "
|
||||
"%s/%08lx\n",
|
||||
hlen, ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
espstat.esps_hdrops++; /* XXX diffs from openbsd */
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Initialize ESP header. */
|
||||
bcopy((caddr_t) &sav->spi, mtod(mo, caddr_t) + roff, sizeof(u_int32_t));
|
||||
if (sav->replay) {
|
||||
u_int32_t replay = htonl(++(sav->replay->count));
|
||||
bcopy((caddr_t) &replay,
|
||||
mtod(mo, caddr_t) + roff + sizeof(u_int32_t),
|
||||
sizeof(u_int32_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Add padding -- better to do it ourselves than use the crypto engine,
|
||||
* although if/when we support compression, we'd have to do that.
|
||||
*/
|
||||
pad = (u_char *) m_pad(m, padding + alen);
|
||||
if (pad == NULL) {
|
||||
DPRINTF(("esp_output: m_pad failed for SA %s/%08lx\n",
|
||||
ipsec_address(&saidx->dst), (u_long) ntohl(sav->spi)));
|
||||
m = NULL; /* NB: free'd by m_pad */
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add padding: random, zero, or self-describing.
|
||||
* XXX catch unexpected setting
|
||||
*/
|
||||
switch (sav->flags & SADB_X_EXT_PMASK) {
|
||||
case SADB_X_EXT_PRAND:
|
||||
(void) read_random(pad, padding - 2);
|
||||
break;
|
||||
case SADB_X_EXT_PZERO:
|
||||
bzero(pad, padding - 2);
|
||||
break;
|
||||
case SADB_X_EXT_PSEQ:
|
||||
for (i = 0; i < padding - 2; i++)
|
||||
pad[i] = i+1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fix padding length and Next Protocol in padding itself. */
|
||||
pad[padding - 2] = padding - 2;
|
||||
m_copydata(m, protoff, sizeof(u_int8_t), pad + padding - 1);
|
||||
|
||||
/* Fix Next Protocol in IPv4/IPv6 header. */
|
||||
prot = IPPROTO_ESP;
|
||||
m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot);
|
||||
|
||||
/* Get crypto descriptors. */
|
||||
crp = crypto_getreq(esph && espx ? 2 : 1);
|
||||
if (crp == NULL) {
|
||||
DPRINTF(("esp_output: failed to acquire crypto descriptors\n"));
|
||||
espstat.esps_crypto++;
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (espx) {
|
||||
crde = crp->crp_desc;
|
||||
crda = crde->crd_next;
|
||||
|
||||
/* Encryption descriptor. */
|
||||
crde->crd_skip = skip + hlen;
|
||||
crde->crd_len = m->m_pkthdr.len - (skip + hlen + alen);
|
||||
crde->crd_flags = CRD_F_ENCRYPT;
|
||||
crde->crd_inject = skip + hlen - sav->ivlen;
|
||||
|
||||
/* Encryption operation. */
|
||||
crde->crd_alg = espx->type;
|
||||
crde->crd_key = _KEYBUF(sav->key_enc);
|
||||
crde->crd_klen = _KEYBITS(sav->key_enc);
|
||||
/* XXX Rounds ? */
|
||||
} else
|
||||
crda = crp->crp_desc;
|
||||
|
||||
/* IPsec-specific opaque crypto info. */
|
||||
tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
|
||||
M_XDATA, M_NOWAIT|M_ZERO);
|
||||
if (tc == NULL) {
|
||||
crypto_freereq(crp);
|
||||
DPRINTF(("esp_output: failed to allocate tdb_crypto\n"));
|
||||
espstat.esps_crypto++;
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Callback parameters */
|
||||
tc->tc_isr = isr;
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = saidx->dst;
|
||||
tc->tc_proto = saidx->proto;
|
||||
|
||||
/* Crypto operation descriptor. */
|
||||
crp->crp_ilen = m->m_pkthdr.len; /* Total input length. */
|
||||
crp->crp_flags = CRYPTO_F_IMBUF;
|
||||
crp->crp_buf = (caddr_t) m;
|
||||
crp->crp_callback = esp_output_cb;
|
||||
crp->crp_opaque = (caddr_t) tc;
|
||||
crp->crp_sid = sav->tdb_cryptoid;
|
||||
|
||||
if (esph) {
|
||||
/* Authentication descriptor. */
|
||||
crda->crd_skip = skip;
|
||||
crda->crd_len = m->m_pkthdr.len - (skip + alen);
|
||||
crda->crd_inject = m->m_pkthdr.len - alen;
|
||||
|
||||
/* Authentication operation. */
|
||||
crda->crd_alg = esph->type;
|
||||
crda->crd_key = _KEYBUF(sav->key_auth);
|
||||
crda->crd_klen = _KEYBITS(sav->key_auth);
|
||||
}
|
||||
|
||||
return crypto_dispatch(crp);
|
||||
bad:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ESP output callback from the crypto driver.
|
||||
*/
|
||||
static int
|
||||
esp_output_cb(struct cryptop *crp)
|
||||
{
|
||||
struct tdb_crypto *tc;
|
||||
struct ipsecrequest *isr;
|
||||
struct secasvar *sav;
|
||||
struct mbuf *m;
|
||||
int s, err, error;
|
||||
|
||||
tc = (struct tdb_crypto *) crp->crp_opaque;
|
||||
IPSEC_ASSERT(tc != NULL, ("esp_output_cb: null opaque data area!"));
|
||||
m = (struct mbuf *) crp->crp_buf;
|
||||
|
||||
s = splsoftnet();
|
||||
|
||||
isr = tc->tc_isr;
|
||||
sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
|
||||
if (sav == NULL) {
|
||||
espstat.esps_notdb++;
|
||||
DPRINTF(("esp_output_cb: SA expired while in crypto "
|
||||
"(SA %s/%08lx proto %u)\n", ipsec_address(&tc->tc_dst),
|
||||
(u_long) ntohl(tc->tc_spi), tc->tc_proto));
|
||||
error = ENOBUFS; /*XXX*/
|
||||
goto bad;
|
||||
}
|
||||
IPSEC_ASSERT(isr->sav == sav,
|
||||
("esp_output_cb: SA changed was %p now %p\n", isr->sav, sav));
|
||||
|
||||
/* Check for crypto errors. */
|
||||
if (crp->crp_etype) {
|
||||
/* Reset session ID. */
|
||||
if (sav->tdb_cryptoid != 0)
|
||||
sav->tdb_cryptoid = crp->crp_sid;
|
||||
|
||||
if (crp->crp_etype == EAGAIN) {
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return crypto_dispatch(crp);
|
||||
}
|
||||
|
||||
espstat.esps_noxform++;
|
||||
DPRINTF(("esp_output_cb: crypto error %d\n", crp->crp_etype));
|
||||
error = crp->crp_etype;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Shouldn't happen... */
|
||||
if (m == NULL) {
|
||||
espstat.esps_crypto++;
|
||||
DPRINTF(("esp_output_cb: bogus returned buffer from crypto\n"));
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
espstat.esps_hist[sav->alg_enc]++;
|
||||
if (sav->tdb_authalgxform != NULL)
|
||||
ahstat.ahs_hist[sav->alg_auth]++;
|
||||
|
||||
/* Release crypto descriptors. */
|
||||
free(tc, M_XDATA);
|
||||
crypto_freereq(crp);
|
||||
|
||||
/* NB: m is reclaimed by ipsec_process_done. */
|
||||
err = ipsec_process_done(m, isr);
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return err;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
if (m)
|
||||
m_freem(m);
|
||||
free(tc, M_XDATA);
|
||||
crypto_freereq(crp);
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct xformsw esp_xformsw = {
|
||||
XF_ESP, XFT_CONF|XFT_AUTH, "IPsec ESP",
|
||||
esp_init, esp_zeroize, esp_input,
|
||||
esp_output
|
||||
};
|
||||
|
||||
INITFN void
|
||||
esp_attach(void)
|
||||
{
|
||||
#define MAXIV(xform) \
|
||||
if (xform.blocksize > esp_max_ivlen) \
|
||||
esp_max_ivlen = xform.blocksize \
|
||||
|
||||
esp_max_ivlen = 0;
|
||||
MAXIV(enc_xform_des); /* SADB_EALG_DESCBC */
|
||||
MAXIV(enc_xform_3des); /* SADB_EALG_3DESCBC */
|
||||
MAXIV(enc_xform_rijndael128); /* SADB_X_EALG_AES */
|
||||
MAXIV(enc_xform_blf); /* SADB_X_EALG_BLOWFISHCBC */
|
||||
MAXIV(enc_xform_cast5); /* SADB_X_EALG_CAST128CBC */
|
||||
MAXIV(enc_xform_skipjack); /* SADB_X_EALG_SKIPJACK */
|
||||
MAXIV(enc_xform_null); /* SADB_EALG_NULL */
|
||||
|
||||
xform_register(&esp_xformsw);
|
||||
#undef MAXIV
|
||||
}
|
||||
#ifdef __FreeBSD__
|
||||
SYSINIT(esp_xform_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, esp_attach, NULL)
|
||||
#else
|
||||
#endif
|
|
@ -0,0 +1,614 @@
|
|||
/* $NetBSD: xform_ipcomp.c,v 1.1 2003/08/13 20:06:52 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/xform_ipcomp.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $OpenBSD: ip_ipcomp.c,v 1.1 2001/07/05 12:08:52 jjbg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
|
||||
*
|
||||
* 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. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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>
|
||||
__KERNEL_RCSID(0, "$NetBSD: xform_ipcomp.c,v 1.1 2003/08/13 20:06:52 jonathan Exp $");
|
||||
|
||||
/* IP payload compression protocol (IPComp), see RFC 2393 */
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
|
||||
#include <net/route.h>
|
||||
#include <netipsec/ipsec.h>
|
||||
#include <netipsec/xform.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netipsec/ipsec6.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/ipcomp.h>
|
||||
#include <netipsec/ipcomp_var.h>
|
||||
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
|
||||
#include <opencrypto/cryptodev.h>
|
||||
#include <opencrypto/deflate.h>
|
||||
#include <opencrypto/xform.h>
|
||||
|
||||
int ipcomp_enable = 0;
|
||||
struct ipcompstat ipcompstat;
|
||||
|
||||
#ifdef __freeBSD__
|
||||
SYSCTL_DECL(_net_inet_ipcomp);
|
||||
SYSCTL_INT(_net_inet_ipcomp, OID_AUTO,
|
||||
ipcomp_enable, CTLFLAG_RW, &ipcomp_enable, 0, "");
|
||||
SYSCTL_STRUCT(_net_inet_ipcomp, IPSECCTL_STATS,
|
||||
stats, CTLFLAG_RD, &ipcompstat, ipcompstat, "");
|
||||
#endif __FreeBSD__
|
||||
|
||||
static int ipcomp_input_cb(struct cryptop *crp);
|
||||
static int ipcomp_output_cb(struct cryptop *crp);
|
||||
|
||||
struct comp_algo *
|
||||
ipcomp_algorithm_lookup(int alg)
|
||||
{
|
||||
if (alg >= IPCOMP_ALG_MAX)
|
||||
return NULL;
|
||||
switch (alg) {
|
||||
case SADB_X_CALG_DEFLATE:
|
||||
return &comp_algo_deflate;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipcomp_init() is called when an CPI is being set up.
|
||||
*/
|
||||
static int
|
||||
ipcomp_init(struct secasvar *sav, struct xformsw *xsp)
|
||||
{
|
||||
struct comp_algo *tcomp;
|
||||
struct cryptoini cric;
|
||||
|
||||
/* NB: algorithm really comes in alg_enc and not alg_comp! */
|
||||
tcomp = ipcomp_algorithm_lookup(sav->alg_enc);
|
||||
if (tcomp == NULL) {
|
||||
DPRINTF(("ipcomp_init: unsupported compression algorithm %d\n",
|
||||
sav->alg_comp));
|
||||
return EINVAL;
|
||||
}
|
||||
sav->alg_comp = sav->alg_enc; /* set for doing histogram */
|
||||
sav->tdb_xform = xsp;
|
||||
sav->tdb_compalgxform = tcomp;
|
||||
|
||||
/* Initialize crypto session */
|
||||
bzero(&cric, sizeof (cric));
|
||||
cric.cri_alg = sav->tdb_compalgxform->type;
|
||||
|
||||
return crypto_newsession(&sav->tdb_cryptoid, &cric, crypto_support);
|
||||
}
|
||||
|
||||
/*
|
||||
* ipcomp_zeroize() used when IPCA is deleted
|
||||
*/
|
||||
static int
|
||||
ipcomp_zeroize(struct secasvar *sav)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = crypto_freesession(sav->tdb_cryptoid);
|
||||
sav->tdb_cryptoid = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipcomp_input() gets called to uncompress an input packet
|
||||
*/
|
||||
static int
|
||||
ipcomp_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
|
||||
{
|
||||
struct tdb_crypto *tc;
|
||||
struct cryptodesc *crdc;
|
||||
struct cryptop *crp;
|
||||
int hlen = IPCOMP_HLENGTH;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("ipcomp_input");
|
||||
|
||||
/* Get crypto descriptors */
|
||||
crp = crypto_getreq(1);
|
||||
if (crp == NULL) {
|
||||
m_freem(m);
|
||||
DPRINTF(("ipcomp_input: no crypto descriptors\n"));
|
||||
ipcompstat.ipcomps_crypto++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
/* Get IPsec-specific opaque pointer */
|
||||
tc = (struct tdb_crypto *) malloc(sizeof (*tc), M_XDATA, M_NOWAIT|M_ZERO);
|
||||
if (tc == NULL) {
|
||||
m_freem(m);
|
||||
crypto_freereq(crp);
|
||||
DPRINTF(("ipcomp_input: cannot allocate tdb_crypto\n"));
|
||||
ipcompstat.ipcomps_crypto++;
|
||||
return ENOBUFS;
|
||||
}
|
||||
crdc = crp->crp_desc;
|
||||
|
||||
crdc->crd_skip = skip + hlen;
|
||||
crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
|
||||
crdc->crd_inject = skip;
|
||||
|
||||
tc->tc_ptr = 0;
|
||||
|
||||
/* Decompression operation */
|
||||
crdc->crd_alg = sav->tdb_compalgxform->type;
|
||||
|
||||
/* Crypto operation descriptor */
|
||||
crp->crp_ilen = m->m_pkthdr.len - (skip + hlen);
|
||||
crp->crp_flags = CRYPTO_F_IMBUF;
|
||||
crp->crp_buf = (caddr_t) m;
|
||||
crp->crp_callback = ipcomp_input_cb;
|
||||
crp->crp_sid = sav->tdb_cryptoid;
|
||||
crp->crp_opaque = (caddr_t) tc;
|
||||
|
||||
/* These are passed as-is to the callback */
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = sav->sah->saidx.dst;
|
||||
tc->tc_proto = sav->sah->saidx.proto;
|
||||
tc->tc_protoff = protoff;
|
||||
tc->tc_skip = skip;
|
||||
|
||||
return crypto_dispatch(crp);
|
||||
}
|
||||
|
||||
#ifdef INET6
|
||||
#define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) do { \
|
||||
if (saidx->dst.sa.sa_family == AF_INET6) { \
|
||||
error = ipsec6_common_input_cb(m, sav, skip, protoff, mtag); \
|
||||
} else { \
|
||||
error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, mtag) \
|
||||
(error = ipsec4_common_input_cb(m, sav, skip, protoff, mtag))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IPComp input callback from the crypto driver.
|
||||
*/
|
||||
static int
|
||||
ipcomp_input_cb(struct cryptop *crp)
|
||||
{
|
||||
struct cryptodesc *crd;
|
||||
struct tdb_crypto *tc;
|
||||
int skip, protoff;
|
||||
struct mtag *mtag;
|
||||
struct mbuf *m;
|
||||
struct secasvar *sav;
|
||||
struct secasindex *saidx;
|
||||
int s, hlen = IPCOMP_HLENGTH, error, clen;
|
||||
u_int8_t nproto;
|
||||
caddr_t addr;
|
||||
|
||||
crd = crp->crp_desc;
|
||||
|
||||
tc = (struct tdb_crypto *) crp->crp_opaque;
|
||||
IPSEC_ASSERT(tc != NULL, ("ipcomp_input_cb: null opaque crypto data area!"));
|
||||
skip = tc->tc_skip;
|
||||
protoff = tc->tc_protoff;
|
||||
mtag = (struct mtag *) tc->tc_ptr;
|
||||
m = (struct mbuf *) crp->crp_buf;
|
||||
|
||||
s = splsoftnet();
|
||||
|
||||
sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
|
||||
if (sav == NULL) {
|
||||
ipcompstat.ipcomps_notdb++;
|
||||
DPRINTF(("ipcomp_input_cb: SA expired while in crypto\n"));
|
||||
error = ENOBUFS; /*XXX*/
|
||||
goto bad;
|
||||
}
|
||||
|
||||
saidx = &sav->sah->saidx;
|
||||
IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET ||
|
||||
saidx->dst.sa.sa_family == AF_INET6,
|
||||
("ah_input_cb: unexpected protocol family %u",
|
||||
saidx->dst.sa.sa_family));
|
||||
|
||||
/* Check for crypto errors */
|
||||
if (crp->crp_etype) {
|
||||
/* Reset the session ID */
|
||||
if (sav->tdb_cryptoid != 0)
|
||||
sav->tdb_cryptoid = crp->crp_sid;
|
||||
|
||||
if (crp->crp_etype == EAGAIN) {
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return crypto_dispatch(crp);
|
||||
}
|
||||
|
||||
ipcompstat.ipcomps_noxform++;
|
||||
DPRINTF(("ipcomp_input_cb: crypto error %d\n", crp->crp_etype));
|
||||
error = crp->crp_etype;
|
||||
goto bad;
|
||||
}
|
||||
/* Shouldn't happen... */
|
||||
if (m == NULL) {
|
||||
ipcompstat.ipcomps_crypto++;
|
||||
DPRINTF(("ipcomp_input_cb: null mbuf returned from crypto\n"));
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
ipcompstat.ipcomps_hist[sav->alg_comp]++;
|
||||
|
||||
clen = crp->crp_olen; /* Length of data after processing */
|
||||
|
||||
/* Release the crypto descriptors */
|
||||
free(tc, M_XDATA), tc = NULL;
|
||||
crypto_freereq(crp), crp = NULL;
|
||||
|
||||
/* In case it's not done already, adjust the size of the mbuf chain */
|
||||
m->m_pkthdr.len = clen + hlen + skip;
|
||||
|
||||
if (m->m_len < skip + hlen && (m = m_pullup(m, skip + hlen)) == 0) {
|
||||
ipcompstat.ipcomps_hdrops++; /*XXX*/
|
||||
DPRINTF(("ipcomp_input_cb: m_pullup failed\n"));
|
||||
error = EINVAL; /*XXX*/
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Keep the next protocol field */
|
||||
addr = (caddr_t) mtod(m, struct ip *) + skip;
|
||||
nproto = ((struct ipcomp *) addr)->comp_nxt;
|
||||
|
||||
/* Remove the IPCOMP header */
|
||||
error = m_striphdr(m, skip, hlen);
|
||||
if (error) {
|
||||
ipcompstat.ipcomps_hdrops++;
|
||||
DPRINTF(("ipcomp_input_cb: bad mbuf chain, IPCA %s/%08lx\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Restore the Next Protocol field */
|
||||
m_copyback(m, protoff, sizeof (u_int8_t), (u_int8_t *) &nproto);
|
||||
|
||||
IPSEC_COMMON_INPUT_CB(m, sav, skip, protoff, NULL);
|
||||
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return error;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
if (m)
|
||||
m_freem(m);
|
||||
if (tc != NULL)
|
||||
free(tc, M_XDATA);
|
||||
if (crp)
|
||||
crypto_freereq(crp);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* IPComp output routine, called by ipsec[46]_process_packet()
|
||||
*/
|
||||
static int
|
||||
ipcomp_output(
|
||||
struct mbuf *m,
|
||||
struct ipsecrequest *isr,
|
||||
struct mbuf **mp,
|
||||
int skip,
|
||||
int protoff
|
||||
)
|
||||
{
|
||||
struct secasvar *sav;
|
||||
struct comp_algo *ipcompx;
|
||||
int error, ralen, hlen, maxpacketsize, roff;
|
||||
u_int8_t prot;
|
||||
struct cryptodesc *crdc;
|
||||
struct cryptop *crp;
|
||||
struct tdb_crypto *tc;
|
||||
struct mbuf *mo;
|
||||
struct ipcomp *ipcomp;
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("ipcomp_output");
|
||||
sav = isr->sav;
|
||||
IPSEC_ASSERT(sav != NULL, ("ipcomp_output: null SA"));
|
||||
ipcompx = sav->tdb_compalgxform;
|
||||
IPSEC_ASSERT(ipcompx != NULL, ("ipcomp_output: null compression xform"));
|
||||
|
||||
ralen = m->m_pkthdr.len - skip; /* Raw payload length before comp. */
|
||||
hlen = IPCOMP_HLENGTH;
|
||||
|
||||
ipcompstat.ipcomps_output++;
|
||||
|
||||
/* Check for maximum packet size violations. */
|
||||
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
maxpacketsize = IP_MAXPACKET;
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
maxpacketsize = IPV6_MAXPACKET;
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
ipcompstat.ipcomps_nopf++;
|
||||
DPRINTF(("ipcomp_output: unknown/unsupported protocol family %d"
|
||||
", IPCA %s/%08lx\n",
|
||||
sav->sah->saidx.dst.sa.sa_family,
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
error = EPFNOSUPPORT;
|
||||
goto bad;
|
||||
}
|
||||
if (skip + hlen + ralen > maxpacketsize) {
|
||||
ipcompstat.ipcomps_toobig++;
|
||||
DPRINTF(("ipcomp_output: packet in IPCA %s/%08lx got too big "
|
||||
"(len %u, max len %u)\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi),
|
||||
skip + hlen + ralen, maxpacketsize));
|
||||
error = EMSGSIZE;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Update the counters */
|
||||
ipcompstat.ipcomps_obytes += m->m_pkthdr.len - skip;
|
||||
|
||||
m = m_clone(m);
|
||||
if (m == NULL) {
|
||||
ipcompstat.ipcomps_hdrops++;
|
||||
DPRINTF(("ipcomp_output: cannot clone mbuf chain, IPCA %s/%08lx\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Inject IPCOMP header */
|
||||
mo = m_makespace(m, skip, hlen, &roff);
|
||||
if (mo == NULL) {
|
||||
ipcompstat.ipcomps_wrap++;
|
||||
DPRINTF(("ipcomp_output: failed to inject IPCOMP header for "
|
||||
"IPCA %s/%08lx\n",
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
ipcomp = (struct ipcomp *)(mtod(mo, caddr_t) + roff);
|
||||
|
||||
/* Initialize the IPCOMP header */
|
||||
/* XXX alignment always correct? */
|
||||
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
ipcomp->comp_nxt = mtod(m, struct ip *)->ip_p;
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ipcomp->comp_nxt = mtod(m, struct ip6_hdr *)->ip6_nxt;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
ipcomp->comp_flags = 0;
|
||||
ipcomp->comp_cpi = htons((u_int16_t) ntohl(sav->spi));
|
||||
|
||||
/* Fix Next Protocol in IPv4/IPv6 header */
|
||||
prot = IPPROTO_IPCOMP;
|
||||
m_copyback(m, protoff, sizeof(u_int8_t), (u_char *) &prot);
|
||||
|
||||
/* Ok now, we can pass to the crypto processing */
|
||||
|
||||
/* Get crypto descriptors */
|
||||
crp = crypto_getreq(1);
|
||||
if (crp == NULL) {
|
||||
ipcompstat.ipcomps_crypto++;
|
||||
DPRINTF(("ipcomp_output: failed to acquire crypto descriptor\n"));
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
crdc = crp->crp_desc;
|
||||
|
||||
/* Compression descriptor */
|
||||
crdc->crd_skip = skip + hlen;
|
||||
crdc->crd_len = m->m_pkthdr.len - (skip + hlen);
|
||||
crdc->crd_flags = CRD_F_COMP;
|
||||
crdc->crd_inject = skip + hlen;
|
||||
|
||||
/* Compression operation */
|
||||
crdc->crd_alg = ipcompx->type;
|
||||
|
||||
/* IPsec-specific opaque crypto info */
|
||||
tc = (struct tdb_crypto *) malloc(sizeof(struct tdb_crypto),
|
||||
M_XDATA, M_NOWAIT|M_ZERO);
|
||||
if (tc == NULL) {
|
||||
ipcompstat.ipcomps_crypto++;
|
||||
DPRINTF(("ipcomp_output: failed to allocate tdb_crypto\n"));
|
||||
crypto_freereq(crp);
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
tc->tc_isr = isr;
|
||||
tc->tc_spi = sav->spi;
|
||||
tc->tc_dst = sav->sah->saidx.dst;
|
||||
tc->tc_proto = sav->sah->saidx.proto;
|
||||
tc->tc_skip = skip + hlen;
|
||||
|
||||
/* Crypto operation descriptor */
|
||||
crp->crp_ilen = m->m_pkthdr.len; /* Total input length */
|
||||
crp->crp_flags = CRYPTO_F_IMBUF;
|
||||
crp->crp_buf = (caddr_t) m;
|
||||
crp->crp_callback = ipcomp_output_cb;
|
||||
crp->crp_opaque = (caddr_t) tc;
|
||||
crp->crp_sid = sav->tdb_cryptoid;
|
||||
|
||||
return crypto_dispatch(crp);
|
||||
bad:
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* IPComp output callback from the crypto driver.
|
||||
*/
|
||||
static int
|
||||
ipcomp_output_cb(struct cryptop *crp)
|
||||
{
|
||||
struct tdb_crypto *tc;
|
||||
struct ipsecrequest *isr;
|
||||
struct secasvar *sav;
|
||||
struct mbuf *m;
|
||||
int s, error, skip, rlen;
|
||||
|
||||
tc = (struct tdb_crypto *) crp->crp_opaque;
|
||||
IPSEC_ASSERT(tc != NULL, ("ipcomp_output_cb: null opaque data area!"));
|
||||
m = (struct mbuf *) crp->crp_buf;
|
||||
skip = tc->tc_skip;
|
||||
rlen = crp->crp_ilen - skip;
|
||||
|
||||
s = splsoftnet();
|
||||
|
||||
isr = tc->tc_isr;
|
||||
sav = KEY_ALLOCSA(&tc->tc_dst, tc->tc_proto, tc->tc_spi);
|
||||
if (sav == NULL) {
|
||||
ipcompstat.ipcomps_notdb++;
|
||||
DPRINTF(("ipcomp_output_cb: SA expired while in crypto\n"));
|
||||
error = ENOBUFS; /*XXX*/
|
||||
goto bad;
|
||||
}
|
||||
IPSEC_ASSERT(isr->sav == sav, ("ipcomp_output_cb: SA changed\n"));
|
||||
|
||||
/* Check for crypto errors */
|
||||
if (crp->crp_etype) {
|
||||
/* Reset session ID */
|
||||
if (sav->tdb_cryptoid != 0)
|
||||
sav->tdb_cryptoid = crp->crp_sid;
|
||||
|
||||
if (crp->crp_etype == EAGAIN) {
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return crypto_dispatch(crp);
|
||||
}
|
||||
ipcompstat.ipcomps_noxform++;
|
||||
DPRINTF(("ipcomp_output_cb: crypto error %d\n", crp->crp_etype));
|
||||
error = crp->crp_etype;
|
||||
goto bad;
|
||||
}
|
||||
/* Shouldn't happen... */
|
||||
if (m == NULL) {
|
||||
ipcompstat.ipcomps_crypto++;
|
||||
DPRINTF(("ipcomp_output_cb: bogus return buffer from crypto\n"));
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
ipcompstat.ipcomps_hist[sav->alg_comp]++;
|
||||
|
||||
if (rlen > crp->crp_olen) {
|
||||
/* Adjust the length in the IP header */
|
||||
switch (sav->sah->saidx.dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
mtod(m, struct ip6_hdr *)->ip6_plen =
|
||||
htons(m->m_pkthdr.len) - sizeof(struct ip6_hdr);
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
default:
|
||||
ipcompstat.ipcomps_nopf++;
|
||||
DPRINTF(("ipcomp_output: unknown/unsupported protocol "
|
||||
"family %d, IPCA %s/%08lx\n",
|
||||
sav->sah->saidx.dst.sa.sa_family,
|
||||
ipsec_address(&sav->sah->saidx.dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
error = EPFNOSUPPORT;
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
/* compression was useless, we have lost time */
|
||||
/* XXX add statistic */
|
||||
}
|
||||
|
||||
/* Release the crypto descriptor */
|
||||
free(tc, M_XDATA);
|
||||
crypto_freereq(crp);
|
||||
|
||||
/* NB: m is reclaimed by ipsec_process_done. */
|
||||
error = ipsec_process_done(m, isr);
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
return error;
|
||||
bad:
|
||||
if (sav)
|
||||
KEY_FREESAV(&sav);
|
||||
splx(s);
|
||||
if (m)
|
||||
m_freem(m);
|
||||
free(tc, M_XDATA);
|
||||
crypto_freereq(crp);
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct xformsw ipcomp_xformsw = {
|
||||
XF_IPCOMP, XFT_COMP, "IPcomp",
|
||||
ipcomp_init, ipcomp_zeroize, ipcomp_input,
|
||||
ipcomp_output
|
||||
};
|
||||
|
||||
INITFN void
|
||||
ipcomp_attach(void)
|
||||
{
|
||||
xform_register(&ipcomp_xformsw);
|
||||
}
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
SYSINIT(ipcomp_xform_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, ipcomp_attach, NULL)
|
||||
#endif __FreeBSD__
|
|
@ -0,0 +1,728 @@
|
|||
/* $NetBSD: xform_ipip.c,v 1.1 2003/08/13 20:06:52 jonathan Exp $ */
|
||||
/* $FreeBSD: src/sys/netipsec/xform_ipip.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $ */
|
||||
/* $OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
|
||||
|
||||
/*
|
||||
* The authors of this code are John Ioannidis (ji@tla.org),
|
||||
* Angelos D. Keromytis (kermit@csd.uch.gr) and
|
||||
* Niels Provos (provos@physnet.uni-hamburg.de).
|
||||
*
|
||||
* The original version of this code was written by John Ioannidis
|
||||
* for BSD/OS in Athens, Greece, in November 1995.
|
||||
*
|
||||
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
|
||||
* by Angelos D. Keromytis.
|
||||
*
|
||||
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
|
||||
* and Niels Provos.
|
||||
*
|
||||
* Additional features in 1999 by Angelos D. Keromytis.
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
|
||||
* Angelos D. Keromytis and Niels Provos.
|
||||
* Copyright (c) 2001, Angelos D. Keromytis.
|
||||
*
|
||||
* Permission to use, copy, and modify this software with or without fee
|
||||
* is hereby granted, provided that this entire notice is included in
|
||||
* all copies of any software which is or includes a copy or
|
||||
* modification of this software.
|
||||
* You may use this code under the GNU public license if you so wish. Please
|
||||
* contribute changes back to the authors under this freer than GPL license
|
||||
* so that we may further the use of strong encryption without limitations to
|
||||
* all.
|
||||
*
|
||||
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
|
||||
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
||||
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
||||
* PURPOSE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.1 2003/08/13 20:06:52 jonathan Exp $");
|
||||
|
||||
/*
|
||||
* IP-inside-IP processing
|
||||
*/
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
#ifdef __FreeBSD__
|
||||
#include "opt_random_ip_id.h"
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/netisr.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_ecn.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_encap.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <netinet/ipprotosw.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/ipsec.h>
|
||||
#include <netipsec/xform.h>
|
||||
|
||||
#include <netipsec/ipip_var.h>
|
||||
|
||||
#ifdef MROUTING
|
||||
#include <netinet/ip_mroute.h>
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netipsec/ipsec6.h>
|
||||
#include <netinet6/ip6_ecn.h>
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <netinet6/ip6protosw.h>
|
||||
#endif
|
||||
|
||||
#include <netipsec/key.h>
|
||||
#include <netipsec/key_debug.h>
|
||||
#include <netipsec/ipsec_osdep.h>
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
typedef void pr_in_input_t (struct mbuf *, int, int); /* XXX FIX THIS */
|
||||
#else
|
||||
typedef void pr_in_input_t (struct mbuf *m, ...);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We can control the acceptance of IP4 packets by altering the sysctl
|
||||
* net.inet.ipip.allow value. Zero means drop them, all else is acceptance.
|
||||
*/
|
||||
int ipip_allow = 0;
|
||||
struct ipipstat ipipstat;
|
||||
|
||||
#ifdef SYSCTL_DECL
|
||||
SYSCTL_DECL(_net_inet_ipip);
|
||||
|
||||
SYSCTL_INT(_net_inet_ipip, OID_AUTO,
|
||||
ipip_allow, CTLFLAG_RW, &ipip_allow, 0, "");
|
||||
SYSCTL_STRUCT(_net_inet_ipip, IPSECCTL_STATS,
|
||||
stats, CTLFLAG_RD, &ipipstat, ipipstat, "");
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static
|
||||
#endif
|
||||
void ipe4_attach(void);
|
||||
|
||||
|
||||
/* XXX IPCOMP */
|
||||
#define M_IPSEC (M_AUTHIPHDR|M_AUTHIPDGM|M_DECRYPTED)
|
||||
|
||||
static void _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp);
|
||||
|
||||
#ifdef INET6
|
||||
/*
|
||||
* Really only a wrapper for ipip_input(), for use with IPv6.
|
||||
*/
|
||||
int
|
||||
ip4_input6(struct mbuf **m, int *offp, int proto)
|
||||
{
|
||||
#if 0
|
||||
/* If we do not accept IP-in-IP explicitly, drop. */
|
||||
if (!ipip_allow && ((*m)->m_flags & M_IPSEC) == 0) {
|
||||
DPRINTF(("ip4_input6: dropped due to policy\n"));
|
||||
ipipstat.ipips_pdrops++;
|
||||
m_freem(*m);
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif
|
||||
_ipip_input(*m, *offp, NULL);
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
#ifdef INET
|
||||
/*
|
||||
* Really only a wrapper for ipip_input(), for use with IPv4.
|
||||
*/
|
||||
void
|
||||
ip4_input(struct mbuf *m, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int iphlen;
|
||||
|
||||
#if 0
|
||||
/* If we do not accept IP-in-IP explicitly, drop. */
|
||||
if (!ipip_allow && (m->m_flags & M_IPSEC) == 0) {
|
||||
DPRINTF(("ip4_input: dropped due to policy\n"));
|
||||
ipipstat.ipips_pdrops++;
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
va_start(ap, m);
|
||||
iphlen = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
_ipip_input(m, iphlen, NULL);
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
/*
|
||||
* ipip_input gets called when we receive an IP{46} encapsulated packet,
|
||||
* either because we got it at a real interface, or because AH or ESP
|
||||
* were being used in tunnel mode (in which case the rcvif element will
|
||||
* contain the address of the encX interface associated with the tunnel.
|
||||
*/
|
||||
|
||||
static void
|
||||
_ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp)
|
||||
{
|
||||
register struct sockaddr_in *sin;
|
||||
register struct ifnet *ifp;
|
||||
register struct ifaddr *ifa;
|
||||
struct ifqueue *ifq = NULL;
|
||||
struct ip *ipo;
|
||||
#ifdef INET6
|
||||
register struct sockaddr_in6 *sin6;
|
||||
struct ip6_hdr *ip6 = NULL;
|
||||
u_int8_t itos;
|
||||
#endif
|
||||
u_int8_t nxt;
|
||||
int isr;
|
||||
u_int8_t otos;
|
||||
u_int8_t v;
|
||||
int hlen;
|
||||
|
||||
ipipstat.ipips_ipackets++;
|
||||
|
||||
m_copydata(m, 0, 1, &v);
|
||||
|
||||
switch (v >> 4) {
|
||||
#ifdef INET
|
||||
case 4:
|
||||
hlen = sizeof(struct ip);
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
hlen = sizeof(struct ip6_hdr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
DPRINTF(("_ipip_input: bad protocol version 0x%x (%u) "
|
||||
"for outer header\n", v, v>>4));
|
||||
ipipstat.ipips_family++;
|
||||
m_freem(m);
|
||||
return /* EAFNOSUPPORT */;
|
||||
}
|
||||
|
||||
/* Bring the IP header in the first mbuf, if not there already */
|
||||
if (m->m_len < hlen) {
|
||||
if ((m = m_pullup(m, hlen)) == NULL) {
|
||||
DPRINTF(("ipip_input: m_pullup (1) failed\n"));
|
||||
ipipstat.ipips_hdrops++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ipo = mtod(m, struct ip *);
|
||||
|
||||
#ifdef MROUTING
|
||||
if (ipo->ip_v == IPVERSION && ipo->ip_p == IPPROTO_IPV4) {
|
||||
if (IN_MULTICAST(((struct ip *)((char *) ipo + iphlen))->ip_dst.s_addr)) {
|
||||
ipip_mroute_input (m, iphlen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* MROUTING */
|
||||
|
||||
/* Keep outer ecn field. */
|
||||
switch (v >> 4) {
|
||||
#ifdef INET
|
||||
case 4:
|
||||
otos = ipo->ip_tos;
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
panic("ipip_input: unknown ip version %u (outer)", v>>4);
|
||||
}
|
||||
|
||||
/* Remove outer IP header */
|
||||
m_adj(m, iphlen);
|
||||
|
||||
/* Sanity check */
|
||||
if (m->m_pkthdr.len < sizeof(struct ip)) {
|
||||
ipipstat.ipips_hdrops++;
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
m_copydata(m, 0, 1, &v);
|
||||
|
||||
switch (v >> 4) {
|
||||
#ifdef INET
|
||||
case 4:
|
||||
hlen = sizeof(struct ip);
|
||||
break;
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
hlen = sizeof(struct ip6_hdr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
DPRINTF(("_ipip_input: bad protocol version 0x%x (%u) "
|
||||
"for inner header\n", v, v>>4));
|
||||
ipipstat.ipips_family++;
|
||||
m_freem(m);
|
||||
return; /* EAFNOSUPPORT */
|
||||
}
|
||||
|
||||
/*
|
||||
* Bring the inner IP header in the first mbuf, if not there already.
|
||||
*/
|
||||
if (m->m_len < hlen) {
|
||||
if ((m = m_pullup(m, hlen)) == NULL) {
|
||||
DPRINTF(("ipip_input: m_pullup (2) failed\n"));
|
||||
ipipstat.ipips_hdrops++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 1853 specifies that the inner TTL should not be touched on
|
||||
* decapsulation. There's no reason this comment should be here, but
|
||||
* this is as good as any a position.
|
||||
*/
|
||||
|
||||
/* Some sanity checks in the inner IP header */
|
||||
switch (v >> 4) {
|
||||
#ifdef INET
|
||||
case 4:
|
||||
ipo = mtod(m, struct ip *);
|
||||
nxt = ipo->ip_p;
|
||||
ip_ecn_egress(ip4_ipsec_ecn, &otos, &ipo->ip_tos);
|
||||
break;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
ip6 = (struct ip6_hdr *) ipo;
|
||||
nxt = ip6->ip6_nxt;
|
||||
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
|
||||
ip_ecn_egress(ip6_ipsec_ecn, &otos, &itos);
|
||||
ip6->ip6_flow &= ~htonl(0xff << 20);
|
||||
ip6->ip6_flow |= htonl((u_int32_t) itos << 20);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
panic("ipip_input: unknown ip version %u (inner)", v>>4);
|
||||
}
|
||||
|
||||
/* Check for local address spoofing. */
|
||||
if ((m->m_pkthdr.rcvif == NULL ||
|
||||
!(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)) &&
|
||||
ipip_allow != 2) {
|
||||
for (ifp = ifnet.tqh_first; ifp != 0;
|
||||
ifp = ifp->if_list.tqe_next) {
|
||||
for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
|
||||
ifa = ifa->ifa_list.tqe_next) {
|
||||
#ifdef INET
|
||||
if (ipo) {
|
||||
if (ifa->ifa_addr->sa_family !=
|
||||
AF_INET)
|
||||
continue;
|
||||
|
||||
sin = (struct sockaddr_in *) ifa->ifa_addr;
|
||||
|
||||
if (sin->sin_addr.s_addr ==
|
||||
ipo->ip_src.s_addr) {
|
||||
ipipstat.ipips_spoof++;
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
if (ip6) {
|
||||
if (ifa->ifa_addr->sa_family !=
|
||||
AF_INET6)
|
||||
continue;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *) ifa->ifa_addr;
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_src)) {
|
||||
ipipstat.ipips_spoof++;
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* INET6 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Statistics */
|
||||
ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen;
|
||||
|
||||
/*
|
||||
* Interface pointer stays the same; if no IPsec processing has
|
||||
* been done (or will be done), this will point to a normal
|
||||
* interface. Otherwise, it'll point to an enc interface, which
|
||||
* will allow a packet filter to distinguish between secure and
|
||||
* untrusted packets.
|
||||
*/
|
||||
|
||||
switch (v >> 4) {
|
||||
#ifdef INET
|
||||
case 4:
|
||||
ifq = &ipintrq;
|
||||
isr = NETISR_IP;
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
ifq = &ip6intrq;
|
||||
isr = NETISR_IPV6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
panic("ipip_input: should never reach here");
|
||||
}
|
||||
|
||||
if (!IF_HANDOFF(ifq, m, NULL)) {
|
||||
ipipstat.ipips_qfull++;
|
||||
|
||||
DPRINTF(("ipip_input: packet dropped because of full queue\n"));
|
||||
} else {
|
||||
schednetisr(isr);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ipip_output(
|
||||
struct mbuf *m,
|
||||
struct ipsecrequest *isr,
|
||||
struct mbuf **mp,
|
||||
int skip,
|
||||
int protoff
|
||||
)
|
||||
{
|
||||
struct secasvar *sav;
|
||||
u_int8_t tp, otos;
|
||||
struct secasindex *saidx;
|
||||
int error;
|
||||
#ifdef INET
|
||||
u_int8_t itos;
|
||||
struct ip *ipo;
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
struct ip6_hdr *ip6, *ip6o;
|
||||
#endif /* INET6 */
|
||||
|
||||
IPSEC_SPLASSERT_SOFTNET("ipip_output");
|
||||
|
||||
sav = isr->sav;
|
||||
IPSEC_ASSERT(sav != NULL, ("ipip_output: null SA"));
|
||||
IPSEC_ASSERT(sav->sah != NULL, ("ipip_output: null SAH"));
|
||||
|
||||
/* XXX Deal with empty TDB source/destination addresses. */
|
||||
|
||||
m_copydata(m, 0, 1, &tp);
|
||||
tp = (tp >> 4) & 0xff; /* Get the IP version number. */
|
||||
|
||||
saidx = &sav->sah->saidx;
|
||||
switch (saidx->dst.sa.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
if (saidx->src.sa.sa_family != AF_INET ||
|
||||
saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
|
||||
saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) {
|
||||
DPRINTF(("ipip_output: unspecified tunnel endpoint "
|
||||
"address in SA %s/%08lx\n",
|
||||
ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
ipipstat.ipips_unspec++;
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
|
||||
if (m == 0) {
|
||||
DPRINTF(("ipip_output: M_PREPEND failed\n"));
|
||||
ipipstat.ipips_hdrops++;
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ipo = mtod(m, struct ip *);
|
||||
|
||||
ipo->ip_v = IPVERSION;
|
||||
ipo->ip_hl = 5;
|
||||
ipo->ip_len = htons(m->m_pkthdr.len);
|
||||
ipo->ip_ttl = ip_defttl;
|
||||
ipo->ip_sum = 0;
|
||||
ipo->ip_src = saidx->src.sin.sin_addr;
|
||||
ipo->ip_dst = saidx->dst.sin.sin_addr;
|
||||
|
||||
#ifdef RANDOM_IP_ID
|
||||
ipo->ip_id = ip_randomid();
|
||||
#else
|
||||
ipo->ip_id = htons(ip_id++);
|
||||
#endif
|
||||
|
||||
/* If the inner protocol is IP... */
|
||||
if (tp == IPVERSION) {
|
||||
/* Save ECN notification */
|
||||
m_copydata(m, sizeof(struct ip) +
|
||||
offsetof(struct ip, ip_tos),
|
||||
sizeof(u_int8_t), (caddr_t) &itos);
|
||||
|
||||
ipo->ip_p = IPPROTO_IPIP;
|
||||
|
||||
/*
|
||||
* We should be keeping tunnel soft-state and
|
||||
* send back ICMPs if needed.
|
||||
*/
|
||||
m_copydata(m, sizeof(struct ip) +
|
||||
offsetof(struct ip, ip_off),
|
||||
sizeof(u_int16_t), (caddr_t) &ipo->ip_off);
|
||||
ipo->ip_off = ntohs(ipo->ip_off);
|
||||
ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK);
|
||||
ipo->ip_off = htons(ipo->ip_off);
|
||||
}
|
||||
#ifdef INET6
|
||||
else if (tp == (IPV6_VERSION >> 4)) {
|
||||
u_int32_t itos32;
|
||||
|
||||
/* Save ECN notification. */
|
||||
m_copydata(m, sizeof(struct ip) +
|
||||
offsetof(struct ip6_hdr, ip6_flow),
|
||||
sizeof(u_int32_t), (caddr_t) &itos32);
|
||||
itos = ntohl(itos32) >> 20;
|
||||
ipo->ip_p = IPPROTO_IPV6;
|
||||
ipo->ip_off = 0;
|
||||
}
|
||||
#endif /* INET6 */
|
||||
else {
|
||||
goto nofamily;
|
||||
}
|
||||
|
||||
otos = 0;
|
||||
ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
|
||||
ipo->ip_tos = otos;
|
||||
break;
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) ||
|
||||
saidx->src.sa.sa_family != AF_INET6 ||
|
||||
IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) {
|
||||
DPRINTF(("ipip_output: unspecified tunnel endpoint "
|
||||
"address in SA %s/%08lx\n",
|
||||
ipsec_address(&saidx->dst),
|
||||
(u_long) ntohl(sav->spi)));
|
||||
ipipstat.ipips_unspec++;
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* scoped address handling */
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
|
||||
ip6->ip6_src.s6_addr16[1] = 0;
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
|
||||
ip6->ip6_dst.s6_addr16[1] = 0;
|
||||
|
||||
M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
|
||||
if (m == 0) {
|
||||
DPRINTF(("ipip_output: M_PREPEND failed\n"));
|
||||
ipipstat.ipips_hdrops++;
|
||||
*mp = NULL;
|
||||
error = ENOBUFS;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Initialize IPv6 header */
|
||||
ip6o = mtod(m, struct ip6_hdr *);
|
||||
ip6o->ip6_flow = 0;
|
||||
ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
|
||||
ip6o->ip6_vfc |= IPV6_VERSION;
|
||||
ip6o->ip6_plen = htons(m->m_pkthdr.len);
|
||||
ip6o->ip6_hlim = ip_defttl;
|
||||
ip6o->ip6_dst = saidx->dst.sin6.sin6_addr;
|
||||
ip6o->ip6_src = saidx->src.sin6.sin6_addr;
|
||||
|
||||
#ifdef INET
|
||||
if (tp == IPVERSION) {
|
||||
/* Save ECN notification */
|
||||
m_copydata(m, sizeof(struct ip6_hdr) +
|
||||
offsetof(struct ip, ip_tos), sizeof(u_int8_t),
|
||||
(caddr_t) &itos);
|
||||
|
||||
/* This is really IPVERSION. */
|
||||
ip6o->ip6_nxt = IPPROTO_IPIP;
|
||||
} else
|
||||
#endif /* INET */
|
||||
if (tp == (IPV6_VERSION >> 4)) {
|
||||
u_int32_t itos32;
|
||||
|
||||
/* Save ECN notification. */
|
||||
m_copydata(m, sizeof(struct ip6_hdr) +
|
||||
offsetof(struct ip6_hdr, ip6_flow),
|
||||
sizeof(u_int32_t), (caddr_t) &itos32);
|
||||
itos = ntohl(itos32) >> 20;
|
||||
|
||||
ip6o->ip6_nxt = IPPROTO_IPV6;
|
||||
} else {
|
||||
goto nofamily;
|
||||
}
|
||||
|
||||
otos = 0;
|
||||
ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
|
||||
ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
|
||||
break;
|
||||
#endif /* INET6 */
|
||||
|
||||
default:
|
||||
nofamily:
|
||||
DPRINTF(("ipip_output: unsupported protocol family %u\n",
|
||||
saidx->dst.sa.sa_family));
|
||||
ipipstat.ipips_family++;
|
||||
error = EAFNOSUPPORT; /* XXX diffs from openbsd */
|
||||
goto bad;
|
||||
}
|
||||
|
||||
ipipstat.ipips_opackets++;
|
||||
*mp = m;
|
||||
|
||||
#ifdef INET
|
||||
if (saidx->dst.sa.sa_family == AF_INET) {
|
||||
#if 0
|
||||
if (sav->tdb_xform->xf_type == XF_IP4)
|
||||
tdb->tdb_cur_bytes +=
|
||||
m->m_pkthdr.len - sizeof(struct ip);
|
||||
#endif
|
||||
ipipstat.ipips_obytes += m->m_pkthdr.len - sizeof(struct ip);
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
if (saidx->dst.sa.sa_family == AF_INET6) {
|
||||
#if 0
|
||||
if (sav->tdb_xform->xf_type == XF_IP4)
|
||||
tdb->tdb_cur_bytes +=
|
||||
m->m_pkthdr.len - sizeof(struct ip6_hdr);
|
||||
#endif
|
||||
ipipstat.ipips_obytes +=
|
||||
m->m_pkthdr.len - sizeof(struct ip6_hdr);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
if (m)
|
||||
m_freem(m), *mp = NULL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef FAST_IPSEC
|
||||
static int
|
||||
ipe4_init(struct secasvar *sav, struct xformsw *xsp)
|
||||
{
|
||||
sav->tdb_xform = xsp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipe4_zeroize(struct secasvar *sav)
|
||||
{
|
||||
sav->tdb_xform = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
|
||||
{
|
||||
/* This is a rather serious mistake, so no conditional printing. */
|
||||
printf("ipe4_input: should never be called\n");
|
||||
if (m)
|
||||
m_freem(m);
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static struct xformsw ipe4_xformsw = {
|
||||
XF_IP4, 0, "IPv4 Simple Encapsulation",
|
||||
ipe4_init, ipe4_zeroize, ipe4_input, ipip_output,
|
||||
};
|
||||
|
||||
extern struct domain inetdomain;
|
||||
static struct ipprotosw ipe4_protosw[] = {
|
||||
{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
|
||||
ip4_input, 0, 0, rip_ctloutput,
|
||||
rip_usrreq,
|
||||
0, 0, 0, 0,
|
||||
},
|
||||
#ifdef INET6
|
||||
{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR,
|
||||
ip4_input, 0, 0, rip_ctloutput,
|
||||
rip_usrreq,
|
||||
0, 0, 0, 0,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Check the encapsulated packet to see if we want it
|
||||
*/
|
||||
static int
|
||||
ipe4_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
{
|
||||
/*
|
||||
* Only take packets coming from IPSEC tunnels; the rest
|
||||
* must be handled by the gif tunnel code. Note that we
|
||||
* also return a minimum priority when we want the packet
|
||||
* so any explicit gif tunnels take precedence.
|
||||
*/
|
||||
return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
INITFN void
|
||||
ipe4_attach(void)
|
||||
{
|
||||
xform_register(&ipe4_xformsw);
|
||||
/* attach to encapsulation framework */
|
||||
/* XXX save return cookie for detach on module remove */
|
||||
(void) encap_attach_func(AF_INET, -1,
|
||||
ipe4_encapcheck, (struct protosw*) &ipe4_protosw[0], NULL);
|
||||
#ifdef INET6
|
||||
(void) encap_attach_func(AF_INET6, -1,
|
||||
ipe4_encapcheck, (struct protosw*) &ipe4_protosw[1], NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SYSINIT
|
||||
SYSINIT(ipe4_xform_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_MIDDLE, ipe4_attach, NULL);
|
||||
#endif
|
||||
|
||||
#endif /* FAST_IPSEC */
|
Loading…
Reference in New Issue