2006-02-25 05:28:55 +03:00
|
|
|
/* $NetBSD: ipsec.c,v 1.107 2006/02/25 02:28:58 wiz Exp $ */
|
2002-05-19 04:46:40 +04:00
|
|
|
/* $KAME: ipsec.c,v 1.136 2002/05/19 00:36:39 itojun Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-06-03 20:14:02 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* 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.
|
2000-06-03 20:14:02 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 03:56:55 +03:00
|
|
|
#include <sys/cdefs.h>
|
2006-02-25 05:28:55 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.107 2006/02/25 02:28:58 wiz Exp $");
|
2001-11-13 03:56:55 +03:00
|
|
|
|
1999-07-10 02:57:15 +04:00
|
|
|
#include "opt_inet.h"
|
|
|
|
#include "opt_ipsec.h"
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/domain.h>
|
|
|
|
#include <sys/protosw.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_var.h>
|
|
|
|
#include <netinet/in_var.h>
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/udp_var.h>
|
|
|
|
#include <netinet/ip_ecn.h>
|
2000-09-22 09:49:46 +04:00
|
|
|
#include <netinet/tcp.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
2000-09-25 19:00:08 +04:00
|
|
|
#ifdef INET6
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/ip6_var.h>
|
2000-01-31 17:18:52 +03:00
|
|
|
#endif
|
|
|
|
#include <netinet/in_pcb.h>
|
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet6/in6_pcb.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/icmp6.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
2000-01-31 17:18:52 +03:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#include <netinet6/ipsec.h>
|
|
|
|
#include <netinet6/ah.h>
|
1999-07-01 12:12:45 +04:00
|
|
|
#ifdef IPSEC_ESP
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/esp.h>
|
1999-07-01 12:12:45 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/ipcomp.h>
|
|
|
|
#include <netkey/key.h>
|
|
|
|
#include <netkey/keydb.h>
|
|
|
|
#include <netkey/key_debug.h>
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
#include <net/net_osdep.h>
|
|
|
|
|
|
|
|
#ifdef IPSEC_DEBUG
|
|
|
|
int ipsec_debug = 1;
|
|
|
|
#else
|
|
|
|
int ipsec_debug = 0;
|
|
|
|
#endif
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ipsecstat ipsecstat;
|
|
|
|
int ip4_ah_cleartos = 1;
|
|
|
|
int ip4_ah_offsetmask = 0; /* maybe IP_DF? */
|
2005-09-09 19:38:05 +04:00
|
|
|
int ip4_ipsec_dfbit = 2; /* DF bit on encap. 0: clear 1: set 2: copy */
|
1999-06-28 10:36:47 +04:00
|
|
|
int ip4_esp_trans_deflev = IPSEC_LEVEL_USE;
|
|
|
|
int ip4_esp_net_deflev = IPSEC_LEVEL_USE;
|
|
|
|
int ip4_ah_trans_deflev = IPSEC_LEVEL_USE;
|
|
|
|
int ip4_ah_net_deflev = IPSEC_LEVEL_USE;
|
2002-06-12 21:56:45 +04:00
|
|
|
struct secpolicy *ip4_def_policy;
|
1999-06-28 10:36:47 +04:00
|
|
|
int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
struct ipsecstat ipsec6stat;
|
|
|
|
int ip6_esp_trans_deflev = IPSEC_LEVEL_USE;
|
|
|
|
int ip6_esp_net_deflev = IPSEC_LEVEL_USE;
|
|
|
|
int ip6_ah_trans_deflev = IPSEC_LEVEL_USE;
|
|
|
|
int ip6_ah_net_deflev = IPSEC_LEVEL_USE;
|
2002-06-12 21:56:45 +04:00
|
|
|
struct secpolicy *ip6_def_policy;
|
1999-06-28 10:36:47 +04:00
|
|
|
int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
|
|
|
|
|
|
|
|
#endif /* INET6 */
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
u_int ipsec_spdgen = 1; /* SPD generation # */
|
|
|
|
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
static struct pf_tag *ipsec_get_tag __P((struct mbuf *));
|
|
|
|
#endif
|
2001-08-06 14:25:00 +04:00
|
|
|
static struct secpolicy *ipsec_checkpcbcache __P((struct mbuf *,
|
2002-06-12 05:47:34 +04:00
|
|
|
struct inpcbpolicy *, int));
|
2001-08-06 14:25:00 +04:00
|
|
|
static int ipsec_fillpcbcache __P((struct inpcbpolicy *, struct mbuf *,
|
|
|
|
struct secpolicy *, int));
|
|
|
|
static int ipsec_invalpcbcache __P((struct inpcbpolicy *, int));
|
2000-01-31 17:18:52 +03:00
|
|
|
static int ipsec_setspidx_mbuf
|
2002-06-12 05:47:34 +04:00
|
|
|
__P((struct secpolicyindex *, int, struct mbuf *, int));
|
2000-09-22 09:49:46 +04:00
|
|
|
static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int));
|
2002-06-12 05:47:34 +04:00
|
|
|
static void ipsec4_get_ulp __P((struct mbuf *, struct secpolicyindex *, int));
|
2000-09-22 09:49:46 +04:00
|
|
|
static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
|
|
|
|
#ifdef INET6
|
2002-06-12 05:47:34 +04:00
|
|
|
static void ipsec6_get_ulp __P((struct mbuf *, struct secpolicyindex *, int));
|
2000-09-22 09:49:46 +04:00
|
|
|
static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
|
1999-06-28 10:36:47 +04:00
|
|
|
#endif
|
2000-01-31 17:18:52 +03:00
|
|
|
static struct inpcbpolicy *ipsec_newpcbpolicy __P((void));
|
|
|
|
static void ipsec_delpcbpolicy __P((struct inpcbpolicy *));
|
2002-06-12 05:47:34 +04:00
|
|
|
#if 0
|
2002-06-11 23:39:59 +04:00
|
|
|
static int ipsec_deepcopy_pcbpolicy __P((struct inpcbpolicy *));
|
2002-06-12 05:47:34 +04:00
|
|
|
#endif
|
2002-06-12 21:56:45 +04:00
|
|
|
static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *));
|
2002-06-11 21:26:52 +04:00
|
|
|
static int ipsec_set_policy
|
|
|
|
__P((struct secpolicy **, int, caddr_t, size_t, int));
|
2002-06-12 05:47:34 +04:00
|
|
|
static int ipsec_get_policy __P((struct secpolicy *, struct mbuf **));
|
1999-06-28 10:36:47 +04:00
|
|
|
static void vshiftl __P((unsigned char *, int, int));
|
|
|
|
static int ipsec_in_reject __P((struct secpolicy *, struct mbuf *));
|
|
|
|
static size_t ipsec_hdrsiz __P((struct secpolicy *));
|
2000-10-02 07:55:41 +04:00
|
|
|
#ifdef INET
|
1999-06-28 10:36:47 +04:00
|
|
|
static struct mbuf *ipsec4_splithdr __P((struct mbuf *));
|
2000-10-02 07:55:41 +04:00
|
|
|
#endif
|
1999-07-01 12:12:45 +04:00
|
|
|
#ifdef INET6
|
1999-06-28 10:36:47 +04:00
|
|
|
static struct mbuf *ipsec6_splithdr __P((struct mbuf *));
|
1999-07-01 12:12:45 +04:00
|
|
|
#endif
|
2000-10-02 07:55:41 +04:00
|
|
|
#ifdef INET
|
2000-01-31 17:18:52 +03:00
|
|
|
static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *));
|
2000-10-02 07:55:41 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
#ifdef INET6
|
2000-01-31 17:18:52 +03:00
|
|
|
static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
|
1999-06-28 10:36:47 +04:00
|
|
|
#endif
|
2003-01-17 11:11:49 +03:00
|
|
|
static struct m_tag *ipsec_addaux __P((struct mbuf *));
|
|
|
|
static struct m_tag *ipsec_findaux __P((struct mbuf *));
|
|
|
|
static void ipsec_optaux __P((struct mbuf *, struct m_tag *));
|
2002-06-27 16:12:49 +04:00
|
|
|
#ifdef INET
|
|
|
|
static int ipsec4_checksa __P((struct ipsecrequest *,
|
|
|
|
struct ipsec_output_state *));
|
|
|
|
#endif
|
|
|
|
#ifdef INET6
|
|
|
|
static int ipsec6_checksa __P((struct ipsecrequest *,
|
|
|
|
struct ipsec_output_state *, int));
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
/*
|
|
|
|
* try to validate and use cached policy on a pcb.
|
|
|
|
*/
|
|
|
|
static struct secpolicy *
|
|
|
|
ipsec_checkpcbcache(m, pcbsp, dir)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct inpcbpolicy *pcbsp;
|
|
|
|
int dir;
|
|
|
|
{
|
|
|
|
struct secpolicyindex spidx;
|
|
|
|
|
|
|
|
switch (dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
2002-06-14 18:47:24 +04:00
|
|
|
case IPSEC_DIR_ANY:
|
2001-08-06 14:25:00 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#ifdef DIAGNOSTIC
|
2004-03-02 05:17:38 +03:00
|
|
|
if (dir >= sizeof(pcbsp->sp_cache)/sizeof(pcbsp->sp_cache[0]))
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("dir too big in ipsec_checkpcbcache");
|
|
|
|
#endif
|
|
|
|
/* SPD table change invalidates all the caches */
|
2004-03-02 05:17:38 +03:00
|
|
|
if (ipsec_spdgen != pcbsp->sp_cache[dir].cachegen) {
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(pcbsp, dir);
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-03-02 05:17:38 +03:00
|
|
|
if (!pcbsp->sp_cache[dir].cachesp)
|
2001-08-06 14:25:00 +04:00
|
|
|
return NULL;
|
2004-03-02 05:17:38 +03:00
|
|
|
if (pcbsp->sp_cache[dir].cachesp->state != IPSEC_SPSTATE_ALIVE) {
|
2002-05-19 04:46:40 +04:00
|
|
|
ipsec_invalpcbcache(pcbsp, dir);
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-03-02 05:17:38 +03:00
|
|
|
if ((pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) == 0) {
|
|
|
|
if (!pcbsp->sp_cache[dir].cachesp)
|
2001-08-06 14:25:00 +04:00
|
|
|
return NULL;
|
|
|
|
if (ipsec_setspidx(m, &spidx, 1) != 0)
|
|
|
|
return NULL;
|
2004-03-02 05:17:38 +03:00
|
|
|
if (bcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx,
|
|
|
|
sizeof(spidx))) {
|
|
|
|
if (!pcbsp->sp_cache[dir].cachesp->spidx ||
|
|
|
|
!key_cmpspidx_withmask(pcbsp->sp_cache[dir].cachesp->spidx,
|
2001-08-06 14:25:00 +04:00
|
|
|
&spidx))
|
|
|
|
return NULL;
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cache[dir].cacheidx = spidx;
|
2001-08-06 14:25:00 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* The pcb is connected, and the L4 code is sure that:
|
|
|
|
* - outgoing side uses inp_[lf]addr
|
|
|
|
* - incoming side looks up policy after inpcb lookup
|
|
|
|
* and address pair is known to be stable. We do not need
|
|
|
|
* to generate spidx again, nor check the address match again.
|
|
|
|
*
|
|
|
|
* For IPv4/v6 SOCK_STREAM sockets, this assumption holds
|
|
|
|
* and there are calls to ipsec_pcbconn() from in_pcbconnect().
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cache[dir].cachesp->lastused = mono_time.tv_sec;
|
|
|
|
pcbsp->sp_cache[dir].cachesp->refcnt++;
|
2001-08-06 14:25:00 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec_checkpcbcache cause refcnt++:%d SP:%p\n",
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cache[dir].cachesp->refcnt,
|
|
|
|
pcbsp->sp_cache[dir].cachesp));
|
|
|
|
return pcbsp->sp_cache[dir].cachesp;
|
2001-08-06 14:25:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipsec_fillpcbcache(pcbsp, m, sp, dir)
|
|
|
|
struct inpcbpolicy *pcbsp;
|
|
|
|
struct mbuf *m;
|
|
|
|
struct secpolicy *sp;
|
|
|
|
int dir;
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#ifdef DIAGNOSTIC
|
2004-03-02 05:17:38 +03:00
|
|
|
if (dir >= sizeof(pcbsp->sp_cache)/sizeof(pcbsp->sp_cache[0]))
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("dir too big in ipsec_checkpcbcache");
|
|
|
|
#endif
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
if (pcbsp->sp_cache[dir].cachesp)
|
|
|
|
key_freesp(pcbsp->sp_cache[dir].cachesp);
|
|
|
|
pcbsp->sp_cache[dir].cachesp = NULL;
|
|
|
|
pcbsp->sp_cache[dir].cachehint = IPSEC_PCBHINT_MAYBE;
|
|
|
|
if (ipsec_setspidx(m, &pcbsp->sp_cache[dir].cacheidx, 1) != 0) {
|
2001-08-06 14:25:00 +04:00
|
|
|
return EINVAL;
|
|
|
|
}
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cache[dir].cachesp = sp;
|
|
|
|
if (pcbsp->sp_cache[dir].cachesp) {
|
|
|
|
pcbsp->sp_cache[dir].cachesp->refcnt++;
|
2001-08-06 14:25:00 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec_fillpcbcache cause refcnt++:%d SP:%p\n",
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cache[dir].cachesp->refcnt,
|
|
|
|
pcbsp->sp_cache[dir].cachesp));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the PCB is connected, we can remember a hint to
|
|
|
|
* possibly short-circuit IPsec processing in other places.
|
|
|
|
*/
|
|
|
|
if (pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) {
|
|
|
|
switch (pcbsp->sp_cache[dir].cachesp->policy) {
|
|
|
|
case IPSEC_POLICY_NONE:
|
|
|
|
case IPSEC_POLICY_BYPASS:
|
|
|
|
pcbsp->sp_cache[dir].cachehint =
|
|
|
|
IPSEC_PCBHINT_NO;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pcbsp->sp_cache[dir].cachehint =
|
|
|
|
IPSEC_PCBHINT_YES;
|
|
|
|
}
|
|
|
|
}
|
2001-08-06 14:25:00 +04:00
|
|
|
}
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cache[dir].cachegen = ipsec_spdgen;
|
2001-08-06 14:25:00 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ipsec_invalpcbcache(pcbsp, dir)
|
|
|
|
struct inpcbpolicy *pcbsp;
|
|
|
|
int dir;
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) {
|
|
|
|
if (dir != IPSEC_DIR_ANY && i != dir)
|
|
|
|
continue;
|
2004-03-02 05:17:38 +03:00
|
|
|
if (pcbsp->sp_cache[i].cachesp)
|
|
|
|
key_freesp(pcbsp->sp_cache[i].cachesp);
|
|
|
|
pcbsp->sp_cache[i].cachesp = NULL;
|
|
|
|
pcbsp->sp_cache[i].cachehint = IPSEC_PCBHINT_MAYBE;
|
|
|
|
pcbsp->sp_cache[i].cachegen = 0;
|
|
|
|
bzero(&pcbsp->sp_cache[i].cacheidx,
|
|
|
|
sizeof(pcbsp->sp_cache[i].cacheidx));
|
2001-08-06 14:25:00 +04:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec_pcbconn(pcbsp)
|
|
|
|
struct inpcbpolicy *pcbsp;
|
|
|
|
{
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cacheflags |= IPSEC_PCBSP_CONNECTED;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec_pcbdisconn(pcbsp)
|
|
|
|
struct inpcbpolicy *pcbsp;
|
|
|
|
{
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
pcbsp->sp_cacheflags &= ~IPSEC_PCBSP_CONNECTED;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
void
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcacheall()
|
|
|
|
{
|
|
|
|
|
2004-03-02 05:17:38 +03:00
|
|
|
if (ipsec_spdgen == UINT_MAX)
|
|
|
|
ipsec_spdgen = 1;
|
|
|
|
else
|
|
|
|
ipsec_spdgen++;
|
2001-08-06 14:25:00 +04:00
|
|
|
}
|
|
|
|
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
static struct pf_tag *
|
|
|
|
ipsec_get_tag(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
struct m_tag *mtag;
|
|
|
|
|
|
|
|
if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
|
|
|
|
return ((struct pf_tag *)(mtag + 1));
|
|
|
|
else
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* For OUTBOUND packet having a socket. Searching SPD for packet,
|
|
|
|
* and return a pointer to SP.
|
|
|
|
* OUT: NULL: no apropreate SP found, the following value is set to error.
|
|
|
|
* 0 : bypass
|
|
|
|
* EACCES : discard packet.
|
|
|
|
* ENOENT : ipsec_acquire() in progress, maybe.
|
2004-02-24 18:12:51 +03:00
|
|
|
* others : error occurred.
|
1999-06-28 10:36:47 +04:00
|
|
|
* others: a pointer to SP
|
|
|
|
*
|
2006-02-25 05:28:55 +03:00
|
|
|
* NOTE: IPv6 mapped address concern is implemented here.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
struct secpolicy *
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec4_getpolicybysock(m, dir, so, error)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
u_int dir;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct socket *so;
|
|
|
|
int *error;
|
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct inpcbpolicy *pcbsp = NULL;
|
|
|
|
struct secpolicy *currsp = NULL; /* policy on socket */
|
1999-06-28 10:36:47 +04:00
|
|
|
struct secpolicy *kernsp = NULL; /* policy on kernel */
|
2002-06-12 05:47:34 +04:00
|
|
|
struct secpolicyindex spidx;
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
struct pf_tag *t;
|
|
|
|
#endif
|
|
|
|
u_int16_t tag;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
/* sanity check */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (m == NULL || so == NULL || error == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_getpolicybysock: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
switch (so->so_proto->pr_domain->dom_family) {
|
|
|
|
case AF_INET:
|
2001-08-06 14:25:00 +04:00
|
|
|
pcbsp = sotoinpcb(so)->inp_sp;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
#ifdef INET6
|
|
|
|
case AF_INET6:
|
2001-08-06 14:25:00 +04:00
|
|
|
pcbsp = sotoin6pcb(so)->in6p_sp;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
#endif
|
2002-06-11 23:39:59 +04:00
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_getpolicybysock: unsupported address family");
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2001-08-06 14:25:00 +04:00
|
|
|
|
2002-06-22 16:27:09 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (pcbsp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_getpolicybysock: pcbsp is NULL.");
|
2002-06-22 16:27:09 +04:00
|
|
|
#endif
|
|
|
|
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
t = ipsec_get_tag(m);
|
|
|
|
tag = t ? t->tag : 0;
|
|
|
|
#else
|
|
|
|
tag = 0;
|
|
|
|
#endif
|
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
/* if we have a cached entry, and if it is still valid, use it. */
|
|
|
|
ipsecstat.spdcachelookup++;
|
|
|
|
currsp = ipsec_checkpcbcache(m, pcbsp, dir);
|
|
|
|
if (currsp) {
|
|
|
|
*error = 0;
|
|
|
|
return currsp;
|
|
|
|
}
|
|
|
|
ipsecstat.spdcachemiss++;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
|
|
|
currsp = pcbsp->sp_in;
|
|
|
|
break;
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
|
|
|
currsp = pcbsp->sp_out;
|
|
|
|
break;
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_getpolicybysock: illegal direction.");
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (currsp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_getpolicybysock: currsp is NULL.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2004-01-14 02:02:00 +03:00
|
|
|
/* when privileged socket */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (pcbsp->priv) {
|
|
|
|
switch (currsp->policy) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_BYPASS:
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, currsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return currsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
2000-01-31 17:18:52 +03:00
|
|
|
/* look for a policy in SPD */
|
2002-06-22 16:04:07 +04:00
|
|
|
if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
|
2003-09-12 11:53:29 +04:00
|
|
|
(kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
/* SP found */
|
1999-06-28 10:36:47 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec4_getpolicybysock called "
|
|
|
|
"to allocate SP:%p\n", kernsp));
|
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
|
1999-06-28 10:36:47 +04:00
|
|
|
return kernsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no SP found */
|
2002-06-12 21:56:45 +04:00
|
|
|
ip4_def_policy->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2002-06-12 21:56:45 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir);
|
|
|
|
return ip4_def_policy;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, currsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return currsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
|
|
|
|
"Invalid policy for PCB %d\n", currsp->policy));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
2004-01-14 02:02:00 +03:00
|
|
|
/* when non-privileged socket */
|
2000-01-31 17:18:52 +03:00
|
|
|
/* look for a policy in SPD */
|
2002-06-22 16:04:07 +04:00
|
|
|
if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
|
2003-09-12 11:53:29 +04:00
|
|
|
(kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
/* SP found */
|
1999-06-28 10:36:47 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec4_getpolicybysock called "
|
|
|
|
"to allocate SP:%p\n", kernsp));
|
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
|
1999-06-28 10:36:47 +04:00
|
|
|
return kernsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no SP found */
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (currsp->policy) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_BYPASS:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
|
2004-01-14 02:02:00 +03:00
|
|
|
"Illegal policy for non-privileged defined %d\n",
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->policy));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
2002-06-12 21:56:45 +04:00
|
|
|
ip4_def_policy->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2002-06-12 21:56:45 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir);
|
|
|
|
return ip4_def_policy;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPSEC_POLICY_IPSEC:
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, currsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return currsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec4_getpolicybysock: "
|
|
|
|
"Invalid policy for PCB %d\n", currsp->policy));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet,
|
|
|
|
* and return a pointer to SP.
|
|
|
|
* OUT: positive: a pointer to the entry for security policy leaf matched.
|
|
|
|
* NULL: no apropreate SP found, the following value is set to error.
|
|
|
|
* 0 : bypass
|
|
|
|
* EACCES : discard packet.
|
|
|
|
* ENOENT : ipsec_acquire() in progress, maybe.
|
2004-02-24 18:12:51 +03:00
|
|
|
* others : error occurred.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
struct secpolicy *
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec4_getpolicybyaddr(m, dir, flag, error)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
u_int dir;
|
1999-06-28 10:36:47 +04:00
|
|
|
int flag;
|
|
|
|
int *error;
|
|
|
|
{
|
|
|
|
struct secpolicy *sp = NULL;
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
struct pf_tag *t;
|
|
|
|
#endif
|
|
|
|
u_int16_t tag;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL || error == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_getpolicybyaddr: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-12 05:47:34 +04:00
|
|
|
/* get a policy entry matched with the packet */
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secpolicyindex spidx;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
bzero(&spidx, sizeof(spidx));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2003-09-07 19:59:36 +04:00
|
|
|
/* make an index to look for a policy */
|
2002-06-12 05:47:34 +04:00
|
|
|
*error = ipsec_setspidx_mbuf(&spidx, AF_INET, m,
|
2000-09-22 09:49:46 +04:00
|
|
|
(flag & IP_FORWARDING) ? 0 : 1);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (*error != 0)
|
|
|
|
return NULL;
|
|
|
|
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
t = ipsec_get_tag(m);
|
|
|
|
tag = t ? t->tag : 0;
|
|
|
|
#else
|
|
|
|
tag = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sp = key_allocsp(tag, &spidx, dir);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SP found */
|
|
|
|
if (sp != NULL) {
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec4_getpolicybyaddr called "
|
|
|
|
"to allocate SP:%p\n", sp));
|
|
|
|
*error = 0;
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no SP found */
|
2002-06-12 21:56:45 +04:00
|
|
|
ip4_def_policy->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2002-06-12 21:56:45 +04:00
|
|
|
return ip4_def_policy;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
/*
|
|
|
|
* For OUTBOUND packet having a socket. Searching SPD for packet,
|
|
|
|
* and return a pointer to SP.
|
|
|
|
* OUT: NULL: no apropreate SP found, the following value is set to error.
|
|
|
|
* 0 : bypass
|
|
|
|
* EACCES : discard packet.
|
|
|
|
* ENOENT : ipsec_acquire() in progress, maybe.
|
2004-02-24 18:12:51 +03:00
|
|
|
* others : error occurred.
|
1999-06-28 10:36:47 +04:00
|
|
|
* others: a pointer to SP
|
|
|
|
*/
|
|
|
|
struct secpolicy *
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6_getpolicybysock(m, dir, so, error)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
u_int dir;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct socket *so;
|
|
|
|
int *error;
|
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct inpcbpolicy *pcbsp = NULL;
|
|
|
|
struct secpolicy *currsp = NULL; /* policy on socket */
|
|
|
|
struct secpolicy *kernsp = NULL; /* policy on kernel */
|
2002-06-12 05:47:34 +04:00
|
|
|
struct secpolicyindex spidx;
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
struct pf_tag *t;
|
|
|
|
#endif
|
|
|
|
u_int16_t tag;
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL || so == NULL || error == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_getpolicybysock: NULL pointer was passed.");
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (so->so_proto->pr_domain->dom_family != AF_INET6)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_getpolicybysock: socket domain != inet6");
|
2000-09-22 09:49:46 +04:00
|
|
|
#endif
|
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
pcbsp = sotoin6pcb(so)->in6p_sp;
|
|
|
|
|
2002-06-22 16:27:09 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (pcbsp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_getpolicybysock: pcbsp is NULL.");
|
2002-06-22 16:27:09 +04:00
|
|
|
#endif
|
|
|
|
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
t = ipsec_get_tag(m);
|
|
|
|
tag = t ? t->tag : 0;
|
|
|
|
#else
|
|
|
|
tag = 0;
|
|
|
|
#endif
|
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
/* if we have a cached entry, and if it is still valid, use it. */
|
|
|
|
ipsec6stat.spdcachelookup++;
|
|
|
|
currsp = ipsec_checkpcbcache(m, pcbsp, dir);
|
|
|
|
if (currsp) {
|
|
|
|
*error = 0;
|
|
|
|
return currsp;
|
|
|
|
}
|
|
|
|
ipsec6stat.spdcachemiss++;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
|
|
|
currsp = pcbsp->sp_in;
|
|
|
|
break;
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
|
|
|
currsp = pcbsp->sp_out;
|
|
|
|
break;
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_getpolicybysock: illegal direction.");
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (currsp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_getpolicybysock: currsp is NULL.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2004-01-14 02:02:00 +03:00
|
|
|
/* when privileged socket */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (pcbsp->priv) {
|
|
|
|
switch (currsp->policy) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_BYPASS:
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, currsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return currsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
2000-01-31 17:18:52 +03:00
|
|
|
/* look for a policy in SPD */
|
2002-06-22 16:04:07 +04:00
|
|
|
if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
|
2003-09-12 11:53:29 +04:00
|
|
|
(kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
/* SP found */
|
1999-06-28 10:36:47 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec6_getpolicybysock called "
|
2000-01-31 17:18:52 +03:00
|
|
|
"to allocate SP:%p\n", kernsp));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return kernsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* no SP found */
|
2002-06-12 21:56:45 +04:00
|
|
|
ip6_def_policy->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2002-06-12 21:56:45 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir);
|
|
|
|
return ip6_def_policy;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, currsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return currsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
|
|
|
|
"Invalid policy for PCB %d\n", currsp->policy));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
2004-01-14 02:02:00 +03:00
|
|
|
/* when non-privileged socket */
|
2000-01-31 17:18:52 +03:00
|
|
|
/* look for a policy in SPD */
|
2002-06-22 16:04:07 +04:00
|
|
|
if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
|
2003-09-12 11:53:29 +04:00
|
|
|
(kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
/* SP found */
|
1999-06-28 10:36:47 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec6_getpolicybysock called "
|
2000-01-31 17:18:52 +03:00
|
|
|
"to allocate SP:%p\n", kernsp));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return kernsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* no SP found */
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (currsp->policy) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_BYPASS:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_getpolicybysock: "
|
2004-01-14 02:02:00 +03:00
|
|
|
"Illegal policy for non-privileged defined %d\n",
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->policy));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
2002-06-12 21:56:45 +04:00
|
|
|
ip6_def_policy->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2002-06-12 21:56:45 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir);
|
|
|
|
return ip6_def_policy;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
case IPSEC_POLICY_IPSEC:
|
2000-01-31 17:18:52 +03:00
|
|
|
currsp->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_fillpcbcache(pcbsp, m, currsp, dir);
|
2000-01-31 17:18:52 +03:00
|
|
|
return currsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR,
|
|
|
|
"ipsec6_policybysock: Invalid policy for PCB %d\n",
|
|
|
|
currsp->policy));
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet,
|
|
|
|
* and return a pointer to SP.
|
|
|
|
* `flag' means that packet is to be forwarded whether or not.
|
|
|
|
* flag = 1: forwad
|
|
|
|
* OUT: positive: a pointer to the entry for security policy leaf matched.
|
|
|
|
* NULL: no apropreate SP found, the following value is set to error.
|
|
|
|
* 0 : bypass
|
|
|
|
* EACCES : discard packet.
|
|
|
|
* ENOENT : ipsec_acquire() in progress, maybe.
|
2004-02-24 18:12:51 +03:00
|
|
|
* others : error occurred.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
#ifndef IP_FORWARDING
|
|
|
|
#define IP_FORWARDING 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct secpolicy *
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6_getpolicybyaddr(m, dir, flag, error)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
u_int dir;
|
1999-06-28 10:36:47 +04:00
|
|
|
int flag;
|
|
|
|
int *error;
|
|
|
|
{
|
|
|
|
struct secpolicy *sp = NULL;
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
struct pf_tag *t;
|
|
|
|
#endif
|
|
|
|
u_int16_t tag;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL || error == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_getpolicybyaddr: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-12 05:47:34 +04:00
|
|
|
/* get a policy entry matched with the packet */
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secpolicyindex spidx;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
bzero(&spidx, sizeof(spidx));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2003-09-07 19:59:36 +04:00
|
|
|
/* make an index to look for a policy */
|
2002-06-12 05:47:34 +04:00
|
|
|
*error = ipsec_setspidx_mbuf(&spidx, AF_INET6, m,
|
2000-09-22 09:49:46 +04:00
|
|
|
(flag & IP_FORWARDING) ? 0 : 1);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (*error != 0)
|
|
|
|
return NULL;
|
|
|
|
|
2003-09-12 11:53:29 +04:00
|
|
|
#ifdef SADB_X_EXT_TAG
|
|
|
|
t = ipsec_get_tag(m);
|
|
|
|
tag = t ? t->tag : 0;
|
|
|
|
#else
|
|
|
|
tag = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sp = key_allocsp(tag, &spidx, dir);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SP found */
|
|
|
|
if (sp != NULL) {
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec6_getpolicybyaddr called "
|
|
|
|
"to allocate SP:%p\n", sp));
|
|
|
|
*error = 0;
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no SP found */
|
2002-06-12 21:56:45 +04:00
|
|
|
ip6_def_policy->refcnt++;
|
1999-06-28 10:36:47 +04:00
|
|
|
*error = 0;
|
2002-06-12 21:56:45 +04:00
|
|
|
return ip6_def_policy;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
#endif /* INET6 */
|
|
|
|
|
|
|
|
/*
|
2000-01-31 17:18:52 +03:00
|
|
|
* set IP address into spidx from mbuf.
|
|
|
|
* When Forwarding packet and ICMP echo reply, this function is used.
|
|
|
|
*
|
|
|
|
* IN: get the followings from mbuf.
|
|
|
|
* protocol family, src, dst, next protocol
|
1999-06-28 10:36:47 +04:00
|
|
|
* OUT:
|
2000-01-31 17:18:52 +03:00
|
|
|
* 0: success.
|
|
|
|
* other: failure, and set errno.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
int
|
2002-06-12 05:47:34 +04:00
|
|
|
ipsec_setspidx_mbuf(spidx, family, m, needport)
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secpolicyindex *spidx;
|
2002-06-12 05:47:34 +04:00
|
|
|
int family;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-09-22 09:49:46 +04:00
|
|
|
int needport;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-09-22 09:49:46 +04:00
|
|
|
int error;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* sanity check */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (spidx == NULL || m == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_setspidx_mbuf: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
bzero(spidx, sizeof(*spidx));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
error = ipsec_setspidx(m, spidx, needport);
|
|
|
|
if (error)
|
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
bad:
|
|
|
|
/* XXX initialize */
|
|
|
|
bzero(spidx, sizeof(*spidx));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
/*
|
|
|
|
* configure security policy index (src/dst/proto/sport/dport)
|
|
|
|
* by looking at the content of mbuf.
|
|
|
|
* the caller is responsible for error recovery (like clearing up spidx).
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ipsec_setspidx(m, spidx, needport)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct secpolicyindex *spidx;
|
|
|
|
int needport;
|
|
|
|
{
|
|
|
|
struct ip *ip = NULL;
|
|
|
|
struct ip ipbuf;
|
|
|
|
u_int v;
|
|
|
|
struct mbuf *n;
|
|
|
|
int len;
|
|
|
|
int error;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
if (m == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_setspidx: m == 0 passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
bzero(spidx, sizeof(*spidx));
|
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
/*
|
|
|
|
* validate m->m_pkthdr.len. we see incorrect length if we
|
|
|
|
* mistakenly call this function with inconsistent mbuf chain
|
|
|
|
* (like 4.4BSD tcp/udp processing). XXX should we panic here?
|
|
|
|
*/
|
|
|
|
len = 0;
|
|
|
|
for (n = m; n; n = n->m_next)
|
|
|
|
len += n->m_len;
|
|
|
|
if (m->m_pkthdr.len != len) {
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec_setspidx: "
|
|
|
|
"total of m_len(%d) != pkthdr.len(%d), "
|
|
|
|
"ignored.\n",
|
|
|
|
len, m->m_pkthdr.len));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
if (m->m_pkthdr.len < sizeof(struct ip)) {
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec_setspidx: "
|
|
|
|
"pkthdr.len(%d) < sizeof(struct ip), ignored.\n",
|
|
|
|
m->m_pkthdr.len));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
if (m->m_len >= sizeof(*ip))
|
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
else {
|
|
|
|
m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf);
|
|
|
|
ip = &ipbuf;
|
|
|
|
}
|
|
|
|
v = ip->ip_v;
|
|
|
|
switch (v) {
|
|
|
|
case 4:
|
|
|
|
error = ipsec4_setspidx_ipaddr(m, spidx);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
ipsec4_get_ulp(m, spidx, needport);
|
|
|
|
return 0;
|
2000-01-31 17:18:52 +03:00
|
|
|
#ifdef INET6
|
2000-09-22 09:49:46 +04:00
|
|
|
case 6:
|
|
|
|
if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec_setspidx: "
|
|
|
|
"pkthdr.len(%d) < sizeof(struct ip6_hdr), "
|
|
|
|
"ignored.\n", m->m_pkthdr.len));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
error = ipsec6_setspidx_ipaddr(m, spidx);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
ipsec6_get_ulp(m, spidx, needport);
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec_setspidx: "
|
|
|
|
"unknown IP version %u, ignored.\n", v));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
static void
|
2000-09-22 09:49:46 +04:00
|
|
|
ipsec4_get_ulp(m, spidx, needport)
|
2000-01-31 17:18:52 +03:00
|
|
|
struct mbuf *m;
|
|
|
|
struct secpolicyindex *spidx;
|
2000-09-22 09:49:46 +04:00
|
|
|
int needport;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-09-22 09:49:46 +04:00
|
|
|
struct ip ip;
|
|
|
|
struct ip6_ext ip6e;
|
|
|
|
u_int8_t nxt;
|
|
|
|
int off;
|
|
|
|
struct tcphdr th;
|
|
|
|
struct udphdr uh;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_get_ulp: NULL pointer was passed.");
|
2000-09-22 09:49:46 +04:00
|
|
|
if (m->m_pkthdr.len < sizeof(ip))
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_get_ulp: too short");
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* set default */
|
|
|
|
spidx->ul_proto = IPSEC_ULPROTO_ANY;
|
2000-09-22 09:49:46 +04:00
|
|
|
((struct sockaddr_in *)&spidx->src)->sin_port = IPSEC_PORT_ANY;
|
|
|
|
((struct sockaddr_in *)&spidx->dst)->sin_port = IPSEC_PORT_ANY;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
|
2002-08-14 04:23:27 +04:00
|
|
|
if (ip.ip_off & htons(IP_MF | IP_OFFMASK))
|
2000-03-22 02:53:30 +03:00
|
|
|
return;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
nxt = ip.ip_p;
|
|
|
|
off = ip.ip_hl << 2;
|
|
|
|
while (off < m->m_pkthdr.len) {
|
|
|
|
switch (nxt) {
|
|
|
|
case IPPROTO_TCP:
|
|
|
|
spidx->ul_proto = nxt;
|
|
|
|
if (!needport)
|
|
|
|
return;
|
|
|
|
if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
|
|
|
|
return;
|
2000-03-22 02:53:30 +03:00
|
|
|
m_copydata(m, off, sizeof(th), (caddr_t)&th);
|
2000-09-22 09:49:46 +04:00
|
|
|
((struct sockaddr_in *)&spidx->src)->sin_port =
|
2000-06-03 20:14:02 +04:00
|
|
|
th.th_sport;
|
2000-09-22 09:49:46 +04:00
|
|
|
((struct sockaddr_in *)&spidx->dst)->sin_port =
|
2000-06-03 20:14:02 +04:00
|
|
|
th.th_dport;
|
2000-09-22 09:49:46 +04:00
|
|
|
return;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
spidx->ul_proto = nxt;
|
|
|
|
if (!needport)
|
|
|
|
return;
|
|
|
|
if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
|
|
|
|
return;
|
2000-03-22 02:53:30 +03:00
|
|
|
m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
|
2000-09-22 09:49:46 +04:00
|
|
|
((struct sockaddr_in *)&spidx->src)->sin_port =
|
2000-06-03 20:14:02 +04:00
|
|
|
uh.uh_sport;
|
2000-09-22 09:49:46 +04:00
|
|
|
((struct sockaddr_in *)&spidx->dst)->sin_port =
|
2000-06-03 20:14:02 +04:00
|
|
|
uh.uh_dport;
|
2000-09-22 09:49:46 +04:00
|
|
|
return;
|
|
|
|
case IPPROTO_AH:
|
2005-03-09 17:17:13 +03:00
|
|
|
if (off + sizeof(ip6e) > m->m_pkthdr.len)
|
2000-09-22 09:49:46 +04:00
|
|
|
return;
|
|
|
|
m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
|
|
|
|
off += (ip6e.ip6e_len + 2) << 2;
|
|
|
|
nxt = ip6e.ip6e_nxt;
|
|
|
|
break;
|
2001-08-06 14:25:00 +04:00
|
|
|
case IPPROTO_ICMP:
|
2000-09-22 09:49:46 +04:00
|
|
|
default:
|
2001-08-06 14:25:00 +04:00
|
|
|
/* XXX intermediate headers??? */
|
|
|
|
spidx->ul_proto = nxt;
|
2000-09-22 09:49:46 +04:00
|
|
|
return;
|
2000-03-22 02:53:30 +03:00
|
|
|
}
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
/* assumes that m is sane */
|
|
|
|
static int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec4_setspidx_ipaddr(m, spidx)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct secpolicyindex *spidx;
|
|
|
|
{
|
|
|
|
struct ip *ip = NULL;
|
|
|
|
struct ip ipbuf;
|
2000-09-22 09:49:46 +04:00
|
|
|
struct sockaddr_in *sin;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
if (m->m_len >= sizeof(*ip))
|
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
else {
|
|
|
|
m_copydata(m, 0, sizeof(ipbuf), (caddr_t)&ipbuf);
|
|
|
|
ip = &ipbuf;
|
|
|
|
}
|
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
sin = (struct sockaddr_in *)&spidx->src;
|
|
|
|
bzero(sin, sizeof(*sin));
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_len = sizeof(struct sockaddr_in);
|
|
|
|
bcopy(&ip->ip_src, &sin->sin_addr, sizeof(ip->ip_src));
|
|
|
|
spidx->prefs = sizeof(struct in_addr) << 3;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
sin = (struct sockaddr_in *)&spidx->dst;
|
|
|
|
bzero(sin, sizeof(*sin));
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_len = sizeof(struct sockaddr_in);
|
|
|
|
bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst));
|
|
|
|
spidx->prefd = sizeof(struct in_addr) << 3;
|
|
|
|
return 0;
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
static void
|
2000-09-22 09:49:46 +04:00
|
|
|
ipsec6_get_ulp(m, spidx, needport)
|
2000-01-31 17:18:52 +03:00
|
|
|
struct mbuf *m;
|
|
|
|
struct secpolicyindex *spidx;
|
2000-09-22 09:49:46 +04:00
|
|
|
int needport;
|
|
|
|
{
|
|
|
|
int off, nxt;
|
|
|
|
struct tcphdr th;
|
|
|
|
struct udphdr uh;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* sanity check */
|
2000-09-22 09:49:46 +04:00
|
|
|
if (m == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_get_ulp: NULL pointer was passed.");
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec6_get_ulp:\n"); kdebug_mbuf(m));
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
/* set default */
|
|
|
|
spidx->ul_proto = IPSEC_ULPROTO_ANY;
|
|
|
|
((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY;
|
|
|
|
((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
nxt = -1;
|
|
|
|
off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
|
|
|
|
if (off < 0 || m->m_pkthdr.len < off)
|
|
|
|
return;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
switch (nxt) {
|
|
|
|
case IPPROTO_TCP:
|
|
|
|
spidx->ul_proto = nxt;
|
|
|
|
if (!needport)
|
|
|
|
break;
|
|
|
|
if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
|
|
|
|
break;
|
|
|
|
m_copydata(m, off, sizeof(th), (caddr_t)&th);
|
|
|
|
((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport;
|
|
|
|
((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport;
|
|
|
|
break;
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
spidx->ul_proto = nxt;
|
|
|
|
if (!needport)
|
|
|
|
break;
|
|
|
|
if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
|
|
|
|
break;
|
|
|
|
m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
|
|
|
|
((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport;
|
|
|
|
((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport;
|
|
|
|
break;
|
|
|
|
case IPPROTO_ICMPV6:
|
|
|
|
default:
|
2001-08-06 14:25:00 +04:00
|
|
|
/* XXX intermediate headers??? */
|
|
|
|
spidx->ul_proto = nxt;
|
2000-09-22 09:49:46 +04:00
|
|
|
break;
|
|
|
|
}
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
/* assumes that m is sane */
|
|
|
|
static int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6_setspidx_ipaddr(m, spidx)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct secpolicyindex *spidx;
|
|
|
|
{
|
2000-06-03 20:14:02 +04:00
|
|
|
struct ip6_hdr *ip6 = NULL;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct ip6_hdr ip6buf;
|
2000-06-03 20:14:02 +04:00
|
|
|
struct sockaddr_in6 *sin6;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
2000-06-03 20:14:02 +04:00
|
|
|
if (m->m_len >= sizeof(*ip6))
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
2000-01-31 17:18:52 +03:00
|
|
|
else {
|
|
|
|
m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
|
2000-06-03 20:14:02 +04:00
|
|
|
ip6 = &ip6buf;
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
2000-06-03 20:14:02 +04:00
|
|
|
sin6 = (struct sockaddr_in6 *)&spidx->src;
|
2000-09-22 09:49:46 +04:00
|
|
|
bzero(sin6, sizeof(*sin6));
|
|
|
|
sin6->sin6_family = AF_INET6;
|
|
|
|
sin6->sin6_len = sizeof(struct sockaddr_in6);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
sin6->sin6_addr = ip6->ip6_src;
|
2000-09-22 09:49:46 +04:00
|
|
|
spidx->prefs = sizeof(struct in6_addr) << 3;
|
2000-06-03 20:14:02 +04:00
|
|
|
|
|
|
|
sin6 = (struct sockaddr_in6 *)&spidx->dst;
|
2000-09-22 09:49:46 +04:00
|
|
|
bzero(sin6, sizeof(*sin6));
|
|
|
|
sin6->sin6_family = AF_INET6;
|
|
|
|
sin6->sin6_len = sizeof(struct sockaddr_in6);
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
sin6->sin6_addr = ip6->ip6_dst;
|
2000-09-22 09:49:46 +04:00
|
|
|
spidx->prefd = sizeof(struct in6_addr) << 3;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-09-22 09:49:46 +04:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
static struct inpcbpolicy *
|
|
|
|
ipsec_newpcbpolicy()
|
|
|
|
{
|
|
|
|
struct inpcbpolicy *p;
|
|
|
|
|
|
|
|
p = (struct inpcbpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ipsec_delpcbpolicy(p)
|
|
|
|
struct inpcbpolicy *p;
|
|
|
|
{
|
2001-08-06 14:25:00 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
free(p, M_SECA);
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* initialize policy in PCB */
|
|
|
|
int
|
2002-06-11 23:39:59 +04:00
|
|
|
ipsec_init_pcbpolicy(so, pcb_sp)
|
2000-01-31 17:18:52 +03:00
|
|
|
struct socket *so;
|
|
|
|
struct inpcbpolicy **pcb_sp;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct inpcbpolicy *new;
|
2002-06-11 23:39:59 +04:00
|
|
|
static int initialized = 0;
|
|
|
|
static struct secpolicy *in = NULL, *out = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* sanity check. */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (so == NULL || pcb_sp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_init_pcbpolicy: NULL pointer was passed.");
|
2002-06-11 23:39:59 +04:00
|
|
|
|
|
|
|
if (!initialized) {
|
2003-08-22 10:22:21 +04:00
|
|
|
if ((in = key_newsp(0)) == NULL)
|
2002-06-11 23:39:59 +04:00
|
|
|
return ENOBUFS;
|
2003-08-22 10:22:21 +04:00
|
|
|
if ((out = key_newsp(0)) == NULL) {
|
2002-06-11 23:39:59 +04:00
|
|
|
key_freesp(in);
|
|
|
|
in = NULL;
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
|
|
|
|
in->state = IPSEC_SPSTATE_ALIVE;
|
|
|
|
in->policy = IPSEC_POLICY_ENTRUST;
|
2002-06-12 05:47:34 +04:00
|
|
|
in->dir = IPSEC_DIR_INBOUND;
|
2002-06-11 23:39:59 +04:00
|
|
|
in->readonly = 1;
|
2003-09-22 08:47:43 +04:00
|
|
|
in->persist = 1;
|
|
|
|
in->so = NULL;
|
2002-06-11 23:39:59 +04:00
|
|
|
|
|
|
|
out->state = IPSEC_SPSTATE_ALIVE;
|
|
|
|
out->policy = IPSEC_POLICY_ENTRUST;
|
2002-06-12 05:47:34 +04:00
|
|
|
out->dir = IPSEC_DIR_OUTBOUND;
|
2002-06-11 23:39:59 +04:00
|
|
|
out->readonly = 1;
|
2003-09-22 08:47:43 +04:00
|
|
|
out->persist = 1;
|
|
|
|
out->so = NULL;
|
2002-06-11 23:39:59 +04:00
|
|
|
|
|
|
|
initialized++;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
new = ipsec_newpcbpolicy();
|
|
|
|
if (new == NULL) {
|
2002-06-11 23:39:59 +04:00
|
|
|
ipseclog((LOG_DEBUG, "ipsec_init_pcbpolicy: No more memory.\n"));
|
1999-06-28 10:36:47 +04:00
|
|
|
return ENOBUFS;
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
bzero(new, sizeof(*new));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2005-05-07 21:44:11 +04:00
|
|
|
if (so->so_uidinfo->ui_uid == 0) /* XXX */
|
2000-01-31 17:18:52 +03:00
|
|
|
new->priv = 1;
|
|
|
|
else
|
|
|
|
new->priv = 0;
|
|
|
|
|
2002-06-11 23:39:59 +04:00
|
|
|
new->sp_in = in;
|
|
|
|
new->sp_in->refcnt++;
|
|
|
|
new->sp_out = out;
|
|
|
|
new->sp_out->refcnt++;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
*pcb_sp = new;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copy old ipsec policy into new */
|
|
|
|
int
|
2002-06-11 23:39:59 +04:00
|
|
|
ipsec_copy_pcbpolicy(old, new)
|
2000-01-31 17:18:52 +03:00
|
|
|
struct inpcbpolicy *old, *new;
|
|
|
|
{
|
2002-06-11 23:39:59 +04:00
|
|
|
|
|
|
|
if (new->sp_in)
|
|
|
|
key_freesp(new->sp_in);
|
2002-06-12 21:56:45 +04:00
|
|
|
if (old->sp_in->policy == IPSEC_POLICY_IPSEC)
|
|
|
|
new->sp_in = ipsec_deepcopy_policy(old->sp_in);
|
|
|
|
else {
|
|
|
|
new->sp_in = old->sp_in;
|
|
|
|
new->sp_in->refcnt++;
|
|
|
|
}
|
|
|
|
|
2002-06-11 23:39:59 +04:00
|
|
|
if (new->sp_out)
|
|
|
|
key_freesp(new->sp_out);
|
2002-06-12 21:56:45 +04:00
|
|
|
if (old->sp_out->policy == IPSEC_POLICY_IPSEC)
|
|
|
|
new->sp_out = ipsec_deepcopy_policy(old->sp_out);
|
|
|
|
else {
|
|
|
|
new->sp_out = old->sp_out;
|
|
|
|
new->sp_out->refcnt++;
|
|
|
|
}
|
|
|
|
|
2002-06-11 23:39:59 +04:00
|
|
|
new->priv = old->priv;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-12 05:47:34 +04:00
|
|
|
#if 0
|
2002-06-11 23:39:59 +04:00
|
|
|
static int
|
|
|
|
ipsec_deepcopy_pcbpolicy(pcb_sp)
|
|
|
|
struct inpcbpolicy *pcb_sp;
|
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secpolicy *sp;
|
|
|
|
|
2002-06-11 23:39:59 +04:00
|
|
|
sp = ipsec_deepcopy_policy(pcb_sp->sp_in);
|
2000-01-31 17:18:52 +03:00
|
|
|
if (sp) {
|
2002-06-11 23:39:59 +04:00
|
|
|
key_freesp(pcb_sp->sp_in);
|
|
|
|
pcb_sp->sp_in = sp;
|
2000-01-31 17:18:52 +03:00
|
|
|
} else
|
|
|
|
return ENOBUFS;
|
|
|
|
|
2002-06-11 23:39:59 +04:00
|
|
|
sp = ipsec_deepcopy_policy(pcb_sp->sp_out);
|
2000-01-31 17:18:52 +03:00
|
|
|
if (sp) {
|
2002-06-11 23:39:59 +04:00
|
|
|
key_freesp(pcb_sp->sp_out);
|
|
|
|
pcb_sp->sp_out = sp;
|
2000-01-31 17:18:52 +03:00
|
|
|
} else
|
|
|
|
return ENOBUFS;
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2002-06-12 21:56:45 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* deep-copy a policy in PCB */
|
2000-01-31 17:18:52 +03:00
|
|
|
static struct secpolicy *
|
|
|
|
ipsec_deepcopy_policy(src)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct secpolicy *src;
|
|
|
|
{
|
|
|
|
struct ipsecrequest *newchain = NULL;
|
|
|
|
struct ipsecrequest *p;
|
|
|
|
struct ipsecrequest **q;
|
|
|
|
struct ipsecrequest *r;
|
|
|
|
struct secpolicy *dst;
|
|
|
|
|
2004-01-14 02:01:08 +03:00
|
|
|
if (src == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2003-08-22 10:22:21 +04:00
|
|
|
dst = key_newsp(0);
|
2004-01-14 02:01:08 +03:00
|
|
|
if (dst == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deep-copy IPsec request chain. This is required since struct
|
|
|
|
* ipsecrequest is not reference counted.
|
|
|
|
*/
|
|
|
|
q = &newchain;
|
|
|
|
for (p = src->req; p; p = p->next) {
|
2000-01-31 17:18:52 +03:00
|
|
|
*q = (struct ipsecrequest *)malloc(sizeof(struct ipsecrequest),
|
|
|
|
M_SECA, M_NOWAIT);
|
1999-06-28 10:36:47 +04:00
|
|
|
if (*q == NULL)
|
|
|
|
goto fail;
|
|
|
|
bzero(*q, sizeof(**q));
|
|
|
|
(*q)->next = NULL;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
(*q)->saidx.proto = p->saidx.proto;
|
|
|
|
(*q)->saidx.mode = p->saidx.mode;
|
1999-06-28 10:36:47 +04:00
|
|
|
(*q)->level = p->level;
|
2000-01-31 17:18:52 +03:00
|
|
|
(*q)->saidx.reqid = p->saidx.reqid;
|
|
|
|
|
|
|
|
bcopy(&p->saidx.src, &(*q)->saidx.src, sizeof((*q)->saidx.src));
|
|
|
|
bcopy(&p->saidx.dst, &(*q)->saidx.dst, sizeof((*q)->saidx.dst));
|
|
|
|
|
|
|
|
(*q)->sav = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
(*q)->sp = dst;
|
|
|
|
|
|
|
|
q = &((*q)->next);
|
|
|
|
}
|
|
|
|
|
2002-06-12 21:56:45 +04:00
|
|
|
if (src->spidx)
|
2002-06-13 09:10:13 +04:00
|
|
|
if (keydb_setsecpolicyindex(dst, src->spidx) != 0)
|
|
|
|
goto fail;
|
2002-06-12 21:56:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
dst->req = newchain;
|
|
|
|
dst->state = src->state;
|
|
|
|
dst->policy = src->policy;
|
2002-06-22 16:04:07 +04:00
|
|
|
dst->dir = src->dir;
|
2003-09-11 02:29:27 +04:00
|
|
|
dst->so = src->so;
|
1999-06-28 10:36:47 +04:00
|
|
|
/* do not touch the refcnt fields */
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
for (p = newchain; p; p = r) {
|
|
|
|
r = p->next;
|
2000-01-31 17:18:52 +03:00
|
|
|
free(p, M_SECA);
|
1999-06-28 10:36:47 +04:00
|
|
|
p = NULL;
|
|
|
|
}
|
2002-06-12 21:56:45 +04:00
|
|
|
key_freesp(dst);
|
1999-06-28 10:36:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set policy and ipsec request if present. */
|
2000-01-31 17:18:52 +03:00
|
|
|
static int
|
2002-06-11 21:26:52 +04:00
|
|
|
ipsec_set_policy(spp, optname, request, len, priv)
|
|
|
|
struct secpolicy **spp;
|
2000-01-31 17:18:52 +03:00
|
|
|
int optname;
|
1999-06-28 10:36:47 +04:00
|
|
|
caddr_t request;
|
2000-01-31 17:18:52 +03:00
|
|
|
size_t len;
|
1999-06-28 10:36:47 +04:00
|
|
|
int priv;
|
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct sadb_x_policy *xpl;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct secpolicy *newsp = NULL;
|
2000-01-31 17:18:52 +03:00
|
|
|
int error;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* sanity check. */
|
2002-06-11 21:26:52 +04:00
|
|
|
if (spp == NULL || *spp == NULL || request == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return EINVAL;
|
2000-01-31 17:18:52 +03:00
|
|
|
if (len < sizeof(*xpl))
|
|
|
|
return EINVAL;
|
|
|
|
xpl = (struct sadb_x_policy *)request;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
2000-01-31 17:18:52 +03:00
|
|
|
printf("ipsec_set_policy: passed policy\n");
|
1999-06-28 10:36:47 +04:00
|
|
|
kdebug_sadb_x_policy((struct sadb_ext *)xpl));
|
|
|
|
|
|
|
|
/* check policy type */
|
|
|
|
/* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */
|
2002-06-11 23:39:59 +04:00
|
|
|
if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD ||
|
|
|
|
xpl->sadb_x_policy_type == IPSEC_POLICY_NONE)
|
1999-06-28 10:36:47 +04:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* check privileged socket */
|
|
|
|
if (priv == 0 && xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS)
|
|
|
|
return EACCES;
|
|
|
|
|
|
|
|
/* allocation new SP entry */
|
2000-01-31 17:18:52 +03:00
|
|
|
if ((newsp = key_msg2sp(xpl, len, &error)) == NULL)
|
|
|
|
return error;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
newsp->state = IPSEC_SPSTATE_ALIVE;
|
|
|
|
|
|
|
|
/* clear old SP and set new SP */
|
2002-06-11 21:26:52 +04:00
|
|
|
key_freesp(*spp);
|
|
|
|
*spp = newsp;
|
1999-06-28 10:36:47 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
2000-01-31 17:18:52 +03:00
|
|
|
printf("ipsec_set_policy: new policy\n");
|
1999-06-28 10:36:47 +04:00
|
|
|
kdebug_secpolicy(newsp));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
static int
|
2002-06-11 21:26:52 +04:00
|
|
|
ipsec_get_policy(sp, mp)
|
|
|
|
struct secpolicy *sp;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf **mp;
|
|
|
|
{
|
|
|
|
|
|
|
|
/* sanity check. */
|
2002-06-11 21:26:52 +04:00
|
|
|
if (sp == NULL || mp == NULL)
|
1999-06-28 10:36:47 +04:00
|
|
|
return EINVAL;
|
|
|
|
|
2002-06-11 21:26:52 +04:00
|
|
|
*mp = key_sp2msg(sp);
|
2000-01-31 17:18:52 +03:00
|
|
|
if (!*mp) {
|
|
|
|
ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n"));
|
1999-06-28 10:36:47 +04:00
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
(*mp)->m_type = MT_SOOPTS;
|
1999-06-28 10:36:47 +04:00
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec_get_policy:\n");
|
|
|
|
kdebug_mbuf(*mp));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
int
|
|
|
|
ipsec4_set_policy(inp, optname, request, len, priv)
|
|
|
|
struct inpcb *inp;
|
|
|
|
int optname;
|
|
|
|
caddr_t request;
|
|
|
|
size_t len;
|
|
|
|
int priv;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2000-01-31 17:18:52 +03:00
|
|
|
struct sadb_x_policy *xpl;
|
2002-06-11 21:26:52 +04:00
|
|
|
struct secpolicy **spp;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* sanity check. */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (inp == NULL || request == NULL)
|
|
|
|
return EINVAL;
|
|
|
|
if (len < sizeof(*xpl))
|
|
|
|
return EINVAL;
|
|
|
|
xpl = (struct sadb_x_policy *)request;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
/* select direction */
|
|
|
|
switch (xpl->sadb_x_policy_dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
spp = &inp->inp_sp->sp_in;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
spp = &inp->inp_sp->sp_out;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n",
|
|
|
|
xpl->sadb_x_policy_dir));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY);
|
2002-06-11 21:26:52 +04:00
|
|
|
return ipsec_set_policy(spp, optname, request, len, priv);
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec4_get_policy(inp, request, len, mp)
|
|
|
|
struct inpcb *inp;
|
|
|
|
caddr_t request;
|
|
|
|
size_t len;
|
|
|
|
struct mbuf **mp;
|
|
|
|
{
|
|
|
|
struct sadb_x_policy *xpl;
|
2002-06-11 21:26:52 +04:00
|
|
|
struct secpolicy *sp;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* sanity check. */
|
|
|
|
if (inp == NULL || request == NULL || mp == NULL)
|
|
|
|
return EINVAL;
|
2000-03-22 02:53:30 +03:00
|
|
|
if (inp->inp_sp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("policy in PCB is NULL");
|
2000-03-22 02:53:30 +03:00
|
|
|
if (len < sizeof(*xpl))
|
2000-01-31 17:18:52 +03:00
|
|
|
return EINVAL;
|
|
|
|
xpl = (struct sadb_x_policy *)request;
|
|
|
|
|
|
|
|
/* select direction */
|
|
|
|
switch (xpl->sadb_x_policy_dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
sp = inp->inp_sp->sp_in;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
sp = inp->inp_sp->sp_out;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
default:
|
2002-06-11 23:39:59 +04:00
|
|
|
ipseclog((LOG_ERR, "ipsec4_get_policy: invalid direction=%u\n",
|
2000-01-31 17:18:52 +03:00
|
|
|
xpl->sadb_x_policy_dir));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
2002-06-11 21:26:52 +04:00
|
|
|
return ipsec_get_policy(sp, mp);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* delete policy in PCB */
|
|
|
|
int
|
|
|
|
ipsec4_delete_pcbpolicy(inp)
|
|
|
|
struct inpcb *inp;
|
|
|
|
{
|
|
|
|
/* sanity check. */
|
|
|
|
if (inp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec4_delete_pcbpolicy: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-06-03 20:14:02 +04:00
|
|
|
if (inp->inp_sp == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (inp->inp_sp->sp_in != NULL) {
|
|
|
|
key_freesp(inp->inp_sp->sp_in);
|
|
|
|
inp->inp_sp->sp_in = NULL;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (inp->inp_sp->sp_out != NULL) {
|
|
|
|
key_freesp(inp->inp_sp->sp_out);
|
|
|
|
inp->inp_sp->sp_out = NULL;
|
|
|
|
}
|
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY);
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec_delpcbpolicy(inp->inp_sp);
|
1999-06-28 10:36:47 +04:00
|
|
|
inp->inp_sp = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
2000-01-31 17:18:52 +03:00
|
|
|
int
|
|
|
|
ipsec6_set_policy(in6p, optname, request, len, priv)
|
|
|
|
struct in6pcb *in6p;
|
|
|
|
int optname;
|
|
|
|
caddr_t request;
|
|
|
|
size_t len;
|
|
|
|
int priv;
|
|
|
|
{
|
|
|
|
struct sadb_x_policy *xpl;
|
2002-06-11 21:26:52 +04:00
|
|
|
struct secpolicy **spp;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* sanity check. */
|
|
|
|
if (in6p == NULL || request == NULL)
|
|
|
|
return EINVAL;
|
|
|
|
if (len < sizeof(*xpl))
|
|
|
|
return EINVAL;
|
|
|
|
xpl = (struct sadb_x_policy *)request;
|
|
|
|
|
|
|
|
/* select direction */
|
|
|
|
switch (xpl->sadb_x_policy_dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
spp = &in6p->in6p_sp->sp_in;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
spp = &in6p->in6p_sp->sp_out;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n",
|
|
|
|
xpl->sadb_x_policy_dir));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY);
|
2002-06-11 21:26:52 +04:00
|
|
|
return ipsec_set_policy(spp, optname, request, len, priv);
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec6_get_policy(in6p, request, len, mp)
|
|
|
|
struct in6pcb *in6p;
|
|
|
|
caddr_t request;
|
|
|
|
size_t len;
|
|
|
|
struct mbuf **mp;
|
|
|
|
{
|
|
|
|
struct sadb_x_policy *xpl;
|
2002-06-11 21:26:52 +04:00
|
|
|
struct secpolicy *sp;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* sanity check. */
|
|
|
|
if (in6p == NULL || request == NULL || mp == NULL)
|
|
|
|
return EINVAL;
|
2000-03-22 02:53:30 +03:00
|
|
|
if (in6p->in6p_sp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("policy in PCB is NULL");
|
2000-03-22 02:53:30 +03:00
|
|
|
if (len < sizeof(*xpl))
|
2000-01-31 17:18:52 +03:00
|
|
|
return EINVAL;
|
|
|
|
xpl = (struct sadb_x_policy *)request;
|
|
|
|
|
|
|
|
/* select direction */
|
|
|
|
switch (xpl->sadb_x_policy_dir) {
|
|
|
|
case IPSEC_DIR_INBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
sp = in6p->in6p_sp->sp_in;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
case IPSEC_DIR_OUTBOUND:
|
2002-06-11 21:26:52 +04:00
|
|
|
sp = in6p->in6p_sp->sp_out;
|
2000-01-31 17:18:52 +03:00
|
|
|
break;
|
|
|
|
default:
|
2002-06-11 23:39:59 +04:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_get_policy: invalid direction=%u\n",
|
2000-01-31 17:18:52 +03:00
|
|
|
xpl->sadb_x_policy_dir));
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
2002-06-11 21:26:52 +04:00
|
|
|
return ipsec_get_policy(sp, mp);
|
2000-01-31 17:18:52 +03:00
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
int
|
|
|
|
ipsec6_delete_pcbpolicy(in6p)
|
|
|
|
struct in6pcb *in6p;
|
|
|
|
{
|
|
|
|
/* sanity check. */
|
|
|
|
if (in6p == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec6_delete_pcbpolicy: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-06-03 20:14:02 +04:00
|
|
|
if (in6p->in6p_sp == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (in6p->in6p_sp->sp_in != NULL) {
|
|
|
|
key_freesp(in6p->in6p_sp->sp_in);
|
|
|
|
in6p->in6p_sp->sp_in = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in6p->in6p_sp->sp_out != NULL) {
|
|
|
|
key_freesp(in6p->in6p_sp->sp_out);
|
|
|
|
in6p->in6p_sp->sp_out = NULL;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY);
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec_delpcbpolicy(in6p->in6p_sp);
|
1999-06-28 10:36:47 +04:00
|
|
|
in6p->in6p_sp = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* return current level.
|
2000-01-31 17:18:52 +03:00
|
|
|
* Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
u_int
|
2002-06-12 05:47:34 +04:00
|
|
|
ipsec_get_reqlevel(isr, af)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ipsecrequest *isr;
|
2002-06-12 05:47:34 +04:00
|
|
|
int af;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
u_int level = 0;
|
|
|
|
u_int esp_trans_deflev, esp_net_deflev, ah_trans_deflev, ah_net_deflev;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (isr == NULL || isr->sp == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_get_reqlevel: NULL pointer is passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* set default level */
|
2002-06-12 05:47:34 +04:00
|
|
|
switch (af) {
|
1999-06-28 10:36:47 +04:00
|
|
|
#ifdef INET
|
|
|
|
case AF_INET:
|
2002-06-12 05:47:34 +04:00
|
|
|
esp_trans_deflev = ip4_esp_trans_deflev;
|
|
|
|
esp_net_deflev = ip4_esp_net_deflev;
|
|
|
|
ah_trans_deflev = ip4_ah_trans_deflev;
|
|
|
|
ah_net_deflev = ip4_ah_net_deflev;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef INET6
|
|
|
|
case AF_INET6:
|
2002-06-12 05:47:34 +04:00
|
|
|
esp_trans_deflev = ip6_esp_trans_deflev;
|
|
|
|
esp_net_deflev = ip6_esp_net_deflev;
|
|
|
|
ah_trans_deflev = ip6_ah_trans_deflev;
|
|
|
|
ah_net_deflev = ip6_ah_net_deflev;
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
#endif /* INET6 */
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("key_get_reqlevel: Unknown family. %d",
|
2002-06-12 05:47:34 +04:00
|
|
|
((struct sockaddr *)&isr->sp->spidx->src)->sa_family);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* set level */
|
|
|
|
switch (isr->level) {
|
|
|
|
case IPSEC_LEVEL_DEFAULT:
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (isr->saidx.proto) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPPROTO_ESP:
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
|
1999-06-28 10:36:47 +04:00
|
|
|
level = esp_net_deflev;
|
|
|
|
else
|
|
|
|
level = esp_trans_deflev;
|
|
|
|
break;
|
|
|
|
case IPPROTO_AH:
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
|
1999-06-28 10:36:47 +04:00
|
|
|
level = ah_net_deflev;
|
|
|
|
else
|
|
|
|
level = ah_trans_deflev;
|
2004-10-28 02:26:50 +04:00
|
|
|
break;
|
2000-01-16 21:06:03 +03:00
|
|
|
case IPPROTO_IPCOMP:
|
|
|
|
/*
|
|
|
|
* we don't really care, as IPcomp document says that
|
|
|
|
* we shouldn't compress small packets
|
|
|
|
*/
|
|
|
|
level = IPSEC_LEVEL_USE;
|
|
|
|
break;
|
2005-03-09 17:17:13 +03:00
|
|
|
case IPPROTO_IPV4:
|
|
|
|
case IPPROTO_IPV6:
|
|
|
|
/* should never go into here */
|
|
|
|
level = IPSEC_LEVEL_REQUIRE;
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
default:
|
|
|
|
panic("ipsec_get_reqlevel: "
|
|
|
|
"Illegal protocol defined %u\n",
|
2000-01-31 17:18:52 +03:00
|
|
|
isr->saidx.proto);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPSEC_LEVEL_USE:
|
|
|
|
case IPSEC_LEVEL_REQUIRE:
|
|
|
|
level = isr->level;
|
|
|
|
break;
|
2000-01-31 17:18:52 +03:00
|
|
|
case IPSEC_LEVEL_UNIQUE:
|
|
|
|
level = IPSEC_LEVEL_REQUIRE;
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_get_reqlevel: Illegal IPsec level %u",
|
1999-06-28 10:36:47 +04:00
|
|
|
isr->level);
|
|
|
|
}
|
|
|
|
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check AH/ESP integrity.
|
|
|
|
* OUT:
|
|
|
|
* 0: valid
|
|
|
|
* 1: invalid
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ipsec_in_reject(sp, m)
|
|
|
|
struct secpolicy *sp;
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
struct ipsecrequest *isr;
|
|
|
|
u_int level;
|
|
|
|
int need_auth, need_conf, need_icv;
|
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
|
|
|
printf("ipsec_in_reject: using SP\n");
|
|
|
|
kdebug_secpolicy(sp));
|
|
|
|
|
|
|
|
/* check policy */
|
|
|
|
switch (sp->policy) {
|
|
|
|
case IPSEC_POLICY_DISCARD:
|
|
|
|
return 1;
|
|
|
|
case IPSEC_POLICY_BYPASS:
|
|
|
|
case IPSEC_POLICY_NONE:
|
|
|
|
return 0;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_in_reject: Invalid policy found. %d", sp->policy);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
need_auth = 0;
|
|
|
|
need_conf = 0;
|
|
|
|
need_icv = 0;
|
|
|
|
|
2001-02-08 18:04:26 +03:00
|
|
|
/* XXX should compare policy against ipsec header history */
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
for (isr = sp->req; isr != NULL; isr = isr->next) {
|
|
|
|
/* get current level */
|
2002-06-12 05:47:34 +04:00
|
|
|
level = ipsec_get_reqlevel(isr, AF_INET);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (isr->saidx.proto) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPPROTO_ESP:
|
|
|
|
if (level == IPSEC_LEVEL_REQUIRE) {
|
|
|
|
need_conf++;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->sav != NULL
|
|
|
|
&& isr->sav->flags == SADB_X_EXT_NONE
|
|
|
|
&& isr->sav->alg_auth != SADB_AALG_NONE)
|
1999-06-28 10:36:47 +04:00
|
|
|
need_icv++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_AH:
|
|
|
|
if (level == IPSEC_LEVEL_REQUIRE) {
|
|
|
|
need_auth++;
|
|
|
|
need_icv++;
|
|
|
|
}
|
|
|
|
break;
|
2000-01-16 21:06:03 +03:00
|
|
|
case IPPROTO_IPCOMP:
|
|
|
|
/*
|
|
|
|
* we don't really care, as IPcomp document says that
|
2000-09-22 09:49:46 +04:00
|
|
|
* we shouldn't compress small packets, IPComp policy
|
|
|
|
* should always be treated as being in "use" level.
|
2000-01-16 21:06:03 +03:00
|
|
|
*/
|
|
|
|
break;
|
2005-03-09 17:17:13 +03:00
|
|
|
case IPPROTO_IPV4:
|
|
|
|
case IPPROTO_IPV6:
|
|
|
|
/*
|
|
|
|
* XXX what shall we do, until introducing more complex
|
|
|
|
* policy checking code?
|
|
|
|
*/
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
|
|
|
|
printf("ipsec_in_reject: auth:%d conf:%d icv:%d m_flags:%x\n",
|
|
|
|
need_auth, need_conf, need_icv, m->m_flags));
|
|
|
|
|
|
|
|
if ((need_conf && !(m->m_flags & M_DECRYPTED))
|
|
|
|
|| (!need_auth && need_icv && !(m->m_flags & M_AUTHIPDGM))
|
|
|
|
|| (need_auth && !(m->m_flags & M_AUTHIPHDR)))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check AH/ESP integrity.
|
|
|
|
* This function is called from tcp_input(), udp_input(),
|
|
|
|
* and {ah,esp}4_input for tunnel mode
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipsec4_in_reject_so(m, so)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct socket *so;
|
|
|
|
{
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
int error;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL)
|
|
|
|
return 0; /* XXX should be panic ? */
|
|
|
|
|
|
|
|
/* get SP for this packet.
|
|
|
|
* When we are called from ip_forward(), we call
|
|
|
|
* ipsec4_getpolicybyaddr() with IP_FORWARDING flag.
|
|
|
|
*/
|
|
|
|
if (so == NULL)
|
2003-09-07 19:59:36 +04:00
|
|
|
sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
|
|
|
|
IP_FORWARDING, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
else
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec4_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-08-01 09:17:47 +04:00
|
|
|
/* XXX should be panic ? -> No, there may be error. */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (sp == NULL)
|
2002-08-01 09:17:47 +04:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
result = ipsec_in_reject(sp, m);
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec4_in_reject_so call free SP:%p\n", sp));
|
|
|
|
key_freesp(sp);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec4_in_reject(m, inp)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct inpcb *inp;
|
|
|
|
{
|
|
|
|
if (inp == NULL)
|
|
|
|
return ipsec4_in_reject_so(m, NULL);
|
2000-09-22 09:49:46 +04:00
|
|
|
if (inp->inp_socket)
|
|
|
|
return ipsec4_in_reject_so(m, inp->inp_socket);
|
|
|
|
else
|
|
|
|
panic("ipsec4_in_reject: invalid inpcb/socket");
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
/*
|
|
|
|
* Check AH/ESP integrity.
|
|
|
|
* This function is called from tcp6_input(), udp6_input(),
|
|
|
|
* and {ah,esp}6_input for tunnel mode
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipsec6_in_reject_so(m, so)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct socket *so;
|
|
|
|
{
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
int error;
|
|
|
|
int result;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL)
|
|
|
|
return 0; /* XXX should be panic ? */
|
|
|
|
|
|
|
|
/* get SP for this packet.
|
|
|
|
* When we are called from ip_forward(), we call
|
|
|
|
* ipsec6_getpolicybyaddr() with IP_FORWARDING flag.
|
|
|
|
*/
|
|
|
|
if (so == NULL)
|
2003-09-07 19:59:36 +04:00
|
|
|
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
|
|
|
|
IP_FORWARDING, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
else
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec6_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (sp == NULL)
|
|
|
|
return 0; /* XXX should be panic ? */
|
|
|
|
|
|
|
|
result = ipsec_in_reject(sp, m);
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec6_in_reject_so call free SP:%p\n", sp));
|
|
|
|
key_freesp(sp);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec6_in_reject(m, in6p)
|
|
|
|
struct mbuf *m;
|
|
|
|
struct in6pcb *in6p;
|
|
|
|
{
|
|
|
|
if (in6p == NULL)
|
|
|
|
return ipsec6_in_reject_so(m, NULL);
|
2000-09-22 09:49:46 +04:00
|
|
|
if (in6p->in6p_socket)
|
|
|
|
return ipsec6_in_reject_so(m, in6p->in6p_socket);
|
|
|
|
else
|
|
|
|
panic("ipsec6_in_reject: invalid in6p/socket");
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* compute the byte size to be occupied by IPsec header.
|
|
|
|
* in case it is tunneled, it includes the size of outer IP header.
|
|
|
|
* NOTE: SP passed is free in this function.
|
|
|
|
*/
|
|
|
|
static size_t
|
|
|
|
ipsec_hdrsiz(sp)
|
|
|
|
struct secpolicy *sp;
|
|
|
|
{
|
|
|
|
struct ipsecrequest *isr;
|
|
|
|
size_t siz, clen;
|
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
2002-06-11 21:26:52 +04:00
|
|
|
printf("ipsec_hdrsiz: using SP\n");
|
1999-06-28 10:36:47 +04:00
|
|
|
kdebug_secpolicy(sp));
|
|
|
|
|
|
|
|
/* check policy */
|
|
|
|
switch (sp->policy) {
|
|
|
|
case IPSEC_POLICY_DISCARD:
|
|
|
|
case IPSEC_POLICY_BYPASS:
|
|
|
|
case IPSEC_POLICY_NONE:
|
|
|
|
return 0;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_POLICY_IPSEC:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPSEC_POLICY_ENTRUST:
|
|
|
|
default:
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_hdrsiz: Invalid policy found. %d", sp->policy);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
siz = 0;
|
|
|
|
|
|
|
|
for (isr = sp->req; isr != NULL; isr = isr->next) {
|
|
|
|
|
|
|
|
clen = 0;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (isr->saidx.proto) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPPROTO_ESP:
|
|
|
|
#ifdef IPSEC_ESP
|
|
|
|
clen = esp_hdrsiz(isr);
|
|
|
|
#else
|
2001-08-06 02:20:44 +04:00
|
|
|
clen = 0; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case IPPROTO_AH:
|
|
|
|
clen = ah_hdrsiz(isr);
|
|
|
|
break;
|
|
|
|
case IPPROTO_IPCOMP:
|
|
|
|
clen = sizeof(struct ipcomp);
|
|
|
|
break;
|
2005-03-09 17:17:13 +03:00
|
|
|
case IPPROTO_IPV4:
|
|
|
|
case IPPROTO_IPV6:
|
|
|
|
/* the next "if" clause will compute it */
|
|
|
|
clen = 0;
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
|
|
|
switch (((struct sockaddr *)&isr->saidx.dst)->sa_family) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case AF_INET:
|
|
|
|
clen += sizeof(struct ip);
|
|
|
|
break;
|
|
|
|
#ifdef INET6
|
|
|
|
case AF_INET6:
|
|
|
|
clen += sizeof(struct ip6_hdr);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec_hdrsiz: "
|
|
|
|
"unknown AF %d in IPsec tunnel SA\n",
|
|
|
|
((struct sockaddr *)&isr->saidx.dst)->sa_family));
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
siz += clen;
|
|
|
|
}
|
|
|
|
|
|
|
|
return siz;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */
|
|
|
|
size_t
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec4_hdrsiz(m, dir, inp)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
u_int dir;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct inpcb *inp;
|
|
|
|
{
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
int error;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL)
|
|
|
|
return 0; /* XXX should be panic ? */
|
|
|
|
if (inp != NULL && inp->inp_socket == NULL)
|
|
|
|
panic("ipsec4_hdrsize: why is socket NULL but there is PCB.");
|
|
|
|
|
|
|
|
/* get SP for this packet.
|
|
|
|
* When we are called from ip_forward(), we call
|
|
|
|
* ipsec4_getpolicybyaddr() with IP_FORWARDING flag.
|
|
|
|
*/
|
|
|
|
if (inp == NULL)
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
else
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec4_getpolicybysock(m, dir, inp->inp_socket, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (sp == NULL)
|
|
|
|
return 0; /* XXX should be panic ? */
|
|
|
|
|
|
|
|
size = ipsec_hdrsiz(sp);
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec4_hdrsiz call free SP:%p\n", sp));
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
1999-07-11 21:45:11 +04:00
|
|
|
printf("ipsec4_hdrsiz: size:%lu.\n", (unsigned long)size));
|
1999-06-28 10:36:47 +04:00
|
|
|
key_freesp(sp);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
/* This function is called from ipsec6_hdrsize_tcp(),
|
|
|
|
* and maybe from ip6_forward.()
|
|
|
|
*/
|
|
|
|
size_t
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6_hdrsiz(m, dir, in6p)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
u_int dir;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct in6pcb *in6p;
|
|
|
|
{
|
|
|
|
struct secpolicy *sp = NULL;
|
|
|
|
int error;
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if (m == NULL)
|
2002-07-18 15:59:06 +04:00
|
|
|
return 0; /* XXX should be panic ? */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (in6p != NULL && in6p->in6p_socket == NULL)
|
|
|
|
panic("ipsec6_hdrsize: why is socket NULL but there is PCB.");
|
|
|
|
|
|
|
|
/* get SP for this packet */
|
|
|
|
/* XXX Is it right to call with IP_FORWARDING. */
|
|
|
|
if (in6p == NULL)
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
else
|
2000-01-31 17:18:52 +03:00
|
|
|
sp = ipsec6_getpolicybysock(m, dir, in6p->in6p_socket, &error);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (sp == NULL)
|
|
|
|
return 0;
|
|
|
|
size = ipsec_hdrsiz(sp);
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
|
|
|
|
printf("DP ipsec6_hdrsiz call free SP:%p\n", sp));
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
1999-07-11 21:45:11 +04:00
|
|
|
printf("ipsec6_hdrsiz: size:%lu.\n", (unsigned long)size));
|
1999-06-28 10:36:47 +04:00
|
|
|
key_freesp(sp);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
2001-08-06 02:20:44 +04:00
|
|
|
#endif /* INET6 */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#ifdef INET
|
|
|
|
/*
|
|
|
|
* encapsulate for ipsec tunnel.
|
|
|
|
* ip->ip_src must be fixed later on.
|
|
|
|
*/
|
|
|
|
static int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec4_encapsulate(m, sav)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct ip *oip;
|
|
|
|
struct ip *ip;
|
|
|
|
size_t hlen;
|
|
|
|
size_t plen;
|
|
|
|
|
|
|
|
/* can't tunnel between different AFs */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
|
|
|
|
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
|
|
|
|
|| ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET) {
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#if 0
|
2000-01-31 17:18:52 +03:00
|
|
|
/* XXX if the dst is myself, perform nothing. */
|
2000-06-12 14:40:37 +04:00
|
|
|
if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-06-03 20:14:02 +04:00
|
|
|
if (m->m_len < sizeof(*ip))
|
|
|
|
panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
hlen = ip->ip_hl << 2;
|
|
|
|
|
2000-06-03 20:14:02 +04:00
|
|
|
if (m->m_len != hlen)
|
|
|
|
panic("ipsec4_encapsulate: assumption failed (first mbuf length)");
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* generate header checksum */
|
|
|
|
ip->ip_sum = 0;
|
|
|
|
ip->ip_sum = in_cksum(m, hlen);
|
|
|
|
|
|
|
|
plen = m->m_pkthdr.len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* grow the mbuf to accomodate the new IPv4 header.
|
|
|
|
* NOTE: IPv4 options will never be copied.
|
|
|
|
*/
|
|
|
|
if (M_LEADINGSPACE(m->m_next) < hlen) {
|
|
|
|
struct mbuf *n;
|
|
|
|
MGET(n, M_DONTWAIT, MT_DATA);
|
|
|
|
if (!n) {
|
|
|
|
m_freem(m);
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
n->m_len = hlen;
|
|
|
|
n->m_next = m->m_next;
|
|
|
|
m->m_next = n;
|
|
|
|
} else {
|
|
|
|
m->m_next->m_len += hlen;
|
|
|
|
m->m_next->m_data -= hlen;
|
|
|
|
}
|
2003-05-10 17:23:07 +04:00
|
|
|
oip = mtod(m->m_next, struct ip *);
|
|
|
|
m->m_pkthdr.len += hlen;
|
1999-06-28 10:36:47 +04:00
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
ovbcopy((caddr_t)ip, (caddr_t)oip, hlen);
|
|
|
|
m->m_len = sizeof(struct ip);
|
|
|
|
m->m_pkthdr.len -= (hlen - sizeof(struct ip));
|
|
|
|
|
|
|
|
/* construct new IPv4 header. see RFC 2401 5.1.2.1 */
|
|
|
|
/* ECN consideration. */
|
|
|
|
ip_ecn_ingress(ip4_ipsec_ecn, &ip->ip_tos, &oip->ip_tos);
|
|
|
|
ip->ip_hl = sizeof(struct ip) >> 2;
|
|
|
|
ip->ip_off &= htons(~IP_OFFMASK);
|
|
|
|
ip->ip_off &= htons(~IP_MF);
|
|
|
|
switch (ip4_ipsec_dfbit) {
|
2001-08-06 02:20:44 +04:00
|
|
|
case 0: /* clear DF bit */
|
1999-06-28 10:36:47 +04:00
|
|
|
ip->ip_off &= htons(~IP_DF);
|
|
|
|
break;
|
2001-08-06 02:20:44 +04:00
|
|
|
case 1: /* set DF bit */
|
1999-06-28 10:36:47 +04:00
|
|
|
ip->ip_off |= htons(IP_DF);
|
|
|
|
break;
|
2001-08-06 02:20:44 +04:00
|
|
|
default: /* copy DF bit */
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ip->ip_p = IPPROTO_IPIP;
|
|
|
|
if (plen + sizeof(struct ip) < IP_MAXPACKET)
|
|
|
|
ip->ip_len = htons(plen + sizeof(struct ip));
|
|
|
|
else {
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "IPv4 ipsec: size exceeds limit: "
|
2002-08-14 04:23:27 +04:00
|
|
|
"leave ip_len as is (invalid packet)\n"));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2003-11-18 00:34:27 +03:00
|
|
|
ip->ip_id = ip_newid();
|
2000-01-31 17:18:52 +03:00
|
|
|
bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr,
|
|
|
|
&ip->ip_src, sizeof(ip->ip_src));
|
|
|
|
bcopy(&((struct sockaddr_in *)&sav->sah->saidx.dst)->sin_addr,
|
1999-06-28 10:36:47 +04:00
|
|
|
&ip->ip_dst, sizeof(ip->ip_dst));
|
2001-04-15 05:55:49 +04:00
|
|
|
ip->ip_ttl = IPDEFTTL;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* XXX Should ip_src be updated later ? */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-06 02:20:44 +04:00
|
|
|
#endif /* INET */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
static int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6_encapsulate(m, sav)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct mbuf *m;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct ip6_hdr *oip6;
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
size_t plen;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
int error;
|
|
|
|
struct sockaddr_in6 sa6;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* can't tunnel between different AFs */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
|
|
|
|
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family
|
|
|
|
|| ((struct sockaddr *)&sav->sah->saidx.src)->sa_family != AF_INET6) {
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#if 0
|
2000-01-31 17:18:52 +03:00
|
|
|
/* XXX if the dst is myself, perform nothing. */
|
2000-06-12 14:40:37 +04:00
|
|
|
if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(m);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
plen = m->m_pkthdr.len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* grow the mbuf to accomodate the new IPv6 header.
|
|
|
|
*/
|
|
|
|
if (m->m_len != sizeof(struct ip6_hdr))
|
|
|
|
panic("ipsec6_encapsulate: assumption failed (first mbuf length)");
|
|
|
|
if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) {
|
|
|
|
struct mbuf *n;
|
|
|
|
MGET(n, M_DONTWAIT, MT_DATA);
|
|
|
|
if (!n) {
|
|
|
|
m_freem(m);
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
n->m_len = sizeof(struct ip6_hdr);
|
|
|
|
n->m_next = m->m_next;
|
|
|
|
m->m_next = n;
|
|
|
|
m->m_pkthdr.len += sizeof(struct ip6_hdr);
|
|
|
|
oip6 = mtod(n, struct ip6_hdr *);
|
|
|
|
} else {
|
|
|
|
m->m_next->m_len += sizeof(struct ip6_hdr);
|
|
|
|
m->m_next->m_data -= sizeof(struct ip6_hdr);
|
|
|
|
m->m_pkthdr.len += sizeof(struct ip6_hdr);
|
|
|
|
oip6 = mtod(m->m_next, struct ip6_hdr *);
|
|
|
|
}
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr));
|
|
|
|
|
|
|
|
/* Fake link-local scope-class addresses */
|
2003-10-03 12:46:15 +04:00
|
|
|
in6_clearscope(&oip6->ip6_src);
|
|
|
|
in6_clearscope(&oip6->ip6_dst);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* 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;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
sa6 = *(struct sockaddr_in6 *)&sav->sah->saidx.src;
|
|
|
|
if ((error = sa6_embedscope(&sa6, 0)) != 0)
|
|
|
|
return (error);
|
|
|
|
ip6->ip6_src = sa6.sin6_addr;
|
|
|
|
|
|
|
|
sa6 = *(struct sockaddr_in6 *)&sav->sah->saidx.dst;
|
|
|
|
if ((error = sa6_embedscope(&sa6, 0)) != 0)
|
|
|
|
return (error);
|
|
|
|
ip6->ip6_dst = sa6.sin6_addr;
|
|
|
|
|
2001-04-15 05:55:49 +04:00
|
|
|
ip6->ip6_hlim = IPV6_DEFHLIM;
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* XXX Should ip6_src be updated later ? */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-06 02:20:44 +04:00
|
|
|
#endif /* INET6 */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the variable replay window.
|
|
|
|
* ipsec_chkreplay() performs replay check before ICV verification.
|
|
|
|
* ipsec_updatereplay() updates replay bitmap. This must be called after
|
|
|
|
* ICV verification (it also performs replay check, which is usually done
|
|
|
|
* beforehand).
|
|
|
|
* 0 (zero) is returned if packet disallowed, 1 if packet permitted.
|
|
|
|
*
|
|
|
|
* based on RFC 2401.
|
2003-09-07 19:59:36 +04:00
|
|
|
*
|
|
|
|
* XXX need to update for 64bit sequence number - 2401bis
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec_chkreplay(seq, sav)
|
1999-06-28 10:36:47 +04:00
|
|
|
u_int32_t seq;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
const struct secreplay *replay;
|
|
|
|
u_int32_t diff;
|
|
|
|
int fr;
|
|
|
|
u_int32_t wsizeb; /* constant: bits of window size */
|
|
|
|
int frlast; /* constant: last frame */
|
|
|
|
|
|
|
|
/* sanity check */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (sav == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_chkreplay: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
replay = sav->replay;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (replay->wsize == 0)
|
|
|
|
return 1; /* no need to check replay. */
|
|
|
|
|
|
|
|
/* constant */
|
|
|
|
frlast = replay->wsize - 1;
|
|
|
|
wsizeb = replay->wsize << 3;
|
|
|
|
|
|
|
|
/* sequence number of 0 is invalid */
|
|
|
|
if (seq == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* first time is always okay */
|
|
|
|
if (replay->count == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (seq > replay->lastseq) {
|
|
|
|
/* larger sequences are okay */
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
/* seq is equal or less than lastseq. */
|
|
|
|
diff = replay->lastseq - seq;
|
|
|
|
|
|
|
|
/* over range to check, i.e. too old or wrapped */
|
|
|
|
if (diff >= wsizeb)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fr = frlast - diff / 8;
|
|
|
|
|
|
|
|
/* this packet already seen ? */
|
2002-09-11 06:41:19 +04:00
|
|
|
if (replay->bitmap[fr] & (1 << (diff % 8)))
|
1999-06-28 10:36:47 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* out of order but good */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
/*
|
|
|
|
* check replay counter whether to update or not.
|
|
|
|
* OUT: 0: OK
|
|
|
|
* 1: NG
|
2003-09-07 19:59:36 +04:00
|
|
|
* XXX need to update for 64bit sequence number - 2401bis
|
2000-01-31 17:18:52 +03:00
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec_updatereplay(seq, sav)
|
1999-06-28 10:36:47 +04:00
|
|
|
u_int32_t seq;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct secreplay *replay;
|
2003-09-07 19:59:36 +04:00
|
|
|
u_int64_t diff;
|
1999-06-28 10:36:47 +04:00
|
|
|
int fr;
|
|
|
|
u_int32_t wsizeb; /* constant: bits of window size */
|
|
|
|
int frlast; /* constant: last frame */
|
|
|
|
|
|
|
|
/* sanity check */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (sav == NULL)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_chkreplay: NULL pointer was passed.");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
replay = sav->replay;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (replay->wsize == 0)
|
|
|
|
goto ok; /* no need to check replay. */
|
|
|
|
|
|
|
|
/* constant */
|
|
|
|
frlast = replay->wsize - 1;
|
|
|
|
wsizeb = replay->wsize << 3;
|
|
|
|
|
|
|
|
/* sequence number of 0 is invalid */
|
|
|
|
if (seq == 0)
|
2000-01-31 17:18:52 +03:00
|
|
|
return 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* first time */
|
|
|
|
if (replay->count == 0) {
|
|
|
|
replay->lastseq = seq;
|
|
|
|
bzero(replay->bitmap, replay->wsize);
|
2002-09-11 06:41:19 +04:00
|
|
|
replay->bitmap[frlast] = 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
goto ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (seq > replay->lastseq) {
|
|
|
|
/* seq is larger than lastseq. */
|
|
|
|
diff = seq - replay->lastseq;
|
|
|
|
|
|
|
|
/* new larger sequence number */
|
|
|
|
if (diff < wsizeb) {
|
|
|
|
/* In window */
|
|
|
|
/* set bit for this packet */
|
|
|
|
vshiftl(replay->bitmap, diff, replay->wsize);
|
2002-09-11 06:41:19 +04:00
|
|
|
replay->bitmap[frlast] |= 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
} else {
|
|
|
|
/* this packet has a "way larger" */
|
|
|
|
bzero(replay->bitmap, replay->wsize);
|
2002-09-11 06:41:19 +04:00
|
|
|
replay->bitmap[frlast] = 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
replay->lastseq = seq;
|
|
|
|
|
|
|
|
/* larger is good */
|
|
|
|
} else {
|
|
|
|
/* seq is equal or less than lastseq. */
|
|
|
|
diff = replay->lastseq - seq;
|
|
|
|
|
|
|
|
/* over range to check, i.e. too old or wrapped */
|
|
|
|
if (diff >= wsizeb)
|
2000-01-31 17:18:52 +03:00
|
|
|
return 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
fr = frlast - diff / 8;
|
|
|
|
|
|
|
|
/* this packet already seen ? */
|
2002-09-11 06:41:19 +04:00
|
|
|
if (replay->bitmap[fr] & (1 << (diff % 8)))
|
2000-01-31 17:18:52 +03:00
|
|
|
return 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* mark as seen */
|
2002-09-11 06:41:19 +04:00
|
|
|
replay->bitmap[fr] |= (1 << (diff % 8));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* out of order but good */
|
|
|
|
}
|
|
|
|
|
|
|
|
ok:
|
2003-09-07 19:59:36 +04:00
|
|
|
if (replay->count == 0xffffffff) {
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
/* set overflow flag */
|
|
|
|
replay->overflow++;
|
|
|
|
|
|
|
|
/* don't increment, no more packets accepted */
|
|
|
|
if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
ipseclog((LOG_WARNING, "replay counter made %d cycle. %s\n",
|
|
|
|
replay->overflow, ipsec_logsastr(sav)));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
replay->count++;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-06-11 21:26:52 +04:00
|
|
|
* shift variable length buffer to left.
|
1999-06-28 10:36:47 +04:00
|
|
|
* IN: bitmap: pointer to the buffer
|
|
|
|
* nbit: the number of to shift.
|
|
|
|
* wsize: buffer size (bytes).
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
vshiftl(bitmap, nbit, wsize)
|
|
|
|
unsigned char *bitmap;
|
|
|
|
int nbit, wsize;
|
|
|
|
{
|
|
|
|
int s, j, i;
|
|
|
|
unsigned char over;
|
|
|
|
|
|
|
|
for (j = 0; j < nbit; j += 8) {
|
|
|
|
s = (nbit - j < 8) ? (nbit - j): 8;
|
|
|
|
bitmap[0] <<= s;
|
|
|
|
for (i = 1; i < wsize; i++) {
|
|
|
|
over = (bitmap[i] >> (8 - s));
|
|
|
|
bitmap[i] <<= s;
|
2002-09-11 06:41:19 +04:00
|
|
|
bitmap[i - 1] |= over;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
ipsec4_logpacketstr(ip, spi)
|
|
|
|
struct ip *ip;
|
|
|
|
u_int32_t spi;
|
|
|
|
{
|
|
|
|
static char buf[256];
|
|
|
|
char *p;
|
|
|
|
u_int8_t *s, *d;
|
|
|
|
|
|
|
|
s = (u_int8_t *)(&ip->ip_src);
|
|
|
|
d = (u_int8_t *)(&ip->ip_dst);
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
p = buf;
|
1999-08-25 16:56:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi));
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
2000-09-22 09:49:46 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), "src=%u.%u.%u.%u",
|
1999-06-28 10:36:47 +04:00
|
|
|
s[0], s[1], s[2], s[3]);
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
2000-09-22 09:49:46 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), " dst=%u.%u.%u.%u",
|
1999-06-28 10:36:47 +04:00
|
|
|
d[0], d[1], d[2], d[3]);
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), ")");
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
const char *
|
|
|
|
ipsec6_logpacketstr(ip6, spi)
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
u_int32_t spi;
|
|
|
|
{
|
|
|
|
static char buf[256];
|
|
|
|
char *p;
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
p = buf;
|
1999-08-25 16:56:38 +04:00
|
|
|
snprintf(buf, sizeof(buf), "packet(SPI=%u ", (u_int32_t)ntohl(spi));
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), "src=%s",
|
|
|
|
ip6_sprintf(&ip6->ip6_src));
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), " dst=%s",
|
|
|
|
ip6_sprintf(&ip6->ip6_dst));
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), ")");
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
2001-08-06 02:20:44 +04:00
|
|
|
#endif /* INET6 */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
const char *
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec_logsastr(sav)
|
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
static char buf[256];
|
|
|
|
char *p;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasindex *saidx = &sav->sah->saidx;
|
|
|
|
|
|
|
|
/* validity check */
|
|
|
|
if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family
|
|
|
|
!= ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family)
|
2002-09-27 19:35:29 +04:00
|
|
|
panic("ipsec_logsastr: family mismatched.");
|
2000-01-31 17:18:52 +03:00
|
|
|
|
|
|
|
p = buf;
|
|
|
|
snprintf(buf, sizeof(buf), "SA(SPI=%u ", (u_int32_t)ntohl(sav->spi));
|
|
|
|
while (p && *p)
|
|
|
|
p++;
|
|
|
|
if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET) {
|
1999-06-28 10:36:47 +04:00
|
|
|
u_int8_t *s, *d;
|
2000-01-31 17:18:52 +03:00
|
|
|
s = (u_int8_t *)&((struct sockaddr_in *)&saidx->src)->sin_addr;
|
|
|
|
d = (u_int8_t *)&((struct sockaddr_in *)&saidx->dst)->sin_addr;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf),
|
|
|
|
"src=%d.%d.%d.%d dst=%d.%d.%d.%d",
|
|
|
|
s[0], s[1], s[2], s[3], d[0], d[1], d[2], d[3]);
|
1999-07-01 12:12:45 +04:00
|
|
|
}
|
|
|
|
#ifdef INET6
|
2000-01-31 17:18:52 +03:00
|
|
|
else if (((struct sockaddr *)&saidx->src)->sa_family == AF_INET6) {
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf),
|
2000-01-31 17:18:52 +03:00
|
|
|
"src=%s",
|
|
|
|
ip6_sprintf(&((struct sockaddr_in6 *)&saidx->src)->sin6_addr));
|
|
|
|
while (p && *p)
|
|
|
|
p++;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf),
|
2000-01-31 17:18:52 +03:00
|
|
|
" dst=%s",
|
|
|
|
ip6_sprintf(&((struct sockaddr_in6 *)&saidx->dst)->sin6_addr));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
1999-07-01 12:12:45 +04:00
|
|
|
#endif
|
2000-01-31 17:18:52 +03:00
|
|
|
while (p && *p)
|
|
|
|
p++;
|
1999-06-28 10:36:47 +04:00
|
|
|
snprintf(p, sizeof(buf) - (p - buf), ")");
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ipsec_dumpmbuf(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
int totlen;
|
|
|
|
int i;
|
|
|
|
u_char *p;
|
|
|
|
|
|
|
|
totlen = 0;
|
|
|
|
printf("---\n");
|
|
|
|
while (m) {
|
|
|
|
p = mtod(m, u_char *);
|
|
|
|
for (i = 0; i < m->m_len; i++) {
|
|
|
|
printf("%02x ", p[i]);
|
|
|
|
totlen++;
|
|
|
|
if (totlen % 16 == 0)
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
m = m->m_next;
|
|
|
|
}
|
|
|
|
if (totlen % 16 != 0)
|
|
|
|
printf("\n");
|
|
|
|
printf("---\n");
|
|
|
|
}
|
|
|
|
|
2000-10-02 07:55:41 +04:00
|
|
|
#ifdef INET
|
2002-06-27 16:12:49 +04:00
|
|
|
static int
|
|
|
|
ipsec4_checksa(isr, state)
|
|
|
|
struct ipsecrequest *isr;
|
|
|
|
struct ipsec_output_state *state;
|
|
|
|
{
|
|
|
|
struct ip *ip;
|
|
|
|
struct secasindex saidx;
|
|
|
|
struct sockaddr_in *sin;
|
|
|
|
|
|
|
|
/* make SA index for search proper SA */
|
|
|
|
ip = mtod(state->m, struct ip *);
|
|
|
|
bcopy(&isr->saidx, &saidx, sizeof(saidx));
|
|
|
|
saidx.mode = isr->saidx.mode;
|
|
|
|
saidx.reqid = isr->saidx.reqid;
|
|
|
|
sin = (struct sockaddr_in *)&saidx.src;
|
|
|
|
if (sin->sin_len == 0) {
|
2004-02-11 13:42:24 +03:00
|
|
|
bzero(sin, sizeof(*sin));
|
2002-06-27 16:12:49 +04:00
|
|
|
sin->sin_len = sizeof(*sin);
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_port = IPSEC_PORT_ANY;
|
|
|
|
bcopy(&ip->ip_src, &sin->sin_addr, sizeof(sin->sin_addr));
|
|
|
|
}
|
|
|
|
sin = (struct sockaddr_in *)&saidx.dst;
|
|
|
|
if (sin->sin_len == 0) {
|
2004-02-11 13:42:24 +03:00
|
|
|
bzero(sin, sizeof(*sin));
|
2002-06-27 16:12:49 +04:00
|
|
|
sin->sin_len = sizeof(*sin);
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_port = IPSEC_PORT_ANY;
|
|
|
|
bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(sin->sin_addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
return key_checkrequest(isr, &saidx);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IPsec output logic for IPv4.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipsec4_output(state, sp, flags)
|
|
|
|
struct ipsec_output_state *state;
|
|
|
|
struct secpolicy *sp;
|
|
|
|
int flags;
|
|
|
|
{
|
|
|
|
struct ip *ip = NULL;
|
|
|
|
struct ipsecrequest *isr = NULL;
|
|
|
|
int s;
|
|
|
|
int error;
|
|
|
|
struct sockaddr_in *dst4;
|
|
|
|
|
|
|
|
if (!state)
|
|
|
|
panic("state == NULL in ipsec4_output");
|
|
|
|
if (!state->m)
|
|
|
|
panic("state->m == NULL in ipsec4_output");
|
|
|
|
if (!state->ro)
|
|
|
|
panic("state->ro == NULL in ipsec4_output");
|
|
|
|
if (!state->dst)
|
|
|
|
panic("state->dst == NULL in ipsec4_output");
|
2001-11-21 09:28:08 +03:00
|
|
|
state->encap = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
|
|
|
printf("ipsec4_output: applyed SP\n");
|
|
|
|
kdebug_secpolicy(sp));
|
|
|
|
|
|
|
|
for (isr = sp->req; isr != NULL; isr = isr->next) {
|
|
|
|
|
1999-07-31 22:41:15 +04:00
|
|
|
#if 0 /* give up to check restriction of transport mode */
|
|
|
|
/* XXX but should be checked somewhere */
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* some of the IPsec operation must be performed only in
|
|
|
|
* originating case.
|
|
|
|
*/
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TRANSPORT
|
1999-06-28 10:36:47 +04:00
|
|
|
&& (flags & IP_FORWARDING))
|
|
|
|
continue;
|
1999-07-31 22:41:15 +04:00
|
|
|
#endif
|
2002-06-27 16:12:49 +04:00
|
|
|
error = ipsec4_checksa(isr, state);
|
|
|
|
if (error != 0) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IPsec processing is required, but no SA found.
|
|
|
|
* I assume that key_acquire() had been called
|
|
|
|
* to get/establish the SA. Here I discard
|
|
|
|
* this packet because it is responsibility for
|
|
|
|
* upper layer to retransmit the packet.
|
|
|
|
*/
|
|
|
|
ipsecstat.out_nosa++;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validity check */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->sav == NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
switch (ipsec_get_reqlevel(isr, AF_INET)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_LEVEL_USE:
|
|
|
|
continue;
|
|
|
|
case IPSEC_LEVEL_REQUIRE:
|
2005-03-09 17:17:13 +03:00
|
|
|
if (isr->saidx.proto == AF_INET ||
|
|
|
|
isr->saidx.proto == AF_INET6)
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
/* must be not reached here. */
|
|
|
|
panic("ipsec4_output: no SA found, but required.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
/*
|
|
|
|
* If there is no valid SA, we give up to process any
|
|
|
|
* more. In such a case, the SA's status is changed
|
|
|
|
* from DYING to DEAD after allocating. If a packet
|
|
|
|
* send to the receiver by dead SA, the receiver can
|
|
|
|
* not decode a packet because SA has been dead.
|
|
|
|
*/
|
|
|
|
if (isr->sav->state != SADB_SASTATE_MATURE
|
|
|
|
&& isr->sav->state != SADB_SASTATE_DYING) {
|
1999-06-28 10:36:47 +04:00
|
|
|
ipsecstat.out_nosa++;
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There may be the case that SA status will be changed when
|
1999-07-04 06:01:15 +04:00
|
|
|
* we are refering to one. So calling splsoftnet().
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* build IPsec tunnel.
|
|
|
|
*/
|
|
|
|
/* XXX should be processed with other familiy */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET) {
|
|
|
|
ipseclog((LOG_ERR, "ipsec4_output: "
|
|
|
|
"family mismatched between inner and outer spi=%u\n",
|
|
|
|
(u_int32_t)ntohl(isr->sav->spi)));
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->m = ipsec4_splithdr(state->m);
|
|
|
|
if (!state->m) {
|
|
|
|
splx(s);
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
2000-01-31 17:18:52 +03:00
|
|
|
error = ipsec4_encapsulate(state->m, isr->sav);
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
|
|
|
if (error) {
|
|
|
|
state->m = NULL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip = mtod(state->m, struct ip *);
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
state->ro = &isr->sav->sah->sa_route;
|
1999-06-28 10:36:47 +04:00
|
|
|
state->dst = (struct sockaddr *)&state->ro->ro_dst;
|
|
|
|
dst4 = (struct sockaddr_in *)state->dst;
|
|
|
|
if (state->ro->ro_rt
|
|
|
|
&& ((state->ro->ro_rt->rt_flags & RTF_UP) == 0
|
|
|
|
|| dst4->sin_addr.s_addr != ip->ip_dst.s_addr)) {
|
|
|
|
RTFREE(state->ro->ro_rt);
|
|
|
|
bzero((caddr_t)state->ro, sizeof (*state->ro));
|
|
|
|
}
|
|
|
|
if (state->ro->ro_rt == 0) {
|
|
|
|
dst4->sin_family = AF_INET;
|
|
|
|
dst4->sin_len = sizeof(*dst4);
|
|
|
|
dst4->sin_addr = ip->ip_dst;
|
|
|
|
rtalloc(state->ro);
|
|
|
|
}
|
|
|
|
if (state->ro->ro_rt == 0) {
|
|
|
|
ipstat.ips_noroute++;
|
|
|
|
error = EHOSTUNREACH;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2001-02-08 18:04:26 +03:00
|
|
|
/* adjust state->dst if tunnel endpoint is offlink */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
|
|
|
|
state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
|
|
|
|
dst4 = (struct sockaddr_in *)state->dst;
|
|
|
|
}
|
2001-11-21 09:28:08 +03:00
|
|
|
|
|
|
|
state->encap++;
|
1999-06-28 10:36:47 +04:00
|
|
|
} else
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
state->m = ipsec4_splithdr(state->m);
|
|
|
|
if (!state->m) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (isr->saidx.proto) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPPROTO_ESP:
|
|
|
|
#ifdef IPSEC_ESP
|
|
|
|
if ((error = esp4_output(state->m, isr)) != 0) {
|
|
|
|
state->m = NULL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
m_freem(state->m);
|
|
|
|
state->m = NULL;
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
#endif
|
|
|
|
case IPPROTO_AH:
|
|
|
|
if ((error = ah4_output(state->m, isr)) != 0) {
|
|
|
|
state->m = NULL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IPPROTO_IPCOMP:
|
|
|
|
if ((error = ipcomp4_output(state->m, isr)) != 0) {
|
|
|
|
state->m = NULL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
break;
|
2005-03-09 17:17:13 +03:00
|
|
|
case IPPROTO_IPV4:
|
|
|
|
break;
|
|
|
|
case IPPROTO_IPV6:
|
|
|
|
ipseclog((LOG_ERR, "ipsec4_output: "
|
|
|
|
"family mismatched between inner and outer "
|
|
|
|
"header\n"));
|
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR,
|
|
|
|
"ipsec4_output: unknown ipsec protocol %d\n",
|
|
|
|
isr->saidx.proto));
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(state->m);
|
|
|
|
state->m = NULL;
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->m == 0) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip = mtod(state->m, struct ip *);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
m_freem(state->m);
|
|
|
|
state->m = NULL;
|
|
|
|
return error;
|
|
|
|
}
|
2000-10-02 07:55:41 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#ifdef INET6
|
2002-06-27 16:12:49 +04:00
|
|
|
static int
|
|
|
|
ipsec6_checksa(isr, state, tunnel)
|
|
|
|
struct ipsecrequest *isr;
|
|
|
|
struct ipsec_output_state *state;
|
|
|
|
int tunnel;
|
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
struct secasindex saidx;
|
|
|
|
struct sockaddr_in6 *sin6;
|
|
|
|
|
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (!tunnel)
|
|
|
|
panic("ipsec6_checksa/inconsistent tunnel attribute");
|
|
|
|
#endif
|
|
|
|
/* When tunnel mode, SA peers must be specified. */
|
|
|
|
return key_checkrequest(isr, &isr->saidx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make SA index for search proper SA */
|
|
|
|
ip6 = mtod(state->m, struct ip6_hdr *);
|
|
|
|
if (tunnel) {
|
|
|
|
bzero(&saidx, sizeof(saidx));
|
|
|
|
saidx.proto = isr->saidx.proto;
|
|
|
|
} else
|
|
|
|
bcopy(&isr->saidx, &saidx, sizeof(saidx));
|
|
|
|
saidx.mode = isr->saidx.mode;
|
|
|
|
saidx.reqid = isr->saidx.reqid;
|
|
|
|
sin6 = (struct sockaddr_in6 *)&saidx.src;
|
|
|
|
if (sin6->sin6_len == 0 || tunnel) {
|
2004-02-11 13:42:24 +03:00
|
|
|
bzero(sin6, sizeof(*sin6));
|
2002-06-27 16:12:49 +04:00
|
|
|
sin6->sin6_len = sizeof(*sin6);
|
|
|
|
sin6->sin6_family = AF_INET6;
|
|
|
|
sin6->sin6_port = IPSEC_PORT_ANY;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
sin6->sin6_addr = ip6->ip6_src;
|
2002-06-27 16:12:49 +04:00
|
|
|
}
|
|
|
|
sin6 = (struct sockaddr_in6 *)&saidx.dst;
|
|
|
|
if (sin6->sin6_len == 0 || tunnel) {
|
2004-02-11 13:42:24 +03:00
|
|
|
bzero(sin6, sizeof(*sin6));
|
2002-06-27 16:12:49 +04:00
|
|
|
sin6->sin6_len = sizeof(*sin6);
|
|
|
|
sin6->sin6_family = AF_INET6;
|
|
|
|
sin6->sin6_port = IPSEC_PORT_ANY;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
sin6->sin6_addr = ip6->ip6_dst;
|
2002-06-27 16:12:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return key_checkrequest(isr, &saidx);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IPsec output logic for IPv6, transport mode.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
|
|
|
|
struct ipsec_output_state *state;
|
|
|
|
u_char *nexthdrp;
|
|
|
|
struct mbuf *mprev;
|
|
|
|
struct secpolicy *sp;
|
|
|
|
int flags;
|
|
|
|
int *tun;
|
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
struct ipsecrequest *isr = NULL;
|
|
|
|
int error = 0;
|
|
|
|
int plen;
|
|
|
|
|
|
|
|
if (!state)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("state == NULL in ipsec6_output_trans");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!state->m)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("state->m == NULL in ipsec6_output_trans");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!nexthdrp)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("nexthdrp == NULL in ipsec6_output_trans");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!mprev)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("mprev == NULL in ipsec6_output_trans");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!sp)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("sp == NULL in ipsec6_output_trans");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!tun)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("tun == NULL in ipsec6_output_trans");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
2000-01-31 17:18:52 +03:00
|
|
|
printf("ipsec6_output_trans: applyed SP\n");
|
1999-06-28 10:36:47 +04:00
|
|
|
kdebug_secpolicy(sp));
|
|
|
|
|
|
|
|
*tun = 0;
|
|
|
|
for (isr = sp->req; isr; isr = isr->next) {
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/* the rest will be handled by ipsec6_output_tunnel() */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2002-06-27 16:12:49 +04:00
|
|
|
error = ipsec6_checksa(isr, state, 0);
|
|
|
|
if (error == ENOENT) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IPsec processing is required, but no SA found.
|
|
|
|
* I assume that key_acquire() had been called
|
|
|
|
* to get/establish the SA. Here I discard
|
|
|
|
* this packet because it is responsibility for
|
|
|
|
* upper layer to retransmit the packet.
|
|
|
|
*/
|
|
|
|
ipsec6stat.out_nosa++;
|
2001-02-08 18:04:26 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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?
|
2001-08-06 14:25:00 +04:00
|
|
|
*
|
|
|
|
* Noone have initialized rcvif until this point,
|
|
|
|
* so clear it.
|
2001-02-08 18:04:26 +03:00
|
|
|
*/
|
2001-08-06 14:25:00 +04:00
|
|
|
if ((state->m->m_flags & M_PKTHDR) != 0)
|
|
|
|
state->m->m_pkthdr.rcvif = NULL;
|
2001-02-08 18:04:26 +03:00
|
|
|
icmp6_error(state->m, ICMP6_DST_UNREACH,
|
|
|
|
ICMP6_DST_UNREACH_ADMIN, 0);
|
|
|
|
state->m = NULL; /* icmp6_error freed the mbuf */
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validity check */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->sav == NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
switch (ipsec_get_reqlevel(isr, AF_INET6)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_LEVEL_USE:
|
|
|
|
continue;
|
|
|
|
case IPSEC_LEVEL_REQUIRE:
|
|
|
|
/* must be not reached here. */
|
2000-01-31 17:18:52 +03:00
|
|
|
panic("ipsec6_output_trans: no SA found, but required.");
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
/*
|
|
|
|
* If there is no valid SA, we give up to process.
|
|
|
|
* see same place at ipsec4_output().
|
|
|
|
*/
|
|
|
|
if (isr->sav->state != SADB_SASTATE_MATURE
|
|
|
|
&& isr->sav->state != SADB_SASTATE_DYING) {
|
1999-06-28 10:36:47 +04:00
|
|
|
ipsec6stat.out_nosa++;
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (isr->saidx.proto) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPPROTO_ESP:
|
|
|
|
#ifdef IPSEC_ESP
|
|
|
|
error = esp6_output(state->m, nexthdrp, mprev->m_next, isr);
|
|
|
|
#else
|
|
|
|
m_freem(state->m);
|
|
|
|
error = EINVAL;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case IPPROTO_AH:
|
|
|
|
error = ah6_output(state->m, nexthdrp, mprev->m_next, isr);
|
|
|
|
break;
|
|
|
|
case IPPROTO_IPCOMP:
|
|
|
|
error = ipcomp6_output(state->m, nexthdrp, mprev->m_next, isr);
|
|
|
|
break;
|
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_output_trans: "
|
|
|
|
"unknown ipsec protocol %d\n", isr->saidx.proto));
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(state->m);
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6stat.out_inval++;
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
state->m = NULL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr);
|
|
|
|
if (plen > IPV6_MAXPACKET) {
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_output_trans: "
|
|
|
|
"IPsec with IPv6 jumbogram is not supported\n"));
|
1999-06-28 10:36:47 +04:00
|
|
|
ipsec6stat.out_inval++;
|
2001-08-06 02:20:44 +04:00
|
|
|
error = EINVAL; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip6 = mtod(state->m, struct ip6_hdr *);
|
|
|
|
ip6->ip6_plen = htons(plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we have more to go, we need a tunnel mode processing */
|
|
|
|
if (isr != NULL)
|
|
|
|
*tun = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
m_freem(state->m);
|
|
|
|
state->m = NULL;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IPsec output logic for IPv6, tunnel mode.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ipsec6_output_tunnel(state, sp, flags)
|
|
|
|
struct ipsec_output_state *state;
|
|
|
|
struct secpolicy *sp;
|
|
|
|
int flags;
|
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
struct ipsecrequest *isr = NULL;
|
|
|
|
int error = 0;
|
|
|
|
int plen;
|
|
|
|
struct sockaddr_in6* dst6;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
if (!state)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("state == NULL in ipsec6_output_tunnel");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!state->m)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("state->m == NULL in ipsec6_output_tunnel");
|
1999-06-28 10:36:47 +04:00
|
|
|
if (!sp)
|
2001-08-06 14:25:00 +04:00
|
|
|
panic("sp == NULL in ipsec6_output_tunnel");
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
|
|
|
|
printf("ipsec6_output_tunnel: applyed SP\n");
|
|
|
|
kdebug_secpolicy(sp));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* transport mode ipsec (before the 1st tunnel mode) is already
|
|
|
|
* processed by ipsec6_output_trans().
|
|
|
|
*/
|
|
|
|
for (isr = sp->req; isr; isr = isr->next) {
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-08-06 02:20:44 +04:00
|
|
|
for (/* already initialized */; isr; isr = isr->next) {
|
2002-06-27 16:12:49 +04:00
|
|
|
error = ipsec6_checksa(isr, state, 1);
|
|
|
|
if (error == ENOENT) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* IPsec processing is required, but no SA found.
|
|
|
|
* I assume that key_acquire() had been called
|
|
|
|
* to get/establish the SA. Here I discard
|
|
|
|
* this packet because it is responsibility for
|
|
|
|
* upper layer to retransmit the packet.
|
|
|
|
*/
|
|
|
|
ipsec6stat.out_nosa++;
|
|
|
|
error = ENOENT;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validity check */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->sav == NULL) {
|
2002-06-12 05:47:34 +04:00
|
|
|
switch (ipsec_get_reqlevel(isr, AF_INET6)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSEC_LEVEL_USE:
|
|
|
|
continue;
|
|
|
|
case IPSEC_LEVEL_REQUIRE:
|
|
|
|
/* must be not reached here. */
|
|
|
|
panic("ipsec6_output_tunnel: no SA found, but required.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
/*
|
|
|
|
* If there is no valid SA, we give up to process.
|
|
|
|
* see same place at ipsec4_output().
|
|
|
|
*/
|
|
|
|
if (isr->sav->state != SADB_SASTATE_MATURE
|
|
|
|
&& isr->sav->state != SADB_SASTATE_DYING) {
|
1999-06-28 10:36:47 +04:00
|
|
|
ipsec6stat.out_nosa++;
|
|
|
|
error = EINVAL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There may be the case that SA status will be changed when
|
1999-07-04 06:01:15 +04:00
|
|
|
* we are refering to one. So calling splsoftnet().
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* build IPsec tunnel.
|
|
|
|
*/
|
|
|
|
/* XXX should be processed with other familiy */
|
2000-01-31 17:18:52 +03:00
|
|
|
if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET6) {
|
|
|
|
ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
|
|
|
|
"family mismatched between inner and outer, spi=%u\n",
|
|
|
|
(u_int32_t)ntohl(isr->sav->spi)));
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6stat.out_inval++;
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EAFNOSUPPORT;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
state->m = ipsec6_splithdr(state->m);
|
|
|
|
if (!state->m) {
|
|
|
|
splx(s);
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6stat.out_nomem++;
|
1999-06-28 10:36:47 +04:00
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
2000-01-31 17:18:52 +03:00
|
|
|
error = ipsec6_encapsulate(state->m, isr->sav);
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
|
|
|
if (error) {
|
|
|
|
state->m = 0;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip6 = mtod(state->m, struct ip6_hdr *);
|
|
|
|
|
2000-01-31 17:18:52 +03:00
|
|
|
state->ro = &isr->sav->sah->sa_route;
|
1999-06-28 10:36:47 +04:00
|
|
|
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);
|
|
|
|
bzero((caddr_t)state->ro, sizeof (*state->ro));
|
|
|
|
}
|
|
|
|
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++;
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6stat.out_noroute++;
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EHOSTUNREACH;
|
|
|
|
goto bad;
|
|
|
|
}
|
2001-02-08 18:04:26 +03:00
|
|
|
|
|
|
|
/* adjust state->dst if tunnel endpoint is offlink */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
|
|
|
|
state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
|
|
|
|
dst6 = (struct sockaddr_in6 *)state->dst;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
state->m = ipsec6_splithdr(state->m);
|
|
|
|
if (!state->m) {
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6stat.out_nomem++;
|
1999-06-28 10:36:47 +04:00
|
|
|
error = ENOMEM;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip6 = mtod(state->m, struct ip6_hdr *);
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (isr->saidx.proto) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPPROTO_ESP:
|
|
|
|
#ifdef IPSEC_ESP
|
2002-06-11 21:26:52 +04:00
|
|
|
error = esp6_output(state->m, &ip6->ip6_nxt,
|
|
|
|
state->m->m_next, isr);
|
1999-06-28 10:36:47 +04:00
|
|
|
#else
|
|
|
|
m_freem(state->m);
|
|
|
|
error = EINVAL;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case IPPROTO_AH:
|
2002-06-11 21:26:52 +04:00
|
|
|
error = ah6_output(state->m, &ip6->ip6_nxt,
|
|
|
|
state->m->m_next, isr);
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
2000-01-16 21:06:03 +03:00
|
|
|
case IPPROTO_IPCOMP:
|
|
|
|
/* XXX code should be here */
|
2001-08-06 02:20:44 +04:00
|
|
|
/* FALLTHROUGH */
|
1999-06-28 10:36:47 +04:00
|
|
|
default:
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
|
|
|
|
"unknown ipsec protocol %d\n", isr->saidx.proto));
|
1999-06-28 10:36:47 +04:00
|
|
|
m_freem(state->m);
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6stat.out_inval++;
|
1999-06-28 10:36:47 +04:00
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
state->m = NULL;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
plen = state->m->m_pkthdr.len - sizeof(struct ip6_hdr);
|
|
|
|
if (plen > IPV6_MAXPACKET) {
|
2000-01-31 17:18:52 +03:00
|
|
|
ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
|
|
|
|
"IPsec with IPv6 jumbogram is not supported\n"));
|
1999-06-28 10:36:47 +04:00
|
|
|
ipsec6stat.out_inval++;
|
2001-08-06 02:20:44 +04:00
|
|
|
error = EINVAL; /* XXX */
|
1999-06-28 10:36:47 +04:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
ip6 = mtod(state->m, struct ip6_hdr *);
|
|
|
|
ip6->ip6_plen = htons(plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
m_freem(state->m);
|
|
|
|
state->m = NULL;
|
|
|
|
return error;
|
|
|
|
}
|
2001-08-06 02:20:44 +04:00
|
|
|
#endif /* INET6 */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2000-10-02 07:55:41 +04:00
|
|
|
#ifdef INET
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Chop IP header and option off from the payload.
|
|
|
|
*/
|
|
|
|
static struct mbuf *
|
|
|
|
ipsec4_splithdr(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
struct mbuf *mh;
|
|
|
|
struct ip *ip;
|
|
|
|
int hlen;
|
|
|
|
|
|
|
|
if (m->m_len < sizeof(struct ip))
|
|
|
|
panic("ipsec4_splithdr: first mbuf too short");
|
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
hlen = ip->ip_hl << 2;
|
|
|
|
if (m->m_len > hlen) {
|
|
|
|
MGETHDR(mh, M_DONTWAIT, MT_HEADER);
|
|
|
|
if (!mh) {
|
|
|
|
m_freem(m);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-08-18 04:30:58 +04:00
|
|
|
M_MOVE_PKTHDR(mh, m);
|
1999-06-28 10:36:47 +04:00
|
|
|
MH_ALIGN(mh, hlen);
|
|
|
|
m->m_len -= hlen;
|
|
|
|
m->m_data += hlen;
|
|
|
|
mh->m_next = m;
|
|
|
|
m = mh;
|
|
|
|
m->m_len = hlen;
|
|
|
|
bcopy((caddr_t)ip, mtod(m, caddr_t), hlen);
|
|
|
|
} else if (m->m_len < hlen) {
|
|
|
|
m = m_pullup(m, hlen);
|
|
|
|
if (!m)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
2000-10-02 07:55:41 +04:00
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
static struct mbuf *
|
|
|
|
ipsec6_splithdr(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
struct mbuf *mh;
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
int hlen;
|
|
|
|
|
|
|
|
if (m->m_len < sizeof(struct ip6_hdr))
|
|
|
|
panic("ipsec6_splithdr: first mbuf too short");
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
hlen = sizeof(struct ip6_hdr);
|
|
|
|
if (m->m_len > hlen) {
|
|
|
|
MGETHDR(mh, M_DONTWAIT, MT_HEADER);
|
|
|
|
if (!mh) {
|
|
|
|
m_freem(m);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-08-18 04:30:58 +04:00
|
|
|
M_MOVE_PKTHDR(mh, m);
|
1999-06-28 10:36:47 +04:00
|
|
|
MH_ALIGN(mh, hlen);
|
|
|
|
m->m_len -= hlen;
|
|
|
|
m->m_data += hlen;
|
|
|
|
mh->m_next = m;
|
|
|
|
m = mh;
|
|
|
|
m->m_len = hlen;
|
|
|
|
bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen);
|
|
|
|
} else if (m->m_len < hlen) {
|
|
|
|
m = m_pullup(m, hlen);
|
|
|
|
if (!m)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* validate inbound IPsec tunnel packet. */
|
|
|
|
int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec4_tunnel_validate(ip, nxt0, sav)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ip *ip;
|
|
|
|
u_int nxt0;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
u_int8_t nxt = nxt0 & 0xff;
|
|
|
|
struct sockaddr_in *sin;
|
|
|
|
int hlen;
|
|
|
|
|
|
|
|
if (nxt != IPPROTO_IPV4)
|
|
|
|
return 0;
|
2000-11-10 04:10:36 +03:00
|
|
|
/* do not decapsulate if the SA is for transport mode only */
|
|
|
|
if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT)
|
|
|
|
return 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
hlen = ip->ip_hl << 2;
|
|
|
|
if (hlen != sizeof(struct ip))
|
|
|
|
return 0;
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case AF_INET:
|
2000-01-31 17:18:52 +03:00
|
|
|
sin = (struct sockaddr_in *)&sav->sah->saidx.dst;
|
1999-06-28 10:36:47 +04:00
|
|
|
if (bcmp(&ip->ip_dst, &sin->sin_addr, sizeof(ip->ip_dst)) != 0)
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
#ifdef INET6
|
|
|
|
case AF_INET6:
|
|
|
|
/* should be supported, but at this moment we don't. */
|
|
|
|
/*FALLTHROUGH*/
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
/* validate inbound IPsec tunnel packet. */
|
|
|
|
int
|
2000-01-31 17:18:52 +03:00
|
|
|
ipsec6_tunnel_validate(ip6, nxt0, sav)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
u_int nxt0;
|
2000-01-31 17:18:52 +03:00
|
|
|
struct secasvar *sav;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
u_int8_t nxt = nxt0 & 0xff;
|
|
|
|
struct sockaddr_in6 *sin6;
|
2003-10-02 11:19:37 +04:00
|
|
|
struct in6_addr in6;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (nxt != IPPROTO_IPV6)
|
|
|
|
return 0;
|
2000-11-10 04:10:36 +03:00
|
|
|
/* do not decapsulate if the SA is for transport mode only */
|
|
|
|
if (sav->sah->saidx.mode == IPSEC_MODE_TRANSPORT)
|
|
|
|
return 0;
|
2000-01-31 17:18:52 +03:00
|
|
|
switch (((struct sockaddr *)&sav->sah->saidx.dst)->sa_family) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case AF_INET6:
|
2000-01-31 17:18:52 +03:00
|
|
|
sin6 = ((struct sockaddr_in6 *)&sav->sah->saidx.dst);
|
2003-10-02 11:19:37 +04:00
|
|
|
if (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &in6))
|
1999-06-28 10:36:47 +04:00
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case AF_INET:
|
|
|
|
/* should be supported, but at this moment we don't. */
|
|
|
|
/*FALLTHROUGH*/
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a mbuf chain for encryption.
|
|
|
|
* If the original mbuf chain contains a mbuf with a cluster,
|
|
|
|
* allocate a new cluster and copy the data to the new cluster.
|
|
|
|
* XXX: this hack is inefficient, but is necessary to handle cases
|
|
|
|
* of TCP retransmission...
|
|
|
|
*/
|
|
|
|
struct mbuf *
|
|
|
|
ipsec_copypkt(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
|
|
|
struct mbuf *n, **mpp, *mnew;
|
|
|
|
|
|
|
|
for (n = m, mpp = &m; n; n = n->m_next) {
|
|
|
|
if (n->m_flags & M_EXT) {
|
|
|
|
/*
|
2002-06-11 21:26:52 +04:00
|
|
|
* Make a copy only if there is more than one
|
2001-09-13 10:30:57 +04:00
|
|
|
* references to the cluster.
|
1999-06-28 10:36:47 +04:00
|
|
|
* XXX: is this approach effective?
|
|
|
|
*/
|
2002-06-11 21:26:52 +04:00
|
|
|
if (M_READONLY(n))
|
|
|
|
{
|
1999-06-28 10:36:47 +04:00
|
|
|
int remain, copied;
|
|
|
|
struct mbuf *mm;
|
|
|
|
|
|
|
|
if (n->m_flags & M_PKTHDR) {
|
|
|
|
MGETHDR(mnew, M_DONTWAIT, MT_HEADER);
|
|
|
|
if (mnew == NULL)
|
|
|
|
goto fail;
|
|
|
|
mnew->m_pkthdr = n->m_pkthdr;
|
2000-03-01 15:49:27 +03:00
|
|
|
#if 0
|
2003-01-17 11:11:49 +03:00
|
|
|
/* XXX: convert to m_tag or delete? */
|
2000-03-01 15:49:27 +03:00
|
|
|
if (n->m_pkthdr.aux) {
|
|
|
|
mnew->m_pkthdr.aux =
|
|
|
|
m_copym(n->m_pkthdr.aux,
|
|
|
|
0, M_COPYALL, M_DONTWAIT);
|
|
|
|
}
|
|
|
|
#endif
|
2005-08-18 04:30:58 +04:00
|
|
|
M_MOVE_PKTHDR(mnew, n);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
MGET(mnew, M_DONTWAIT, MT_DATA);
|
|
|
|
if (mnew == NULL)
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
mnew->m_len = 0;
|
|
|
|
mm = mnew;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy data. If we don't have enough space to
|
|
|
|
* store the whole data, allocate a cluster
|
|
|
|
* or additional mbufs.
|
|
|
|
* XXX: we don't use m_copyback(), since the
|
|
|
|
* function does not use clusters and thus is
|
|
|
|
* inefficient.
|
|
|
|
*/
|
|
|
|
remain = n->m_len;
|
|
|
|
copied = 0;
|
2001-02-08 18:04:26 +03:00
|
|
|
while (1) {
|
1999-06-28 10:36:47 +04:00
|
|
|
int len;
|
|
|
|
struct mbuf *mn;
|
|
|
|
|
|
|
|
if (remain <= (mm->m_flags & M_PKTHDR ? MHLEN : MLEN))
|
|
|
|
len = remain;
|
|
|
|
else { /* allocate a cluster */
|
|
|
|
MCLGET(mm, M_DONTWAIT);
|
|
|
|
if (!(mm->m_flags & M_EXT)) {
|
|
|
|
m_free(mm);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
len = remain < MCLBYTES ?
|
|
|
|
remain : MCLBYTES;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcopy(n->m_data + copied, mm->m_data,
|
|
|
|
len);
|
|
|
|
|
|
|
|
copied += len;
|
|
|
|
remain -= len;
|
|
|
|
mm->m_len = len;
|
|
|
|
|
|
|
|
if (remain <= 0) /* completed? */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* need another mbuf */
|
|
|
|
MGETHDR(mn, M_DONTWAIT, MT_HEADER);
|
|
|
|
if (mn == NULL)
|
|
|
|
goto fail;
|
2001-08-06 14:25:00 +04:00
|
|
|
mn->m_pkthdr.rcvif = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
mm->m_next = mn;
|
|
|
|
mm = mn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust chain */
|
|
|
|
mm->m_next = m_free(n);
|
|
|
|
n = mm;
|
|
|
|
*mpp = mnew;
|
|
|
|
mpp = &n->m_next;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*mpp = n;
|
|
|
|
mpp = &n->m_next;
|
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (m);
|
1999-06-28 10:36:47 +04:00
|
|
|
fail:
|
|
|
|
m_freem(m);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (NULL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
static struct m_tag *
|
2001-01-24 12:04:15 +03:00
|
|
|
ipsec_addaux(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2003-01-17 11:11:49 +03:00
|
|
|
struct m_tag *mtag;
|
2001-01-24 12:04:15 +03:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
mtag = m_tag_find(m, PACKET_TAG_ESP, NULL);
|
|
|
|
if (mtag == NULL) {
|
|
|
|
mtag = m_tag_get(PACKET_TAG_ESP, sizeof(struct ipsecaux),
|
|
|
|
M_NOWAIT);
|
|
|
|
if (mtag != NULL)
|
|
|
|
m_tag_prepend(m, mtag);
|
|
|
|
}
|
|
|
|
if (mtag == NULL)
|
|
|
|
return NULL; /* ENOBUFS */
|
|
|
|
/* XXX is this necessary? */
|
|
|
|
bzero((void *)(mtag + 1), sizeof(struct ipsecaux));
|
|
|
|
return mtag;
|
2001-01-24 12:04:15 +03:00
|
|
|
}
|
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
static struct m_tag *
|
2001-01-24 12:04:15 +03:00
|
|
|
ipsec_findaux(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2003-01-17 11:11:49 +03:00
|
|
|
return m_tag_find(m, PACKET_TAG_ESP, NULL);
|
2001-01-24 12:04:15 +03:00
|
|
|
}
|
|
|
|
|
2000-03-01 15:49:27 +03:00
|
|
|
void
|
2001-01-24 12:04:15 +03:00
|
|
|
ipsec_delaux(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2003-01-17 11:11:49 +03:00
|
|
|
struct m_tag *mtag;
|
2001-01-24 12:04:15 +03:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
mtag = m_tag_find(m, PACKET_TAG_ESP, NULL);
|
|
|
|
if (mtag != NULL)
|
|
|
|
m_tag_delete(m, mtag);
|
2001-01-24 12:04:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if the aux buffer is unnecessary, nuke it. */
|
|
|
|
static void
|
2003-01-17 11:11:49 +03:00
|
|
|
ipsec_optaux(m, mtag)
|
2001-01-24 12:04:15 +03:00
|
|
|
struct mbuf *m;
|
2003-01-17 11:11:49 +03:00
|
|
|
struct m_tag *mtag;
|
2001-01-24 12:04:15 +03:00
|
|
|
{
|
2001-08-06 14:25:00 +04:00
|
|
|
struct ipsecaux *aux;
|
2001-01-24 12:04:15 +03:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
if (mtag == NULL)
|
2001-01-24 12:04:15 +03:00
|
|
|
return;
|
2003-01-17 11:11:49 +03:00
|
|
|
aux = (struct ipsecaux *)(mtag + 1);
|
2001-08-06 14:25:00 +04:00
|
|
|
if (!aux->so && !aux->sp)
|
2001-01-24 12:04:15 +03:00
|
|
|
ipsec_delaux(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ipsec_addhist(m, proto, spi)
|
|
|
|
struct mbuf *m;
|
|
|
|
int proto;
|
|
|
|
u_int32_t spi;
|
|
|
|
{
|
2003-01-17 11:11:49 +03:00
|
|
|
struct m_tag *mtag;
|
2001-08-06 14:25:00 +04:00
|
|
|
struct ipsecaux *aux;
|
2001-01-24 12:04:15 +03:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
mtag = ipsec_addaux(m);
|
|
|
|
if (mtag == NULL)
|
2001-01-24 12:04:15 +03:00
|
|
|
return ENOBUFS;
|
2003-01-17 11:11:49 +03:00
|
|
|
aux = (struct ipsecaux *)(mtag + 1);
|
2001-08-06 14:25:00 +04:00
|
|
|
aux->hdrs++;
|
2001-01-24 12:04:15 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-08-06 14:25:00 +04:00
|
|
|
int
|
|
|
|
ipsec_getnhist(m)
|
2001-01-24 12:04:15 +03:00
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2003-01-17 11:11:49 +03:00
|
|
|
struct m_tag *mtag;
|
2001-08-06 14:25:00 +04:00
|
|
|
struct ipsecaux *aux;
|
2001-01-24 12:04:15 +03:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
mtag = ipsec_findaux(m);
|
|
|
|
if (mtag == NULL)
|
2001-08-06 14:25:00 +04:00
|
|
|
return 0;
|
2003-01-17 11:11:49 +03:00
|
|
|
aux = (struct ipsecaux *)(mtag + 1);
|
2001-08-06 14:25:00 +04:00
|
|
|
return aux->hdrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ipsec_history *
|
|
|
|
ipsec_gethist(m, lenp)
|
|
|
|
struct mbuf *m;
|
|
|
|
int *lenp;
|
|
|
|
{
|
|
|
|
|
|
|
|
panic("ipsec_gethist: obsolete API");
|
2001-01-24 12:04:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ipsec_clearhist(m)
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2003-01-17 11:11:49 +03:00
|
|
|
struct m_tag *mtag;
|
2001-01-24 12:04:15 +03:00
|
|
|
|
2003-01-17 11:11:49 +03:00
|
|
|
mtag = ipsec_findaux(m);
|
|
|
|
ipsec_optaux(m, mtag);
|
2001-01-24 12:04:15 +03:00
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* System control for IPSEC
|
|
|
|
*/
|
|
|
|
u_char ipsecctlermap[PRC_NCMDS] = {
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
|
|
|
|
EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
|
|
|
|
EMSGSIZE, EHOSTUNREACH, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
ENOPROTOOPT
|
|
|
|
};
|
|
|
|
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
/*
|
|
|
|
* sysctl helper routine for some net.inet.ipsec and net.inet6.ipnet6
|
|
|
|
* nodes. ensures that the given value is correct and clears the
|
|
|
|
* ipsec cache accordingly.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sysctl_ipsec(SYSCTLFN_ARGS)
|
|
|
|
{
|
|
|
|
int error, t;
|
|
|
|
struct sysctlnode node;
|
|
|
|
|
|
|
|
node = *rnode;
|
|
|
|
if (rnode->sysctl_num == IPSECCTL_DEF_POLICY)
|
|
|
|
t = (*((struct secpolicy**)rnode->sysctl_data))->policy;
|
|
|
|
else
|
|
|
|
t = *(int*)rnode->sysctl_data;
|
|
|
|
node.sysctl_data = &t;
|
|
|
|
error = sysctl_lookup(SYSCTLFN_CALL(&node));
|
|
|
|
if (error || newp == NULL)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (rnode->sysctl_num) {
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSECCTL_DEF_ESP_TRANSLEV:
|
|
|
|
case IPSECCTL_DEF_ESP_NETLEV:
|
|
|
|
case IPSECCTL_DEF_AH_TRANSLEV:
|
|
|
|
case IPSECCTL_DEF_AH_NETLEV:
|
2005-02-27 01:45:09 +03:00
|
|
|
if (t != IPSEC_LEVEL_USE &&
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
t != IPSEC_LEVEL_REQUIRE)
|
|
|
|
return (EINVAL);
|
|
|
|
ipsec_invalpcbcacheall();
|
2002-06-12 05:47:34 +04:00
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
case IPSECCTL_DEF_POLICY:
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
if (t != IPSEC_POLICY_DISCARD &&
|
|
|
|
t != IPSEC_POLICY_NONE)
|
|
|
|
return (EINVAL);
|
|
|
|
ipsec_invalpcbcacheall();
|
2002-06-12 05:47:34 +04:00
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
default:
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
return (EINVAL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
|
|
|
|
if (rnode->sysctl_num == IPSECCTL_DEF_POLICY)
|
|
|
|
(*((struct secpolicy**)rnode->sysctl_data))->policy = t;
|
|
|
|
else
|
|
|
|
*(int*)rnode->sysctl_data = t;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_SETUP(sysctl_net_inet_ipsec_setup, "sysctl net.inet.ipsec subtree setup")
|
|
|
|
{
|
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "net", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "inet", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_NODE, "ipsec",
|
|
|
|
SYSCTL_DESCR("IPv4 related IPSec settings"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
|
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_STRUCT, "stats",
|
|
|
|
SYSCTL_DESCR("IPSec statistics and counters"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ipsecstat, sizeof(ipsecstat),
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_STATS, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "def_policy",
|
|
|
|
SYSCTL_DESCR("Default action for non-IPSec packets"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip4_def_policy, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_POLICY, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "esp_trans_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"transport mode traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip4_esp_trans_deflev, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_ESP_TRANSLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "esp_net_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"tunneled traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip4_esp_net_deflev, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_ESP_NETLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ah_trans_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"transport mode headers"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip4_ah_trans_deflev, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_AH_TRANSLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ah_net_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"tunneled headers"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip4_ah_net_deflev, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_AH_NETLEV, CTL_EOL);
|
|
|
|
#if 0 /* obsolete, do not reuse */
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_INT, "inbound_call_ike", NULL,
|
|
|
|
NULL, 0, &ip4_inbound_call_ike, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_INBOUND_CALL_IKE, CTL_EOL);
|
|
|
|
#endif
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ah_cleartos",
|
|
|
|
SYSCTL_DESCR("Clear IP TOS field before calculating AH"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ip4_ah_cleartos, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_AH_CLEARTOS, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ah_offsetmask",
|
|
|
|
SYSCTL_DESCR("Mask for IP fragment offset field when "
|
|
|
|
"calculating AH"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ip4_ah_offsetmask, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_AH_OFFSETMASK, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "dfbit",
|
|
|
|
SYSCTL_DESCR("IP header DF bit setting for tunneled "
|
|
|
|
"traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ip4_ipsec_dfbit, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DFBIT, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ecn",
|
|
|
|
SYSCTL_DESCR("Behavior of ECN for tunneled traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ip4_ipsec_ecn, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_ECN, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "debug",
|
|
|
|
SYSCTL_DESCR("Enable IPSec debugging output"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ipsec_debug, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEBUG, CTL_EOL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "aliases" for the ipsec subtree
|
|
|
|
*/
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "esp", NULL,
|
|
|
|
NULL, IPPROTO_AH, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_ESP, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "ipcomp", NULL,
|
|
|
|
NULL, IPPROTO_AH, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, IPPROTO_IPCOMP, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "ah", NULL,
|
|
|
|
NULL, IPPROTO_AH, NULL, 0,
|
|
|
|
CTL_NET, PF_INET, CTL_CREATE, CTL_EOL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef INET6
|
|
|
|
/*
|
|
|
|
* System control for IPSEC6
|
|
|
|
*/
|
|
|
|
u_char ipsec6ctlermap[PRC_NCMDS] = {
|
|
|
|
0, 0, 0, 0,
|
|
|
|
0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH,
|
|
|
|
EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
|
|
|
|
EMSGSIZE, EHOSTUNREACH, 0, 0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
ENOPROTOOPT
|
|
|
|
};
|
|
|
|
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
SYSCTL_SETUP(sysctl_net_inet6_ipsec6_setup,
|
|
|
|
"sysctl net.inet6.ipsec6 subtree setup")
|
|
|
|
{
|
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "net", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "inet6", NULL,
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET6, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_NODE, "ipsec6",
|
|
|
|
SYSCTL_DESCR("IPv6 related IPSec settings"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH, CTL_EOL);
|
|
|
|
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_STRUCT, "stats",
|
|
|
|
SYSCTL_DESCR("IPSec statistics and counters"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ipsec6stat, sizeof(ipsec6stat),
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_STATS, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "def_policy",
|
|
|
|
SYSCTL_DESCR("Default action for non-IPSec packets"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip6_def_policy, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_POLICY, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "esp_trans_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"transport mode traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip6_esp_trans_deflev, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_ESP_TRANSLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "esp_net_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"tunneled traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip6_esp_net_deflev, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_ESP_NETLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ah_trans_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"transport mode headers"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip6_ah_trans_deflev, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_AH_TRANSLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ah_net_deflev",
|
|
|
|
SYSCTL_DESCR("Default required security level for "
|
|
|
|
"tunneled headers"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
sysctl_ipsec, 0, &ip6_ah_net_deflev, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEF_AH_NETLEV, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "ecn",
|
|
|
|
SYSCTL_DESCR("Behavior of ECN for tunneled traffic"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ip6_ipsec_ecn, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_ECN, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2004-05-25 08:33:59 +04:00
|
|
|
CTLTYPE_INT, "debug",
|
|
|
|
SYSCTL_DESCR("Enable IPSec debugging output"),
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
NULL, 0, &ipsec_debug, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_AH,
|
|
|
|
IPSECCTL_DEBUG, CTL_EOL);
|
2002-06-12 05:47:34 +04:00
|
|
|
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
/*
|
|
|
|
* "aliases" for the ipsec6 subtree
|
|
|
|
*/
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "esp6", NULL,
|
|
|
|
NULL, IPPROTO_AH, NULL, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_ESP, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "ipcomp6", NULL,
|
|
|
|
NULL, IPPROTO_AH, NULL, 0,
|
|
|
|
CTL_NET, PF_INET6, IPPROTO_IPCOMP, CTL_EOL);
|
2004-03-24 18:34:46 +03:00
|
|
|
sysctl_createv(clog, 0, NULL, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
CTLTYPE_NODE, "ah6", NULL,
|
|
|
|
NULL, IPPROTO_AH, NULL, 0,
|
|
|
|
CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2001-10-16 10:24:44 +04:00
|
|
|
#endif /* INET6 */
|